Skip to content

Commit

Permalink
simplify some of the instance state business
Browse files Browse the repository at this point in the history
  • Loading branch information
david-crespo committed Mar 5, 2025
1 parent 7581cf4 commit b14857b
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 57 deletions.
60 changes: 8 additions & 52 deletions app/components/StopInstancePrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,87 +5,43 @@
*
* Copyright Oxide Computer Company
*/
import { useEffect, useState, type ReactNode } from 'react'
import { type ReactNode } from 'react'

import {
instanceTransitioning,
useApiMutation,
useApiQuery,
useApiQueryClient,
type Instance,
} from '@oxide/api'
import { apiQueryClient, useApiMutation, type Instance } from '@oxide/api'

import { HL } from '~/components/HL'
import { addToast } from '~/stores/toast'
import { Button } from '~/ui/lib/Button'
import { Message } from '~/ui/lib/Message'

const POLL_INTERVAL_FAST = 2000 // 2 seconds

type StopInstancePromptProps = {
instance: Instance
children: ReactNode
}

export function StopInstancePrompt({ instance, children }: StopInstancePromptProps) {
const queryClient = useApiQueryClient()
const [isStoppingInstance, setIsStoppingInstance] = useState(false)

const { data } = useApiQuery(
'instanceView',
{
path: { instance: instance.name },
query: { project: instance.projectId },
},
{
refetchInterval:
isStoppingInstance || instanceTransitioning(instance) ? POLL_INTERVAL_FAST : false,
}
)
const isStoppingInstance = instance.runState === 'stopping'

const { mutateAsync: stopInstanceAsync } = useApiMutation('instanceStop', {
onSuccess: () => {
setIsStoppingInstance(true)
addToast(
<>
Stopping instance <HL>{instance.name}</HL>
</>
)
addToast(<>Stopping instance <HL>{instance.name}</HL></>) // prettier-ignore
},
onError: (error) => {
addToast({
variant: 'error',
title: `Error stopping instance '${instance.name}'`,
content: error.message,
})
setIsStoppingInstance(false)
},
})

const handleStopInstance = () => {
stopInstanceAsync({
const handleStopInstance = async () => {
await stopInstanceAsync({
path: { instance: instance.name },
query: { project: instance.projectId },
})
}

const currentInstance = data || instance

useEffect(() => {
if (!data) {
return
}
if (isStoppingInstance && data.runState === 'stopped') {
queryClient.invalidateQueries('instanceView')
setIsStoppingInstance(false)
}
}, [isStoppingInstance, data, queryClient])

if (
!currentInstance ||
(currentInstance.runState !== 'stopping' && currentInstance.runState !== 'running')
) {
return null
// doing this after means it triggers polling by the top level InstancePage one
apiQueryClient.invalidateQueries('instanceView')
}

return (
Expand Down
14 changes: 9 additions & 5 deletions app/forms/disk-attach.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type AttachDiskProps = {
diskNamesToExclude?: string[]
loading?: boolean
submitError?: ApiError | null
instance: Instance
instance?: Instance
}

/**
Expand Down Expand Up @@ -70,12 +70,16 @@ export function AttachDiskModalForm({
onSubmit={onSubmit}
width="medium"
submitDisabled={
!instanceCan.attachDisk(instance) ? 'Instance must be stopped' : undefined
instance && !instanceCan.attachDisk(instance)
? 'Instance must be stopped'
: undefined
}
>
<StopInstancePrompt instance={instance}>
An instance must be stopped to attach a disk.
</StopInstancePrompt>
{instance && ['stopping', 'running'].includes(instance.runState) && (
<StopInstancePrompt instance={instance}>
An instance must be stopped to attach a disk.
</StopInstancePrompt>
)}
<ComboboxField
label="Disk name"
placeholder="Select a disk"
Expand Down
1 change: 1 addition & 0 deletions app/pages/project/instances/StorageTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ export default function StorageTab() {
}}
loading={attachDisk.isPending}
submitError={attachDisk.error}
instance={instance}
/>
)}
</div>
Expand Down

0 comments on commit b14857b

Please sign in to comment.