通知 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 示例 了解完整的实现示例。