CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-uppy--dashboard

Universal UI plugin for Uppy file uploader providing comprehensive dashboard interface with drag-and-drop, file previews, metadata editing, and progress tracking.

Pending
Overview
Eval results
Files

plugin-integration.mddocs/

Plugin Integration

Register and manage plugins that integrate with the dashboard interface.

Capabilities

Add Target

Register a plugin as a dashboard target for integration with the dashboard interface.

/**
 * Register plugin as dashboard target
 * Only acquirer, progressindicator, and editor plugins are supported
 * @param plugin - Plugin instance to register
 * @returns Dashboard element for plugin mounting or null if invalid
 */
addTarget(plugin: UnknownPlugin): HTMLElement | null;

Usage Examples:

import Dashboard from "@uppy/dashboard";
import GoogleDrive from "@uppy/google-drive";
import Webcam from "@uppy/webcam";

const dashboard = uppy.getPlugin("Dashboard") as Dashboard;

// Manual plugin registration
const googleDrive = new GoogleDrive(uppy, { /* options */ });
const dashboardElement = dashboard.addTarget(googleDrive);

// Automatic registration via plugin mounting
uppy.use(GoogleDrive, { /* options */ });
// Dashboard automatically calls addTarget for compatible plugins

// Custom plugin registration
class CustomAcquirer extends BasePlugin {
  type = 'acquirer';
  id = 'CustomAcquirer';
  title = 'Custom Source';
  
  mount(target, plugin) {
    // Plugin-specific mounting logic
    return dashboard.addTarget(this);
  }
}

uppy.use(CustomAcquirer);

Behavior:

  • Validates plugin type (must be 'acquirer', 'progressindicator', or 'editor')
  • Creates target object with plugin ID, name, and type
  • Adds target to dashboard state
  • Returns dashboard element for plugin mounting
  • Logs error and returns null for invalid plugin types

Remove Target

Unregister a plugin target from the dashboard interface.

/**
 * Unregister plugin target
 * Removes plugin from dashboard targets and cleans up state
 * @param plugin - Plugin instance to unregister
 */
removeTarget(plugin: UnknownPlugin): void;

Usage Examples:

// Remove plugin programmatically
const googleDrive = uppy.getPlugin("GoogleDrive");
if (googleDrive) {
  dashboard.removeTarget(googleDrive);
}

// Remove plugin on uninstall
uppy.removePlugin(googleDrive);
// Dashboard automatically calls removeTarget

// Conditional plugin removal
function removePluginIfUnsupported(pluginId: string) {
  const plugin = uppy.getPlugin(pluginId);
  if (plugin && !plugin.isSupported?.()) {
    dashboard.removeTarget(plugin);
    uppy.removePlugin(plugin);
  }
}

Behavior:

  • Filters out the target with matching plugin ID
  • Updates dashboard state to remove target
  • Cleans up any active panels for the removed plugin

Plugin Target Interface

Structure and requirements for plugin targets.

/**
 * Basic plugin target interface
 */
interface Target {
  /** Unique plugin identifier */
  id: string;
  /** Human-readable plugin name */
  name: string;
  /** Plugin type classification */
  type: 'acquirer' | 'progressindicator' | 'editor';
}

/**
 * Enhanced target with render capabilities
 */
interface TargetWithRender extends Target {
  /** Function to render plugin icon */
  icon: () => ComponentChild;
  /** Function to render plugin interface */
  render: () => ComponentChild;
}

Supported Plugin Types

Different types of plugins supported by the dashboard.

/**
 * Acquirer plugins - File source providers
 * Provide interfaces for selecting files from various sources
 */
interface AcquirerPlugin {
  type: 'acquirer';
  /** Plugin identifier */
  id: string;
  /** Display name */
  title?: string;
  /** Check if plugin is supported in current environment */
  isSupported?(): boolean;
  /** Render plugin interface */
  render(): ComponentChild;
  /** Optional icon for plugin */
  icon?(): ComponentChild;
  /** Handle root-level paste events */
  handleRootPaste?(event: ClipboardEvent): void;
  /** Handle root-level drop events */
  handleRootDrop?(event: DragEvent): void;
  /** Check if plugin can handle root drop */
  canHandleRootDrop?(event: DragEvent): boolean;
}

/**
 * Progress indicator plugins - Upload progress display
 * Provide custom progress visualization
 */
interface ProgressIndicatorPlugin {
  type: 'progressindicator';
  id: string;
  title?: string;
  render(): ComponentChild;
}

/**
 * Editor plugins - File editing capabilities
 * Provide file editing and manipulation interfaces
 */
interface EditorPlugin {
  type: 'editor';
  id: string;
  title?: string;
  /** Check if plugin can edit specific file */
  canEditFile(file: UppyFile): boolean;
  /** Select file for editing */
  selectFile(file: UppyFile): void;
  /** Save editor changes */
  save(): void;
  /** Render editor interface */
  render(): ComponentChild;
}

Automatic Plugin Discovery

Dashboard automatically discovers and integrates compatible plugins.

/**
 * Automatic plugin discovery system
 */
interface AutoDiscovery {
  /** Discover plugins on Uppy plugin addition */
  onPluginAdded(plugin: UnknownPlugin): void;
  /** Remove targets on plugin removal */
  onPluginRemoved(plugin: UnknownPlugin): void;
  /** Add supported plugin if no target specified */
  addSupportedPluginIfNoTarget(plugin: UnknownPlugin): void;
}

Auto-Discovery Examples:

// Plugins are automatically discovered when added to Uppy
uppy.use(GoogleDrive, { 
  companionUrl: 'https://companion.uppy.io' 
});
// Dashboard automatically integrates GoogleDrive

uppy.use(Webcam, { 
  modes: ['picture', 'video'] 
});
// Dashboard automatically integrates Webcam

// Manual control over auto-discovery
uppy.use(Dashboard, {
  plugins: ['GoogleDrive', 'Webcam'] // Only these plugins will be integrated
});

// Disable auto-discovery by providing empty plugins array
uppy.use(Dashboard, {
  plugins: [] // No automatic plugin integration
});

Plugin Configuration Options

Configure which plugins are integrated with the dashboard.

/**
 * Plugin integration configuration
 */
interface PluginIntegrationConfig {
  /** Array of plugin IDs to integrate (empty array disables auto-discovery) */
  plugins?: string[];
  /** Default icon for plugins without custom icons */
  defaultPickerIcon?: typeof defaultPickerIcon;
}

Configuration Examples:

// Specific plugin integration
uppy.use(Dashboard, {
  plugins: ['GoogleDrive', 'Dropbox', 'Instagram'],
  defaultPickerIcon: CustomIcon
});

// All compatible plugins (default behavior)
uppy.use(Dashboard, {
  plugins: [] // Will auto-discover all compatible plugins
});

// No plugin integration
uppy.use(Dashboard, {
  plugins: [], // Empty array disables auto-discovery
  // Must manually call addTarget for any integrations
});

Plugin State Management

State management for integrated plugins and their targets.

/**
 * Plugin state properties
 */
interface PluginState {
  /** Array of registered plugin targets */
  targets: Target[];
  /** Currently active picker panel */
  activePickerPanel: Target | undefined;
}

/**
 * Plugin categorization helpers
 */
interface PluginCategories {
  /** Get acquirer plugins (file sources) */
  getAcquirers(targets: Target[]): TargetWithRender[];
  /** Get progress indicator plugins */
  getProgressIndicators(targets: Target[]): TargetWithRender[];
  /** Get editor plugins */
  getEditors(targets: Target[]): TargetWithRender[];
}

Plugin Support Detection

Detect and handle plugin compatibility and support.

/**
 * Plugin support detection
 */
interface PluginSupport {
  /** Check if plugin is supported in current environment */
  isTargetSupported(target: Target): boolean;
  /** Attach render functions to supported targets */
  attachRenderFunctionToTarget(target: Target): TargetWithRender;
}

Support Detection Examples:

// Plugin with support detection
class WebRTCPlugin extends BasePlugin {
  type = 'acquirer';
  
  isSupported(): boolean {
    return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
  }
}

// Conditional plugin loading
async function loadCompatiblePlugins() {
  const plugins = [
    { Plugin: GoogleDrive, supported: () => true },
    { Plugin: Webcam, supported: () => !!navigator.mediaDevices },
    { Plugin: ScreenCapture, supported: () => !!navigator.mediaDevices.getDisplayMedia }
  ];

  for (const { Plugin, supported } of plugins) {
    if (supported()) {
      uppy.use(Plugin);
    }
  }
}

// Runtime support checking
function checkPluginSupport() {
  const dashboard = uppy.getPlugin('Dashboard');
  const state = dashboard.getPluginState();
  
  state.targets.forEach(target => {
    const plugin = uppy.getPlugin(target.id);
    if (plugin.isSupported && !plugin.isSupported()) {
      console.warn(`Plugin ${target.id} is not supported in this environment`);
      dashboard.removeTarget(plugin);
    }
  });
}

Plugin Events and Communication

Event system for plugin communication and lifecycle management.

/**
 * Plugin lifecycle events
 */
interface PluginLifecycleEvents {
  /** Plugin added to Uppy */
  'plugin-added': (plugin: UnknownPlugin) => void;
  /** Plugin removed from Uppy */
  'plugin-remove': (plugin: UnknownPlugin) => void;
}

Event Examples:

// Listen for plugin lifecycle
uppy.on('plugin-added', (plugin) => {
  console.log(`Plugin added: ${plugin.id}`);
  if (plugin.type === 'acquirer') {
    setupAcquirerIntegration(plugin);
  }
});

uppy.on('plugin-remove', (plugin) => {
  console.log(`Plugin removed: ${plugin.id}`);
  cleanupPluginIntegration(plugin);
});

// Plugin communication
function setupPluginCommunication() {
  const dashboard = uppy.getPlugin('Dashboard');
  const googleDrive = uppy.getPlugin('GoogleDrive');
  
  if (googleDrive) {
    googleDrive.on('folder-selected', (folder) => {
      dashboard.showPanel('GoogleDrive');
    });
    
    googleDrive.on('files-selected', (files) => {
      dashboard.hideAllPanels();
    });
  }
}

Custom Plugin Development

Guidelines for developing plugins compatible with dashboard integration.

/**
 * Custom plugin development interface
 */
interface CustomPluginRequirements {
  /** Unique plugin identifier */
  id: string;
  /** Plugin type for dashboard integration */
  type: 'acquirer' | 'progressindicator' | 'editor';
  /** Human-readable title */
  title?: string;
  /** Render function for plugin interface */
  render(): ComponentChild;
  /** Optional icon function */
  icon?(): ComponentChild;
  /** Optional support detection */
  isSupported?(): boolean;
  /** Mount function for dashboard integration */
  mount?(target: any, plugin: any): HTMLElement | null;
}

Custom Plugin Examples:

// Custom file source plugin
class CustomCloudStorage extends BasePlugin {
  static VERSION = '1.0.0';
  
  type = 'acquirer';
  id = 'CustomCloudStorage';
  title = 'My Cloud Storage';

  constructor(uppy, opts) {
    super(uppy, opts);
    this.id = this.opts.id || 'CustomCloudStorage';
  }

  isSupported() {
    return typeof window !== 'undefined' && window.fetch;
  }

  mount(target, plugin) {
    const dashboard = target;
    return dashboard.addTarget(this);
  }

  render() {
    return h('div', { className: 'custom-cloud-storage' }, [
      h('h3', null, 'Select from My Cloud Storage'),
      h('button', { 
        onclick: this.openFilePicker.bind(this) 
      }, 'Browse Files')
    ]);
  }

  icon() {
    return h('svg', { /* icon properties */ }, [
      // SVG paths for custom icon
    ]);
  }

  async openFilePicker() {
    const files = await this.fetchFilesFromAPI();
    files.forEach(file => this.uppy.addFile(file));
  }
}

// Usage
uppy.use(CustomCloudStorage, {
  apiKey: 'your-api-key',
  serverUrl: 'https://api.example.com'
});

Plugin Integration Best Practices

Recommended patterns for plugin integration and development.

/**
 * Integration best practices
 */
interface IntegrationBestPractices {
  /** Provide meaningful plugin IDs and titles */
  naming: 'Use descriptive, unique identifiers';
  /** Implement proper support detection */
  supportDetection: 'Check environment capabilities';
  /** Handle errors gracefully */
  errorHandling: 'Provide user-friendly error messages';
  /** Clean up resources properly */
  cleanup: 'Remove event listeners and clean state';
  /** Follow accessibility guidelines */
  accessibility: 'Support keyboard navigation and screen readers';
  /** Provide consistent user experience */
  ux: 'Match dashboard styling and interaction patterns';
}

Best Practice Examples:

class WellDesignedPlugin extends BasePlugin {
  constructor(uppy, opts) {
    super(uppy, opts);
    this.id = this.opts.id || 'WellDesignedPlugin';
    this.title = this.opts.title || 'Well Designed Plugin';
    
    // Validate required options
    if (!this.opts.apiKey) {
      throw new Error('WellDesignedPlugin: apiKey is required');
    }
  }

  isSupported() {
    return !!(window.fetch && window.FileReader);
  }

  mount(target, plugin) {
    this.target = target;
    return target.addTarget(this);
  }

  unmount() {
    if (this.target) {
      this.target.removeTarget(this);
    }
    this.cleanup();
  }

  cleanup() {
    // Clean up event listeners, timers, etc.
    if (this.pollInterval) {
      clearInterval(this.pollInterval);
    }
  }

  render() {
    return h('div', {
      className: 'uppy-Plugin-panel',
      'aria-label': `${this.title} file picker`
    }, [
      this.renderContent()
    ]);
  }

  handleError(error) {
    this.uppy.log(`[${this.id}] ${error.message}`, 'error');
    this.uppy.info(`${this.title}: ${error.message}`, 'error');
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-uppy--dashboard

docs

configuration.md

file-editor.md

file-management.md

index.md

modal-management.md

panel-management.md

plugin-integration.md

tile.json