Skip to content

Commit e2f99c7

Browse files
Merge pull request #247 from pascalbreuninger/main
feat(ui): trigger `check status` action if workspace status is unknow…
2 parents 14cd68f + 9574681 commit e2f99c7

File tree

12 files changed

+138
-56
lines changed

12 files changed

+138
-56
lines changed

desktop/src/client/workspaces/client.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ export class WorkspacesClient implements TDebuggable {
8282
if (result.err) {
8383
return result
8484
}
85+
86+
return result
8587
}
8688

8789
public setDebug(isEnabled: boolean): void {
@@ -93,7 +95,7 @@ export class WorkspacesClient implements TDebuggable {
9395
}
9496

9597
public async getStatus(id: TWorkspaceID): Promise<Result<TWorkspace["status"]>> {
96-
const result = await WorkspaceCommands.GetWorkspaceStatus(id)
98+
const result = await WorkspaceCommands.FetchWorkspaceStatus(id)
9799
if (result.err) {
98100
return result
99101
}
@@ -114,7 +116,7 @@ export class WorkspacesClient implements TDebuggable {
114116
): Promise<Result<TWorkspace["status"]>> {
115117
const cmd = WorkspaceCommands.StartWorkspace(ctx.id, config)
116118
const result = await this.execActionCmd(cmd, { ...ctx, listener, actionName: "start" })
117-
if (result?.err) {
119+
if (result.err) {
118120
return result
119121
}
120122

@@ -127,7 +129,7 @@ export class WorkspacesClient implements TDebuggable {
127129
): Promise<Result<TWorkspace["status"]>> {
128130
const cmd = WorkspaceCommands.StopWorkspace(ctx.id)
129131
const result = await this.execActionCmd(cmd, { ...ctx, listener, actionName: "stop" })
130-
if (result?.err) {
132+
if (result.err) {
131133
return result
132134
}
133135

@@ -140,7 +142,7 @@ export class WorkspacesClient implements TDebuggable {
140142
): Promise<Result<TWorkspace["status"]>> {
141143
const cmd = WorkspaceCommands.RebuildWorkspace(ctx.id)
142144
const result = await this.execActionCmd(cmd, { ...ctx, listener, actionName: "rebuild" })
143-
if (result?.err) {
145+
if (result.err) {
144146
return result
145147
}
146148

@@ -151,10 +153,23 @@ export class WorkspacesClient implements TDebuggable {
151153
force: boolean,
152154
listener: TStreamEventListenerFn | undefined,
153155
ctx: TWorkspaceClientContext
154-
): Promise<ResultError> {
156+
): Promise<Result<TWorkspace["status"]>> {
155157
const cmd = WorkspaceCommands.RemoveWorkspace(ctx.id, force)
156158
const result = await this.execActionCmd(cmd, { ...ctx, listener, actionName: "remove" })
157-
if (result?.err) {
159+
if (result.err) {
160+
return result
161+
}
162+
163+
return result
164+
}
165+
166+
public async checkStatus(
167+
listener: TStreamEventListenerFn | undefined,
168+
ctx: TWorkspaceClientContext
169+
): Promise<ResultError> {
170+
const cmd = WorkspaceCommands.GetStatusLogs(ctx.id)
171+
const result = await this.execActionCmd(cmd, { ...ctx, listener, actionName: "checkStatus" })
172+
if (result.err) {
158173
return result
159174
}
160175

desktop/src/client/workspaces/workspaceCommands.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ export class WorkspaceCommands {
5151
)
5252
}
5353

54-
static async GetWorkspaceStatus(id: string): Promise<Result<Pick<TWorkspace, "id" | "status">>> {
54+
static async FetchWorkspaceStatus(
55+
id: string
56+
): Promise<Result<Pick<TWorkspace, "id" | "status">>> {
5557
const result = await new Command([DEVPOD_COMMAND_STATUS, id, DEVPOD_FLAG_JSON_OUTPUT]).run()
5658
if (result.err) {
5759
return result
@@ -83,6 +85,10 @@ export class WorkspaceCommands {
8385
return Return.Value(result.val.stdout)
8486
}
8587

88+
static GetStatusLogs(id: string) {
89+
return new Command([DEVPOD_COMMAND_STATUS, id, DEVPOD_FLAG_JSON_LOG_OUTPUT])
90+
}
91+
8692
static StartWorkspace(id: TWorkspaceID, config: TWorkspaceStartConfig) {
8793
const maybeSource = config.sourceConfig?.source
8894
const maybeIDFlag = exists(maybeSource) ? [toFlagArg(DEVPOD_FLAG_ID, id)] : []

desktop/src/contexts/DevPodContext/action/action.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Result, SingleEventManager, EventManager } from "../../../lib"
22

3-
export type TActionName = "start" | "stop" | "rebuild" | "remove"
3+
export type TActionName = "start" | "stop" | "rebuild" | "remove" | "checkStatus"
44
export type TActionFn = (context: TActionContext) => Promise<Result<unknown>>
55
export type TActionStatus = "pending" | "success" | "error" | "cancelled"
66
export type TActionID = Action["id"]

desktop/src/contexts/DevPodContext/workspaces/useWorkspace.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export type TWorkspaceResult = Readonly<{
3030
stop: (onStream?: TStreamEventListenerFn) => TActionID | undefined
3131
remove: (force: boolean, onStream?: TStreamEventListenerFn) => TActionID | undefined
3232
rebuild: (onStream?: TStreamEventListenerFn) => TActionID | undefined
33+
checkStatus: (onStream?: TStreamEventListenerFn) => TActionID | undefined
3334
}>
3435

3536
export function useWorkspaceActions(
@@ -107,6 +108,33 @@ export function useWorkspace(workspaceID: TWorkspaceID | undefined): TWorkspaceR
107108
[viewID, workspaceID]
108109
)
109110

111+
const checkStatus = useCallback<TWorkspaceResult["stop"]>(
112+
(onStream) => {
113+
if (workspaceID === undefined) {
114+
return
115+
}
116+
117+
return devPodStore.startAction({
118+
actionName: "checkStatus",
119+
workspaceID,
120+
actionFn: async (ctx) => {
121+
const result = await client.workspaces.checkStatus(onStream, {
122+
id: workspaceID,
123+
actionID: ctx.id,
124+
streamID: viewID,
125+
})
126+
if (result.err) {
127+
return result
128+
}
129+
devPodStore.setStatus(workspaceID, result.val)
130+
131+
return result
132+
},
133+
})
134+
},
135+
[viewID, workspaceID]
136+
)
137+
110138
const stop = useCallback<TWorkspaceResult["stop"]>(
111139
(onStream) => {
112140
if (workspaceID === undefined) {
@@ -222,8 +250,9 @@ export function useWorkspace(workspaceID: TWorkspaceID | undefined): TWorkspaceR
222250
stop,
223251
rebuild,
224252
remove,
253+
checkStatus,
225254
}),
226-
[data, isLoading, current, history, create, start, stop, rebuild, remove]
255+
[data, isLoading, current, history, create, start, stop, rebuild, remove, checkStatus]
227256
)
228257
}
229258

desktop/src/lib/helpers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ export function sleep(ms: number): Promise<void> {
9999
}
100100

101101
export function getActionDisplayName(action: TActionObj): string {
102+
if (action.name === "checkStatus") {
103+
return `check status ${action.targetID}`
104+
}
105+
102106
return `${action.name} ${action.targetID}`
103107
}
104108

desktop/src/lib/useHover.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
import { MutableRefObject, useEffect, useRef, useState } from "react"
1+
import { LegacyRef, useEffect, useRef, useState } from "react"
22

3-
export function useHover<T extends HTMLElement>(): [boolean, MutableRefObject<T | null>] {
3+
export function useHover<T extends HTMLButtonElement>(): [boolean, LegacyRef<T>] {
44
const [isHovering, setIsHovering] = useState<boolean>(false)
55

6-
const ref = useRef<T | null>(null)
6+
const ref = useRef<T>(null)
77

88
useEffect(
99
() => {
10-
const node = ref.current
11-
const handleMouseOver = (): void => setIsHovering(true)
12-
const handleMouseOut = (): void => setIsHovering(false)
13-
if (node) {
14-
node.addEventListener("mouseover", handleMouseOver)
15-
node.addEventListener("mouseout", handleMouseOut)
10+
const handleMouseOver = () => setIsHovering(true)
11+
const handleMouseOut = () => setIsHovering(false)
1612

17-
return () => {
18-
node.removeEventListener("mouseover", handleMouseOver)
19-
node.removeEventListener("mouseout", handleMouseOut)
13+
setTimeout(() => {
14+
const node = ref.current
15+
if (node) {
16+
node.addEventListener("mouseover", handleMouseOver)
17+
node.addEventListener("mouseout", handleMouseOut)
18+
19+
return () => {
20+
node.removeEventListener("mouseover", handleMouseOver)
21+
node.removeEventListener("mouseout", handleMouseOut)
22+
}
2023
}
21-
}
24+
})
2225
},
2326
// rerun if ref changes!
2427
// eslint-disable-next-line react-hooks/exhaustive-deps

desktop/src/views/Providers/AddProvider/ConfigureProviderOptionsForm.tsx

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -312,18 +312,7 @@ export function ConfigureProviderOptionsForm({
312312
)}
313313
</HStack>
314314

315-
<HStack>
316-
{addProvider && (
317-
<Text
318-
position="absolute"
319-
left="50%"
320-
fontWeight="medium"
321-
fontFamily="monospace"
322-
color="gray.700">
323-
{provider?.config?.name}
324-
</Text>
325-
)}
326-
</HStack>
315+
<HStack />
327316

328317
<Popover placement="top" computePositionOnMount>
329318
<PopoverTrigger>

desktop/src/views/Providers/AddProvider/SetupProviderSourceForm.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,6 @@ export function SetupProviderSourceForm({
157157
preferredProviderName = providerIDRes.val
158158
}
159159

160-
console.log(maybeProviderName, providerSource, preferredProviderName)
161-
162160
removeDanglingProviders()
163161
// custom name taken
164162
if (maybeProviderName !== undefined && providers?.[maybeProviderName] !== undefined) {
@@ -178,7 +176,10 @@ export function SetupProviderSourceForm({
178176
}
179177
} else {
180178
setValue(FieldName.PROVIDER_NAME, undefined, opts)
181-
addProvider({ rawProviderSource: providerSource, config: { name: maybeProviderName } })
179+
addProvider({
180+
rawProviderSource: providerSource,
181+
config: { name: maybeProviderName ?? preferredProviderName },
182+
})
182183
}
183184
},
184185
[addProvider, providers, removeDanglingProviders, setValue]
@@ -209,9 +210,8 @@ export function SetupProviderSourceForm({
209210
shouldValidate: true,
210211
}
211212
setValue(FieldName.PROVIDER_SOURCE, sourceName, opts)
213+
setValue(FieldName.PROVIDER_NAME, undefined, opts)
212214
if (providerSource === sourceName) {
213-
setValue(FieldName.PROVIDER_NAME, undefined, opts)
214-
215215
return
216216
}
217217

@@ -247,8 +247,9 @@ export function SetupProviderSourceForm({
247247
}
248248
setValue(FieldName.PROVIDER_SOURCE, "", opts)
249249
setValue(FieldName.PROVIDER_NAME, undefined, opts)
250+
removeDanglingProviders()
250251
reset()
251-
}, [reset, setValue])
252+
}, [removeDanglingProviders, reset, setValue])
252253

253254
const isLoading = formState.isSubmitting || status === "loading"
254255
const exampleCardSize = useBreakpointValue<"md" | "lg">({ base: "md", xl: "lg" })
@@ -259,7 +260,7 @@ export function SetupProviderSourceForm({
259260
return (
260261
<>
261262
<Form onSubmit={handleSubmit(onSubmit)} spellCheck={false}>
262-
<Stack spacing={6} width="full" alignItems="center" paddingBottom="8">
263+
<Stack spacing={6} width="full" alignItems="center" paddingBottom={8}>
263264
<FormControl
264265
isRequired
265266
isInvalid={exists(providerSourceError)}

desktop/src/views/Providers/AddProvider/SetupProviderSteps.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@ import { ConfigureProviderOptionsForm } from "./ConfigureProviderOptionsForm"
55
import { SetupProviderSourceForm } from "./SetupProviderSourceForm"
66
import { useSetupProvider } from "./useSetupProvider"
77

8+
type TSetupProviderStepsProps = Readonly<{
9+
onFinish?: () => void
10+
suggestedProvider?: TProviderID
11+
isModal?: boolean
12+
onProviderIDChanged?: (id: string | null) => void
13+
}>
814
export function SetupProviderSteps({
915
onFinish,
1016
suggestedProvider,
17+
onProviderIDChanged,
1118
isModal = false,
12-
}: Readonly<{ onFinish?: () => void; suggestedProvider?: TProviderID; isModal?: boolean }>) {
19+
}: TSetupProviderStepsProps) {
1320
const openLockRef = useRef(false)
1421
const configureProviderRef = useRef<HTMLDivElement>(null)
1522
const {
@@ -26,6 +33,14 @@ export function SetupProviderSteps({
2633
}
2734
}, [onFinish, state.currentStep])
2835

36+
useEffect(() => {
37+
if (state.providerID) {
38+
onProviderIDChanged?.(state.providerID)
39+
40+
return () => onProviderIDChanged?.(null)
41+
}
42+
}, [onProviderIDChanged, state.providerID])
43+
2944
const scrollToElement = useCallback((el: HTMLElement | null) => {
3045
if (!openLockRef.current) {
3146
openLockRef.current = true
@@ -53,7 +68,7 @@ export function SetupProviderSteps({
5368
/>
5469
</VStack>
5570

56-
<VStack align="start" spacing={8} marginTop={6} width="full">
71+
<VStack align="start" spacing={8} marginTop={4} width="full">
5772
<Box width="full" ref={configureProviderRef}>
5873
{state.currentStep === "configure-provider" && (
5974
<VStack align="start" width="full">

desktop/src/views/Providers/AddProvider/useSetupProvider.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ export function useSetupProvider() {
7878

7979
const removeDanglingProviders = useCallback(() => {
8080
const danglingProviderIDs = client.providers.popAllDangling()
81+
console.log(danglingProviderIDs)
8182
for (const danglingProviderID of danglingProviderIDs) {
8283
remove.run({ providerID: danglingProviderID })
8384
}
8485
}, [remove])
8586

8687
useEffect(() => {
88+
console.log(state)
8789
if (state.currentStep === "done") {
8890
client.providers.popDangling()
8991

@@ -94,10 +96,11 @@ export function useSetupProvider() {
9496
}
9597

9698
client.providers.setDangling(state.providerID)
97-
}, [remove, removeDanglingProviders, state])
99+
}, [state])
98100

99101
useEffect(() => {
100102
return () => {
103+
console.log("unmounting")
101104
removeDanglingProviders()
102105
}
103106
// We need to ensure this effect only runs when the hook unmounts at the cost of potentially stale dependencies

0 commit comments

Comments
 (0)