Skip to content

Collages ​

Overview ​

Collages are cross-folder asset collections that let workspace users group assets from anywhere in the DAM into a named, shareable set. They are distinct from folders — a collage holds references to assets rather than owning them, so the same asset can appear in many collages without duplication.

  1. Collage listing page: Paginated grid or list of all collages in the workspace, with sorting, preview thumbnails, and per-row actions.
  2. Collage detail page: Full asset browser scoped to one collage, with grid, list, and mosaic view modes, inner search, filters, bulk selection, and a bulk action bar.
  3. SaveToCollage dialog: Inline workflow for adding or removing assets from collages without leaving the current page.
  4. CreateCollageDialog: Shared dialog for creating a new collage or renaming an existing one.
  5. Permission control: Collage visibility is controlled per-portal via the PermissionDialog (instance_visibility array). Restricted collages show a lock icon on every card and list row.

Architecture ​

The collage feature is built across two pages, a card component, and two shared dialogs. The listing page (pages/_workspace_id/dam/collage/index.vue) owns pagination, sorting, and the top-level collage actions (create, rename, share, download, delete, permission). It fetches data from digital-assets/collection/get-all-by-page directly in page methods rather than through a dedicated Vuex action, writing results into local collagesList state and appending on infinite scroll.

The detail page (pages/_workspace_id/dam/collage/_id/index.vue) is the heavier of the two. It loads collage metadata and its asset list separately, supports three view modes (grid, list, mosaic), and integrates the same search and filter stack used on the main DAM search page via the searchCommonFunctions mixin. Sort preferences, column visibility, and thumbnail size are each cached to localStorage via dedicated mixins so they survive page reloads.

Both pages rely on the dam Vuex store for the shared collectionList (used by SaveToCollage) and for the delete/rename actions. Analytics events are dispatched via the amplitudeAnalytics mixin on every significant user action.

File Structure ​

JavaScript Files (.js) ​

  • mixins/common-functions.js — Shared page utility mixin

    • $getWorkspaceId() helper for workspace ID resolution
    • $canCreateCollages(), $canDeleteCollage(), $canEditCollageNameDescription(), etc.
    • changedFields() for computing analytics diff payloads
    • dispatchAnalytics() and trackActivity() wrappers
  • mixins/view-mode-cache.js — View mode persistence

    • getCachedViewModeWithDefault(default) reads from localStorage
    • setCachedViewMode(mode) writes the current mode
    • Shared between collage listing page and detail page
  • mixins/sort-preference-cache.js — Sort persistence

    • getCachedSort(key) returns { field, direction } or null
    • setCachedSort(key, field, direction) persists across sessions
  • mixins/column-visibility-cache.js — Column visibility for list view

    • getCachedColumns(key) returns saved column array
    • setCachedColumns(key, columns) persists the selection
  • mixins/amplitude-analytics.js — Analytics wrapper

    • dispatchAnalytics(body) sends structured analytics events
    • Used for collage create, view, update, delete, and download events
  • store/dam.js — DAM Vuex store (collage-relevant slice)

    • collectionList state: flat array of all collages (used by SaveToCollage)
    • collectionLoading state: loading flag for delete operations
    • getCollections action: fetches full list via digital-assets/collection/get-all
    • addCollection action: prepends a new collage to collectionList
    • deleteCollection action: calls delete API and removes from local state
    • renameCollection action: updates name in collectionList after a successful update

Vue Component Files (.vue) ​

  • pages/_workspace_id/dam/collage/index.vue — Collage listing page

    • Paginated grid and list views with infinite scroll
    • Sort by name, date modified, date added, and asset count
    • Dialogs: create, rename, share, delete, permission
    • Route middleware: authCheck, check-workspace-access, checkWorkspace, can-access-dam-module
  • pages/_workspace_id/dam/collage/_id/index.vue — Collage detail page

    • Three view modes: grid, list, mosaic with masonry layout
    • Inner search and filter bar (reuses DAM search stack)
    • Bulk selection with shift-click and marquee drag
    • BulkActionBar for multi-asset share, download, add-to-another-collage, tag, and custom fields
  • components/dam/Collage/index.vue — Collage card component

    • Multi-image preview thumbnail (1-, 2-, or 3-image mosaic layouts)
    • Context menu with Share, Download, Edit, Portals, Delete
    • Lock icon when instance_visibility is empty
    • Used in both listing page and search results
  • components/dam/Collage/FileListingCard.vue — Asset card inside a collage

    • Grid and mosaic card for individual assets within a collage
    • Quick-view, select, rename, remove-from-collage, download, permission actions
  • components/dam/Dialogs/CreateCollageDialog.vue — Create / rename dialog

    • Dual purpose: new collage (with showSubHeading: true) or rename existing
    • Optional description field controlled by the isDescription prop
    • Also handles folder creation when addNewFolder: true
  • components/dam/Dialogs/SaveToCollage.vue — Add-to-collage dialog

    • Searchable list of all workspace collages with Add/Remove toggles
    • Inline create via search input when no match found
    • Supports deferred mode (for upload queue) and selectAll for bulk operations
  • components/svg/Collages.vue — Collages sidebar icon
  • components/svg/CollageEmptyIcon.vue — Empty-state illustration

Collage Listing Page ​

File: pages/_workspace_id/dam/collage/index.vue

Route: /:workspace_id/dam/collage

Features ​

  • Grid and list view with persisted view mode
  • Infinite scroll pagination (50 items per page)
  • Sort by name, date modified, date added, or asset count
  • Lock icon for collages with restricted portal visibility
  • Share, download (single-file or zip), rename, manage portals, delete per row

Key Methods ​

javascript
{
  getCollagesList(page = 1) {},    // Fetch paginated collages; appends on page > 1
  onScroll(event) {},              // Triggers loadMoreCollages when near bottom
  loadMoreCollages() {},           // Increments page and calls getCollagesList
  sortCollage(field, isSort) {},   // Toggles sort direction and re-sorts local list
  addCollage() {},                 // Emits 'openCreateCollage' EventBus event
  shareCollage(item) {},           // Opens ShareAssetDialog for the selected collage
  downloadCollage(collage) {},     // Single file or multi-file zip download
  deleteCollage() {},              // Dispatches dam/deleteCollection
  changeCollageName(payload) {},   // PATCH name+description, dispatches dam/renameCollection
  openPermissions(item) {},        // Opens PermissionDialog
  onPermissionUpdated(collage, e) {} // Updates local instance_visibility after save
}

Usage ​

vue
<template>
  <!-- Rendered by Nuxt routing — no direct parent usage -->
  <!-- Accessed at /:workspace_id/dam/collage -->
</template>

Collage Detail Page ​

File: pages/_workspace_id/dam/collage/_id/index.vue

Route: /:workspace_id/dam/collage/:id

Features ​

  • Three view modes: grid, list, mosaic (masonry)
  • Inner search with 500ms debounce
  • Filter bar with tag, file type, uploaded-by, and custom field filters
  • Multi-select with shift-click (shiftSelection mixin) and drag marquee (marqueeSelection mixin)
  • BulkActionBar for bulk share, download, tag, custom fields, add to another collage
  • Sort and column visibility cached to localStorage

Key Methods ​

javascript
{
  getCollageDetails() {},          // Loads collage metadata (name, description, etc.)
  loadCollageAssets(sortField) {}, // Loads the asset list with server-side sort
  performSearch() {},              // Issues search/filter API request
  handleSearchInput() {},          // Debounces performSearch via lodash debounce
  applyHeaderSort(field) {},       // Column header click sort with direction toggle
  handleSortMenuChange(payload) {}, // DisplayPanel sort-menu change handler
  openAsset(file) {},              // Opens QuickView or navigates to asset detail
  toggleSelect(file, idx, event) {}, // Handles individual and shift-click selection
  downloadFile(type) {},           // Single, multi, or full-collage zip download
  removeCollage() {},              // Deletes the collage and navigates to listing
  deleteFromDrop(flag) {},         // Removes selected assets from collage
  openPermissionDialog(item, flag) {} // Opens PermissionDialog for asset or collage
}

Collage Card Component ​

File: components/dam/Collage/index.vue

Features ​

  • Multi-image preview: 1-image (full), 2-image (60/40 split), 3-image (60 + 40 stacked)
  • Context menu driven by a menuItems computed array (Share, Download, Edit, Portals, Delete)
  • Subscription gate on Portals action (collection_permission_customisation feature flag)
  • SVG icon fallback for non-image asset types

Props ​

javascript
{
  collage: {
    type: Object,
    required: true
    // { id, name, description, assets_count, assets_id, preview_images, instance_visibility }
  },
  downloading: {
    type: Boolean,
    default: false
  },
  flag: {
    type: String,
    default: '' // 'asset-detail' | 'search-page' | ''
  }
}

Events ​

javascript
{
  'share': (collage) => {},        // Request parent to open ShareAssetDialog
  'download': (collage) => {},     // Request parent to start download
  'permission': (collage) => {},   // Request parent to open PermissionDialog
  'delete': (collage) => {},       // Request parent to confirm and delete
  'nameChange': () => {},          // Emitted after a successful rename
  'opened': () => {}               // Emitted when card click navigates to detail
}

Usage ​

vue
<template>
  <CollageCards
    :collage="collage"
    :downloading="downloadColgId == collage.id"
    @delete="confirmDeleteCollage(collage)"
    @permission="openPermissions(collage)"
    @share="shareCollage(collage)"
    @download="downloadCollage(collage)"
  />
</template>

<script>
export default {
  components: {
    CollageCards: () => import('~/components/dam/Collage'),
  }
}
</script>

SaveToCollage Dialog ​

File: components/dam/Dialogs/SaveToCollage.vue

Features ​

  • Searchable collage list with Add/Remove toggles per row
  • Inline create: when search has no exact match, a "Create new collage" button appears
  • Sorted so already-added collages appear at the top
  • deferred prop for the upload queue — selections are batched and emitted on close rather than applied immediately

Props ​

javascript
{
  files: {
    type: Array,
    default: () => []  // Asset objects or IDs to add/remove
  },
  dialog: {
    type: Boolean,
    default: false
  },
  selectAll: {
    type: Boolean,
    default: false    // When true, passes all selected asset IDs
  },
  flag: {
    type: String,
    default: ''       // Context flag, e.g. 'collage-details'
  },
  deferred: {
    type: Boolean,
    default: false    // Batch mode for upload queue
  },
  queuedCollageIds: {
    type: Array,
    default: () => [] // Pre-selected collage IDs in deferred mode
  }
}

Events ​

javascript
{
  'close': (false) => {},          // Dialog closed
  'reload': () => {},              // Request parent to reload asset list
  'queue-complete': (payload) => {} // Deferred mode: { collages, changed }
}

Workflows ​

Create Collage ​

1. User clicks "New Collage" button
   Page: pages/_workspace_id/dam/collage/index.vue
   Action: addCollage() emits EventBus 'openCreateCollage'
   ↓
2. CreateCollageDialog opens (showSubHeading: true, isDescription: true)
   Component: components/dam/Dialogs/CreateCollageDialog.vue
   ↓
3. User fills name (required, min 3 chars) and optional description
   Validation: rejects characters / \ : ? * " < >
   ↓
4. User submits → submitCollage()
   POST /digital-assets/collection/create
   Body: { name, description }
   ↓
5. On success:
   - dam/addCollection dispatched → collectionList updated
   - EventBus 'collectionUpdate' emitted → listing page calls getCollagesList()
   - EventBus 'syncDashboard' emitted with 'collage'
   - Analytics event: collage / created

Add Assets to a Collage ​

1. User selects assets in DAM (any folder, search, or uploaded view)
   ↓
2. User opens "Add to Collage" via:
   - Asset card context menu → SaveToCollage.vue
   - BulkActionBar "Add to Collage" button
   ↓
3. SaveToCollage dialog loads
   - dam/getCollections dispatched → collages fetched
   - Already-added collages sorted to top and marked is_added: true
   ↓
4. User clicks "Add" on a collage row → saveCollection(id)
   POST /digital-assets/collection/:id/add-assets
   Body: { assets_id: [1, 2, 3] }
   ↓
5. On success:
   - Collage row toggles to "Remove"
   - EventBus 'updateCollageAssets' emitted with { flag: 'add', collage_id, assetsId }
   - Collage detail page updates its file list if currently open
   - Analytics event: collage / asset-added

Share a Collage ​

1. User clicks Share from collage card menu or collage detail options menu
   Condition: collage.assets_count > 0 (disabled for empty collages)
   ↓
2. ShareAssetDialog opens
   Props: { heading: 'Share Collage', collection: true, collection-assets-id: collage.id }
   ↓
3. User configures share link (expiry, password, download permissions)
   API: POST /digital-assets/share-link/create
   ↓
4. Share link generated and displayed to user
   - Shareable URL returned and shown in dialog
   - Analytics event: collage / share (via parent)

Delete a Collage ​

1. User clicks Delete from context menu
   Action: confirmDeleteCollage(item) sets deleteDialog = true
   ↓
2. ConfirmationDialog displays warning
   Message: 'Are you sure you want to delete this <name> collage?'
   ↓
3. User confirms → deleteCollage()
   Action: dam/deleteCollection(collage.id)
   DELETE /digital-assets/collection/delete/:id
   ↓
4. On success:
   - collectionList mutation removes the entry
   - Page removes collage from local collagesList
   - Detail page navigates back to listing route
   - Pending collage queue in localStorage is also cleaned
   - Analytics event: collage / deleted

API Integration ​

Endpoints ​

MethodEndpointPurpose
GETdigital-assets/collection/get-all-by-pagePaginated collage listing
GETdigital-assets/collection/get-allFull list for SaveToCollage
POSTdigital-assets/collection/createCreate new collage
POSTdigital-assets/collection/update/:idRename / update description
DELETEdigital-assets/collection/delete/:idDelete collage
POSTdigital-assets/collection/:id/add-assetsAdd assets to collage
POSTdigital-assets/collection/:id/remove-assetsRemove assets from collage

Get Collage List (Paginated) ​

javascript
// Request
GET /digital-assets/collection/get-all-by-page?page=1&sort_value=modified_at&sort_by=DESC&workspace_id=42

// Response
{
  "data": {
    "current_page": 1,
    "last_page": 3,
    "data": [
      {
        "id": 101,
        "name": "Campaign Assets",
        "description": "Q2 brand campaign",
        "assets_count": 24,
        "assets_id": [1, 2, 3],
        "preview_images": [
          { "url": "https://cdn.example.com/thumb1.jpg", "file_type": "jpg", "uuid": "abc" },
          { "url": "https://cdn.example.com/thumb2.jpg", "file_type": "png", "uuid": "def" }
        ],
        "instance_visibility": [5, 8],
        "modified_at": "2025-07-15T10:30:00Z",
        "created_at": "2025-06-01T08:00:00Z"
      }
    ]
  }
}

Create Collage ​

javascript
// Request
POST /digital-assets/collection/create
{
  "name": "Campaign Assets",
  "description": "Q2 brand campaign"
}

// Response
{
  "message": "Collage created successfully",
  "data": {
    "id": 101,
    "name": "Campaign Assets",
    "description": "Q2 brand campaign",
    "assets_count": 0,
    "assets_id": [],
    "preview_images": []
  }
}

Add Assets to Collage ​

javascript
// Request
POST /digital-assets/collection/101/add-assets
{
  "assets_id": [45, 67, 89]
}

// Response
{
  "message": "Assets added to collage successfully"
}

Component Integration ​

vue
<template>
  <div>
    <!-- Collage list -->
    <v-row no-gutters class="my-0 row-gap-24">
      <v-col
        v-for="collage in collagesList"
        :key="collage.id"
        cols="4"
        lg="3"
        xl="2"
      >
        <CollageCards
          :collage="collage"
          :downloading="downloadColgId === collage.id"
          @delete="confirmDelete(collage)"
          @share="openShare(collage)"
          @download="downloadCollage(collage)"
          @permission="openPermissions(collage)"
        />
      </v-col>
    </v-row>

    <!-- Dialogs -->
    <client-only>
      <SaveToCollage
        :dialog="saveCollageDialog"
        :files="selectedAssets"
        @close="saveCollageDialog = false"
        @reload="refreshAssets"
      />
      <CreateCollageDialog
        :dialog="createDialog"
        heading="New Collage"
        :isDescription="true"
        :showSubHeading="true"
        @close="createDialog = false"
      />
    </client-only>
  </div>
</template>

<script>
import commonFunctions from '~/mixins/common-functions'

export default {
  components: {
    CollageCards: () => import('~/components/dam/Collage'),
    SaveToCollage: () => import('~/components/dam/Dialogs/SaveToCollage'),
    CreateCollageDialog: () =>
      import('~/components/dam/Dialogs/CreateCollageDialog.vue'),
  },
  mixins: [commonFunctions],
  data() {
    return {
      collagesList: [],
      selectedAssets: [],
      saveCollageDialog: false,
      createDialog: false,
      downloadColgId: 0,
    }
  },
  methods: {
    confirmDelete(collage) {
      // open confirmation dialog...
    },
    openShare(collage) {
      // open ShareAssetDialog...
    },
    async downloadCollage(collage) {
      this.downloadColgId = collage.id
      await this.$store.dispatch('dam/downloadMultipleFiles', {
        collection_id: collage.id,
        download_name: collage.name,
      })
    },
    openPermissions(collage) {
      // open PermissionDialog...
    },
    refreshAssets() {
      // reload after add-to-collage
    },
  },
}
</script>
  • File Upload — Upload system that feeds assets into collages
  • Search — Search results surface collage cards alongside assets
  • Portals — Portal permission management referenced by collage instance_visibility
  • DAM Store — collectionList, getCollections, addCollection, deleteCollection, renameCollection
  • Mixins - Common Functions — Permission helpers ($canCreateCollages, etc.)
  • Mixins - View Mode Cache — Grid/list persistence