Skip to content

Commit 6b37868

Browse files
committed
Add templates table
1 parent c76d68c commit 6b37868

File tree

3 files changed

+108
-62
lines changed

3 files changed

+108
-62
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentMeta, Story } from "@storybook/react"
2+
import React from "react"
3+
import { MockOrganization, MockTemplate } from "../../testHelpers/entities"
4+
import { TemplatesTable, TemplatesTableProps } from "./TemplatesTable"
5+
6+
export default {
7+
title: "components/TemplatesTable",
8+
component: TemplatesTable,
9+
} as ComponentMeta<typeof TemplatesTable>
10+
11+
const Template: Story<TemplatesTableProps> = (args) => <TemplatesTable {...args} />
12+
13+
export const Example = Template.bind({})
14+
Example.args = {
15+
templates: [MockTemplate],
16+
organizations: [MockOrganization],
17+
}
18+
19+
export const Empty = Template.bind({})
20+
Empty.args = {
21+
templates: [],
22+
organizations: [],
23+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import Box from "@material-ui/core/Box"
2+
import Table from "@material-ui/core/Table"
3+
import TableBody from "@material-ui/core/TableBody"
4+
import TableCell from "@material-ui/core/TableCell"
5+
import TableHead from "@material-ui/core/TableHead"
6+
import TableRow from "@material-ui/core/TableRow"
7+
import React from "react"
8+
import { Link } from "react-router-dom"
9+
import * as TypesGen from "../../api/typesGenerated"
10+
import { CodeExample } from "../../components/CodeExample/CodeExample"
11+
import { EmptyState } from "../../components/EmptyState/EmptyState"
12+
import { TableHeaderRow } from "../../components/TableHeaders/TableHeaders"
13+
import { TableLoader } from "../../components/TableLoader/TableLoader"
14+
import { TableTitle } from "../../components/TableTitle/TableTitle"
15+
16+
export const Language = {
17+
title: "Templates",
18+
tableTitle: "All templates",
19+
nameLabel: "Name",
20+
emptyMessage: "No templates have been created yet",
21+
emptyDescription: "Run the following command to get started:",
22+
totalLabel: "total",
23+
}
24+
25+
export interface TemplatesTableProps {
26+
templates?: TypesGen.Template[]
27+
organizations?: TypesGen.Organization[]
28+
}
29+
30+
export const TemplatesTable: React.FC<TemplatesTableProps> = ({ templates, organizations }) => {
31+
const isLoading = !templates || !organizations
32+
33+
// Create a dictionary of organization ID -> organization Name
34+
// Needed to properly construct links to dive into a template
35+
const orgDictionary =
36+
organizations &&
37+
organizations.reduce((acc: Record<string, string>, curr: TypesGen.Organization) => {
38+
return {
39+
...acc,
40+
[curr.id]: curr.name,
41+
}
42+
}, {})
43+
44+
return (
45+
<Table>
46+
<TableHead>
47+
<TableTitle title={Language.tableTitle} />
48+
<TableHeaderRow>
49+
<TableCell size="small">{Language.nameLabel}</TableCell>
50+
</TableHeaderRow>
51+
</TableHead>
52+
<TableBody>
53+
{isLoading && <TableLoader />}
54+
{templates &&
55+
organizations &&
56+
orgDictionary &&
57+
templates.map((t) => (
58+
<TableRow key={t.id}>
59+
<TableCell>
60+
<Link to={`/templates/${orgDictionary[t.organization_id]}/${t.name}`}>{t.name}</Link>
61+
</TableCell>
62+
</TableRow>
63+
))}
64+
65+
{templates && templates.length === 0 && (
66+
<TableRow>
67+
<TableCell colSpan={999}>
68+
<Box p={4}>
69+
<EmptyState
70+
message={Language.emptyMessage}
71+
description={Language.emptyDescription}
72+
cta={<CodeExample code="coder templates create" />}
73+
/>
74+
</Box>
75+
</TableCell>
76+
</TableRow>
77+
)}
78+
</TableBody>
79+
</Table>
80+
)
81+
}

site/src/pages/TemplatesPages/TemplatesPage.tsx

Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
1-
import Box from "@material-ui/core/Box"
2-
import Table from "@material-ui/core/Table"
3-
import TableBody from "@material-ui/core/TableBody"
4-
import TableCell from "@material-ui/core/TableCell"
5-
import TableHead from "@material-ui/core/TableHead"
6-
import TableRow from "@material-ui/core/TableRow"
71
import React from "react"
8-
import { Link } from "react-router-dom"
92
import useSWR from "swr"
103
import * as TypesGen from "../../api/typesGenerated"
11-
import { CodeExample } from "../../components/CodeExample/CodeExample"
12-
import { EmptyState } from "../../components/EmptyState/EmptyState"
134
import { ErrorSummary } from "../../components/ErrorSummary/ErrorSummary"
145
import { Header } from "../../components/Header/Header"
156
import { Margins } from "../../components/Margins/Margins"
167
import { Stack } from "../../components/Stack/Stack"
17-
import { TableHeaderRow } from "../../components/TableHeaders/TableHeaders"
18-
import { TableLoader } from "../../components/TableLoader/TableLoader"
19-
import { TableTitle } from "../../components/TableTitle/TableTitle"
8+
import { TemplatesTable } from "../../components/TemplatesTable/TemplatesTable"
209

2110
export const Language = {
2211
title: "Templates",
@@ -29,66 +18,19 @@ export const Language = {
2918

3019
export const TemplatesPage: React.FC = () => {
3120
const { data: orgs, error: orgsError } = useSWR<TypesGen.Organization[], Error>("/api/v2/users/me/organizations")
32-
const { data: templates, error } = useSWR<TypesGen.Template[] | null, Error>(
33-
orgs ? `/api/v2/organizations/${orgs[0].id}/templates` : null,
21+
const { data: templates, error } = useSWR<TypesGen.Template[] | undefined, Error>(
22+
orgs ? `/api/v2/organizations/${orgs[0].id}/templates` : undefined,
3423
)
35-
const isLoading = !templates || !orgs
3624
const subTitle = templates ? `${templates.length} ${Language.totalLabel}` : undefined
3725
const hasError = orgsError || error
38-
// Create a dictionary of organization ID -> organization Name
39-
// Needed to properly construct links to dive into a template
40-
const orgDictionary =
41-
orgs &&
42-
orgs.reduce((acc: Record<string, string>, curr: TypesGen.Organization) => {
43-
return {
44-
...acc,
45-
[curr.id]: curr.name,
46-
}
47-
}, {})
4826

4927
return (
5028
<Stack spacing={4}>
5129
<Header title={Language.title} subTitle={subTitle} />
5230
<Margins>
5331
{error && <ErrorSummary error={error} />}
5432
{orgsError && <ErrorSummary error={orgsError} />}
55-
{!hasError && (
56-
<Table>
57-
<TableHead>
58-
<TableTitle title={Language.tableTitle} />
59-
<TableHeaderRow>
60-
<TableCell size="small">{Language.nameLabel}</TableCell>
61-
</TableHeaderRow>
62-
</TableHead>
63-
<TableBody>
64-
{isLoading && <TableLoader />}
65-
{templates &&
66-
orgs &&
67-
orgDictionary &&
68-
templates.map((t) => (
69-
<TableRow key={t.id}>
70-
<TableCell>
71-
<Link to={`/templates/${orgDictionary[t.organization_id]}/${t.name}`}>{t.name}</Link>
72-
</TableCell>
73-
</TableRow>
74-
))}
75-
76-
{templates && templates.length === 0 && (
77-
<TableRow>
78-
<TableCell colSpan={999}>
79-
<Box p={4}>
80-
<EmptyState
81-
message={Language.emptyMessage}
82-
description={Language.emptyDescription}
83-
cta={<CodeExample code="coder templates create" />}
84-
/>
85-
</Box>
86-
</TableCell>
87-
</TableRow>
88-
)}
89-
</TableBody>
90-
</Table>
91-
)}
33+
{!hasError && <TemplatesTable organizations={orgs} templates={templates} />}
9234
</Margins>
9335
</Stack>
9436
)

0 commit comments

Comments
 (0)