Appearance
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
- Tag Definitions: Workspace-level tag definitions with colors and metadata
- Tag Assignments: Tags assigned to assets (many-to-many relationship)
- Tag Management: UI for creating, editing, and managing tags
- Asset Integration: Components for adding/removing tags from assets
- Search Integration: Tag-based filtering and search capabilities
- 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
addTagmethod - Tag management functionality
- Tag display in uploaded assets list
- Tag filtering options
- Contains
Tag Search & Filtering
JavaScript Files (.js)
mixins/search-common-functions.js- Search common functions mixin- Contains
buildTagFilterfunction - Constructs tag filter queries
- Integrates with search API
- Handles multiple tag filters
- Contains
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 tagsnot_in- Assets without any of the specified tagsall- 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 inputAdd 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 dialogSearch 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 filterRemove 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 detailsComponent 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>Using Tags in Search
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>Related Documentation
- Tags and Custom Fields System - Combined tags and custom fields overview
- Custom Fields System - Custom fields documentation
- Advanced Search Filters - Search filtering including tags
- Global Search Functionality - Search system integration
- Typesense Search Integration - Search backend integration