add List view for workflow tempalte (#3710)

Co-authored-by: Chenlei Hu <hcl@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Terry Jia
2025-05-02 17:50:53 -04:00
committed by GitHub
parent 23d32282bc
commit ba3b1bae87
11 changed files with 175 additions and 27 deletions

View File

@@ -0,0 +1,69 @@
<template>
<DataTable
v-model:selection="selectedTemplate"
:value="templates"
striped-rows
selection-mode="single"
>
<Column field="title" :header="t('g.title')">
<template #body="slotProps">
<span :title="getTemplateTitle(slotProps.data)">{{
getTemplateTitle(slotProps.data)
}}</span>
</template>
</Column>
<Column field="description" :header="t('g.description')">
<template #body="slotProps">
<span :title="slotProps.data.description.replace(/[-_]/g, ' ')">
{{ slotProps.data.description.replace(/[-_]/g, ' ') }}
</span>
</template>
</Column>
<Column field="actions" header="" class="w-12">
<template #body="slotProps">
<Button
icon="pi pi-arrow-right"
text
rounded
size="small"
:loading="loading === slotProps.data.name"
@click="emit('loadWorkflow', slotProps.data.name)"
/>
</template>
</Column>
</DataTable>
</template>
<script setup lang="ts">
import Button from 'primevue/button'
import Column from 'primevue/column'
import DataTable from 'primevue/datatable'
import { ref } from 'vue'
import { st, t } from '@/i18n'
import type { TemplateInfo } from '@/types/workflowTemplateTypes'
import { normalizeI18nKey } from '@/utils/formatUtil'
const { sourceModule, categoryTitle, loading, templates } = defineProps<{
sourceModule: string
categoryTitle: string
loading: string | null
templates: TemplateInfo[]
}>()
const selectedTemplate = ref(null)
const emit = defineEmits<{
loadWorkflow: [name: string]
}>()
const getTemplateTitle = (template: TemplateInfo) => {
const fallback = template.title ?? template.name ?? `${sourceModule} Template`
return sourceModule === 'default'
? st(
`templateWorkflows.template.${normalizeI18nKey(categoryTitle)}.${normalizeI18nKey(template.name)}`,
fallback
)
: fallback
}
</script>

View File

@@ -0,0 +1,82 @@
<template>
<DataView
:value="templates"
:layout="layout"
data-key="name"
:lazy="true"
pt:root="h-full grid grid-rows-[auto_1fr]"
pt:content="p-2 overflow-auto"
>
<template #header>
<div class="flex justify-between items-center">
<h2 class="text-lg">{{ title }}</h2>
<SelectButton
v-model="layout"
:options="['grid', 'list']"
:allow-empty="false"
>
<template #option="{ option }">
<i :class="[option === 'list' ? 'pi pi-bars' : 'pi pi-table']" />
</template>
</SelectButton>
</div>
</template>
<template #list="{ items }">
<TemplateWorkflowList
:source-module="sourceModule"
:templates="items"
:loading="loading"
:category-title="categoryTitle"
@load-workflow="onLoadWorkflow"
/>
</template>
<template #grid="{ items }">
<div
class="grid grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] auto-rows-fr gap-8 justify-items-center"
>
<TemplateWorkflowCard
v-for="template in items"
:key="template.name"
:source-module="sourceModule"
:template="template"
:loading="loading === template.name"
:category-title="categoryTitle"
@load-workflow="onLoadWorkflow"
/>
</div>
</template>
</DataView>
</template>
<script setup lang="ts">
import { useLocalStorage } from '@vueuse/core'
import DataView from 'primevue/dataview'
import SelectButton from 'primevue/selectbutton'
import TemplateWorkflowCard from '@/components/templates/TemplateWorkflowCard.vue'
import TemplateWorkflowList from '@/components/templates/TemplateWorkflowList.vue'
import type { TemplateInfo } from '@/types/workflowTemplateTypes'
defineProps<{
title: string
sourceModule: string
categoryTitle: string
loading: string | null
templates: TemplateInfo[]
}>()
const layout = useLocalStorage<'grid' | 'list'>(
'Comfy.TemplateWorkflow.Layout',
'grid'
)
const emit = defineEmits<{
loadWorkflow: [name: string]
}>()
const onLoadWorkflow = (name: string) => {
emit('loadWorkflow', name)
}
</script>

View File

@@ -30,36 +30,22 @@
/>
</aside>
<div
class="flex-1 overflow-auto transition-all duration-300"
class="flex-1 transition-all duration-300"
:class="{
'pl-80': isSideNavOpen || !isSmallScreen,
'pl-8': !isSideNavOpen && isSmallScreen
}"
>
<div v-if="isReady && selectedTab" class="flex flex-col px-12 pb-4">
<div class="py-3 text-left">
<h2 class="text-lg">
{{ selectedTab.title }}
</h2>
</div>
<div
class="grid grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] auto-rows-fr gap-8 justify-items-center"
>
<div
v-for="template in selectedTab.templates"
:key="template.name"
class="h-full"
>
<TemplateWorkflowCard
:source-module="selectedTab.moduleName"
:template="template"
:loading="template.name === workflowLoading"
:category-title="selectedTab.title"
@load-workflow="loadWorkflow"
/>
</div>
</div>
</div>
<TemplateWorkflowView
v-if="isReady && selectedTab"
class="px-12 py-4"
:title="selectedTab.title"
:source-module="selectedTab.moduleName"
:templates="selectedTab.templates"
:loading="workflowLoading"
:category-title="selectedTab.title"
@load-workflow="loadWorkflow"
/>
</div>
</div>
</div>
@@ -73,7 +59,7 @@ import ProgressSpinner from 'primevue/progressspinner'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import TemplateWorkflowCard from '@/components/templates/TemplateWorkflowCard.vue'
import TemplateWorkflowView from '@/components/templates/TemplateWorkflowView.vue'
import TemplateWorkflowsSideNav from '@/components/templates/TemplateWorkflowsSideNav.vue'
import { useResponsiveCollapse } from '@/composables/element/useResponsiveCollapse'
import { api } from '@/scripts/api'