Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
6 changes: 4 additions & 2 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions codersdk/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -1682,6 +1682,9 @@ const (
// https://github.com/coder/coder/milestone/19
ExperimentWorkspaceActions Experiment = "workspace_actions"

// New workspace filter
ExperimentWorkspaceFilter Experiment = "workspace_filter"

// Add new experiments here!
// ExperimentExample Experiment = "example"
)
Expand Down
1 change: 1 addition & 0 deletions docs/api/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -2559,6 +2559,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a
| ------------------- |
| `moons` |
| `workspace_actions` |
| `workspace_filter` |

## codersdk.Feature

Expand Down
1 change: 1 addition & 0 deletions site/.eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ rules:
"object-curly-spacing": "off"
react-hooks/exhaustive-deps: warn
react-hooks/rules-of-hooks: error
react/display-name: "off"
react/jsx-no-script-url:
- error
- - name: Link
Expand Down
4 changes: 2 additions & 2 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@
"@testing-library/user-event": "14.4.3",
"@types/jest": "29.4.0",
"@types/node": "14.18.22",
"@types/react": "18.0.15",
"@types/react-dom": "18.0.6",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"@types/react-helmet": "6.1.5",
"@types/react-syntax-highlighter": "15.5.5",
"@types/react-virtualized-auto-sizer": "1.0.1",
Expand Down
File renamed without changes.
10 changes: 10 additions & 0 deletions site/src/@types/i18n.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import "i18next"

// https://github.com/i18next/react-i18next/issues/1543#issuecomment-1528679591
declare module "i18next" {
interface TypeOptions {
returnNull: false
allowObjectInHTMLChildren: false
}
export function t<T>(s: string): T
}
File renamed without changes.
3 changes: 3 additions & 0 deletions site/src/api/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export const isApiValidationError = (error: unknown): error is ApiError => {
return isApiError(error) && hasApiFieldErrors(error)
}

export const hasError = (error: unknown) =>
error !== undefined && error !== null

export const mapApiErrorToFieldErrors = (
apiErrorResponse: ApiErrorResponse,
): FieldErrors => {
Expand Down
8 changes: 6 additions & 2 deletions site/src/api/typesGenerated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1385,8 +1385,12 @@ export const Entitlements: Entitlement[] = [
]

// From codersdk/deployment.go
export type Experiment = "moons" | "workspace_actions"
export const Experiments: Experiment[] = ["moons", "workspace_actions"]
export type Experiment = "moons" | "workspace_actions" | "workspace_filter"
export const Experiments: Experiment[] = [
"moons",
"workspace_actions",
"workspace_filter",
]

// From codersdk/deployment.go
export type FeatureName =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { DeploymentStats, WorkspaceStatus } from "api/typesGenerated"
import { FC, useMemo, useEffect, useState } from "react"
import prettyBytes from "pretty-bytes"
import { getStatus } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
import BuildingIcon from "@mui/icons-material/Build"
import { makeStyles } from "@mui/styles"
import { RocketIcon } from "components/Icons/RocketIcon"
Expand All @@ -19,6 +18,7 @@ import dayjs from "dayjs"
import CollectedIcon from "@mui/icons-material/Compare"
import RefreshIcon from "@mui/icons-material/Refresh"
import Button from "@mui/material/Button"
import { getDisplayWorkspaceStatus } from "utils/workspace"

export const bannerHeight = 36

Expand Down Expand Up @@ -218,7 +218,7 @@ const WorkspaceBuildValue: FC<{
count?: number
}> = ({ status, count }) => {
const styles = useStyles()
const displayStatus = getStatus(status)
const displayStatus = getDisplayWorkspaceStatus(status)
let statusText = displayStatus.text
let icon = displayStatus.icon
if (status === "starting") {
Expand Down
14 changes: 6 additions & 8 deletions site/src/components/UserAvatar/UserAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { Avatar } from "components/Avatar/Avatar"
import { Avatar, AvatarProps } from "components/Avatar/Avatar"
import { FC } from "react"

export interface UserAvatarProps {
export type UserAvatarProps = {
username: string
avatarURL?: string
// It is needed to work with the AvatarGroup so it can pass the
// MuiAvatarGroup-avatar className
className?: string
}
} & AvatarProps

export const UserAvatar: FC<UserAvatarProps> = ({
username,
avatarURL,
className,

...avatarProps
}) => {
return (
<Avatar title={username} src={avatarURL} className={className}>
<Avatar title={username} src={avatarURL} {...avatarProps}>
{username}
</Avatar>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import CircularProgress from "@mui/material/CircularProgress"
import ErrorIcon from "@mui/icons-material/ErrorOutline"
import StopIcon from "@mui/icons-material/StopOutlined"
import PlayIcon from "@mui/icons-material/PlayArrowOutlined"
import QueuedIcon from "@mui/icons-material/HourglassEmpty"
import { Workspace, WorkspaceBuild } from "api/typesGenerated"
import { Workspace } from "api/typesGenerated"
import { Pill } from "components/Pill/Pill"
import i18next from "i18next"
import { FC, PropsWithChildren } from "react"
import { makeStyles } from "@mui/styles"
import { combineClasses } from "utils/combineClasses"
Expand All @@ -14,82 +8,7 @@ import {
ImpendingDeletionBadge,
ImpendingDeletionText,
} from "components/WorkspaceDeletion"

const LoadingIcon: FC = () => {
return <CircularProgress size={10} style={{ color: "#FFF" }} />
}

export const getStatus = (buildStatus: WorkspaceBuild["status"]) => {
const { t } = i18next

switch (buildStatus) {
case undefined:
return {
text: t("workspaceStatus.loading", { ns: "common" }),
icon: <LoadingIcon />,
} as const
case "running":
return {
type: "success",
text: t("workspaceStatus.running", { ns: "common" }),
icon: <PlayIcon />,
} as const
case "starting":
return {
type: "success",
text: t("workspaceStatus.starting", { ns: "common" }),
icon: <LoadingIcon />,
} as const
case "stopping":
return {
type: "warning",
text: t("workspaceStatus.stopping", { ns: "common" }),
icon: <LoadingIcon />,
} as const
case "stopped":
return {
type: "warning",
text: t("workspaceStatus.stopped", { ns: "common" }),
icon: <StopIcon />,
} as const
case "deleting":
return {
type: "warning",
text: t("workspaceStatus.deleting", { ns: "common" }),
icon: <LoadingIcon />,
} as const
case "deleted":
return {
type: "error",
text: t("workspaceStatus.deleted", { ns: "common" }),
icon: <ErrorIcon />,
} as const
case "canceling":
return {
type: "warning",
text: t("workspaceStatus.canceling", { ns: "common" }),
icon: <LoadingIcon />,
} as const
case "canceled":
return {
type: "warning",
text: t("workspaceStatus.canceled", { ns: "common" }),
icon: <ErrorIcon />,
} as const
case "failed":
return {
type: "error",
text: t("workspaceStatus.failed", { ns: "common" }),
icon: <ErrorIcon />,
} as const
case "pending":
return {
type: "info",
text: t("workspaceStatus.pending", { ns: "common" }),
icon: <QueuedIcon />,
} as const
}
}
import { getDisplayWorkspaceStatus } from "utils/workspace"

export type WorkspaceStatusBadgeProps = {
workspace: Workspace
Expand All @@ -99,7 +18,9 @@ export type WorkspaceStatusBadgeProps = {
export const WorkspaceStatusBadge: FC<
PropsWithChildren<WorkspaceStatusBadgeProps>
> = ({ workspace, className }) => {
const { text, icon, type } = getStatus(workspace.latest_build.status)
const { text, icon, type } = getDisplayWorkspaceStatus(
workspace.latest_build.status,
)
return (
<ChooseOne>
{/* <ImpendingDeletionBadge/> determines its own visibility */}
Expand All @@ -117,7 +38,9 @@ export const WorkspaceStatusText: FC<
PropsWithChildren<WorkspaceStatusBadgeProps>
> = ({ workspace, className }) => {
const styles = useStyles()
const { text, type } = getStatus(workspace.latest_build.status)
const { text, type } = getDisplayWorkspaceStatus(
workspace.latest_build.status,
)

return (
<ChooseOne>
Expand Down
1 change: 0 additions & 1 deletion site/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ export * from "./useClickable"
export * from "./useClickableTableRow"
export * from "./useClipboard"
export * from "./useFeatureVisibility"
export * from "./useFilter"
export * from "./useLocalStorage"
export * from "./useMe"
export * from "./useOrganizationId"
Expand Down
21 changes: 0 additions & 21 deletions site/src/hooks/useFilter.ts

This file was deleted.

16 changes: 7 additions & 9 deletions site/src/hooks/usePagination.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { DEFAULT_RECORDS_PER_PAGE } from "components/PaginationWidget/utils"
import { useSearchParams } from "react-router-dom"

type UsePaginationResult = {
page: number
limit: number
goToPage: (page: number) => void
}

export const usePagination = (): UsePaginationResult => {
const [searchParams, setSearchParams] = useSearchParams()
const page = searchParams.get("page") ? Number(searchParams.get("page")) : 0
export const usePagination = ({
searchParamsResult,
}: {
searchParamsResult: ReturnType<typeof useSearchParams>
}) => {
const [searchParams, setSearchParams] = searchParamsResult
const page = searchParams.get("page") ? Number(searchParams.get("page")) : 1
const limit = DEFAULT_RECORDS_PER_PAGE

const goToPage = (page: number) => {
Expand Down
16 changes: 8 additions & 8 deletions site/src/pages/UserSettingsPage/TokensPage/TokensPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FC, PropsWithChildren, useState } from "react"
import { Section } from "components/SettingsLayout/Section"
import { TokensPageView } from "./TokensPageView"
import makeStyles from "@mui/styles/makeStyles"
import { useTranslation, Trans } from "react-i18next"
import { useTranslation } from "react-i18next"
import { useTokensData } from "./hooks"
import { ConfirmDeleteDialog } from "./components"
import { Stack } from "components/Stack/Stack"
Expand All @@ -16,12 +16,6 @@ export const TokensPage: FC<PropsWithChildren<unknown>> = () => {
const { t } = useTranslation("tokensPage")

const cliCreateCommand = "coder tokens create"
const description = (
<Trans t={t} i18nKey="description" values={{ cliCreateCommand }}>
Tokens are used to authenticate with the Coder API. You can create a token
with the Coder CLI using the <code>{{ cliCreateCommand }}</code> command.
</Trans>
)

const TokenActions = () => (
<Stack direction="row" justifyContent="end" className={styles.tokenActions}>
Expand Down Expand Up @@ -52,7 +46,13 @@ export const TokensPage: FC<PropsWithChildren<unknown>> = () => {
<Section
title={t("title")}
className={styles.section}
description={description}
description={
<>
Tokens are used to authenticate with the Coder API. You can create a
token with the Coder CLI using the <code>{cliCreateCommand}</code>{" "}
command.
</>
}
layout="fluid"
>
<TokenActions />
Expand Down
Loading