Skip to content

Commit

Permalink
Merge pull request #2766 from PrefectHQ/run-menu-enhancements
Browse files Browse the repository at this point in the history
Fix FlowRunMenu attribute fall through and create TaskRunMenu component
  • Loading branch information
pleek91 authored Oct 14, 2024
2 parents 8c06c6e + 099d19e commit 0da4fa0
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 79 deletions.
6 changes: 5 additions & 1 deletion src/components/FlowRunMenu.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<p-icon-button-menu>
<p-icon-button-menu class="flow-run-menu" v-bind="$attrs">
<template #default>
<p-overflow-menu-item v-if="flowRun?.deploymentId && deployment?.can.run" label="Copy to new run" :to="routes.deploymentFlowRunCreate(flowRun.deploymentId, flowRun.parameters)" />
<p-overflow-menu-item v-if="canRetry && showAll" label="Retry" @click="openRetryModal" />
Expand Down Expand Up @@ -60,6 +60,10 @@
import { deleteItem } from '@/utilities'
import { getApiErrorMessage } from '@/utilities/errors'
defineOptions({
inheritAttrs: false,
})
const props = defineProps<{
flowRun: FlowRun,
showAll?: boolean,
Expand Down
90 changes: 12 additions & 78 deletions src/components/PageHeadingTaskRun.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,104 +3,38 @@
<template #after-crumbs>
<StateBadge :state="taskRun.state" />
</template>
<template #actions>
<p-icon-button-menu>
<template #default>
<p-overflow-menu-item v-if="showChangeStateMenuItemButton" label="Change state" @click="openChangeStateModal" />
<copy-overflow-menu-item label="Copy ID" :item="taskRun.id" />
<p-overflow-menu-item v-if="can.delete.task_run" label="Delete" @click="openDeleteModal" />
</template>
</p-icon-button-menu>
<ConfirmDeleteModal
v-model:showModal="showDeleteModal"
label="Task Run"
:name="taskRun.name!"
@delete="() => deleteTaskRun(taskRunId)"
/>

<ConfirmStateChangeModal
v-model:showModal="showStateChangeModal"
:run="taskRun"
label="Task Run"
@change="changeTaskRunState"
/>
<template #actions>
<TaskRunMenu :task-run @delete="emit('delete')" @update="taskRunSubscription.refresh" />
</template>
</page-heading>
</template>

<script lang="ts" setup>
import { Crumb, showToast } from '@prefecthq/prefect-design'
import { useSubscription, useSubscriptionWithDependencies } from '@prefecthq/vue-compositions'
import { computed, ref } from 'vue'
import { StateBadge, PageHeading, CopyOverflowMenuItem, ConfirmDeleteModal, ConfirmStateChangeModal } from '@/components'
import { useWorkspaceApi, useWorkspaceRoutes } from '@/compositions'
import { useCan } from '@/compositions/useCan'
import { localization } from '@/localization'
import { isTerminalStateType, StateUpdateDetails } from '@/models'
import { deleteItem } from '@/utilities'
import { getApiErrorMessage } from '@/utilities/errors'
import { Crumb } from '@prefecthq/prefect-design'
import { computed } from 'vue'
import { StateBadge, PageHeading, TaskRunMenu } from '@/components'
import { useFlowRun, useTaskRun, useWorkspaceRoutes } from '@/compositions'
const props = defineProps<{
taskRunId: string,
}>()
const can = useCan()
const api = useWorkspaceApi()
const routes = useWorkspaceRoutes()
const taskRunSubscription = useSubscription(api.taskRuns.getTaskRun, [props.taskRunId])
const taskRun = computed(() => taskRunSubscription.response)
const emit = defineEmits(['delete'])
const flowRunId = computed(() => taskRun.value?.flowRunId)
const flowRunIdArgs = computed<[string] | null>(() => flowRunId.value ? [flowRunId.value] : null)
const flowRunSubscription = useSubscriptionWithDependencies(api.flowRuns.getFlowRun, flowRunIdArgs)
const flowRunName = computed(() => flowRunSubscription.response?.name)
const routes = useWorkspaceRoutes()
const { taskRun, subscription: taskRunSubscription } = useTaskRun(() => props.taskRunId)
const { flowRun } = useFlowRun(() => taskRun.value?.flowRunId)
const crumbs = computed(() => {
const crumbs: Crumb[] = [{ text: 'Runs', to: routes.runs({ tab: 'task-runs' }) }]
if (flowRunId.value) {
crumbs.push({ text: flowRunName.value ?? '', to: routes.flowRun(flowRunId.value!) })
if (flowRun.value) {
crumbs.push({ text: flowRun.value.name ?? '', to: routes.flowRun(flowRun.value.id) })
}
crumbs.push({ text: taskRun.value?.name ?? '' })
return crumbs
})
const showChangeStateMenuItemButton = computed(() => {
if (can.update.task_run && taskRun.value?.stateType && isTerminalStateType(taskRun.value.stateType)) {
return true
}
return false
})
const showStateChangeModal = ref(false)
const openChangeStateModal = (): void => {
showStateChangeModal.value = true
}
const showDeleteModal = ref(false)
const openDeleteModal = (): void => {
showDeleteModal.value = true
}
const emit = defineEmits(['delete'])
const deleteTaskRun = async (id: string): Promise<void> => {
await deleteItem(id, api.taskRuns.deleteTaskRun, 'Task run')
emit('delete', id)
}
const changeTaskRunState = async (values: StateUpdateDetails): Promise<void> => {
try {
await api.taskRuns.setTaskRunState(props.taskRunId, { state: values })
taskRunSubscription.refresh()
showToast(localization.success.changeTaskRunState, 'success')
} catch (error) {
console.error(error)
const message = getApiErrorMessage(error, localization.error.changeTaskRunState)
showToast(message, 'error')
}
}
</script>
79 changes: 79 additions & 0 deletions src/components/TaskRunMenu.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<p-icon-button-menu class="task-run-menu" v-bind="$attrs">
<template #default>
<p-overflow-menu-item v-if="showChangeStateMenuItemButton" label="Change state" @click="openStateChangeModal" />
<copy-overflow-menu-item label="Copy ID" :item="taskRun.id" />
<p-overflow-menu-item v-if="can.delete.task_run" label="Delete" @click="openDeleteModal" />
</template>
</p-icon-button-menu>

<ConfirmDeleteModal
v-model:showModal="showDeleteModal"
label="Task Run"
:name="taskRun.name!"
@delete="() => deleteTaskRun()"
/>

<ConfirmStateChangeModal
v-model:showModal="showStateChangeModal"
:run="taskRun"
label="Task Run"
@change="changeTaskRunState"
/>
</template>

<script lang="ts" setup>
import { showToast } from '@prefecthq/prefect-design'
import { computed } from 'vue'
import { CopyOverflowMenuItem, ConfirmDeleteModal, ConfirmStateChangeModal } from '@/components'
import { useCan, useShowModal, useWorkspaceApi } from '@/compositions'
import { localization } from '@/localization'
import { isTerminalStateType, StateUpdateDetails, TaskRun } from '@/models'
import { getApiErrorMessage } from '@/utilities'
import { deleteItem } from '@/utilities/delete'
defineOptions({
inheritAttrs: false,
})
const { taskRun } = defineProps<{
taskRun: TaskRun,
}>()
const emit = defineEmits(['delete', 'update'])
const can = useCan()
const api = useWorkspaceApi()
const showChangeStateMenuItemButton = computed(() => {
if (can.update.task_run && taskRun.stateType && isTerminalStateType(taskRun.stateType)) {
return true
}
return false
})
const { showModal: showStateChangeModal, open: openStateChangeModal } = useShowModal()
const { showModal: showDeleteModal, open: openDeleteModal } = useShowModal()
const deleteTaskRun = async (): Promise<void> => {
await deleteItem(taskRun.id, api.taskRuns.deleteTaskRun, 'Task run')
emit('delete', taskRun.id)
}
const changeTaskRunState = async (values: StateUpdateDetails): Promise<void> => {
try {
await api.taskRuns.setTaskRunState(taskRun.id, { state: values })
emit('update')
showToast(localization.success.changeTaskRunState, 'success')
} catch (error) {
console.error(error)
const message = getApiErrorMessage(error, localization.error.changeTaskRunState)
showToast(message, 'error')
}
}
</script>
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ export { default as TaskRunIconText } from './TaskRunIconText.vue'
export { default as TaskRunList } from './TaskRunList.vue'
export { default as TaskRunListItem } from './TaskRunListItem.vue'
export { default as TaskRunLogs } from './TaskRunLogs.vue'
export { default as TaskRunMenu } from './TaskRunMenu.vue'
export { default as TaskRunsDeleteButton } from './TaskRunsDeleteButton.vue'
export { default as TaskRunsSort } from './TaskRunsSort.vue'
export { default as TimeSpanFilter } from './TimeSpanFilter.vue'
Expand Down

0 comments on commit 0da4fa0

Please sign in to comment.