Add JumpToFileButton, pass changesetId for creating link

This commit is contained in:
Florian Scholdei
2020-07-23 16:55:20 +02:00
parent 127a335b8f
commit f62e8d076d
7 changed files with 4505 additions and 24 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
import React, { useEffect, useState } from "react"; import React, { ReactNode, useEffect, useState } from "react";
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import Diff from "./Diff"; import Diff from "./Diff";
// @ts-ignore // @ts-ignore
@@ -34,6 +34,7 @@ import Toast from "../toast/Toast";
import { getPath } from "./diffs"; import { getPath } from "./diffs";
import DiffButton from "./DiffButton"; import DiffButton from "./DiffButton";
import styled from "styled-components"; import styled from "styled-components";
import { MemoryRouter } from "react-router-dom";
const diffFiles = parser.parse(simpleDiff); const diffFiles = parser.parse(simpleDiff);
@@ -41,7 +42,10 @@ const Container = styled.div`
padding: 2rem 6rem; padding: 2rem 6rem;
`; `;
const RoutingDecorator = (story: () => ReactNode) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>;
storiesOf("Diff", module) storiesOf("Diff", module)
.addDecorator(RoutingDecorator)
.addDecorator(storyFn => <Container>{storyFn()}</Container>) .addDecorator(storyFn => <Container>{storyFn()}</Container>)
.add("Default", () => <Diff diff={diffFiles} />) .add("Default", () => <Diff diff={diffFiles} />)
.add("Side-By-Side", () => <Diff diff={diffFiles} sideBySide={true} />) .add("Side-By-Side", () => <Diff diff={diffFiles} sideBySide={true} />)
@@ -121,4 +125,5 @@ storiesOf("Diff", module)
return file; return file;
}); });
return <Diff diff={filesWithLanguage} />; return <Diff diff={filesWithLanguage} />;
}); })
.add("WithLinkToFile", () => <Diff diff={diffFiles} changesetId="0b92307029a2a171e3b467a1502f392c733e3e8f" />);

View File

@@ -30,6 +30,7 @@ import { WithTranslation, withTranslation } from "react-i18next";
type Props = WithTranslation & type Props = WithTranslation &
DiffObjectProps & { DiffObjectProps & {
diff: File[]; diff: File[];
changesetId?: string;
}; };
class Diff extends React.Component<Props> { class Diff extends React.Component<Props> {

View File

@@ -21,8 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
import React, { FC } from "react"; import React from "react";
import { useTranslation, withTranslation, WithTranslation } from "react-i18next"; import { withTranslation, WithTranslation } from "react-i18next";
import classNames from "classnames"; import classNames from "classnames";
import styled from "styled-components"; import styled from "styled-components";
// @ts-ignore // @ts-ignore
@@ -39,13 +39,14 @@ import HunkExpandLink from "./HunkExpandLink";
import { Modal } from "../modals"; import { Modal } from "../modals";
import ErrorNotification from "../ErrorNotification"; import ErrorNotification from "../ErrorNotification";
import HunkExpandDivider from "./HunkExpandDivider"; import HunkExpandDivider from "./HunkExpandDivider";
import Tooltip from "../Tooltip"; import JumpToFileButton from "./JumpToFileButton";
const EMPTY_ANNOTATION_FACTORY = {}; const EMPTY_ANNOTATION_FACTORY = {};
type Props = DiffObjectProps & type Props = DiffObjectProps &
WithTranslation & { WithTranslation & {
file: File; file: File;
changesetId?: string;
}; };
type Collapsible = { type Collapsible = {
@@ -91,10 +92,6 @@ const ChangeTypeTag = styled(Tag)`
margin-left: 0.75rem; margin-left: 0.75rem;
`; `;
const LeftMarginSpan = styled.span`
margin-left: 0.25rem;
`;
class DiffFile extends React.Component<Props, State> { class DiffFile extends React.Component<Props, State> {
static defaultProps: Partial<Props> = { static defaultProps: Partial<Props> = {
defaultCollapse: false, defaultCollapse: false,
@@ -396,9 +393,10 @@ class DiffFile extends React.Component<Props, State> {
hasContent = (file: File) => file && !file.isBinary && file.hunks && file.hunks.length > 0; hasContent = (file: File) => file && !file.isBinary && file.hunks && file.hunks.length > 0;
render() { render() {
const { fileControlFactory, fileAnnotationFactory, t } = this.props; const { fileControlFactory, fileAnnotationFactory, changesetId, t } = this.props;
const { file, collapsed, sideBySide, diffExpander, expansionError } = this.state; const { file, collapsed, sideBySide, diffExpander, expansionError } = this.state;
const viewType = sideBySide ? "split" : "unified"; const viewType = sideBySide ? "split" : "unified";
console.log(`DifFile ${file.newPath}:`, file); //TODO: delete log
let body = null; let body = null;
let icon = "angle-right"; let icon = "angle-right";
@@ -420,6 +418,7 @@ class DiffFile extends React.Component<Props, State> {
} }
const collapseIcon = this.hasContent(file) ? <Icon name={icon} color="inherit" /> : null; const collapseIcon = this.hasContent(file) ? <Icon name={icon} color="inherit" /> : null;
const fileControls = fileControlFactory ? fileControlFactory(file, this.setCollapse) : null; const fileControls = fileControlFactory ? fileControlFactory(file, this.setCollapse) : null;
const jumpToFile = changesetId ? <JumpToFileButton link={`../sources/${changesetId}/${file.newPath}/`} /> : null;
const sideBySideToggle = const sideBySideToggle =
file.hunks && file.hunks.length > 0 ? ( file.hunks && file.hunks.length > 0 ? (
<ButtonWrapper className={classNames("level-right", "is-flex")}> <ButtonWrapper className={classNames("level-right", "is-flex")}>
@@ -440,9 +439,14 @@ class DiffFile extends React.Component<Props, State> {
)} )}
</MenuContext.Consumer> </MenuContext.Consumer>
{fileControls} {fileControls}
{jumpToFile}
</ButtonGroup> </ButtonGroup>
</ButtonWrapper> </ButtonWrapper>
) : null; ) : (
<ButtonWrapper className={classNames("level-right", "is-flex")}>
<ButtonGroup>{jumpToFile}</ButtonGroup>
</ButtonWrapper>
);
let errorModal; let errorModal;
if (expansionError) { if (expansionError) {
@@ -470,7 +474,6 @@ class DiffFile extends React.Component<Props, State> {
<TitleWrapper className={classNames("is-ellipsis-overflow", "is-size-6")}> <TitleWrapper className={classNames("is-ellipsis-overflow", "is-size-6")}>
{this.renderFileTitle(file)} {this.renderFileTitle(file)}
</TitleWrapper> </TitleWrapper>
<LinkToFile file={file} />
{this.renderChangeTag(file)} {this.renderChangeTag(file)}
</FullWidthTitleHeader> </FullWidthTitleHeader>
{sideBySideToggle} {sideBySideToggle}
@@ -482,15 +485,4 @@ class DiffFile extends React.Component<Props, State> {
} }
} }
const LinkToFile: FC<Props> = ({ file }) => {
const [t] = useTranslation("repos");
return (
<LeftMarginSpan>
<Tooltip location="top" message={t("diff.jumpToFile")}>
<Icon iconStyle="far" name="file-alt" color="grey" className="fa-sm" />
</Tooltip>
</LeftMarginSpan>
);
};
export default withTranslation("repos")(DiffFile); export default withTranslation("repos")(DiffFile);

View File

@@ -0,0 +1,55 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import React, { FC } from "react";
import styled from "styled-components";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
import Tooltip from "../Tooltip";
import Icon from "../Icon";
const Button = styled(Link)`
width: 50px;
cursor: pointer;
&:hover {
color: #33b2e8;
}
`;
type Props = {
link: string;
};
const JumpToFileButton: FC<Props> = ({ link }) => {
const [t] = useTranslation("repos");
const tooltip = t("diff.jumpToFile");
return (
<Tooltip message={tooltip} location="top">
<Button aria-label={tooltip} className="button" to={link}>
<Icon name="file-code" color="inherit" />
</Button>
</Tooltip>
);
};
export default JumpToFileButton;

View File

@@ -37,6 +37,7 @@ import { withTranslation, WithTranslation } from "react-i18next";
type Props = WithTranslation & type Props = WithTranslation &
DiffObjectProps & { DiffObjectProps & {
url: string; url: string;
changesetId?: string;
}; };
type State = { type State = {

View File

@@ -52,7 +52,7 @@ class ChangesetDiff extends React.Component<Props> {
return <Notification type="danger">{t("changeset.diffNotSupported")}</Notification>; return <Notification type="danger">{t("changeset.diffNotSupported")}</Notification>;
} else { } else {
const url = createUrl(changeset); const url = createUrl(changeset);
return <LoadingDiff url={url} defaultCollapse={defaultCollapse} sideBySide={false} />; return <LoadingDiff url={url} defaultCollapse={defaultCollapse} sideBySide={false} changesetId={changeset.id} />;
} }
} }
} }