diff --git a/site/src/components/SearchBarWithFilter/SearchBarWithFilter.stories.tsx b/site/src/components/SearchBarWithFilter/SearchBarWithFilter.stories.tsx new file mode 100644 index 0000000000000..2df5a0d485c82 --- /dev/null +++ b/site/src/components/SearchBarWithFilter/SearchBarWithFilter.stories.tsx @@ -0,0 +1,25 @@ +import { ComponentMeta, Story } from "@storybook/react" +import { workspaceFilterQuery } from "../../util/workspace" +import { SearchBarWithFilter, SearchBarWithFilterProps } from "./SearchBarWithFilter" + +export default { + title: "components/SearchBarWithFilter", + component: SearchBarWithFilter, + argTypes: { + filter: { + defaultValue: workspaceFilterQuery.me, + }, + }, +} as ComponentMeta + +const Template: Story = (args) => + +export const WithoutPresetFilters = Template.bind({}) + +export const WithPresetFilters = Template.bind({}) +WithPresetFilters.args = { + presetFilters: [ + { query: workspaceFilterQuery.me, name: "Your workspaces" }, + { query: "random query", name: "Random query" }, + ], +} diff --git a/site/src/components/SearchBarWithFilter/SearchBarWithFilter.tsx b/site/src/components/SearchBarWithFilter/SearchBarWithFilter.tsx new file mode 100644 index 0000000000000..4ef07939025f7 --- /dev/null +++ b/site/src/components/SearchBarWithFilter/SearchBarWithFilter.tsx @@ -0,0 +1,140 @@ +import Button from "@material-ui/core/Button" +import Fade from "@material-ui/core/Fade" +import InputAdornment from "@material-ui/core/InputAdornment" +import Menu from "@material-ui/core/Menu" +import MenuItem from "@material-ui/core/MenuItem" +import { makeStyles } from "@material-ui/core/styles" +import TextField from "@material-ui/core/TextField" +import SearchIcon from "@material-ui/icons/Search" +import { FormikErrors, useFormik } from "formik" +import { useState } from "react" +import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils" +import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows" +import { Stack } from "../Stack/Stack" + +export const Language = { + filterName: "Filters", +} + +export interface SearchBarWithFilterProps { + filter?: string + onFilter: (query: string) => void + presetFilters?: PresetFilter[] +} + +export interface PresetFilter { + name: string + query: string +} + +interface FilterFormValues { + query: string +} + +export type FilterFormErrors = FormikErrors + +export const SearchBarWithFilter: React.FC = ({ filter, onFilter, presetFilters }) => { + const styles = useStyles() + + const form = useFormik({ + enableReinitialize: true, + initialValues: { + query: filter ?? "", + }, + onSubmit: ({ query }) => { + onFilter(query) + }, + }) + + const getFieldHelpers = getFormHelpers(form) + + const [anchorEl, setAnchorEl] = useState(null) + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget) + } + + const handleClose = () => { + setAnchorEl(null) + } + + const setPresetFilter = (query: string) => () => { + void form.setFieldValue("query", query) + void form.submitForm() + handleClose() + } + + return ( + + {presetFilters && presetFilters.length > 0 && ( + + )} + +
+ + + + ), + }} + /> + + + {presetFilters && presetFilters.length > 0 && ( + + {presetFilters.map((presetFilter) => ( + + {presetFilter.name} + + ))} + + )} +
+ ) +} + +const useStyles = makeStyles((theme) => ({ + filterContainer: { + border: `1px solid ${theme.palette.divider}`, + borderRadius: theme.shape.borderRadius, + marginBottom: theme.spacing(2), + }, + filterForm: { + width: "100%", + }, + buttonRoot: { + border: "none", + borderRight: `1px solid ${theme.palette.divider}`, + borderRadius: `${theme.shape.borderRadius}px 0px 0px ${theme.shape.borderRadius}px`, + }, + textFieldRoot: { + margin: "0px", + "& fieldset": { + border: "none", + }, + }, +})) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index a66a58005e6e3..da24f921fd5a7 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -1,32 +1,25 @@ import Button from "@material-ui/core/Button" -import Fade from "@material-ui/core/Fade" -import InputAdornment from "@material-ui/core/InputAdornment" import Link from "@material-ui/core/Link" -import Menu from "@material-ui/core/Menu" -import MenuItem from "@material-ui/core/MenuItem" import { fade, makeStyles, Theme } from "@material-ui/core/styles" import Table from "@material-ui/core/Table" import TableBody from "@material-ui/core/TableBody" import TableCell from "@material-ui/core/TableCell" import TableHead from "@material-ui/core/TableHead" import TableRow from "@material-ui/core/TableRow" -import TextField from "@material-ui/core/TextField" import AddCircleOutline from "@material-ui/icons/AddCircleOutline" import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight" import RefreshIcon from "@material-ui/icons/Refresh" -import SearchIcon from "@material-ui/icons/Search" import useTheme from "@material-ui/styles/useTheme" import { useActor } from "@xstate/react" import dayjs from "dayjs" import relativeTime from "dayjs/plugin/relativeTime" -import { FormikErrors, useFormik } from "formik" -import { FC, useState } from "react" +import { FC } from "react" import { Link as RouterLink, useNavigate } from "react-router-dom" import { AvatarData } from "../../components/AvatarData/AvatarData" -import { CloseDropdown, OpenDropdown } from "../../components/DropdownArrows/DropdownArrows" import { EmptyState } from "../../components/EmptyState/EmptyState" import { Margins } from "../../components/Margins/Margins" import { PageHeader, PageHeaderSubtitle, PageHeaderTitle } from "../../components/PageHeader/PageHeader" +import { SearchBarWithFilter } from "../../components/SearchBarWithFilter/SearchBarWithFilter" import { Stack } from "../../components/Stack/Stack" import { TableCellLink } from "../../components/TableCellLink/TableCellLink" import { TableLoader } from "../../components/TableLoader/TableLoader" @@ -38,7 +31,6 @@ import { HelpTooltipText, HelpTooltipTitle, } from "../../components/Tooltips/HelpTooltip/HelpTooltip" -import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils" import { getDisplayStatus, workspaceFilterQuery } from "../../util/workspace" import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService" @@ -49,7 +41,6 @@ export const Language = { emptyCreateWorkspaceMessage: "Create your first workspace", emptyCreateWorkspaceDescription: "Start editing your source code and building your software", emptyResultsMessage: "No results matched your search", - filterName: "Filters", yourWorkspacesButton: "Your workspaces", allWorkspacesButton: "All workspaces", workspaceTooltipTitle: "What is a workspace?", @@ -154,12 +145,6 @@ const WorkspaceRow: React.FC<{ workspaceRef: WorkspaceItemMachineRef }> = ({ wor ) } -interface FilterFormValues { - query: string -} - -export type FilterFormErrors = FormikErrors - export interface WorkspacesPageViewProps { loading?: boolean workspaceRefs?: WorkspaceItemMachineRef[] @@ -168,41 +153,10 @@ export interface WorkspacesPageViewProps { } export const WorkspacesPageView: FC = ({ loading, workspaceRefs, filter, onFilter }) => { - const styles = useStyles() - - const form = useFormik({ - enableReinitialize: true, - initialValues: { - query: filter ?? "", - }, - onSubmit: ({ query }) => { - onFilter(query) - }, - }) - - const getFieldHelpers = getFormHelpers(form) - - const [anchorEl, setAnchorEl] = useState(null) - - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget) - } - - const handleClose = () => { - setAnchorEl(null) - } - - const setYourWorkspaces = () => { - void form.setFieldValue("query", "owner:me") - void form.submitForm() - handleClose() - } - - const setAllWorkspaces = () => { - void form.setFieldValue("query", "") - void form.submitForm() - handleClose() - } + const presetFilters = [ + { query: workspaceFilterQuery.me, name: Language.yourWorkspacesButton }, + { query: workspaceFilterQuery.all, name: Language.allWorkspacesButton }, + ] return ( @@ -223,48 +177,7 @@ export const WorkspacesPageView: FC = ({ loading, works - - - -
- - - - ), - }} - /> - - - - {Language.yourWorkspacesButton} - {Language.allWorkspacesButton} - -
+ @@ -328,25 +241,6 @@ const useStyles = makeStyles((theme) => ({ lineHeight: `${theme.spacing(3)}px`, }, }, - filterContainer: { - border: `1px solid ${theme.palette.divider}`, - borderRadius: theme.shape.borderRadius, - marginBottom: theme.spacing(2), - }, - filterForm: { - width: "100%", - }, - buttonRoot: { - border: "none", - borderRight: `1px solid ${theme.palette.divider}`, - borderRadius: `${theme.shape.borderRadius}px 0px 0px ${theme.shape.borderRadius}px`, - }, - textFieldRoot: { - margin: "0px", - "& fieldset": { - border: "none", - }, - }, clickableTableRow: { "&:hover td": { backgroundColor: fade(theme.palette.primary.light, 0.1), 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