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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy