merge main into rh-test

This commit is contained in:
bymyself
2025-09-28 15:33:29 -07:00
parent 1c0f151d02
commit ff0c15b119
1317 changed files with 85439 additions and 18373 deletions

View File

@@ -37,8 +37,8 @@ import { computed } from 'vue'
import ExtensionSlot from '@/components/common/ExtensionSlot.vue'
import SidebarBottomPanelToggleButton from '@/components/sidebar/SidebarBottomPanelToggleButton.vue'
import SidebarShortcutsToggleButton from '@/components/sidebar/SidebarShortcutsToggleButton.vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useKeybindingStore } from '@/stores/keybindingStore'
import { useSettingStore } from '@/stores/settingStore'
import { useUserStore } from '@/stores/userStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import type { SidebarTabExtension } from '@/types/extensionTypes'

View File

@@ -42,6 +42,7 @@
'sidebar-right': sidebarLocation === 'right',
'small-sidebar': sidebarSize === 'small'
}"
@whats-new-dismissed="handleWhatsNewDismissed"
/>
</Teleport>
@@ -61,19 +62,36 @@ import { storeToRefs } from 'pinia'
import { computed, onMounted } from 'vue'
import HelpCenterMenuContent from '@/components/helpcenter/HelpCenterMenuContent.vue'
import ReleaseNotificationToast from '@/components/helpcenter/ReleaseNotificationToast.vue'
import WhatsNewPopup from '@/components/helpcenter/WhatsNewPopup.vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useReleaseStore } from '@/platform/updates/common/releaseStore'
import ReleaseNotificationToast from '@/platform/updates/components/ReleaseNotificationToast.vue'
import WhatsNewPopup from '@/platform/updates/components/WhatsNewPopup.vue'
import { useDialogService } from '@/services/dialogService'
import { useHelpCenterStore } from '@/stores/helpCenterStore'
import { useReleaseStore } from '@/stores/releaseStore'
import { useSettingStore } from '@/stores/settingStore'
import { useConflictAcknowledgment } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment'
import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection'
import SidebarIcon from './SidebarIcon.vue'
const settingStore = useSettingStore()
const releaseStore = useReleaseStore()
const helpCenterStore = useHelpCenterStore()
const { shouldShowRedDot } = storeToRefs(releaseStore)
const { isVisible: isHelpCenterVisible } = storeToRefs(helpCenterStore)
const { shouldShowRedDot: showReleaseRedDot } = storeToRefs(releaseStore)
const conflictDetection = useConflictDetection()
const { showNodeConflictDialog } = useDialogService()
// Use conflict acknowledgment state from composable - call only once
const { shouldShowRedDot: shouldShowConflictRedDot, markConflictsAsSeen } =
useConflictAcknowledgment()
// Use either release red dot or conflict red dot
const shouldShowRedDot = computed((): boolean => {
const releaseRedDot = showReleaseRedDot.value
return releaseRedDot || shouldShowConflictRedDot.value
})
const sidebarLocation = computed(() =>
settingStore.get('Comfy.Sidebar.Location')
@@ -89,6 +107,36 @@ const closeHelpCenter = () => {
helpCenterStore.hide()
}
/**
* Handle What's New popup dismissal
* Check if conflict modal should be shown after ComfyUI update
*/
const handleWhatsNewDismissed = async () => {
try {
// Check if conflict modal should be shown after update
const shouldShow =
await conflictDetection.shouldShowConflictModalAfterUpdate()
if (shouldShow) {
showConflictModal()
}
} catch (error) {
console.error('[HelpCenter] Error checking conflict modal:', error)
}
}
/**
* Show the node conflict dialog with current conflict data
*/
const showConflictModal = () => {
showNodeConflictDialog({
showAfterWhatsNew: true,
dialogComponentProps: {
onClose: () => {
markConflictsAsSeen()
}
}
})
}
// Initialize release store on mount
onMounted(async () => {
// Initialize release store to fetch releases for toast and popup

View File

@@ -94,6 +94,8 @@ const computedTooltip = computed(() => t(tooltip) + tooltipSuffix)
</style>
<style scoped>
@reference '../../assets/css/style.css';
.side-bar-button {
width: var(--sidebar-width);
height: calc(var(--sidebar-width) + 0.5rem);

View File

@@ -12,8 +12,8 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useCommandStore } from '@/stores/commandStore'
import { useSettingStore } from '@/stores/settingStore'
import SidebarIcon from './SidebarIcon.vue'

View File

@@ -1,7 +1,7 @@
<template>
<SidebarTabTemplate
:title="$t('sideToolbar.modelLibrary')"
class="bg-[var(--p-tree-background)]"
class="bg-(--p-tree-background)"
>
<template #tool-buttons>
<Button
@@ -21,7 +21,7 @@
</template>
<template #header>
<SearchBox
v-model:modelValue="searchQuery"
v-model:model-value="searchQuery"
class="model-lib-search-box p-2 2xl:p-4"
:placeholder="$t('g.searchModels') + '...'"
@search="handleSearch"
@@ -31,7 +31,7 @@
<ElectronDownloadItems v-if="isElectron()" />
<TreeExplorer
v-model:expandedKeys="expandedKeys"
v-model:expanded-keys="expandedKeys"
class="model-lib-tree-explorer"
:root="renderedRoot"
>
@@ -54,15 +54,11 @@ import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue
import ElectronDownloadItems from '@/components/sidebar/tabs/modelLibrary/ElectronDownloadItems.vue'
import ModelTreeLeaf from '@/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue'
import { useTreeExpansion } from '@/composables/useTreeExpansion'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useLitegraphService } from '@/services/litegraphService'
import {
ComfyModelDef,
ModelFolder,
ResourceState,
useModelStore
} from '@/stores/modelStore'
import type { ComfyModelDef, ModelFolder } from '@/stores/modelStore'
import { ResourceState, useModelStore } from '@/stores/modelStore'
import { useModelToNodeStore } from '@/stores/modelToNodeStore'
import { useSettingStore } from '@/stores/settingStore'
import type { TreeNode } from '@/types/treeExplorerTypes'
import type { TreeExplorerNode } from '@/types/treeExplorerTypes'
import { isElectron } from '@/utils/envUtil'

View File

@@ -3,7 +3,7 @@
<SidebarTabTemplate
v-if="!isHelpOpen"
:title="$t('sideToolbar.nodeLibrary')"
class="bg-[var(--p-tree-background)]"
class="bg-(--p-tree-background)"
>
<template #tool-buttons>
<Button
@@ -78,7 +78,7 @@
<template #header>
<div>
<SearchBox
v-model:modelValue="searchQuery"
v-model:model-value="searchQuery"
class="node-lib-search-box p-2 2xl:p-4"
:placeholder="$t('g.searchNodes') + '...'"
filter-icon="pi pi-filter"
@@ -106,7 +106,7 @@
class="m-2"
/>
<TreeExplorer
v-model:expandedKeys="expandedKeys"
v-model:expanded-keys="expandedKeys"
class="node-lib-tree-explorer"
:root="renderedRoot"
>
@@ -129,10 +129,11 @@ import { storeToRefs } from 'pinia'
import Button from 'primevue/button'
import Divider from 'primevue/divider'
import Popover from 'primevue/popover'
import { Ref, computed, h, nextTick, ref, render } from 'vue'
import type { Ref } from 'vue'
import { computed, h, nextTick, ref, render } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import { SearchFilter } from '@/components/common/SearchFilterChip.vue'
import type { SearchFilter } from '@/components/common/SearchFilterChip.vue'
import TreeExplorer from '@/components/common/TreeExplorer.vue'
import NodePreview from '@/components/node/NodePreview.vue'
import NodeSearchFilter from '@/components/searchbox/NodeSearchFilter.vue'
@@ -148,7 +149,8 @@ import {
} from '@/services/nodeOrganizationService'
import { useCommandStore } from '@/stores/commandStore'
import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
import { ComfyNodeDefImpl, useNodeDefStore } from '@/stores/nodeDefStore'
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import { useNodeDefStore } from '@/stores/nodeDefStore'
import { useNodeHelpStore } from '@/stores/workspace/nodeHelpStore'
import type {
GroupingStrategyId,
@@ -156,7 +158,7 @@ import type {
} from '@/types/nodeOrganizationTypes'
import type { TreeNode } from '@/types/treeExplorerTypes'
import type { TreeExplorerNode } from '@/types/treeExplorerTypes'
import { FuseFilterWithValue } from '@/utils/fuseUtil'
import type { FuseFilterWithValue } from '@/utils/fuseUtil'
import NodeBookmarkTreeExplorer from './nodeLibrary/NodeBookmarkTreeExplorer.vue'

View File

@@ -86,7 +86,7 @@
<ConfirmPopup />
<ContextMenu ref="menu" :model="menuItems" />
<ResultGallery
v-model:activeIndex="galleryActiveIndex"
v-model:active-index="galleryActiveIndex"
:all-gallery-items="allGalleryItems"
/>
</template>
@@ -104,17 +104,14 @@ import { useI18n } from 'vue-i18n'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import VirtualGrid from '@/components/common/VirtualGrid.vue'
import { ComfyNode } from '@/schemas/comfyWorkflowSchema'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
import type { ComfyNode } from '@/platform/workflow/validation/schemas/workflowSchema'
import { api } from '@/scripts/api'
import { useLitegraphService } from '@/services/litegraphService'
import { useWorkflowService } from '@/services/workflowService'
import { useCommandStore } from '@/stores/commandStore'
import {
ResultItemImpl,
TaskItemImpl,
useQueueStore
} from '@/stores/queueStore'
import { useSettingStore } from '@/stores/settingStore'
import type { ResultItemImpl, TaskItemImpl } from '@/stores/queueStore'
import { useQueueStore } from '@/stores/queueStore'
import SidebarTabTemplate from './SidebarTabTemplate.vue'
import ResultGallery from './queue/ResultGallery.vue'

View File

@@ -20,8 +20,8 @@
</Toolbar>
<slot name="header" />
</div>
<!-- h-0 to force scrollpanel to flex-grow -->
<ScrollPanel class="comfy-vue-side-bar-body flex-grow h-0">
<!-- h-0 to force scrollpanel to grow -->
<ScrollPanel class="comfy-vue-side-bar-body grow h-0">
<slot name="body" />
</ScrollPanel>
</div>
@@ -38,6 +38,8 @@ const props = defineProps<{
</script>
<style scoped>
@reference '../../../assets/css/style.css';
:deep(.p-toolbar-end) .p-button {
@apply py-1 2xl:py-2;
}

View File

@@ -1,7 +1,7 @@
<template>
<SidebarTabTemplate
:title="$t('sideToolbar.workflows')"
class="workflows-sidebar-tab bg-[var(--p-tree-background)]"
class="workflows-sidebar-tab bg-(--p-tree-background)"
>
<template #tool-buttons>
<Button
@@ -14,7 +14,7 @@
</template>
<template #header>
<SearchBox
v-model:modelValue="searchQuery"
v-model:model-value="searchQuery"
class="workflows-search-box p-2 2xl:p-4"
:placeholder="$t('g.searchWorkflows') + '...'"
@search="handleSearch"
@@ -32,7 +32,7 @@
class="ml-2"
/>
<TreeExplorer
v-model:expandedKeys="dummyExpandedKeys"
v-model:expanded-keys="dummyExpandedKeys"
:root="renderTreeNode(openWorkflowsTree, WorkflowTreeType.Open)"
:selection-keys="selectionKeys"
>
@@ -74,7 +74,7 @@
class="ml-2"
/>
<TreeExplorer
v-model:expandedKeys="dummyExpandedKeys"
v-model:expanded-keys="dummyExpandedKeys"
:root="
renderTreeNode(
bookmarkedWorkflowsTree,
@@ -96,7 +96,7 @@
/>
<TreeExplorer
v-if="workflowStore.persistedWorkflows.length > 0"
v-model:expandedKeys="expandedKeys"
v-model:expanded-keys="expandedKeys"
:root="renderTreeNode(workflowsTree, WorkflowTreeType.Browse)"
:selection-keys="selectionKeys"
>
@@ -114,7 +114,7 @@
</div>
<div v-else class="comfyui-workflows-search-panel">
<TreeExplorer
v-model:expandedKeys="expandedKeys"
v-model:expanded-keys="expandedKeys"
:root="renderTreeNode(filteredRoot, WorkflowTreeType.Browse)"
>
<template #node="{ node }">
@@ -141,16 +141,16 @@ import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue'
import WorkflowTreeLeaf from '@/components/sidebar/tabs/workflows/WorkflowTreeLeaf.vue'
import { useTreeExpansion } from '@/composables/useTreeExpansion'
import { useWorkflowService } from '@/services/workflowService'
import { useSettingStore } from '@/stores/settingStore'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
import {
useWorkflowBookmarkStore,
useWorkflowStore
} from '@/stores/workflowStore'
import { ComfyWorkflow } from '@/stores/workflowStore'
} from '@/platform/workflow/management/stores/workflowStore'
import { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import type { TreeNode } from '@/types/treeExplorerTypes'
import { TreeExplorerNode } from '@/types/treeExplorerTypes'
import type { TreeExplorerNode } from '@/types/treeExplorerTypes'
import { appendJsonExt } from '@/utils/formatUtil'
import { buildTree, sortedTree } from '@/utils/treeUtil'

View File

@@ -20,19 +20,13 @@
</template>
<script setup lang="ts">
import {
CSSProperties,
computed,
nextTick,
onMounted,
onUnmounted,
ref
} from 'vue'
import type { CSSProperties } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import { ComfyModelDef } from '@/stores/modelStore'
import { useSettingStore } from '@/stores/settingStore'
import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
import { useSettingStore } from '@/platform/settings/settingStore'
import type { ComfyModelDef } from '@/stores/modelStore'
import type { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
import ModelPreview from './ModelPreview.vue'

View File

@@ -33,7 +33,7 @@ import NodeTreeLeaf from '@/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue
import { useTreeExpansion } from '@/composables/useTreeExpansion'
import { useLitegraphService } from '@/services/litegraphService'
import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import type { TreeNode } from '@/types/treeExplorerTypes'
import type {
RenderedTreeExplorerNode,

View File

@@ -1,7 +1,7 @@
<template>
<div class="flex flex-col h-full bg-[var(--p-tree-background)] overflow-auto">
<div class="flex flex-col h-full bg-(--p-tree-background) overflow-auto">
<div
class="px-3 py-2 flex items-center border-b border-[var(--p-divider-color)]"
class="px-3 py-2 flex items-center border-b border-(--p-divider-color)"
>
<Button
v-tooltip.bottom="$t('g.back')"
@@ -12,7 +12,7 @@
/>
<span class="ml-2 font-semibold">{{ node.display_name }}</span>
</div>
<div class="p-4 flex-grow node-help-content w-full mx-auto">
<div class="p-4 grow node-help-content w-full mx-auto">
<ProgressSpinner
v-if="isLoading"
class="m-auto"
@@ -118,7 +118,9 @@ const outputList = computed(() =>
)
</script>
<style scoped lang="postcss">
<style scoped>
@reference './../../../../assets/css/style.css';
.node-help-content :deep(:is(img, video)) {
@apply max-w-full h-auto block mb-4;
}

View File

@@ -10,7 +10,7 @@ import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue'
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import type { BookmarkCustomization } from '@/schemas/apiSchema'
import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import {
InjectKeyExpandedKeys,
type RenderedTreeExplorerNode

View File

@@ -1,6 +1,6 @@
<template>
<div ref="container" class="node-lib-node-container">
<TreeExplorerTreeNode :node="node">
<TreeExplorerTreeNode :node="node" @contextmenu="handleContextMenu">
<template #before-label>
<Tag
v-if="nodeDef.experimental"
@@ -13,7 +13,30 @@
severity="danger"
/>
</template>
<template #actions>
<template
v-if="nodeDef.name.startsWith(useSubgraphStore().typePrefix)"
#actions
>
<Button
size="small"
icon="pi pi-trash"
text
severity="danger"
@click.stop="deleteBlueprint"
>
</Button>
<Button
size="small"
text
severity="secondary"
@click.stop="editBlueprint"
>
<template #icon>
<i-lucide:square-pen />
</template>
</Button>
</template>
<template v-else #actions>
<Button
class="bookmark-button"
size="small"
@@ -40,26 +63,27 @@
</div>
</teleport>
</div>
<ContextMenu ref="menu" :model="menuItems" />
</template>
<script setup lang="ts">
import Button from 'primevue/button'
import ContextMenu from 'primevue/contextmenu'
import type { MenuItem } from 'primevue/menuitem'
import Tag from 'primevue/tag'
import {
CSSProperties,
computed,
nextTick,
onMounted,
onUnmounted,
ref
} from 'vue'
import type { CSSProperties } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import NodePreview from '@/components/node/NodePreview.vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import { useSettingStore } from '@/stores/settingStore'
import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
import { useSubgraphStore } from '@/stores/subgraphStore'
import type { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
const { t } = useI18n()
const props = defineProps<{
node: RenderedTreeExplorerNode<ComfyNodeDefImpl>
@@ -80,6 +104,33 @@ const sidebarLocation = computed<'left' | 'right'>(() =>
const toggleBookmark = async () => {
await nodeBookmarkStore.toggleBookmark(nodeDef.value)
}
const editBlueprint = async () => {
if (!props.node.data)
throw new Error(
'Failed to edit subgraph blueprint lacking backing node data'
)
await useSubgraphStore().editBlueprint(props.node.data.name)
}
const menu = ref<InstanceType<typeof ContextMenu> | null>(null)
const menuItems = computed<MenuItem[]>(() => {
const items: MenuItem[] = [
{
label: t('g.delete'),
icon: 'pi pi-trash',
severity: 'error',
command: deleteBlueprint
}
]
return items
})
function handleContextMenu(event: Event) {
if (!nodeDef.value.name.startsWith(useSubgraphStore().typePrefix)) return
menu.value?.show(event)
}
function deleteBlueprint() {
if (!props.node.data) return
void useSubgraphStore().deleteBlueprint(props.node.data.name)
}
const previewRef = ref<InstanceType<typeof NodePreview> | null>(null)
const nodePreviewStyle = ref<CSSProperties>({
@@ -133,6 +184,8 @@ onUnmounted(() => {
</script>
<style scoped>
@reference '../../../../assets/css/style.css';
.node-lib-node-container {
@apply h-full w-full;
}

View File

@@ -8,7 +8,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { ResultItemImpl } from '@/stores/queueStore'
import type { ResultItemImpl } from '@/stores/queueStore'
const { result } = defineProps<{
result: ResultItemImpl

View File

@@ -4,7 +4,7 @@ import Galleria from 'primevue/galleria'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { createApp, nextTick } from 'vue'
import type { NodeId } from '@/schemas/comfyWorkflowSchema'
import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'
import type { ResultItemImpl } from '@/stores/queueStore'
import ResultGallery from './ResultGallery.vue'

View File

@@ -45,7 +45,7 @@ import Galleria from 'primevue/galleria'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import ComfyImage from '@/components/common/ComfyImage.vue'
import { ResultItemImpl } from '@/stores/queueStore'
import type { ResultItemImpl } from '@/stores/queueStore'
import ResultAudio from './ResultAudio.vue'
import ResultVideo from './ResultVideo.vue'

View File

@@ -24,8 +24,8 @@
import { computed, onMounted, ref } from 'vue'
import ComfyImage from '@/components/common/ComfyImage.vue'
import { ResultItemImpl } from '@/stores/queueStore'
import { useSettingStore } from '@/stores/settingStore'
import { useSettingStore } from '@/platform/settings/settingStore'
import type { ResultItemImpl } from '@/stores/queueStore'
import ResultAudio from './ResultAudio.vue'
import ResultVideo from './ResultVideo.vue'

View File

@@ -8,9 +8,9 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useExtensionStore } from '@/stores/extensionStore'
import { ResultItemImpl } from '@/stores/queueStore'
import { useSettingStore } from '@/stores/settingStore'
import type { ResultItemImpl } from '@/stores/queueStore'
const props = defineProps<{
result: ResultItemImpl

View File

@@ -78,7 +78,7 @@ import Button from 'primevue/button'
import Tag from 'primevue/tag'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { ComfyNode } from '@/schemas/comfyWorkflowSchema'
import type { ComfyNode } from '@/platform/workflow/validation/schemas/workflowSchema'
import { api } from '@/scripts/api'
import { useLitegraphService } from '@/services/litegraphService'
import { TaskItemDisplayStatus, type TaskItemImpl } from '@/stores/queueStore'

View File

@@ -17,7 +17,8 @@ import Button from 'primevue/button'
import { computed } from 'vue'
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
import { ComfyWorkflow, useWorkflowBookmarkStore } from '@/stores/workflowStore'
import type { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
import { useWorkflowBookmarkStore } from '@/platform/workflow/management/stores/workflowStore'
import type { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
const { node } = defineProps<{