mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
## Summary Add workflow sharing by URL and a multi-step ComfyHub publish wizard, gated by feature flags and an optional profile gate. ## Changes - **What**: Share dialog with URL generation and asset warnings; ComfyHub publish wizard (Describe → Examples → Finish) with thumbnail upload and tags; profile gate flow; shared workflow URL loader with confirmation dialog - **Dependencies**: None (new `sharing/` module under `src/platform/workflow/`) ## Review Focus - Three new feature flags: `workflow_sharing_enabled`, `comfyhub_upload_enabled`, `comfyhub_profile_gate_enabled` - Share service API contract and stale-share detection (`workflowShareService.ts`) - Publish wizard and profile gate state management - Shared workflow URL loading and query-param preservation ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8951-feat-share-workflow-by-URL-30b6d73d3650813ebbfafdad775bfb33) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: GitHub Action <action@github.com>
72 lines
1.6 KiB
TypeScript
72 lines
1.6 KiB
TypeScript
import { partition } from 'es-toolkit'
|
|
import { computed, ref, watch } from 'vue'
|
|
|
|
import type { AssetInfo } from '@/schemas/apiSchema'
|
|
|
|
type SectionId = 'media' | 'models'
|
|
|
|
interface AssetSection {
|
|
id: SectionId
|
|
labelKey: string
|
|
items: AssetInfo[]
|
|
}
|
|
|
|
export function useAssetSections(items: () => AssetInfo[]) {
|
|
const sections = computed(() => {
|
|
const [models, media] = partition(items(), (a) => a.model)
|
|
const allSections: AssetSection[] = [
|
|
{
|
|
id: 'media',
|
|
labelKey: 'shareWorkflow.mediaLabel',
|
|
items: media
|
|
},
|
|
{
|
|
id: 'models',
|
|
labelKey: 'shareWorkflow.modelsLabel',
|
|
items: models
|
|
}
|
|
]
|
|
return allSections.filter((s) => s.items.length > 0)
|
|
})
|
|
|
|
const expandedSectionId = ref<SectionId | null>(null)
|
|
|
|
function getDefaultExpandedSection(
|
|
availableSections: AssetSection[]
|
|
): SectionId | null {
|
|
if (availableSections.length === 0) return null
|
|
return (
|
|
availableSections.find((s) => s.id === 'media')?.id ??
|
|
availableSections[0].id
|
|
)
|
|
}
|
|
|
|
watch(
|
|
sections,
|
|
(availableSections) => {
|
|
const hasExpanded = availableSections.some(
|
|
(s) => s.id === expandedSectionId.value
|
|
)
|
|
if (hasExpanded) return
|
|
expandedSectionId.value = getDefaultExpandedSection(availableSections)
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
function onSectionOpenChange(sectionId: SectionId, open: boolean) {
|
|
if (open) {
|
|
expandedSectionId.value = sectionId
|
|
return
|
|
}
|
|
if (expandedSectionId.value === sectionId) {
|
|
expandedSectionId.value = null
|
|
}
|
|
}
|
|
|
|
return {
|
|
sections,
|
|
expandedSectionId,
|
|
onSectionOpenChange
|
|
}
|
|
}
|