diff --git a/dashboard/src/i18n/locales/en-US/features/command.json b/dashboard/src/i18n/locales/en-US/features/command.json index f2346096e..b20044e3c 100644 --- a/dashboard/src/i18n/locales/en-US/features/command.json +++ b/dashboard/src/i18n/locales/en-US/features/command.json @@ -5,6 +5,11 @@ "disabled": "Disabled", "conflicts": "Conflicts" }, + "conflictAlert": { + "title": "Command Conflicts Detected", + "description": "There are {count} conflicting commands. Conflicting commands will trigger multiple plugins simultaneously, which may cause unexpected behavior.", + "hint": "Click the \"Rename\" button to rename conflicting commands and resolve conflicts." + }, "table": { "headers": { "command": "Command", diff --git a/dashboard/src/i18n/locales/zh-CN/features/command.json b/dashboard/src/i18n/locales/zh-CN/features/command.json index 278038029..da7fc259f 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/command.json +++ b/dashboard/src/i18n/locales/zh-CN/features/command.json @@ -5,6 +5,11 @@ "disabled": "已禁用", "conflicts": "有冲突" }, + "conflictAlert": { + "title": "检测到指令冲突", + "description": "当前有 {count} 对指令存在冲突,冲突的指令会同时触发多个插件响应,可能导致意外行为。", + "hint": "请点击「重命名」按钮修改冲突指令的名称以解决冲突。" + }, "table": { "headers": { "command": "指令", diff --git a/dashboard/src/views/CommandPage.vue b/dashboard/src/views/CommandPage.vue index 9244b8095..12c82949d 100644 --- a/dashboard/src/views/CommandPage.vue +++ b/dashboard/src/views/CommandPage.vue @@ -111,7 +111,28 @@ const filteredCommands = computed(() => { } } - return result; + // Sort: conflict commands first, grouped by effective_command + const conflictCmds: CommandItem[] = []; + const normalCmds: CommandItem[] = []; + + const conflictGroupMap: Map = new Map(); + for (const cmd of result) { + if (cmd.has_conflict) { + const key = cmd.effective_command || ''; + if (!conflictGroupMap.has(key)) { + conflictGroupMap.set(key, []); + } + conflictGroupMap.get(key)!.push(cmd); + } else { + normalCmds.push(cmd); + } + } + + for (const [_, group] of conflictGroupMap) { + conflictCmds.push(...group); + } + + return [...conflictCmds, ...normalCmds]; }); // Toast helper @@ -226,6 +247,14 @@ const getStatusInfo = (cmd: CommandItem) => { return { text: tm('status.disabled'), color: 'error', variant: 'outlined' as const }; }; +// Get row props for conflict highlighting +const getRowProps = ({ item }: { item: CommandItem }) => { + if (item.has_conflict) { + return { class: 'conflict-row' }; + } + return {}; +}; + onMounted(async () => { await fetchCommands(); }); @@ -323,6 +352,30 @@ onMounted(async () => { + + + + + {{ tm('conflictAlert.title') }} + +
+ {{ tm('conflictAlert.description', { count: summary.conflicts }) }} +
+
+ mdi-lightbulb-outline + {{ tm('conflictAlert.hint') }} +
+
+ { :loading="loading" item-key="handler_full_name" hover + :row-props="getRowProps" >