mirror of https://github.com/coder/coder.git
chore(site): Remove dead code (#7436)
This commit is contained in:
parent
dc3d39baf8
commit
ec11405208
|
@ -1,22 +0,0 @@
|
|||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { Skeleton } from "@material-ui/lab"
|
||||
import { FC } from "react"
|
||||
import { borderRadiusSm } from "theme/constants"
|
||||
|
||||
export const AppLinkSkeleton: FC<{ width: number }> = ({ width }) => {
|
||||
const styles = useStyles()
|
||||
return (
|
||||
<Skeleton
|
||||
width={width}
|
||||
height={36}
|
||||
variant="rect"
|
||||
className={styles.skeleton}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
skeleton: {
|
||||
borderRadius: borderRadiusSm,
|
||||
},
|
||||
}))
|
|
@ -64,14 +64,6 @@ function dispatchNotificationEvent(
|
|||
})
|
||||
}
|
||||
|
||||
export const displayMsg = (msg: string, additionalMsg?: string): void => {
|
||||
dispatchNotificationEvent(
|
||||
MsgType.Info,
|
||||
msg,
|
||||
additionalMsg ? [additionalMsg] : undefined,
|
||||
)
|
||||
}
|
||||
|
||||
export const displaySuccess = (msg: string, additionalMsg?: string): void => {
|
||||
dispatchNotificationEvent(
|
||||
MsgType.Success,
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { ReactElement } from "react"
|
||||
import { CodeBlock } from "../CodeBlock/CodeBlock"
|
||||
import { createCtas } from "./createCtas"
|
||||
|
||||
const Language = {
|
||||
reportLoading: "Generating crash report...",
|
||||
}
|
||||
|
||||
interface ReportState {
|
||||
error: Error
|
||||
mappedStack: string[] | null
|
||||
}
|
||||
|
||||
interface StackTraceAvailableMsg {
|
||||
type: "stackTraceAvailable"
|
||||
stackTrace: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* stackTraceUnavailable is a Msg describing a stack trace not being available
|
||||
*/
|
||||
export const stackTraceUnavailable = {
|
||||
type: "stackTraceUnavailable",
|
||||
} as const
|
||||
|
||||
type ReportMessage = StackTraceAvailableMsg | typeof stackTraceUnavailable
|
||||
|
||||
export const stackTraceAvailable = (
|
||||
stackTrace: string[],
|
||||
): StackTraceAvailableMsg => {
|
||||
return {
|
||||
type: "stackTraceAvailable",
|
||||
stackTrace,
|
||||
}
|
||||
}
|
||||
|
||||
const setStackTrace = (
|
||||
model: ReportState,
|
||||
mappedStack: string[],
|
||||
): ReportState => {
|
||||
return {
|
||||
...model,
|
||||
mappedStack,
|
||||
}
|
||||
}
|
||||
|
||||
export const reducer = (
|
||||
model: ReportState,
|
||||
msg: ReportMessage,
|
||||
): ReportState => {
|
||||
switch (msg.type) {
|
||||
case "stackTraceAvailable":
|
||||
return setStackTrace(model, msg.stackTrace)
|
||||
case "stackTraceUnavailable":
|
||||
return setStackTrace(model, ["Unable to get stack trace"])
|
||||
}
|
||||
}
|
||||
|
||||
export const createFormattedStackTrace = (
|
||||
error: Error,
|
||||
mappedStack: string[] | null,
|
||||
): string[] => {
|
||||
return [
|
||||
"======================= STACK TRACE ========================",
|
||||
"",
|
||||
error.message,
|
||||
...(mappedStack ? mappedStack : []),
|
||||
"",
|
||||
"============================================================",
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* A code block component that contains the error stack resulting from an error boundary trigger
|
||||
*/
|
||||
export const RuntimeErrorReport = ({
|
||||
error,
|
||||
mappedStack,
|
||||
}: ReportState): ReactElement => {
|
||||
const styles = useStyles()
|
||||
|
||||
if (!mappedStack) {
|
||||
return (
|
||||
<CodeBlock
|
||||
lines={[Language.reportLoading]}
|
||||
className={styles.codeBlock}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const formattedStackTrace = createFormattedStackTrace(error, mappedStack)
|
||||
return (
|
||||
<CodeBlock
|
||||
lines={formattedStackTrace}
|
||||
className={styles.codeBlock}
|
||||
ctas={createCtas(formattedStackTrace)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
codeBlock: {
|
||||
minHeight: "auto",
|
||||
userSelect: "all",
|
||||
width: "100%",
|
||||
},
|
||||
}))
|
|
@ -1,73 +0,0 @@
|
|||
import Button from "@material-ui/core/Button"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import RefreshIcon from "@material-ui/icons/Refresh"
|
||||
import { ReactElement } from "react"
|
||||
import { CopyButton } from "../CopyButton/CopyButton"
|
||||
|
||||
export const Language = {
|
||||
reloadApp: "Reload Application",
|
||||
copyReport: "Copy Report",
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper component for a full-width copy button
|
||||
*/
|
||||
const CopyStackButton = ({ text }: { text: string }): ReactElement => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<CopyButton
|
||||
text={text}
|
||||
ctaCopy={Language.copyReport}
|
||||
wrapperClassName={styles.buttonWrapper}
|
||||
buttonClassName={styles.copyButton}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A button that reloads our application
|
||||
*/
|
||||
const ReloadAppButton = (): ReactElement => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={styles.buttonWrapper}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
startIcon={<RefreshIcon />}
|
||||
onClick={() => location.replace("/")}
|
||||
>
|
||||
{Language.reloadApp}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* createCtas generates an array of buttons to be used with our error boundary UI
|
||||
*/
|
||||
export const createCtas = (codeBlock: string[]): ReactElement[] => {
|
||||
return [
|
||||
<CopyStackButton key="copy-stack-btn" text={codeBlock.join("\r\n")} />,
|
||||
<ReloadAppButton key="reload-app-btn" />,
|
||||
]
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
buttonWrapper: {
|
||||
marginTop: theme.spacing(1),
|
||||
marginLeft: 0,
|
||||
flex: theme.spacing(1),
|
||||
textTransform: "uppercase",
|
||||
fontSize: theme.typography.fontSize,
|
||||
},
|
||||
|
||||
copyButton: {
|
||||
width: "100%",
|
||||
marginRight: theme.spacing(1),
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
textTransform: "uppercase",
|
||||
fontSize: theme.typography.fontSize,
|
||||
},
|
||||
}))
|
|
@ -1,53 +0,0 @@
|
|||
import Link from "@material-ui/core/Link"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import TableCell, { TableCellProps } from "@material-ui/core/TableCell"
|
||||
import { Link as RouterLink } from "react-router-dom"
|
||||
import { combineClasses } from "../../utils/combineClasses"
|
||||
|
||||
// TableCellLink wraps a TableCell filling the entirety with a Link.
|
||||
// This allows table rows to be clickable with browser-behavior like ctrl+click.
|
||||
export const TableCellLink: React.FC<
|
||||
React.PropsWithChildren<
|
||||
TableCellProps & {
|
||||
to: string
|
||||
}
|
||||
>
|
||||
> = (props) => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<TableCell className={styles.cell} {...props}>
|
||||
<Link
|
||||
component={RouterLink}
|
||||
to={props.to}
|
||||
className={combineClasses([
|
||||
styles.link,
|
||||
"MuiTableCell-root",
|
||||
"MuiTableCell-body",
|
||||
])}
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
</TableCell>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
cell: {
|
||||
// This must override all padding for all rules on a TableCell.
|
||||
// Otherwise, the link will not cover the entire region.
|
||||
// It's unfortunate to use `!important`, but this seems to be
|
||||
// a reasonable use-case.
|
||||
padding: "0 !important",
|
||||
},
|
||||
link: {
|
||||
display: "block",
|
||||
width: "100%",
|
||||
border: "none",
|
||||
background: "none",
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2),
|
||||
// This is required to hide all underlines for child elements!
|
||||
textDecoration: "none !important",
|
||||
},
|
||||
}))
|
|
@ -26,10 +26,6 @@ interface HelpTooltipProps {
|
|||
buttonClassName?: string
|
||||
}
|
||||
|
||||
export const Language = {
|
||||
ariaLabel: "tooltip",
|
||||
}
|
||||
|
||||
export const HelpTooltipContext = createContext<
|
||||
{ open: boolean; onClose: () => void } | undefined
|
||||
>(undefined)
|
||||
|
@ -108,7 +104,7 @@ export const HelpTooltip: FC<PropsWithChildren<HelpTooltipProps>> = ({
|
|||
onMouseLeave={() => {
|
||||
setIsOpen(false)
|
||||
}}
|
||||
aria-label={Language.ariaLabel}
|
||||
aria-label="More info"
|
||||
>
|
||||
<Icon className={combineClasses([styles.icon, iconClassName])} />
|
||||
</button>
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { fireEvent, screen } from "@testing-library/react"
|
||||
import { Language as TooltipLanguage } from "components/Tooltips/HelpTooltip/HelpTooltip"
|
||||
import { Language as UserRoleLanguage } from "components/Tooltips/UserRoleHelpTooltip"
|
||||
import { render } from "testHelpers/renderHelpers"
|
||||
import { UsersTable } from "./UsersTable"
|
||||
|
||||
describe("AuditPage", () => {
|
||||
it("renders a page with a title and subtitle", async () => {
|
||||
// When
|
||||
render(
|
||||
<UsersTable
|
||||
onSuspendUser={() => jest.fn()}
|
||||
onDeleteUser={() => jest.fn()}
|
||||
onListWorkspaces={() => jest.fn()}
|
||||
onActivateUser={() => jest.fn()}
|
||||
onResetUserPassword={() => jest.fn()}
|
||||
onUpdateUserRoles={() => jest.fn()}
|
||||
isNonInitialPage={false}
|
||||
actorID="12345678-1234-1234-1234-123456789012"
|
||||
/>,
|
||||
)
|
||||
|
||||
// Then
|
||||
const tooltipIcon = await screen.findByRole("button", {
|
||||
name: TooltipLanguage.ariaLabel,
|
||||
})
|
||||
fireEvent.mouseOver(tooltipIcon)
|
||||
expect(await screen.findByText(UserRoleLanguage.title)).toBeInTheDocument()
|
||||
})
|
||||
})
|
|
@ -1,4 +1,3 @@
|
|||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import {
|
||||
Template,
|
||||
TemplateVersion,
|
||||
|
@ -55,26 +54,3 @@ export const TemplateSummaryPageView: FC<TemplateSummaryPageViewProps> = ({
|
|||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
export const useStyles = makeStyles((theme) => {
|
||||
return {
|
||||
markdownSection: {
|
||||
background: theme.palette.background.paper,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
|
||||
readmeLabel: {
|
||||
color: theme.palette.text.secondary,
|
||||
fontWeight: 600,
|
||||
padding: theme.spacing(2, 3),
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
|
||||
markdownWrapper: {
|
||||
padding: theme.spacing(0, 3, 5),
|
||||
maxWidth: 800,
|
||||
margin: "auto",
|
||||
},
|
||||
}
|
||||
})
|
||||
|
|
|
@ -20,8 +20,6 @@ import {
|
|||
TemplateVariableField,
|
||||
} from "components/TemplateVariableField/TemplateVariableField"
|
||||
|
||||
export const getValidationSchema = (): Yup.AnyObjectSchema => Yup.object()
|
||||
|
||||
export interface TemplateVariablesForm {
|
||||
templateVersion: TemplateVersion
|
||||
templateVariables: TemplateVersionVariable[]
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import dayjs from "dayjs"
|
||||
import duration from "dayjs/plugin/duration"
|
||||
import relativeTime from "dayjs/plugin/relativeTime"
|
||||
|
||||
dayjs.extend(duration)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export const humanDuration = (
|
||||
time: number,
|
||||
durationUnitType?: duration.DurationUnitType | undefined,
|
||||
) => {
|
||||
return dayjs.duration(time, durationUnitType).humanize()
|
||||
}
|
|
@ -2,10 +2,6 @@ import * as API from "api/api"
|
|||
import * as TypesGen from "api/typesGenerated"
|
||||
import { assign, createMachine } from "xstate"
|
||||
|
||||
export const Language = {
|
||||
createFirstUserError: "Failed to create the user.",
|
||||
}
|
||||
|
||||
export interface SetupContext {
|
||||
error?: unknown
|
||||
firstUser?: TypesGen.CreateFirstUserRequest
|
||||
|
|
|
@ -14,10 +14,6 @@ import { isAllowedFile } from "utils/templateVersion"
|
|||
import { TarReader, TarWriter } from "utils/tar"
|
||||
import { PublishVersionData } from "pages/TemplateVersionPage/TemplateVersionEditorPage/types"
|
||||
|
||||
export interface CreateVersionData {
|
||||
file: File
|
||||
}
|
||||
|
||||
export interface TemplateVersionEditorMachineContext {
|
||||
orgId: string
|
||||
templateId?: string
|
||||
|
|
|
@ -1,414 +0,0 @@
|
|||
import { getPaginationData } from "components/PaginationWidget/utils"
|
||||
import {
|
||||
PaginationContext,
|
||||
paginationMachine,
|
||||
PaginationMachineRef,
|
||||
} from "xServices/pagination/paginationXService"
|
||||
import { ActorRefFrom, assign, createMachine, spawn, send } from "xstate"
|
||||
import * as API from "../../api/api"
|
||||
import { getErrorMessage } from "../../api/errors"
|
||||
import * as TypesGen from "../../api/typesGenerated"
|
||||
import {
|
||||
displayError,
|
||||
displayMsg,
|
||||
displaySuccess,
|
||||
} from "../../components/GlobalSnackbar/utils"
|
||||
import { queryToFilter } from "../../utils/filters"
|
||||
|
||||
export const workspacePaginationId = "workspacePagination"
|
||||
|
||||
/**
|
||||
* Workspace item machine
|
||||
*
|
||||
* It is used to control the state and actions of each workspace in the
|
||||
* workspaces page view
|
||||
**/
|
||||
interface WorkspaceItemContext {
|
||||
data: TypesGen.Workspace
|
||||
updatedTemplate?: TypesGen.Template
|
||||
}
|
||||
|
||||
type WorkspaceItemEvent =
|
||||
| {
|
||||
type: "UPDATE_VERSION"
|
||||
}
|
||||
| {
|
||||
type: "UPDATE_DATA"
|
||||
data: TypesGen.Workspace
|
||||
}
|
||||
|
||||
export const workspaceItemMachine = createMachine(
|
||||
{
|
||||
id: "workspaceItemMachine",
|
||||
predictableActionArguments: true,
|
||||
tsTypes: {} as import("./workspacesXService.typegen").Typegen0,
|
||||
schema: {
|
||||
context: {} as WorkspaceItemContext,
|
||||
events: {} as WorkspaceItemEvent,
|
||||
services: {} as {
|
||||
getTemplate: {
|
||||
data: TypesGen.Template
|
||||
}
|
||||
startWorkspace: {
|
||||
data: TypesGen.WorkspaceBuild
|
||||
}
|
||||
getWorkspace: {
|
||||
data: TypesGen.Workspace
|
||||
}
|
||||
},
|
||||
},
|
||||
type: "parallel",
|
||||
|
||||
states: {
|
||||
updateVersion: {
|
||||
initial: "idle",
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
UPDATE_VERSION: {
|
||||
target: "gettingUpdatedTemplate",
|
||||
// We can improve the UI by optimistically updating the workspace status
|
||||
// to "Pending" so the UI can display the updated state right away and we
|
||||
// don't need to display an extra spinner.
|
||||
actions: [
|
||||
"assignPendingStatus",
|
||||
"displayUpdatingVersionMessage",
|
||||
],
|
||||
},
|
||||
UPDATE_DATA: {
|
||||
actions: "assignUpdatedData",
|
||||
},
|
||||
},
|
||||
},
|
||||
gettingUpdatedTemplate: {
|
||||
invoke: {
|
||||
id: "getTemplate",
|
||||
src: "getTemplate",
|
||||
onDone: {
|
||||
actions: "assignUpdatedTemplate",
|
||||
target: "restartingWorkspace",
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: "displayUpdateVersionError",
|
||||
},
|
||||
},
|
||||
},
|
||||
restartingWorkspace: {
|
||||
invoke: {
|
||||
id: "startWorkspace",
|
||||
src: "startWorkspace",
|
||||
onDone: {
|
||||
actions: "assignLatestBuild",
|
||||
target: "waitingToBeUpdated",
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: "displayUpdateVersionError",
|
||||
},
|
||||
},
|
||||
},
|
||||
waitingToBeUpdated: {
|
||||
after: {
|
||||
5000: "gettingUpdatedWorkspaceData",
|
||||
},
|
||||
},
|
||||
gettingUpdatedWorkspaceData: {
|
||||
invoke: {
|
||||
id: "getWorkspace",
|
||||
src: "getWorkspace",
|
||||
onDone: [
|
||||
{
|
||||
target: "waitingToBeUpdated",
|
||||
cond: "isOutdated",
|
||||
actions: ["assignUpdatedData"],
|
||||
},
|
||||
{
|
||||
target: "idle",
|
||||
actions: [
|
||||
"assignUpdatedData",
|
||||
"displayUpdatedSuccessMessage",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
guards: {
|
||||
isOutdated: (_, event) => event.data.outdated,
|
||||
},
|
||||
services: {
|
||||
getTemplate: (context) => API.getTemplate(context.data.template_id),
|
||||
startWorkspace: (context) => {
|
||||
if (!context.updatedTemplate) {
|
||||
throw new Error("Updated template is not loaded.")
|
||||
}
|
||||
|
||||
return API.startWorkspace(
|
||||
context.data.id,
|
||||
context.updatedTemplate.active_version_id,
|
||||
)
|
||||
},
|
||||
getWorkspace: (context) => API.getWorkspace(context.data.id),
|
||||
},
|
||||
actions: {
|
||||
assignUpdatedTemplate: assign({
|
||||
updatedTemplate: (_, event) => event.data,
|
||||
}),
|
||||
assignLatestBuild: assign({
|
||||
data: (context, event) => {
|
||||
return {
|
||||
...context.data,
|
||||
latest_build: event.data,
|
||||
}
|
||||
},
|
||||
}),
|
||||
displayUpdateVersionError: (_, event) => {
|
||||
const message = getErrorMessage(
|
||||
event.data,
|
||||
"Error on update workspace version.",
|
||||
)
|
||||
displayError(message)
|
||||
},
|
||||
displayUpdatingVersionMessage: () => {
|
||||
displayMsg("Updating workspace...")
|
||||
},
|
||||
assignPendingStatus: assign({
|
||||
data: (ctx) => {
|
||||
return {
|
||||
...ctx.data,
|
||||
latest_build: {
|
||||
...ctx.data.latest_build,
|
||||
status: "pending" as TypesGen.WorkspaceStatus,
|
||||
job: {
|
||||
...ctx.data.latest_build.job,
|
||||
status: "pending" as TypesGen.ProvisionerJobStatus,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}),
|
||||
displayUpdatedSuccessMessage: () => {
|
||||
displaySuccess("Workspace updated successfully.")
|
||||
},
|
||||
assignUpdatedData: assign({
|
||||
data: (_, event) => event.data,
|
||||
}),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
* Workspaces machine
|
||||
*
|
||||
* It is used to control the state of the workspace list
|
||||
**/
|
||||
|
||||
export type WorkspaceItemMachineRef = ActorRefFrom<typeof workspaceItemMachine>
|
||||
|
||||
interface WorkspacesContext {
|
||||
workspaceRefs?: WorkspaceItemMachineRef[]
|
||||
paginationRef?: PaginationMachineRef
|
||||
filter: string
|
||||
count?: number
|
||||
getWorkspacesError?: Error | unknown
|
||||
paginationContext: PaginationContext
|
||||
}
|
||||
|
||||
type WorkspacesEvent =
|
||||
| { type: "UPDATE_PAGE"; page: string }
|
||||
| { type: "UPDATE_VERSION"; workspaceId: string }
|
||||
| { type: "UPDATE_FILTER"; query?: string }
|
||||
|
||||
export const workspacesMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QHcD2AnA1rADgQwGM4BlAFz1LADpZz1SBLAOygAU8pmKHUmBiANoAGALqJQOVLAaNe4kAA9EAWgAcANnVUAzAEYATOoCcAdiFHt+obtUAaEAE9Euo6qo2LR0y-3bV+1QBfQPs0LFxCEnJKKhhSRhYAdQxsfCJYPgheamYAN1RMajjk8LS4YTEkEElpWSZ5JQRlAFYjABYdA1UjXVbmtu1teycENqN9KhNm5tVVbXU5nvHm4NCUiPSyCiKweOYoEtTIjKymHKZ8wtjdw43y3UqJKRkeeqrG5X02rT11XSEAiYBl4TMNEG1+lQhEJ1FZtF4hM0TPpdKsQGEjptojs9kl1mUMmB0OgMFQcAAbCgAMwwAFtrqRbgSKvIai85O8VM11EIdNMNEJtBCBkNHODoVQAtChCZ4eYbNo0Ri7rAtjEAK44CDcPGlSIAJTAVJO2SoeQK1E12soTINRtgLKqbLqDRU+n0RioRn6JhMqiRQjaQn96jBCBszSozX0zW0rSMxnUst0ipC6PxxzV1GQeBkABVUIaqeg4AALW3pPgKWjbKh4KmUdAACma0oAlHxlQSs1Qc-nC0aS7Byxn0o6nrVXq6mtzPULevDdEm2kHQWKEB6Jt045ZoUn-uo2krR1FtnwAKqsAAiAEE8wBRAD6ADV7-riABJADyADlx9VnhdTkmksXRJgTBY-GMYNvTDZRek9TRej9XQDFcP0VjTLtM2xC9rzvJ9WBvABxe9-2dKdgOUWUtGjL5Az8QY-TsdcEyjVCTBsIEvB49Rjz1LEz0vW8H0fAAxD8ABkH31cjAMo0APn6Dpvhlf4E3+GNmjgpdtCoMYYVUAZuQ0JMgjRJhUAgOB5GwwSYhreh9nYTgmG4DkJ3ZN5FJULwOiFMw-SsVRrEFMNvS9Hiouikx+MxU8YjiBIDhPeAnXkjzFF8gYdERfwEy8PwUTDQw9KRZoU2hcZNDafRYqw1KeytHUUoEsAizSzygJ8poAjcKxvmMNpZW5VoSosL0iu6UrLGROKVR7PtSALIshxHNrOoAydMqUmYo00ExTCM-pBhK8woRTWFWh5WYgyPBqNqzVkMu8rKmn+WqdGGmV-GDULRRGLQotUXRfVBsx2kRYJgiAA */
|
||||
createMachine(
|
||||
{
|
||||
tsTypes: {} as import("./workspacesXService.typegen").Typegen1,
|
||||
schema: {
|
||||
context: {} as WorkspacesContext,
|
||||
events: {} as WorkspacesEvent,
|
||||
services: {} as {
|
||||
getWorkspaces: {
|
||||
data: TypesGen.WorkspacesResponse
|
||||
}
|
||||
updateWorkspaceRefs: {
|
||||
data: {
|
||||
refsToKeep: WorkspaceItemMachineRef[]
|
||||
newWorkspaces: TypesGen.Workspace[]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
predictableActionArguments: true,
|
||||
id: "workspacesState",
|
||||
on: {
|
||||
UPDATE_VERSION: {
|
||||
actions: "triggerUpdateVersion",
|
||||
},
|
||||
UPDATE_PAGE: {
|
||||
target: "gettingWorkspaces",
|
||||
actions: "updateURL",
|
||||
},
|
||||
UPDATE_FILTER: {
|
||||
actions: ["assignFilter", "sendResetPage"],
|
||||
},
|
||||
},
|
||||
initial: "startingPagination",
|
||||
states: {
|
||||
startingPagination: {
|
||||
entry: "assignPaginationRef",
|
||||
always: {
|
||||
target: "gettingWorkspaces",
|
||||
},
|
||||
},
|
||||
gettingWorkspaces: {
|
||||
entry: "clearGetWorkspacesError",
|
||||
invoke: {
|
||||
src: "getWorkspaces",
|
||||
id: "getWorkspaces",
|
||||
onDone: [
|
||||
{
|
||||
target: "waitToRefreshWorkspaces",
|
||||
cond: "isEmpty",
|
||||
actions: ["assignWorkspaceRefs", "assignCount"],
|
||||
},
|
||||
{
|
||||
target: "updatingWorkspaceRefs",
|
||||
actions: "assignCount",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "waitToRefreshWorkspaces",
|
||||
actions: "assignGetWorkspacesError",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
updatingWorkspaceRefs: {
|
||||
invoke: {
|
||||
src: "updateWorkspaceRefs",
|
||||
id: "updateWorkspaceRefs",
|
||||
onDone: [
|
||||
{
|
||||
target: "waitToRefreshWorkspaces",
|
||||
actions: "assignUpdatedWorkspaceRefs",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
waitToRefreshWorkspaces: {
|
||||
after: {
|
||||
"5000": {
|
||||
target: "gettingWorkspaces",
|
||||
actions: [],
|
||||
internal: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
guards: {
|
||||
isEmpty: (context) => !context.workspaceRefs,
|
||||
},
|
||||
actions: {
|
||||
assignWorkspaceRefs: assign({
|
||||
workspaceRefs: (_, event) =>
|
||||
event.data.workspaces.map((data) => {
|
||||
return spawn(workspaceItemMachine.withContext({ data }), data.id)
|
||||
}),
|
||||
}),
|
||||
assignCount: assign({
|
||||
count: (_, event) => event.data.count,
|
||||
}),
|
||||
assignPaginationRef: assign({
|
||||
paginationRef: (context) =>
|
||||
spawn(
|
||||
paginationMachine.withContext(context.paginationContext),
|
||||
workspacePaginationId,
|
||||
),
|
||||
}),
|
||||
assignFilter: assign({
|
||||
filter: (context, event) => event.query ?? context.filter,
|
||||
}),
|
||||
sendResetPage: send(
|
||||
{ type: "RESET_PAGE" },
|
||||
{ to: workspacePaginationId },
|
||||
),
|
||||
assignGetWorkspacesError: assign({
|
||||
getWorkspacesError: (_, event) => event.data,
|
||||
}),
|
||||
clearGetWorkspacesError: (context) =>
|
||||
assign({ ...context, getWorkspacesError: undefined }),
|
||||
triggerUpdateVersion: (context, event) => {
|
||||
const workspaceRef = context.workspaceRefs?.find(
|
||||
(ref) => ref.id === event.workspaceId,
|
||||
)
|
||||
|
||||
if (!workspaceRef) {
|
||||
throw new Error(`No workspace ref found for ${event.workspaceId}.`)
|
||||
}
|
||||
|
||||
workspaceRef.send("UPDATE_VERSION")
|
||||
},
|
||||
assignUpdatedWorkspaceRefs: assign({
|
||||
workspaceRefs: (_, event) => {
|
||||
const newWorkspaceRefs = event.data.newWorkspaces.map((workspace) =>
|
||||
spawn(
|
||||
workspaceItemMachine.withContext({ data: workspace }),
|
||||
workspace.id,
|
||||
),
|
||||
)
|
||||
return event.data.refsToKeep.concat(newWorkspaceRefs)
|
||||
},
|
||||
}),
|
||||
},
|
||||
services: {
|
||||
getWorkspaces: (context) => {
|
||||
if (context.paginationRef) {
|
||||
const { offset, limit } = getPaginationData(context.paginationRef)
|
||||
return API.getWorkspaces({
|
||||
...queryToFilter(context.filter),
|
||||
offset,
|
||||
limit,
|
||||
})
|
||||
} else {
|
||||
throw new Error("Cannot get workspaces without pagination data")
|
||||
}
|
||||
},
|
||||
updateWorkspaceRefs: (context, event) => {
|
||||
const refsToKeep: WorkspaceItemMachineRef[] = []
|
||||
context.workspaceRefs?.forEach((ref) => {
|
||||
const matchingWorkspace = event.data.workspaces.find(
|
||||
(workspace) => ref.id === workspace.id,
|
||||
)
|
||||
if (matchingWorkspace) {
|
||||
// if a workspace machine reference describes a workspace that has not been deleted,
|
||||
// update its data and mark it as a refToKeep
|
||||
ref.send({ type: "UPDATE_DATA", data: matchingWorkspace })
|
||||
refsToKeep.push(ref)
|
||||
} else {
|
||||
// if it describes a workspace that has been deleted, stop the machine
|
||||
ref.stop && ref.stop()
|
||||
}
|
||||
})
|
||||
|
||||
const newWorkspaces = event.data.workspaces.filter(
|
||||
(workspace) =>
|
||||
!context.workspaceRefs?.find((ref) => ref.id === workspace.id),
|
||||
)
|
||||
|
||||
return Promise.resolve({
|
||||
refsToKeep,
|
||||
newWorkspaces,
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
Loading…
Reference in New Issue