or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cli.mdcomposables.mdextensions.mdindex.mdutilities.md
tile.json

utilities.mddocs/

Utility Functions

Helper functions for working with Directus data structures, templates, and relationships. These utilities are re-exported from the @directus/utils package.

Capabilities

Template Field Extraction

Extract field names from Directus template strings, commonly used in display templates and computed fields.

/**
 * Extract field names from a Directus template string
 * @param template - Template string containing field references in {{ field }} format
 * @returns Array of field names found in the template
 */
function getFieldsFromTemplate(template?: string | null): string[];

Usage Examples:

import { getFieldsFromTemplate } from '@directus/extensions-sdk';

// Extract fields from display template
const template = "{{first_name}} {{last_name}} ({{email}})";
const fields = getFieldsFromTemplate(template);
// Result: ['first_name', 'last_name', 'email']

// Handle complex templates with nested objects
const complexTemplate = "{{user.name}} - {{status}} - {{created_on}}";
const complexFields = getFieldsFromTemplate(complexTemplate);
// Result: ['user.name', 'status', 'created_on']

// Handle empty or null templates
const emptyFields = getFieldsFromTemplate(null);
// Result: []

// Use in display extension
export default defineDisplay({
  id: 'my-template-display',
  name: 'Template Display',
  component: TemplateComponent,
  options: [
    {
      field: 'template',
      name: 'Template',
      type: 'string',
      meta: {
        interface: 'input',
        note: 'Use {{field_name}} syntax for dynamic values'
      }
    }
  ],
  types: ['alias'],
  setup(props) {
    // Automatically determine which fields are needed
    const requiredFields = computed(() => 
      getFieldsFromTemplate(props.template)
    );
    
    return { requiredFields };
  }
});

Relationship Type Detection

Determine the type of relationship between collections based on field configuration.

/**
 * Determine the relationship type between collections based on field configuration
 * @param options - Object containing relation, collection, and field information
 * @param options.relation - The relation configuration object
 * @param options.collection - The current collection name or null
 * @param options.field - The field name in the current collection
 * @returns String indicating the relationship type ('m2o', 'o2m', 'm2a') or null if not relational
 */
function getRelationType(options: {
  relation: Relation;
  collection: string | null;
  field: string;
}): 'm2o' | 'o2m' | 'm2a' | null;

interface Relation {
  /** The collection containing the relation field */
  collection: string;
  /** The field name that holds the relation */
  field: string;
  /** The related collection, null for Many-to-Any relations */
  related_collection: string | null;
  /** Additional metadata for the relation */
  meta?: {
    /** Field name on the "one" side of the relation */
    one_field?: string;
    /** Field that stores collection name in Many-to-Any relations */
    one_collection_field?: string;
    /** Allowed collections for Many-to-Any relations */
    one_allowed_collections?: string[];
    /** Additional relation metadata */
    [key: string]: any;
  } | null;
}

Usage Examples:

import { getRelationType } from '@directus/extensions-sdk';

// Use in interface or layout extensions
export default defineInterface({
  id: 'my-relational-interface',
  name: 'Relational Interface',
  component: RelationalComponent,
  types: ['integer'],
  relational: true,
  setup(props) {
    // Get relation information from props or context
    const relationType = computed(() => 
      getRelationType({
        relation: props.relation,
        collection: props.collection,
        field: props.field
      })
    );
    
    // Adapt interface behavior based on relationship type
    const isOneToMany = computed(() => relationType.value === 'o2m');
    const isManyToOne = computed(() => relationType.value === 'm2o');
    const isManyToAny = computed(() => relationType.value === 'm2a');
    
    return {
      relationType,
      isOneToMany,
      isManyToOne,
      isManyToAny
    };
  }
});

// Use in layout extensions for relationship-aware displays
export default defineLayout({
  id: 'relationship-layout',
  name: 'Relationship Layout',
  component: RelationshipLayoutComponent,
  setup(props) {
    const relationType = computed(() =>
      getRelationType({
        relation: props.relation,
        collection: props.collection,
        field: props.field
      })
    );
    
    // Configure layout based on relationship type
    const layoutConfig = computed(() => {
      switch (relationType.value) {
        case 'o2m':
          return { showCreate: true, showEdit: true, showDelete: true };
        case 'm2o':
          return { showCreate: false, showEdit: true, showDelete: false };
        case 'm2a':
          return { showCreate: true, showEdit: false, showDelete: true };
        default:
          return { showCreate: false, showEdit: false, showDelete: false };
      }
    });
    
    return { relationType, layoutConfig };
  }
});

Common Usage Patterns

These utilities are frequently used together in extension development:

import { 
  getFieldsFromTemplate, 
  getRelationType,
  useCollection,
  useItems 
} from '@directus/extensions-sdk';

export default defineDisplay({
  id: 'smart-relationship-display',
  name: 'Smart Relationship Display',
  component: SmartRelationshipComponent,
  types: ['integer', 'string'],
  relational: true,
  options: [
    {
      field: 'display_template',
      name: 'Display Template',
      type: 'string',
      meta: {
        interface: 'input',
        note: 'Template for displaying related items: {{field_name}}'
      }
    }
  ],
  setup(props) {
    const collection = useCollection();
    const items = useItems();
    
    // Determine relationship characteristics
    const relationType = computed(() =>
      getRelationType({
        relation: props.relation,
        collection: props.collection,
        field: props.field
      })
    );
    const isRelational = computed(() => 
      relationType.value !== null && ['m2o', 'o2m', 'm2a'].includes(relationType.value)
    );
    
    // Extract required fields from template
    const templateFields = computed(() => 
      getFieldsFromTemplate(props.display_template)
    );
    
    // Fetch related items with only required fields
    const fetchRelatedItems = async () => {
      if (!isRelational.value || !templateFields.value.length) {
        return [];
      }
      
      return await items.fetchItems({
        collection: collection.related,
        fields: templateFields.value,
        // ... other parameters
      });
    };
    
    return {
      relationType,
      isRelational,
      templateFields,
      fetchRelatedItems
    };
  }
});

Integration with Directus Core

These utilities integrate seamlessly with Directus core functionality:

  • Template Processing: Used throughout Directus admin for dynamic field display
  • Relationship Management: Core to Directus's relational data model
  • Field Dependency: Ensures only necessary data is fetched and processed
  • Type Safety: Provides compile-time checking for field references
  • Performance: Optimizes queries by understanding field requirements

The utilities are particularly valuable when building extensions that need to:

  • Parse user-defined templates for dynamic content
  • Understand relationship structures for appropriate UI behavior
  • Optimize data fetching based on actual field usage
  • Provide intelligent defaults based on field and relationship types