mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-23 07:50:15 +00:00
feat: Add sort functionality to Media Asset Panel (#6695)
## Overview Adds sort functionality to the Media Asset Panel. Users can sort assets by creation time in Cloud environments. ## Key Changes ### 1. Sort Functionality (Cloud Only) - "Newest first" (most recent) - "Oldest first" (oldest) - Sorting based on `create_time` field (output assets) - Sorting based on `created_at` field (input assets) - Sort button is only displayed in Cloud environments ### 2. create_time Field Integration **Related PR**: #6092 Implemented sort functionality using the `create_time` field introduced in PR #6092. Applied the code from that PR directly to the following files: - `src/schemas/apiSchema.ts`: Added `create_time` field to `zExtraData` - `src/stores/queueStore.ts`: Added `createTime` getter to `TaskItemImpl` - `src/platform/remote/comfyui/history/types/historyV2Types.ts`: Added `create_time` to History V2 API response types - `src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts`: Pass through `create_time` in V2→V1 adapter - `src/platform/assets/composables/media/assetMappers.ts`: Include `create_time` in asset metadata ### 3. Component Structure Improvements Created new components following existing component styles for consistency: - **`MediaAssetSearchBar.vue`**: Component combining existing SearchBox with sort button - **`AssetSortButton.vue`**: Same structure as `MoreButton.vue` (IconButton + Popover) - **`MediaAssetSortMenu.vue`**: Same style as `MediaAssetMoreMenu.vue` (using IconTextButton) - **`AssetsSidebarTab.vue`**: Refactored to use `MediaAssetSearchBar` ### 4. Utility Usage - Improved sort logic using `es-toolkit`'s `sortBy` - Follows project guidelines (CLAUDE.md) ## Technical Details ### History V2 API's create_time - Cloud backend provides `create_time` (in milliseconds) through History V2 API - Enables accurate sorting by creation time - For input assets, uses existing `created_at` (ISO string) ### Sort Implementation Uses `es-toolkit`'s `sortBy` in `useMediaAssetFiltering` composable: ```typescript // Get timestamp from asset (either create_time or created_at) const getAssetTime = (asset: AssetItem): number => { return ( (asset.user_metadata?.create_time as number) ?? (asset.created_at ? new Date(asset.created_at).getTime() : 0) ) } // Sort by time if (sortBy.value === 'oldest') { return sortByUtil(searchFiltered.value, [getAssetTime]) } else { return sortByUtil(searchFiltered.value, [(asset) => -getAssetTime(asset)]) } ``` ## Testing - ✅ Typecheck passed - ✅ Lint passed - ✅ Format passed 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6695-feat-Add-sort-functionality-to-Media-Asset-Panel-2ab6d73d3650818c818ff3559875d869) by [Unito](https://www.unito.io) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,8 @@ export function mapTaskOutputToAssetItem(
|
||||
subfolder: output.subfolder,
|
||||
executionTimeInSeconds: taskItem.executionTimeInSeconds,
|
||||
format: output.format,
|
||||
workflow: taskItem.workflow
|
||||
workflow: taskItem.workflow,
|
||||
create_time: taskItem.createTime
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
import { sortBy as sortByUtil } from 'es-toolkit'
|
||||
import Fuse from 'fuse.js'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
|
||||
type SortOption = 'newest' | 'oldest'
|
||||
|
||||
/**
|
||||
* Get timestamp from asset (either create_time or created_at)
|
||||
*/
|
||||
const getAssetTime = (asset: AssetItem): number => {
|
||||
return (
|
||||
(asset.user_metadata?.create_time as number) ??
|
||||
(asset.created_at ? new Date(asset.created_at).getTime() : 0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Media Asset Filtering composable
|
||||
* Manages search, filter, and sort for media assets
|
||||
@@ -12,6 +25,7 @@ import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
export function useMediaAssetFiltering(assets: Ref<AssetItem[]>) {
|
||||
const searchQuery = ref('')
|
||||
const debouncedSearchQuery = refDebounced(searchQuery, 50)
|
||||
const sortBy = ref<SortOption>('newest')
|
||||
|
||||
const fuseOptions = {
|
||||
keys: ['name'],
|
||||
@@ -21,7 +35,7 @@ export function useMediaAssetFiltering(assets: Ref<AssetItem[]>) {
|
||||
|
||||
const fuse = computed(() => new Fuse(assets.value, fuseOptions))
|
||||
|
||||
const filteredAssets = computed(() => {
|
||||
const searchFiltered = computed(() => {
|
||||
if (!debouncedSearchQuery.value.trim()) {
|
||||
return assets.value
|
||||
}
|
||||
@@ -30,8 +44,20 @@ export function useMediaAssetFiltering(assets: Ref<AssetItem[]>) {
|
||||
return results.map((result) => result.item)
|
||||
})
|
||||
|
||||
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)])
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
searchQuery,
|
||||
sortBy,
|
||||
filteredAssets
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user