From 8410aa68c60bb4aa27d7809b13fcbd7055cbdeae Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 19 Dec 2019 09:51:44 +0100 Subject: [PATCH] added storybook stories for diff --- scm-ui/ui-components/.storybook/config.js | 5 + .../src/MarkdownView.stories.tsx | 2 - .../src/__resources__/Diff.simple.ts | 148 ++++++++++++++++++ .../src/buttons/index.stories.tsx | 11 +- .../ui-components/src/repos/Diff.stories.tsx | 47 ++++++ scm-ui/ui-components/src/repos/DiffFile.tsx | 4 +- scm-ui/ui-components/src/repos/DiffTypes.ts | 2 +- 7 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 scm-ui/ui-components/src/__resources__/Diff.simple.ts create mode 100644 scm-ui/ui-components/src/repos/Diff.stories.tsx diff --git a/scm-ui/ui-components/.storybook/config.js b/scm-ui/ui-components/.storybook/config.js index 5b9ed3d3a2..1033a7a805 100644 --- a/scm-ui/ui-components/.storybook/config.js +++ b/scm-ui/ui-components/.storybook/config.js @@ -4,6 +4,8 @@ import { addDecorator, configure } from "@storybook/react"; import { withI18next } from "storybook-addon-i18next"; import "!style-loader!css-loader!sass-loader!../../ui-styles/src/scm.scss"; +import React, { ReactNode } from "react"; +import { MemoryRouter } from "react-router-dom"; i18n.use(initReactI18next).init({ whitelist: ["en", "de", "es"], @@ -28,4 +30,7 @@ addDecorator( }) ); +const RoutingDecorator = (story) => {story()}; +addDecorator(RoutingDecorator); + configure(require.context("../src", true, /\.stories\.tsx?$/), module); diff --git a/scm-ui/ui-components/src/MarkdownView.stories.tsx b/scm-ui/ui-components/src/MarkdownView.stories.tsx index a7e71aac2b..22a478f1b2 100644 --- a/scm-ui/ui-components/src/MarkdownView.stories.tsx +++ b/scm-ui/ui-components/src/MarkdownView.stories.tsx @@ -2,7 +2,6 @@ import React from "react"; import { storiesOf } from "@storybook/react"; import MarkdownView from "./MarkdownView"; import styled from "styled-components"; -import { MemoryRouter } from "react-router-dom"; import TestPage from "./__resources__/test-page.md"; import MarkdownWithoutLang from "./__resources__/markdown-without-lang.md"; @@ -12,7 +11,6 @@ const Spacing = styled.div` `; storiesOf("MarkdownView", module) - .addDecorator(story => {story()}) .add("Default", () => ( diff --git a/scm-ui/ui-components/src/__resources__/Diff.simple.ts b/scm-ui/ui-components/src/__resources__/Diff.simple.ts new file mode 100644 index 0000000000..a08aa7cdb0 --- /dev/null +++ b/scm-ui/ui-components/src/__resources__/Diff.simple.ts @@ -0,0 +1,148 @@ +export default `diff --git a/src/main/java/com/cloudogu/scm/review/events/EventListener.java b/src/main/java/com/cloudogu/scm/review/events/EventListener.java +index f889f9c..95e3b10 100644 +--- a/src/main/java/com/cloudogu/scm/review/events/EventListener.java ++++ b/src/main/java/com/cloudogu/scm/review/events/EventListener.java +@@ -1,20 +1,12 @@ + package com.cloudogu.scm.review.events; + +-import com.cloudogu.scm.review.comment.service.BasicComment; +-import com.cloudogu.scm.review.comment.service.BasicCommentEvent; +-import com.cloudogu.scm.review.comment.service.CommentEvent; +-import com.cloudogu.scm.review.comment.service.ReplyEvent; + import com.cloudogu.scm.review.pullrequest.service.BasicPullRequestEvent; + import com.cloudogu.scm.review.pullrequest.service.PullRequest; +-import com.cloudogu.scm.review.pullrequest.service.PullRequestEvent; + import com.github.legman.Subscribe; +-import lombok.Data; + import org.apache.shiro.SecurityUtils; + import org.apache.shiro.subject.PrincipalCollection; + import org.apache.shiro.subject.Subject; + import sonia.scm.EagerSingleton; +-import sonia.scm.HandlerEventType; +-import sonia.scm.event.HandlerEvent; + import sonia.scm.plugin.Extension; + import sonia.scm.repository.Repository; + import sonia.scm.security.SessionId; +diff --git a/src/main/js/ChangeNotification.tsx b/src/main/js/ChangeNotification.tsx +index f6d61a9..5f371e4 100644 +--- a/src/main/js/ChangeNotification.tsx ++++ b/src/main/js/ChangeNotification.tsx +@@ -2,6 +2,7 @@ import React, { FC, useEffect, useState } from "react"; + import { Link } from "@scm-manager/ui-types"; + import { apiClient, Toast, ToastButtons, ToastButton } from "@scm-manager/ui-components"; + import { PullRequest } from "./types/PullRequest"; ++import { useTranslation } from "react-i18next"; + + type HandlerProps = { + url: string; +@@ -15,14 +16,19 @@ const EventNotificationHandler: FC = ({ url, reload }) => { + pullRequest: setEvent + }); + }, [url]); ++ const { t } = useTranslation("plugins"); + if (event) { + return ( +- +-

The underlying Pull-Request has changed. Press reload to see the changes.

+-

Warning: Non saved modification will be lost.

++ ++

{t("scm-review-plugin.changeNotification.description")}

++

{t("scm-review-plugin.changeNotification.modificationWarning")}

+ +- Reload +- setEvent(undefined)}>Ignore ++ ++ {t("scm-review-plugin.changeNotification.buttons.reload")} ++ ++ setEvent(undefined)}> ++ {t("scm-review-plugin.changeNotification.buttons.ignore")} ++ + +
+ ); +diff --git a/src/main/resources/locales/de/plugins.json b/src/main/resources/locales/de/plugins.json +index 80f84a1..2c63ab3 100644 +--- a/src/main/resources/locales/de/plugins.json ++++ b/src/main/resources/locales/de/plugins.json +@@ -181,6 +181,15 @@ + "titleClickable": "Der Kommentar bezieht sich auf eine ältere Version des Source- oder Target-Branches. Klicken Sie hier, um den ursprünglichen Kontext zu sehen." + } + } ++ }, ++ "changeNotification": { ++ "title": "Neue Änderungen", ++ "description": "An diesem Pull Request wurden Änderungen vorgenommen. Laden Sie die Seite neu um diese anzuzeigen.", ++ "modificationWarning": "Warnung: Nicht gespeicherte Eingaben gehen verloren.", ++ "buttons": { ++ "reload": "Neu laden", ++ "ignore": "Ignorieren" ++ } + } + }, + "permissions": { +diff --git a/src/main/resources/locales/en/plugins.json b/src/main/resources/locales/en/plugins.json +index d020fcd..e3c1630 100644 +--- a/src/main/resources/locales/en/plugins.json ++++ b/src/main/resources/locales/en/plugins.json +@@ -181,6 +181,15 @@ + "titleClickable": "The comment is related to an older of the source or target branch. Click here to see the original context." + } + } ++ }, ++ "changeNotification": { ++ "title": "New Changes", ++ "description": "The underlying Pull-Request has changed. Press reload to see the changes.", ++ "modificationWarning": "Warning: Non saved modification will be lost.", ++ "buttons": { ++ "reload": "Reload", ++ "ignore": "Ignore" ++ } + } + }, + "permissions": { +diff --git a/src/test/java/com/cloudogu/scm/review/events/ClientTest.java b/src/test/java/com/cloudogu/scm/review/events/ClientTest.java +index 889cc49..d5a4811 100644 +--- a/src/test/java/com/cloudogu/scm/review/events/ClientTest.java ++++ b/src/test/java/com/cloudogu/scm/review/events/ClientTest.java +@@ -7,19 +7,16 @@ import org.mockito.Answers; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + import sonia.scm.security.SessionId; ++ + import javax.ws.rs.sse.OutboundSseEvent; + import javax.ws.rs.sse.SseEventSink; +- + import java.time.Clock; + import java.time.Instant; + import java.time.LocalDateTime; + import java.time.ZoneOffset; + import java.time.temporal.ChronoField; +-import java.time.temporal.ChronoUnit; +-import java.time.temporal.TemporalField; + import java.util.concurrent.CompletableFuture; + import java.util.concurrent.CompletionStage; +-import java.util.concurrent.atomic.AtomicLong; + import java.util.concurrent.atomic.AtomicReference; + + import static java.time.temporal.ChronoUnit.MINUTES; +@@ -83,7 +80,7 @@ class ClientTest { + + @Test + @SuppressWarnings("unchecked") +- void shouldCloseEventSinkOnFailure() throws InterruptedException { ++ void shouldCloseEventSinkOnFailure() { + CompletionStage future = CompletableFuture.supplyAsync(() -> { + throw new RuntimeException("failed to send message"); + }); +@@ -91,9 +88,7 @@ class ClientTest { + + client.send(message); + +- Thread.sleep(50L); +- +- verify(eventSink).close(); ++ verify(eventSink, timeout(50L)).close(); + } + + @Test +`; diff --git a/scm-ui/ui-components/src/buttons/index.stories.tsx b/scm-ui/ui-components/src/buttons/index.stories.tsx index 79d5be448c..a238f25689 100644 --- a/scm-ui/ui-components/src/buttons/index.stories.tsx +++ b/scm-ui/ui-components/src/buttons/index.stories.tsx @@ -2,7 +2,6 @@ import React, { ReactNode } from "react"; import Button from "./Button"; import { storiesOf } from "@storybook/react"; import styled from "styled-components"; -import { MemoryRouter } from "react-router-dom"; import AddButton from "./AddButton"; import CreateButton from "./CreateButton"; import DeleteButton from "./DeleteButton"; @@ -17,14 +16,9 @@ const Spacing = styled.div` padding: 1em; `; -type StoryFn = () => ReactNode; - -const RoutingDecorator = (story: StoryFn) => {story()}; - -const SpacingDecorator = (story: StoryFn) => {story()}; +const SpacingDecorator = (story: () => ReactNode) => {story()}; storiesOf("Buttons|Button", module) - .addDecorator(RoutingDecorator) .add("Colors", () => (
{colors.map(color => ( @@ -44,7 +38,6 @@ storiesOf("Buttons|Button", module) const buttonStory = (name: string, storyFn: () => ReactElement) => { return storiesOf("Buttons|" + name, module) - .addDecorator(RoutingDecorator) .addDecorator(SpacingDecorator) .add("Default", storyFn); }; @@ -53,7 +46,7 @@ buttonStory("CreateButton", () => Create); buttonStory("DeleteButton", () => Delete); buttonStory("DownloadButton", () => ).add( "Disabled", - () => + () => ); buttonStory("EditButton", () => Edit); buttonStory("SubmitButton", () => Submit); diff --git a/scm-ui/ui-components/src/repos/Diff.stories.tsx b/scm-ui/ui-components/src/repos/Diff.stories.tsx new file mode 100644 index 0000000000..2f93ffd919 --- /dev/null +++ b/scm-ui/ui-components/src/repos/Diff.stories.tsx @@ -0,0 +1,47 @@ +import React, { useEffect, useState } from "react"; +import { storiesOf } from "@storybook/react"; +import Diff from "./Diff"; +// @ts-ignore +import parser from "gitdiff-parser"; +import simpleDiff from "../__resources__/Diff.simple"; +import Button from "../buttons/Button"; +import { DiffEventContext } from "./DiffTypes"; +import Toast from "../toast/Toast"; + +const diffFiles = parser.parse(simpleDiff); + +storiesOf("Diff", module) + .add("Default", () => ) + .add("Side-By-Side", () => ) + .add("Collapsed", () => ) + .add("File Controls", () => } />) + .add("File Annotation", () => ( + [

Custom File annotation for {file.newPath}

]} /> + )) + .add("Line Annotation", () => ( + { + return { + N2: [

Line Annotation

] + }; + }} + /> + )) + .add("OnClick", () => { + const OnClickDemo = ({}) => { + const [changeId, setChangeId] = useState(); + useEffect(() => { + const interval = setInterval(() => setChangeId(undefined), 2000); + return () => clearInterval(interval); + }); + const onClick = (context: DiffEventContext) => setChangeId(context.changeId); + return ( + <> + {changeId && } + + + ); + }; + return ; + }); diff --git a/scm-ui/ui-components/src/repos/DiffFile.tsx b/scm-ui/ui-components/src/repos/DiffFile.tsx index 0c51a30982..4e2e7e08b4 100644 --- a/scm-ui/ui-components/src/repos/DiffFile.tsx +++ b/scm-ui/ui-components/src/repos/DiffFile.tsx @@ -20,7 +20,7 @@ type Collapsible = { }; type State = Collapsible & { - sideBySide: boolean; + sideBySide?: boolean; }; const DiffFilePanel = styled.div` @@ -87,7 +87,7 @@ class DiffFile extends React.Component { super(props); this.state = { collapsed: !!this.props.defaultCollapse, - sideBySide: false + sideBySide: props.sideBySide }; } diff --git a/scm-ui/ui-components/src/repos/DiffTypes.ts b/scm-ui/ui-components/src/repos/DiffTypes.ts index 58dd5aef5b..ba89d40aaa 100644 --- a/scm-ui/ui-components/src/repos/DiffTypes.ts +++ b/scm-ui/ui-components/src/repos/DiffTypes.ts @@ -66,7 +66,7 @@ export type DiffEventHandler = (context: DiffEventContext) => void; export type FileControlFactory = (file: File, setCollapseState: (p: boolean) => void) => ReactNode | null | undefined; export type DiffObjectProps = { - sideBySide: boolean; + sideBySide?: boolean; onClick?: DiffEventHandler; fileControlFactory?: FileControlFactory; fileAnnotationFactory?: FileAnnotationFactory;