mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore(site): remove workspace build machine (#9813)
This commit is contained in:
+6
-6
@@ -792,11 +792,11 @@ export const getWorkspaceBuildByNumber = async (
|
||||
};
|
||||
|
||||
export const getWorkspaceBuildLogs = async (
|
||||
buildname: string,
|
||||
buildId: string,
|
||||
before: Date,
|
||||
): Promise<TypesGen.ProvisionerJobLog[]> => {
|
||||
const response = await axios.get<TypesGen.ProvisionerJobLog[]>(
|
||||
`/api/v2/workspacebuilds/${buildname}/logs?before=${before.getTime()}`,
|
||||
`/api/v2/workspacebuilds/${buildId}/logs?before=${before.getTime()}`,
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
@@ -1432,8 +1432,8 @@ export const watchWorkspaceAgentLogs = (
|
||||
type WatchBuildLogsByBuildIdOptions = {
|
||||
after?: number;
|
||||
onMessage: (log: TypesGen.ProvisionerJobLog) => void;
|
||||
onDone: () => void;
|
||||
onError: (error: Error) => void;
|
||||
onDone?: () => void;
|
||||
onError?: (error: Error) => void;
|
||||
};
|
||||
export const watchBuildLogsByBuildId = (
|
||||
buildId: string,
|
||||
@@ -1454,12 +1454,12 @@ export const watchBuildLogsByBuildId = (
|
||||
onMessage(JSON.parse(event.data) as TypesGen.ProvisionerJobLog),
|
||||
);
|
||||
socket.addEventListener("error", () => {
|
||||
onError(new Error("Connection for logs failed."));
|
||||
onError && onError(new Error("Connection for logs failed."));
|
||||
socket.close();
|
||||
});
|
||||
socket.addEventListener("close", () => {
|
||||
// When the socket closes, logs have finished streaming!
|
||||
onDone();
|
||||
onDone && onDone();
|
||||
});
|
||||
return socket;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import * as API from "api/api";
|
||||
|
||||
export const workspaceBuildByNumber = (
|
||||
username: string,
|
||||
workspaceName: string,
|
||||
buildNumber: number,
|
||||
) => {
|
||||
return {
|
||||
queryKey: [username, workspaceName, "workspaceBuild", buildNumber],
|
||||
queryFn: () =>
|
||||
API.getWorkspaceBuildByNumber(username, workspaceName, buildNumber),
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
import { watchBuildLogsByBuildId } from "api/api";
|
||||
import { ProvisionerJobLog } from "api/typesGenerated";
|
||||
import { displayError } from "components/GlobalSnackbar/utils";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
// buildId is optional because sometimes the build is not loaded yet
|
||||
export const useWorkspaceBuildLogs = (buildId?: string) => {
|
||||
const [logs, setLogs] = useState<ProvisionerJobLog[]>();
|
||||
useEffect(() => {
|
||||
if (!buildId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Every time this hook is called reset the values
|
||||
setLogs(undefined);
|
||||
|
||||
const socket = watchBuildLogsByBuildId(buildId, {
|
||||
// Retrieve all the logs
|
||||
after: -1,
|
||||
onMessage: (log) => {
|
||||
setLogs((previousLogs) => {
|
||||
if (!previousLogs) {
|
||||
return [log];
|
||||
}
|
||||
return [...previousLogs, log];
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
displayError("Error on getting the build logs");
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.close();
|
||||
};
|
||||
}, [buildId]);
|
||||
|
||||
return logs;
|
||||
};
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useMachine } from "@xstate/react";
|
||||
import { FC, useEffect } from "react";
|
||||
import { FC } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { pageTitle } from "../../utils/page";
|
||||
import { workspaceBuildMachine } from "../../xServices/workspaceBuild/workspaceBuildXService";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { WorkspaceBuildPageView } from "./WorkspaceBuildPageView";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getWorkspaceBuilds } from "api/api";
|
||||
import dayjs from "dayjs";
|
||||
import { workspaceBuildByNumber } from "api/queries/workspaceBuilds";
|
||||
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
|
||||
|
||||
export const WorkspaceBuildPage: FC = () => {
|
||||
const params = useParams() as {
|
||||
@@ -18,10 +18,11 @@ export const WorkspaceBuildPage: FC = () => {
|
||||
const workspaceName = params.workspace;
|
||||
const buildNumber = Number(params.buildNumber);
|
||||
const username = params.username.replace("@", "");
|
||||
const [buildState, send] = useMachine(workspaceBuildMachine, {
|
||||
context: { username, workspaceName, buildNumber, timeCursor: new Date() },
|
||||
const wsBuildQuery = useQuery({
|
||||
...workspaceBuildByNumber(username, workspaceName, buildNumber),
|
||||
keepPreviousData: true,
|
||||
});
|
||||
const { logs, build } = buildState.context;
|
||||
const build = wsBuildQuery.data;
|
||||
const { data: builds } = useQuery({
|
||||
queryKey: ["builds", username, build?.workspace_id],
|
||||
queryFn: () => {
|
||||
@@ -32,10 +33,7 @@ export const WorkspaceBuildPage: FC = () => {
|
||||
},
|
||||
enabled: Boolean(build),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
send("RESET", { buildNumber, timeCursor: new Date() });
|
||||
}, [buildNumber, send]);
|
||||
const logs = useWorkspaceBuildLogs(build?.id);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useActor, useMachine } from "@xstate/react";
|
||||
import { useActor } from "@xstate/react";
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||
import dayjs from "dayjs";
|
||||
import { useFeatureVisibility } from "hooks/useFeatureVisibility";
|
||||
@@ -28,12 +28,12 @@ import {
|
||||
ConfirmDialog,
|
||||
ConfirmDialogProps,
|
||||
} from "components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import { workspaceBuildMachine } from "xServices/workspaceBuild/workspaceBuildXService";
|
||||
import * as TypesGen from "api/typesGenerated";
|
||||
import { WorkspaceBuildLogsSection } from "./WorkspaceBuildLogsSection";
|
||||
import { templateVersion, templateVersions } from "api/queries/templates";
|
||||
import { Alert } from "components/Alert/Alert";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
|
||||
|
||||
interface WorkspaceReadyPageProps {
|
||||
workspaceState: StateFrom<typeof workspaceMachine>;
|
||||
@@ -91,7 +91,7 @@ export const WorkspaceReadyPage = ({
|
||||
enabled: workspace.outdated,
|
||||
});
|
||||
|
||||
const buildLogs = useBuildLogs(workspace);
|
||||
const buildLogs = useWorkspaceBuildLogs(workspace.latest_build.id);
|
||||
const shouldDisplayBuildLogs =
|
||||
hasJobError(workspace) ||
|
||||
["canceling", "deleting", "pending", "starting", "stopping"].includes(
|
||||
@@ -285,22 +285,3 @@ const WarningDialog: FC<
|
||||
> = (props) => {
|
||||
return <ConfirmDialog type="info" hideCancel={false} {...props} />;
|
||||
};
|
||||
|
||||
const useBuildLogs = (workspace: TypesGen.Workspace) => {
|
||||
const buildNumber = workspace.latest_build.build_number;
|
||||
const [buildState, buildSend] = useMachine(workspaceBuildMachine, {
|
||||
context: {
|
||||
buildNumber,
|
||||
username: workspace.owner_name,
|
||||
workspaceName: workspace.name,
|
||||
timeCursor: new Date(),
|
||||
},
|
||||
});
|
||||
const { logs } = buildState.context;
|
||||
|
||||
useEffect(() => {
|
||||
buildSend({ type: "RESET", buildNumber, timeCursor: new Date() });
|
||||
}, [buildNumber, buildSend]);
|
||||
|
||||
return logs;
|
||||
};
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
import { assign, createMachine } from "xstate";
|
||||
import * as API from "../../api/api";
|
||||
import { ProvisionerJobLog, WorkspaceBuild } from "../../api/typesGenerated";
|
||||
|
||||
type LogsContext = {
|
||||
// Build
|
||||
username: string;
|
||||
workspaceName: string;
|
||||
buildNumber: number;
|
||||
buildId: string;
|
||||
// Used to reference logs before + after.
|
||||
timeCursor: Date;
|
||||
build?: WorkspaceBuild;
|
||||
getBuildError?: unknown;
|
||||
// Logs
|
||||
logs?: ProvisionerJobLog[];
|
||||
};
|
||||
|
||||
type LogsEvent =
|
||||
| {
|
||||
type: "ADD_LOG";
|
||||
log: ProvisionerJobLog;
|
||||
}
|
||||
| {
|
||||
type: "BUILD_DONE";
|
||||
}
|
||||
| {
|
||||
type: "RESET";
|
||||
buildNumber: number;
|
||||
timeCursor: Date;
|
||||
};
|
||||
|
||||
export const workspaceBuildMachine = createMachine(
|
||||
{
|
||||
id: "workspaceBuildState",
|
||||
predictableActionArguments: true,
|
||||
tsTypes: {} as import("./workspaceBuildXService.typegen").Typegen0,
|
||||
schema: {
|
||||
context: {} as LogsContext,
|
||||
events: {} as LogsEvent,
|
||||
services: {} as {
|
||||
getWorkspaceBuild: {
|
||||
data: WorkspaceBuild;
|
||||
};
|
||||
getLogs: {
|
||||
data: ProvisionerJobLog[];
|
||||
};
|
||||
},
|
||||
},
|
||||
initial: "gettingBuild",
|
||||
on: {
|
||||
RESET: {
|
||||
target: "gettingBuild",
|
||||
actions: ["resetContext"],
|
||||
},
|
||||
},
|
||||
states: {
|
||||
gettingBuild: {
|
||||
entry: "clearGetBuildError",
|
||||
invoke: {
|
||||
src: "getWorkspaceBuild",
|
||||
onDone: {
|
||||
target: "logs",
|
||||
actions: ["assignBuild", "assignBuildId"],
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: "assignGetBuildError",
|
||||
},
|
||||
},
|
||||
},
|
||||
idle: {},
|
||||
logs: {
|
||||
initial: "gettingExistentLogs",
|
||||
states: {
|
||||
gettingExistentLogs: {
|
||||
invoke: {
|
||||
id: "getLogs",
|
||||
src: "getLogs",
|
||||
onDone: {
|
||||
actions: ["assignLogs"],
|
||||
target: "watchingLogs",
|
||||
},
|
||||
},
|
||||
},
|
||||
watchingLogs: {
|
||||
id: "watchingLogs",
|
||||
invoke: {
|
||||
id: "streamWorkspaceBuildLogs",
|
||||
src: "streamWorkspaceBuildLogs",
|
||||
},
|
||||
on: {
|
||||
ADD_LOG: {
|
||||
actions: "addLog",
|
||||
},
|
||||
BUILD_DONE: {
|
||||
target: "loaded",
|
||||
},
|
||||
},
|
||||
},
|
||||
loaded: {
|
||||
type: "final",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
resetContext: assign({
|
||||
buildNumber: (_, event) => event.buildNumber,
|
||||
timeCursor: (_, event) => event.timeCursor,
|
||||
logs: undefined,
|
||||
}),
|
||||
// Build ID
|
||||
assignBuildId: assign({
|
||||
buildId: (_, event) => event.data.id,
|
||||
}),
|
||||
// Build
|
||||
assignBuild: assign({
|
||||
build: (_, event) => event.data,
|
||||
}),
|
||||
assignGetBuildError: assign({
|
||||
getBuildError: (_, event) => event.data,
|
||||
}),
|
||||
clearGetBuildError: assign({
|
||||
getBuildError: (_) => undefined,
|
||||
}),
|
||||
// Logs
|
||||
assignLogs: assign({
|
||||
logs: (_, event) => event.data,
|
||||
}),
|
||||
addLog: assign({
|
||||
logs: (context, event) => {
|
||||
const previousLogs = context.logs ?? [];
|
||||
return [...previousLogs, event.log];
|
||||
},
|
||||
}),
|
||||
},
|
||||
services: {
|
||||
getWorkspaceBuild: (ctx) =>
|
||||
API.getWorkspaceBuildByNumber(
|
||||
ctx.username,
|
||||
ctx.workspaceName,
|
||||
ctx.buildNumber,
|
||||
),
|
||||
getLogs: async (ctx) =>
|
||||
API.getWorkspaceBuildLogs(ctx.buildId, ctx.timeCursor),
|
||||
streamWorkspaceBuildLogs: (ctx) => async (callback) => {
|
||||
if (!ctx.logs) {
|
||||
throw new Error("logs must be set");
|
||||
}
|
||||
const after =
|
||||
ctx.logs.length > 0 ? ctx.logs[ctx.logs.length - 1].id : undefined;
|
||||
const socket = API.watchBuildLogsByBuildId(ctx.buildId, {
|
||||
after,
|
||||
onMessage: (log) => {
|
||||
callback({ type: "ADD_LOG", log });
|
||||
},
|
||||
onDone: () => {
|
||||
callback({ type: "BUILD_DONE" });
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
},
|
||||
});
|
||||
return () => {
|
||||
socket.close();
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user