Skip to content

Commit 388e85a

Browse files
committed
feat: client side org filtering
1 parent 340f9a6 commit 388e85a

File tree

8 files changed

+80
-70
lines changed

8 files changed

+80
-70
lines changed

site/src/api/queries/templates.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ export const templatesByOrganizationId = (
4747
};
4848
};
4949

50-
export const templates = (config: TemplateFilter = {}) => {
50+
export const templates = (filter: TemplateFilter = {}) => {
5151
return {
52-
queryKey: ["templates", config],
53-
queryFn: () => API.getTemplates(config),
52+
queryKey: ["templates", filter],
53+
queryFn: () => API.getTemplates(filter),
5454
};
5555
};
5656

site/src/pages/StarterTemplatesPage/StarterTemplatesPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { templateExamples } from "api/queries/templates";
55
import type { TemplateExample } from "api/typesGenerated";
66
import { useDashboard } from "modules/dashboard/useDashboard";
77
import { pageTitle } from "utils/page";
8-
import { getTemplatesByTag } from "utils/starterTemplates";
8+
import { getTemplatesByTag } from "utils/templateAggregators";
99
import { StarterTemplatesPageView } from "./StarterTemplatesPageView";
1010

1111
const StarterTemplatesPage: FC = () => {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
MockTemplateExample,
66
MockTemplateExample2,
77
} from "testHelpers/entities";
8-
import { getTemplatesByTag } from "utils/starterTemplates";
8+
import { getTemplatesByTag } from "utils/templateAggregators";
99
import { StarterTemplatesPageView } from "./StarterTemplatesPageView";
1010

1111
const meta: Meta<typeof StarterTemplatesPageView> = {

site/src/pages/StarterTemplatesPage/StarterTemplatesPageView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from "components/PageHeader/PageHeader";
1212
import { Stack } from "components/Stack/Stack";
1313
import { TemplateExampleCard } from "modules/templates/TemplateExampleCard/TemplateExampleCard";
14-
import type { StarterTemplatesByTag } from "utils/starterTemplates";
14+
import type { StarterTemplatesByTag } from "utils/templateAggregators";
1515

1616
const getTagLabel = (tag: string) => {
1717
const labelByTag: Record<string, string> = {

site/src/pages/TemplatesPage/MultiOrgTemplatePage/TemplatesPageView.stories.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
MockTemplateExample,
77
MockTemplateExample2,
88
} from "testHelpers/entities";
9+
import { getTemplatesByOrg } from "utils/templateAggregators";
910
import { TemplatesPageView } from "./TemplatesPageView";
1011

1112
const meta: Meta<typeof TemplatesPageView> = {
@@ -21,7 +22,7 @@ export const WithTemplates: Story = {
2122
args: {
2223
canCreateTemplates: true,
2324
error: undefined,
24-
templates: [
25+
templatesByOrg: getTemplatesByOrg([
2526
MockTemplate,
2627
{
2728
...MockTemplate,
@@ -62,7 +63,7 @@ export const WithTemplates: Story = {
6263
display_name: "Deprecated",
6364
description: "Template is incompatible",
6465
},
65-
],
66+
]),
6667
examples: [],
6768
},
6869
};
@@ -71,15 +72,15 @@ export const EmptyCanCreate: Story = {
7172
args: {
7273
canCreateTemplates: true,
7374
error: undefined,
74-
templates: [],
75+
templatesByOrg: getTemplatesByOrg([]),
7576
examples: [MockTemplateExample, MockTemplateExample2],
7677
},
7778
};
7879

7980
export const EmptyCannotCreate: Story = {
8081
args: {
8182
error: undefined,
82-
templates: [],
83+
templatesByOrg: getTemplatesByOrg([]),
8384
examples: [MockTemplateExample, MockTemplateExample2],
8485
canCreateTemplates: false,
8586
},
@@ -90,7 +91,7 @@ export const Error: Story = {
9091
error: mockApiError({
9192
message: "Something went wrong fetching templates.",
9293
}),
93-
templates: undefined,
94+
templatesByOrg: undefined,
9495
examples: undefined,
9596
canCreateTemplates: false,
9697
},

site/src/pages/TemplatesPage/MultiOrgTemplatePage/TemplatesPageView.tsx

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Interpolation, Theme } from "@emotion/react";
22
import type { FC } from "react";
3-
import { Link, useNavigate } from "react-router-dom";
4-
import type { Template, TemplateExample } from "api/typesGenerated";
3+
import { Link, useNavigate, useSearchParams } from "react-router-dom";
4+
import type { TemplateExample } from "api/typesGenerated";
55
import { ErrorAlert } from "components/Alert/ErrorAlert";
66
import {
77
HelpTooltip,
@@ -12,6 +12,7 @@ import {
1212
HelpTooltipTitle,
1313
HelpTooltipTrigger,
1414
} from "components/HelpTooltip/HelpTooltip";
15+
import { Loader } from "components/Loader/Loader";
1516
import { Margins } from "components/Margins/Margins";
1617
import {
1718
PageHeader,
@@ -21,6 +22,7 @@ import {
2122
import { Stack } from "components/Stack/Stack";
2223
import { TemplateCard } from "modules/templates/TemplateCard/TemplateCard";
2324
import { docs } from "utils/docs";
25+
import type { TemplatesByOrg } from "utils/templateAggregators";
2426
import { CreateTemplateButton } from "../CreateTemplateButton";
2527
import { EmptyTemplates } from "../EmptyTemplates";
2628

@@ -49,51 +51,32 @@ const TemplateHelpTooltip: FC = () => {
4951
};
5052

5153
export interface TemplatesPageViewProps {
52-
templates: Template[] | undefined;
54+
templatesByOrg?: TemplatesByOrg;
5355
examples: TemplateExample[] | undefined;
5456
canCreateTemplates: boolean;
55-
query: string | undefined;
5657
error?: unknown;
5758
}
5859

59-
export type TemplatesByOrg = Record<
60-
string,
61-
{ displayName: string; count: number }
62-
>;
63-
64-
const getTemplatesByOrg = (templates: Template[]): TemplatesByOrg => {
65-
const orgs: TemplatesByOrg = {
66-
all: { displayName: "All Organizations", count: 0 },
67-
};
68-
69-
templates.forEach((template) => {
70-
if (orgs[template.organization_name]) {
71-
orgs[template.organization_name].count += 1;
72-
} else {
73-
orgs[template.organization_name] = {
74-
displayName: template.organization_display_name,
75-
count: 1,
76-
};
77-
}
78-
79-
orgs.all.count += 1;
80-
});
81-
82-
return orgs;
60+
const sortOrgs = (templatesByOrg: TemplatesByOrg) => {
61+
return templatesByOrg
62+
? Object.keys(templatesByOrg).sort((a, b) => a.localeCompare(b))
63+
: undefined;
8364
};
8465

8566
export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
86-
templates,
67+
templatesByOrg,
8768
examples,
8869
canCreateTemplates,
89-
query,
9070
error,
9171
}) => {
9272
const navigate = useNavigate();
93-
const isEmpty = templates && templates.length === 0;
94-
const q = query?.split(":") || [];
95-
const activeOrg = q[0] === "organization" ? query?.split(":")[1] : "all";
96-
const templatesByOrg = getTemplatesByOrg(templates ?? []);
73+
const [urlParams] = useSearchParams();
74+
const isEmpty = templatesByOrg && templatesByOrg["all"].length === 0;
75+
const orgs = templatesByOrg ? sortOrgs(templatesByOrg) : undefined;
76+
const activeOrg = urlParams.get("org") ?? "all";
77+
const visibleTemplates = templatesByOrg
78+
? templatesByOrg[activeOrg]
79+
: undefined;
9780

9881
return (
9982
<Margins>
@@ -108,7 +91,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
10891
<TemplateHelpTooltip />
10992
</Stack>
11093
</PageHeaderTitle>
111-
{templates && templates.length > 0 && (
94+
{!isEmpty && (
11295
<PageHeaderSubtitle>
11396
Select a template to create a workspace.
11497
</PageHeaderSubtitle>
@@ -119,19 +102,28 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
119102
<ErrorAlert error={error} css={{ marginBottom: 32 }} />
120103
)}
121104

105+
{Boolean(!templatesByOrg) && <Loader />}
106+
122107
<Stack direction="row" spacing={4} alignItems="flex-start">
123-
<Stack css={{ width: 208, flexShrink: 0, position: "sticky", top: 48 }}>
124-
<span css={styles.filterCaption}>ORGANIZATION</span>
125-
{Object.entries(templatesByOrg).map(([key, value]) => (
126-
<Link
127-
key={key}
128-
to={key !== "all" ? `?filter=organization:${key}` : "?"}
129-
css={[styles.tagLink, key === activeOrg && styles.tagLinkActive]}
130-
>
131-
{value.displayName} ({value.count ?? 0})
132-
</Link>
133-
))}
134-
</Stack>
108+
{templatesByOrg && orgs && (
109+
<Stack
110+
css={{ width: 208, flexShrink: 0, position: "sticky", top: 48 }}
111+
>
112+
<span css={styles.filterCaption}>ORGANIZATION</span>
113+
{orgs.map((org) => (
114+
<Link
115+
key={org}
116+
to={`?org=${org}`}
117+
css={[
118+
styles.tagLink,
119+
org === activeOrg && styles.tagLinkActive,
120+
]}
121+
>
122+
{org} ({templatesByOrg[org].length})
123+
</Link>
124+
))}
125+
</Stack>
126+
)}
135127

136128
<div
137129
css={{
@@ -147,8 +139,8 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
147139
examples={examples ?? []}
148140
/>
149141
) : (
150-
templates &&
151-
templates.map((template) => (
142+
visibleTemplates &&
143+
visibleTemplates.map((template) => (
152144
<TemplateCard
153145
css={(theme) => ({
154146
backgroundColor: theme.palette.background.paper,

site/src/pages/TemplatesPage/TemplatesPage.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
import type { FC } from "react";
22
import { Helmet } from "react-helmet-async";
33
import { useQuery } from "react-query";
4-
import { useSearchParams } from "react-router-dom";
54
import {
65
templateExamples,
76
templatesByOrganizationId,
87
templates,
98
} from "api/queries/templates";
109
import { useAuthenticated } from "contexts/auth/RequireAuth";
1110
import { useDashboard } from "modules/dashboard/useDashboard";
12-
import { filterParamsKey } from "utils/filters";
1311
import { pageTitle } from "utils/page";
12+
import { getTemplatesByOrg } from "utils/templateAggregators";
1413
import { TemplatesPageView as MultiOrgTemplatesPageView } from "./MultiOrgTemplatePage/TemplatesPageView";
1514
import { TemplatesPageView } from "./TemplatePage/TemplatesPageView";
1615

1716
export const TemplatesPage: FC = () => {
1817
const { permissions } = useAuthenticated();
1918
const { organizationId, experiments } = useDashboard();
20-
const [searchParams] = useSearchParams();
21-
const query = searchParams.get(filterParamsKey) || undefined;
2219

2320
const templatesByOrganizationIdQuery = useQuery(
2421
templatesByOrganizationId(organizationId),
2522
);
26-
const templatesQuery = useQuery(templates({ q: query }));
23+
const templatesQuery = useQuery(templates());
24+
const templatesByOrg = templatesQuery.data
25+
? getTemplatesByOrg(templatesQuery.data)
26+
: undefined;
2727
const examplesQuery = useQuery({
2828
...templateExamples(organizationId),
2929
enabled: permissions.createTemplates,
@@ -41,11 +41,10 @@ export const TemplatesPage: FC = () => {
4141
</Helmet>
4242
{multiOrgExperimentEnabled ? (
4343
<MultiOrgTemplatesPageView
44-
error={error}
45-
canCreateTemplates={permissions.createTemplates}
44+
templatesByOrg={templatesByOrg}
4645
examples={examplesQuery.data}
47-
templates={templatesQuery.data}
48-
query={query}
46+
canCreateTemplates={permissions.createTemplates}
47+
error={error}
4948
/>
5049
) : (
5150
<TemplatesPageView

site/src/utils/starterTemplates.ts renamed to site/src/utils/templateAggregators.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import type { TemplateExample } from "api/typesGenerated";
1+
import type { Template, TemplateExample } from "api/typesGenerated";
22

33
export type StarterTemplatesByTag = Record<string, TemplateExample[]>;
4+
export type TemplatesByOrg = Record<string, Template[]>;
45

56
export const getTemplatesByTag = (
67
templates: TemplateExample[],
@@ -22,3 +23,20 @@ export const getTemplatesByTag = (
2223

2324
return tags;
2425
};
26+
27+
export const getTemplatesByOrg = (templates: Template[]): TemplatesByOrg => {
28+
const orgs: TemplatesByOrg = {
29+
all: templates,
30+
};
31+
32+
templates.forEach((template) => {
33+
const org = template.organization_name;
34+
if (orgs[org]) {
35+
orgs[org].push(template);
36+
} else {
37+
orgs[org] = [template];
38+
}
39+
});
40+
41+
return orgs;
42+
};

0 commit comments

Comments
 (0)