Skip to content

Commit 518e8db

Browse files
committed
feat(frontend): add stories for relay-workflows-lib components
1 parent 943ea49 commit 518e8db

19 files changed

+823
-6
lines changed

frontend/dashboard/src/mocks/handlers.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ import {
5656
TemplateViewRetriggerQuery$data,
5757
TemplateViewRetriggerQuery$variables,
5858
} from "relay-workflows-lib/lib/views/__generated__/TemplateViewRetriggerQuery.graphql";
59+
import {
60+
MockRenderSubmittedMessageQuery$data,
61+
MockRenderSubmittedMessageQuery$variables,
62+
} from "relay-workflows-lib/stories/mock-queries/__generated__/MockRenderSubmittedMessageQuery.graphql";
5963

6064
const api = graphql.link("https://workflows.diamond.ac.uk/graphql");
6165

@@ -158,4 +162,62 @@ export const handlers = [
158162
});
159163
},
160164
),
165+
166+
api.query<
167+
MockRenderSubmittedMessageQuery$data,
168+
MockRenderSubmittedMessageQuery$variables
169+
>("MockRenderSubmittedMessageQuery", ({ variables }) => {
170+
switch (variables.name) {
171+
case "completed-workflow":
172+
return HttpResponse.json({
173+
data: {
174+
workflow: {
175+
status: {
176+
__typename: "WorkflowSucceededStatus",
177+
},
178+
},
179+
} as unknown as MockRenderSubmittedMessageQuery$data,
180+
});
181+
case "running-workflow":
182+
return HttpResponse.json({
183+
data: {
184+
workflow: {
185+
status: {
186+
__typename: "WorkflowRunningStatus",
187+
},
188+
},
189+
} as unknown as MockRenderSubmittedMessageQuery$data,
190+
});
191+
case "pending-workflow":
192+
return HttpResponse.json({
193+
data: {
194+
workflow: {
195+
status: {
196+
__typename: "WorkflowPendingStatus",
197+
},
198+
},
199+
} as unknown as MockRenderSubmittedMessageQuery$data,
200+
});
201+
case "errored-workflow":
202+
return HttpResponse.json({
203+
data: {
204+
workflow: {
205+
status: {
206+
__typename: "WorkflowErroredStatus",
207+
},
208+
},
209+
} as unknown as MockRenderSubmittedMessageQuery$data,
210+
});
211+
default:
212+
return HttpResponse.json({
213+
data: {
214+
workflow: {
215+
status: {
216+
__typename: "Unknown",
217+
},
218+
},
219+
} as unknown as MockRenderSubmittedMessageQuery$data,
220+
});
221+
}
222+
}),
161223
];
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { StorybookConfig } from "@storybook/react-vite";
2+
3+
import { join, dirname } from "path";
4+
5+
/**
6+
* This function is used to resolve the absolute path of a package.
7+
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
8+
*/
9+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
function getAbsolutePath(value: string): any {
11+
return dirname(require.resolve(join(value, "package.json")));
12+
}
13+
const config: StorybookConfig = {
14+
stories: [
15+
// "../stories/**/*.mdx",
16+
"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)",
17+
],
18+
addons: [
19+
getAbsolutePath("@storybook/addon-links"),
20+
getAbsolutePath("@chromatic-com/storybook"),
21+
getAbsolutePath("@storybook/addon-docs"),
22+
],
23+
framework: {
24+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
25+
name: getAbsolutePath("@storybook/react-vite"),
26+
options: {},
27+
},
28+
env: (config) => ({
29+
...config,
30+
VITE_ENABLE_MOCKING: "true",
31+
VITE_GRAPH_URL: "https://workflows.diamond.ac.uk/graphql",
32+
VITE_GRAPH_WS_URL: "wss://workflows.diamond.ac.uk/graphql/ws",
33+
}),
34+
};
35+
export default config;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { Preview } from "@storybook/react-vite";
2+
import { worker } from "dashboard/src/mocks/browser";
3+
4+
const preview: Preview = {
5+
async beforeAll() {
6+
await worker.start();
7+
},
8+
beforeEach() {
9+
return () => {
10+
worker.resetHandlers();
11+
};
12+
},
13+
parameters: {
14+
controls: {
15+
matchers: {
16+
color: /(background|color)$/i,
17+
date: /Date$/i,
18+
},
19+
},
20+
},
21+
};
22+
23+
export default preview;

frontend/relay-workflows-lib/lib/components/WorkflowListFilterDrawer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function WorkflowListFilterDisplay({
7474
);
7575
}
7676

77-
function WorkflowListFilterDrawer({
77+
export function WorkflowListFilterDrawer({
7878
data,
7979
onApplyFilters,
8080
}: WorkflowListFilterDrawerProps) {

frontend/relay-workflows-lib/lib/views/SingleWorkflowView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import BaseSingleWorkflowView from "./BaseSingleWorkflowView";
77
import { graphql } from "react-relay";
88
import { useState } from "react";
99

10-
const SingleWorkflowViewQuery = graphql`
10+
export const SingleWorkflowViewQuery = graphql`
1111
query SingleWorkflowViewQuery($visit: VisitInput!, $name: String!) {
1212
workflow(visit: $visit, name: $name) {
1313
status {

frontend/relay-workflows-lib/lib/views/TemplateView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { TemplateViewMutation } from "./__generated__/TemplateViewMutation.graph
1111
import { TemplateViewQuery as TemplateViewQueryType } from "./__generated__/TemplateViewQuery.graphql";
1212
import { SubmissionFormParametersFragment$key } from "../components/__generated__/SubmissionFormParametersFragment.graphql";
1313

14-
const TemplateViewQuery = graphql`
14+
export const TemplateViewQuery = graphql`
1515
query TemplateViewQuery($templateName: String!) {
1616
workflowTemplate(name: $templateName) {
1717
...SubmissionFormFragment

frontend/relay-workflows-lib/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"dev": "vite",
99
"build": "tsc --build && vite build",
1010
"preview": "vite preview",
11-
"relay": "relay-compiler"
11+
"relay": "relay-compiler",
12+
"storybook": "storybook dev -p 6006",
13+
"build-storybook": "storybook build"
1214
},
1315
"dependencies": {
1416
"@types/relay-test-utils": "^19.0.0",

frontend/relay-workflows-lib/relay.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"src": "./lib",
2+
"src": "./",
33
"language": "typescript",
44
"schema": "./supergraph.graphql",
55
"exclude": ["**/node_modules/**", "**/__mocks__/**", "**/__generated__/**"],
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Meta, StoryObj } from "@storybook/react";
2+
import {
3+
RelayEnvironmentProvider,
4+
useFragment,
5+
useLazyLoadQuery,
6+
} from "react-relay";
7+
import { ThemeProvider, DiamondTheme } from "@diamondlightsource/sci-react-ui";
8+
import { MemoryRouter } from "react-router-dom";
9+
import React, { ReactElement } from "react";
10+
import { getRelayEnvironment } from "dashboard/src/RelayEnvironment";
11+
import { WorkflowsListViewQuery } from "../../lib/views/WorkflowsListView";
12+
import { WorkflowsListViewQuery$data } from "../../lib/views/__generated__/WorkflowsListViewQuery.graphql";
13+
import { WorkflowsContentFragment$key } from "../../lib/components/__generated__/WorkflowsContentFragment.graphql";
14+
import { WorkflowsContentFragment } from "../../lib/components/WorkflowsContent";
15+
import BaseWorkflowRelay from "../../lib/components/BaseWorkflowRelay";
16+
import { WorkflowRelayFragment$key } from "../../lib/components/__generated__/WorkflowRelayFragment.graphql";
17+
import { WorkflowRelayFragment } from "../../lib/components/WorkflowRelay";
18+
19+
const environment = await getRelayEnvironment();
20+
21+
const Wrapper = ({ children }: { children: ReactElement }) => {
22+
const queryData = useLazyLoadQuery(
23+
WorkflowsListViewQuery,
24+
{},
25+
) as WorkflowsListViewQuery$data;
26+
const workflowsData = useFragment<WorkflowsContentFragment$key>(
27+
WorkflowsContentFragment,
28+
queryData.workflows,
29+
);
30+
const data = useFragment<WorkflowRelayFragment$key>(
31+
WorkflowRelayFragment,
32+
workflowsData.nodes[1],
33+
);
34+
return React.cloneElement(children, {
35+
fragmentRef: data,
36+
});
37+
};
38+
39+
const meta: Meta<typeof BaseWorkflowRelay> = {
40+
component: BaseWorkflowRelay,
41+
title: "BaseWorkflowRelay",
42+
tags: ["autodocs"],
43+
parameters: {
44+
docs: {
45+
description: {
46+
component: "Render base version of workflow relay",
47+
},
48+
},
49+
},
50+
decorators: [
51+
(Story) => (
52+
<RelayEnvironmentProvider environment={environment}>
53+
<ThemeProvider theme={DiamondTheme} defaultMode="light">
54+
<MemoryRouter initialEntries={["/"]}>
55+
<Story />
56+
</MemoryRouter>
57+
</ThemeProvider>
58+
</RelayEnvironmentProvider>
59+
),
60+
],
61+
} satisfies Meta<typeof BaseWorkflowRelay>;
62+
63+
export default meta;
64+
type Story = StoryObj<typeof meta>;
65+
66+
export const Example: Story = {
67+
render: (args) => (
68+
<Wrapper>
69+
<BaseWorkflowRelay {...args} />
70+
</Wrapper>
71+
),
72+
};
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { Meta, StoryObj } from "@storybook/react";
2+
import { RenderSubmittedMessage } from "../../lib/components/RenderSubmittedMessage";
3+
import { RelayEnvironmentProvider, useLazyLoadQuery } from "react-relay";
4+
import { getRelayEnvironment } from "dashboard/src/RelayEnvironment";
5+
import { ThemeProvider, DiamondTheme } from "@diamondlightsource/sci-react-ui";
6+
import { MemoryRouter } from "react-router-dom";
7+
import React, { ReactElement } from "react";
8+
import { MockRenderSubmittedMessageQuery } from "../mock-queries/MockRenderSubmittedMessageQuery";
9+
import { MockRenderSubmittedMessageQuery$data } from "../mock-queries/__generated__/MockRenderSubmittedMessageQuery.graphql";
10+
11+
const environment = await getRelayEnvironment();
12+
13+
const Wrapper = ({
14+
name,
15+
children,
16+
...props
17+
}: {
18+
name: string;
19+
children: ReactElement;
20+
}) => {
21+
const data = useLazyLoadQuery(MockRenderSubmittedMessageQuery, {
22+
name,
23+
}) as MockRenderSubmittedMessageQuery$data;
24+
return React.cloneElement(children, { ...props, fragmentRef: data.workflow });
25+
};
26+
27+
const meta: Meta<typeof RenderSubmittedMessage> = {
28+
component: RenderSubmittedMessage,
29+
title: "RenderSubmittedMessage",
30+
tags: ["autodocs"],
31+
parameters: {
32+
docs: {
33+
description: {
34+
component: "Render message",
35+
},
36+
},
37+
},
38+
decorators: [
39+
(Story) => (
40+
<RelayEnvironmentProvider environment={environment}>
41+
<ThemeProvider theme={DiamondTheme} defaultMode="light">
42+
<MemoryRouter initialEntries={["/"]}>
43+
<Story />
44+
</MemoryRouter>
45+
</ThemeProvider>
46+
</RelayEnvironmentProvider>
47+
),
48+
],
49+
} satisfies Meta<typeof RenderSubmittedMessage>;
50+
51+
export default meta;
52+
type Story = StoryObj<typeof meta>;
53+
54+
export const unknownStatus: Story = {
55+
render: (args) => (
56+
<Wrapper name="workflow-name">
57+
<RenderSubmittedMessage {...args} />
58+
</Wrapper>
59+
),
60+
args: {
61+
result: {
62+
type: "success",
63+
message: "workflow-name",
64+
},
65+
},
66+
};
67+
68+
export const completedWorkflow: Story = {
69+
render: (args) => (
70+
<Wrapper name="completed-workflow">
71+
<RenderSubmittedMessage {...args} />
72+
</Wrapper>
73+
),
74+
args: {
75+
result: {
76+
type: "success",
77+
message: "completed-workflow",
78+
},
79+
},
80+
};
81+
82+
export const runningWorkflow: Story = {
83+
render: (args) => (
84+
<Wrapper name="running-workflow">
85+
<RenderSubmittedMessage {...args} />
86+
</Wrapper>
87+
),
88+
args: {
89+
result: {
90+
type: "success",
91+
message: "running-workflow",
92+
},
93+
},
94+
};
95+
96+
export const pendingWorkflow: Story = {
97+
render: (args) => (
98+
<Wrapper name="pending-workflow">
99+
<RenderSubmittedMessage {...args} />
100+
</Wrapper>
101+
),
102+
args: {
103+
result: {
104+
type: "success",
105+
message: "pending-workflow",
106+
},
107+
},
108+
};
109+
110+
export const erroredWorkflow: Story = {
111+
render: (args) => (
112+
<Wrapper name="errored-workflow">
113+
<RenderSubmittedMessage {...args} />
114+
</Wrapper>
115+
),
116+
args: {
117+
result: {
118+
type: "success",
119+
message: "errored-workflow",
120+
},
121+
},
122+
};
123+
124+
export const networkError: Story = {
125+
args: {
126+
result: {
127+
type: "networkError",
128+
error: {
129+
name: "404",
130+
message: "Network Error",
131+
},
132+
},
133+
},
134+
};
135+
136+
export const graphqlError: Story = {
137+
args: {
138+
result: {
139+
type: "graphQLError",
140+
errors: [{ message: "GraphQL Error" }],
141+
},
142+
},
143+
};

0 commit comments

Comments
 (0)