Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e05d148

Browse files
committed
Add filter
1 parent e05a8dc commit e05d148

File tree

5 files changed

+81
-43
lines changed

5 files changed

+81
-43
lines changed
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
{
22
"title": "Starter Templates",
3-
"subtitle": "Pick one of the built-in templates to start using Coder"
3+
"subtitle": "Pick one of the built-in templates to start using Coder",
4+
"filterCaption": "Filter",
5+
"tags": {
6+
"all": "All templates",
7+
"digitalocean": "Digital Ocean",
8+
"aws": "AWS",
9+
"google": "Google Cloud"
10+
}
411
}

site/src/pages/StarterTemplatesPage/StarterTemplatesPageView.stories.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
MockTemplateExample,
66
MockTemplateExample2,
77
} from "testHelpers/entities"
8+
import { getTemplatesByTag } from "util/starterTemplates"
89
import {
910
StarterTemplatesPageView,
1011
StarterTemplatesPageViewProps,
@@ -24,7 +25,10 @@ Default.args = {
2425
context: {
2526
organizationId: MockOrganization.id,
2627
error: undefined,
27-
starterTemplates: [MockTemplateExample, MockTemplateExample2],
28+
starterTemplatesByTag: getTemplatesByTag([
29+
MockTemplateExample,
30+
MockTemplateExample2,
31+
]),
2832
},
2933
}
3034

@@ -35,6 +39,6 @@ Error.args = {
3539
error: makeMockApiError({
3640
message: "Error on loading the template examples",
3741
}),
38-
starterTemplates: undefined,
42+
starterTemplatesByTag: undefined,
3943
},
4044
}

site/src/pages/StarterTemplatesPage/StarterTemplatesPageView.tsx

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { makeStyles } from "@material-ui/core/styles"
2-
import { TemplateExample } from "api/typesGenerated"
32
import { AlertBanner } from "components/AlertBanner/AlertBanner"
43
import { Maybe } from "components/Conditionals/Maybe"
54
import { Loader } from "components/Loader/Loader"
@@ -12,39 +11,26 @@ import {
1211
import { Stack } from "components/Stack/Stack"
1312
import { FC } from "react"
1413
import { useTranslation } from "react-i18next"
15-
import { Link } from "react-router-dom"
14+
import { Link, useSearchParams } from "react-router-dom"
15+
import { combineClasses } from "util/combineClasses"
1616
import { StarterTemplatesContext } from "xServices/starterTemplates/starterTemplatesXService"
1717

18-
const getTagLabel = (tag: string) => {
18+
const getTagLabel = (tag: string, t: (key: string) => string) => {
1919
const labelByTag: Record<string, string> = {
20-
digitalocean: "Digital Ocean",
21-
aws: "AWS",
22-
google: "Google Cloud",
20+
all: t("tags.all"),
21+
digitalocean: t("tags.digitalocean"),
22+
aws: t("tags.aws"),
23+
google: t("tags.google"),
2324
}
24-
2525
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- this can be undefined
2626
return labelByTag[tag] ?? tag
2727
}
2828

29-
const getTemplatesByTag = (starterTemplates: TemplateExample[] | undefined) => {
30-
if (!starterTemplates) {
31-
return
32-
}
33-
34-
const tags: Record<string, TemplateExample[]> = {}
35-
starterTemplates.forEach((template) => {
36-
template.tags.forEach((tag) => {
37-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- this can be undefined
38-
if (tags[tag]) {
39-
tags[tag].push(template)
40-
} else {
41-
tags[tag] = [template]
42-
}
43-
})
44-
})
45-
return tags
29+
const selectTags = ({ starterTemplatesByTag }: StarterTemplatesContext) => {
30+
return starterTemplatesByTag
31+
? Object.keys(starterTemplatesByTag).sort((a, b) => a.localeCompare(b))
32+
: undefined
4633
}
47-
4834
export interface StarterTemplatesPageViewProps {
4935
context: StarterTemplatesContext
5036
}
@@ -53,10 +39,13 @@ export const StarterTemplatesPageView: FC<StarterTemplatesPageViewProps> = ({
5339
context,
5440
}) => {
5541
const { t } = useTranslation("starterTemplatesPage")
42+
const [urlParams] = useSearchParams()
5643
const styles = useStyles()
57-
const templatesByTag = getTemplatesByTag(context.starterTemplates)
58-
const tags = templatesByTag
59-
? Object.keys(templatesByTag).sort((a, b) => a.localeCompare(b))
44+
const { starterTemplatesByTag } = context
45+
const tags = selectTags(context)
46+
const activeTag = urlParams.get("tag") ?? "all"
47+
const visibleTemplates = starterTemplatesByTag
48+
? starterTemplatesByTag[activeTag]
6049
: undefined
6150

6251
return (
@@ -70,28 +59,32 @@ export const StarterTemplatesPageView: FC<StarterTemplatesPageViewProps> = ({
7059
<AlertBanner error={context.error} severity="error" />
7160
</Maybe>
7261

73-
<Maybe condition={Boolean(!context.starterTemplates)}>
62+
<Maybe condition={Boolean(!starterTemplatesByTag)}>
7463
<Loader />
7564
</Maybe>
7665

7766
<Stack direction="row" spacing={4}>
78-
{templatesByTag && tags && (
67+
{starterTemplatesByTag && tags && (
7968
<Stack className={styles.filter}>
80-
<span className={styles.filterCaption}>Filter</span>
81-
<Link to="" className={styles.tagLink}>
82-
All templates ({context.starterTemplates?.length})
83-
</Link>
69+
<span className={styles.filterCaption}>{t("filterCaption")}</span>
8470
{tags.map((tag) => (
85-
<Link key={tag} to={`?tag=${tag}`} className={styles.tagLink}>
86-
{getTagLabel(tag)} ({templatesByTag[tag].length})
71+
<Link
72+
key={tag}
73+
to={`?tag=${tag}`}
74+
className={combineClasses({
75+
[styles.tagLink]: true,
76+
[styles.tagLinkActive]: tag === activeTag,
77+
})}
78+
>
79+
{getTagLabel(tag, t)} ({starterTemplatesByTag[tag].length})
8780
</Link>
8881
))}
8982
</Stack>
9083
)}
9184

9285
<div className={styles.templates}>
93-
{context.starterTemplates &&
94-
context.starterTemplates.map((example) => (
86+
{visibleTemplates &&
87+
visibleTemplates.map((example) => (
9588
<Link
9689
to={example.id}
9790
className={styles.template}
@@ -117,6 +110,7 @@ export const StarterTemplatesPageView: FC<StarterTemplatesPageViewProps> = ({
117110
const useStyles = makeStyles((theme) => ({
118111
filter: {
119112
width: theme.spacing(26),
113+
flexShrink: 0,
120114
},
121115

122116
filterCaption: {
@@ -138,10 +132,17 @@ const useStyles = makeStyles((theme) => ({
138132
},
139133
},
140134

135+
tagLinkActive: {
136+
color: theme.palette.text.primary,
137+
fontWeight: 600,
138+
},
139+
141140
templates: {
141+
flex: "1",
142142
display: "grid",
143143
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
144144
gap: theme.spacing(2),
145+
gridAutoRows: "min-content",
145146
},
146147

147148
template: {
@@ -152,6 +153,7 @@ const useStyles = makeStyles((theme) => ({
152153
color: "inherit",
153154
display: "flex",
154155
alignItems: "center",
156+
height: "fit-content",
155157

156158
"&:hover": {
157159
backgroundColor: theme.palette.background.paperLight,

site/src/util/starterTemplates.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { TemplateExample } from "api/typesGenerated"
2+
3+
export type StarterTemplatesByTag = Record<string, TemplateExample[]>
4+
5+
export const getTemplatesByTag = (
6+
templates: TemplateExample[],
7+
): StarterTemplatesByTag => {
8+
const tags: StarterTemplatesByTag = {
9+
all: templates,
10+
}
11+
12+
templates.forEach((template) => {
13+
template.tags.forEach((tag) => {
14+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- this can be undefined
15+
if (tags[tag]) {
16+
tags[tag].push(template)
17+
} else {
18+
tags[tag] = [template]
19+
}
20+
})
21+
})
22+
23+
return tags
24+
}

site/src/xServices/starterTemplates/starterTemplatesXService.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { getTemplateExamples } from "api/api"
22
import { TemplateExample } from "api/typesGenerated"
3+
import { getTemplatesByTag, StarterTemplatesByTag } from "util/starterTemplates"
34
import { assign, createMachine } from "xstate"
45

56
export interface StarterTemplatesContext {
67
organizationId: string
7-
starterTemplates?: TemplateExample[]
8+
starterTemplatesByTag?: StarterTemplatesByTag
89
error?: unknown
910
}
1011

@@ -55,7 +56,7 @@ export const starterTemplatesMachine = createMachine(
5556
error: (_, { data }) => data,
5657
}),
5758
assignStarterTemplates: assign({
58-
starterTemplates: (_, { data }) => data,
59+
starterTemplatesByTag: (_, { data }) => getTemplatesByTag(data),
5960
}),
6061
},
6162
},

0 commit comments

Comments
 (0)