mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
Handle errors
This commit is contained in:
+1
-1
@@ -288,7 +288,7 @@ export const getWorkspaces = async (
|
||||
|
||||
// TODO change types
|
||||
export const getWorkspacesCount = async (
|
||||
options: TypesGen.AuditLogCountRequest = {}
|
||||
options: TypesGen.AuditLogCountRequest = {},
|
||||
): Promise<TypesGen.AuditLogCountResponse> => {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (options.q) {
|
||||
|
||||
@@ -11,12 +11,12 @@ import { severityConstants } from "./severityConstants"
|
||||
import { AlertBannerCtas } from "./AlertBannerCtas"
|
||||
|
||||
/**
|
||||
* severity: the level of alert severity (see ./severityTypes.ts)
|
||||
* text: default text to be displayed to the user; useful for warnings or as a fallback error message
|
||||
* error: should be passed in if the severity is 'Error'; warnings can use 'text' instead
|
||||
* actions: an array of CTAs passed in by the consumer
|
||||
* dismissible: determines whether or not the banner should have a `Dismiss` CTA
|
||||
* retry: a handler to retry the action that spawned the error
|
||||
* @param severity: the level of alert severity (see ./severityTypes.ts)
|
||||
* @param text: default text to be displayed to the user; useful for warnings or as a fallback error message
|
||||
* @param error: should be passed in if the severity is 'Error'; warnings can use 'text' instead
|
||||
* @param actions: an array of CTAs passed in by the consumer
|
||||
* @param dismissible: determines whether or not the banner should have a `Dismiss` CTA
|
||||
* @param retry: a handler to retry the action that spawned the error
|
||||
*/
|
||||
export const AlertBanner: FC<AlertBannerProps> = ({
|
||||
severity,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { useMachine } from "@xstate/react"
|
||||
import { FC } from "react"
|
||||
import { Helmet } from "react-helmet-async"
|
||||
import { useSearchParams } from "react-router-dom"
|
||||
import { useNavigate, useSearchParams } from "react-router-dom"
|
||||
import { workspaceFilterQuery } from "util/filters"
|
||||
import { pageTitle } from "util/page"
|
||||
import { workspacesMachine } from "xServices/workspaces/workspacesXService"
|
||||
import { WorkspacesPageView } from "./WorkspacesPageView"
|
||||
|
||||
const WorkspacesPage: FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
const filter = searchParams.get("filter") ?? workspaceFilterQuery.me
|
||||
const currentPage = searchParams.get("page")
|
||||
@@ -16,7 +17,7 @@ const WorkspacesPage: FC = () => {
|
||||
const [workspacesState, send] = useMachine(workspacesMachine, {
|
||||
context: {
|
||||
page: currentPage,
|
||||
limit: 25,
|
||||
limit: 2, //TODO
|
||||
filter,
|
||||
},
|
||||
actions: {
|
||||
@@ -28,7 +29,14 @@ const WorkspacesPage: FC = () => {
|
||||
},
|
||||
})
|
||||
|
||||
const { workspaceRefs, count, page, limit } = workspacesState.context
|
||||
const {
|
||||
workspaceRefs,
|
||||
count,
|
||||
page,
|
||||
limit,
|
||||
getWorkspacesError,
|
||||
getCountError,
|
||||
} = workspacesState.context
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -41,6 +49,8 @@ const WorkspacesPage: FC = () => {
|
||||
isLoading={!workspaceRefs}
|
||||
workspaceRefs={workspaceRefs}
|
||||
count={count}
|
||||
getWorkspacesError={getWorkspacesError}
|
||||
getCountError={getCountError}
|
||||
page={page}
|
||||
limit={limit}
|
||||
onNext={() => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Link from "@material-ui/core/Link"
|
||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import { PaginationWidget } from "components/PaginationWidget/PaginationWidget"
|
||||
import { FC } from "react"
|
||||
@@ -29,6 +30,8 @@ export interface WorkspacesPageViewProps {
|
||||
isLoading?: boolean
|
||||
workspaceRefs?: WorkspaceItemMachineRef[]
|
||||
count?: number
|
||||
getWorkspacesError: Error | unknown
|
||||
getCountError: Error | unknown
|
||||
page: number
|
||||
limit: number
|
||||
filter?: string
|
||||
@@ -44,6 +47,8 @@ export const WorkspacesPageView: FC<
|
||||
isLoading,
|
||||
workspaceRefs,
|
||||
count,
|
||||
getWorkspacesError,
|
||||
getCountError,
|
||||
page,
|
||||
limit,
|
||||
filter,
|
||||
@@ -80,6 +85,21 @@ export const WorkspacesPageView: FC<
|
||||
</PageHeaderSubtitle>
|
||||
</PageHeader>
|
||||
|
||||
<Maybe condition={getWorkspacesError !== undefined}>
|
||||
<AlertBanner
|
||||
error={getWorkspacesError}
|
||||
severity={
|
||||
workspaceRefs !== undefined && workspaceRefs.length > 0
|
||||
? "warning"
|
||||
: "error"
|
||||
}
|
||||
/>
|
||||
</Maybe>
|
||||
|
||||
<Maybe condition={getCountError !== undefined}>
|
||||
<AlertBanner error={getCountError} severity="warning" />
|
||||
</Maybe>
|
||||
|
||||
<SearchBarWithFilter
|
||||
filter={filter}
|
||||
onFilter={onFilter}
|
||||
|
||||
@@ -206,6 +206,7 @@ interface WorkspacesContext {
|
||||
workspaceRefs?: WorkspaceItemMachineRef[]
|
||||
filter: string
|
||||
getWorkspacesError?: Error | unknown
|
||||
getCountError?: Error | unknown
|
||||
page: number
|
||||
count?: number
|
||||
limit: number
|
||||
@@ -219,229 +220,234 @@ type WorkspacesEvent =
|
||||
| { type: "GO_TO_PAGE"; page: number }
|
||||
|
||||
export const workspacesMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QHcD2AnA1rADgQwGM4BlAFz1LADpk8BLUgFVQCUwAzdOACwHUNs+IrADEAD1jlKVPO0roAFAFYADGoCUItFlyESU6rQbM2nHvx1C4AbRUBdRKBypYDOqgB2jkGMQBGAGYANgCqFQAmAE4-cIAOOPDwoIB2ZIAaEABPRHCVKljAv2S-EMiClSUAFliAXxqM7UE9WDIKanYwUgJuOg8oKgJUAFcPUioYUlJeqABhYdGRCE9qXoA3VExqCYsm4TmR0lsHJBBnVynPb18ESsq8uOLk2KCVSqVY4qUM7IQAyqoApElOFKskgpEUn5avUQI1dMJWtIOl0en0BvMxhMpn19gswOh0BgqDgADYUdgYAC2406O3hcFxh3s3jObkuJ2ufyUVEiAXi4QCySUAWBARF3xyaiowuqZShQSCiUidQaAnpLQMVGR3WmNDVVlgVCGOAgFGmdKsplESw8Kw8602RpNbQteitRxZLjZXg5iFitwByTKARUQVulQCiQlCBeeX9sWifihhXBKth+uaiPanR1aLhBppk3NGeEi2WVDWGy2tJLNmZJ1ZFx9oGub25f0jyQqSiUQvi0aUiqoiXCfnecT8kRUwTT+czmu1qP6c+EhexUFdpZtdod1dIm5sfmOTi9TauiFukWlCb5097-tD0cqQ57dw+8cCz9ntY1bS1OaXPVLGaNdi2A0t8UJdBiTJUgKXQalth-D0G1Pdxmx8fximHF5O1uVJKgFAJoxCZIqChPlIhBUMngib9wP0P9F2mMtbSoSQ-xXRikQA6YUJPc50PPBBAhSYcQWBJJcmBfsshyIpxNHLsCiUIFIyCejdm4sARAAcQAUUYAB9XgAHkWAAaWIAAFABBGZ9OIfjTjQ9kW0QABaQiwmKadkhDQjgmSSpow8gIx3Ivkg17KIwSUPxNPVLMRAAVWsgARWzGH0oyADV9JYYgAElTIAOWcxshN9BB4jIsdhReSpIgjJrwlCkU-CoYKlQqQVYniRKDWS0r9IADUYCrXIw64Sm5XsFSSHtR1BQJ2r8f5Xg+KIww+YogiUQb5zaERrJYfTcpKlKnPrATvWEwV-nBUdR0HZqRTDNaNuqZJtu+vaDphLjf0oPTTKMxgwbsgzJsEtzMIQd4gi6ypRNBO4BWeT6wm+37dtmuoYQ8VAIDgbwgazGh6CYVgOC4WA+B-T1Yem-wxUe3sij6uIOujUSeSCKF-MFXlAmBQ6EQXXi0UGA5QJxDEmbu6q-mHVT+oTEIYkIkK5N+K9ARUeIIlHNQRUqcXtP-FFdRl0YqG3RWz2qkIkdeP5XmKEEFujUckZ+0dnj5DGewCC3geza3pYV1DmeEjzAmRlQkz8acgg+ebQqqKhGqFCNIkiIUkmhVUGPDq3c2XH8nVNdcDytR2qvcmrIx5TmhUBJIk6+XXbliLrB369SDZTgGS60svmLzKusTA8eG7hzl-l7YoqKIxUShKJ83n7tOnnC7bwkHMOKcnyvS-t5Z55ZhBin+ajfIxsUIWjfy5pSXlFVDAfQ8Bn8T6ls+c8Y5KybvHUIhE4gqFSAqPqfIdY-HejvWIlFqh8gesfSWkcoBXzjgLROydU7pzBKFdaoQc6XjBOGEUGC2g4OqvHFQV5gpJyTIQoUxDdZeVeJFD4zUIypGKD-OoQA */
|
||||
createMachine(
|
||||
{
|
||||
tsTypes: {} as import("./workspacesXService.typegen").Typegen1,
|
||||
schema: {
|
||||
context: {} as WorkspacesContext,
|
||||
events: {} as WorkspacesEvent,
|
||||
services: {} as {
|
||||
getWorkspaces: {
|
||||
data: TypesGen.Workspace[]
|
||||
}
|
||||
getWorkspacesCount: {
|
||||
data: { count: number }
|
||||
}
|
||||
updateWorkspaceRefs: {
|
||||
data: {
|
||||
refsToKeep: WorkspaceItemMachineRef[]
|
||||
newWorkspaces: TypesGen.Workspace[]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
predictableActionArguments: true,
|
||||
id: "workspacesState",
|
||||
on: {
|
||||
GET_WORKSPACES: {
|
||||
target: ".fetching",
|
||||
actions: "assignFilter",
|
||||
},
|
||||
UPDATE_VERSION: {
|
||||
actions: "triggerUpdateVersion",
|
||||
},
|
||||
NEXT: {
|
||||
target: ".fetching",
|
||||
actions: ["assignNextPage", "onPageChange"],
|
||||
},
|
||||
PREVIOUS: {
|
||||
target: ".fetching",
|
||||
actions: ["assignPreviousPage", "onPageChange"],
|
||||
},
|
||||
GO_TO_PAGE: {
|
||||
target: ".fetching",
|
||||
actions: ["assignPage", "onPageChange"],
|
||||
},
|
||||
},
|
||||
initial: "fetching",
|
||||
states: {
|
||||
waitToRefreshWorkspaces: {
|
||||
after: {
|
||||
"5000": {
|
||||
target: "#workspacesState.fetching",
|
||||
actions: [],
|
||||
internal: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
fetching: {
|
||||
type: "parallel",
|
||||
states: {
|
||||
count: {
|
||||
initial: "gettingCount",
|
||||
states: {
|
||||
gettingCount: {
|
||||
entry: "clearGetCountError",
|
||||
invoke: {
|
||||
src: "getWorkspacesCount",
|
||||
id: "getWorkspacesCount",
|
||||
onDone: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignCount",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignGetCountError",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
done: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
workspaces: {
|
||||
initial: "gettingWorkspaces",
|
||||
states: {
|
||||
updatingWorkspaceRefs: {
|
||||
invoke: {
|
||||
src: "updateWorkspaceRefs",
|
||||
id: "updateWorkspaceRefs",
|
||||
onDone: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignUpdatedWorkspaceRefs"
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
gettingWorkspaces: {
|
||||
entry: "clearGetWorkspacesError",
|
||||
invoke: {
|
||||
src: "getWorkspaces",
|
||||
id: "getWorkspaces",
|
||||
onDone: [
|
||||
{
|
||||
target: "done",
|
||||
cond: "isEmpty",
|
||||
actions: "assignWorkspaceRefs",
|
||||
},
|
||||
{
|
||||
target: "updatingWorkspaceRefs",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignGetWorkspacesError",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
done: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
onDone: {
|
||||
target: "waitToRefreshWorkspaces",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
guards: {
|
||||
isEmpty: (context) => !context.workspaceRefs,
|
||||
},
|
||||
actions: {
|
||||
assignWorkspaceRefs: assign({
|
||||
workspaceRefs: (_, event) =>
|
||||
event.data.map((data) => {
|
||||
return spawn(workspaceItemMachine.withContext({ data }), data.id)
|
||||
}),
|
||||
}),
|
||||
assignFilter: assign({
|
||||
filter: (context, event) => event.query ?? context.filter,
|
||||
}),
|
||||
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)
|
||||
},
|
||||
}),
|
||||
assignNextPage: assign({
|
||||
page: (context) => context.page + 1,
|
||||
}),
|
||||
assignPreviousPage: assign({
|
||||
page: (context) => context.page - 1,
|
||||
}),
|
||||
assignPage: assign({
|
||||
page: (_, event) => event.page,
|
||||
}),
|
||||
assignCount: assign({
|
||||
count: (_, event) => event.data.count
|
||||
})
|
||||
},
|
||||
services: {
|
||||
getWorkspaces: (context) =>
|
||||
API.getWorkspaces(queryToFilter(context.filter)),
|
||||
updateWorkspaceRefs: (context, event) => {
|
||||
const refsToKeep: WorkspaceItemMachineRef[] = []
|
||||
context.workspaceRefs?.forEach((ref) => {
|
||||
const matchingWorkspace = event.data.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()
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QHcD2AnA1rADgQwGM4BlAFz1LADpk8BLUgFVQCUwAzdOACwHUNs+IrADEAD1jlKVPO0roAFAFYADGoCUItFlyESU6rQbM2nHvx1C4AbRUBdRKBypYDOqgB2jkGMQBGAGYANgCqFQAmAE4-cIAOOPDwoIB2ZIAaEABPRHCVKljAv2S-EMiClSUAFliAXxqM7UE9WDIKanYwUgJuOg8oKgJUAFcPUioYUlJeqABhYdGRCE9qXoA3VExqCYsm4TmR0lsHJBBnVynPb18ESsq8uOLk2KCVSqVY4qUM7IQAyqoApElOFKskgpEUn5avUQI1dMJWtIOl0en0BvMxhMpn19gswOh0BgqDgADYUdgYAC2406O3hcFxh3s3jObkuJ2ufyUVEiAXi4QCySUAWBARF3xyaiowuqZShQSCiUidQaAnpLQMVGR3WmNDVVlgVCGOAgFGmdKsplESw8Kw8602RpNbQteitRxZLjZXg5iFitwByTKARUQVulQCiQlCBeeX9sWifihhXBKth+uaiPanR1aLhBppk3NGeEi2WVDWGy2tJLNmZJ1ZFx9oGub25f0jyQqSiUQvi0aUiqoiXCfnecT8kRUwTT+czmu1qP6c+EhexUFdpZtdod1dIm5sfmOTi9TauiFukWlCb5097-tD0cqQ57dw+8cCz9ntY1bS1OaXPVLGaNdi2A0t8UJdBiTJUgKXQalth-D0G1Pdxmx8fximHF5O1uVJKgFAJoxCZIqChPlIhBUMngib9wP0P9F2mMtbSoSQ-xXRikQA6YUJPc50PPBBAhSYcQWBJJcmBfsshyIpxNHLsCiUIFIyCejdm4sARAAcQAUUYAB9XgAHkWAAaWIAAFABBGZ9OIfjTjQ9kW0QABaQiwmKadkhDQjgmSSpow8gIx3Ivkg17KIwSUPxNPVLMRAAVWsgARWzGH0oyADV9JYYgAElTIAOWcxshN9BB4jIsdhReSpIgjJrwlCkU-CoYKlQqQVYniRKDWS0r9IADUYCrXIw64Sm5XsFSSHtR1BQJ2r8f5Xg+KIww+YogiUQb5zaERrJYfTcpKlKnPrATvWEwV-nBUdR0HZqRTDNaNuqZJtu+vaDphLjf0oPTTKMxgwbsgzJsEtzMIQd4gi6ypRNBO4BWeT6wm+37dtmuoYQ8VAIDgbwgazGh6CYVgOC4WA+B-T1Yem-wxUe3sij6uIOujUSeSCKF-MFXlAmBQ6EQXXi0UGA5QJxDEmbu6q-mHVT+oTEIYkIkK5N+K9ARUeIIlHNQRUqcXtP-FFdRl0YqG3RWz2qkIkdeP5XmKEEFujUckZ+0dnj5DGewCC3geza3pYV1DmeEjzAmRlQkz8acgg+ebQqqKhGqFCNIkiIUkmhVUGPDq3c2XH8nVNdcDytR2qvcmrIx5TmhUBJIk6+XXbliLrB369SDZTgGS60svmLzKusTA8eG7hzl-l7YoqKIxUShKJ83n7tOnnC7bwkHMOKcnyvS-t5Z55ZhBin+ajfIxsUIWjfy5pSXlFVDAfQ8Bn8T6ls+c8Y5KybvHUIhE4gqFSAqPqfIdY-HejvWIlFqh8gesfSWkcoBXzjgLROydU7pzBKFdaoQc6XjBOGEUGC2g4OqvHFQV5gpJyTIQoUxDdZeVeJFD4zUIypGKD-OoQA */
|
||||
createMachine(
|
||||
{
|
||||
tsTypes: {} as import("./workspacesXService.typegen").Typegen1,
|
||||
schema: {
|
||||
context: {} as WorkspacesContext,
|
||||
events: {} as WorkspacesEvent,
|
||||
services: {} as {
|
||||
getWorkspaces: {
|
||||
data: TypesGen.Workspace[]
|
||||
}
|
||||
})
|
||||
|
||||
const newWorkspaces = event.data.filter(
|
||||
(workspace) =>
|
||||
!context.workspaceRefs?.find((ref) => ref.id === workspace.id),
|
||||
)
|
||||
|
||||
return Promise.resolve({
|
||||
refsToKeep,
|
||||
newWorkspaces,
|
||||
})
|
||||
getWorkspacesCount: {
|
||||
data: { count: number }
|
||||
}
|
||||
updateWorkspaceRefs: {
|
||||
data: {
|
||||
refsToKeep: WorkspaceItemMachineRef[]
|
||||
newWorkspaces: TypesGen.Workspace[]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
predictableActionArguments: true,
|
||||
id: "workspacesState",
|
||||
on: {
|
||||
GET_WORKSPACES: {
|
||||
target: ".fetching",
|
||||
actions: "assignFilter",
|
||||
},
|
||||
UPDATE_VERSION: {
|
||||
actions: "triggerUpdateVersion",
|
||||
},
|
||||
NEXT: {
|
||||
target: ".fetching",
|
||||
actions: ["assignNextPage", "onPageChange"],
|
||||
},
|
||||
PREVIOUS: {
|
||||
target: ".fetching",
|
||||
actions: ["assignPreviousPage", "onPageChange"],
|
||||
},
|
||||
GO_TO_PAGE: {
|
||||
target: ".fetching",
|
||||
actions: ["assignPage", "onPageChange"],
|
||||
},
|
||||
},
|
||||
initial: "fetching",
|
||||
states: {
|
||||
waitToRefreshWorkspaces: {
|
||||
after: {
|
||||
"5000": {
|
||||
target: "#workspacesState.fetching",
|
||||
actions: [],
|
||||
internal: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
fetching: {
|
||||
type: "parallel",
|
||||
states: {
|
||||
count: {
|
||||
initial: "gettingCount",
|
||||
states: {
|
||||
gettingCount: {
|
||||
entry: "clearGetCountError",
|
||||
invoke: {
|
||||
src: "getWorkspacesCount",
|
||||
id: "getWorkspacesCount",
|
||||
onDone: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignCount",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignGetCountError",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
done: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
workspaces: {
|
||||
initial: "gettingWorkspaces",
|
||||
states: {
|
||||
updatingWorkspaceRefs: {
|
||||
invoke: {
|
||||
src: "updateWorkspaceRefs",
|
||||
id: "updateWorkspaceRefs",
|
||||
onDone: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignUpdatedWorkspaceRefs",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
gettingWorkspaces: {
|
||||
entry: "clearGetWorkspacesError",
|
||||
invoke: {
|
||||
src: "getWorkspaces",
|
||||
id: "getWorkspaces",
|
||||
onDone: [
|
||||
{
|
||||
target: "done",
|
||||
cond: "isEmpty",
|
||||
actions: "assignWorkspaceRefs",
|
||||
},
|
||||
{
|
||||
target: "updatingWorkspaceRefs",
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
{
|
||||
target: "done",
|
||||
actions: "assignGetWorkspacesError",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
done: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
onDone: {
|
||||
target: "waitToRefreshWorkspaces",
|
||||
},
|
||||
},
|
||||
},
|
||||
getWorkspacesCount: (context) => (
|
||||
API.getWorkspacesCount({ q: context.filter })
|
||||
)
|
||||
},
|
||||
},
|
||||
)
|
||||
{
|
||||
guards: {
|
||||
isEmpty: (context) => !context.workspaceRefs,
|
||||
},
|
||||
actions: {
|
||||
assignWorkspaceRefs: assign({
|
||||
workspaceRefs: (_, event) =>
|
||||
event.data.map((data) => {
|
||||
return spawn(workspaceItemMachine.withContext({ data }), data.id)
|
||||
}),
|
||||
}),
|
||||
assignFilter: assign({
|
||||
filter: (context, event) => event.query ?? context.filter,
|
||||
}),
|
||||
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)
|
||||
},
|
||||
}),
|
||||
assignNextPage: assign({
|
||||
page: (context) => context.page + 1,
|
||||
}),
|
||||
assignPreviousPage: assign({
|
||||
page: (context) => context.page - 1,
|
||||
}),
|
||||
assignPage: assign({
|
||||
page: (_, event) => event.page,
|
||||
}),
|
||||
assignCount: assign({
|
||||
count: (_, event) => event.data.count,
|
||||
}),
|
||||
assignGetCountError: assign({
|
||||
getCountError: (_, event) => event.data,
|
||||
}),
|
||||
clearGetCountError: assign({
|
||||
getCountError: (_) => undefined,
|
||||
}),
|
||||
},
|
||||
services: {
|
||||
getWorkspaces: (context) =>
|
||||
API.getWorkspaces(queryToFilter(context.filter)),
|
||||
updateWorkspaceRefs: (context, event) => {
|
||||
const refsToKeep: WorkspaceItemMachineRef[] = []
|
||||
context.workspaceRefs?.forEach((ref) => {
|
||||
const matchingWorkspace = event.data.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.filter(
|
||||
(workspace) =>
|
||||
!context.workspaceRefs?.find((ref) => ref.id === workspace.id),
|
||||
)
|
||||
|
||||
return Promise.resolve({
|
||||
refsToKeep,
|
||||
newWorkspaces,
|
||||
})
|
||||
},
|
||||
getWorkspacesCount: (context) =>
|
||||
API.getWorkspacesCount({ q: context.filter }),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user