Skip to content

Commit

Permalink
be fussy
Browse files Browse the repository at this point in the history
  • Loading branch information
david-crespo committed Oct 17, 2024
1 parent 22d584f commit 8fd33a8
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 74 deletions.
10 changes: 6 additions & 4 deletions app/pages/project/instances/InstancesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ const POLL_INTERVAL_SLOW = 60 * sec

export function InstancesPage() {
const { project } = useProjectSelector()

const { makeActions } = useMakeInstanceActions(
const { makeButtonActions, makeMenuActions } = useMakeInstanceActions(
{ project },
{ onSuccess: refetchInstances, onDelete: refetchInstances }
)
Expand Down Expand Up @@ -182,9 +181,12 @@ export function InstancesPage() {
}
),
colHelper.accessor('timeCreated', Columns.timeCreated),
getActionsCol(makeActions),
getActionsCol((instance: Instance) => [
...makeButtonActions(instance),
...makeMenuActions(instance),
]),
],
[project, makeActions]
[project, makeButtonActions, makeMenuActions]
)

if (!instances) return null
Expand Down
119 changes: 54 additions & 65 deletions app/pages/project/instances/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* Copyright Oxide Computer Company
*/
import { useCallback, useMemo } from 'react'
import { useCallback } from 'react'
import { useNavigate } from 'react-router-dom'

import { instanceCan, useApiMutation, type Instance } from '@oxide/api'
Expand Down Expand Up @@ -47,57 +47,69 @@ export const useMakeInstanceActions = (
onSuccess: options.onDelete,
})

const makeActions = useCallback(
(instance: Instance) => {
const instanceSelector = { project, instance: instance.name }
const instanceParams = { path: { instance: instance.name }, query: { project } }
return [
{
label: 'Start',
onActivate() {
startInstance(instanceParams, {
const makeButtonActions = useCallback(
(instance: Instance) => [
{
label: 'Start',
onActivate() {
startInstance(
{ path: { instance: instance.name }, query: { project } },
{
onSuccess: () => addToast({ title: `Starting instance '${instance.name}'` }),
onError: (error) =>
addToast({
variant: 'error',
title: `Error starting instance '${instance.name}'`,
content: error.message,
}),
})
},
disabled: !instanceCan.start(instance) && (
<>Only {fancifyStates(instanceCan.start.states)} instances can be started</>
),
}
)
},
{
label: 'Stop',
onActivate() {
confirmAction({
actionType: 'danger',
doAction: () =>
stopInstanceAsync(instanceParams, {
disabled: !instanceCan.start(instance) && (
<>Only {fancifyStates(instanceCan.start.states)} instances can be started</>
),
},
{
label: 'Stop',
onActivate() {
confirmAction({
actionType: 'danger',
doAction: () =>
stopInstanceAsync(
{ path: { instance: instance.name }, query: { project } },
{
onSuccess: () =>
addToast({ title: `Stopping instance '${instance.name}'` }),
}),
modalTitle: 'Confirm stop instance',
modalContent: (
<div className="space-y-2">
<p>
Are you sure you want to stop <HL>{instance.name}</HL>?
</p>
<p>
Stopped instances retain attached disks and IP addresses, but allocated
CPU and memory are freed.
</p>
</div>
}
),
errorTitle: `Error stopping ${instance.name}`,
})
},
disabled: !instanceCan.stop(instance) && (
<>Only {fancifyStates(instanceCan.stop.states)} instances can be stopped</>
),
modalTitle: 'Confirm stop instance',
modalContent: (
<div className="space-y-2">
<p>
Are you sure you want to stop <HL>{instance.name}</HL>?
</p>
<p>
Stopped instances retain attached disks and IP addresses, but allocated
CPU and memory are freed.
</p>
</div>
),
errorTitle: `Error stopping ${instance.name}`,
})
},
disabled: !instanceCan.stop(instance) && (
<>Only {fancifyStates(instanceCan.stop.states)} instances can be stopped</>
),
},
],
[project, startInstance, stopInstanceAsync]
)

const makeMenuActions = useCallback(
(instance: Instance) => {
const instanceSelector = { project, instance: instance.name }
const instanceParams = { path: { instance: instance.name }, query: { project } }
return [
{
label: 'Reboot',
onActivate() {
Expand Down Expand Up @@ -140,31 +152,8 @@ export const useMakeInstanceActions = (
},
]
},
[
project,
deleteInstanceAsync,
navigate,
rebootInstance,
startInstance,
stopInstanceAsync,
]
[project, deleteInstanceAsync, navigate, rebootInstance]
)

const useInstanceActions = (instance: Instance) => {
const allActions = useMemo(() => makeActions(instance), [instance])

const buttonActions = useMemo(
() => allActions.filter((a) => a.label === 'Start' || a.label === 'Stop'),
[allActions]
)

const menuActions = useMemo(
() => allActions.filter((a) => a.label !== 'Start' && a.label !== 'Stop'),
[allActions]
)

return { allActions, buttonActions, menuActions }
}

return { useInstanceActions, makeActions }
return { makeButtonActions, makeMenuActions }
}
10 changes: 5 additions & 5 deletions app/pages/project/instances/instance/InstancePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export function InstancePage() {

const navigate = useNavigate()

const { useInstanceActions } = useMakeInstanceActions(instanceSelector, {
const { makeButtonActions, makeMenuActions } = useMakeInstanceActions(instanceSelector, {
onSuccess: refreshData,
// go to project instances list since there's no more instance
onDelete: () => {
Expand Down Expand Up @@ -134,7 +134,6 @@ export function InstancePage() {
{ enabled: !!primaryVpcId }
)

const { buttonActions, menuActions } = useInstanceActions(instance)
const allMenuActions = useMemo(
() => [
{
Expand All @@ -143,9 +142,9 @@ export function InstancePage() {
window.navigator.clipboard.writeText(instance.id || '')
},
},
...menuActions,
...makeMenuActions(instance),
],
[instance.id, menuActions]
[instance, makeMenuActions]
)

const memory = filesize(instance.memory, { output: 'object', base: 2 })
Expand All @@ -158,13 +157,14 @@ export function InstancePage() {
<RefreshButton onClick={refreshData} />
<InstanceDocsPopover />
<div className="flex space-x-2 border-l pl-2 border-default">
{buttonActions.map((action) => (
{makeButtonActions(instance).map((action) => (
<Button
key={action.label}
variant="ghost"
size="sm"
onClick={action.onActivate}
disabled={!!action.disabled}
disabledReason={action.disabled}
>
{action.label}
</Button>
Expand Down

0 comments on commit 8fd33a8

Please sign in to comment.