diff --git a/app/pages/project/instances/actions.tsx b/app/pages/project/instances/actions.tsx index b9eaf3c1f7..488ea52516 100644 --- a/app/pages/project/instances/actions.tsx +++ b/app/pages/project/instances/actions.tsx @@ -6,6 +6,7 @@ * Copyright Oxide Computer Company */ import { useCallback } from 'react' +import { useNavigate } from 'react-router-dom' import { instanceCan, useApiMutation, type Instance } from '@oxide/api' @@ -13,6 +14,7 @@ import { HL } from '~/components/HL' import { confirmAction } from '~/stores/confirm-action' import { confirmDelete } from '~/stores/confirm-delete' import { addToast } from '~/stores/toast' +import { pb } from '~/util/path-builder' import { fancifyStates } from './instance/tabs/common' @@ -114,6 +116,7 @@ export const useMakeInstanceActions = ( [project, startInstanceAsync, stopInstanceAsync] ) + const navigate = useNavigate() const makeMenuActions = useCallback( (instance: Instance) => { const instanceParams = { path: { instance: instance.name }, query: { project } } @@ -148,6 +151,12 @@ export const useMakeInstanceActions = ( <>Only {fancifyStates(instanceCan.update.states)} instances can be resized ), }, + { + label: 'View serial console', + onActivate() { + navigate(pb.serialConsole({ project, instance: instance.name })) + }, + }, { label: 'Delete', onActivate: confirmDelete({ @@ -170,7 +179,7 @@ export const useMakeInstanceActions = ( // Do not put `options` in here, refer to the property. options is not ref // stable. Extra renders here cause the row actions menu to close when it // shouldn't, like during polling on instance list. - [project, deleteInstanceAsync, rebootInstanceAsync, onResizeClick] + [project, deleteInstanceAsync, rebootInstanceAsync, onResizeClick, navigate] ) return { makeButtonActions, makeMenuActions } diff --git a/test/e2e/instance-serial.e2e.ts b/test/e2e/instance-serial.e2e.ts index 399f4bf577..432b1b6399 100644 --- a/test/e2e/instance-serial.e2e.ts +++ b/test/e2e/instance-serial.e2e.ts @@ -5,7 +5,7 @@ * * Copyright Oxide Computer Company */ -import { expect, test } from './utils' +import { clickRowAction, expect, test } from './utils' test('serial console can connect while starting', async ({ page }) => { // create an instance @@ -31,3 +31,14 @@ test('serial console can connect while starting', async ({ page }) => { // Here it would be nice to test that the serial console connects, but we // can't mock websockets with MSW yet: https://github.com/mswjs/msw/pull/2011 }) + +test('links in instance actions', async ({ page }) => { + await page.goto('/projects/mock-project/instances') + await clickRowAction(page, 'db1', 'View serial console') + await expect(page).toHaveURL('/projects/mock-project/instances/db1/serial-console') + + await page.goto('/projects/mock-project/instances/db1') + await page.getByRole('button', { name: 'Instance actions' }).click() + await page.getByRole('menuitem', { name: 'View serial console' }).click() + await expect(page).toHaveURL('/projects/mock-project/instances/db1/serial-console') +})