Extract error handling with toast message as hook (#825)

This commit is contained in:
Chenlei Hu
2024-09-14 11:25:08 +09:00
committed by GitHub
parent c98ea5ba01
commit ebdcd92977
4 changed files with 78 additions and 35 deletions

View File

@@ -40,8 +40,10 @@ import type {
RenderedTreeExplorerNode, RenderedTreeExplorerNode,
TreeExplorerNode TreeExplorerNode
} from '@/types/treeExplorerTypes' } from '@/types/treeExplorerTypes'
import type { MenuItem } from 'primevue/menuitem' import type { MenuItem, MenuItemCommandEvent } from 'primevue/menuitem'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useToast } from 'primevue/usetoast'
import { useErrorHandling } from '@/hooks/errorHooks'
const expandedKeys = defineModel<Record<string, boolean>>('expandedKeys') const expandedKeys = defineModel<Record<string, boolean>>('expandedKeys')
provide('expandedKeys', expandedKeys) provide('expandedKeys', expandedKeys)
@@ -105,25 +107,31 @@ const deleteCommand = (node: RenderedTreeExplorerNode) => {
node.handleDelete?.(node) node.handleDelete?.(node)
emit('nodeDelete', node) emit('nodeDelete', node)
} }
const menuItems = computed<MenuItem[]>(() => [ const menuItems = computed<MenuItem[]>(() =>
{ [
label: t('rename'), {
icon: 'pi pi-file-edit', label: t('rename'),
command: () => renameCommand(menuTargetNode.value), icon: 'pi pi-file-edit',
visible: menuTargetNode.value?.handleRename !== undefined command: () => renameCommand(menuTargetNode.value),
}, visible: menuTargetNode.value?.handleRename !== undefined
{ },
label: t('delete'), {
icon: 'pi pi-trash', label: t('delete'),
command: () => deleteCommand(menuTargetNode.value), icon: 'pi pi-trash',
visible: menuTargetNode.value?.handleDelete !== undefined command: () => deleteCommand(menuTargetNode.value),
}, visible: menuTargetNode.value?.handleDelete !== undefined
...(props.extraMenuItems },
? typeof props.extraMenuItems === 'function' ...(props.extraMenuItems
? props.extraMenuItems(menuTargetNode.value) ? typeof props.extraMenuItems === 'function'
: props.extraMenuItems ? props.extraMenuItems(menuTargetNode.value)
: []) : props.extraMenuItems
]) : [])
].map((menuItem) => ({
...menuItem,
command: wrapCommandWithErrorHandler(menuItem.command)
}))
)
const handleContextMenu = (node: RenderedTreeExplorerNode, e: MouseEvent) => { const handleContextMenu = (node: RenderedTreeExplorerNode, e: MouseEvent) => {
menuTargetNode.value = node menuTargetNode.value = node
emit('contextMenu', node, e) emit('contextMenu', node, e)
@@ -131,6 +139,17 @@ const handleContextMenu = (node: RenderedTreeExplorerNode, e: MouseEvent) => {
menu.value?.show(e) menu.value?.show(e)
} }
} }
const errorHandling = useErrorHandling()
const wrapCommandWithErrorHandler = (
command: (event: MenuItemCommandEvent) => void
) => {
return errorHandling.wrapWithErrorHandling(
command,
menuTargetNode.value?.handleError
)
}
defineExpose({ defineExpose({
renameCommand, renameCommand,
deleteCommand deleteCommand
@@ -145,6 +164,7 @@ defineExpose({
margin-left: var(--p-tree-node-gap); margin-left: var(--p-tree-node-gap);
flex-grow: 1; flex-grow: 1;
} }
/* /*
* The following styles are necessary to avoid layout shift when dragging nodes over folders. * The following styles are necessary to avoid layout shift when dragging nodes over folders.
* By setting the position to relative on the parent and using an absolutely positioned pseudo-element, * By setting the position to relative on the parent and using an absolutely positioned pseudo-element,
@@ -153,6 +173,7 @@ defineExpose({
:deep(.p-tree-node-content:has(.tree-folder)) { :deep(.p-tree-node-content:has(.tree-folder)) {
position: relative; position: relative;
} }
:deep(.p-tree-node-content:has(.tree-folder.can-drop))::after { :deep(.p-tree-node-content:has(.tree-folder.can-drop))::after {
content: ''; content: '';
position: absolute; position: absolute;

View File

@@ -36,12 +36,12 @@ import type {
TreeExplorerNode TreeExplorerNode
} from '@/types/treeExplorerTypes' } from '@/types/treeExplorerTypes'
import type { TreeNode } from 'primevue/treenode' import type { TreeNode } from 'primevue/treenode'
import { useToast } from 'primevue/usetoast'
import { computed, nextTick, ref, watch } from 'vue' import { computed, nextTick, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useTreeExpansion } from '@/hooks/treeHooks' import { useTreeExpansion } from '@/hooks/treeHooks'
import { app } from '@/scripts/app' import { app } from '@/scripts/app'
import { findNodeByKey } from '@/utils/treeUtil' import { findNodeByKey } from '@/utils/treeUtil'
import { useErrorHandling } from '@/hooks/errorHooks'
import { useI18n } from 'vue-i18n'
const props = defineProps<{ const props = defineProps<{
filteredNodeDefs: ComfyNodeDefImpl[] filteredNodeDefs: ComfyNodeDefImpl[]
@@ -182,22 +182,13 @@ defineExpose({
addNewBookmarkFolder addNewBookmarkFolder
}) })
const toast = useToast() const handleRename = useErrorHandling().wrapWithErrorHandling(
const { t } = useI18n() (node: TreeNode, newName: string) => {
const handleRename = (node: TreeNode, newName: string) => { if (node.data && node.data.isDummyFolder) {
if (node.data && node.data.isDummyFolder) {
try {
nodeBookmarkStore.renameBookmarkFolder(node.data, newName) nodeBookmarkStore.renameBookmarkFolder(node.data, newName)
} catch (e) {
toast.add({
severity: 'error',
summary: t('error'),
detail: e.message,
life: 3000
})
} }
} }
} )
const showCustomizationDialog = ref(false) const showCustomizationDialog = ref(false)
const initialIcon = ref(nodeBookmarkStore.defaultBookmarkIcon) const initialIcon = ref(nodeBookmarkStore.defaultBookmarkIcon)
@@ -212,6 +203,7 @@ const updateCustomization = (icon: string, color: string) => {
} }
} }
const { t } = useI18n()
const extraMenuItems = computed( const extraMenuItems = computed(
() => (menuTargetNode: RenderedTreeExplorerNode<ComfyNodeDefImpl>) => [ () => (menuTargetNode: RenderedTreeExplorerNode<ComfyNodeDefImpl>) => [
{ {

28
src/hooks/errorHooks.ts Normal file
View File

@@ -0,0 +1,28 @@
import { useToast } from 'primevue/usetoast'
import { useI18n } from 'vue-i18n'
export function useErrorHandling() {
const toast = useToast()
const { t } = useI18n()
const wrapWithErrorHandling =
(action: (...args: any[]) => any, errorHandler?: (error: any) => void) =>
(...args: any[]) => {
try {
return action(...args)
} catch (e) {
if (errorHandler) {
errorHandler(e)
} else {
toast.add({
severity: 'error',
summary: t('error'),
detail: e.message,
life: 3000
})
}
}
}
return { wrapWithErrorHandling }
}

View File

@@ -24,6 +24,8 @@ export interface TreeExplorerNode<T = any> {
node: TreeExplorerNode<T>, node: TreeExplorerNode<T>,
data: TreeExplorerDragAndDropData data: TreeExplorerDragAndDropData
) => void ) => void
// Function to handle errors
handleError?: (error: Error) => void
} }
export interface RenderedTreeExplorerNode<T = any> extends TreeExplorerNode<T> { export interface RenderedTreeExplorerNode<T = any> extends TreeExplorerNode<T> {