Skip to content

Commit

Permalink
make instance list polling not do weirdo stuff to the row actions menu
Browse files Browse the repository at this point in the history
  • Loading branch information
david-crespo committed Aug 9, 2024
1 parent 95399db commit 73c9cb6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 30 deletions.
27 changes: 10 additions & 17 deletions app/pages/project/instances/InstancesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@ import { createColumnHelper } from '@tanstack/react-table'
import { useMemo } from 'react'
import { useNavigate, type LoaderFunctionArgs } from 'react-router-dom'

import {
apiQueryClient,
useApiQueryClient,
usePrefetchedApiQuery,
type Instance,
} from '@oxide/api'
import { apiQueryClient, usePrefetchedApiQuery, type Instance } from '@oxide/api'
import { Instances16Icon, Instances24Icon } from '@oxide/design-system/icons/react'

// import { instanceTransitioning } from '~/api/util'
import { instanceTransitioning } from '~/api/util'
import { DocsPopover } from '~/components/DocsPopover'
import { RefreshButton } from '~/components/RefreshButton'
import { getProjectSelector, useProjectSelector, useQuickActions } from '~/hooks'
Expand All @@ -31,7 +26,7 @@ import { CreateLink } from '~/ui/lib/CreateButton'
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
import { PageHeader, PageTitle } from '~/ui/lib/PageHeader'
import { TableActions } from '~/ui/lib/Table'
// import { useInterval } from '~/ui/lib/use-interval'
import { useInterval } from '~/ui/lib/use-interval'
import { docLinks } from '~/util/links'
import { pb } from '~/util/path-builder'

Expand All @@ -57,12 +52,11 @@ InstancesPage.loader = async ({ params }: LoaderFunctionArgs) => {
return null
}

const refetchInstances = () => apiQueryClient.invalidateQueries('instanceList')

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

const queryClient = useApiQueryClient()
const refetchInstances = () => queryClient.invalidateQueries('instanceList')

const makeActions = useMakeInstanceActions(
{ project },
{ onSuccess: refetchInstances, onDelete: refetchInstances }
Expand All @@ -73,12 +67,11 @@ export function InstancesPage() {
})

// if any instance in the list is transitioning, poll
// TODO: figure out this logic. polling requests have the horrible effect of close
// any open row actions menus
// useInterval({
// fn: () => apiQueryClient.invalidateQueries('instanceList'),
// delay: instances.items.some(instanceTransitioning) ? 1000 : null,
// })
// TODO: figure out this logic. polling if any instance is transitioning might be excessive
useInterval({
fn: () => apiQueryClient.invalidateQueries('instanceList'),
delay: instances.items.some(instanceTransitioning) ? 1000 : null,
})

const navigate = useNavigate()
useQuickActions(
Expand Down
39 changes: 26 additions & 13 deletions app/pages/project/instances/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,35 @@ type Options = {
}

export const useMakeInstanceActions = (
projectSelector: { project: string },
{ project }: { project: string },
options: Options = {}
): MakeActions<Instance> => {
const navigate = useNavigate()

// if you also pass onSuccess to mutate(), this one is not overridden — this
// one runs first, then the one passed to mutate()
// one runs first, then the one passed to mutate().
//
// We pull out the mutate functions because they are referentially stable,
// while the whole useMutation result object is not. The async ones are used
// when we need to confirm because the confirm modals want that.
const opts = { onSuccess: options.onSuccess }
const startInstance = useApiMutation('instanceStart', opts)
const stopInstance = useApiMutation('instanceStop', opts)
const rebootInstance = useApiMutation('instanceReboot', opts)
const { mutate: startInstance } = useApiMutation('instanceStart', opts)
const { mutateAsync: stopInstanceAsync } = useApiMutation('instanceStop', opts)
const { mutate: rebootInstance } = useApiMutation('instanceReboot', opts)
// delete has its own
const deleteInstance = useApiMutation('instanceDelete', { onSuccess: options.onDelete })
const { mutateAsync: deleteInstanceAsync } = useApiMutation('instanceDelete', {
onSuccess: options.onDelete,
})

return useCallback(
(instance) => {
const instanceSelector = { ...projectSelector, instance: instance.name }
const instanceParams = { path: { instance: instance.name }, query: projectSelector }
const instanceSelector = { project, instance: instance.name }
const instanceParams = { path: { instance: instance.name }, query: { project } }
return [
{
label: 'Start',
onActivate() {
startInstance.mutate(instanceParams, {
startInstance(instanceParams, {
onSuccess: () => addToast({ title: `Starting instance '${instance.name}'` }),
onError: (error) =>
addToast({
Expand All @@ -71,7 +77,7 @@ export const useMakeInstanceActions = (
confirmAction({
actionType: 'danger',
doAction: () =>
stopInstance.mutateAsync(instanceParams, {
stopInstanceAsync(instanceParams, {
onSuccess: () =>
addToast({ title: `Stopping instance '${instance.name}'` }),
}),
Expand All @@ -93,7 +99,7 @@ export const useMakeInstanceActions = (
{
label: 'Reboot',
onActivate() {
rebootInstance.mutate(instanceParams, {
rebootInstance(instanceParams, {
onSuccess: () => addToast({ title: `Rebooting instance '${instance.name}'` }),
onError: (error) =>
addToast({
Expand All @@ -117,7 +123,7 @@ export const useMakeInstanceActions = (
label: 'Delete',
onActivate: confirmDelete({
doDelete: () =>
deleteInstance.mutateAsync(instanceParams, {
deleteInstanceAsync(instanceParams, {
onSuccess: () =>
addToast({ title: `Deleting instance '${instance.name}'` }),
}),
Expand All @@ -132,6 +138,13 @@ export const useMakeInstanceActions = (
},
]
},
[projectSelector, deleteInstance, navigate, rebootInstance, startInstance, stopInstance]
[
project,
navigate,
deleteInstanceAsync,
rebootInstance,
startInstance,
stopInstanceAsync,
]
)
}

0 comments on commit 73c9cb6

Please sign in to comment.