mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-07 06:00:03 +00:00
feat: Add generation time sort options to Media Asset Panel (#6698)
## Summary Add generation time-based sorting options to the Media Asset Panel ## Changes - **New sorting options**: - Generation time (longest first) - Sort by longest execution time - Generation time (fastest first) - Sort by shortest execution time - **Show only in Generated tab**: - Generation time sorting is only meaningful for output assets with `executionTimeInSeconds` metadata - Implemented conditional rendering via `showGenerationTimeSort` prop ## Technical Details - `useMediaAssetFiltering.ts`: - Added `'longest'` and `'fastest'` to `SortOption` type - Added `getAssetExecutionTime` helper function - Implemented sorting logic using switch-case pattern - `MediaAssetSortMenu.vue`: - Added `showGenerationTimeSort` prop - Generation time sort buttons placed inside `<template v-if="showGenerationTimeSort">` - `MediaAssetFilterBar.vue`: - Receives `showGenerationTimeSort` prop and passes it to `MediaAssetSortMenu` - `AssetsSidebarTab.vue`: - Passes `showGenerationTimeSort` prop based on `activeTab === 'output'` - `src/locales/en/main.json`: - Added `sortLongestFirst`: "Generation time (longest first)" - Added `sortFastestFirst`: "Generation time (fastest first)" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -36,13 +36,14 @@
|
||||
</div>
|
||||
<!-- Normal Tab View -->
|
||||
<TabList v-else v-model="activeTab" class="pt-4 pb-1">
|
||||
<Tab value="input">{{ $t('sideToolbar.labels.imported') }}</Tab>
|
||||
<Tab value="output">{{ $t('sideToolbar.labels.generated') }}</Tab>
|
||||
<Tab value="input">{{ $t('sideToolbar.labels.imported') }}</Tab>
|
||||
</TabList>
|
||||
<!-- Filter Bar -->
|
||||
<MediaAssetFilterBar
|
||||
v-model:search-query="searchQuery"
|
||||
v-model:sort-by="sortBy"
|
||||
:show-generation-time-sort="activeTab === 'output'"
|
||||
/>
|
||||
</template>
|
||||
<template #body>
|
||||
|
||||
@@ -621,7 +621,9 @@
|
||||
"mediaAssets": {
|
||||
"title": "Media Assets",
|
||||
"sortNewestFirst": "Newest first",
|
||||
"sortOldestFirst": "Oldest first"
|
||||
"sortOldestFirst": "Oldest first",
|
||||
"sortLongestFirst": "Generation time (longest first)",
|
||||
"sortFastestFirst": "Generation time (fastest first)"
|
||||
},
|
||||
"backToAssets": "Back to all assets",
|
||||
"searchAssets": "Search assets...",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<template #default="{ close }">
|
||||
<MediaAssetSortMenu
|
||||
:sort-by="sortBy"
|
||||
:show-generation-time-sort
|
||||
:close="close"
|
||||
@update:sort-by="handleSortChange"
|
||||
/>
|
||||
@@ -29,23 +30,24 @@ import { isCloud } from '@/platform/distribution/types'
|
||||
import AssetSortButton from './MediaAssetSortButton.vue'
|
||||
import MediaAssetSortMenu from './MediaAssetSortMenu.vue'
|
||||
|
||||
interface MediaAssetSearchBarProps {
|
||||
const { showGenerationTimeSort = false } = defineProps<{
|
||||
searchQuery: string
|
||||
sortBy: 'newest' | 'oldest'
|
||||
}
|
||||
|
||||
defineProps<MediaAssetSearchBarProps>()
|
||||
sortBy: 'newest' | 'oldest' | 'longest' | 'fastest'
|
||||
showGenerationTimeSort?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:searchQuery': [value: string]
|
||||
'update:sortBy': [value: 'newest' | 'oldest']
|
||||
'update:sortBy': [value: 'newest' | 'oldest' | 'longest' | 'fastest']
|
||||
}>()
|
||||
|
||||
const handleSearchChange = (value: string | undefined) => {
|
||||
emit('update:searchQuery', value ?? '')
|
||||
}
|
||||
|
||||
const handleSortChange = (value: 'newest' | 'oldest') => {
|
||||
const handleSortChange = (
|
||||
value: 'newest' | 'oldest' | 'longest' | 'fastest'
|
||||
) => {
|
||||
emit('update:sortBy', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -21,22 +21,53 @@
|
||||
<i v-if="sortBy === 'oldest'" class="icon-[lucide--check] size-4" />
|
||||
</template>
|
||||
</IconTextButton>
|
||||
|
||||
<template v-if="showGenerationTimeSort">
|
||||
<IconTextButton
|
||||
type="transparent"
|
||||
icon-position="right"
|
||||
:label="$t('sideToolbar.mediaAssets.sortLongestFirst')"
|
||||
@click="handleSortChange('longest')"
|
||||
>
|
||||
<template #icon>
|
||||
<i v-if="sortBy === 'longest'" class="icon-[lucide--check] size-4" />
|
||||
</template>
|
||||
</IconTextButton>
|
||||
|
||||
<IconTextButton
|
||||
type="transparent"
|
||||
icon-position="right"
|
||||
:label="$t('sideToolbar.mediaAssets.sortFastestFirst')"
|
||||
@click="handleSortChange('fastest')"
|
||||
>
|
||||
<template #icon>
|
||||
<i v-if="sortBy === 'fastest'" class="icon-[lucide--check] size-4" />
|
||||
</template>
|
||||
</IconTextButton>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconTextButton from '@/components/button/IconTextButton.vue'
|
||||
|
||||
const { sortBy, close } = defineProps<{
|
||||
sortBy: 'newest' | 'oldest'
|
||||
const {
|
||||
sortBy,
|
||||
close,
|
||||
showGenerationTimeSort = false
|
||||
} = defineProps<{
|
||||
sortBy: 'newest' | 'oldest' | 'longest' | 'fastest'
|
||||
close: () => void
|
||||
showGenerationTimeSort?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:sortBy': [value: 'newest' | 'oldest']
|
||||
'update:sortBy': [value: 'newest' | 'oldest' | 'longest' | 'fastest']
|
||||
}>()
|
||||
|
||||
const handleSortChange = (value: 'newest' | 'oldest') => {
|
||||
const handleSortChange = (
|
||||
value: 'newest' | 'oldest' | 'longest' | 'fastest'
|
||||
) => {
|
||||
emit('update:sortBy', value)
|
||||
close()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Ref } from 'vue'
|
||||
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
|
||||
type SortOption = 'newest' | 'oldest'
|
||||
type SortOption = 'newest' | 'oldest' | 'longest' | 'fastest'
|
||||
|
||||
/**
|
||||
* Get timestamp from asset (either create_time or created_at)
|
||||
@@ -18,6 +18,13 @@ const getAssetTime = (asset: AssetItem): number => {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get execution time from asset user_metadata
|
||||
*/
|
||||
const getAssetExecutionTime = (asset: AssetItem): number => {
|
||||
return (asset.user_metadata?.executionTimeInSeconds as number) ?? 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Media Asset Filtering composable
|
||||
* Manages search, filter, and sort for media assets
|
||||
@@ -46,12 +53,24 @@ export function useMediaAssetFiltering(assets: Ref<AssetItem[]>) {
|
||||
|
||||
const filteredAssets = computed(() => {
|
||||
// Sort by create_time (output assets) or created_at (input assets)
|
||||
if (sortBy.value === 'oldest') {
|
||||
// Ascending order (oldest first)
|
||||
return sortByUtil(searchFiltered.value, [getAssetTime])
|
||||
} else {
|
||||
// Descending order (newest first) - negate for descending
|
||||
return sortByUtil(searchFiltered.value, [(asset) => -getAssetTime(asset)])
|
||||
switch (sortBy.value) {
|
||||
case 'oldest':
|
||||
// Ascending order (oldest first)
|
||||
return sortByUtil(searchFiltered.value, [getAssetTime])
|
||||
case 'longest':
|
||||
// Descending order (longest execution time first)
|
||||
return sortByUtil(searchFiltered.value, [
|
||||
(asset) => -getAssetExecutionTime(asset)
|
||||
])
|
||||
case 'fastest':
|
||||
// Ascending order (fastest execution time first)
|
||||
return sortByUtil(searchFiltered.value, [getAssetExecutionTime])
|
||||
case 'newest':
|
||||
default:
|
||||
// Descending order (newest first) - negate for descending
|
||||
return sortByUtil(searchFiltered.value, [
|
||||
(asset) => -getAssetTime(asset)
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user