Skip to content

Commit d7a4be0

Browse files
committed
Add base structure for the new filter component
1 parent f149279 commit d7a4be0

File tree

3 files changed

+150
-1
lines changed

3 files changed

+150
-1
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { userEvent, within, expect } from "@storybook/test";
3+
import { useState } from "react";
4+
import { NewFilter } from "./NewFilter";
5+
6+
const meta: Meta<typeof NewFilter> = {
7+
title: "components/NewFilter",
8+
component: NewFilter,
9+
render: function NewFilterWithState(args) {
10+
const [value, setValue] = useState<string>(args.value);
11+
return <NewFilter {...args} value={value} onChange={setValue} />;
12+
},
13+
};
14+
15+
export default meta;
16+
type Story = StoryObj<typeof NewFilter>;
17+
18+
export const Empty: Story = {
19+
args: {
20+
value: "",
21+
},
22+
};
23+
24+
export const DefaultValue: Story = {
25+
args: {
26+
value: "owner:CoderUser",
27+
},
28+
};
29+
30+
export const Focused: Story = {
31+
args: {
32+
value: "",
33+
},
34+
play: async ({ canvasElement }) => {
35+
const canvas = within(canvasElement);
36+
await userEvent.click(canvas.getByRole("textbox"));
37+
await expect(canvas.getByRole("textbox")).toHaveFocus();
38+
},
39+
};
40+
41+
export const Typing: Story = {
42+
args: {
43+
value: "",
44+
},
45+
play: async ({ canvasElement }) => {
46+
const text = "owner:SomeSearchString";
47+
const canvas = within(canvasElement);
48+
await userEvent.type(canvas.getByRole("textbox"), text);
49+
await expect(canvas.getByRole("textbox")).toHaveValue(text);
50+
},
51+
};
52+
53+
export const ClearInput: Story = {
54+
args: {
55+
value: "owner:CoderUser",
56+
},
57+
play: async ({ canvasElement }) => {
58+
const canvas = within(canvasElement);
59+
await userEvent.click(canvas.getByRole("button", { name: "Clear filter" }));
60+
await expect(canvas.getByRole("textbox")).toHaveValue("");
61+
},
62+
};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { useTheme } from "@emotion/react";
2+
import CloseOutlined from "@mui/icons-material/CloseOutlined";
3+
import SearchOutlined from "@mui/icons-material/SearchOutlined";
4+
import IconButton from "@mui/material/IconButton";
5+
import InputBase from "@mui/material/InputBase";
6+
import Tooltip from "@mui/material/Tooltip";
7+
import { visuallyHidden } from "@mui/utils";
8+
import type { FC } from "react";
9+
10+
const inputHeight = 36;
11+
const inputBorderRadius = 6;
12+
const inputSidePadding = 12;
13+
14+
type NewFilterProps = {
15+
value: string;
16+
onChange: (value: string) => void;
17+
};
18+
19+
export const NewFilter: FC<NewFilterProps> = (props) => {
20+
const theme = useTheme();
21+
const { value, onChange } = props;
22+
const isEmpty = value.length === 0;
23+
24+
return (
25+
<div
26+
css={{
27+
borderRadius: inputBorderRadius,
28+
border: `1px solid ${theme.palette.divider}`,
29+
height: inputHeight,
30+
padding: `0 ${inputSidePadding}px`,
31+
32+
"&:focus-within": {
33+
outline: `2px solid ${theme.palette.primary.main}`,
34+
outlineOffset: -1, // Overrides the border
35+
},
36+
}}
37+
>
38+
<InputBase
39+
startAdornment={
40+
<SearchOutlined
41+
role="presentation"
42+
css={{
43+
width: 14,
44+
height: 14,
45+
color: theme.palette.text.secondary,
46+
marginRight: inputSidePadding / 2,
47+
}}
48+
/>
49+
}
50+
endAdornment={
51+
!isEmpty && (
52+
<Tooltip title="Clear filter">
53+
<IconButton
54+
size="small"
55+
onClick={() => {
56+
onChange("");
57+
}}
58+
>
59+
<CloseOutlined
60+
css={{
61+
width: 14,
62+
height: 14,
63+
color: theme.palette.text.secondary,
64+
}}
65+
/>
66+
<span css={{ ...visuallyHidden }}>Clear filter</span>
67+
</IconButton>
68+
</Tooltip>
69+
)
70+
}
71+
fullWidth
72+
placeholder="Search..."
73+
css={{ fontSize: 14, height: "100%" }}
74+
value={value}
75+
onChange={(e) => {
76+
onChange(e.currentTarget.value);
77+
}}
78+
/>
79+
</div>
80+
);
81+
};

site/src/pages/WorkspacesPage/filter/menus.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ export const useTemplateFilterMenu = ({
2020
value,
2121
id: "template",
2222
getSelectedOption: async () => {
23-
// Show all templates including deprecated
23+
debugger;
24+
if (!value) {
25+
return null;
26+
}
27+
2428
const templates = await API.getTemplates(organizationId);
2529
const template = templates.find((template) => template.name === value);
2630
if (template) {
@@ -33,9 +37,11 @@ export const useTemplateFilterMenu = ({
3337
icon: template.icon,
3438
};
3539
}
40+
3641
return null;
3742
},
3843
getOptions: async (query) => {
44+
debugger;
3945
// Show all templates including deprecated
4046
const templates = await API.getTemplates(organizationId);
4147
const filteredTemplates = templates.filter(

0 commit comments

Comments
 (0)