Skip to content

通知 API

概述

Trae 通知 API 提供了一套完整的用户通知系统,支持信息提示、警告、错误消息、进度通知等多种类型。开发者可以通过 API 创建、管理和自定义各种通知,提升用户体验。

核心概念

通知类型

typescript
enum NotificationType {
  Info = 'info',
  Warning = 'warning',
  Error = 'error',
  Success = 'success'
}

interface NotificationOptions {
  type?: NotificationType;
  title?: string;
  message: string;
  detail?: string;
  modal?: boolean;
  timeout?: number;
  actions?: NotificationAction[];
  onDidClose?: () => void;
  onDidShow?: () => void;
}

interface NotificationAction {
  label: string;
  action: () => void | Promise<void>;
  primary?: boolean;
  destructive?: boolean;
}

通知级别

typescript
enum NotificationLevel {
  Silent = 0,
  Error = 1,
  Warning = 2,
  Info = 3,
  Debug = 4
}

interface NotificationSettings {
  level: NotificationLevel;
  showInStatusBar: boolean;
  showInNotificationCenter: boolean;
  playSound: boolean;
  duration: number;
}

API 参考

基础通知

显示信息通知

typescript
import { window } from '@trae/api';

// 显示简单信息通知
const showInfo = (message: string): Thenable<string | undefined> => {
  return window.showInformationMessage(message);
};

// 显示带操作的信息通知
const showInfoWithActions = (
  message: string,
  ...actions: string[]
): Thenable<string | undefined> => {
  return window.showInformationMessage(message, ...actions);
};

// 显示带选项的信息通知
const showInfoWithOptions = (
  message: string,
  options: MessageOptions,
  ...actions: string[]
): Thenable<string | undefined> => {
  return window.showInformationMessage(message, options, ...actions);
};

interface MessageOptions {
  modal?: boolean;
  detail?: string;
}

// 使用示例
const handleSaveSuccess = async (): Promise<void> => {
  const action = await showInfoWithActions(
    '文件保存成功',
    '查看文件',
    '继续编辑'
  );
  
  switch (action) {
    case '查看文件':
      // 打开文件资源管理器
      break;
    case '继续编辑':
      // 继续编辑操作
      break;
  }
};

显示警告通知

typescript
// 显示警告通知
const showWarning = (message: string): Thenable<string | undefined> => {
  return window.showWarningMessage(message);
};

// 显示带操作的警告通知
const showWarningWithActions = (
  message: string,
  ...actions: string[]
): Thenable<string | undefined> => {
  return window.showWarningMessage(message, ...actions);
};

// 使用示例
const handleUnsavedChanges = async (): Promise<boolean> => {
  const action = await showWarningWithActions(
    '文件有未保存的更改',
    '保存',
    '不保存',
    '取消'
  );
  
  switch (action) {
    case '保存':
      await saveFile();
      return true;
    case '不保存':
      return true;
    case '取消':
    default:
      return false;
  }
};

显示错误通知

typescript
// 显示错误通知
const showError = (message: string): Thenable<string | undefined> => {
  return window.showErrorMessage(message);
};

// 显示带操作的错误通知
const showErrorWithActions = (
  message: string,
  ...actions: string[]
): Thenable<string | undefined> => {
  return window.showErrorMessage(message, ...actions);
};

// 使用示例
const handleCompilationError = async (error: Error): Promise<void> => {
  const action = await showErrorWithActions(
    `编译失败: ${error.message}`,
    '查看详情',
    '重试',
    '忽略'
  );
  
  switch (action) {
    case '查看详情':
      showErrorDetails(error);
      break;
    case '重试':
      await retryCompilation();
      break;
    case '忽略':
      // 忽略错误
      break;
  }
};

进度通知

进度指示器

typescript
// 显示进度通知
const withProgress = <T>(
  options: ProgressOptions,
  task: (progress: Progress<ProgressUpdate>, token: CancellationToken) => Thenable<T>
): Thenable<T> => {
  return window.withProgress(options, task);
};

interface ProgressOptions {
  location: ProgressLocation;
  title?: string;
  cancellable?: boolean;
}

enum ProgressLocation {
  SourceControl = 1,
  Window = 10,
  Notification = 15
}

interface Progress<T> {
  report(value: T): void;
}

interface ProgressUpdate {
  message?: string;
  increment?: number;
}

// 使用示例
const performLongRunningTask = async (): Promise<void> => {
  await withProgress(
    {
      location: ProgressLocation.Notification,
      title: '正在处理文件',
      cancellable: true
    },
    async (progress, token) => {
      const files = await getFilesToProcess();
      const totalFiles = files.length;
      
      for (let i = 0; i < totalFiles; i++) {
        if (token.isCancellationRequested) {
          throw new Error('操作已取消');
        }
        
        const file = files[i];
        progress.report({
          message: `正在处理 ${file.name}`,
          increment: (100 / totalFiles)
        });
        
        await processFile(file);
      }
      
      progress.report({ message: '处理完成' });
    }
  );
};

状态栏进度

typescript
// 在状态栏显示进度
const showStatusBarProgress = async (
  title: string,
  task: () => Promise<void>
): Promise<void> => {
  await withProgress(
    {
      location: ProgressLocation.Window,
      title
    },
    async (progress) => {
      await task();
    }
  );
};

// 使用示例
const saveAllFiles = async (): Promise<void> => {
  await showStatusBarProgress('保存所有文件', async () => {
    const openDocuments = workspace.textDocuments;
    
    for (const document of openDocuments) {
      if (document.isDirty) {
        await document.save();
      }
    }
  });
};

自定义通知

通知管理器

typescript
class NotificationManager {
  private notifications: Map<string, NotificationItem> = new Map();
  private settings: NotificationSettings;
  
  constructor(settings: NotificationSettings) {
    this.settings = settings;
  }
  
  // 显示通知
  show(
    id: string,
    options: NotificationOptions
  ): NotificationItem {
    // 检查通知级别
    if (!this.shouldShowNotification(options.type)) {
      return new SilentNotificationItem(id, options);
    }
    
    // 创建通知项
    const notification = new NotificationItem(id, options);
    this.notifications.set(id, notification);
    
    // 显示通知
    this.displayNotification(notification);
    
    // 设置自动关闭
    if (options.timeout && options.timeout > 0) {
      setTimeout(() => {
        this.hide(id);
      }, options.timeout);
    }
    
    return notification;
  }
  
  // 隐藏通知
  hide(id: string): void {
    const notification = this.notifications.get(id);
    if (notification) {
      notification.hide();
      this.notifications.delete(id);
    }
  }
  
  // 清除所有通知
  clear(): void {
    for (const [id] of this.notifications) {
      this.hide(id);
    }
  }
  
  // 更新通知
  update(id: string, options: Partial<NotificationOptions>): void {
    const notification = this.notifications.get(id);
    if (notification) {
      notification.update(options);
    }
  }
  
  // 获取所有通知
  getAll(): NotificationItem[] {
    return Array.from(this.notifications.values());
  }
  
  // 获取特定类型的通知
  getByType(type: NotificationType): NotificationItem[] {
    return this.getAll().filter(n => n.options.type === type);
  }
  
  private shouldShowNotification(type?: NotificationType): boolean {
    const typeLevel = this.getNotificationLevel(type);
    return typeLevel <= this.settings.level;
  }
  
  private getNotificationLevel(type?: NotificationType): NotificationLevel {
    switch (type) {
      case NotificationType.Error:
        return NotificationLevel.Error;
      case NotificationType.Warning:
        return NotificationLevel.Warning;
      case NotificationType.Info:
      case NotificationType.Success:
        return NotificationLevel.Info;
      default:
        return NotificationLevel.Debug;
    }
  }
  
  private displayNotification(notification: NotificationItem): void {
    const { options } = notification;
    
    if (options.modal) {
      this.showModalNotification(notification);
    } else {
      this.showToastNotification(notification);
    }
    
    // 播放声音
    if (this.settings.playSound) {
      this.playNotificationSound(options.type);
    }
    
    // 触发显示事件
    if (options.onDidShow) {
      options.onDidShow();
    }
  }
  
  private showModalNotification(notification: NotificationItem): void {
    const { options } = notification;
    const actions = options.actions?.map(a => a.label) || [];
    
    let promise: Thenable<string | undefined>;
    
    switch (options.type) {
      case NotificationType.Error:
        promise = window.showErrorMessage(
          options.message,
          { modal: true, detail: options.detail },
          ...actions
        );
        break;
      case NotificationType.Warning:
        promise = window.showWarningMessage(
          options.message,
          { modal: true, detail: options.detail },
          ...actions
        );
        break;
      default:
        promise = window.showInformationMessage(
          options.message,
          { modal: true, detail: options.detail },
          ...actions
        );
        break;
    }
    
    promise.then(selectedAction => {
      if (selectedAction && options.actions) {
        const action = options.actions.find(a => a.label === selectedAction);
        if (action) {
          action.action();
        }
      }
    });
  }
  
  private showToastNotification(notification: NotificationItem): void {
    // 实现非模态通知显示逻辑
    // 这里可以使用自定义的 UI 组件
  }
  
  private playNotificationSound(type?: NotificationType): void {
    // 实现通知声音播放逻辑
    switch (type) {
      case NotificationType.Error:
        // 播放错误声音
        break;
      case NotificationType.Warning:
        // 播放警告声音
        break;
      case NotificationType.Success:
        // 播放成功声音
        break;
      default:
        // 播放默认声音
        break;
    }
  }
}

class NotificationItem {
  constructor(
    public readonly id: string,
    public options: NotificationOptions
  ) {}
  
  update(newOptions: Partial<NotificationOptions>): void {
    this.options = { ...this.options, ...newOptions };
  }
  
  hide(): void {
    if (this.options.onDidClose) {
      this.options.onDidClose();
    }
  }
}

class SilentNotificationItem extends NotificationItem {
  constructor(id: string, options: NotificationOptions) {
    super(id, options);
  }
  
  update(): void {
    // 静默通知不更新 UI
  }
  
  hide(): void {
    // 静默通知不需要隐藏 UI
    if (this.options.onDidClose) {
      this.options.onDidClose();
    }
  }
}

通知使用示例

typescript
// 创建通知管理器
const notificationManager = new NotificationManager({
  level: NotificationLevel.Info,
  showInStatusBar: true,
  showInNotificationCenter: true,
  playSound: true,
  duration: 5000
});

// 显示成功通知
const showSuccessNotification = (message: string): void => {
  notificationManager.show('success-' + Date.now(), {
    type: NotificationType.Success,
    title: '操作成功',
    message,
    timeout: 3000
  });
};

// 显示错误通知
const showErrorNotification = (error: Error): void => {
  notificationManager.show('error-' + Date.now(), {
    type: NotificationType.Error,
    title: '操作失败',
    message: error.message,
    detail: error.stack,
    modal: true,
    actions: [
      {
        label: '重试',
        action: () => {
          // 重试操作
        },
        primary: true
      },
      {
        label: '报告问题',
        action: () => {
          // 打开问题报告
        }
      }
    ]
  });
};

// 显示带进度的通知
const showProgressNotification = async (
  title: string,
  task: (updateProgress: (progress: number, message?: string) => void) => Promise<void>
): Promise<void> => {
  const notificationId = 'progress-' + Date.now();
  
  // 显示初始通知
  notificationManager.show(notificationId, {
    type: NotificationType.Info,
    title,
    message: '正在处理...',
    timeout: 0 // 不自动关闭
  });
  
  try {
    await task((progress: number, message?: string) => {
      notificationManager.update(notificationId, {
        message: message || `进度: ${Math.round(progress)}%`
      });
    });
    
    // 更新为成功状态
    notificationManager.update(notificationId, {
      type: NotificationType.Success,
      message: '处理完成',
      timeout: 2000
    });
  } catch (error) {
    // 更新为错误状态
    notificationManager.update(notificationId, {
      type: NotificationType.Error,
      message: `处理失败: ${error.message}`,
      timeout: 5000
    });
  }
};

通知中心

通知历史

typescript
class NotificationCenter {
  private history: NotificationHistoryItem[] = [];
  private maxHistorySize = 100;
  
  // 添加到历史记录
  addToHistory(notification: NotificationItem): void {
    const historyItem: NotificationHistoryItem = {
      id: notification.id,
      options: notification.options,
      timestamp: new Date(),
      read: false
    };
    
    this.history.unshift(historyItem);
    
    // 限制历史记录大小
    if (this.history.length > this.maxHistorySize) {
      this.history = this.history.slice(0, this.maxHistorySize);
    }
  }
  
  // 获取历史记录
  getHistory(filter?: NotificationHistoryFilter): NotificationHistoryItem[] {
    let filtered = this.history;
    
    if (filter) {
      if (filter.type) {
        filtered = filtered.filter(item => item.options.type === filter.type);
      }
      
      if (filter.unreadOnly) {
        filtered = filtered.filter(item => !item.read);
      }
      
      if (filter.since) {
        filtered = filtered.filter(item => item.timestamp >= filter.since!);
      }
    }
    
    return filtered;
  }
  
  // 标记为已读
  markAsRead(id: string): void {
    const item = this.history.find(h => h.id === id);
    if (item) {
      item.read = true;
    }
  }
  
  // 标记所有为已读
  markAllAsRead(): void {
    this.history.forEach(item => {
      item.read = true;
    });
  }
  
  // 清除历史记录
  clearHistory(filter?: NotificationHistoryFilter): void {
    if (!filter) {
      this.history = [];
      return;
    }
    
    this.history = this.history.filter(item => {
      if (filter.type && item.options.type === filter.type) {
        return false;
      }
      
      if (filter.readOnly && item.read) {
        return false;
      }
      
      if (filter.before && item.timestamp < filter.before) {
        return false;
      }
      
      return true;
    });
  }
  
  // 获取未读数量
  getUnreadCount(): number {
    return this.history.filter(item => !item.read).length;
  }
}

interface NotificationHistoryItem {
  id: string;
  options: NotificationOptions;
  timestamp: Date;
  read: boolean;
}

interface NotificationHistoryFilter {
  type?: NotificationType;
  unreadOnly?: boolean;
  readOnly?: boolean;
  since?: Date;
  before?: Date;
}

通知模板

预定义模板

typescript
class NotificationTemplates {
  // 文件操作模板
  static fileOperation = {
    saved: (fileName: string) => ({
      type: NotificationType.Success,
      message: `文件 "${fileName}" 已保存`,
      timeout: 2000
    }),
    
    deleted: (fileName: string) => ({
      type: NotificationType.Info,
      message: `文件 "${fileName}" 已删除`,
      timeout: 3000
    }),
    
    error: (fileName: string, error: string) => ({
      type: NotificationType.Error,
      title: '文件操作失败',
      message: `无法处理文件 "${fileName}": ${error}`,
      modal: true
    })
  };
  
  // 编译模板
  static compilation = {
    started: () => ({
      type: NotificationType.Info,
      message: '开始编译...',
      timeout: 0
    }),
    
    success: (duration: number) => ({
      type: NotificationType.Success,
      message: `编译成功 (${duration}ms)`,
      timeout: 3000
    }),
    
    failed: (errors: number, warnings: number) => ({
      type: NotificationType.Error,
      title: '编译失败',
      message: `${errors} 个错误, ${warnings} 个警告`,
      actions: [
        {
          label: '查看问题',
          action: () => {
            // 打开问题面板
          },
          primary: true
        }
      ]
    })
  };
  
  // 网络操作模板
  static network = {
    connecting: (url: string) => ({
      type: NotificationType.Info,
      message: `正在连接到 ${url}...`,
      timeout: 0
    }),
    
    connected: (url: string) => ({
      type: NotificationType.Success,
      message: `已连接到 ${url}`,
      timeout: 2000
    }),
    
    disconnected: (url: string) => ({
      type: NotificationType.Warning,
      message: `与 ${url} 的连接已断开`,
      timeout: 5000
    }),
    
    error: (url: string, error: string) => ({
      type: NotificationType.Error,
      title: '网络错误',
      message: `无法连接到 ${url}: ${error}`,
      actions: [
        {
          label: '重试',
          action: () => {
            // 重试连接
          },
          primary: true
        },
        {
          label: '检查设置',
          action: () => {
            // 打开网络设置
          }
        }
      ]
    })
  };
  
  // 扩展模板
  static extension = {
    installed: (name: string) => ({
      type: NotificationType.Success,
      message: `扩展 "${name}" 安装成功`,
      actions: [
        {
          label: '重新加载',
          action: () => {
            // 重新加载窗口
          },
          primary: true
        }
      ]
    }),
    
    updated: (name: string, version: string) => ({
      type: NotificationType.Info,
      message: `扩展 "${name}" 已更新到版本 ${version}`,
      timeout: 3000
    }),
    
    error: (name: string, error: string) => ({
      type: NotificationType.Error,
      title: '扩展错误',
      message: `扩展 "${name}" 出现错误: ${error}`,
      modal: true
    })
  };
}

// 使用模板
const useNotificationTemplates = () => {
  const notificationManager = new NotificationManager({
    level: NotificationLevel.Info,
    showInStatusBar: true,
    showInNotificationCenter: true,
    playSound: true,
    duration: 5000
  });
  
  // 文件保存成功
  const notifyFileSaved = (fileName: string) => {
    notificationManager.show(
      'file-saved-' + Date.now(),
      NotificationTemplates.fileOperation.saved(fileName)
    );
  };
  
  // 编译开始
  const notifyCompilationStarted = () => {
    notificationManager.show(
      'compilation-started',
      NotificationTemplates.compilation.started()
    );
  };
  
  // 编译成功
  const notifyCompilationSuccess = (duration: number) => {
    notificationManager.hide('compilation-started');
    notificationManager.show(
      'compilation-success',
      NotificationTemplates.compilation.success(duration)
    );
  };
  
  return {
    notifyFileSaved,
    notifyCompilationStarted,
    notifyCompilationSuccess
  };
};

最佳实践

通知设计原则

typescript
// 1. 合适的通知级别
const chooseNotificationLevel = (situation: string): NotificationType => {
  switch (situation) {
    case 'user-action-success':
      return NotificationType.Success;
    case 'user-attention-needed':
      return NotificationType.Warning;
    case 'operation-failed':
      return NotificationType.Error;
    case 'general-information':
    default:
      return NotificationType.Info;
  }
};

// 2. 适当的通知时长
const getNotificationTimeout = (type: NotificationType): number => {
  switch (type) {
    case NotificationType.Success:
      return 2000; // 成功消息短暂显示
    case NotificationType.Info:
      return 4000; // 信息消息中等时长
    case NotificationType.Warning:
      return 6000; // 警告消息较长时间
    case NotificationType.Error:
      return 0; // 错误消息需要用户主动关闭
    default:
      return 3000;
  }
};

// 3. 避免通知泛滥
class NotificationThrottler {
  private recentNotifications: Map<string, number> = new Map();
  private throttleWindow = 5000; // 5秒内相同通知只显示一次
  
  shouldShow(key: string): boolean {
    const now = Date.now();
    const lastShown = this.recentNotifications.get(key);
    
    if (!lastShown || now - lastShown > this.throttleWindow) {
      this.recentNotifications.set(key, now);
      return true;
    }
    
    return false;
  }
  
  clear(): void {
    this.recentNotifications.clear();
  }
}

// 4. 智能通知分组
class NotificationGrouper {
  private groups: Map<string, NotificationGroup> = new Map();
  
  addToGroup(groupKey: string, notification: NotificationOptions): void {
    let group = this.groups.get(groupKey);
    
    if (!group) {
      group = new NotificationGroup(groupKey);
      this.groups.set(groupKey, group);
    }
    
    group.add(notification);
    
    // 如果组内通知过多,显示汇总通知
    if (group.size() > 3) {
      this.showGroupSummary(group);
    }
  }
  
  private showGroupSummary(group: NotificationGroup): void {
    const count = group.size();
    const type = group.getMostSevereType();
    
    window.showInformationMessage(
      `${count} 个${this.getTypeDisplayName(type)}通知`,
      '查看详情'
    ).then(action => {
      if (action === '查看详情') {
        // 打开通知中心
      }
    });
    
    group.clear();
  }
  
  private getTypeDisplayName(type: NotificationType): string {
    switch (type) {
      case NotificationType.Error: return '错误';
      case NotificationType.Warning: return '警告';
      case NotificationType.Success: return '成功';
      default: return '信息';
    }
  }
}

class NotificationGroup {
  private notifications: NotificationOptions[] = [];
  
  constructor(private key: string) {}
  
  add(notification: NotificationOptions): void {
    this.notifications.push(notification);
  }
  
  size(): number {
    return this.notifications.length;
  }
  
  getMostSevereType(): NotificationType {
    const severityOrder = [
      NotificationType.Error,
      NotificationType.Warning,
      NotificationType.Info,
      NotificationType.Success
    ];
    
    for (const type of severityOrder) {
      if (this.notifications.some(n => n.type === type)) {
        return type;
      }
    }
    
    return NotificationType.Info;
  }
  
  clear(): void {
    this.notifications = [];
  }
}

错误处理

typescript
// 通知错误处理
class NotificationErrorHandler {
  static handleNotificationError(error: Error, context: string): void {
    console.error(`Notification error in ${context}:`, error);
    
    // 降级到简单通知
    try {
      window.showErrorMessage(
        `通知系统错误: ${error.message}`,
        '报告问题'
      ).then(action => {
        if (action === '报告问题') {
          // 打开错误报告
        }
      });
    } catch (fallbackError) {
      // 如果连简单通知都失败,记录到控制台
      console.error('Fallback notification also failed:', fallbackError);
    }
  }
  
  static wrapNotificationCall<T>(
    operation: () => T,
    context: string
  ): T | undefined {
    try {
      return operation();
    } catch (error) {
      this.handleNotificationError(error as Error, context);
      return undefined;
    }
  }
}

// 使用错误处理包装器
const safeShowNotification = (
  message: string,
  type: NotificationType = NotificationType.Info
): void => {
  NotificationErrorHandler.wrapNotificationCall(() => {
    switch (type) {
      case NotificationType.Error:
        return window.showErrorMessage(message);
      case NotificationType.Warning:
        return window.showWarningMessage(message);
      default:
        return window.showInformationMessage(message);
    }
  }, 'safeShowNotification');
};

相关 API

示例项目

查看 通知 API 示例 了解完整的实现示例。

您的终极 AI 驱动 IDE 学习指南