Skip to content

Tag Management ​

Overview ​

The Tags System provides flexible categorization and organization for digital assets using simple key-value tags. Tags enable users to quickly label, group, and search assets with custom keywords. The system supports tag creation, management, bulk operations, search filtering, and asset integration.

Architecture ​

System Components ​

  1. Tag Definitions: Workspace-level tag definitions with colors and metadata
  2. Tag Assignments: Tags assigned to assets (many-to-many relationship)
  3. Tag Management: UI for creating, editing, and managing tags
  4. Asset Integration: Components for adding/removing tags from assets
  5. Search Integration: Tag-based filtering and search capabilities
  6. Bulk Operations: Apply/remove tags from multiple assets simultaneously

File Structure ​

Core Tag Components ​

Vue Component Files (.vue) ​

  • components/dam/FileTagInput.vue - Tag input component

    • Add/remove tags from files
    • Tag autocomplete/suggestions
    • Tag creation on-the-fly
    • Tag display with colors
    • Tag validation
  • components/dam/Dialogs/AddTags/TagsBox.vue - Tags box dialog component

    • Tag selection interface
    • Available tags display
    • Tag search/filter
    • Tag creation
    • Tag assignment to assets
  • components/dam/AssetList/AddTags.vue - Add tags component for asset list

    • Tag management in asset list context
    • Quick tag addition
    • Tag removal
    • Tag display in list view
  • components/dam/Dialogs/AddTags/AddMultipleTags.vue - Dialog for adding multiple tags

    • Bulk tag assignment
    • Multiple asset selection
    • Tag selection interface
    • Batch tag operations

SVG Icon Components ​

  • components/svg/CollageTagsIcon.vue - Tags icon
    • Used in navigation and UI elements
    • Consistent iconography for tags

Tag Display & Asset Integration ​

Vue Component Files (.vue) ​

  • pages/_workspace_id/dam/uploaded.vue - Uploaded assets page
    • Contains addTag method
    • Tag management functionality
    • Tag display in uploaded assets list
    • Tag filtering options

Tag Search & Filtering ​

JavaScript Files (.js) ​

  • mixins/search-common-functions.js - Search common functions mixin
    • Contains buildTagFilter function
    • Constructs tag filter queries
    • Integrates with search API
    • Handles multiple tag filters

Vue Component Files (.vue) ​

  • components/dam/SearchAssets.vue - Search assets component

    • Includes tag search functionality
    • Tag filter application
    • Tag-based result filtering
  • components/dam/SearchBarTypeSense.vue - Search bar component

    • Includes tag search
    • Tag autocomplete in search
    • Tag suggestions
  • components/dam/Search/SearchFilter.vue - Search filter component

    • Includes tag filters
    • Tag selection interface
    • Multiple tag filter support
    • Tag filter removal
  • components/dam/Search/ListLevelThree.vue - Search list level three

    • Includes tag filter options
    • Nested tag filter display
    • Tag-specific filter UI
  • components/dam/Search/AddedFilterOption.vue - Added filter option component

    • Displays active tag filters
    • Tag filter removal functionality
    • Tag filter value display
    • Tag filter editing
  • pages/_workspace_id/dam/search.vue - Search page

    • Includes tag search
    • Tag filter integration
    • Tag-based search results

Tag Bulk Actions ​

Vue Component Files (.vue) ​

  • components/dam/SearchBulkActions.vue - Bulk actions component
    • Tag bulk operations
    • Apply tags to multiple assets
    • Remove tags from multiple assets
    • Bulk tag management interface

Supporting Files ​

JavaScript Files (.js) ​

  • plugins/helper.js - Helper functions plugin
    • Tag utilities
    • Tag management functions
    • Tag formatting helpers
    • Tag validation functions

Tag Structure ​

Tag Object ​

javascript
{
  id: 1,
  workspace_id: 123,
  name: "marketing",
  color: "#FF5722",
  usage_count: 45,
  created_at: "2024-01-15T10:00:00Z",
  updated_at: "2024-01-20T14:30:00Z"
}

Tag Assignment Object ​

javascript
{
  id: 1,
  asset_id: 456,
  tag_id: 1,
  tag: {
    id: 1,
    name: "marketing",
    color: "#FF5722"
  },
  created_at: "2024-01-15T10:00:00Z"
}

Component Implementation ​

File Tag Input Component ​

File: components/dam/FileTagInput.vue

Tag input component for adding and removing tags from files.

Props ​

javascript
{
  value: {
    type: Array,
    default: () => []
    // Array of tag objects or tag IDs
  },
  assetId: {
    type: [String, Number],
    default: null
  },
  multiple: {
    type: Boolean,
    default: true
  },
  creatable: {
    type: Boolean,
    default: true
  },
  workspaceId: {
    type: [String, Number],
    required: true
  }
}

Methods ​

javascript
// Add tag
addTag(tag) {
  // Validate tag
  // Add to selected tags
  // Emit update event
  // Call API to save if assetId provided
}

// Remove tag
removeTag(tagId) {
  // Remove from selected tags
  // Emit update event
  // Call API to remove if assetId provided
}

// Create new tag
createTag(tagName, color) {
  // Validate tag name
  // Call API to create tag
  // Add to selected tags
  // Emit tag-created event
}

// Search tags
searchTags(query) {
  // Filter available tags
  // Return matching tags
}

Events ​

javascript
{
  'input': (tags) => {},        // Tags changed
  'tag-added': (tag) => {},      // Tag added
  'tag-removed': (tagId) => {},  // Tag removed
  'tag-created': (tag) => {}     // New tag created
}

Usage ​

vue
<template>
  <FileTagInput
    v-model="selectedTags"
    :asset-id="assetId"
    :workspace-id="workspaceId"
    :creatable="true"
    @tag-added="handleTagAdded"
    @tag-removed="handleTagRemoved"
  />
</template>

<script>
import FileTagInput from '~/components/dam/FileTagInput.vue'

export default {
  components: {
    FileTagInput
  },
  data() {
    return {
      assetId: 456,
      workspaceId: this.$route.params.workspace_id,
      selectedTags: []
    }
  }
}
</script>

Tags Box Dialog Component ​

File: components/dam/Dialogs/AddTags/TagsBox.vue

Dialog component for tag management and assignment.

Features ​

  • Display available tags
  • Tag search and filtering
  • Tag selection interface
  • Create new tags
  • Assign tags to assets
  • Remove tags from assets

Props ​

javascript
{
  dialog: {
    type: Boolean,
    default: false
  },
  assetIds: {
    type: Array,
    default: () => []
    // Array of asset IDs for bulk operations
  },
  currentTags: {
    type: Array,
    default: () => []
    // Currently assigned tags
  },
  workspaceId: {
    type: [String, Number],
    required: true
  }
}

Methods ​

javascript
// Load available tags
async loadTags() {
  // Fetch all tags for workspace
  // Filter and format tags
}

// Search tags
searchTags(query) {
  // Filter tags by name
  // Return matching tags
}

// Select tag
selectTag(tag) {
  // Add to selected tags
  // Update UI
}

// Create tag
async createTag(name, color) {
  // Validate tag name
  // Call API to create
  // Add to available tags
  // Select new tag
}

// Apply tags
async applyTags() {
  // Validate selection
  // Call API to assign tags
  // Handle success/error
}

// Remove tags
async removeTags(tagIds) {
  // Call API to remove tags
  // Update local state
}

Add Tags Component ​

File: components/dam/AssetList/AddTags.vue

Component for adding tags in asset list context.

Features ​

  • Quick tag addition
  • Tag display in list
  • Tag removal
  • Tag management for list items

Props ​

javascript
{
  asset: {
    type: Object,
    required: true
  },
  tags: {
    type: Array,
    default: () => []
  },
  editable: {
    type: Boolean,
    default: true
  }
}

Add Multiple Tags Dialog ​

File: components/dam/Dialogs/AddTags/AddMultipleTags.vue

Dialog for adding multiple tags to multiple assets.

Features ​

  • Bulk tag assignment
  • Multiple asset selection
  • Tag selection interface
  • Batch operations
  • Progress tracking

Props ​

javascript
{
  dialog: {
    type: Boolean,
    default: false
  },
  assetIds: {
    type: Array,
    required: true
    // Array of selected asset IDs
  },
  workspaceId: {
    type: [String, Number],
    required: true
  }
}

Methods ​

javascript
// Load available tags
async loadAvailableTags() {
  // Fetch all workspace tags
}

// Apply tags to selected assets
async applyTagsToAssets(tagIds) {
  // Validate inputs
  // Call bulk API
  // Track progress
  // Handle success/error
}

// Remove tags from selected assets
async removeTagsFromAssets(tagIds) {
  // Call bulk remove API
  // Update UI
}

Tag Search & Filtering ​

Build Tag Filter Function ​

File: mixins/search-common-functions.js

The buildTagFilter function constructs filter queries for tags.

Function Signature ​

javascript
buildTagFilter(tagIds, operator = 'in') {
  // Build filter object for tags
  // Return filter query object
}

Supported Operators ​

  • in - Assets with any of the specified tags
  • not_in - Assets without any of the specified tags
  • all - Assets with all of the specified tags

Usage ​

javascript
// In search component
import searchCommonFunctions from '~/mixins/search-common-functions'

export default {
  mixins: [searchCommonFunctions],
  methods: {
    applyTagFilter(tagIds) {
      const filter = this.buildTagFilter(tagIds, 'in')
      this.addFilter(filter)
    }
  }
}

Search Filter Component ​

File: components/dam/Search/SearchFilter.vue

Includes tag filters in the search interface.

Features ​

  • Tag filter selection
  • Multiple tag selection
  • Tag search within filters
  • Filter application
  • Filter removal

Added Filter Option Component ​

File: components/dam/Search/AddedFilterOption.vue

Displays active tag filters.

Features ​

  • Shows active tag filters with tag names and colors
  • Remove filter functionality
  • Edit filter value

Tag Bulk Actions ​

Search Bulk Actions Component ​

File: components/dam/SearchBulkActions.vue

Bulk actions component including tag operations.

Features ​

  • Apply tags to multiple selected assets
  • Remove tags from multiple selected assets
  • Bulk tag management
  • Progress tracking for bulk operations

Methods ​

javascript
// Apply tags to selected assets
async applyTagsToSelected(tagIds) {
  // Get selected asset IDs
  // Call bulk API
  // Show progress
  // Handle success/error
}

// Remove tags from selected assets
async removeTagsFromSelected(tagIds) {
  // Get selected asset IDs
  // Call bulk remove API
  // Update UI
}

Helper Functions ​

Tag Utilities ​

File: plugins/helper.js

Helper functions for tag management.

Functions ​

javascript
// Format tag for display
formatTag(tag) {
  // Format tag object
  // Return formatted tag
}

// Validate tag name
validateTagName(name) {
  // Check length
  // Check characters
  // Return validation result
}

// Generate tag color
generateTagColor(name) {
  // Generate color from tag name
  // Return hex color
}

// Sort tags
sortTags(tags, sortBy = 'name') {
  // Sort tags by specified field
  // Return sorted array
}

API Integration ​

Tag API Endpoints ​

List Tags ​

Endpoint: GET /api/workspaces/:workspace_id/tags

Response:

json
{
  "tags": [
    {
      "id": 1,
      "workspace_id": 123,
      "name": "marketing",
      "color": "#FF5722",
      "usage_count": 45,
      "created_at": "2024-01-15T10:00:00Z",
      "updated_at": "2024-01-20T14:30:00Z"
    }
  ]
}

Create Tag ​

Endpoint: POST /api/workspaces/:workspace_id/tags

Request Body:

json
{
  "name": "marketing",
  "color": "#FF5722"
}

Response:

json
{
  "tag": {
    "id": 1,
    "workspace_id": 123,
    "name": "marketing",
    "color": "#FF5722",
    "usage_count": 0,
    "created_at": "2024-01-15T10:00:00Z"
  }
}

Update Tag ​

Endpoint: PUT /api/workspaces/:workspace_id/tags/:tag_id

Request Body:

json
{
  "name": "Marketing Campaign",
  "color": "#E91E63"
}

Response:

json
{
  "tag": {
    "id": 1,
    "name": "Marketing Campaign",
    "color": "#E91E63",
    "updated_at": "2024-01-20T14:30:00Z"
  }
}

Delete Tag ​

Endpoint: DELETE /api/workspaces/:workspace_id/tags/:tag_id

Response:

json
{
  "success": true,
  "message": "Tag deleted successfully"
}

Assign Tags to Asset ​

Endpoint: POST /api/digital-assets/:asset_id/tags

Request Body:

json
{
  "tag_ids": [1, 2, 3]
}

Response:

json
{
  "success": true,
  "asset": {
    "id": 456,
    "tags": [
      { "id": 1, "name": "marketing", "color": "#FF5722" },
      { "id": 2, "name": "campaign", "color": "#2196F3" },
      { "id": 3, "name": "2024", "color": "#4CAF50" }
    ]
  }
}

Remove Tags from Asset ​

Endpoint: DELETE /api/digital-assets/:asset_id/tags

Request Body:

json
{
  "tag_ids": [1, 2]
}

Response:

json
{
  "success": true,
  "message": "Tags removed successfully"
}

Bulk Assign Tags ​

Endpoint: POST /api/digital-assets/bulk-tags

Request Body:

json
{
  "asset_ids": [456, 457, 458],
  "tag_ids": [1, 2, 3],
  "action": "add" // or "remove"
}

Response:

json
{
  "success": true,
  "updated_assets": 3,
  "message": "Tags applied to 3 assets"
}

Get Asset Tags ​

Endpoint: GET /api/digital-assets/:asset_id/tags

Response:

json
{
  "tags": [
    {
      "id": 1,
      "name": "marketing",
      "color": "#FF5722",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ]
}

Workflows ​

Create Tag ​

1. User navigates to tag management
   - Asset details page OR
   - Tag input component
   ↓
2. User enters tag name
   Component: FileTagInput.vue or TagsBox.vue
   - Type tag name
   - Optional: Select color
   ↓
3. Create tag
   - If tag doesn't exist → Create new
   - If tag exists → Use existing
   ↓
4. Call API
   API: POST /api/workspaces/:workspace_id/tags
   Body: { name, color }
   ↓
5. Tag created
   - Tag added to workspace
   - Available for use
   - Auto-selected if in input component
   ↓
6. Update UI
   - Add tag to available tags list
   - Show success message
   - Update tag input

Add Tags to Asset ​

1. User navigates to asset details
   Route: /:workspace_id/dam/assets/:asset_id
   ↓
2. Open tag management
   Component: FileTagInput.vue or TagsBox.vue
   - Click tag input/button
   - Or open Add Tags dialog
   ↓
3. Select tags
   - Search/select from available tags
   - Or create new tags
   - Multiple selection supported
   ↓
4. Apply tags
   API: POST /api/digital-assets/:asset_id/tags
   Body: { tag_ids: [1, 2, 3] }
   ↓
5. Tags assigned
   - Tags added to asset
   - Displayed in asset details
   - Available for search/filtering
   ↓
6. Update UI
   - Refresh tag display
   - Show success message
   - Close dialog (if applicable)

Bulk Tag Assignment ​

1. User selects multiple assets
   - Use multi-select in asset list
   - Or select from search results
   ↓
2. Open bulk actions
   Component: SearchBulkActions.vue
   - Click "Add Tags" or similar
   ↓
3. Open Add Multiple Tags dialog
   Component: AddMultipleTags.vue
   Props: assetIds: [456, 457, 458]
   ↓
4. Select tags
   - Choose tags to apply
   - Multiple selection supported
   ↓
5. Apply tags
   API: POST /api/digital-assets/bulk-tags
   Body: {
     asset_ids: [456, 457, 458],
     tag_ids: [1, 2, 3],
     action: "add"
   }
   ↓
6. Tags applied
   - All selected assets updated
   - Progress tracking
   - Success/error handling
   ↓
7. Update UI
   - Refresh asset lists
   - Show success message
   - Close dialog

Search with Tag Filter ​

1. Navigate to search page
   Route: /:workspace_id/dam/search
   ↓
2. Open search filters
   Component: SearchFilter.vue
   ↓
3. Select tag filter
   - Choose "Tags" filter option
   - Tag selection interface appears
   ↓
4. Select tags
   - Search/select tags
   - Multiple tags can be selected
   - Operator selection (in, not_in, all)
   ↓
5. Apply filter
   Mixin: buildTagFilter()
   - Constructs tag filter query
   - Adds to search filters
   ↓
6. Execute search
   API: Search with tag filter
   - Filter applied to search query
   - Results filtered by tags
   ↓
7. Display results
   - Assets matching tag filter
   - Filter shown in AddedFilterOption component
   - Can remove or edit filter

Remove Tags from Asset ​

1. User navigates to asset details
   Route: /:workspace_id/dam/assets/:asset_id
   ↓
2. View current tags
   Component: FileTagInput.vue or TagsBox.vue
   - Tags displayed with remove buttons
   ↓
3. Remove tag
   - Click remove button on tag
   - Or deselect in tag input
   ↓
4. Call API
   API: DELETE /api/digital-assets/:asset_id/tags
   Body: { tag_ids: [1] }
   ↓
5. Tag removed
   - Tag removed from asset
   - Updated in database
   ↓
6. Update UI
   - Remove tag from display
   - Show success message
   - Refresh asset details

Component Integration ​

Using Tags in Asset Details ​

vue
<template>
  <div>
    <!-- Tag Input -->
    <FileTagInput
      v-model="assetTags"
      :asset-id="assetId"
      :workspace-id="workspaceId"
      :creatable="true"
      @tag-added="handleTagAdded"
      @tag-removed="handleTagRemoved"
    />
    
    <!-- Or use Tags Box Dialog -->
    <v-btn @click="openTagsDialog">Manage Tags</v-btn>
    
    <TagsBox
      :dialog="tagsDialogOpen"
      :asset-ids="[assetId]"
      :current-tags="assetTags"
      :workspace-id="workspaceId"
      @close="closeTagsDialog"
      @tags-applied="handleTagsApplied"
    />
  </div>
</template>

<script>
import FileTagInput from '~/components/dam/FileTagInput.vue'
import TagsBox from '~/components/dam/Dialogs/AddTags/TagsBox.vue'

export default {
  components: {
    FileTagInput,
    TagsBox
  },
  data() {
    return {
      assetId: this.$route.params.asset_id,
      workspaceId: this.$route.params.workspace_id,
      assetTags: [],
      tagsDialogOpen: false
    }
  },
  async mounted() {
    await this.loadAssetTags()
  },
  methods: {
    async loadAssetTags() {
      const response = await this.$axios.get(
        `/api/digital-assets/${this.assetId}/tags`
      )
      this.assetTags = response.data.tags
    },
    handleTagAdded(tag) {
      // Tag added via input
      this.assetTags.push(tag)
    },
    handleTagRemoved(tagId) {
      // Tag removed via input
      this.assetTags = this.assetTags.filter(t => t.id !== tagId)
    },
    openTagsDialog() {
      this.tagsDialogOpen = true
    },
    closeTagsDialog() {
      this.tagsDialogOpen = false
    },
    handleTagsApplied(tags) {
      // Tags applied via dialog
      this.assetTags = tags
      this.closeTagsDialog()
    }
  }
}
</script>
vue
<template>
  <div>
    <SearchFilter
      :tags="availableTags"
      @tag-filter-applied="applyTagFilter"
    />
    
    <AddedFilterOption
      v-for="filter in activeTagFilters"
      :key="filter.id"
      :filter="filter"
      @remove="removeTagFilter"
    />
  </div>
</template>

<script>
import SearchFilter from '~/components/dam/Search/SearchFilter.vue'
import AddedFilterOption from '~/components/dam/Search/AddedFilterOption.vue'
import searchCommonFunctions from '~/mixins/search-common-functions'

export default {
  components: {
    SearchFilter,
    AddedFilterOption
  },
  mixins: [searchCommonFunctions],
  data() {
    return {
      availableTags: [],
      activeTagFilters: []
    }
  },
  methods: {
    applyTagFilter(tagIds, operator = 'in') {
      const filter = this.buildTagFilter(tagIds, operator)
      this.activeTagFilters.push(filter)
      this.executeSearch()
    },
    removeTagFilter(filterId) {
      this.activeTagFilters = this.activeTagFilters.filter(f => f.id !== filterId)
      this.executeSearch()
    }
  }
}
</script>

Using Bulk Tag Operations ​

vue
<template>
  <div>
    <SearchBulkActions
      v-if="selectedAssets.length > 0"
      :selected-assets="selectedAssets"
      @bulk-add-tags="handleBulkAddTags"
      @bulk-remove-tags="handleBulkRemoveTags"
    />
    
    <AddMultipleTags
      :dialog="bulkTagsDialogOpen"
      :asset-ids="selectedAssetIds"
      :workspace-id="workspaceId"
      @close="closeBulkTagsDialog"
      @tags-applied="handleBulkTagsApplied"
    />
  </div>
</template>

<script>
import SearchBulkActions from '~/components/dam/SearchBulkActions.vue'
import AddMultipleTags from '~/components/dam/Dialogs/AddTags/AddMultipleTags.vue'

export default {
  components: {
    SearchBulkActions,
    AddMultipleTags
  },
  data() {
    return {
      selectedAssets: [],
      bulkTagsDialogOpen: false,
      workspaceId: this.$route.params.workspace_id
    }
  },
  computed: {
    selectedAssetIds() {
      return this.selectedAssets.map(a => a.id)
    }
  },
  methods: {
    handleBulkAddTags() {
      this.bulkTagsDialogOpen = true
    },
    handleBulkRemoveTags() {
      // Open remove tags dialog
    },
    closeBulkTagsDialog() {
      this.bulkTagsDialogOpen = false
    },
    handleBulkTagsApplied() {
      // Refresh asset list
      this.closeBulkTagsDialog()
    }
  }
}
</script>