Skip to content

Commit 6b80b33

Browse files
committed
chore: handle merge conflicts
1 parent bcef49f commit 6b80b33

File tree

4 files changed

+184
-94
lines changed

4 files changed

+184
-94
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { screen, userEvent } from "@storybook/test";
3+
import { CreateTemplateButton } from "./CreateTemplateButton";
4+
5+
const meta: Meta<typeof CreateTemplateButton> = {
6+
title: "pages/TemplatesPage/CreateTemplateButton",
7+
component: CreateTemplateButton,
8+
};
9+
10+
export default meta;
11+
type Story = StoryObj<typeof CreateTemplateButton>;
12+
13+
export const Close: Story = {};
14+
15+
export const Open: Story = {
16+
play: async ({ step }) => {
17+
const user = userEvent.setup();
18+
await step("click on trigger", async () => {
19+
await user.click(screen.getByRole("button"));
20+
});
21+
},
22+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import AddIcon from "@mui/icons-material/AddOutlined";
2+
import Inventory2 from "@mui/icons-material/Inventory2";
3+
import NoteAddOutlined from "@mui/icons-material/NoteAddOutlined";
4+
import UploadOutlined from "@mui/icons-material/UploadOutlined";
5+
import Button from "@mui/material/Button";
6+
import {
7+
MoreMenu,
8+
MoreMenuContent,
9+
MoreMenuItem,
10+
MoreMenuTrigger,
11+
} from "components/MoreMenu/MoreMenu";
12+
import type { FC } from "react";
13+
14+
type CreateTemplateButtonProps = {
15+
onNavigate: (path: string) => void;
16+
};
17+
18+
export const CreateTemplateButton: FC<CreateTemplateButtonProps> = ({
19+
onNavigate,
20+
}) => {
21+
return (
22+
<MoreMenu>
23+
<MoreMenuTrigger>
24+
<Button startIcon={<AddIcon />} variant="contained">
25+
Create Template
26+
</Button>
27+
</MoreMenuTrigger>
28+
<MoreMenuContent>
29+
<MoreMenuItem
30+
onClick={() => {
31+
onNavigate("/templates/new?exampleId=scratch");
32+
}}
33+
>
34+
<NoteAddOutlined />
35+
From scratch
36+
</MoreMenuItem>
37+
<MoreMenuItem
38+
onClick={() => {
39+
onNavigate("/templates/new");
40+
}}
41+
>
42+
<UploadOutlined />
43+
Upload template
44+
</MoreMenuItem>
45+
<MoreMenuItem
46+
onClick={() => {
47+
onNavigate("/starter-templates");
48+
}}
49+
>
50+
<Inventory2 />
51+
Choose a starter template
52+
</MoreMenuItem>
53+
</MoreMenuContent>
54+
</MoreMenu>
55+
);
56+
};

site/src/pages/TemplatesPage/TemplatesPage.test.tsx

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,37 @@ import { RequireAuth } from "contexts/auth/RequireAuth";
66
import TemplatesPage from "./TemplatesPage";
77

88
test("create template from scratch", async () => {
9-
const user = userEvent.setup();
10-
const router = createMemoryRouter(
11-
[
12-
{
13-
element: <RequireAuth />,
14-
children: [
15-
{
16-
path: "/templates",
17-
element: <TemplatesPage />,
18-
},
19-
{
20-
path: "/starter-templates",
21-
element: <div data-testid="new-template-page" />,
22-
},
23-
],
24-
},
25-
],
26-
{ initialEntries: ["/templates"] },
27-
);
28-
render(
29-
<AppProviders>
30-
<RouterProvider router={router} />
31-
</AppProviders>,
32-
);
33-
const createTemplateButton = await screen.findByRole("button", {
34-
name: "Create Template",
35-
});
36-
await user.click(createTemplateButton);
37-
await screen.findByTestId("new-template-page");
38-
expect(router.state.location.pathname).toBe("/starter-templates");
9+
const user = userEvent.setup();
10+
const router = createMemoryRouter(
11+
[
12+
{
13+
element: <RequireAuth />,
14+
children: [
15+
{
16+
path: "/templates",
17+
element: <TemplatesPage />,
18+
},
19+
{
20+
path: "/templates/new",
21+
element: <div data-testid="new-template-page" />,
22+
},
23+
],
24+
},
25+
],
26+
{ initialEntries: ["/templates"] },
27+
);
28+
render(
29+
<AppProviders>
30+
<RouterProvider router={router} />
31+
</AppProviders>,
32+
);
33+
const createTemplateButton = await screen.findByRole("button", {
34+
name: "Create Template",
35+
});
36+
await user.click(createTemplateButton);
37+
const fromScratchMenuItem = await screen.findByText("From scratch");
38+
await user.click(fromScratchMenuItem);
39+
await screen.findByTestId("new-template-page");
40+
expect(router.state.location.pathname).toBe("/templates/new");
41+
expect(router.state.location.search).toBe("?exampleId=scratch");
3942
});

site/src/pages/TemplatesPage/TemplatesPageView.tsx

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ import {
3838
TableRowSkeleton,
3939
} from "components/TableLoader/TableLoader";
4040
import { useClickableTableRow } from "hooks/useClickableTableRow";
41+
import { useDashboard } from "modules/dashboard/useDashboard";
4142
import { linkToTemplate, useLinks } from "modules/navigation";
4243
import { createDayString } from "utils/createDayString";
4344
import { docs } from "utils/docs";
4445
import {
4546
formatTemplateBuildTime,
4647
formatTemplateActiveDevelopers,
4748
} from "utils/templates";
49+
import { CreateTemplateButton } from "./CreateTemplateButton";
4850
import { EmptyTemplates } from "./EmptyTemplates";
4951

5052
export const Language = {
@@ -167,73 +169,80 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
167169
examples,
168170
canCreateTemplates,
169171
}) => {
170-
const isLoading = !templates;
171-
const isEmpty = templates && templates.length === 0;
172-
const navigate = useNavigate();
172+
const { experiments } = useDashboard();
173+
const isLoading = !templates;
174+
const isEmpty = templates && templates.length === 0;
175+
const navigate = useNavigate();
176+
const multiOrgExperimentEnabled = experiments.includes("multi-organization");
173177

174-
return (
175-
<Margins>
176-
<PageHeader
177-
actions={
178-
canCreateTemplates && (
179-
<Button
180-
startIcon={<AddIcon />}
181-
variant="contained"
182-
onClick={() => {
183-
navigate("/starter-templates");
184-
}}
185-
>
186-
Create Template
187-
</Button>
188-
)
189-
}
190-
>
191-
<PageHeaderTitle>
192-
<Stack spacing={1} direction="row" alignItems="center">
193-
Templates
194-
<TemplateHelpTooltip />
195-
</Stack>
196-
</PageHeaderTitle>
197-
{templates && templates.length > 0 && (
198-
<PageHeaderSubtitle>
199-
Select a template to create a workspace.
200-
</PageHeaderSubtitle>
201-
)}
202-
</PageHeader>
178+
const createTemplateAction = () => {
179+
return multiOrgExperimentEnabled ? (
180+
<Button
181+
startIcon={<AddIcon />}
182+
variant="contained"
183+
onClick={() => {
184+
navigate("/starter-templates");
185+
}}
186+
>
187+
Create Template
188+
</Button>
189+
) : (
190+
<CreateTemplateButton onNavigate={navigate} />
191+
);
192+
};
203193

204-
{error ? (
205-
<ErrorAlert error={error} />
206-
) : (
207-
<TableContainer>
208-
<Table>
209-
<TableHead>
210-
<TableRow>
211-
<TableCell width="35%">{Language.nameLabel}</TableCell>
212-
<TableCell width="15%">{Language.usedByLabel}</TableCell>
213-
<TableCell width="10%">{Language.buildTimeLabel}</TableCell>
214-
<TableCell width="15%">{Language.lastUpdatedLabel}</TableCell>
215-
<TableCell width="1%"></TableCell>
216-
</TableRow>
217-
</TableHead>
218-
<TableBody>
219-
{isLoading && <TableLoader />}
194+
return (
195+
<Margins>
196+
<PageHeader actions={canCreateTemplates && createTemplateAction()}>
197+
<PageHeaderTitle>
198+
<Stack spacing={1} direction="row" alignItems="center">
199+
Templates
200+
<TemplateHelpTooltip />
201+
</Stack>
202+
</PageHeaderTitle>
203+
<PageHeaderSubtitle>
204+
Select a template to create a workspace.
205+
</PageHeaderSubtitle>
206+
</PageHeader>
220207

221-
{isEmpty ? (
222-
<EmptyTemplates
223-
canCreateTemplates={canCreateTemplates}
224-
examples={examples ?? []}
225-
/>
226-
) : (
227-
templates?.map((template) => (
228-
<TemplateRow key={template.id} template={template} />
229-
))
230-
)}
231-
</TableBody>
232-
</Table>
233-
</TableContainer>
234-
)}
235-
</Margins>
236-
);
208+
{error ? (
209+
<ErrorAlert error={error} />
210+
) : (
211+
<TableContainer>
212+
<Table>
213+
<TableHead>
214+
<TableRow>
215+
<TableCell width="35%">{Language.nameLabel}</TableCell>
216+
<TableCell width="15%">
217+
{Language.usedByLabel}
218+
</TableCell>
219+
<TableCell width="10%">{Language.buildTimeLabel}</TableCell>
220+
<TableCell width="15%">{Language.lastUpdatedLabel}</TableCell>
221+
<TableCell width="1%" />
222+
</TableRow>
223+
</TableHead>
224+
<TableBody>
225+
{isLoading && <TableLoader />}
226+
227+
{isEmpty ? (
228+
<EmptyTemplates
229+
canCreateTemplates={canCreateTemplates}
230+
examples={examples ?? []}
231+
/>
232+
) : (
233+
templates?.map((template) => (
234+
<TemplateRow
235+
key={template.id}
236+
template={template}
237+
/>
238+
))
239+
)}
240+
</TableBody>
241+
</Table>
242+
</TableContainer>
243+
)}
244+
</Margins>
245+
);
237246
};
238247

239248
const TableLoader: FC = () => {

0 commit comments

Comments
 (0)