Appearance
Asset Management ​
File Information ​
- Path:
app/pages/[brand_name]/files/[id].vue,app/components/card/Asset/ - Purpose: Complete asset viewing, downloading, and management system
Overview ​
The Asset Management system provides comprehensive functionality for viewing, downloading, and managing digital assets. It supports multiple file types, asset previews, quick actions, bulk operations, and integration with sharing and download systems.
Architecture ​
System Components ​
- Asset Details Page: Individual asset view with metadata
- Asset Cards: Asset display in grid/list views
- Asset Preview: Quick view and full preview dialogs
- Asset Actions: Download, share, and other operations
- Bulk Operations: Operations on multiple selected assets
Key Features ​
1. Asset Viewing ​
- Asset detail page with full metadata
- Quick view dialog for preview without navigation
- Full preview with zoom and navigation
- Multiple file type support (images, videos, documents, audio)
- Asset metadata display (name, size, type, dates, tags)
2. Asset Cards ​
- Grid view with thumbnails
- List view with detailed information
- Selection support (single and multi-select)
- Quick actions (download, share, view)
- Loading states with skeleton loaders
3. Asset Preview ​
- Quick view dialog for fast preview
- Full-screen preview mode
- Image zoom and pan
- Video playback with controls
- Document preview (PDF, Office files)
- Keyboard navigation
4. Asset Actions ​
- Download: Single and bulk downloads
- Share: Share asset with permissions
- View Details: Navigate to asset detail page
- Convert: Asset format conversion (if supported)
5. Bulk Operations ​
- Multi-select with Shift+Click support
- Select all functionality
- Bulk download
- Bulk share
- Selection count display
6. Gallery Quick View (collage and folder detail) ​
Added by PR #137 (jasmita/riv-1266-brand-portal-development-quick-view-navigation-as-per-final, RIV-1266, merged 2026-10-28). On the collage detail page (/[brand_name]/collage/[id]) and the folder detail page (/[brand_name]/folders/[id]) the card's expand button opens GalleryQuickViewDialog instead of the single-asset QuickViewDialog. The gallery steps through every asset of the collage or folder (not only the loaded page) with arrow buttons, the keyboard, swipe and a thumbnail strip. Every other AssetCard (search, home, share link) still opens QuickViewDialog; the switch is the externalQuickView prop, which only these two pages set.
Entry points ​
| Trigger | Page | Calls | Assets shown | Starts at | Server paging |
|---|---|---|---|---|---|
Card expand button (tooltip Preview, icon expandGalleryIcon) | collage, folder | openGallery(file) | live list: displayFiles rows without parent_id | clicked asset | yes, unless the inner search is active (isSearchActive) |
Toolbar Preview button (selection toolbar) | collage | openGalleryForSelection() | snapshot of loaded rows with is_selected and no parent_id | first selected row | only when select-all is on (internal_select_all) and search is off |
Toolbar Preview button | folder | openGalleryForSelection() | same | first selected row | same |
The folder Preview button is disabled, with the tooltip Only applicable for assets, while no asset is selected or any folder is selected. On both pages openGalleryForSelection() returns without opening when no loaded row is selected. Without server paging the gallery only contains the rows already loaded on the page.
Pagination contract ​
Each page hands the dialog a GalleryPagination object (fetchPage, loadedPages = max(currentPage, 1), lastPage, total). Fetches go through queryClient.fetchQuery with staleTime: getDefaultStaleTime() and use the page's current sort.
Collage (useCollageDetails) | Folder (useFolderDetails) | |
|---|---|---|
| Query | queryKeys.collections.details(collectionId, params) -> collectionApi.getCollageDetails | queryKeys.folderDetails.details(params) -> foldersApi.fetchFolderDetails |
| Params | page, url_workspace_id, total_record: 36 (COLLAGE_ASSETS_PER_PAGE), sort_value, sort_by | sort_value, sort_by, workspace_id, category_id (route id), page, total_record: 36 |
| Items | data.assets.data | data.assets_with_folder.data, rows with parent_id removed |
| Total | assetList.assets_id.length | data.totalCounts.assets (stored as folderAssetsTotal on every folder load) |
| Last page | data.assets.last_page | data.assets_with_folder.last_page |
With select-all on, fetchPage is wrapped so only selected assets come back:
- Collage: items whose id is in
selectedItemAssets(with select-all: every id inassetList.assets_idexcept loaded rows that were unticked); total = that set's size. - Folder: ids of loaded rows that were unticked form
deselectedIds. IffolderAssetsTotalis larger than the number of loaded asset rows ("capped"), every asset not indeselectedIdscounts as selected and total =folderAssetsTotal - deselectedIds.size(never below 0). Otherwise the set isselectedItemAssetsminusdeselectedIds.
How paging works ​
useGalleryPreviewPager keeps two lists: a head (page 1 onward) and a tail (loaded from the last page backward, so the gallery can wrap from the first asset to the last without loading everything in between). Lists are merged by String(id), so duplicates across pages are dropped. If a fetched page adds nothing new, the next page is fetched in the same run. A failed fetch shows the error in a snackbar and pauses automatic loading until the next explicit load. Every reopen resets the pager.
useGalleryPreviewNavigation decides what Next does:
Previous mirrors it: at the first tail item it loads the page before the tail (backward); at index 0 with loop on it jumps to the last item, loading the last page first (last) when no tail exists yet. While a move is pending both arrow buttons are disabled and the button for that direction shows a spinner; the move completes as soon as the page arrives. loop defaults to true. Prefetch starts when the current index passes 60% of the head (DEFAULT_PREFETCH_RATIO = 0.6, overridable with pagination.prefetchRatio), or 60% into the tail when browsing backwards.
The counter shows {position} of {total}; a position in the tail is counted from the end (total - (count - 1 - index)), so it is correct even when the pages in between were never loaded.
Input ​
| Input | Rule |
|---|---|
ArrowLeft / ArrowRight | Previous / next. Ignored while focus is in INPUT, TEXTAREA, SELECT, VIDEO, AUDIO or a contentEditable element |
Escape | Closes the dialog |
| Swipe on the preview | Horizontal only; at least 50 px, or a flick of at least 0.5 px/ms and more than 10 px. Not started on buttons, links, form fields, video/audio, sliders or .v-slide-group. Off for a single asset |
| Drag on the thumbnail strip | 5 px dead zone, then one step per 88 px (64 px when the window is 600 px or narrower); dragging left moves next |
| Horizontal wheel / trackpad on the strip | Same step size; only when deltaX is larger than deltaY |
| Thumbnail click | Jumps to that asset (ignored right after a drag) |
The strip shows an odd number of slots, at least 3 (floor(stripWidth / step)), centred on the current asset. Slots wrap around when loop is on and there are at least as many assets as slots; otherwise slots outside the range stay empty. A slot whose asset is not loaded yet shows a skeleton and triggers a load (right side: next page; left side: page before the tail, or the last page). With one asset, the arrows, counter and strip are hidden.
The two assets on each side of the current one are preloaded as images: videos (mp4, mov, avi, mkv, mpg, webm, wmv, m4v) use thumbnail_file or preview_image; other types use compress_file, then display_file, thumbnail_file, preview_image.
View tracking ​
| When | What is sent |
|---|---|
| Card expand button | useAssetCard.onExpandAssetsCount: view-count mutation, dispatchAnalytics, trackActivity(body, { source: "preview" }) (was "card" before) |
An asset stays on screen 400 ms (CHANGE_SETTLE_MS) | Once per asset per open: useViewAssetsCount mutation, then dispatchAnalytics and trackActivity(payload, { source: "preview" }) |
Open detail view | dispatchAnalytics and trackActivity (no source), then the asset page (brand_name-files-id) opens in a new tab |
Payload: { asset_id: [id], event: "asset", sub_event: "viewed", environment: "dealer" } plus category_id: [route id] on folder routes (route name contains folders or category) or collection_id: Number(route id) otherwise. The start asset is marked as already tracked when the dialog opens, because the card click counted it. If tracking fails, the asset is unmarked and counted again the next time it is shown.
Header actions ​
- Info tooltip:
Uploaded By(user.name, thenexternal_user.name, thencreated_by, elseN/A),Uploaded Date(created_at),Last Modified(modified_at, elseupdated_at), bothMMM D, YYYY;File Type,File Size,Dimensionwhen width and height exist. - Download (hidden with
hideDownload):downloadFileRef(isImage, asset, false), spinner per asset id, errors in a snackbar.downloadFileRefnow awaitsdownloadStore.downloadFile, so the spinner stays until the download request finishes. - Open detail view, close.
Related changes in the same PR ​
QuickViewDialogand the asset detail page (useAssetDetails,Uploaded By) also fall back toexternal_user.name.useCollageDetails.loadCollageAssets("sort")no longer returns early when a page load is in progress or the last page is reached, so sorting a fully loaded collage refetches._dialogs.scss: theoverflow: hiddenrule on dialog content skips.galleryDialogContent, so the arrow buttons can sit outside the card._skeleton.scss:.assetsDetailBox .imageSkeletongets its ownheight: 100%; width: 100%rule.
File Structure ​
Core Files ​
Vue Page Files (.vue) ​
app/pages/[brand_name]/files/[id].vue- Asset details page- Asset metadata display
- Asset preview
- Asset actions
- Asset information
Route: /{brand_name}/files/{id}
Components ​
app/components/card/Asset/AssetCard.vue- Asset card component- Asset thumbnail display
- Asset metadata
- Quick actions
- Selection support
app/components/card/Asset/AssetContainer.vue- Asset container- Grid/list layout
- Asset card rendering
- Selection management
app/components/dialogs/QuickViewDialog.vue- Quick view dialog- Asset preview
- Asset metadata
- Quick actions
app/components/dialogs/GalleryQuickViewDialog.vue- Gallery quick view (collage and folder detail)- Paged preview with arrows, keyboard, swipe and thumbnail strip
- Download and open detail view
app/components/dialogs/AssetConverterDialog.vue- Asset converter dialog- Format selection
- Quality settings
- Conversion progress
Composables ​
app/composables/core/pages/useAssetDetails.ts- Asset details composable- Asset data fetching
- Asset operations
- Asset metadata management
app/composables/core/components/card/useAssetCard.ts- Asset card composable- Asset card logic
- Selection handling
- Action handlers
app/composables/core/components/dialogs/useQuickViewDialog.ts- Quick view composable- Preview state management
- Navigation handling
API ​
app/composables/api/useAssetsApi.ts- Asset API operations- Get asset details
- Update asset metadata
- Delete asset
- Convert asset format
Data Flow ​
Asset Viewing ​
- User clicks asset card or navigates to asset URL
- Asset details fetched from API
- Asset metadata displayed
- Asset preview loaded (if applicable)
- Actions available (download, share, etc.)
Asset Selection ​
- User clicks asset card checkbox or Shift+Click
- Selection state updated
- Selection count displayed
- Bulk actions enabled
- Selection persisted across pagination
User Interactions ​
Asset Viewing
- Click asset card to view details
- Quick view from card actions
- Full-screen preview
Asset Selection
- Single click to select
- Shift+Click for range selection
- Select all functionality
Asset Actions
- Download asset
- Share asset
- View asset details
- Convert asset format
Bulk Operations
- Download selected assets
- Share selected assets
- Clear selection
File Type Support ​
- Images: JPEG, PNG, GIF, WebP, SVG
- Videos: MP4, WebM, MOV
- Documents: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
- Audio: MP3, WAV, OGG
- Other: ZIP, TXT, HTML
Related Documentation ​
- Asset Details Page - Asset detail page
- AssetCard Component - Asset card component
- QuickViewDialog Component - Quick view dialog
- Download System - Download functionality
- Sharing System - Sharing functionality