mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore(site): refactor workspace quota to use react-query instead of XState (#9626)
This commit is contained in:
+4
-2
@@ -961,9 +961,11 @@ export const deleteGroup = async (groupId: string): Promise<void> => {
|
||||
};
|
||||
|
||||
export const getWorkspaceQuota = async (
|
||||
userID: string,
|
||||
username: string,
|
||||
): Promise<TypesGen.WorkspaceQuota> => {
|
||||
const response = await axios.get(`/api/v2/workspace-quota/${userID}`);
|
||||
const response = await axios.get(
|
||||
`/api/v2/workspace-quota/${encodeURIComponent(username)}`,
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import * as API from "api/api";
|
||||
|
||||
const getWorkspaceQuotaQueryKey = (username: string) => [
|
||||
username,
|
||||
"workspaceQuota",
|
||||
];
|
||||
|
||||
export const workspaceQuota = (username: string) => {
|
||||
return {
|
||||
queryKey: getWorkspaceQuotaQueryKey(username),
|
||||
queryFn: () => API.getWorkspaceQuota(username),
|
||||
};
|
||||
};
|
||||
@@ -68,7 +68,7 @@ export interface WorkspaceProps {
|
||||
buildInfo?: TypesGen.BuildInfoResponse;
|
||||
sshPrefix?: string;
|
||||
template?: TypesGen.Template;
|
||||
quota_budget?: number;
|
||||
quotaBudget?: number;
|
||||
handleBuildRetry: () => void;
|
||||
buildLogs?: React.ReactNode;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
buildInfo,
|
||||
sshPrefix,
|
||||
template,
|
||||
quota_budget,
|
||||
quotaBudget,
|
||||
handleBuildRetry,
|
||||
templateWarnings,
|
||||
buildLogs,
|
||||
@@ -183,7 +183,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||
|
||||
<WorkspaceStats
|
||||
workspace={workspace}
|
||||
quota_budget={quota_budget}
|
||||
quotaBudget={quotaBudget}
|
||||
handleUpdate={handleUpdate}
|
||||
canUpdateWorkspace={canUpdateWorkspace}
|
||||
maxDeadlineDecrease={scheduleProps.maxDeadlineDecrease}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { FC } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { quotaMachine } from "xServices/quotas/quotasXService";
|
||||
import { workspaceMachine } from "xServices/workspace/workspaceXService";
|
||||
import { WorkspaceReadyPage } from "./WorkspaceReadyPage";
|
||||
import { RequirePermission } from "components/RequirePermission/RequirePermission";
|
||||
@@ -11,6 +10,8 @@ import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { useOrganizationId } from "hooks";
|
||||
import { isAxiosError } from "axios";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
import { workspaceQuota } from "api/queries/workspaceQuota";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
export const WorkspacePage: FC = () => {
|
||||
const params = useParams() as {
|
||||
@@ -28,9 +29,8 @@ export const WorkspacePage: FC = () => {
|
||||
},
|
||||
});
|
||||
const { workspace, error } = workspaceState.context;
|
||||
const [quotaState] = useMachine(quotaMachine, { context: { username } });
|
||||
const { getQuotaError } = quotaState.context;
|
||||
const pageError = error ?? getQuotaError;
|
||||
const quotaQuery = useQuery(workspaceQuota(username));
|
||||
const pageError = error ?? quotaQuery.error;
|
||||
|
||||
return (
|
||||
<RequirePermission
|
||||
@@ -48,12 +48,12 @@ export const WorkspacePage: FC = () => {
|
||||
condition={
|
||||
Boolean(workspace) &&
|
||||
workspaceState.matches("ready") &&
|
||||
quotaState.matches("success")
|
||||
quotaQuery.isSuccess
|
||||
}
|
||||
>
|
||||
<WorkspaceReadyPage
|
||||
workspaceState={workspaceState}
|
||||
quotaState={quotaState}
|
||||
quota={quotaQuery.data}
|
||||
workspaceSend={workspaceSend}
|
||||
/>
|
||||
</Cond>
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
getMaxDeadlineChange,
|
||||
getMinDeadline,
|
||||
} from "utils/schedule";
|
||||
import { quotaMachine } from "xServices/quotas/quotasXService";
|
||||
import { StateFrom } from "xstate";
|
||||
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog";
|
||||
import { Workspace, WorkspaceErrors } from "./Workspace";
|
||||
@@ -38,14 +37,14 @@ import { WorkspaceBuildLogsSection } from "./WorkspaceBuildLogsSection";
|
||||
|
||||
interface WorkspaceReadyPageProps {
|
||||
workspaceState: StateFrom<typeof workspaceMachine>;
|
||||
quotaState: StateFrom<typeof quotaMachine>;
|
||||
workspaceSend: (event: WorkspaceEvent) => void;
|
||||
quota?: TypesGen.WorkspaceQuota;
|
||||
}
|
||||
|
||||
export const WorkspaceReadyPage = ({
|
||||
workspaceState,
|
||||
quotaState,
|
||||
workspaceSend,
|
||||
quota,
|
||||
}: WorkspaceReadyPageProps): JSX.Element => {
|
||||
const [_, bannerSend] = useActor(
|
||||
workspaceState.children["scheduleBannerMachine"],
|
||||
@@ -186,7 +185,7 @@ export const WorkspaceReadyPage = ({
|
||||
buildInfo={buildInfo}
|
||||
sshPrefix={sshPrefix}
|
||||
template={template}
|
||||
quota_budget={quotaState.context.quota?.budget}
|
||||
quotaBudget={quota?.budget}
|
||||
templateWarnings={templateVersion?.warnings}
|
||||
buildLogs={
|
||||
shouldDisplayBuildLogs && (
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface WorkspaceStatsProps {
|
||||
maxDeadlineIncrease: number;
|
||||
maxDeadlineDecrease: number;
|
||||
canUpdateWorkspace: boolean;
|
||||
quota_budget?: number;
|
||||
quotaBudget?: number;
|
||||
onDeadlinePlus: (hours: number) => void;
|
||||
onDeadlineMinus: (hours: number) => void;
|
||||
handleUpdate: () => void;
|
||||
@@ -47,7 +47,7 @@ export interface WorkspaceStatsProps {
|
||||
|
||||
export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
workspace,
|
||||
quota_budget,
|
||||
quotaBudget,
|
||||
maxDeadlineDecrease,
|
||||
maxDeadlineIncrease,
|
||||
canUpdateWorkspace,
|
||||
@@ -169,7 +169,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
|
||||
className={styles.statsItem}
|
||||
label={Language.costLabel}
|
||||
value={`${workspace.latest_build.daily_cost} ${
|
||||
quota_budget ? `/ ${quota_budget}` : ""
|
||||
quotaBudget ? `/ ${quotaBudget}` : ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { assign, createMachine } from "xstate";
|
||||
import * as API from "../../api/api";
|
||||
import { WorkspaceQuota } from "../../api/typesGenerated";
|
||||
|
||||
export type QuotaContext = {
|
||||
username: string;
|
||||
quota?: WorkspaceQuota;
|
||||
getQuotaError?: unknown;
|
||||
};
|
||||
|
||||
export const quotaMachine = createMachine(
|
||||
{
|
||||
id: "quotasMachine",
|
||||
predictableActionArguments: true,
|
||||
tsTypes: {} as import("./quotasXService.typegen").Typegen0,
|
||||
schema: {
|
||||
context: {} as QuotaContext,
|
||||
services: {
|
||||
getQuota: {
|
||||
data: {} as WorkspaceQuota,
|
||||
},
|
||||
},
|
||||
},
|
||||
initial: "gettingQuotas",
|
||||
states: {
|
||||
idle: {},
|
||||
gettingQuotas: {
|
||||
entry: "clearGetQuotaError",
|
||||
invoke: {
|
||||
id: "getQuota",
|
||||
src: "getQuota",
|
||||
onDone: {
|
||||
target: "success",
|
||||
actions: ["assignQuota"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: ["assignGetQuotaError"],
|
||||
},
|
||||
},
|
||||
},
|
||||
success: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
assignQuota: assign({
|
||||
quota: (_, event) => event.data,
|
||||
}),
|
||||
assignGetQuotaError: assign({
|
||||
getQuotaError: (_, event) => event.data,
|
||||
}),
|
||||
clearGetQuotaError: assign({
|
||||
getQuotaError: (_) => undefined,
|
||||
}),
|
||||
},
|
||||
services: {
|
||||
getQuota: ({ username }) => API.getWorkspaceQuota(username),
|
||||
},
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user