Skip to content

chore(site): Use react-query and refactor the workspaces page to use it #5838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion site/.eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ rules:
["error", "1tbs", { "allowSingleLine": false }]
"@typescript-eslint/camelcase": "off"
"@typescript-eslint/explicit-function-return-type": "off"
"@typescript-eslint/explicit-module-boundary-types": "error"
"@typescript-eslint/method-signature-style": ["error", "property"]
"@typescript-eslint/no-floating-promises": error
"@typescript-eslint/no-invalid-void-type": error
Expand Down
1 change: 1 addition & 0 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@material-ui/icons": "4.5.1",
"@material-ui/lab": "4.0.0-alpha.42",
"@monaco-editor/react": "4.4.6",
"@tanstack/react-query": "4.22.4",
"@testing-library/react-hooks": "8.0.1",
"@types/color-convert": "2.0.0",
"@types/react-color": "3.0.6",
Expand Down
7 changes: 7 additions & 0 deletions site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -779,3 +779,10 @@ export const getTemplateVersionLogs = async (
)
return response.data
}

export const updateWorkspaceVersion = async (
workspace: TypesGen.Workspace,
): Promise<TypesGen.WorkspaceBuild> => {
const template = await getTemplate(workspace.template_id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to handle the error for getTemplate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already handled. If it fails, it will throw an error that will be passed to the Alert component. But I guess, you were talking about handling errors in a more granular way. Since these operations are consecutive, one by one, the first one that fails will throw the error, so only one error will happen at a time. But even in case we could have two errors happening at the same time in this operation, I would ask: As a user are those two errors helpful? Or would be good enough to just show a single error like "Update template version failed"? IMO, as a user, usually don't need to know what is happening under the hood so I would avoid showing multiple errors which can make me confused. Makes sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, totally makes sense. I just see a blank screen with a toast when that error is thrown. Maybe down the road and outside of the PR, we can have a cuter error state, like even an empty table.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it should not be a toast, should be an alert banner, not VERY different tho. I agree we could have better error components when there is a main loading data error.

return startWorkspace(workspace.id, template.active_version_id)
}
32 changes: 26 additions & 6 deletions site/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
import CssBaseline from "@material-ui/core/CssBaseline"
import ThemeProvider from "@material-ui/styles/ThemeProvider"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { AuthProvider } from "components/AuthProvider/AuthProvider"
import { FC } from "react"
import { FC, PropsWithChildren } from "react"
import { HelmetProvider } from "react-helmet-async"
import { AppRouter } from "./AppRouter"
import { ErrorBoundary } from "./components/ErrorBoundary/ErrorBoundary"
import { GlobalSnackbar } from "./components/GlobalSnackbar/GlobalSnackbar"
import { dark } from "./theme"
import "./theme/globalFonts"

export const App: FC = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
cacheTime: 0,
},
},
})

export const AppProviders: FC<PropsWithChildren> = ({ children }) => {
return (
<HelmetProvider>
<ThemeProvider theme={dark}>
<CssBaseline />
<ErrorBoundary>
<AuthProvider>
<AppRouter />
<GlobalSnackbar />
</AuthProvider>
<QueryClientProvider client={queryClient}>
<AuthProvider>
{children}
<GlobalSnackbar />
</AuthProvider>
</QueryClientProvider>
</ErrorBoundary>
</ThemeProvider>
</HelmetProvider>
)
}

export const App: FC = () => {
return (
<AppProviders>
<AppRouter />
</AppProviders>
)
}
104 changes: 104 additions & 0 deletions site/src/components/PaginationWidget/PaginationWidgetBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import Button from "@material-ui/core/Button"
import { makeStyles, useTheme } from "@material-ui/core/styles"
import useMediaQuery from "@material-ui/core/useMediaQuery"
import KeyboardArrowLeft from "@material-ui/icons/KeyboardArrowLeft"
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
import { PageButton } from "./PageButton"
import { buildPagedList } from "./utils"

export type PaginationWidgetBaseProps = {
count: number
page: number
limit: number
onChange: (page: number) => void
}

export const PaginationWidgetBase = ({
count,
page,
limit,
onChange,
}: PaginationWidgetBaseProps): JSX.Element | null => {
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down("sm"))
const styles = useStyles()
const numPages = Math.ceil(count / limit)
const isFirstPage = page === 0
const isLastPage = page === numPages - 1

if (numPages < 2) {
return null
}

return (
<div className={styles.defaultContainerStyles}>
<Button
className={styles.prevLabelStyles}
aria-label="Previous page"
disabled={isFirstPage}
onClick={() => {
if (!isFirstPage) {
onChange(page - 1)
}
}}
>
<KeyboardArrowLeft />
</Button>
<ChooseOne>
<Cond condition={isMobile}>
<PageButton activePage={page} page={page} numPages={numPages} />
</Cond>
<Cond>
{buildPagedList(numPages, page).map((pageItem) => {
if (pageItem === "left" || pageItem === "right") {
return (
<PageButton
key={pageItem}
activePage={page}
placeholder="..."
disabled
/>
)
}

return (
<PageButton
key={pageItem}
page={pageItem}
activePage={page}
numPages={numPages}
onPageClick={() => onChange(pageItem)}
/>
)
})}
</Cond>
</ChooseOne>
<Button
aria-label="Next page"
disabled={isLastPage}
onClick={() => {
if (!isLastPage) {
onChange(page + 1)
}
}}
>
<KeyboardArrowRight />
</Button>
</div>
)
}

const useStyles = makeStyles((theme) => ({
defaultContainerStyles: {
justifyContent: "center",
alignItems: "center",
display: "flex",
flexDirection: "row",
padding: "20px",
},

prevLabelStyles: {
marginRight: `${theme.spacing(0.5)}px`,
},
}))
6 changes: 3 additions & 3 deletions site/src/components/PaginationWidget/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const NUM_PAGE_BLOCKS = PAGES_TO_DISPLAY + 2
export const buildPagedList = (
numPages: number,
activePage: number,
): (string | number)[] => {
): ("left" | "right" | number)[] => {
if (numPages > NUM_PAGE_BLOCKS) {
let pages = []
const leftBound = activePage - PAGE_NEIGHBORS
Expand All @@ -44,8 +44,8 @@ export const buildPagedList = (
const singleSpillOffset = PAGES_TO_DISPLAY - pages.length - 1
const hasLeftOverflow = startPage > 2
const hasRightOverflow = endPage < beforeLastPage
const leftOverflowPage = "left"
const rightOverflowPage = "right"
const leftOverflowPage = "left" as const
const rightOverflowPage = "right" as const

if (hasLeftOverflow && !hasRightOverflow) {
const extraPages = range(startPage - singleSpillOffset, startPage - 1)
Expand Down
16 changes: 7 additions & 9 deletions site/src/components/WorkspacesTable/WorkspacesRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@ import TableCell from "@material-ui/core/TableCell"
import { makeStyles } from "@material-ui/core/styles"
import TableRow from "@material-ui/core/TableRow"
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
import { useActor } from "@xstate/react"
import { AvatarData } from "components/AvatarData/AvatarData"
import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
import { useClickable } from "hooks/useClickable"
import { FC } from "react"
import { useNavigate } from "react-router-dom"
import { getDisplayWorkspaceTemplateName } from "util/workspace"
import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService"
import { LastUsed } from "../LastUsed/LastUsed"
import { OutdatedHelpTooltip } from "../Tooltips"
import { Workspace } from "api/typesGenerated"
import { OutdatedHelpTooltip } from "components/Tooltips/OutdatedHelpTooltip"

export const WorkspacesRow: FC<{ workspaceRef: WorkspaceItemMachineRef }> = ({
workspaceRef,
}) => {
export const WorkspacesRow: FC<{
workspace: Workspace
onUpdateWorkspace: (workspace: Workspace) => void
}> = ({ workspace, onUpdateWorkspace }) => {
const styles = useStyles()
const navigate = useNavigate()
const [workspaceState, send] = useActor(workspaceRef)
const { data: workspace } = workspaceState.context
const workspacePageLink = `/@${workspace.owner_name}/${workspace.name}`
const hasTemplateIcon =
workspace.template_icon && workspace.template_icon !== ""
Expand Down Expand Up @@ -58,7 +56,7 @@ export const WorkspacesRow: FC<{ workspaceRef: WorkspaceItemMachineRef }> = ({
{workspace.outdated && (
<OutdatedHelpTooltip
onUpdateVersion={() => {
send("UPDATE_VERSION")
onUpdateWorkspace(workspace)
}}
/>
)}
Expand Down
24 changes: 12 additions & 12 deletions site/src/components/WorkspacesTable/WorkspacesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import TableCell from "@material-ui/core/TableCell"
import TableContainer from "@material-ui/core/TableContainer"
import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow"
import { Workspace } from "api/typesGenerated"
import { FC } from "react"
import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService"
import { WorkspacesTableBody } from "./WorkspacesTableBody"

const Language = {
Expand All @@ -18,15 +18,16 @@ const Language = {
}

export interface WorkspacesTableProps {
isLoading?: boolean
workspaceRefs?: WorkspaceItemMachineRef[]
filter?: string
isNonInitialPage: boolean
workspaces?: Workspace[]
isUsingFilter: boolean
onUpdateWorkspace: (workspace: Workspace) => void
}

export const WorkspacesTable: FC<
React.PropsWithChildren<WorkspacesTableProps>
> = ({ isLoading, workspaceRefs, filter, isNonInitialPage }) => {
export const WorkspacesTable: FC<WorkspacesTableProps> = ({
workspaces,
isUsingFilter,
onUpdateWorkspace,
}) => {
return (
<TableContainer>
<Table>
Expand All @@ -42,10 +43,9 @@ export const WorkspacesTable: FC<
</TableHead>
<TableBody>
<WorkspacesTableBody
isLoading={isLoading}
workspaceRefs={workspaceRefs}
filter={filter}
isNonInitialPage={isNonInitialPage}
workspaces={workspaces}
isUsingFilter={isUsingFilter}
onUpdateWorkspace={onUpdateWorkspace}
/>
</TableBody>
</Table>
Expand Down
Loading