Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions app/pages/project/instances/instance/tabs/StorageTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import { Button, EmptyMessage, Storage24Icon } from '@oxide/ui'
import { DiskStatusBadge } from 'app/components/StatusBadge'
import AttachDiskSideModalForm from 'app/forms/disk-attach'
import { CreateDiskSideModalForm } from 'app/forms/disk-create'
import { getInstanceSelector, useInstanceSelector, useToast } from 'app/hooks'
import { getInstanceSelector, useInstanceSelector } from 'app/hooks'
import { addToast } from 'app/stores/toast'

import { fancifyStates } from './common'

Expand Down Expand Up @@ -53,19 +54,37 @@ export function StorageTab() {
const [showDiskCreate, setShowDiskCreate] = useState(false)
const [showDiskAttach, setShowDiskAttach] = useState(false)

const addToast = useToast()
const queryClient = useApiQueryClient()
const { instance: instanceName, project } = useInstanceSelector()
const instancePathQuery = useMemo(
() => ({ path: { instance: instanceName }, query: { project } }),
[instanceName, project]
)

const detachDisk = useApiMutation('instanceDiskDetach', {})
const detachDisk = useApiMutation('instanceDiskDetach', {
onSuccess() {
queryClient.invalidateQueries('instanceDiskList')
addToast({ content: 'Disk detached' })
},
onError(err) {
addToast({
title: 'Failed to detach disk',
content: err.message,
variant: 'error',
})
},
})
const createSnapshot = useApiMutation('snapshotCreate', {
onSuccess() {
queryClient.invalidateQueries('snapshotList')
addToast({ content: 'Snapshot successfully created' })
addToast({ content: 'Snapshot created' })
},
onError(err) {
addToast({
title: 'Failed to create snapshot',
content: err.message,
variant: 'error',
})
},
})

Expand Down Expand Up @@ -97,18 +116,11 @@ export function StorageTab() {
<>Instance must be in state {detachableStates} before disk can be detached</>
),
onActivate() {
detachDisk.mutate(
{ body: { disk: disk.name }, ...instancePathQuery },
{
onSuccess: () => {
queryClient.invalidateQueries('instanceDiskList')
},
}
)
detachDisk.mutate({ body: { disk: disk.name }, ...instancePathQuery })
},
},
],
[detachDisk, instance, queryClient, instancePathQuery, createSnapshot, project]
[detachDisk, instance, instancePathQuery, createSnapshot, project]
)

const attachDisk = useApiMutation('instanceDiskAttach', {
Expand Down
18 changes: 17 additions & 1 deletion app/test/e2e/instance/disks.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,27 @@ test('Attach disk', async ({ page }) => {
await expectVisible(page, ['role=cell[name="disk-3"]'])
})

test('Detach disk', async ({ page }) => {
await page.goto('/projects/mock-project/instances/db1')

// Have to stop instance to edit disks
await stopInstance(page)

const successMsg = page.getByText('Disk detached').nth(0)
const row = page.getByRole('row', { name: 'disk-1' })
await expect(row).toBeVisible()
await expect(successMsg).toBeHidden()

await clickRowAction(page, 'disk-1', 'Detach')
await expect(successMsg).toBeVisible()
await expect(row).toBeHidden() // disk row goes away
})

test('Snapshot disk', async ({ page }) => {
await page.goto('/projects/mock-project/instances/db1')

// have to use nth with toasts because the text shows up in multiple spots
const successMsg = page.getByText('Snapshot successfully created').nth(0)
const successMsg = page.getByText('Snapshot created').nth(0)
await expect(successMsg).toBeHidden()

await clickRowAction(page, 'disk-2', 'Snapshot')
Expand Down
2 changes: 1 addition & 1 deletion libs/api-mocks/msw/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ export const handlers = makeHandlers({
instanceDiskDetach({ body, path, query: projectParams }) {
const instance = lookup.instance({ ...path, ...projectParams })
if (instance.run_state !== 'stopped') {
throw 'Cannot detach disk to instance that is not stopped'
throw 'Cannot detach disk from instance that is not stopped'
}
const disk = lookup.disk({ ...projectParams, disk: body.disk })
disk.state = { state: 'detached' }
Expand Down