@lesliechan721/aw 0.1.0-beta.30 → 0.1.0-beta.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +5 -2
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +1 -1
- package/dist/src/commands/aw-capabilities.js +2 -0
- package/dist/src/commands/aw-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-operations.js +1 -0
- package/dist/src/commands/rebuild-operations.js.map +1 -1
- package/dist/src/tui/catalog-sources/session.d.ts +5 -1
- package/dist/src/tui/catalog-sources/session.js +6 -1
- package/dist/src/tui/catalog-sources/session.js.map +1 -1
- package/dist/src/tui/catalog-sources/types.d.ts +1 -0
- package/dist/src/tui/components.d.ts +1 -11
- package/dist/src/tui/components.js +9 -41
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/config-value-presentation.d.ts +19 -0
- package/dist/src/tui/config-value-presentation.js +77 -0
- package/dist/src/tui/config-value-presentation.js.map +1 -0
- package/dist/src/tui/console-app-v4.d.ts +1 -1
- package/dist/src/tui/console-app-v4.js +885 -1121
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller.d.ts +8 -0
- package/dist/src/tui/controller.js +85 -18
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/diagnostics.d.ts +2 -1
- package/dist/src/tui/diagnostics.js +8 -1
- package/dist/src/tui/diagnostics.js.map +1 -1
- package/dist/src/tui/input-display.d.ts +1 -0
- package/dist/src/tui/input-display.js +13 -0
- package/dist/src/tui/input-display.js.map +1 -1
- package/dist/src/tui/model.d.ts +3 -2
- package/dist/src/tui/model.js +17 -33
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-diagnostic-screens.d.ts +5 -3
- package/dist/src/tui/operation-diagnostic-screens.js +26 -9
- package/dist/src/tui/operation-diagnostic-screens.js.map +1 -1
- package/dist/src/tui/operation-history.js +5 -4
- package/dist/src/tui/operation-history.js.map +1 -1
- package/dist/src/tui/router.d.ts +4 -6
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/screen-registry.d.ts +10 -19
- package/dist/src/tui/screen-registry.js +3 -4
- package/dist/src/tui/screen-registry.js.map +1 -1
- package/dist/src/tui/viewport.d.ts +1 -0
- package/dist/src/tui/viewport.js +23 -0
- package/dist/src/tui/viewport.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { presentConfigValue, safeConfigText } from './config-value-presentation.js';
|
|
2
3
|
import { Box, Text, useInput, useWindowSize } from 'ink';
|
|
3
4
|
import { useEffect, useRef, useState } from 'react';
|
|
4
5
|
import path from 'node:path';
|
|
@@ -11,7 +12,7 @@ import { normalizePortableAgents, SKILLS_CLI_SUPPORTED_VERSION_LABEL, } from '..
|
|
|
11
12
|
import { selectLifecycleRetryAction, } from '../commands/operation-planner.js';
|
|
12
13
|
import { parseScriptTimeoutMs, SCRIPT_TIMEOUT_DEFAULT_MS, SCRIPT_TIMEOUT_MAX_MS, SCRIPT_TIMEOUT_MIN_MS, } from '../commands/options.js';
|
|
13
14
|
import { projectCatalogSourceLocation } from '../utils/catalog-source-presentation.js';
|
|
14
|
-
import { ActionRow, ObjectCardRow, objectCardRowLayout, StatusBadge, diagnosticDetailLines, Callout, ChoiceRow, ContentViewport,
|
|
15
|
+
import { ActionRow, ObjectCardRow, objectCardRowLayout, StatusBadge, diagnosticDetailLines, Callout, ChoiceRow, ContentViewport, DiagnosticSummary, InputCard, PluginListRow, ProgressRow, ResultCard, ResultRow, ReviewCard, ReviewChangeRow, ScreenFrame, SectionCard, SectionRow, StaticRow, StatusCard, TaskRow, TechnicalDetails, ToggleRow, } from './components.js';
|
|
15
16
|
import { safeDiagnosticCode, sanitizeDiagnosticText, } from './diagnostics.js';
|
|
16
17
|
import { extractPortableError, TuiConfigInvalidStoreError, userIssueKey, } from './controller.js';
|
|
17
18
|
import { pluginWriteTaskVersionEvidence } from './plugin-write-task.js';
|
|
@@ -22,10 +23,10 @@ import { buildDependencyGraphProjection, buildUnifiedDependencyGraphProjection,
|
|
|
22
23
|
import { platformLabel, scopeLabel } from './glossary.js';
|
|
23
24
|
import { InputDisplay, removeLastGrapheme } from './input-display.js';
|
|
24
25
|
import { catalogRefPolicyForPreset } from './source-ref-presets.js';
|
|
25
|
-
import { buildPlatformActions,
|
|
26
|
+
import { buildPlatformActions, configObjectHasSensitiveChild, hasInstalledPlacement, configValuesEqual, } from './model.js';
|
|
26
27
|
import { resolveTuiGlobalKeyAction, resolveTuiSessionNavigationKey } from './keys.js';
|
|
27
28
|
import { tuiTheme } from './theme.js';
|
|
28
|
-
import { contentRowBudget, rowViewport } from './viewport.js';
|
|
29
|
+
import { contentRowBudget, rowViewport, wrapDisplayText } from './viewport.js';
|
|
29
30
|
import { resolveRouteScreenId, routeDefinition, TUI_SCREEN_IDS, unreachableTuiRoute, } from './screen-registry.js';
|
|
30
31
|
export const CONSOLE_V4_SCREEN_IDS = TUI_SCREEN_IDS;
|
|
31
32
|
const PLUGIN_FILTERS = [
|
|
@@ -175,17 +176,17 @@ function helpRowsForRoute(route, actionCount, supportsTechnicalDetails, busy, se
|
|
|
175
176
|
if (route.name === 'pluginList') {
|
|
176
177
|
rows.push(['←/→ · [ / ]', '切换来源']);
|
|
177
178
|
rows.push(['/', '进入搜索']);
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
rows.push(['f', '切换插件状态']);
|
|
180
|
+
rows.push(['m', '原位选择多个插件']);
|
|
180
181
|
}
|
|
181
182
|
if (route.name === 'portableSkillSelect') {
|
|
182
183
|
rows.push(['Space', '切换当前 Skill']);
|
|
183
|
-
rows.push(['a', '
|
|
184
|
+
rows.push(['a', '定位下方操作 / 回到原项']);
|
|
184
185
|
}
|
|
185
186
|
if (route.name === 'batchSelection') {
|
|
186
187
|
rows.push(['Space', '切换当前插件']);
|
|
187
|
-
rows.push(['a', '
|
|
188
|
-
rows.push(['c', '
|
|
188
|
+
rows.push(['a', '定位下方操作 / 回到原项']);
|
|
189
|
+
rows.push(['c', '继续选择任务或查看汇总']);
|
|
189
190
|
}
|
|
190
191
|
if (route.name === 'configFields' && route.layer.scope !== 'effective') {
|
|
191
192
|
rows.push(['s', '查看保存汇总']);
|
|
@@ -390,7 +391,7 @@ function moveFocus(actions, current, direction) {
|
|
|
390
391
|
return 0;
|
|
391
392
|
for (let offset = 1; offset <= actions.length; offset += 1) {
|
|
392
393
|
const next = (current + direction * offset + actions.length) % actions.length;
|
|
393
|
-
if (!actions[next]?.disabled)
|
|
394
|
+
if (!actions[next]?.disabled && actions[next]?.role !== 'navigation')
|
|
394
395
|
return next;
|
|
395
396
|
}
|
|
396
397
|
return current;
|
|
@@ -431,6 +432,31 @@ function wrapConsoleText(value, columns) {
|
|
|
431
432
|
lines.push(line);
|
|
432
433
|
return lines;
|
|
433
434
|
}
|
|
435
|
+
function sourceRefSummary(value) {
|
|
436
|
+
if (!value)
|
|
437
|
+
return '未知';
|
|
438
|
+
if (/^[0-9a-f]{40}(?:[0-9a-f]{24})?$/iu.test(value))
|
|
439
|
+
return value.slice(0, 8);
|
|
440
|
+
return value.replace(/^refs\/(?:heads|tags)\//u, '');
|
|
441
|
+
}
|
|
442
|
+
function relativeCheckTime(value, now = Date.now()) {
|
|
443
|
+
if (!value)
|
|
444
|
+
return '尚未检查';
|
|
445
|
+
const checkedAt = Date.parse(value);
|
|
446
|
+
if (!Number.isFinite(checkedAt))
|
|
447
|
+
return '时间未知';
|
|
448
|
+
const elapsed = Math.max(0, now - checkedAt);
|
|
449
|
+
if (elapsed < 60_000)
|
|
450
|
+
return '刚刚';
|
|
451
|
+
if (elapsed < 3_600_000)
|
|
452
|
+
return `${Math.floor(elapsed / 60_000)} 分钟前`;
|
|
453
|
+
if (elapsed < 86_400_000)
|
|
454
|
+
return `${Math.floor(elapsed / 3_600_000)} 小时前`;
|
|
455
|
+
return `${Math.floor(elapsed / 86_400_000)} 天前`;
|
|
456
|
+
}
|
|
457
|
+
function parseConfigNumberInput(input) {
|
|
458
|
+
return input.trim().length === 0 ? undefined : Number(input);
|
|
459
|
+
}
|
|
434
460
|
function changeDetailLines(changes, columns) {
|
|
435
461
|
const valueLines = (label, value) => [
|
|
436
462
|
label,
|
|
@@ -440,6 +466,7 @@ function changeDetailLines(changes, columns) {
|
|
|
440
466
|
`修改项 · ${change.title}`,
|
|
441
467
|
...valueLines('修改前', change.before),
|
|
442
468
|
...valueLines('修改后', change.after),
|
|
469
|
+
...(change.children ?? []).flatMap((child) => [child.property, ...valueLines('修改前', child.before), ...valueLines('修改后', child.after)]),
|
|
443
470
|
]);
|
|
444
471
|
}
|
|
445
472
|
function operationRiskWarnings(review) {
|
|
@@ -464,29 +491,12 @@ function operationRiskLines(review, columns) {
|
|
|
464
491
|
}
|
|
465
492
|
function actionViewport(actions, compact, focus, requestedOffset, lineBudget) {
|
|
466
493
|
return rowViewport({
|
|
467
|
-
rowHeights: actions.map((action) => compact || (!action.description && !action.disabled) ? 1 : 2),
|
|
468
|
-
focus,
|
|
469
|
-
requestedOffset,
|
|
470
|
-
rowBudget: lineBudget,
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
function objectCardActionViewport(actions, width, compact, focus, requestedOffset, lineBudget) {
|
|
474
|
-
return rowViewport({
|
|
475
|
-
rowHeights: actions.map((action) => objectCardRowLayout({
|
|
476
|
-
width,
|
|
477
|
-
description: action.disabled ?? action.description ?? '',
|
|
478
|
-
meta: action.meta,
|
|
479
|
-
hasTags: action.tags !== undefined,
|
|
480
|
-
compact,
|
|
481
|
-
}).height),
|
|
494
|
+
rowHeights: actions.map((action) => action.role === 'navigation' ? 0 : compact || (!action.description && !action.disabled) ? 1 : 2),
|
|
482
495
|
focus,
|
|
483
496
|
requestedOffset,
|
|
484
497
|
rowBudget: lineBudget,
|
|
485
498
|
});
|
|
486
499
|
}
|
|
487
|
-
function portableSkillCandidateViewport(actions, width, compact, focus, requestedOffset, rowBudget) {
|
|
488
|
-
return objectCardActionViewport(actions, width, compact, focus, requestedOffset, rowBudget);
|
|
489
|
-
}
|
|
490
500
|
function prefixRowLimit(rowHeights, rowBudget) {
|
|
491
501
|
let used = 0;
|
|
492
502
|
let visible = 0;
|
|
@@ -662,17 +672,40 @@ function configUnavailableDiagnostic(route) {
|
|
|
662
672
|
}
|
|
663
673
|
function sourceDiagnostic(sourceId, state, detail, generation, freshness) {
|
|
664
674
|
const unavailable = state === 'unavailable' || state === 'error';
|
|
675
|
+
if (generation?.errorCode === 'catalogLogicalIdentityChanged') {
|
|
676
|
+
return {
|
|
677
|
+
severity: 'error',
|
|
678
|
+
title: '来源发布身份已变化',
|
|
679
|
+
userMessage: '待检查内容与当前来源不是同一发布身份。当前状态不能据此判定为健康。',
|
|
680
|
+
impact: [
|
|
681
|
+
{ state: 'blocked', message: '不能把待检查内容作为当前来源的更新。' },
|
|
682
|
+
{ state: 'degraded', message: '旧 Active 是否仍可用需要单独验证。' },
|
|
683
|
+
],
|
|
684
|
+
nextStep: '检查来源地址和发布身份,然后编辑来源,或移除后重新添加。',
|
|
685
|
+
technical: {
|
|
686
|
+
code: 'catalogLogicalIdentityChanged',
|
|
687
|
+
stage: 'compare-source-identity',
|
|
688
|
+
sourceId,
|
|
689
|
+
checks: ['核对来源地址、ref 和 logical identity。', '确认后编辑来源,或移除后重新添加。'],
|
|
690
|
+
},
|
|
691
|
+
};
|
|
692
|
+
}
|
|
665
693
|
if (generation?.compatibility?.state === 'unsupported') {
|
|
666
694
|
const { requiredCapabilities, missingCapabilities } = generation.compatibility;
|
|
695
|
+
const missingKnown = missingCapabilities.length > 0;
|
|
667
696
|
return {
|
|
668
697
|
severity: 'error',
|
|
669
698
|
title: '当前目录版本不兼容',
|
|
670
|
-
userMessage:
|
|
699
|
+
userMessage: missingKnown
|
|
700
|
+
? `当前 AW 缺少 ${missingCapabilities.length} 项所需功能支持。`
|
|
701
|
+
: '当前目录版本所需功能无法确认。',
|
|
671
702
|
impact: [
|
|
672
703
|
{ state: 'blocked', message: '这个目录版本不能用于浏览、安装或同步。' },
|
|
673
704
|
{ state: 'preserved', message: '当前启用版本和已下载内容保持不变。' },
|
|
674
705
|
],
|
|
675
|
-
nextStep:
|
|
706
|
+
nextStep: missingKnown
|
|
707
|
+
? '升级 AW 到支持所需能力的版本,或修改来源后重新启用。'
|
|
708
|
+
: '检查来源内容和 capability 诊断,再决定修复来源或更新 AW。',
|
|
676
709
|
technical: {
|
|
677
710
|
code: 'awCapabilityUnsupported',
|
|
678
711
|
stage: 'resolve-source',
|
|
@@ -681,7 +714,9 @@ function sourceDiagnostic(sourceId, state, detail, generation, freshness) {
|
|
|
681
714
|
key: 'compatibility',
|
|
682
715
|
value: `required: ${requiredCapabilities.join('、')}; missing: ${missingCapabilities.join('、')}`,
|
|
683
716
|
}],
|
|
684
|
-
checks:
|
|
717
|
+
checks: missingKnown
|
|
718
|
+
? ['检查所需和缺少的 Catalog capability。', '升级 AW 后重新加载来源。']
|
|
719
|
+
: ['检查来源的 capability 声明和验证错误。', '确认原因后重新加载来源。'],
|
|
685
720
|
},
|
|
686
721
|
};
|
|
687
722
|
}
|
|
@@ -704,18 +739,24 @@ function sourceDiagnostic(sourceId, state, detail, generation, freshness) {
|
|
|
704
739
|
};
|
|
705
740
|
}
|
|
706
741
|
if (freshness?.state === 'incompatible') {
|
|
707
|
-
const
|
|
742
|
+
const activeHealthy = generation?.state === 'ready' && generation.active !== undefined;
|
|
743
|
+
const missingCount = freshness.missingCapabilities?.length ?? 0;
|
|
744
|
+
const missingSummary = missingCount && missingCount > 0
|
|
745
|
+
? `缺少 ${missingCount} 项待检查版本所需功能`
|
|
746
|
+
: '待检查版本所需功能无法确认';
|
|
708
747
|
return {
|
|
709
748
|
severity: 'error',
|
|
710
749
|
title: '待检查版本不兼容',
|
|
711
|
-
userMessage:
|
|
712
|
-
? `当前 AW
|
|
713
|
-
: `当前 AW
|
|
750
|
+
userMessage: activeHealthy
|
|
751
|
+
? `当前 AW ${missingSummary}。普通更新已阻止;已验证的当前目录版本保持不变。`
|
|
752
|
+
: `当前 AW ${missingSummary}。这个来源没有已验证可用的目录版本。`,
|
|
714
753
|
impact: [
|
|
715
754
|
{ state: 'blocked', message: '不能直接切换到这个待检查版本。' },
|
|
716
|
-
...(
|
|
755
|
+
...(activeHealthy ? [{ state: 'preserved', message: '已验证的当前目录版本和插件浏览仍可用。' }] : []),
|
|
717
756
|
],
|
|
718
|
-
nextStep:
|
|
757
|
+
nextStep: missingCount > 0
|
|
758
|
+
? '升级 AW 到支持待检查版本所需功能的版本,或编辑来源后重新验证。'
|
|
759
|
+
: '检查来源的 capability 声明和安全诊断,再决定修正来源或升级 AW。',
|
|
719
760
|
technical: {
|
|
720
761
|
code: safeDiagnosticCode(freshness.errorCode, 'catalogincompatible'),
|
|
721
762
|
stage: 'compare-candidate',
|
|
@@ -723,7 +764,9 @@ function sourceDiagnostic(sourceId, state, detail, generation, freshness) {
|
|
|
723
764
|
...(freshness.missingCapabilities?.length ? {
|
|
724
765
|
context: [{ key: 'compatibility', value: freshness.missingCapabilities.join('、') }],
|
|
725
766
|
} : {}),
|
|
726
|
-
checks:
|
|
767
|
+
checks: missingCount > 0
|
|
768
|
+
? ['检查缺少的 Catalog capability。', '升级 AW 后执行完整验证。']
|
|
769
|
+
: ['检查来源的 capability 声明。', '查看安全错误代码后重新验证。'],
|
|
727
770
|
},
|
|
728
771
|
};
|
|
729
772
|
}
|
|
@@ -813,6 +856,8 @@ function SemanticRows(props) {
|
|
|
813
856
|
? props.actions.slice(offset)
|
|
814
857
|
: props.actions.slice(offset, offset + props.limit);
|
|
815
858
|
return (_jsx(Box, { flexDirection: "column", children: actions.map((action, visibleIndex) => {
|
|
859
|
+
if (action.role === 'navigation')
|
|
860
|
+
return null;
|
|
816
861
|
const index = visibleIndex + offset;
|
|
817
862
|
const rowProps = {
|
|
818
863
|
title: action.label,
|
|
@@ -838,6 +883,32 @@ function SemanticRows(props) {
|
|
|
838
883
|
return _jsx(TaskRow, { ...rowProps }, `${action.label}:${index}`);
|
|
839
884
|
}) }));
|
|
840
885
|
}
|
|
886
|
+
function SequenceRows(props) {
|
|
887
|
+
const configLines = (action) => [
|
|
888
|
+
...wrapConsoleText(`${action.label}${action.meta ? ` · ${action.meta}` : ''}`, Math.max(1, props.columns - 2)),
|
|
889
|
+
...(action.description ? wrapConsoleText(action.description, Math.max(1, props.columns - 2)) : []),
|
|
890
|
+
];
|
|
891
|
+
const viewport = rowViewport({
|
|
892
|
+
rowHeights: props.actions.map((action, index) => action.role === 'navigation' ? 0 : index < props.itemCount
|
|
893
|
+
? props.wrapValues ? configLines(action).length : props.cards ? objectCardRowLayout({
|
|
894
|
+
width: props.columns, description: action.disabled ?? action.description ?? '',
|
|
895
|
+
meta: action.meta, hasTags: action.tags !== undefined, compact: props.compact,
|
|
896
|
+
}).height : action.description ? 2 : 1
|
|
897
|
+
: 1),
|
|
898
|
+
focus: props.focus, requestedOffset: props.scrollOffset, rowBudget: props.rowBudget,
|
|
899
|
+
});
|
|
900
|
+
return _jsx(ContentViewport, { children: props.actions.slice(viewport.offset, viewport.offset + viewport.limit).map((action, visibleIndex) => {
|
|
901
|
+
if (action.role === 'navigation')
|
|
902
|
+
return null;
|
|
903
|
+
const index = viewport.offset + visibleIndex;
|
|
904
|
+
const focused = !props.inactive && index === props.focus;
|
|
905
|
+
if (index < props.itemCount && props.wrapValues)
|
|
906
|
+
return _jsx(Box, { flexDirection: "column", children: configLines(action).map((line, lineIndex) => _jsxs(Text, { bold: focused && lineIndex === 0, color: action.status === 'error' ? 'red' : undefined, children: [lineIndex === 0 ? focused ? '› ' : ' ' : ' ', line] }, lineIndex)) }, action.configKey ?? action.label);
|
|
907
|
+
return index < props.itemCount && props.cards
|
|
908
|
+
? _jsx(ObjectCardRow, { width: props.columns, title: `${action.selected === undefined ? '' : action.selected ? '[x] ' : '[ ] '}${action.label}`, description: action.disabled ?? action.description ?? '', meta: action.meta, tags: action.tags, focused: focused, compact: props.compact }, action.actionId ?? action.pluginId ?? action.label)
|
|
909
|
+
: _jsx(SemanticRows, { actions: [action], focus: focused ? 0 : -1, kind: index < props.itemCount ? 'section' : 'action', compact: index >= props.itemCount }, action.actionId ?? action.label);
|
|
910
|
+
}) });
|
|
911
|
+
}
|
|
841
912
|
function PluginRows(props) {
|
|
842
913
|
return (_jsx(Box, { flexDirection: "column", children: props.rows.slice(props.viewport.offset, props.viewport.offset + props.viewport.limit)
|
|
843
914
|
.map((row, visibleIndex) => row.menuAction ? (_jsx(TaskRow, { title: row.name, description: row.description, meta: row.statusLabel, status: row.status, focused: props.active && props.viewport.offset + visibleIndex === props.focus, compact: true }, row.pluginId)) : (_jsx(PluginListRow, { name: row.name, sourceLabel: row.sourceLabel, description: row.description, attention: row.attention, placementSummary: row.placementSummary, tags: row.tags, statusLabel: row.statusLabel, status: row.status, focused: props.active && props.viewport.offset + visibleIndex === props.focus, anchored: !props.active && props.viewport.offset + visibleIndex === props.focus }, row.pluginId))) }));
|
|
@@ -870,7 +941,8 @@ function SourceTabs(props) {
|
|
|
870
941
|
}).join('')}`;
|
|
871
942
|
if (props.compact || terminalTextWidth(fullText) > props.columns) {
|
|
872
943
|
const tab = tabs[index];
|
|
873
|
-
|
|
944
|
+
const neighbour = tabs[(index + 1) % tabs.length];
|
|
945
|
+
return _jsxs(Text, { wrap: "truncate-end", children: ["\u6765\u6E90 ", _jsxs(Text, { color: tuiTheme.colors.accent, children: ["[", tab.label, "]"] }), " \u2190\u2192 \u5207\u6362 ", tabs.length > 1 ? neighbour?.label : ''] });
|
|
874
946
|
}
|
|
875
947
|
return (_jsxs(Text, { wrap: "truncate-end", children: ["\u6765\u6E90 ", tabs.map((tab) => {
|
|
876
948
|
const active = tab.id === props.current;
|
|
@@ -987,9 +1059,6 @@ function dependencyReferenceUsageLabel(reference, consumerName) {
|
|
|
987
1059
|
: reference.consumer.project === 'current' ? '当前项目' : '其他项目';
|
|
988
1060
|
return `${consumerName} · ${location} · ${platformLabel(reference.consumer.platform)}`;
|
|
989
1061
|
}
|
|
990
|
-
function dependencySummaryText(summary) {
|
|
991
|
-
return `${summary.directCount} 个直接 · ${summary.totalCount} 个总计`;
|
|
992
|
-
}
|
|
993
1062
|
function dependencyGraphRowStatus(row) {
|
|
994
1063
|
if (row.nodeState === 'ready')
|
|
995
1064
|
return { value: '正常', status: 'success' };
|
|
@@ -1064,14 +1133,13 @@ export function ConsoleAppV4(props) {
|
|
|
1064
1133
|
const [overlayFocus, setOverlayFocus] = useState(0);
|
|
1065
1134
|
const [operationConfirmation, setOperationConfirmation] = useState();
|
|
1066
1135
|
const [sourceTransportOverlay, setSourceTransportOverlay] = useState();
|
|
1067
|
-
const [pluginListChooser, setPluginListChooser] = useState();
|
|
1068
1136
|
const [projectReminderOpen, setProjectReminderOpen] = useState(false);
|
|
1069
1137
|
const [discardForExit, setDiscardForExit] = useState(false);
|
|
1070
1138
|
const [discardForSessionNavigation, setDiscardForSessionNavigation] = useState();
|
|
1071
1139
|
const [discardDraftConfirmation, setDiscardDraftConfirmation] = useState();
|
|
1072
1140
|
const [focus, setFocus] = useState(0);
|
|
1073
|
-
const
|
|
1074
|
-
const [
|
|
1141
|
+
const actionJumpAnchor = useRef(undefined);
|
|
1142
|
+
const [searchCursor, setSearchCursor] = useState(0);
|
|
1075
1143
|
const [scrollOffset, setScrollOffset] = useState(0);
|
|
1076
1144
|
const [searchFocus, setSearchFocus] = useState(false);
|
|
1077
1145
|
const [query, setQuery] = useState(snapshot.router.current.context.query ?? '');
|
|
@@ -1098,8 +1166,6 @@ export function ConsoleAppV4(props) {
|
|
|
1098
1166
|
const [inputValue, setInputValue] = useState('');
|
|
1099
1167
|
const [inputError, setInputError] = useState();
|
|
1100
1168
|
const [configActionError, setConfigActionError] = useState();
|
|
1101
|
-
const [configGroupChooserOpen, setConfigGroupChooserOpen] = useState(false);
|
|
1102
|
-
const [configGroupChoiceFocus, setConfigGroupChoiceFocus] = useState(0);
|
|
1103
1169
|
const [actionError, setActionError] = useState();
|
|
1104
1170
|
const [configResetAvailability, setConfigResetAvailability] = useState({});
|
|
1105
1171
|
const [sourceDraft, setSourceDraft] = useState();
|
|
@@ -1134,6 +1200,7 @@ export function ConsoleAppV4(props) {
|
|
|
1134
1200
|
const [draftOwner, setDraftOwner] = useState();
|
|
1135
1201
|
const dynamicMenuFocus = useRef(undefined);
|
|
1136
1202
|
const pluginListFocusId = useRef(undefined);
|
|
1203
|
+
const listFocusAnchor = useRef(undefined);
|
|
1137
1204
|
const dependencyGraphContexts = useRef(new Map());
|
|
1138
1205
|
const selectedDependencyReferenceIndex = useRef(0);
|
|
1139
1206
|
const externalDraftRevision = useRef({ config: 0, source: 0, batch: 0 });
|
|
@@ -1159,10 +1226,6 @@ export function ConsoleAppV4(props) {
|
|
|
1159
1226
|
...(configDrafts.user?.updates ?? {}),
|
|
1160
1227
|
...(configDrafts.project?.updates ?? {}),
|
|
1161
1228
|
};
|
|
1162
|
-
const draftRemoves = [...new Set([
|
|
1163
|
-
...(configDrafts.user?.removes ?? []),
|
|
1164
|
-
...(configDrafts.project?.removes ?? []),
|
|
1165
|
-
])];
|
|
1166
1229
|
const definition = routeDefinition(route);
|
|
1167
1230
|
const rendererFamily = definition.rendererFamily;
|
|
1168
1231
|
const routeKey = JSON.stringify(route);
|
|
@@ -1378,10 +1441,6 @@ export function ConsoleAppV4(props) {
|
|
|
1378
1441
|
setInputValue('');
|
|
1379
1442
|
}
|
|
1380
1443
|
}, [route.name]);
|
|
1381
|
-
useEffect(() => {
|
|
1382
|
-
if (route.name !== 'configFields')
|
|
1383
|
-
setConfigGroupChooserOpen(false);
|
|
1384
|
-
}, [route.name]);
|
|
1385
1444
|
const configRoute = route.name === 'configFields'
|
|
1386
1445
|
|| route.name === 'configFieldEditor'
|
|
1387
1446
|
|| route.name === 'configObjectPropertyEditor'
|
|
@@ -1607,42 +1666,6 @@ export function ConsoleAppV4(props) {
|
|
|
1607
1666
|
return;
|
|
1608
1667
|
props.controller.updatePageContext({ configGroupId: tabs[0].id });
|
|
1609
1668
|
}, [props.controller, route.name, currentConfigPage, snapshot.router.current.context.configGroupId]);
|
|
1610
|
-
useEffect(() => {
|
|
1611
|
-
let count;
|
|
1612
|
-
if (route.name === 'sourceList')
|
|
1613
|
-
count = props.controller.listSources().length;
|
|
1614
|
-
else if (route.name === 'issueList') {
|
|
1615
|
-
const issueCount = props.controller.listUserIssues().length;
|
|
1616
|
-
count = issueCount || 2;
|
|
1617
|
-
}
|
|
1618
|
-
else if (route.name === 'operationHistory') {
|
|
1619
|
-
count = snapshot.operationHistorySummaries.length + 1;
|
|
1620
|
-
}
|
|
1621
|
-
else if (route.name === 'pluginList') {
|
|
1622
|
-
const items = props.controller.listPlugins({
|
|
1623
|
-
mode: route.mode,
|
|
1624
|
-
...(route.sourceId ? { sourceId: route.sourceId } : {}),
|
|
1625
|
-
...(query ? { query } : {}),
|
|
1626
|
-
installFilter,
|
|
1627
|
-
});
|
|
1628
|
-
const sourceUnavailable = route.sourceId !== undefined
|
|
1629
|
-
&& props.controller.getSourceOverview(route.sourceId).health?.state === 'unavailable';
|
|
1630
|
-
count = pluginListRowIds(route.mode, items, query, sourceUnavailable).length || 1;
|
|
1631
|
-
}
|
|
1632
|
-
if (count === undefined)
|
|
1633
|
-
return;
|
|
1634
|
-
setFocus((value) => Math.min(value, Math.max(0, count - 1)));
|
|
1635
|
-
setScrollOffset((value) => Math.min(value, Math.max(0, count - 1)));
|
|
1636
|
-
}, [
|
|
1637
|
-
policy.mode,
|
|
1638
|
-
props.controller,
|
|
1639
|
-
query,
|
|
1640
|
-
installFilter,
|
|
1641
|
-
route.name,
|
|
1642
|
-
route.name === 'pluginList' ? route.mode : '',
|
|
1643
|
-
route.name === 'pluginList' ? route.sourceId : '',
|
|
1644
|
-
snapshot.viewModel,
|
|
1645
|
-
]);
|
|
1646
1669
|
useEffect(() => {
|
|
1647
1670
|
if (route.name !== 'pluginWriteTask' || route.goal !== 'update')
|
|
1648
1671
|
return;
|
|
@@ -1800,6 +1823,11 @@ export function ConsoleAppV4(props) {
|
|
|
1800
1823
|
layer: configRoute.layer,
|
|
1801
1824
|
}, snapshot.router.current.context);
|
|
1802
1825
|
}, [props.controller, configRoute, currentConfigPage, activeField, snapshot.router.current.context]);
|
|
1826
|
+
useEffect(() => {
|
|
1827
|
+
if (route.name === 'configFieldAction' && activeField) {
|
|
1828
|
+
props.controller.replace({ ...route, name: 'configFieldEditor', editor: activeField.type });
|
|
1829
|
+
}
|
|
1830
|
+
}, [props.controller, route, activeField]);
|
|
1803
1831
|
const activeObjectKey = activeField?.type === 'object' && configRoute
|
|
1804
1832
|
? `${configOwnerKey(configRoute)}\0${activeField.key}`
|
|
1805
1833
|
: undefined;
|
|
@@ -1944,7 +1972,8 @@ export function ConsoleAppV4(props) {
|
|
|
1944
1972
|
let referenceDetailPagination;
|
|
1945
1973
|
let confirmationPagination;
|
|
1946
1974
|
let pluginRows = [];
|
|
1947
|
-
let
|
|
1975
|
+
let bottomActions = [];
|
|
1976
|
+
let listQueryActions = [];
|
|
1948
1977
|
let selectAllPortableCandidates;
|
|
1949
1978
|
let togglePluginListFilter;
|
|
1950
1979
|
let movePluginListSource;
|
|
@@ -1971,9 +2000,11 @@ export function ConsoleAppV4(props) {
|
|
|
1971
2000
|
: focus;
|
|
1972
2001
|
const pageActionBudget = (staticRows = 0) => contentRowBudget({
|
|
1973
2002
|
terminalRows: size.rows,
|
|
1974
|
-
description: Boolean(description),
|
|
2003
|
+
description: Boolean(actionError ?? description),
|
|
1975
2004
|
compact: policy.mode === 'compact',
|
|
1976
|
-
staticRows
|
|
2005
|
+
staticRows: staticRows
|
|
2006
|
+
+ Math.max(0, wrapConsoleText(actionError ?? description ?? '', size.columns - 2).length - 1)
|
|
2007
|
+
+ Math.max(0, wrapConsoleText(title, size.columns - 2).length - 1),
|
|
1977
2008
|
});
|
|
1978
2009
|
const dependencyPlacementStaticRows = policy.mode === 'compact' ? 3 : 10;
|
|
1979
2010
|
const actionViewportStaticRows = route.name === 'dependencyPlacement'
|
|
@@ -1988,12 +2019,41 @@ export function ConsoleAppV4(props) {
|
|
|
1988
2019
|
const base = policy.mode === 'compact' ? compactRows : standardRows;
|
|
1989
2020
|
return base + Math.max(0, size.rows - baseline);
|
|
1990
2021
|
};
|
|
2022
|
+
const operationDetailPageRows = 2;
|
|
1991
2023
|
const sourceTechnicalPageRows = Math.max(1, contentRowBudget({
|
|
1992
2024
|
terminalRows: size.rows, description: false, compact: policy.mode === 'compact', staticRows: 6,
|
|
1993
2025
|
}));
|
|
1994
2026
|
const resolveSourceTechnicalDiagnostic = (sourceId) => {
|
|
1995
2027
|
const overview = props.controller.getSourceOverview(sourceId);
|
|
1996
|
-
|
|
2028
|
+
const freshness = props.controller.getCatalogFreshness(sourceId);
|
|
2029
|
+
const diagnostic = sourceDiagnostic(sourceId, overview.health?.state ?? overview.source?.state, overview.detail, props.controller.getCatalogGeneration(sourceId), freshness);
|
|
2030
|
+
const evidenceContext = [
|
|
2031
|
+
{ key: 'sourcePolicy', value: overview.detail?.type === 'path'
|
|
2032
|
+
? 'path' : overview.detail?.refPolicy === 'explicit' ? 'explicit' : 'cliChannel' },
|
|
2033
|
+
...(freshness?.checkedAt
|
|
2034
|
+
? [{ key: 'freshness', value: freshness.checkedAt }]
|
|
2035
|
+
: []),
|
|
2036
|
+
...(freshness?.candidate
|
|
2037
|
+
? [{ key: 'candidate', value: JSON.stringify({
|
|
2038
|
+
catalogVersion: freshness.candidate.catalogVersion,
|
|
2039
|
+
requestedRef: freshness.candidate.requestedRef,
|
|
2040
|
+
resolvedCommit: freshness.candidate.resolvedCommit,
|
|
2041
|
+
}) }]
|
|
2042
|
+
: []),
|
|
2043
|
+
];
|
|
2044
|
+
if (diagnostic)
|
|
2045
|
+
return {
|
|
2046
|
+
...diagnostic,
|
|
2047
|
+
...(diagnostic.technical ? { technical: {
|
|
2048
|
+
...diagnostic.technical,
|
|
2049
|
+
...(diagnostic.technical.requestedRef || !overview.detail?.requestedRef
|
|
2050
|
+
? {} : { requestedRef: overview.detail.requestedRef }),
|
|
2051
|
+
...(diagnostic.technical.resolvedCommit || !overview.detail?.resolvedCommit
|
|
2052
|
+
? {} : { resolvedCommit: overview.detail.resolvedCommit }),
|
|
2053
|
+
context: [...(diagnostic.technical.context ?? []), ...evidenceContext],
|
|
2054
|
+
} } : {}),
|
|
2055
|
+
};
|
|
2056
|
+
return {
|
|
1997
2057
|
severity: 'warning',
|
|
1998
2058
|
title: '来源解析详情',
|
|
1999
2059
|
userMessage: '来源当前可用。',
|
|
@@ -2005,6 +2065,7 @@ export function ConsoleAppV4(props) {
|
|
|
2005
2065
|
sourceId,
|
|
2006
2066
|
...(overview.detail?.requestedRef ? { requestedRef: overview.detail.requestedRef } : {}),
|
|
2007
2067
|
...(overview.detail?.resolvedCommit ? { resolvedCommit: overview.detail.resolvedCommit } : {}),
|
|
2068
|
+
context: evidenceContext,
|
|
2008
2069
|
},
|
|
2009
2070
|
};
|
|
2010
2071
|
};
|
|
@@ -2026,12 +2087,11 @@ export function ConsoleAppV4(props) {
|
|
|
2026
2087
|
sourceTabId: route.name === 'pluginList' ? route.sourceId ?? 'all' : undefined,
|
|
2027
2088
|
focusedEntityId: route.name === 'pluginList'
|
|
2028
2089
|
? pluginRows[focus]?.pluginId
|
|
2029
|
-
: route.name === '
|
|
2090
|
+
: route.name === 'batchSelection' ? actions[focus]?.pluginId
|
|
2091
|
+
: route.name === 'sourceList' ? props.controller.listSources()[focus]?.id : undefined,
|
|
2030
2092
|
});
|
|
2031
2093
|
props.controller.push(next);
|
|
2032
2094
|
setFocus(0);
|
|
2033
|
-
setFocusZone('content');
|
|
2034
|
-
setPinnedActionFocus(0);
|
|
2035
2095
|
setScrollOffset(0);
|
|
2036
2096
|
setSearchFocus(false);
|
|
2037
2097
|
if (next.name === 'pluginList') {
|
|
@@ -2072,6 +2132,12 @@ export function ConsoleAppV4(props) {
|
|
|
2072
2132
|
? restoredEntityIndex
|
|
2073
2133
|
: Math.min(restoredFocus, Math.max(0, rowIds.length - 1));
|
|
2074
2134
|
}
|
|
2135
|
+
else if (restoredFrame.route.name === 'batchSelection' && batchDraft) {
|
|
2136
|
+
const candidates = batchCandidates(batchDraft);
|
|
2137
|
+
const entityIndex = candidates.findIndex((candidate) => candidate.pluginId === restored.focusedEntityId);
|
|
2138
|
+
itemCount = candidates.length + 3;
|
|
2139
|
+
restoredFocus = entityIndex >= 0 ? entityIndex : Math.min(restoredFocus, Math.max(0, itemCount - 1));
|
|
2140
|
+
}
|
|
2075
2141
|
else if (restoredFrame.route.name === 'sourceList') {
|
|
2076
2142
|
const sources = props.controller.listSources();
|
|
2077
2143
|
itemCount = sources.length + 3;
|
|
@@ -2139,8 +2205,6 @@ export function ConsoleAppV4(props) {
|
|
|
2139
2205
|
else
|
|
2140
2206
|
props.controller.back();
|
|
2141
2207
|
restorePageContext();
|
|
2142
|
-
setFocusZone('content');
|
|
2143
|
-
setPinnedActionFocus(0);
|
|
2144
2208
|
setActionError(undefined);
|
|
2145
2209
|
};
|
|
2146
2210
|
const acceptSourceFieldAndBack = () => {
|
|
@@ -2237,8 +2301,7 @@ export function ConsoleAppV4(props) {
|
|
|
2237
2301
|
showSelected: false,
|
|
2238
2302
|
});
|
|
2239
2303
|
setDirty(true);
|
|
2240
|
-
setFocus(0);
|
|
2241
|
-
setScrollOffset(0);
|
|
2304
|
+
setFocus(Math.min(focus, Math.max(0, pluginRows.length - 1)));
|
|
2242
2305
|
setSearchFocus(false);
|
|
2243
2306
|
};
|
|
2244
2307
|
const batchCandidates = (draft) => {
|
|
@@ -2433,7 +2496,13 @@ export function ConsoleAppV4(props) {
|
|
|
2433
2496
|
};
|
|
2434
2497
|
const beginPortable = async (pluginId) => {
|
|
2435
2498
|
try {
|
|
2436
|
-
|
|
2499
|
+
if (route.name === 'portableBlocker' && snapshot.portableDraft?.pluginId === pluginId) {
|
|
2500
|
+
await props.controller.refreshPortableInstallDraft(pluginId);
|
|
2501
|
+
props.controller.resetPortableFlowToPreview(pluginId, { name: 'portableSkillSelect', pluginId }, true);
|
|
2502
|
+
}
|
|
2503
|
+
else {
|
|
2504
|
+
await props.controller.preparePortableInstall(pluginId, route.name === 'portableBlocker' ? 'replace' : 'push');
|
|
2505
|
+
}
|
|
2437
2506
|
setFocus(0);
|
|
2438
2507
|
setPortableSelectionView('all');
|
|
2439
2508
|
setScrollOffset(0);
|
|
@@ -2443,8 +2512,13 @@ export function ConsoleAppV4(props) {
|
|
|
2443
2512
|
if (error instanceof Error && error.name === 'AbortError')
|
|
2444
2513
|
return;
|
|
2445
2514
|
const blocker = extractPortableError(error);
|
|
2446
|
-
const
|
|
2447
|
-
|
|
2515
|
+
const operationRecordId = props.controller.recordUiFailure(error, {
|
|
2516
|
+
code: blocker.diagnosticCode,
|
|
2517
|
+
stage: 'prepare-portable',
|
|
2518
|
+
});
|
|
2519
|
+
const target = { name: 'portableBlocker', pluginId, ...blocker, operationRecordId };
|
|
2520
|
+
if (props.controller.snapshot.router.current.route.name === 'portableBlocker'
|
|
2521
|
+
|| props.controller.snapshot.router.current.route.name === 'portablePreparing') {
|
|
2448
2522
|
props.controller.replace(target);
|
|
2449
2523
|
}
|
|
2450
2524
|
else {
|
|
@@ -2476,7 +2550,11 @@ export function ConsoleAppV4(props) {
|
|
|
2476
2550
|
if (error instanceof Error && error.name === 'AbortError')
|
|
2477
2551
|
return false;
|
|
2478
2552
|
const blocker = extractPortableError(error);
|
|
2479
|
-
const
|
|
2553
|
+
const operationRecordId = props.controller.recordUiFailure(error, {
|
|
2554
|
+
code: blocker.diagnosticCode,
|
|
2555
|
+
stage: 'prepare-portable',
|
|
2556
|
+
});
|
|
2557
|
+
const target = { name: 'portableBlocker', pluginId, ...blocker, operationRecordId };
|
|
2480
2558
|
if (route.name === 'result')
|
|
2481
2559
|
leaveResult(target);
|
|
2482
2560
|
else
|
|
@@ -2735,43 +2813,14 @@ export function ConsoleAppV4(props) {
|
|
|
2735
2813
|
const configLayerLabel = (layer) => layer.scope === 'effective' ? '有效设置'
|
|
2736
2814
|
: layer.scope === 'user' ? '个人默认'
|
|
2737
2815
|
: '当前项目';
|
|
2738
|
-
const
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
const keys = Object.keys(value).sort((left, right) => left.localeCompare(right, 'en'));
|
|
2747
|
-
const count = keys.length === 0
|
|
2748
|
-
? '空对象'
|
|
2749
|
-
: `${keys.length} 项(${keys.slice(0, 2).join('、')}${keys.length > 2 ? '…' : ''})`;
|
|
2750
|
-
return preset ? `方案“${preset.title}” · ${count}` : `自定义 · ${count}`;
|
|
2751
|
-
};
|
|
2752
|
-
const scalarSummary = (field, value) => {
|
|
2753
|
-
if (field.sensitive)
|
|
2754
|
-
return '将更新';
|
|
2755
|
-
const preset = field.choices?.find((choice) => configValuesEqual(choice.value, value));
|
|
2756
|
-
if (preset)
|
|
2757
|
-
return preset.title;
|
|
2758
|
-
if (field.type === 'boolean')
|
|
2759
|
-
return value ? '开启' : '关闭';
|
|
2760
|
-
return `${String(value)}${field.unit ? ` ${field.unit}` : ''}`;
|
|
2761
|
-
};
|
|
2762
|
-
const currentFieldDisplay = (field) => {
|
|
2763
|
-
if (draftRemoves.includes(field.key))
|
|
2764
|
-
return '恢复继承';
|
|
2765
|
-
if (Object.hasOwn(draftUpdates, field.key)) {
|
|
2766
|
-
const value = draftUpdates[field.key];
|
|
2767
|
-
return typeof value === 'object'
|
|
2768
|
-
? objectSummary(field, value)
|
|
2769
|
-
: scalarSummary(field, value);
|
|
2770
|
-
}
|
|
2771
|
-
if (field.type === 'boolean' && field.value !== undefined)
|
|
2772
|
-
return field.value ? '开启' : '关闭';
|
|
2773
|
-
return `${field.displayValue}${field.unit && field.displayValue !== '未设置' ? ` ${field.unit}` : ''}`;
|
|
2774
|
-
};
|
|
2816
|
+
const fieldValueText = (field, value, full = false, configured = value !== undefined) => presentConfigValue({
|
|
2817
|
+
definition: field.definition,
|
|
2818
|
+
value,
|
|
2819
|
+
configured,
|
|
2820
|
+
privateValue: field.sensitive,
|
|
2821
|
+
summary: field.summary,
|
|
2822
|
+
full,
|
|
2823
|
+
}).text;
|
|
2775
2824
|
const effectiveFieldDisplay = (field) => {
|
|
2776
2825
|
if (field.type === 'boolean' && field.effectiveValue !== undefined) {
|
|
2777
2826
|
return field.effectiveValue ? '开启' : '关闭';
|
|
@@ -2789,7 +2838,7 @@ export function ConsoleAppV4(props) {
|
|
|
2789
2838
|
const value = draft.updates[field.key];
|
|
2790
2839
|
if (field.sensitive)
|
|
2791
2840
|
return '将更新';
|
|
2792
|
-
return
|
|
2841
|
+
return fieldValueText(field, value);
|
|
2793
2842
|
};
|
|
2794
2843
|
const pendingFieldTargets = (field) => ['project', 'user'].flatMap((scope) => {
|
|
2795
2844
|
const value = pendingFieldDisplay(field, scope);
|
|
@@ -3020,7 +3069,7 @@ export function ConsoleAppV4(props) {
|
|
|
3020
3069
|
return '已设置';
|
|
3021
3070
|
if (typeof value === 'boolean')
|
|
3022
3071
|
return value ? '开启' : '关闭';
|
|
3023
|
-
return String(value);
|
|
3072
|
+
return value === '' ? '(空字符串)' : safeConfigText(String(value));
|
|
3024
3073
|
};
|
|
3025
3074
|
const updatedChildren = beforeObject && afterObject
|
|
3026
3075
|
? [...new Set([...Object.keys(beforeObject), ...Object.keys(afterObject)])]
|
|
@@ -3059,13 +3108,11 @@ export function ConsoleAppV4(props) {
|
|
|
3059
3108
|
: updatedChildren;
|
|
3060
3109
|
const after = draft.removes.includes(key)
|
|
3061
3110
|
? `恢复继承(${field?.fallbackDisplayValue ?? '未设置'} · ${field?.fallbackSourceLabel ?? '未设置'})`
|
|
3062
|
-
:
|
|
3063
|
-
? objectSummary(field, updatedValue)
|
|
3064
|
-
: scalarSummary(field, updatedValue);
|
|
3111
|
+
: fieldValueText(field, updatedValue, true);
|
|
3065
3112
|
return {
|
|
3066
3113
|
key,
|
|
3067
3114
|
title: field?.title ?? key,
|
|
3068
|
-
before: field
|
|
3115
|
+
before: field ? fieldValueText(field, field.draftValue ?? field.value, true, field.configured) : '未设置',
|
|
3069
3116
|
after,
|
|
3070
3117
|
...(children && children.length > 0 ? { children } : {}),
|
|
3071
3118
|
};
|
|
@@ -3184,34 +3231,8 @@ export function ConsoleAppV4(props) {
|
|
|
3184
3231
|
const projectIntentIssue = snapshot.projectIntentIssue;
|
|
3185
3232
|
const projectPendingCount = (projectReminder?.actionableTargets.length ?? 0)
|
|
3186
3233
|
+ (projectReminder?.blockedTargets.length ?? 0);
|
|
3187
|
-
const projectTargetCount = projectPendingCount + (projectReminder?.unconfirmedTargets.length ?? 0);
|
|
3188
3234
|
context = '当前项目';
|
|
3189
3235
|
actions = [
|
|
3190
|
-
...(projectIntentIssue ? [{
|
|
3191
|
-
actionId: 'project-intent-issue',
|
|
3192
|
-
label: projectIntentIssue.state === 'invalid'
|
|
3193
|
-
? '本项目插件声明无效'
|
|
3194
|
-
: '无法读取本项目插件声明',
|
|
3195
|
-
description: projectIntentIssue.state === 'invalid'
|
|
3196
|
-
? '本项目插件声明无效;修复后重新加载'
|
|
3197
|
-
: '无法读取本项目插件声明;检查项目位置或权限后重新加载',
|
|
3198
|
-
status: 'warning',
|
|
3199
|
-
run: () => go({ name: 'projectStatus' }),
|
|
3200
|
-
}] : []),
|
|
3201
|
-
...(projectTargetCount > 0 ? [{
|
|
3202
|
-
label: '项目插件',
|
|
3203
|
-
description: projectReminder.actionableTargets.length > 0
|
|
3204
|
-
? `${projectReminder.actionableTargets.length} 个位置可同步;`
|
|
3205
|
-
+ `${projectReminder.blockedTargets.length} 个位置需要先处理;`
|
|
3206
|
-
+ `${projectReminder.unconfirmedTargets.length} 个位置未确认`
|
|
3207
|
-
: projectReminder.blockedTargets.length > 0
|
|
3208
|
-
? `${projectReminder.blockedTargets.length} 个位置需要先处理;`
|
|
3209
|
-
+ `${projectReminder.unconfirmedTargets.length} 个位置未确认`
|
|
3210
|
-
: `${projectReminder.unconfirmedTargets.length} 个位置未确认`,
|
|
3211
|
-
meta: String(projectTargetCount),
|
|
3212
|
-
status: 'warning',
|
|
3213
|
-
run: () => go({ name: 'projectStatus' }),
|
|
3214
|
-
}] : []),
|
|
3215
3236
|
{ label: '插件', description: '浏览、安装和管理所有插件', meta: `${home.installedPlugins} 已安装`, status: home.pluginUpdateCount > 0 ? 'warning' : undefined, run: () => go({ name: 'pluginList', mode: 'browse' }) },
|
|
3216
3237
|
{ label: '需要处理', description: '解决安装、来源或设置问题', meta: String(home.issueCount), status: 'warning', run: () => go({ name: 'issueList' }) },
|
|
3217
3238
|
{
|
|
@@ -3224,18 +3245,12 @@ export function ConsoleAppV4(props) {
|
|
|
3224
3245
|
run: () => go({ name: 'sourceList' }),
|
|
3225
3246
|
},
|
|
3226
3247
|
];
|
|
3227
|
-
const homeViewport = rowViewport({
|
|
3228
|
-
rowHeights: actions.map((action) => showTechnical ? 1 : objectCardRowLayout({
|
|
3229
|
-
description: action.description ?? '', meta: action.meta, width: size.columns - 2,
|
|
3230
|
-
compact: policy.mode === 'compact',
|
|
3231
|
-
}).height), focus, requestedOffset: scrollOffset, rowBudget: pageActionBudget(showTechnical ? 7 : 2),
|
|
3232
|
-
});
|
|
3233
3248
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: tuiTheme.colors.muted, children: ["[\u5DF2\u5B89\u88C5 ", home.installedPlugins, "] [\u53EF\u66F4\u65B0 ", home.pluginUpdateCount, "]", home.unavailableSourceCount > 0 ? ` [不可用来源 ${home.unavailableSourceCount}]` : ''] }), _jsx(Text, { color: tuiTheme.colors.muted, children: projectIntentIssue ? '! 本项目插件声明需要检查'
|
|
3234
3249
|
: projectReminder && projectReminder.unconfirmedTargets.length > 0
|
|
3235
3250
|
? '? 部分项目插件状态无法确认' : projectPendingCount > 0
|
|
3236
3251
|
? `! ${projectPendingCount} 个位置待处理`
|
|
3237
3252
|
: snapshot.projectDeclarationAbsent
|
|
3238
|
-
? '当前目录没有共享插件声明;不会自动安装插件' : '没有待同步提醒' }), projectIntentIssue && showTechnical ? _jsxs(TechnicalDetails, { title: "\u9879\u76EE\u58F0\u660E\u8BCA\u65AD", compact: true, children: [_jsx(StaticRow, { title: "\u9519\u8BEF\u4EE3\u7801", meta: projectIntentIssue.code, compact: true }), _jsx(StaticRow, { title: "\u8BF4\u660E", meta: sanitizeDiagnosticText(projectIntentIssue.message), compact: true })] }) : null, _jsx(SemanticRows, { actions: actions, focus: projectReminderOpen ? -1 : focus, kind: "task",
|
|
3253
|
+
? '当前目录没有共享插件声明;不会自动安装插件' : '没有待同步提醒' }), projectIntentIssue && showTechnical ? _jsxs(TechnicalDetails, { title: "\u9879\u76EE\u58F0\u660E\u8BCA\u65AD", compact: true, children: [_jsx(StaticRow, { title: "\u9519\u8BEF\u4EE3\u7801", meta: projectIntentIssue.code, compact: true }), _jsx(StaticRow, { title: "\u8BF4\u660E", meta: sanitizeDiagnosticText(projectIntentIssue.message), compact: true })] }) : null, _jsx(SemanticRows, { actions: actions, focus: projectReminderOpen ? -1 : focus, kind: "task", compact: false })] });
|
|
3239
3254
|
}
|
|
3240
3255
|
else if (route.name === 'projectStatus') {
|
|
3241
3256
|
const reminder = snapshot.projectIntentReminder;
|
|
@@ -3321,7 +3336,7 @@ export function ConsoleAppV4(props) {
|
|
|
3321
3336
|
: () => go({ name: 'pluginDetail', pluginId: target.pluginId }),
|
|
3322
3337
|
};
|
|
3323
3338
|
});
|
|
3324
|
-
|
|
3339
|
+
bottomActions = [
|
|
3325
3340
|
...(actionable.length > 0 ? [{
|
|
3326
3341
|
actionId: 'project-sync-actionable',
|
|
3327
3342
|
label: `同步明确的 ${actionable.length} 个位置`,
|
|
@@ -3348,28 +3363,12 @@ export function ConsoleAppV4(props) {
|
|
|
3348
3363
|
description: '查看现有安全错误代码和诊断,不执行写操作',
|
|
3349
3364
|
run: () => setShowTechnical((value) => !value),
|
|
3350
3365
|
}] : []),
|
|
3351
|
-
{
|
|
3352
|
-
actionId: 'project-back-home',
|
|
3353
|
-
label: '返回首页',
|
|
3354
|
-
run: back,
|
|
3355
|
-
},
|
|
3356
3366
|
];
|
|
3357
3367
|
help = showTechnical
|
|
3358
|
-
? 'p/n 或 PgUp/PgDn 阅读 · d 返回项目位置 ·
|
|
3359
|
-
:
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
const viewport = rowViewport({
|
|
3363
|
-
rowHeights: actions.map((action) => objectCardRowLayout({
|
|
3364
|
-
description: action.description ?? '', meta: action.meta,
|
|
3365
|
-
width: size.columns - 2, hasTags: true, compact: policy.mode === 'compact',
|
|
3366
|
-
}).height),
|
|
3367
|
-
focus,
|
|
3368
|
-
requestedOffset: scrollOffset,
|
|
3369
|
-
rowBudget: pageActionBudget(showTechnical ? 5
|
|
3370
|
-
: 1 + (projectIntentIssue || unconfirmed.length > 0 ? 1 : 0)
|
|
3371
|
-
+ (actionable.length > 0 && blocked.length + unconfirmed.length > 0 ? 1 : 0)),
|
|
3372
|
-
});
|
|
3368
|
+
? 'p/n 或 PgUp/PgDn 阅读 · d 返回项目位置 · Esc 返回'
|
|
3369
|
+
: '↑↓ 移动 · Enter 查看 · Esc 返回';
|
|
3370
|
+
const projectItemCount = showTechnical ? 0 : actions.length;
|
|
3371
|
+
actions = [...(showTechnical ? [] : actions), ...bottomActions];
|
|
3373
3372
|
const technicalLines = [
|
|
3374
3373
|
...(projectIntentIssue ? [
|
|
3375
3374
|
`项目声明 · ${safeDiagnosticCode(projectIntentIssue.code, 'projectIntentUnavailable')}`,
|
|
@@ -3383,21 +3382,19 @@ export function ConsoleAppV4(props) {
|
|
|
3383
3382
|
: state === 'blocked' ? '原因 · blocked' : '原因 · unconfirmed']),
|
|
3384
3383
|
]),
|
|
3385
3384
|
];
|
|
3385
|
+
if (showTechnical)
|
|
3386
|
+
description = undefined;
|
|
3386
3387
|
const technicalPageRows = responsiveBudget(4, 8);
|
|
3387
3388
|
const technicalOffset = Math.min(batchTargetOffset, Math.max(0, technicalLines.length - 1));
|
|
3388
3389
|
const visibleTechnicalLines = technicalLines.slice(technicalOffset, technicalOffset + technicalPageRows);
|
|
3389
3390
|
referenceDetailPagination = showTechnical && technicalLines.length > 0
|
|
3390
3391
|
? { total: technicalLines.length, pageRows: technicalPageRows }
|
|
3391
3392
|
: undefined;
|
|
3392
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(
|
|
3393
|
-
id: action.actionId ?? `${action.label}:${index}`,
|
|
3394
|
-
label: action.label,
|
|
3395
|
-
disabled: Boolean(action.disabled),
|
|
3396
|
-
})), active: focusZone === 'actions', focus: pinnedActionFocus, visibleCount: policy.mode === 'compact' ? 2 : 3 }), projectIntentIssue || unconfirmed.length > 0 ? _jsx(StaticRow, { status: "warning", title: "? \u672A\u77E5\u72B6\u6001\u4E0D\u7B49\u4E8E\u672A\u5B89\u88C5\uFF1B\u6CA1\u6709\u81EA\u52A8\u6267\u884C\u5B89\u88C5\u6216\u6062\u590D\u3002", compact: true }) : null, actionable.length > 0 && blocked.length + unconfirmed.length > 0
|
|
3393
|
+
content = _jsxs(Box, { flexDirection: "column", children: [!showTechnical && (projectIntentIssue || unconfirmed.length > 0) ? _jsx(StaticRow, { status: "warning", title: "? \u672A\u77E5\u72B6\u6001\u4E0D\u7B49\u4E8E\u672A\u5B89\u88C5\uFF1B\u6CA1\u6709\u81EA\u52A8\u6267\u884C\u5B89\u88C5\u6216\u6062\u590D\u3002", compact: true }) : null, !showTechnical && actionable.length > 0 && blocked.length + unconfirmed.length > 0
|
|
3397
3394
|
? _jsx(StaticRow, { status: "info", title: `只同步明确项;保留 ${blocked.length} 个受阻位置和 ${unconfirmed.length} 个未确认位置。`, compact: true })
|
|
3398
3395
|
: null, showTechnical ? _jsxs(TechnicalDetails, { title: "\u9879\u76EE\u72B6\u6001\u5B89\u5168\u8BE6\u60C5", compact: true, children: [technicalOffset > 0
|
|
3399
3396
|
? _jsx(StaticRow, { title: `↑ 前面还有 ${technicalOffset} 行`, status: "muted", compact: true }) : null, visibleTechnicalLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${technicalOffset + index}:${line}`)), technicalOffset + visibleTechnicalLines.length < technicalLines.length
|
|
3400
|
-
? _jsx(StaticRow, { title: `↓ 后面还有 ${technicalLines.length - technicalOffset - visibleTechnicalLines.length} 行`, status: "muted", compact: true }) : null] }) : _jsx(
|
|
3397
|
+
? _jsx(StaticRow, { title: `↓ 后面还有 ${technicalLines.length - technicalOffset - visibleTechnicalLines.length} 行`, status: "muted", compact: true }) : null] }) : _jsx(SequenceRows, { actions: actions, itemCount: projectItemCount, focus: focus, scrollOffset: scrollOffset, columns: size.columns - 2, rowBudget: pageActionBudget(2), compact: policy.mode === 'compact', cards: true }), showTechnical ? _jsx(SemanticRows, { actions: actions, offset: projectItemCount, focus: focus, kind: "action", compact: true }) : null] });
|
|
3401
3398
|
}
|
|
3402
3399
|
else if (route.name === 'pluginList') {
|
|
3403
3400
|
const sourceId = route.sourceId ?? 'all';
|
|
@@ -3416,12 +3413,10 @@ export function ConsoleAppV4(props) {
|
|
|
3416
3413
|
}).length,
|
|
3417
3414
|
]));
|
|
3418
3415
|
breadcrumb = '插件';
|
|
3419
|
-
title =
|
|
3420
|
-
description =
|
|
3416
|
+
title = `插件 · ${items.length} 个 [m] 多选`;
|
|
3417
|
+
description = undefined;
|
|
3421
3418
|
context = `${items.length} 个插件`;
|
|
3422
|
-
help =
|
|
3423
|
-
? '←→/↑↓ 操作 · Enter 执行 · Tab 插件列表 · Esc 返回'
|
|
3424
|
-
: '↑↓ 插件 · Enter 查看 · Tab 操作栏 · m 多选 · / 搜索 · f 状态 · Esc 返回';
|
|
3419
|
+
help = '↑↓ 移动 · Enter 查看 · Esc 返回';
|
|
3425
3420
|
const sourceError = sourceId !== 'all'
|
|
3426
3421
|
&& props.controller.getSourceOverview(sourceId).health?.state === 'unavailable';
|
|
3427
3422
|
actions = sourceError
|
|
@@ -3439,7 +3434,7 @@ export function ConsoleAppV4(props) {
|
|
|
3439
3434
|
const retained = selectedPluginId ? nextRowIds.indexOf(selectedPluginId) : -1;
|
|
3440
3435
|
setInstallFilter(nextFilter);
|
|
3441
3436
|
props.controller.updatePageContext({ installFilter: nextFilter });
|
|
3442
|
-
setFocus(retained >= 0 ? retained : 0);
|
|
3437
|
+
setFocus(retained >= 0 ? retained : Math.min(focus, Math.max(0, nextRowIds.length - 1)));
|
|
3443
3438
|
setScrollOffset(0);
|
|
3444
3439
|
};
|
|
3445
3440
|
togglePluginListFilter = () => {
|
|
@@ -3462,7 +3457,7 @@ export function ConsoleAppV4(props) {
|
|
|
3462
3457
|
props.controller.replace({ name: 'pluginList', mode: route.mode, ...(next !== 'all' ? { sourceId: next } : {}) }, { ...snapshot.router.current.context, query, installFilter, sourceTabId: next });
|
|
3463
3458
|
const retainedFocus = retained >= 0
|
|
3464
3459
|
? retained
|
|
3465
|
-
:
|
|
3460
|
+
: Math.min(focus, Math.max(0, nextRowIds.length - 1));
|
|
3466
3461
|
setFocus(retainedFocus);
|
|
3467
3462
|
setScrollOffset(retainedFocus >= 4 ? retainedFocus - 3 : 0);
|
|
3468
3463
|
};
|
|
@@ -3504,32 +3499,24 @@ export function ConsoleAppV4(props) {
|
|
|
3504
3499
|
}] : []),
|
|
3505
3500
|
{
|
|
3506
3501
|
actionId: 'plugin-list-multi',
|
|
3507
|
-
label:
|
|
3502
|
+
label: '选择多个插件 [m]',
|
|
3508
3503
|
description: '先选择插件,再选择安装、更新、恢复、卸载或维护任务',
|
|
3509
3504
|
status: 'info',
|
|
3510
3505
|
run: () => openBatchSelection(),
|
|
3511
3506
|
},
|
|
3512
3507
|
];
|
|
3513
|
-
const
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
focus: Math.max(0, PLUGIN_FILTERS.indexOf(installFilter)),
|
|
3520
|
-
}),
|
|
3521
|
-
},
|
|
3522
|
-
{ actionId: 'plugin-list-search', label: '/ 搜索', run: () => setSearchFocus(true) },
|
|
3523
|
-
{
|
|
3524
|
-
actionId: 'plugin-list-source',
|
|
3525
|
-
label: `来源:${sourceId === 'all' ? '全部' : sourceId}`,
|
|
3526
|
-
run: () => setPluginListChooser({
|
|
3527
|
-
kind: 'source',
|
|
3528
|
-
focus: Math.max(0, ['all', ...props.controller.listSources().map((source) => source.id)]
|
|
3529
|
-
.indexOf(sourceId)),
|
|
3530
|
-
}),
|
|
3508
|
+
const searchAction = {
|
|
3509
|
+
actionId: 'plugin-list-search', label: '搜索 [/]',
|
|
3510
|
+
run: () => {
|
|
3511
|
+
setSearchCursor([...new Intl.Segmenter(undefined, { granularity: 'grapheme' })
|
|
3512
|
+
.segment(query)].length);
|
|
3513
|
+
setSearchFocus(true);
|
|
3531
3514
|
},
|
|
3532
|
-
|
|
3515
|
+
};
|
|
3516
|
+
const filterAction = {
|
|
3517
|
+
actionId: 'plugin-list-filter', label: '切换筛选 [f]', run: togglePluginListFilter,
|
|
3518
|
+
};
|
|
3519
|
+
listQueryActions = [searchAction, filterAction];
|
|
3533
3520
|
const pluginRowsById = new Map([
|
|
3534
3521
|
...items.map((item) => [item.pluginId, {
|
|
3535
3522
|
pluginId: item.pluginId,
|
|
@@ -3600,38 +3587,29 @@ export function ConsoleAppV4(props) {
|
|
|
3600
3587
|
} } : { disabled: '没有可打开的插件' }),
|
|
3601
3588
|
}];
|
|
3602
3589
|
}
|
|
3603
|
-
|
|
3590
|
+
bottomActions = dedupeActions([
|
|
3604
3591
|
...(sourceError ? actions : []),
|
|
3605
|
-
...
|
|
3606
|
-
...
|
|
3592
|
+
...actions,
|
|
3593
|
+
...menuActions,
|
|
3607
3594
|
]);
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
content = (_jsxs(Box, { flexDirection: "column", children: [_jsx(PinnedActionBar, { actions: pinnedActions.map((action, index) => ({
|
|
3621
|
-
id: action.actionId ?? `${action.label}:${index}`,
|
|
3622
|
-
label: action.label,
|
|
3623
|
-
disabled: Boolean(action.disabled),
|
|
3624
|
-
})), active: !pluginListChooser && focusZone === 'actions', focus: pinnedActionFocus, visibleCount: policy.mode === 'compact' ? 2 : 3 }), _jsx(SourceTabs, { controller: props.controller, current: sourceId, compact: policy.mode === 'compact', columns: size.columns - 2, mode: route.mode, query: query || undefined, installFilter: installFilter }), _jsxs(Text, { color: searchFocus ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: ["\u641C\u7D22 / ", searchFocus
|
|
3625
|
-
? _jsx(InputDisplay, { value: query, placeholder: "\u8F93\u5165\u641C\u7D22\u5185\u5BB9", columns: Math.max(8, size.columns - 14) })
|
|
3626
|
-
: _jsxs(_Fragment, { children: [query || '搜索名称、用途或来源…', query ? ' / 编辑' : ''] })] }), _jsxs(Text, { wrap: "truncate-end", color: tuiTheme.colors.muted, children: ["\u72B6\u6001 ", _jsxs(Text, { color: tuiTheme.colors.accent, children: ["[", pluginFilterLabel(installFilter), " ", filterCounts[installFilter], "]"] }), " \u5168\u90E8 ", filterCounts.all, " \u00B7 \u5DF2\u88C5 ", filterCounts.installed, " \u00B7 \u672A\u88C5 ", filterCounts.uninstalled, " \u00B7 \u66F4\u65B0 ", filterCounts.updateAvailable, " \u00B7 \u5904\u7406 ", filterCounts.attention, " f \u5207\u6362"] }), sourceError
|
|
3595
|
+
actions = [...pluginRows.map((row) => ({
|
|
3596
|
+
actionId: `plugin:${row.pluginId}`, pluginId: row.pluginId, label: row.name,
|
|
3597
|
+
run: () => go({ name: 'pluginDetail', pluginId: row.pluginId }),
|
|
3598
|
+
})), ...bottomActions];
|
|
3599
|
+
const viewport = rowViewport({
|
|
3600
|
+
rowHeights: actions.map((_, index) => index < pluginRows.length
|
|
3601
|
+
? pluginRows[index].attention ? 6 : 5 : 1),
|
|
3602
|
+
focus, requestedOffset: scrollOffset, rowBudget: pageActionBudget(3),
|
|
3603
|
+
});
|
|
3604
|
+
content = (_jsxs(Box, { flexDirection: "column", children: [_jsx(SourceTabs, { controller: props.controller, current: sourceId, compact: policy.mode === 'compact', columns: size.columns - 2, mode: route.mode, query: query || undefined, installFilter: installFilter }), _jsxs(Text, { color: searchFocus ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: ["\u641C\u7D22 [/] ", searchFocus
|
|
3605
|
+
? _jsx(InputDisplay, { value: query, cursor: searchCursor, placeholder: "\u8F93\u5165\u641C\u7D22\u5185\u5BB9", columns: Math.max(8, size.columns - 14) })
|
|
3606
|
+
: _jsxs(_Fragment, { children: [query || '输入名称或用途', query ? ' / 编辑' : ''] })] }), _jsxs(Text, { wrap: "truncate-end", color: tuiTheme.colors.muted, children: ["\u7B5B\u9009 ", _jsxs(Text, { color: tuiTheme.colors.accent, children: ["[", pluginFilterLabel(installFilter), " ", filterCounts[installFilter], "]"] }), " [f] \u5207\u6362"] }), sourceError
|
|
3627
3607
|
? _jsx(Callout, { status: "error", title: `${sourceId} 暂时无法提供插件`, description: "\u5F53\u524D\u4E0D\u80FD\u6D4F\u89C8\u8FD9\u4E2A\u6765\u6E90\u3002" })
|
|
3628
3608
|
: route.mode === 'installed' && items.length === 0 && !query && sourceId === 'all'
|
|
3629
3609
|
? installFilter === 'updateAvailable'
|
|
3630
3610
|
? _jsx(Callout, { title: "\u6CA1\u6709\u53EF\u66F4\u65B0\u63D2\u4EF6", description: "\u5F53\u524D\u7B5B\u9009\u8303\u56F4\u5185\u6CA1\u6709\u7ECF\u8FC7\u7248\u672C\u8BC1\u636E\u786E\u8BA4\u7684\u66F4\u65B0\u3002" })
|
|
3631
3611
|
: _jsx(Callout, { title: "\u5F00\u59CB\u6DFB\u52A0\u7B2C\u4E00\u4E2A\u63D2\u4EF6", description: "\u63D2\u4EF6\u53EF\u4EE5\u5B89\u88C5\u5230 Codex\u3001Claude Code \u6216\u4E24\u8005\u3002" })
|
|
3632
|
-
: null,
|
|
3633
|
-
? _jsx(PluginRows, { rows: pluginRows, focus: focus, viewport: viewport, active: !pluginListChooser && focusZone === 'content' })
|
|
3634
|
-
: _jsx(SemanticRows, { actions: actions, focus: !pluginListChooser && focusZone === 'content' ? focus : -1, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit }) })] }));
|
|
3612
|
+
: null, _jsxs(ContentViewport, { children: [_jsx(PluginRows, { rows: pluginRows, focus: focus, viewport: viewport, active: !searchFocus }), _jsx(SemanticRows, { actions: actions, focus: searchFocus ? -1 : focus, kind: "action", compact: true, offset: Math.max(pluginRows.length, viewport.offset), limit: Math.max(0, viewport.offset + viewport.limit - Math.max(pluginRows.length, viewport.offset)) })] })] }));
|
|
3635
3613
|
}
|
|
3636
3614
|
else if (route.name === 'batchSelection') {
|
|
3637
3615
|
breadcrumb = '插件 / 选择多个';
|
|
@@ -3639,12 +3617,12 @@ export function ConsoleAppV4(props) {
|
|
|
3639
3617
|
: batchDraft?.stage === 'maintenance' ? '其他维护方式'
|
|
3640
3618
|
: '选择插件';
|
|
3641
3619
|
description = batchDraft?.stage === 'select'
|
|
3642
|
-
?
|
|
3620
|
+
? undefined
|
|
3643
3621
|
: batchDraft?.stage === 'task'
|
|
3644
3622
|
? '更新和恢复沿用已经添加的位置;移除会逐项显示已有位置。'
|
|
3645
3623
|
: '同步、重新安装和普通清理使用所选插件的已有位置。';
|
|
3646
3624
|
if (!batchDraft) {
|
|
3647
|
-
actions = [{ label: '返回插件列表', run: back }];
|
|
3625
|
+
actions = [{ role: 'navigation', label: '返回插件列表', run: back }];
|
|
3648
3626
|
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true });
|
|
3649
3627
|
}
|
|
3650
3628
|
else if (batchDraft.stage === 'select') {
|
|
@@ -3697,7 +3675,7 @@ export function ConsoleAppV4(props) {
|
|
|
3697
3675
|
};
|
|
3698
3676
|
const continueAction = {
|
|
3699
3677
|
actionId: 'batch-selection-continue',
|
|
3700
|
-
label:
|
|
3678
|
+
label: `继续(${batchDraft.selectedPluginIds.length}) [c]`,
|
|
3701
3679
|
description: batchDraft.selectedPluginIds.length > 0
|
|
3702
3680
|
? batchDraft.recommendedGoal ? '重新读取更新信息并显示操作汇总' : '继续选择任务和确认范围'
|
|
3703
3681
|
: '先选择至少一个插件',
|
|
@@ -3715,18 +3693,16 @@ export function ConsoleAppV4(props) {
|
|
|
3715
3693
|
} : current);
|
|
3716
3694
|
setFocus(0);
|
|
3717
3695
|
setScrollOffset(0);
|
|
3718
|
-
setFocusZone('content');
|
|
3719
3696
|
},
|
|
3720
3697
|
};
|
|
3721
3698
|
const selectionToolActions = [
|
|
3722
3699
|
{
|
|
3723
|
-
label: '返回插件选择',
|
|
3700
|
+
role: 'navigation', label: '返回插件选择',
|
|
3724
3701
|
description: '保留当前已选插件',
|
|
3725
3702
|
run: () => {
|
|
3726
3703
|
setBatchDraft((current) => current ? { ...current, showSelectionTools: false } : current);
|
|
3727
3704
|
setFocus(0);
|
|
3728
3705
|
setScrollOffset(0);
|
|
3729
|
-
setFocusZone('content');
|
|
3730
3706
|
},
|
|
3731
3707
|
},
|
|
3732
3708
|
{
|
|
@@ -3761,29 +3737,18 @@ export function ConsoleAppV4(props) {
|
|
|
3761
3737
|
} : current);
|
|
3762
3738
|
setFocus(0);
|
|
3763
3739
|
setScrollOffset(0);
|
|
3764
|
-
setFocusZone('content');
|
|
3765
3740
|
},
|
|
3766
3741
|
};
|
|
3767
|
-
|
|
3768
|
-
|
|
3742
|
+
bottomActions = [continueAction, selectedSetAction, selectionToolsAction];
|
|
3743
|
+
actions = [...(batchDraft.showSelectionTools ? selectionToolActions : candidateActions), ...bottomActions];
|
|
3769
3744
|
const batchFocus = Math.min(focus, Math.max(0, actions.length - 1));
|
|
3770
3745
|
context = `已选 ${batchDraft.selectedPluginIds.length} 个 · 显示 ${candidates.length} 个${hiddenSelected > 0 ? ` · 隐藏 ${hiddenSelected} 个` : ''}`;
|
|
3771
3746
|
help = batchDraft.showSelectionTools
|
|
3772
|
-
? '↑↓ 移动 · Enter 执行 ·
|
|
3773
|
-
: '↑↓ 移动 · Space 选择 · Enter 查看 ·
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
: objectCardActionViewport(actions, cardWidth, policy.mode === 'compact', batchFocus, scrollOffset, Math.max(1, pageActionBudget(4)));
|
|
3778
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(PinnedActionBar, { actions: pinnedActions.map((action) => ({
|
|
3779
|
-
id: action.actionId ?? action.label,
|
|
3780
|
-
label: action.label,
|
|
3781
|
-
disabled: Boolean(action.disabled),
|
|
3782
|
-
})), active: focusZone === 'actions', focus: pinnedActionFocus, visibleCount: policy.mode === 'compact' ? 2 : 3 }), _jsx(SourceTabs, { controller: props.controller, current: batchDraft.showSelected ? 'all' : batchDraft.sourceId ?? 'all', compact: policy.mode === 'compact', columns: size.columns - 2, mode: batchDraft.mode, query: batchDraft.showSelected ? undefined : batchDraft.query || undefined, installFilter: batchDraft.showSelected ? 'all' : batchDraft.installFilter }), _jsxs(Text, { color: searchFocus ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: ["\u641C\u7D22 / ", searchFocus
|
|
3783
|
-
? _jsx(InputDisplay, { value: batchDraft.query, placeholder: "\u8F93\u5165\u641C\u7D22\u5185\u5BB9", columns: Math.max(8, size.columns - 14) })
|
|
3784
|
-
: _jsxs(_Fragment, { children: [batchDraft.query || '搜索名称、用途或来源…', batchDraft.query ? ' / 编辑' : ''] })] }), _jsxs(Text, { color: tuiTheme.colors.muted, children: ["\u72B6\u6001 ", _jsxs(Text, { color: tuiTheme.colors.accent, children: ["[", pluginFilterLabel(batchDraft.installFilter), "]"] }), " f \u5207\u6362"] }), _jsx(ContentViewport, { children: batchDraft.showSelectionTools
|
|
3785
|
-
? _jsx(SemanticRows, { actions: actions, focus: focusZone === 'content' ? batchFocus : -1, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit })
|
|
3786
|
-
: _jsx(Box, { flexDirection: "column", children: actions.slice(viewport.offset, viewport.offset + viewport.limit).map((action, visibleIndex) => (_jsx(ObjectCardRow, { width: cardWidth, title: `${action.selected ? '[x]' : '[ ]'} ${action.label}`, description: action.disabled ?? action.description ?? '', meta: action.meta, tags: action.tags, focused: focusZone === 'content' && viewport.offset + visibleIndex === batchFocus, anchored: focusZone !== 'content' && viewport.offset + visibleIndex === batchFocus, compact: policy.mode === 'compact' }, action.pluginId ?? action.label))) }) })] });
|
|
3747
|
+
? '↑↓ 移动 · Enter 执行 · Esc 返回选择'
|
|
3748
|
+
: '↑↓ 移动 · Space 选择 · Enter 查看 · Esc 返回';
|
|
3749
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SourceTabs, { controller: props.controller, current: batchDraft.showSelected ? 'all' : batchDraft.sourceId ?? 'all', compact: policy.mode === 'compact', columns: size.columns - 2, mode: batchDraft.mode, query: batchDraft.showSelected ? undefined : batchDraft.query || undefined, installFilter: batchDraft.showSelected ? 'all' : batchDraft.installFilter }), _jsxs(Text, { color: searchFocus ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: ["\u641C\u7D22 [/] ", searchFocus
|
|
3750
|
+
? _jsx(InputDisplay, { value: batchDraft.query, cursor: searchCursor, placeholder: "\u8F93\u5165\u641C\u7D22\u5185\u5BB9", columns: Math.max(8, size.columns - 14) })
|
|
3751
|
+
: _jsxs(_Fragment, { children: [batchDraft.query || '输入名称或用途', batchDraft.query ? ' / 编辑' : ''] })] }), _jsxs(Text, { color: tuiTheme.colors.muted, children: ["\u72B6\u6001 ", _jsxs(Text, { color: tuiTheme.colors.accent, children: ["[", pluginFilterLabel(batchDraft.installFilter), "]"] }), " [f] \u5207\u6362"] }), _jsxs(Text, { color: tuiTheme.colors.muted, children: ["\u5DF2\u9009 ", selected.size, " \u00B7 \u9690\u85CF\u5DF2\u9009 ", hiddenSelected, " [c] \u7EE7\u7EED"] }), _jsx(SequenceRows, { actions: actions, itemCount: batchDraft.showSelectionTools ? 0 : candidateActions.length, focus: batchFocus, scrollOffset: scrollOffset, columns: size.columns - 2, rowBudget: pageActionBudget(4), compact: policy.mode === 'compact', cards: true, inactive: searchFocus })] });
|
|
3787
3752
|
}
|
|
3788
3753
|
else {
|
|
3789
3754
|
const selectedIds = batchDraft.selectedPluginIds;
|
|
@@ -3824,7 +3789,7 @@ export function ConsoleAppV4(props) {
|
|
|
3824
3789
|
{ label: '重新安装', description: `重新生成 ${props.controller.listPluginWriteBatchTargets('reinstall', selectedIds).length} 个已保存或现场目标`, run: () => startExistingBatch('reinstall') },
|
|
3825
3790
|
{ label: '清理遗留内容', description: `${props.controller.listPluginWriteBatchTargets('cleanup', selectedIds).length} 个已核验位置;保留不属于插件或被共用的内容`, run: () => startExistingBatch('cleanup') },
|
|
3826
3791
|
{
|
|
3827
|
-
label: '返回任务选择',
|
|
3792
|
+
role: 'navigation', label: '返回任务选择',
|
|
3828
3793
|
run: () => moveBatchStage('task'),
|
|
3829
3794
|
},
|
|
3830
3795
|
];
|
|
@@ -3866,7 +3831,7 @@ export function ConsoleAppV4(props) {
|
|
|
3866
3831
|
description: '同步、重新安装和普通清理',
|
|
3867
3832
|
run: () => moveBatchStage('maintenance'),
|
|
3868
3833
|
},
|
|
3869
|
-
{ label: '返回调整选择', run: () => moveBatchStage('select') },
|
|
3834
|
+
{ role: 'navigation', label: '返回调整选择', run: () => moveBatchStage('select') },
|
|
3870
3835
|
];
|
|
3871
3836
|
}
|
|
3872
3837
|
context = `${selectedIds.length} 个插件 · ${syncTargets.length} 个已保存或现场目标`;
|
|
@@ -3905,7 +3870,7 @@ export function ConsoleAppV4(props) {
|
|
|
3905
3870
|
};
|
|
3906
3871
|
const confirmPlatforms = {
|
|
3907
3872
|
actionId: 'batch-install-platforms-confirm',
|
|
3908
|
-
label: '确定所选平台',
|
|
3873
|
+
label: '确定所选平台 [c]',
|
|
3909
3874
|
description: `${[...selectedPlatforms].map(platformLabel).join('、')} · 继续选择目标`,
|
|
3910
3875
|
run: () => {
|
|
3911
3876
|
props.controller.push({ name: 'batchInstallScope' });
|
|
@@ -3930,9 +3895,9 @@ export function ConsoleAppV4(props) {
|
|
|
3930
3895
|
},
|
|
3931
3896
|
confirmPlatforms,
|
|
3932
3897
|
];
|
|
3933
|
-
|
|
3934
|
-
help = '↑↓ 移动 · Enter
|
|
3935
|
-
content =
|
|
3898
|
+
bottomActions = [confirmPlatforms];
|
|
3899
|
+
help = '↑↓ 移动 · Space/Enter 切换 · c 确定所选平台 · Esc 返回任务选择';
|
|
3900
|
+
content = _jsx(Box, { flexDirection: "column", children: _jsxs(ContentViewport, { children: [_jsx(SemanticRows, { actions: actions.slice(0, 2), focus: focus, kind: "choice", compact: policy.mode === 'compact' }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: 2 })] }) });
|
|
3936
3901
|
}
|
|
3937
3902
|
else if (route.name === 'batchInstallScope' || route.name === 'batchPlacement') {
|
|
3938
3903
|
breadcrumb = route.name === 'batchInstallScope'
|
|
@@ -3960,7 +3925,7 @@ export function ConsoleAppV4(props) {
|
|
|
3960
3925
|
let installPlacementActions = [];
|
|
3961
3926
|
let maintenanceTargetCount = 0;
|
|
3962
3927
|
if (!batchDraft?.action && !batchDraft?.maintenanceGoal) {
|
|
3963
|
-
actions = [{ label: '返回批量选择', run: back }];
|
|
3928
|
+
actions = [{ role: 'navigation', label: '返回批量选择', run: back }];
|
|
3964
3929
|
}
|
|
3965
3930
|
else if (maintenanceMode) {
|
|
3966
3931
|
const currentTargets = batchDraft.maintenanceGoal
|
|
@@ -4014,9 +3979,9 @@ export function ConsoleAppV4(props) {
|
|
|
4014
3979
|
actions = [
|
|
4015
3980
|
...targetActions,
|
|
4016
3981
|
confirmMaintenance,
|
|
4017
|
-
{ label: '返回任务选择', run: back },
|
|
3982
|
+
{ role: 'navigation', label: '返回任务选择', run: back },
|
|
4018
3983
|
];
|
|
4019
|
-
|
|
3984
|
+
bottomActions = [confirmMaintenance];
|
|
4020
3985
|
}
|
|
4021
3986
|
else {
|
|
4022
3987
|
const projectIntent = batchDraft.selection === 'currentProjectIntentRoots';
|
|
@@ -4106,7 +4071,7 @@ export function ConsoleAppV4(props) {
|
|
|
4106
4071
|
if (route.name === 'batchInstallScope') {
|
|
4107
4072
|
const confirmPlacement = installPlacementActions.find((action) => action.actionId === 'batch-placement-confirm');
|
|
4108
4073
|
if (confirmPlacement)
|
|
4109
|
-
|
|
4074
|
+
bottomActions = [confirmPlacement];
|
|
4110
4075
|
}
|
|
4111
4076
|
if (batchDraft.showPlacementTargets) {
|
|
4112
4077
|
actions = [
|
|
@@ -4118,7 +4083,7 @@ export function ConsoleAppV4(props) {
|
|
|
4118
4083
|
: target.state === 'blocked' ? 'warning' : 'muted',
|
|
4119
4084
|
})),
|
|
4120
4085
|
{
|
|
4121
|
-
label: '返回位置选择',
|
|
4086
|
+
role: 'navigation', label: '返回位置选择',
|
|
4122
4087
|
run: () => {
|
|
4123
4088
|
setBatchDraft((current) => current ? { ...current, showPlacementTargets: false } : current);
|
|
4124
4089
|
restoreActionFocus('batch-placement-details');
|
|
@@ -4137,35 +4102,26 @@ export function ConsoleAppV4(props) {
|
|
|
4137
4102
|
help = batchDraft?.showPlacementTargets
|
|
4138
4103
|
? '↑↓ 查看全部位置 · Esc 返回位置选择'
|
|
4139
4104
|
: maintenanceMode
|
|
4140
|
-
? '↑↓ 移动 · Enter
|
|
4105
|
+
? '↑↓ 移动 · Enter 选择· c 查看确认 · Esc 返回修改'
|
|
4141
4106
|
: '↑↓ 移动 · Enter 选择 · Esc 返回修改';
|
|
4142
4107
|
const placementDetail = Boolean(batchDraft?.showPlacementTargets);
|
|
4143
|
-
const viewport = actionViewport(actions, placementDetail ? false : policy.mode === 'compact', focus, scrollOffset, pageActionBudget(maintenanceMode ?
|
|
4108
|
+
const viewport = actionViewport(actions, placementDetail ? false : policy.mode === 'compact', focus, scrollOffset, pageActionBudget(maintenanceMode ? 4 : 1));
|
|
4144
4109
|
if (maintenanceMode) {
|
|
4145
4110
|
const targetOffset = Math.min(viewport.offset, maintenanceTargetCount);
|
|
4146
4111
|
const targetLimit = Math.max(0, Math.min(maintenanceTargetCount, viewport.offset + viewport.limit) - targetOffset);
|
|
4147
4112
|
const actionOffset = Math.max(0, viewport.offset - maintenanceTargetCount);
|
|
4148
4113
|
const actionLimit = Math.max(0, Math.min(actions.length - maintenanceTargetCount, viewport.offset + viewport.limit - maintenanceTargetCount) - actionOffset);
|
|
4149
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(
|
|
4150
|
-
id: pinnedActions[0].actionId,
|
|
4151
|
-
label: pinnedActions[0].label,
|
|
4152
|
-
disabled: Boolean(pinnedActions[0].disabled),
|
|
4153
|
-
}], active: focusZone === 'actions', focus: pinnedActionFocus }), _jsx(SectionCard, { title: "\u5904\u7406\u8303\u56F4", meta: `${maintenanceSelection.size} 个位置`, compact: true, children: targetLimit > 0 ? _jsx(SemanticRows, { actions: actions.slice(0, maintenanceTargetCount), focus: focus, kind: "toggle", compact: true, offset: targetOffset, limit: targetLimit }) : null }), actionLimit > 0 ? _jsx(SemanticRows, { actions: actions.slice(maintenanceTargetCount), focus: focus - maintenanceTargetCount, kind: "action", compact: policy.mode === 'compact', offset: actionOffset, limit: actionLimit }) : null] });
|
|
4114
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "\u5904\u7406\u8303\u56F4", meta: `${maintenanceSelection.size} 个位置`, compact: true, children: targetLimit > 0 ? _jsx(SemanticRows, { actions: actions.slice(0, maintenanceTargetCount), focus: focus, kind: "toggle", compact: true, offset: targetOffset, limit: targetLimit }) : null }), actionLimit > 0 ? _jsx(SemanticRows, { actions: actions.slice(maintenanceTargetCount), focus: focus - maintenanceTargetCount, kind: "action", compact: policy.mode === 'compact', offset: actionOffset, limit: actionLimit }) : null] });
|
|
4154
4115
|
}
|
|
4155
4116
|
else if (!placementDetail && batchDraft?.action === 'install') {
|
|
4156
|
-
content =
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
const localLimit = Math.max(0, Math.min(group.actions.length - localOffset, viewport.offset + viewport.limit - groupOffset - localOffset));
|
|
4165
|
-
if (localLimit === 0)
|
|
4166
|
-
return null;
|
|
4167
|
-
return _jsxs(Box, { flexDirection: "column", children: [group.title ? _jsx(Text, { color: tuiTheme.colors.muted, children: group.title }) : null, _jsx(SemanticRows, { actions: group.actions, focus: focusZone === 'content' ? focus - groupOffset : -1, kind: group.kind, compact: group.kind === 'choice' || policy.mode === 'compact', offset: localOffset, limit: localLimit })] }, group.title ?? 'actions');
|
|
4168
|
-
}) })] });
|
|
4117
|
+
content = _jsx(Box, { flexDirection: "column", children: _jsx(ContentViewport, { children: installPlacementGroups.map((group) => {
|
|
4118
|
+
const groupOffset = installPlacementActions.findIndex((action) => action.actionId === group.actions[0]?.actionId);
|
|
4119
|
+
const localOffset = Math.max(0, viewport.offset - groupOffset);
|
|
4120
|
+
const localLimit = Math.max(0, Math.min(group.actions.length - localOffset, viewport.offset + viewport.limit - groupOffset - localOffset));
|
|
4121
|
+
if (localLimit === 0)
|
|
4122
|
+
return null;
|
|
4123
|
+
return _jsxs(Box, { flexDirection: "column", children: [group.title ? _jsx(Text, { color: tuiTheme.colors.muted, children: group.title }) : null, _jsx(SemanticRows, { actions: group.actions, focus: focus - groupOffset, kind: group.kind, compact: group.kind === 'choice' || policy.mode === 'compact', offset: localOffset, limit: localLimit })] }, group.title ?? 'actions');
|
|
4124
|
+
}) }) });
|
|
4169
4125
|
}
|
|
4170
4126
|
else
|
|
4171
4127
|
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: placementDetail ? 'action' : 'choice', compact: placementDetail ? false : policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit });
|
|
@@ -4193,11 +4149,7 @@ export function ConsoleAppV4(props) {
|
|
|
4193
4149
|
meta: `${candidate.providerDisplayName} · ${candidate.relation === 'requested' ? '当前插件'
|
|
4194
4150
|
: candidate.relation === 'direct' ? '直接依赖插件' : '间接依赖插件'}`,
|
|
4195
4151
|
tags: _jsxs(Text, { color: tuiTheme.colors.muted, children: ["[", candidate.availableScopes.map(scopeLabel).join('、') || '范围待确认', "]", candidate.dynamic ? ' [按设置生成]' : ''] }),
|
|
4196
|
-
run: () =>
|
|
4197
|
-
name: 'portableSkillSummary',
|
|
4198
|
-
pluginId: plugin.pluginId,
|
|
4199
|
-
skillName: candidate.name,
|
|
4200
|
-
}),
|
|
4152
|
+
run: () => props.controller.togglePortableSkill(candidate.name),
|
|
4201
4153
|
}));
|
|
4202
4154
|
selectAllPortableCandidates = { actionId: 'portable-selection-select-all', label: '全选当前结果', run: () => {
|
|
4203
4155
|
for (const candidate of visibleCandidates) {
|
|
@@ -4221,63 +4173,45 @@ export function ConsoleAppV4(props) {
|
|
|
4221
4173
|
setScrollOffset(0);
|
|
4222
4174
|
} },
|
|
4223
4175
|
...(plugin.dependencySummary?.totalCount ? [{ actionId: 'portable-selection-dependencies', label: '查看依赖关系', run: () => go({ name: 'portableDependencies', pluginId: plugin.pluginId }) }] : []),
|
|
4224
|
-
{ actionId: 'portable-selection-tools-back', label: '返回 Skills 列表', run: () => {
|
|
4176
|
+
{ role: 'navigation', actionId: 'portable-selection-tools-back', label: '返回 Skills 列表', run: () => {
|
|
4225
4177
|
setPortableToolsOpen(false);
|
|
4226
4178
|
setFocus(0);
|
|
4227
4179
|
setScrollOffset(0);
|
|
4228
4180
|
} },
|
|
4229
4181
|
];
|
|
4230
|
-
const continueAction = { actionId: 'portable-selection-continue', label: `继续(${draft.selectedCount}
|
|
4182
|
+
const continueAction = { actionId: 'portable-selection-continue', label: `继续(${draft.selectedCount}) [c]`, run: continuePortableSelection };
|
|
4231
4183
|
const openToolsAction = { actionId: 'portable-selection-tools', label: '选择工具', run: () => {
|
|
4232
4184
|
setPortableToolsOpen(true);
|
|
4233
|
-
setFocusZone('content');
|
|
4234
4185
|
setFocus(0);
|
|
4235
4186
|
setScrollOffset(0);
|
|
4236
4187
|
} };
|
|
4237
|
-
|
|
4238
|
-
actions = portableToolsOpen ? selectionToolActions : candidateActions;
|
|
4239
|
-
const
|
|
4240
|
-
const viewport = showTechnical
|
|
4241
|
-
? { offset: focus < visibleCandidates.length ? focus : candidateViewport.offset, limit: 1 }
|
|
4242
|
-
: candidateViewport;
|
|
4243
|
-
const visibleCandidateEntries = visibleCandidates
|
|
4244
|
-
.map((candidate, index) => ({ candidate, action: candidateActions[index], index }))
|
|
4245
|
-
.slice(viewport.offset, viewport.offset + viewport.limit);
|
|
4188
|
+
bottomActions = [continueAction, openToolsAction];
|
|
4189
|
+
actions = portableToolsOpen ? selectionToolActions : [...candidateActions, ...bottomActions];
|
|
4190
|
+
const visibleCandidateEntries = visibleCandidates.map((candidate, index) => ({ candidate, index }));
|
|
4246
4191
|
const variantCandidates = portableVariantCandidates;
|
|
4247
4192
|
const focusedVariant = variantCandidates.find((candidate) => candidate.name === visibleCandidates[focus]?.name);
|
|
4248
4193
|
const visibleVariant = visibleCandidateEntries.find((entry) => portableScopeVariantsDiffer(entry.candidate))?.candidate;
|
|
4249
4194
|
const technicalVariant = focusedVariant ?? visibleVariant ?? variantCandidates[0];
|
|
4250
|
-
help = portableToolsOpen
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
: _jsx(Callout, { status: "warning", title: `! ${variantCandidates.length} 个 Skill 在不同安装范围会生成不同内容。选择范围后会重新确认最终内容。` })
|
|
4263
|
-
: null, !portableToolsOpen && visibleCandidates.length === 0
|
|
4264
|
-
? _jsx(StaticRow, { title: "\u6CA1\u6709\u5DF2\u9009 Skill", description: "\u9009\u62E9\u201C\u67E5\u770B\u5168\u90E8\u5019\u9009\u201D\u540E\u53EF\u7EE7\u7EED\u52FE\u9009", status: "muted", compact: true })
|
|
4265
|
-
: null, !portableToolsOpen && !draft.canContinue
|
|
4266
|
-
? _jsx(StaticRow, { title: "\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A Skill", status: "warning", compact: true })
|
|
4267
|
-
: null, !portableToolsOpen && showTechnical && technicalVariant ? _jsxs(TechnicalDetails, { title: "\u8303\u56F4\u53D8\u4F53", children: [_jsx(StaticRow, { title: `${technicalVariant.name} · ${portableScopeVariantLabel('project', technicalVariant.scopeDetails.project)}`, compact: true }, `${technicalVariant.name}:project`), _jsx(StaticRow, { title: `${technicalVariant.name} · ${portableScopeVariantLabel('user', technicalVariant.scopeDetails.user)}`, compact: true }, `${technicalVariant.name}:user`), variantCandidates.length > 1 ? _jsx(StaticRow, { title: `另有 ${variantCandidates.length - 1} 个 Skill 的范围变体已折叠`, status: "muted", compact: true }) : null] }) : null] })] });
|
|
4195
|
+
help = portableToolsOpen ? '↑↓ 移动 · Enter 选择 · Esc 返回'
|
|
4196
|
+
: '↑↓ 移动 · Space/Enter 切换 · Esc 返回';
|
|
4197
|
+
content = _jsx(Box, { flexDirection: "column", children: _jsxs(ContentViewport, { children: [_jsx(SequenceRows, { actions: actions, itemCount: portableToolsOpen ? 0 : candidateActions.length, focus: focus, scrollOffset: scrollOffset, columns: size.columns - 2, rowBudget: pageActionBudget((variantCandidates.length > 0 ? 3 : 0) + (!draft.canContinue ? 1 : 0)
|
|
4198
|
+
+ (showTechnical && technicalVariant ? 5 : 0)), compact: policy.mode === 'compact', cards: true, inactive: portableEmptySelectionOpen }), !portableToolsOpen && variantCandidates.length > 0
|
|
4199
|
+
? showTechnical
|
|
4200
|
+
? _jsx(StaticRow, { title: `! ${variantCandidates.length} 个 Skill 存在范围变体`, status: "warning", compact: true })
|
|
4201
|
+
: _jsx(Callout, { status: "warning", title: `! ${variantCandidates.length} 个 Skill 在不同安装范围会生成不同内容。选择范围后会重新确认最终内容。` })
|
|
4202
|
+
: null, !portableToolsOpen && visibleCandidates.length === 0
|
|
4203
|
+
? _jsx(StaticRow, { title: "\u6CA1\u6709\u5DF2\u9009 Skill", description: "\u9009\u62E9\u201C\u67E5\u770B\u5168\u90E8\u5019\u9009\u201D\u540E\u53EF\u7EE7\u7EED\u52FE\u9009", status: "muted", compact: true })
|
|
4204
|
+
: null, !portableToolsOpen && !draft.canContinue
|
|
4205
|
+
? _jsx(StaticRow, { title: "\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A Skill", status: "warning", compact: true })
|
|
4206
|
+
: null, !portableToolsOpen && showTechnical && technicalVariant ? _jsxs(TechnicalDetails, { title: "\u8303\u56F4\u53D8\u4F53", children: [_jsx(StaticRow, { title: `${technicalVariant.name} · ${portableScopeVariantLabel('project', technicalVariant.scopeDetails.project)}`, compact: true }, `${technicalVariant.name}:project`), _jsx(StaticRow, { title: `${technicalVariant.name} · ${portableScopeVariantLabel('user', technicalVariant.scopeDetails.user)}`, compact: true }, `${technicalVariant.name}:user`), variantCandidates.length > 1 ? _jsx(StaticRow, { title: `另有 ${variantCandidates.length - 1} 个 Skill 的范围变体已折叠`, status: "muted", compact: true }) : null] }) : null] }) });
|
|
4268
4207
|
}
|
|
4269
|
-
else if (route.name === '
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
{ label: '返回 Skill 选择', run: back },
|
|
4277
|
-
{ label: '继续选择 Agent', disabled: snapshot.portableDraft.canContinue ? undefined : '至少选择一个 Skill', run: () => go({ name: 'portableAgentMode', pluginId: plugin.pluginId }) },
|
|
4278
|
-
];
|
|
4279
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { title: "\u5185\u5BB9\u6458\u8981", children: [_jsx(StaticRow, { title: "\u6240\u5C5E\u63D2\u4EF6", meta: candidate?.providerDisplayName ?? '未知', compact: true }), _jsx(StaticRow, { title: "\u751F\u6210\u65B9\u5F0F", meta: candidate?.dynamic ? '按当前插件设置生成' : '目录中的静态 Skill', compact: true }), _jsx(StaticRow, { title: "\u53EF\u7528\u8303\u56F4", meta: candidate?.availableScopes.map(scopeLabel).join('、') ?? '未确认', compact: true })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
4280
|
-
help = '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
4208
|
+
else if (route.name === 'portablePreparing' && plugin) {
|
|
4209
|
+
breadcrumb = `${plugin.displayName} / 通用 Skills`;
|
|
4210
|
+
context = '只读检查';
|
|
4211
|
+
title = '正在准备可安装的 Skills';
|
|
4212
|
+
description = '正在检查当前项目和所有项目范围的完整依赖。此步骤不会写入文件或调用 Skills CLI。';
|
|
4213
|
+
content = _jsx(Box, { flexDirection: "column", children: _jsxs(StatusCard, { status: "info", title: "\u51C6\u5907\u5019\u9009", children: [_jsx(StaticRow, { title: "\u25CF \u68C0\u67E5\u5F53\u524D\u9879\u76EE\u8303\u56F4", compact: true }), _jsx(StaticRow, { title: "\u25CF \u68C0\u67E5\u6240\u6709\u9879\u76EE\u8303\u56F4", compact: true }), _jsx(StaticRow, { title: "\u25CB \u5408\u5E76\u53EF\u9009 Skill \u4E0E Agent \u4FE1\u606F", status: "muted", compact: true })] }) });
|
|
4214
|
+
help = 'Esc 取消检查并返回目标平台';
|
|
4281
4215
|
}
|
|
4282
4216
|
else if (route.name === 'portableDependencies' && plugin && snapshot.portableDraft) {
|
|
4283
4217
|
const overview = dependencyOverview(plugin);
|
|
@@ -4286,14 +4220,19 @@ export function ConsoleAppV4(props) {
|
|
|
4286
4220
|
title = '生成这些候选 Skills 需要的插件';
|
|
4287
4221
|
description = '插件依赖用于生成,不能在这里取消。';
|
|
4288
4222
|
actions = [
|
|
4289
|
-
{ label: '返回 Skill 选择', run: back },
|
|
4223
|
+
{ role: 'navigation', label: '返回 Skill 选择', run: back },
|
|
4290
4224
|
{ label: showTechnical ? '隐藏技术详情' : '技术详情', run: () => toggleTechnical() },
|
|
4291
4225
|
];
|
|
4292
4226
|
const dependencies = overview?.dependencies ?? [];
|
|
4293
|
-
const
|
|
4294
|
-
const
|
|
4227
|
+
const dependencyLimit = showTechnical ? 1 : responsiveBudget(2, 3);
|
|
4228
|
+
const dependencyOffset = Math.min(batchTargetOffset, Math.max(0, dependencies.length - dependencyLimit));
|
|
4229
|
+
const visibleDependencies = dependencies.slice(dependencyOffset, dependencyOffset + dependencyLimit);
|
|
4230
|
+
const technicalDependencies = dependencies.slice(dependencyOffset, dependencyOffset + 1);
|
|
4295
4231
|
const compactTechnicalSummary = policy.mode === 'compact' && showTechnical;
|
|
4296
|
-
|
|
4232
|
+
help = dependencies.length > dependencyLimit
|
|
4233
|
+
? '↑↓ 移动 · PageUp/PageDown 或 p/n 阅读依赖 · Enter 选择 · Esc 返回'
|
|
4234
|
+
: '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
4235
|
+
content = _jsxs(Box, { flexDirection: "column", children: [compactTechnicalSummary ? _jsxs(SectionCard, { title: "provider \u6458\u8981", meta: `${dependencies.length + 1} 个`, compact: true, children: [_jsx(StaticRow, { title: plugin.displayName, meta: "\u6839 provider", compact: true }), _jsx(StaticRow, { title: `${dependencies.length} 个依赖 providers`, meta: "\u7528\u4E8E\u751F\u6210", compact: true })] }) : _jsx(SectionCard, { title: "\u5F53\u524D\u63D2\u4EF6", children: _jsx(StaticRow, { title: plugin.displayName, description: "\u63D0\u4F9B\u672C\u6B21\u5B89\u88C5\u5165\u53E3", meta: `提供 ${snapshot.portableDraft.candidates.filter((candidate) => candidate.relation === 'requested').length} 个 Skills`, compact: policy.mode === 'compact' }) }), compactTechnicalSummary ? null : _jsxs(SectionCard, { title: "\u4F9D\u8D56\u63D2\u4EF6", meta: `${dependencies.length} 个`, children: [dependencyOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${dependencyOffset} 个依赖插件`, status: "muted", compact: true }) : null, visibleDependencies.map((dependency) => _jsx(StaticRow, { title: dependency.displayName, description: `${dependency.relation === 'direct' ? '当前插件直接需要' : '由依赖插件继续需要'} · ${dependency.requiredBy.map((entry) => entry.displayName).join('、')} 需要它`, meta: `提供 ${snapshot.portableDraft.candidates.filter((candidate) => candidate.providerPluginId === dependency.pluginId).length} 个 Skills`, compact: policy.mode === 'compact' }, dependency.pluginId)), dependencies.length > dependencyOffset + visibleDependencies.length ? _jsx(StaticRow, { title: `↓ 后面还有 ${dependencies.length - dependencyOffset - visibleDependencies.length} 个依赖插件`, status: "muted", compact: true }) : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true }), showTechnical ? _jsx(TechnicalDetails, { children: technicalDependencies.map((entry) => _jsx(StaticRow, { title: entry.displayName, meta: entry.pluginId, compact: true }, entry.pluginId)) }) : null] });
|
|
4297
4236
|
}
|
|
4298
4237
|
else if (route.name === 'portableAgentMode' && plugin && snapshot.portableDraft) {
|
|
4299
4238
|
breadcrumb = `${plugin.displayName} / 通用 Skills / Agent`;
|
|
@@ -4357,13 +4296,26 @@ export function ConsoleAppV4(props) {
|
|
|
4357
4296
|
setScrollOffset(0);
|
|
4358
4297
|
} }] : []),
|
|
4359
4298
|
{ label: '重新检查', run: () => beginPortable(plugin.pluginId) },
|
|
4299
|
+
...(route.operationRecordId ? [{
|
|
4300
|
+
label: '查看诊断与报告',
|
|
4301
|
+
description: `安全记录 ${route.operationRecordId}`,
|
|
4302
|
+
run: () => go({ name: 'operationDiagnostic', recordId: route.operationRecordId }),
|
|
4303
|
+
}] : []),
|
|
4360
4304
|
{ label: snapshot.installPlacementDraft?.pluginId === plugin.pluginId ? '返回目标平台' : '返回插件详情', run: () => props.controller.resetPortableFlowToPreview(plugin.pluginId) },
|
|
4361
4305
|
...(cliUnavailable
|
|
4362
4306
|
? []
|
|
4363
4307
|
: [{ label: showTechnical ? '返回问题摘要' : '技术详情', run: () => toggleTechnical() }]),
|
|
4364
4308
|
];
|
|
4309
|
+
const technicalPageRows = responsiveBudget(2, 4);
|
|
4310
|
+
if (showTechnical && !showPortableRequirements) {
|
|
4311
|
+
referenceDetailPagination = {
|
|
4312
|
+
total: diagnosticDetailLines(diagnostic, size.columns - 6).length,
|
|
4313
|
+
pageRows: technicalPageRows,
|
|
4314
|
+
};
|
|
4315
|
+
help = 'p/n 或 PgUp/PgDn 阅读技术字段 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
4316
|
+
}
|
|
4365
4317
|
const blockerActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(2, 4));
|
|
4366
|
-
content = _jsxs(Box, { flexDirection: "column", children: [showPortableRequirements ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u5728 PATH \u4E2D\u63D0\u4F9B\u517C\u5BB9\u7684 skills \u53EF\u6267\u884C\u6587\u4EF6\u3002", compact: true }), _jsx(StaticRow, { title: `当前 AW adapter 支持:${SKILLS_CLI_SUPPORTED_VERSION_LABEL}`, compact: true }), _jsx(StaticRow, { title: "\u51C6\u5907\u5B8C\u6210\u540E\u8FD4\u56DE\u95EE\u9898\u6458\u8981\u5E76\u91CD\u65B0\u68C0\u67E5\u3002", compact: true }), _jsx(StaticRow, { title: "\u4E0D\u4F1A\u81EA\u52A8\u8FD0\u884C npx latest\u3001sudo \u6216\u5728\u7EBF\u5B89\u88C5\u811A\u672C\u3002", status: "warning", compact: true }), _jsx(StaticRow, { title: "\u9009\u5B9A\u63D2\u4EF6\u3001\u5B89\u88C5\u76EE\u6807\u548C Portable \u8349\u7A3F\u4FDD\u6301\u4E0D\u53D8\u3002", status: "success", compact: true }), _jsx(StaticRow, { title: "AW \u4E0D\u4F1A\u5728\u6B64\u9875\u5B89\u88C5\u5916\u90E8\u4F9D\u8D56\u3002", status: "warning", compact: true })] }) : _jsx(DiagnosticSummary, { diagnostic: diagnostic, technical: showTechnical, compact: policy.mode === 'compact' }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: blockerActionViewport.offset, limit: blockerActionViewport.limit })] });
|
|
4318
|
+
content = _jsxs(Box, { flexDirection: "column", children: [showPortableRequirements ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u5728 PATH \u4E2D\u63D0\u4F9B\u517C\u5BB9\u7684 skills \u53EF\u6267\u884C\u6587\u4EF6\u3002", compact: true }), _jsx(StaticRow, { title: `当前 AW adapter 支持:${SKILLS_CLI_SUPPORTED_VERSION_LABEL}`, compact: true }), _jsx(StaticRow, { title: "\u51C6\u5907\u5B8C\u6210\u540E\u8FD4\u56DE\u95EE\u9898\u6458\u8981\u5E76\u91CD\u65B0\u68C0\u67E5\u3002", compact: true }), _jsx(StaticRow, { title: "\u4E0D\u4F1A\u81EA\u52A8\u8FD0\u884C npx latest\u3001sudo \u6216\u5728\u7EBF\u5B89\u88C5\u811A\u672C\u3002", status: "warning", compact: true }), _jsx(StaticRow, { title: "\u9009\u5B9A\u63D2\u4EF6\u3001\u5B89\u88C5\u76EE\u6807\u548C Portable \u8349\u7A3F\u4FDD\u6301\u4E0D\u53D8\u3002", status: "success", compact: true }), _jsx(StaticRow, { title: "AW \u4E0D\u4F1A\u5728\u6B64\u9875\u5B89\u88C5\u5916\u90E8\u4F9D\u8D56\u3002", status: "warning", compact: true })] }) : _jsx(DiagnosticSummary, { diagnostic: diagnostic, technical: showTechnical, columns: size.columns, offset: showTechnical ? batchTargetOffset : undefined, limit: showTechnical ? technicalPageRows : undefined, compact: policy.mode === 'compact' }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: blockerActionViewport.offset, limit: blockerActionViewport.limit })] });
|
|
4367
4319
|
}
|
|
4368
4320
|
else if (route.name === 'pluginDependencies' && plugin) {
|
|
4369
4321
|
const overview = dependencyOverview(plugin);
|
|
@@ -4392,7 +4344,7 @@ export function ConsoleAppV4(props) {
|
|
|
4392
4344
|
setFocus(0);
|
|
4393
4345
|
setScrollOffset(0);
|
|
4394
4346
|
} },
|
|
4395
|
-
{ label: '返回插件详情', run: back },
|
|
4347
|
+
{ role: 'navigation', label: '返回插件详情', run: back },
|
|
4396
4348
|
{ label: showTechnical ? '隐藏技术详情' : '技术详情', run: () => toggleTechnical() },
|
|
4397
4349
|
];
|
|
4398
4350
|
const blockedRemovalPagination = !showTechnical && visibleDependents.length > dependentLimit
|
|
@@ -4582,7 +4534,7 @@ export function ConsoleAppV4(props) {
|
|
|
4582
4534
|
pageRows,
|
|
4583
4535
|
move: (direction) => moveBatchTargetPage(detailLines.length, pageRows, direction),
|
|
4584
4536
|
}),
|
|
4585
|
-
{ label: '返回节点详情', run: back },
|
|
4537
|
+
{ role: 'navigation', label: '返回节点详情', run: back },
|
|
4586
4538
|
];
|
|
4587
4539
|
content = _jsxs(Box, { flexDirection: "column", children: [detailOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${detailOffset} 行`, status: "muted", compact: true }) : null, visibleDetailLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${detailOffset + index}:${line}`)), detailOffset + visibleDetailLines.length < detailLines.length
|
|
4588
4540
|
? _jsx(StaticRow, { title: `↓ 后面还有 ${detailLines.length - detailOffset - visibleDetailLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
|
|
@@ -4633,7 +4585,7 @@ export function ConsoleAppV4(props) {
|
|
|
4633
4585
|
...(showTechnical && referenceActions[selectedReferenceIndex]
|
|
4634
4586
|
? [referenceActions[selectedReferenceIndex]] : referenceActions),
|
|
4635
4587
|
...referencePaginationActions,
|
|
4636
|
-
{ label: '返回节点详情', run: back },
|
|
4588
|
+
{ role: 'navigation', label: '返回节点详情', run: back },
|
|
4637
4589
|
];
|
|
4638
4590
|
const referenceViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(3, 6));
|
|
4639
4591
|
help = showTechnical
|
|
@@ -4668,7 +4620,7 @@ export function ConsoleAppV4(props) {
|
|
|
4668
4620
|
go({ ...route, view: 'details' });
|
|
4669
4621
|
},
|
|
4670
4622
|
},
|
|
4671
|
-
{ label: '返回关系图', run: back },
|
|
4623
|
+
{ role: 'navigation', label: '返回关系图', run: back },
|
|
4672
4624
|
];
|
|
4673
4625
|
const nodeActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(2, 4));
|
|
4674
4626
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { title: "\u8282\u70B9\u72B6\u6001", children: [_jsx(StaticRow, { title: "\u7528\u9014", value: node?.description ?? '当前目录没有用途说明', compact: true }), _jsx(StaticRow, { title: "\u4E3A\u4F55\u9700\u8981", value: description, compact: true }), _jsx(StaticRow, { title: "\u5F71\u54CD", value: state?.value ?? (node ? statusText(node) : '尚未检查当前状态'), status: state?.status ?? 'muted', compact: true }), references.length > 0
|
|
@@ -4705,7 +4657,7 @@ export function ConsoleAppV4(props) {
|
|
|
4705
4657
|
description = '根插件或必需依赖不支持当前目标平台组合,因此不会进入确认页。';
|
|
4706
4658
|
actions = [
|
|
4707
4659
|
{ label: '查看依赖关系', run: () => go({ name: 'pluginDependencies', pluginId: plugin.pluginId }) },
|
|
4708
|
-
{ label: '返回插件详情', run: back },
|
|
4660
|
+
{ role: 'navigation', label: '返回插件详情', run: back },
|
|
4709
4661
|
];
|
|
4710
4662
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: "warning", title: "\u6240\u9009\u76EE\u6807\u5E73\u53F0\u4E0D\u53EF\u7528", children: choices.map((choice) => _jsx(StaticRow, { title: `${platformLabel(choice.platform)} · ${choice.disabled ? `不可选 · ${choice.disabled}` : '不可选'}`, status: "muted", compact: policy.mode === 'compact' }, choice.platform)) }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
4711
4663
|
}
|
|
@@ -4781,26 +4733,16 @@ export function ConsoleAppV4(props) {
|
|
|
4781
4733
|
};
|
|
4782
4734
|
const confirmAction = {
|
|
4783
4735
|
actionId: 'confirm-install-platforms',
|
|
4784
|
-
label: '确定所选平台',
|
|
4736
|
+
label: '确定所选平台 [c]',
|
|
4785
4737
|
disabled: validSelectedTargets.length === 0 ? '至少选择一个目标平台' : undefined,
|
|
4786
4738
|
run: confirmNativePlatforms,
|
|
4787
4739
|
};
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
const installTargetStaticRows = (validSelectedTargets.length === 0 ? 2 : 1)
|
|
4795
|
-
+ (policy.mode === 'compact' ? 4 : 0);
|
|
4796
|
-
const platformViewport = objectCardActionViewport(actions, cardWidth, policy.mode === 'compact', focus, scrollOffset, Math.max(1, pageActionBudget(installTargetStaticRows)));
|
|
4797
|
-
help = '↑↓ 移动 · Enter/Space 勾选平台 · Enter 打开通用 Skills · Tab 操作栏 · c 继续 · Esc 返回';
|
|
4798
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(PinnedActionBar, { actions: pinnedActions.map((action) => ({
|
|
4799
|
-
id: action.actionId, label: action.label, disabled: Boolean(action.disabled),
|
|
4800
|
-
})), active: focusZone === 'actions', focus: pinnedActionFocus }), validSelectedTargets.length === 0
|
|
4801
|
-
? _jsx(Text, { color: tuiTheme.colors.muted, children: "\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u76EE\u6807\u5E73\u53F0" }) : null, _jsx(ContentViewport, { children: actions.slice(platformViewport.offset, platformViewport.offset + platformViewport.limit)
|
|
4802
|
-
.map((action, visibleIndex) => _jsx(ObjectCardRow, { width: cardWidth, title: action.actionId?.startsWith('install-platform-')
|
|
4803
|
-
? `${action.selected ? '[x]' : '[ ]'} ${action.label}` : action.label, description: action.disabled ?? action.description ?? '', tags: action.tags, focused: focusZone === 'content' && platformViewport.offset + visibleIndex === focus, anchored: focusZone !== 'content' && platformViewport.offset + visibleIndex === focus, compact: policy.mode === 'compact' }, action.actionId)) })] });
|
|
4740
|
+
actions = [...nativeActions, portableAction, confirmAction];
|
|
4741
|
+
bottomActions = [confirmAction];
|
|
4742
|
+
help = '↑↓ 移动 · Enter/Space 选择 · Esc 返回';
|
|
4743
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions.slice(0, nativeActions.length).map((action) => ({
|
|
4744
|
+
...action, label: `${action.selected ? '[x]' : '[ ]'} ${action.label}`,
|
|
4745
|
+
})), focus: focus, kind: "action", compact: false }), _jsx(SemanticRows, { actions: actions, focus: focus, offset: nativeActions.length, kind: "action", compact: false })] });
|
|
4804
4746
|
}
|
|
4805
4747
|
}
|
|
4806
4748
|
else if (route.name === 'installPlacement' && plugin) {
|
|
@@ -4860,7 +4802,7 @@ export function ConsoleAppV4(props) {
|
|
|
4860
4802
|
scope: exactTargets[0].scope,
|
|
4861
4803
|
}),
|
|
4862
4804
|
},
|
|
4863
|
-
{ label: '返回目标平台', run: back },
|
|
4805
|
+
{ role: 'navigation', label: '返回目标平台', run: back },
|
|
4864
4806
|
];
|
|
4865
4807
|
}
|
|
4866
4808
|
const scopeChoiceCount = commonScopes.length > 0 ? actions.length : Math.max(0, actions.length - 2);
|
|
@@ -4920,7 +4862,7 @@ export function ConsoleAppV4(props) {
|
|
|
4920
4862
|
});
|
|
4921
4863
|
},
|
|
4922
4864
|
},
|
|
4923
|
-
{ label: '返回插件详情', run: back },
|
|
4865
|
+
{ role: 'navigation', label: '返回插件详情', run: back },
|
|
4924
4866
|
];
|
|
4925
4867
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "toggle", compact: policy.mode === 'compact', limit: targetActions.length + 1 }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: targetActions.length + 1 })] });
|
|
4926
4868
|
help = '↑↓ 移动 · Enter 选择/继续 · Esc 返回';
|
|
@@ -4958,7 +4900,7 @@ export function ConsoleAppV4(props) {
|
|
|
4958
4900
|
description: '恢复依赖自动安排的建议位置',
|
|
4959
4901
|
run: () => props.controller.resetDependencyScopes(),
|
|
4960
4902
|
},
|
|
4961
|
-
{ label: '返回目标平台', run: back },
|
|
4903
|
+
{ role: 'navigation', label: '返回目标平台', run: back },
|
|
4962
4904
|
];
|
|
4963
4905
|
const placementViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(dependencyPlacementStaticRows));
|
|
4964
4906
|
const userCount = draft?.targets.filter((target) => target.scope === 'user').length ?? 0;
|
|
@@ -5207,7 +5149,7 @@ export function ConsoleAppV4(props) {
|
|
|
5207
5149
|
setScrollOffset(0);
|
|
5208
5150
|
},
|
|
5209
5151
|
}] : []),
|
|
5210
|
-
{ label: route.recommendedPluginIds ? '返回调整选择' : '返回插件详情', run: back },
|
|
5152
|
+
{ role: 'navigation', label: route.recommendedPluginIds ? '返回调整选择' : '返回插件详情', run: back },
|
|
5211
5153
|
];
|
|
5212
5154
|
const taskTargetLimit = policy.mode === 'compact' ? 3 : 6;
|
|
5213
5155
|
const taskTargetOffset = Math.min(batchTargetOffset, Math.max(0, candidates.length - 1));
|
|
@@ -5243,7 +5185,7 @@ export function ConsoleAppV4(props) {
|
|
|
5243
5185
|
? plugin.version && plugin.version !== installedVersions[0]
|
|
5244
5186
|
? `${installedVersions[0]} → ${plugin.version}`
|
|
5245
5187
|
: `已安装 ${installedVersions[0]}`
|
|
5246
|
-
: plugin.version
|
|
5188
|
+
: plugin.version ?? '待确认';
|
|
5247
5189
|
context = `${plugin.sourceLabel} · ${versionSummary}`;
|
|
5248
5190
|
const updateTaskCandidates = plugin.configOnly ? []
|
|
5249
5191
|
: props.controller.listPluginWriteTaskCandidates('update')
|
|
@@ -5357,18 +5299,20 @@ export function ConsoleAppV4(props) {
|
|
|
5357
5299
|
actionId: 'content',
|
|
5358
5300
|
label: '内容详情',
|
|
5359
5301
|
description: contentOverview
|
|
5360
|
-
? `${contentOverview.items.length}
|
|
5302
|
+
? `${contentOverview.items.length} 项当前目录内容`
|
|
5361
5303
|
: '打开时读取当前目录版本的内容',
|
|
5362
5304
|
run: () => go({ name: 'pluginContent', pluginId: plugin.pluginId }),
|
|
5363
5305
|
} : undefined;
|
|
5364
5306
|
const dependencyOverviewForDetail = dependencyOverview(plugin);
|
|
5365
|
-
const dependencyAction =
|
|
5366
|
-
&& (dependencyOverviewForDetail.dependencies.length > 0
|
|
5367
|
-
|| dependencyOverviewForDetail.dependents.length > 0
|
|
5368
|
-
|| dependencyOverviewForDetail.blockers.length > 0) ? {
|
|
5307
|
+
const dependencyAction = !plugin.configOnly ? {
|
|
5369
5308
|
actionId: 'dependencies',
|
|
5370
5309
|
label: '依赖关系',
|
|
5371
|
-
description:
|
|
5310
|
+
description: dependencyOverviewForDetail
|
|
5311
|
+
&& (dependencyOverviewForDetail.dependencies.length > 0
|
|
5312
|
+
|| dependencyOverviewForDetail.dependents.length > 0
|
|
5313
|
+
|| dependencyOverviewForDetail.blockers.length > 0)
|
|
5314
|
+
? '在同一关系图中查看使用者和所需插件'
|
|
5315
|
+
: '当前没有已声明的所需插件或使用者',
|
|
5372
5316
|
run: () => go({ name: 'pluginDependencies', pluginId: plugin.pluginId }),
|
|
5373
5317
|
} : undefined;
|
|
5374
5318
|
const uninstallAction = installed ? {
|
|
@@ -5396,6 +5340,17 @@ export function ConsoleAppV4(props) {
|
|
|
5396
5340
|
...(installAction ? [installAction] : []),
|
|
5397
5341
|
...(settingsAction ? [{ ...settingsAction, actionId: 'settings' }] : []),
|
|
5398
5342
|
...(contentAction ? [contentAction] : []),
|
|
5343
|
+
{
|
|
5344
|
+
actionId: 'full-description',
|
|
5345
|
+
label: '完整基本信息',
|
|
5346
|
+
description: '阅读未截断的用途和平台状态',
|
|
5347
|
+
run: () => {
|
|
5348
|
+
setShowTechnical(true);
|
|
5349
|
+
setBatchTargetOffset(0);
|
|
5350
|
+
setFocus(0);
|
|
5351
|
+
setScrollOffset(0);
|
|
5352
|
+
},
|
|
5353
|
+
},
|
|
5399
5354
|
...(dependencyAction ? [dependencyAction] : []),
|
|
5400
5355
|
...(uninstallAction ? [uninstallAction] : []),
|
|
5401
5356
|
{
|
|
@@ -5412,123 +5367,81 @@ export function ConsoleAppV4(props) {
|
|
|
5412
5367
|
const detailPositions = plugin.installedPlacements
|
|
5413
5368
|
.filter((placement) => placement.state !== 'notInstalled')
|
|
5414
5369
|
.map((placement) => `${platformLabel(placement.platform)}:${pluginPlacementConclusions(placement).map((entry) => entry.text).join(' · ')}`);
|
|
5415
|
-
const
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5370
|
+
const platformSummary = detailPositions.length > 0
|
|
5371
|
+
? detailPositions.join(';')
|
|
5372
|
+
: plugin.supportedPlatforms.length > 0
|
|
5373
|
+
? `${plugin.supportedPlatforms.map(platformLabel).join('、')} · 尚未安装`
|
|
5374
|
+
: '当前没有可用平台';
|
|
5375
|
+
context = '插件详情';
|
|
5376
|
+
const completeDescriptionLines = [
|
|
5377
|
+
'用途',
|
|
5378
|
+
...wrapConsoleText(plugin.description, Math.max(12, size.columns - 8)).map((line) => ` ${line}`),
|
|
5379
|
+
...wrapConsoleText(`版本 · ${versionSummary}`, Math.max(12, size.columns - 8)),
|
|
5380
|
+
...wrapConsoleText(`来源 · ${plugin.sourceLabel}`, Math.max(12, size.columns - 8)),
|
|
5381
|
+
'平台状态',
|
|
5382
|
+
...(detailPositions.length > 0 ? detailPositions : [platformSummary])
|
|
5383
|
+
.flatMap((line) => wrapConsoleText(line, Math.max(12, size.columns - 8)))
|
|
5384
|
+
.map((line) => ` ${line}`),
|
|
5385
|
+
];
|
|
5386
|
+
if (showTechnical) {
|
|
5387
|
+
const descriptionPageRows = responsiveBudget(5, 10);
|
|
5388
|
+
const descriptionOffset = Math.min(batchTargetOffset, Math.max(0, completeDescriptionLines.length - 1));
|
|
5389
|
+
const visibleDescriptionLines = completeDescriptionLines.slice(descriptionOffset, descriptionOffset + descriptionPageRows);
|
|
5390
|
+
breadcrumb = `插件 / ${plugin.displayName} / 完整基本信息`;
|
|
5391
|
+
context = `${descriptionOffset + 1}–${descriptionOffset + visibleDescriptionLines.length} / ${completeDescriptionLines.length}`;
|
|
5392
|
+
title = '完整基本信息';
|
|
5393
|
+
description = '以下是未截断的插件用途和已检查平台状态。';
|
|
5394
|
+
actions = [
|
|
5395
|
+
...paginationActions({
|
|
5396
|
+
offset: descriptionOffset,
|
|
5397
|
+
total: completeDescriptionLines.length,
|
|
5398
|
+
pageRows: descriptionPageRows,
|
|
5399
|
+
move: (direction) => moveBatchTargetPage(completeDescriptionLines.length, descriptionPageRows, direction),
|
|
5400
|
+
}),
|
|
5401
|
+
{ role: 'navigation', label: '返回插件详情', run: () => toggleTechnical() },
|
|
5402
|
+
];
|
|
5403
|
+
referenceDetailPagination = {
|
|
5404
|
+
total: completeDescriptionLines.length,
|
|
5405
|
+
pageRows: descriptionPageRows,
|
|
5406
|
+
};
|
|
5407
|
+
const descriptionActionViewport = actionViewport(actions, true, focus, scrollOffset, pageActionBudget(visibleDescriptionLines.length + 2));
|
|
5408
|
+
help = 'p/n 或 PgUp/PgDn 阅读 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
5409
|
+
content = _jsxs(Box, { flexDirection: "column", children: [descriptionOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${descriptionOffset} 行`, status: "muted", compact: true }) : null, visibleDescriptionLines.map((line, index) => _jsx(StaticRow, { title: line || ' ', compact: true }, `${descriptionOffset + index}:${line}`)), descriptionOffset + visibleDescriptionLines.length < completeDescriptionLines.length
|
|
5410
|
+
? _jsx(StaticRow, { title: `↓ 后面还有 ${completeDescriptionLines.length - descriptionOffset - visibleDescriptionLines.length} 行`, status: "muted", compact: true })
|
|
5411
|
+
: null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: descriptionActionViewport.offset, limit: descriptionActionViewport.limit })] });
|
|
5412
|
+
}
|
|
5413
|
+
else {
|
|
5414
|
+
const detailExtraRows = (updateDescription ? 1 : 0) + (dependencyDetailText ? 1 : 0)
|
|
5415
|
+
+ (snapshot.completionNotice?.pluginId === plugin.pluginId ? 4 : 0);
|
|
5416
|
+
currentActionViewportLineBudget = pageActionBudget(detailExtraRows + 4 + Number(Boolean(plugin.portableSkills)) + Number(Boolean(plugin.configOnly)));
|
|
5417
|
+
const detailViewport = actionViewport(actions, true, focus, scrollOffset, currentActionViewportLineBudget);
|
|
5418
|
+
content = _jsxs(Box, { flexDirection: "column", children: [snapshot.completionNotice?.pluginId === plugin.pluginId
|
|
5419
|
+
? _jsx(Callout, { status: "success", title: snapshot.completionNotice.title, description: snapshot.completionNotice.description })
|
|
5420
|
+
: null, _jsx(StaticRow, { title: plugin.description, compact: true }), _jsx(StaticRow, { title: `版本 · ${versionSummary}`, compact: true }), _jsx(StaticRow, { title: `来源 · ${plugin.sourceLabel}`, compact: true }), _jsx(StaticRow, { title: platformSummary, compact: true }), plugin.portableSkills ? _jsx(Text, { color: tuiTheme.colors.accent, children: "[Skills \u53EF\u9009]" }) : null, plugin.configOnly ? _jsx(Text, { color: tuiTheme.colors.muted, children: "[\u5DF2\u4FDD\u5B58\u8BBE\u7F6E]" }) : null, updateDescription
|
|
5421
|
+
? _jsx(StaticRow, { title: "\u6709\u53EF\u7528\u66F4\u65B0", meta: updateDescription, status: "warning", compact: true })
|
|
5422
|
+
: null, dependencyDetailText ? _jsx(StaticRow, { title: dependencyDetailText, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: detailViewport.offset, limit: detailViewport.limit })] });
|
|
5423
|
+
}
|
|
5440
5424
|
}
|
|
5441
5425
|
else if (route.name === 'pluginMore' && plugin) {
|
|
5442
5426
|
breadcrumb = `插件 / ${plugin.displayName} / 更多操作`;
|
|
5443
5427
|
context = plugin.sourceLabel;
|
|
5444
5428
|
title = '更多操作';
|
|
5445
5429
|
description = '选择平台可使用同步、重新安装、移除和受限清理。';
|
|
5446
|
-
const dependencySummary = plugin.dependencySummary;
|
|
5447
|
-
const detailMenu = buildPluginDetailActions(plugin);
|
|
5448
|
-
const updateTaskCandidates = props.controller.listPluginWriteTaskCandidates('update')
|
|
5449
|
-
.filter((candidate) => candidate.target.pluginId === plugin.pluginId);
|
|
5450
|
-
const restoreTaskCandidates = props.controller.listPluginWriteTaskCandidates('restore')
|
|
5451
|
-
.filter((candidate) => candidate.target.pluginId === plugin.pluginId);
|
|
5452
5430
|
actions = [
|
|
5453
|
-
...
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
run: () => go({
|
|
5458
|
-
name: 'pluginWriteTask', pluginId: plugin.pluginId, goal: 'update',
|
|
5459
|
-
targetKeys: updateTaskCandidates.map(pluginWriteTaskTargetKey),
|
|
5460
|
-
versionEvidence: pluginWriteTaskVersionEvidence(plugin, updateTaskCandidates),
|
|
5461
|
-
}),
|
|
5462
|
-
}] : []),
|
|
5463
|
-
...(restoreTaskCandidates.length > 0 ? [{
|
|
5464
|
-
label: '恢复正常',
|
|
5465
|
-
description: `${restoreTaskCandidates.length} 个现有位置需要检查`,
|
|
5466
|
-
status: 'warning',
|
|
5467
|
-
run: () => go({
|
|
5468
|
-
name: 'pluginWriteTask', pluginId: plugin.pluginId, goal: 'restore',
|
|
5469
|
-
targetKeys: restoreTaskCandidates.map(pluginWriteTaskTargetKey),
|
|
5470
|
-
}),
|
|
5471
|
-
}] : []),
|
|
5472
|
-
...detailMenu.filter((action) => action.id !== 'refreshAndSync' && action.id !== 'about')
|
|
5473
|
-
.map((action) => {
|
|
5474
|
-
if (action.id === 'platform' || action.id === 'scopeConflict') {
|
|
5475
|
-
const placement = plugin.installedPlacements.find((entry) => entry.platform === action.platform);
|
|
5476
|
-
const projected = placementStatus(placement);
|
|
5477
|
-
return {
|
|
5478
|
-
label: `${platformLabel(action.platform)} 平台与维护`,
|
|
5479
|
-
description: `${projected.description};同步、重装、移除和清理入口`,
|
|
5480
|
-
meta: projected.value,
|
|
5481
|
-
status: projected.status,
|
|
5482
|
-
run: () => action.id === 'scopeConflict'
|
|
5483
|
-
? go({ name: 'issueDetail', issueId: `scope:${plugin.pluginId}:${action.platform}` })
|
|
5484
|
-
: go({ name: 'platform', pluginId: plugin.pluginId, platform: action.platform }),
|
|
5485
|
-
};
|
|
5486
|
-
}
|
|
5487
|
-
if (action.id === 'resolveScopeConflict')
|
|
5488
|
-
return {
|
|
5489
|
-
label: `处理 ${platformLabel(action.platform)} 位置冲突`,
|
|
5490
|
-
description: action.description,
|
|
5491
|
-
status: 'error',
|
|
5492
|
-
run: () => beginScopeConflictRecovery(action),
|
|
5493
|
-
};
|
|
5494
|
-
if (action.id === 'dependencies')
|
|
5495
|
-
return {
|
|
5496
|
-
label: '依赖与当前可用关系',
|
|
5497
|
-
description: dependencySummary?.issueCount ? `${dependencySummary.issueCount} 项需要处理` : '查看完整关系',
|
|
5498
|
-
meta: dependencySummary ? dependencySummaryText(dependencySummary) : undefined,
|
|
5499
|
-
run: () => go({ name: 'pluginDependencies', pluginId: plugin.pluginId }),
|
|
5500
|
-
};
|
|
5501
|
-
if (action.id === 'settings')
|
|
5502
|
-
return {
|
|
5503
|
-
label: plugin.configOnly ? '查看已保存设置' : '插件设置',
|
|
5504
|
-
run: () => plugin.configOnly
|
|
5505
|
-
? props.controller.beginSavedConfigRecovery(plugin.pluginId)
|
|
5506
|
-
: beginConfigFlow(plugin.pluginId),
|
|
5507
|
-
};
|
|
5508
|
-
if (action.id === 'sourceProblem')
|
|
5509
|
-
return {
|
|
5510
|
-
label: '恢复插件来源', status: 'warning',
|
|
5511
|
-
run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }),
|
|
5512
|
-
};
|
|
5513
|
-
if (action.id === 'upgradeAwCli' || action.id === 'capabilityTechnical')
|
|
5514
|
-
return {
|
|
5515
|
-
label: action.id === 'upgradeAwCli' ? '升级 AW CLI' : '查看功能支持详情',
|
|
5516
|
-
status: action.id === 'upgradeAwCli' ? 'warning' : undefined,
|
|
5517
|
-
run: () => go({ name: 'pluginTechnical', pluginId: plugin.pluginId }),
|
|
5518
|
-
};
|
|
5431
|
+
...plugin.installedPlacements
|
|
5432
|
+
.filter((placement) => placement.state !== 'notInstalled')
|
|
5433
|
+
.map((placement) => {
|
|
5434
|
+
const projected = placementStatus(placement);
|
|
5519
5435
|
return {
|
|
5520
|
-
label:
|
|
5521
|
-
|
|
5436
|
+
label: `${platformLabel(placement.platform)} 平台维护`,
|
|
5437
|
+
description: '同步、重新安装和受限清理',
|
|
5438
|
+
meta: projected.value,
|
|
5439
|
+
status: projected.status,
|
|
5440
|
+
run: () => go({ name: 'platform', pluginId: plugin.pluginId, platform: placement.platform }),
|
|
5522
5441
|
};
|
|
5523
5442
|
}),
|
|
5524
|
-
...(!detailMenu.some((action) => action.id === 'dependencies') ? [{
|
|
5525
|
-
label: '依赖与当前可用关系',
|
|
5526
|
-
description: '查看必需依赖、声明者和当前可用关系;当前没有声明的必需依赖',
|
|
5527
|
-
run: () => go({ name: 'pluginDependencies', pluginId: plugin.pluginId }),
|
|
5528
|
-
}] : []),
|
|
5529
|
-
{ label: '插件定义信息', run: () => go({ name: 'pluginAbout', pluginId: plugin.pluginId }) },
|
|
5530
5443
|
{ label: '查看插件来源', run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }) },
|
|
5531
|
-
{ label: '
|
|
5444
|
+
{ label: '诊断与技术详情', description: '查看插件身份、组件状态和安全错误代码', run: () => go({ name: 'pluginTechnical', pluginId: plugin.pluginId }) },
|
|
5532
5445
|
];
|
|
5533
5446
|
const moreViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(1));
|
|
5534
5447
|
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: moreViewport.offset, limit: moreViewport.limit });
|
|
@@ -5587,7 +5500,7 @@ export function ConsoleAppV4(props) {
|
|
|
5587
5500
|
run: () => beginSecondScope(plugin, action.platform, action.scope),
|
|
5588
5501
|
};
|
|
5589
5502
|
if (action.id === 'about')
|
|
5590
|
-
return { label: '查看支持信息', description: '插件定义与平台支持', run: () => go({ name: '
|
|
5503
|
+
return { label: '查看支持信息', description: '插件定义与平台支持', run: () => go({ name: 'pluginTechnical', pluginId: plugin.pluginId }) };
|
|
5591
5504
|
if (action.id === 'source')
|
|
5592
5505
|
return { label: '查看来源', run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }) };
|
|
5593
5506
|
if (action.id === 'outputCollision')
|
|
@@ -5645,7 +5558,7 @@ export function ConsoleAppV4(props) {
|
|
|
5645
5558
|
return typedIssue
|
|
5646
5559
|
? { label: '查看对应问题', description: typedIssue.explanation, run: () => go({ name: 'issueDetail', issueId: typedIssue.issueId }) }
|
|
5647
5560
|
: { label: placement?.state === 'installed' && placement.health === 'error' ? '查看安全技术详情' : placement?.state === 'installed' && placement.health === 'incomplete' ? '查看影响' : '查看安装详情', description: '组件与诊断信息', run: () => go({ name: 'pluginTechnical', pluginId: plugin.pluginId }) };
|
|
5648
|
-
return { label: '返回插件', run: back };
|
|
5561
|
+
return { role: 'navigation', label: '返回插件', run: back };
|
|
5649
5562
|
};
|
|
5650
5563
|
const offlineCleanupAction = typedIssue?.actions.find((action) => action.id === 'cleanup');
|
|
5651
5564
|
const offlineCleanup = typedIssue !== undefined
|
|
@@ -5790,9 +5703,7 @@ export function ConsoleAppV4(props) {
|
|
|
5790
5703
|
const candidateSummary = selectedField && selectedMutation
|
|
5791
5704
|
? selectedMutation.kind === 'unset' ? '恢复继承'
|
|
5792
5705
|
: selectedField.sensitive ? '已更新'
|
|
5793
|
-
:
|
|
5794
|
-
? objectSummary(selectedField, selectedMutation.value)
|
|
5795
|
-
: scalarSummary(selectedField, selectedMutation.value)
|
|
5706
|
+
: fieldValueText(selectedField, selectedMutation.value)
|
|
5796
5707
|
: selectedPreset && configCandidate
|
|
5797
5708
|
? `方案“${selectedPreset.title}” · ${Object.keys(configCandidate.mutations).length} 项修改`
|
|
5798
5709
|
: undefined;
|
|
@@ -5842,10 +5753,10 @@ export function ConsoleAppV4(props) {
|
|
|
5842
5753
|
const readonly = false;
|
|
5843
5754
|
breadcrumb = `${plugin.displayName} / 设置`;
|
|
5844
5755
|
title = '插件设置';
|
|
5845
|
-
description = '
|
|
5756
|
+
description = '先编辑值,再选择保存位置。←→ 切换分组。';
|
|
5846
5757
|
if (configActionError)
|
|
5847
5758
|
description = configActionError;
|
|
5848
|
-
help = '↑↓ 移动 · Enter
|
|
5759
|
+
help = '↑↓ 移动 · Enter 修改· ←→ 分组 · s 查看保存汇总 · u 恢复继承 · Esc 返回';
|
|
5849
5760
|
if (!currentConfigPage) {
|
|
5850
5761
|
content = _jsx(StatusCard, { status: "info", title: "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u8BBE\u7F6E", children: _jsx(ProgressRow, { title: "\u8BFB\u53D6\u8BBE\u7F6E\u5B57\u6BB5", state: "active" }) });
|
|
5851
5762
|
}
|
|
@@ -5871,36 +5782,24 @@ export function ConsoleAppV4(props) {
|
|
|
5871
5782
|
}))
|
|
5872
5783
|
: (activeGroup?.fields ?? []).filter((field) => readonly || configFieldCanSet(field) || configFieldCanUnset(field)).map((field) => ({
|
|
5873
5784
|
label: field.title,
|
|
5874
|
-
description: field.invalidOverrideIssue ?? [
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5785
|
+
description: field.invalidOverrideIssue ?? (focus === (activeGroup?.fields ?? []).indexOf(field)
|
|
5786
|
+
? [field.description, ...pendingFieldTargets(field).filter(() => pendingFieldTargets(field).length > 1
|
|
5787
|
+
|| field.effectiveSourceLabel === '当前项目' && pendingFieldDisplay(field, 'project') === undefined).map(({ scope, value }) => `待保存到${configLayerLabel({ scope })}:${value}`),
|
|
5788
|
+
pendingFieldDisplay(field, 'user') !== undefined
|
|
5789
|
+
&& field.effectiveSourceLabel === '当前项目'
|
|
5790
|
+
&& pendingFieldDisplay(field, 'project') === undefined
|
|
5791
|
+
? '个人默认待修改,当前项目不受此值影响' : undefined,
|
|
5792
|
+
].filter(Boolean).join(' · ') : undefined),
|
|
5879
5793
|
meta: (() => {
|
|
5880
|
-
const
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
}
|
|
5884
|
-
if (targets.length === 1) {
|
|
5885
|
-
const target = targets[0];
|
|
5886
|
-
return `${target.value} · 拟保存:${target.scope === 'project' ? '当前项目' : '个人默认'}`;
|
|
5887
|
-
}
|
|
5888
|
-
return targets.map((target) => `${target.scope === 'project' ? '当前项目' : '个人默认'}:${target.value}`).join(' · ');
|
|
5794
|
+
const project = pendingFieldDisplay(field, 'project');
|
|
5795
|
+
const user = pendingFieldDisplay(field, 'user');
|
|
5796
|
+
const pending = project ?? (field.effectiveSourceLabel === '当前项目' ? undefined : user);
|
|
5797
|
+
return `${pending ?? effectiveFieldDisplay(field)} · ${pending !== undefined ? `拟保存:${project !== undefined ? '当前项目' : '个人默认'} · 待保存` : field.effectiveSourceLabel}${pendingFieldTargets(field).length > 0 && pending === undefined ? ' · 有草稿' : ''}`;
|
|
5889
5798
|
})(),
|
|
5890
5799
|
configKey: field.key,
|
|
5891
|
-
run: () => go(
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
pluginId: plugin.pluginId,
|
|
5895
|
-
layer: mutableLayer,
|
|
5896
|
-
fieldKey: field.key,
|
|
5897
|
-
} : {
|
|
5898
|
-
name: 'configFieldEditor',
|
|
5899
|
-
pluginId: plugin.pluginId,
|
|
5900
|
-
layer: mutableLayer,
|
|
5901
|
-
fieldKey: field.key,
|
|
5902
|
-
editor: fieldEditor(field),
|
|
5903
|
-
...fieldEditorMode(field),
|
|
5800
|
+
run: () => go({
|
|
5801
|
+
name: 'configFieldEditor', pluginId: plugin.pluginId, layer: mutableLayer,
|
|
5802
|
+
fieldKey: field.key, editor: fieldEditor(field), ...fieldEditorMode(field),
|
|
5904
5803
|
}),
|
|
5905
5804
|
}));
|
|
5906
5805
|
const operationActions = [
|
|
@@ -5935,7 +5834,7 @@ export function ConsoleAppV4(props) {
|
|
|
5935
5834
|
];
|
|
5936
5835
|
const configSaveAction = {
|
|
5937
5836
|
actionId: 'config-save-summary',
|
|
5938
|
-
label: configDraftCount > 0 ? `保存设置(${configDraftCount}
|
|
5837
|
+
label: configDraftCount > 0 ? `保存设置(${configDraftCount}) [s]` : '保存设置 [s]',
|
|
5939
5838
|
description: '确认全部设置层的变化,再选择只保存或保存并应用',
|
|
5940
5839
|
status: configDraftCount > 0 ? 'success' : 'muted',
|
|
5941
5840
|
disabled: configDraftCount === 0 ? '没有待保存设置'
|
|
@@ -5946,20 +5845,18 @@ export function ConsoleAppV4(props) {
|
|
|
5946
5845
|
go({ name: 'configSave', pluginId: route.pluginId, layer: { scope: 'effective' } });
|
|
5947
5846
|
},
|
|
5948
5847
|
};
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
}
|
|
5961
|
-
pinnedActions = [configSaveAction, configGroupAction];
|
|
5962
|
-
actions = [...tabActions, ...operationActions];
|
|
5848
|
+
bottomActions = [configSaveAction, {
|
|
5849
|
+
label: '设置选项', run: () => go({ ...route, view: 'options' }),
|
|
5850
|
+
}];
|
|
5851
|
+
actions = [...tabActions, ...bottomActions];
|
|
5852
|
+
if (route.view === 'options') {
|
|
5853
|
+
title = '设置选项';
|
|
5854
|
+
description = '查看各层存储值,或清空一个保存位置。';
|
|
5855
|
+
actions = [{ label: '查看当前值的来源', run: () => {
|
|
5856
|
+
setBatchTargetOffset(0);
|
|
5857
|
+
go({ ...route, view: 'values' });
|
|
5858
|
+
} }, ...operationActions];
|
|
5859
|
+
}
|
|
5963
5860
|
const effectiveConfigFocus = Math.min(focus, Math.max(0, actions.length - 1));
|
|
5964
5861
|
const focusedConfigField = effectiveConfigFocus < (activeGroup?.fields.length ?? 0)
|
|
5965
5862
|
? activeGroup?.fields[effectiveConfigFocus]
|
|
@@ -5969,43 +5866,28 @@ export function ConsoleAppV4(props) {
|
|
|
5969
5866
|
? ['project', 'user'].some((scope) => configLayerPages[scope]?.groups.flatMap((group) => group.fields)
|
|
5970
5867
|
.some((field) => field.key === focusedConfigField.key && configFieldCanUnset(field)))
|
|
5971
5868
|
: false;
|
|
5972
|
-
help =
|
|
5973
|
-
? '↑↓ 移动 · Enter
|
|
5974
|
-
:
|
|
5975
|
-
? '↑↓ 移动 · Enter 修改 · ←→ 分组 · Tab 保存栏 · s 查看汇总 · u 恢复继承 · Esc 返回'
|
|
5976
|
-
: '↑↓ 移动 · Enter 修改 · ←→ 分组 · Tab 保存栏 · s 查看汇总 · Esc 返回';
|
|
5869
|
+
help = canUnsetFocused
|
|
5870
|
+
? '↑↓ 移动 · Enter 修改 · ←→ 分组· s 查看汇总 · u 恢复继承 · Esc 返回'
|
|
5871
|
+
: '↑↓ 移动 · Enter 修改 · ←→ 分组· s 查看汇总 · Esc 返回';
|
|
5977
5872
|
}
|
|
5978
|
-
const fieldFocus = tabActions.length > 0
|
|
5979
|
-
? effectiveConfigFocus < tabActions.length ? effectiveConfigFocus : Math.min(scrollOffset, tabActions.length - 1)
|
|
5980
|
-
: 0;
|
|
5981
|
-
const operationRows = operationActions.reduce((rows, action) => rows + (policy.mode === 'compact' || !action.description ? 1 : 2), 0);
|
|
5982
|
-
const viewport = actionViewport(tabActions, false, fieldFocus, scrollOffset, pageActionBudget(2 + operationRows + 3 + (configDraftIssues.length > 0 ? 3 : 0)));
|
|
5983
5873
|
const totalFields = currentConfigPage.groups.reduce((count, group) => count + group.fields.length, 0);
|
|
5984
5874
|
const countLabel = `${totalFields} 项${currentConfigPage.presets.length > 0 ? ` · ${currentConfigPage.presets.length} 个方案` : ''}`;
|
|
5985
5875
|
context = configDraftCount > 0 ? `${configDraftCount} 项待保存` : countLabel;
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
: _jsxs(Box, { flexDirection: "column", children: [_jsx(
|
|
6001
|
-
id: action.actionId,
|
|
6002
|
-
label: action.label,
|
|
6003
|
-
disabled: Boolean(action.disabled),
|
|
6004
|
-
})), active: focusZone === 'actions', focus: pinnedActionFocus }), !readonly && configDraftIssues.length > 0 ? _jsx(Callout, { status: "warning", title: "\u6709\u672A\u4FDD\u5B58\u4FEE\u6539\u65E0\u6CD5\u7EE7\u7EED\u4F7F\u7528", description: "\u63D2\u4EF6\u6765\u6E90\u6062\u590D\u540E\uFF0C\u8BBE\u7F6E\u5185\u5BB9\u6216\u53EF\u7528\u4F4D\u7F6E\u5DF2\u53D8\u5316\u3002\u8BF7\u653E\u5F03\u8FD9\u4E9B\u4FEE\u6539\uFF0C\u6216\u8FD4\u56DE\u68C0\u67E5\u63D2\u4EF6\u6765\u6E90\uFF1B\u7CFB\u7EDF\u4E0D\u4F1A\u81EA\u52A8\u4FDD\u5B58\u3002" }) : null, activeTab ? _jsx(ConfigGroupTabs, { tabs: visibleConfigTabs, current: activeTab.id, compact: policy.mode === 'compact', columns: size.columns - 2 }) : null, activeTab && tabActions.length > 0
|
|
6005
|
-
? _jsx(SectionCard, { title: activeTab.label, meta: viewport.hiddenBefore > 0 || viewport.hiddenAfter > 0 ? `${viewport.position}/${viewport.total}` : undefined, children: _jsx(SemanticRows, { actions: tabActions, focus: focusZone === 'content' ? effectiveConfigFocus : -1, kind: "section", compact: false, offset: viewport.offset, limit: viewport.limit }) })
|
|
6006
|
-
: null, operationActions.length > 0
|
|
6007
|
-
? _jsx(SemanticRows, { actions: actions, focus: focusZone === 'content' ? effectiveConfigFocus : -1, kind: "action", compact: policy.mode === 'compact', offset: tabActions.length, limit: operationActions.length })
|
|
6008
|
-
: null] });
|
|
5876
|
+
content = route.view === 'options' ? _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })
|
|
5877
|
+
: route.view === 'values' ? (() => {
|
|
5878
|
+
title = '完整设置值与来源';
|
|
5879
|
+
description = '显示各保存位置的完整安全值;敏感值不回显。';
|
|
5880
|
+
const lines = ['effective', 'project', 'user'].flatMap((scope) => ((scope === 'effective' ? currentConfigPage : configLayerPages[scope])?.groups.flatMap((group) => group.fields) ?? []).flatMap((field) => wrapConsoleText(`${field.title} · ${configLayerLabel({ scope })}:${scope === 'effective'
|
|
5881
|
+
? field.invalidOverrideIssue ? '需修正' : fieldValueText(field, field.draftValue ?? field.effectiveValue, true, field.effectiveSourceLabel !== '未设置')
|
|
5882
|
+
: fieldValueText(field, field.draftValue ?? field.value, true, field.configured)}`, size.columns - 4)));
|
|
5883
|
+
const pageRows = Math.max(1, pageActionBudget(4));
|
|
5884
|
+
const offset = Math.min(batchTargetOffset, Math.max(0, lines.length - 1));
|
|
5885
|
+
referenceDetailPagination = { total: lines.length, pageRows };
|
|
5886
|
+
actions = paginationActions({ offset, total: lines.length, pageRows,
|
|
5887
|
+
move: (direction) => moveBatchTargetPage(lines.length, pageRows, direction) });
|
|
5888
|
+
help = 'p/n 或 PgUp/PgDn 阅读 · Esc 返回';
|
|
5889
|
+
return _jsxs(Box, { flexDirection: "column", children: [lines.slice(offset, offset + pageRows).map((line, index) => _jsx(Text, { children: line }, index)), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
|
|
5890
|
+
})() : _jsxs(Box, { flexDirection: "column", children: [!readonly && configDraftIssues.length > 0 ? _jsx(Callout, { status: "warning", title: "\u6709\u672A\u4FDD\u5B58\u4FEE\u6539\u65E0\u6CD5\u7EE7\u7EED\u4F7F\u7528", description: "\u63D2\u4EF6\u6765\u6E90\u6062\u590D\u540E\uFF0C\u8BBE\u7F6E\u5185\u5BB9\u6216\u53EF\u7528\u4F4D\u7F6E\u5DF2\u53D8\u5316\u3002\u8BF7\u653E\u5F03\u8FD9\u4E9B\u4FEE\u6539\uFF0C\u6216\u8FD4\u56DE\u68C0\u67E5\u63D2\u4EF6\u6765\u6E90\uFF1B\u7CFB\u7EDF\u4E0D\u4F1A\u81EA\u52A8\u4FDD\u5B58\u3002" }) : null, activeTab ? _jsx(ConfigGroupTabs, { tabs: visibleConfigTabs, current: activeTab.id, compact: policy.mode === 'compact', columns: size.columns - 2 }) : null, _jsx(SequenceRows, { actions: actions, itemCount: tabActions.length, wrapValues: true, focus: effectiveConfigFocus, scrollOffset: scrollOffset, columns: size.columns - 2, rowBudget: pageActionBudget(2 + (configDraftIssues.length > 0 ? 3 : 0)), compact: policy.mode === 'compact' })] });
|
|
6009
5891
|
}
|
|
6010
5892
|
}
|
|
6011
5893
|
else if (route.name === 'configSave' && plugin) {
|
|
@@ -6036,13 +5918,13 @@ export function ConsoleAppV4(props) {
|
|
|
6036
5918
|
pageRows,
|
|
6037
5919
|
move: (direction) => moveBatchTargetPage(lines.length, pageRows, direction),
|
|
6038
5920
|
}),
|
|
6039
|
-
{ label: '返回保存汇总', run: back },
|
|
5921
|
+
{ role: 'navigation', label: '返回保存汇总', run: back },
|
|
6040
5922
|
];
|
|
6041
5923
|
content = _jsxs(Box, { flexDirection: "column", children: [detailOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${detailOffset} 行`, status: "muted", compact: true }) : null, visibleLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${detailOffset + index}:${line}`)), detailOffset + visibleLines.length < lines.length
|
|
6042
5924
|
? _jsx(StaticRow, { title: `↓ 后面还有 ${lines.length - detailOffset - visibleLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
|
|
6043
5925
|
}
|
|
6044
5926
|
else {
|
|
6045
|
-
const visibleChanges = changes.slice(0,
|
|
5927
|
+
const visibleChanges = changes.slice(0, 2);
|
|
6046
5928
|
breadcrumb = `${plugin.displayName} / 设置 / 保存汇总`;
|
|
6047
5929
|
context = `${changes.length} 项未保存`;
|
|
6048
5930
|
title = `保存 ${changes.length} 项设置修改?`;
|
|
@@ -6069,55 +5951,27 @@ export function ConsoleAppV4(props) {
|
|
|
6069
5951
|
go({ ...route, view: 'changes' });
|
|
6070
5952
|
},
|
|
6071
5953
|
});
|
|
6072
|
-
const
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
content = _jsxs(Box, { flexDirection: "column", children: [
|
|
5954
|
+
const summaryLines = visibleChanges.flatMap((change) => {
|
|
5955
|
+
const lines = wrapConsoleText(`${change.title} · ${change.before ?? '未设置'} → ${change.after}`, Math.max(1, size.columns - 4));
|
|
5956
|
+
return lines.length > 2 ? [lines[0], `${lines[1]}…`] : lines;
|
|
5957
|
+
});
|
|
5958
|
+
const configSaveActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(summaryLines.length + 2));
|
|
5959
|
+
content = _jsxs(Box, { flexDirection: "column", children: [summaryLines.map((line, index) => _jsx(Text, { children: line }, index)), changes.length > visibleChanges.length ? _jsxs(Text, { children: ["\u53E6\u6709 ", changes.length - visibleChanges.length, " \u9879\uFF1B\u5B8C\u6574\u53D8\u5316\u4E2D\u53EF\u8BFB"] }) : null, _jsx(Text, { children: "\u6BCF\u5C42\u72EC\u7ACB\u63D0\u4EA4\uFF1B\u5931\u8D25\u5C42\u4FDD\u7559\u8349\u7A3F" }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: configSaveActionViewport.offset, limit: configSaveActionViewport.limit })] });
|
|
6078
5960
|
}
|
|
6079
5961
|
}
|
|
6080
|
-
else if (route.name === 'configFieldAction' && plugin && activeField) {
|
|
6081
|
-
const layer = configLayerLabel(route.layer);
|
|
6082
|
-
breadcrumb = `${plugin.displayName} / 设置 / ${layer} / ${activeField.title}`;
|
|
6083
|
-
title = activeField.title;
|
|
6084
|
-
description = `这个字段在${layer}中已经有值。`;
|
|
6085
|
-
help = '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
6086
|
-
const targetFields = ['project', 'user'].flatMap((scope) => configLayerPages[scope]?.groups.flatMap((group) => group.fields)
|
|
6087
|
-
.filter((field) => field.key === activeField.key).map((field) => ({ scope, field })) ?? []);
|
|
6088
|
-
const canSet = targetFields.some(({ field }) => configFieldCanSet(field));
|
|
6089
|
-
const canUnset = targetFields.some(({ field }) => configFieldCanUnset(field));
|
|
6090
|
-
actions = [
|
|
6091
|
-
...(canSet ? [{
|
|
6092
|
-
label: '修改值',
|
|
6093
|
-
run: () => go({
|
|
6094
|
-
name: 'configFieldEditor',
|
|
6095
|
-
pluginId: plugin.pluginId,
|
|
6096
|
-
layer: route.layer,
|
|
6097
|
-
fieldKey: activeField.key,
|
|
6098
|
-
editor: fieldEditor(activeField),
|
|
6099
|
-
...fieldEditorMode(activeField),
|
|
6100
|
-
}),
|
|
6101
|
-
}] : []),
|
|
6102
|
-
...(canUnset ? [{
|
|
6103
|
-
label: '恢复继承',
|
|
6104
|
-
description: '选择要删除覆盖值的位置',
|
|
6105
|
-
status: 'error',
|
|
6106
|
-
run: () => removeDraft(activeField.key),
|
|
6107
|
-
}] : []),
|
|
6108
|
-
];
|
|
6109
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { children: [activeField.invalidOverrideIssue
|
|
6110
|
-
? _jsx(StaticRow, { title: "\u5F53\u524D\u8986\u76D6\u65E0\u6548", meta: activeField.invalidOverrideIssue, status: "warning" })
|
|
6111
|
-
: null, !canSet && canUnset
|
|
6112
|
-
? _jsx(StaticRow, { title: "\u672C\u9879\u76EE\u65E7\u503C\u4E0D\u518D\u4F7F\u7528", meta: "\u5F53\u524D\u7EE7\u627F\u4E2A\u4EBA\u6216\u63D2\u4EF6\u9ED8\u8BA4\uFF1B\u5220\u9664\u65E7\u503C\u540E\u4FDD\u6301\u7EE7\u627F", status: "warning" })
|
|
6113
|
-
: null, _jsx(StaticRow, { title: `${layer}中的值`, meta: currentFieldDisplay(activeField) }), _jsx(StaticRow, { title: "\u5F53\u524D\u5B9E\u9645\u751F\u6548", meta: `${effectiveFieldDisplay(activeField)} · 来自${activeField.effectiveSourceLabel}` }), !activeField.invalidOverrideIssue || activeField.invalidOverrideOwnedByLayer
|
|
6114
|
-
? _jsx(StaticRow, { title: "\u5220\u9664\u540E\u5C06\u6062\u590D", meta: `${activeField.fallbackDisplayValue ?? '未设置'} · 来自${activeField.fallbackSourceLabel ?? '未设置'}` })
|
|
6115
|
-
: null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
6116
|
-
}
|
|
6117
5962
|
else if (route.name === 'configFieldEditor' && plugin && activeField) {
|
|
6118
5963
|
breadcrumb = `${plugin.displayName} / 设置 / ${activeField.title}`;
|
|
6119
5964
|
const showChoices = (activeField.choices?.length ?? 0) > 0 && route.mode !== 'custom';
|
|
6120
|
-
|
|
5965
|
+
const targetFields = ['project', 'user'].flatMap((scope) => configLayerPages[scope]?.groups.flatMap((group) => group.fields).filter((field) => field.key === activeField.key) ?? []);
|
|
5966
|
+
const canSet = targetFields.some(configFieldCanSet);
|
|
5967
|
+
const canUnset = targetFields.some(configFieldCanUnset);
|
|
5968
|
+
if (!canSet) {
|
|
5969
|
+
title = activeField.title;
|
|
5970
|
+
description = activeField.invalidOverrideIssue ?? '此旧值不允许修改;可以删除覆盖并恢复继承。';
|
|
5971
|
+
actions = [];
|
|
5972
|
+
content = _jsx(StatusCard, { status: "warning", title: "\u4EC5\u53EF\u5220\u9664\u65E7\u503C", description: description });
|
|
5973
|
+
}
|
|
5974
|
+
else if (showChoices) {
|
|
6121
5975
|
title = `选择${activeField.title}`;
|
|
6122
5976
|
description = activeField.type !== 'boolean' && activeField.allowCustom
|
|
6123
5977
|
? '先选择插件提供的方案,也可以继续自定义。'
|
|
@@ -6180,18 +6034,12 @@ export function ConsoleAppV4(props) {
|
|
|
6180
6034
|
.filter((property) => !fixedKeys.has(property))
|
|
6181
6035
|
.sort((left, right) => left.localeCompare(right, 'en'));
|
|
6182
6036
|
const propertySummary = (property, definition) => {
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
const preset = definition.choices?.presets.find((choice) => choice.value === value);
|
|
6190
|
-
if (preset)
|
|
6191
|
-
return preset.title;
|
|
6192
|
-
if (typeof value === 'boolean')
|
|
6193
|
-
return value ? '开启' : '关闭';
|
|
6194
|
-
return String(value);
|
|
6037
|
+
const presentation = presentConfigValue({ definition,
|
|
6038
|
+
value: activeObjectDraft[property], privateValue: activeField.sensitive,
|
|
6039
|
+
configured: Object.hasOwn(activeObjectDraft, property),
|
|
6040
|
+
});
|
|
6041
|
+
return presentation.state === 'unset' && 'required' in definition && definition.required
|
|
6042
|
+
? '必填 · 未设置' : presentation.text;
|
|
6195
6043
|
};
|
|
6196
6044
|
const propertyActions = [
|
|
6197
6045
|
...fixedEntries.map(([property, definition]) => ({
|
|
@@ -6242,6 +6090,16 @@ export function ConsoleAppV4(props) {
|
|
|
6242
6090
|
: activeField.sensitive ? '当前值不会回显;留空不会自动删除旧值。' : activeField.description ?? '';
|
|
6243
6091
|
content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: inputValue, sensitive: activeField.sensitive, placeholder: activeField.placeholder, columns: Math.max(8, size.columns - 8) }), description: inputError ?? (activeField.sensitive ? '输入已隐藏。' : activeField.placeholder ?? '按 Enter 使用输入值。'), status: inputError ? 'error' : undefined });
|
|
6244
6092
|
}
|
|
6093
|
+
if (canUnset) {
|
|
6094
|
+
const unset = { label: '恢复继承', description: '选择要删除覆盖值的位置', run: () => removeDraft(activeField.key) };
|
|
6095
|
+
const inputEditor = canSet && !showChoices && (route.editor === 'number' || route.editor === 'string');
|
|
6096
|
+
help += ' · Ctrl-R 恢复继承';
|
|
6097
|
+
if (!inputEditor) {
|
|
6098
|
+
const offset = actions.length;
|
|
6099
|
+
actions.push(unset);
|
|
6100
|
+
content = _jsxs(Box, { flexDirection: "column", children: [content, _jsx(SemanticRows, { actions: actions, offset: offset, focus: focus, kind: "action", compact: true })] });
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6245
6103
|
}
|
|
6246
6104
|
else if (route.name === 'configObjectPropertyEditor' && plugin
|
|
6247
6105
|
&& activeField?.definition.type === 'object' && activeObjectDraft) {
|
|
@@ -6380,16 +6238,25 @@ export function ConsoleAppV4(props) {
|
|
|
6380
6238
|
},
|
|
6381
6239
|
] : []),
|
|
6382
6240
|
{ label: showTechnical ? '返回问题摘要' : '技术详情', description: '查看脱敏错误代码和阶段', run: () => toggleTechnical() },
|
|
6383
|
-
{ label: '返回', run: back },
|
|
6241
|
+
{ role: 'navigation', label: '返回', run: back },
|
|
6384
6242
|
];
|
|
6385
6243
|
const unsupportedScopes = resetScopes.filter((scope) => configResetAvailability[scope]?.resettable === false);
|
|
6386
6244
|
const unsupportedRows = unsupportedScopes.map((scope) => _jsx(StaticRow, { title: `${scope === 'user' ? '个人默认' : '当前项目'}设置层不能自动重置:特殊节点,请手动移动`, status: "warning", compact: true }, `unsupported-reset:${scope}`));
|
|
6245
|
+
const technicalPageRows = responsiveBudget(2, 4);
|
|
6246
|
+
if (showTechnical && !invalidLayer) {
|
|
6247
|
+
referenceDetailPagination = {
|
|
6248
|
+
total: diagnosticDetailLines(diagnostic, size.columns - 6).length,
|
|
6249
|
+
pageRows: technicalPageRows,
|
|
6250
|
+
};
|
|
6251
|
+
help = 'p/n 或 PgUp/PgDn 阅读技术字段 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
6252
|
+
}
|
|
6253
|
+
const unavailableActionViewport = actionViewport(actions, true, focus, scrollOffset, pageActionBudget(technicalPageRows + 6 + unsupportedRows.length));
|
|
6387
6254
|
content = invalidLayer
|
|
6388
6255
|
? _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "\u4E0D\u53EF\u8BFB\u53D6\u7684\u8BBE\u7F6E\u5C42", children: (route.invalidStores ?? []).map((store) => _jsx(StaticRow, { title: store.scope === 'user' ? '个人默认设置' : '当前项目设置', meta: "\u9700\u8981\u91CD\u7F6E\u6216\u624B\u52A8\u79FB\u5F00", status: "warning", compact: true }, store.scope)) }), showTechnical ? _jsxs(TechnicalDetails, { children: [(route.invalidStores ?? []).flatMap((store) => [
|
|
6389
6256
|
_jsx(StaticRow, { title: scopeLabel(store.scope), meta: store.code, compact: true }, store.scope),
|
|
6390
6257
|
_jsx(StaticRow, { title: "path summary", meta: store.pathSummary, compact: true }, `${store.scope}:path`),
|
|
6391
6258
|
]), _jsx(StaticRow, { title: "stage", meta: safeDiagnosticCode(route.diagnosticStage, 'read-config'), compact: true })] }) : null, unsupportedRows, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] })
|
|
6392
|
-
: _jsxs(Box, { flexDirection: "column", children: [_jsx(DiagnosticSummary, { diagnostic: diagnostic, technical: showTechnical, compact: policy.mode === 'compact' }), unsupportedRows, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
6259
|
+
: _jsxs(Box, { flexDirection: "column", children: [_jsx(DiagnosticSummary, { diagnostic: diagnostic, technical: showTechnical, columns: size.columns, offset: showTechnical ? batchTargetOffset : undefined, limit: showTechnical ? technicalPageRows : undefined, compact: policy.mode === 'compact' }), unsupportedRows, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: showTechnical || policy.mode === 'compact', offset: showTechnical ? unavailableActionViewport.offset : undefined, limit: showTechnical ? unavailableActionViewport.limit : undefined })] });
|
|
6393
6260
|
}
|
|
6394
6261
|
else if (route.name === 'sourceList') {
|
|
6395
6262
|
breadcrumb = '插件来源';
|
|
@@ -6415,14 +6282,18 @@ export function ConsoleAppV4(props) {
|
|
|
6415
6282
|
: configured?.type === 'git'
|
|
6416
6283
|
&& (configured.url.startsWith('git@') || configured.url.startsWith('ssh://'))
|
|
6417
6284
|
? 'SSH' : 'HTTPS';
|
|
6285
|
+
const policy = overview.detail?.type === 'path' ? 'Path'
|
|
6286
|
+
: overview.detail?.refPolicy === 'explicit'
|
|
6287
|
+
? `固定 ${sourceRefSummary(overview.detail.explicitRef ?? overview.detail.requestedRef)}`
|
|
6288
|
+
: `通道 ${sourceRefSummary(overview.detail?.requestedRef)}`;
|
|
6418
6289
|
const version = `${generation?.active?.catalogVersion ?? '未启用'}${freshness?.candidate?.catalogVersion
|
|
6419
6290
|
? `→${freshness.candidate.catalogVersion}` : ''}`;
|
|
6420
6291
|
const available = generation?.state === 'ready' || health === 'ready';
|
|
6421
6292
|
const unavailable = health === 'unavailable' || health === 'error' || health === 'recovery';
|
|
6422
6293
|
return {
|
|
6423
6294
|
label: source.id,
|
|
6424
|
-
description: sourceLocationSummary(overview.detail?.type ?? 'git', overview.detail?.locationSummary)
|
|
6425
|
-
meta: `当前 ${version} · ${source.count === undefined ? '插件数未知' : `${source.count} 个插件`}`,
|
|
6295
|
+
description: `${sourceLocationSummary(overview.detail?.type ?? 'git', overview.detail?.locationSummary)} · ${policy}`,
|
|
6296
|
+
meta: `当前 ${version} · ${source.count === undefined ? '插件数未知' : `${source.count} 个插件`} · ${relativeCheckTime(freshness?.checkedAt)}`,
|
|
6426
6297
|
tags: _jsxs(Box, { children: [_jsxs(Text, { color: tuiTheme.colors.muted, children: ["[", source.primary ? '主来源' : transport, "] "] }), _jsx(StatusBadge, { items: [{ key: 'health', label: available ? '可用' : unavailable ? '不可用' : '未确认',
|
|
6427
6298
|
symbol: available ? '✓' : unavailable ? '!' : '?', status: available ? 'success' : unavailable ? 'warning' : 'muted' }] }), freshness && freshness.state !== 'current' && freshness.state !== 'fixed'
|
|
6428
6299
|
? _jsxs(Text, { color: tuiTheme.colors.accent, children: [" [", freshness.state === 'updateAvailable' ? '↑ ' : '', presentation.label, "]"] })
|
|
@@ -6431,29 +6302,19 @@ export function ConsoleAppV4(props) {
|
|
|
6431
6302
|
run: () => go({ name: 'sourceDetail', sourceId: source.id }),
|
|
6432
6303
|
};
|
|
6433
6304
|
});
|
|
6434
|
-
|
|
6305
|
+
bottomActions = [
|
|
6435
6306
|
{ label: '+ 添加来源', description: 'Git 仓库或本地目录', run: beginAddSource },
|
|
6436
6307
|
{
|
|
6437
|
-
label: '检查全部来源',
|
|
6308
|
+
actionId: 'source-check-all', label: '检查全部来源 [r]',
|
|
6438
6309
|
description: '并行检查各来源;必要时完整验证;结果不会自动启用待检查版本',
|
|
6439
6310
|
run: () => props.controller.recheckAllCatalogSources(),
|
|
6440
6311
|
},
|
|
6441
6312
|
{ label: 'Catalog 本地存储', description: '检查占用和预览安全清理', run: () => go({ name: 'catalogStoreOverview' }) },
|
|
6442
6313
|
];
|
|
6443
|
-
help =
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
rowHeights: actions.map((action) => objectCardRowLayout({
|
|
6448
|
-
description: action.description ?? '', meta: action.meta, width: size.columns - 2, hasTags: true,
|
|
6449
|
-
}).height),
|
|
6450
|
-
focus, requestedOffset: scrollOffset, rowBudget: pageActionBudget(1),
|
|
6451
|
-
});
|
|
6452
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(PinnedActionBar, { actions: pinnedActions.map((action, index) => ({
|
|
6453
|
-
id: action.actionId ?? `${action.label}:${index}`,
|
|
6454
|
-
label: action.label,
|
|
6455
|
-
disabled: Boolean(action.disabled),
|
|
6456
|
-
})), active: focusZone === 'actions', focus: pinnedActionFocus, visibleCount: policy.mode === 'compact' ? 2 : 3 }), _jsx(ContentViewport, { children: _jsx(SemanticRows, { actions: actions, focus: focusZone === 'content' ? focus : -1, kind: "section", cards: true, columns: size.columns - 2, compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit }) })] });
|
|
6314
|
+
help = '↑↓ 移动 · Enter 打开 · Esc 返回';
|
|
6315
|
+
const sourceCount = actions.length;
|
|
6316
|
+
actions = [...actions, ...bottomActions];
|
|
6317
|
+
content = _jsx(SequenceRows, { actions: actions, itemCount: sourceCount, focus: focus, scrollOffset: scrollOffset, columns: size.columns - 2, rowBudget: pageActionBudget(), compact: policy.mode === 'compact', cards: true });
|
|
6457
6318
|
}
|
|
6458
6319
|
else if (route.name === 'catalogStoreOverview') {
|
|
6459
6320
|
breadcrumb = '插件来源 / 本地存储';
|
|
@@ -6475,7 +6336,7 @@ export function ConsoleAppV4(props) {
|
|
|
6475
6336
|
},
|
|
6476
6337
|
{ actionId: 'catalog-store-rules', label: '查看保留规则', description: '了解哪些目录会保留,以及旧版本何时可以清理', run: () => go({ name: 'catalogStoreRules' }) },
|
|
6477
6338
|
{ actionId: 'catalog-store-refresh', label: '重新检查', description: '重新读取当前本地存储', run: () => setCatalogStoreRefresh((value) => value + 1) },
|
|
6478
|
-
{ actionId: 'catalog-store-back', label: '返回来源列表', run: back },
|
|
6339
|
+
{ role: 'navigation', actionId: 'catalog-store-back', label: '返回来源列表', run: back },
|
|
6479
6340
|
];
|
|
6480
6341
|
content = _jsxs(Box, { flexDirection: "column", children: [catalogStoreError
|
|
6481
6342
|
? _jsx(Callout, { status: "warning", title: "\u672C\u5730\u5B58\u50A8\u68C0\u67E5\u5931\u8D25", description: "\u672A\u6267\u884C\u5220\u9664\u3002\u8BF7\u68C0\u67E5 Catalog \u914D\u7F6E\u548C\u672C\u5730\u5B58\u50A8\u540E\u91CD\u8BD5\u3002" })
|
|
@@ -6490,7 +6351,7 @@ export function ConsoleAppV4(props) {
|
|
|
6490
6351
|
? '' : '清理前会再次检查每个项目,只删除能够确认安全的旧内容。';
|
|
6491
6352
|
actions = [
|
|
6492
6353
|
{ actionId: 'catalog-store-rules-technical', label: showTechnical ? '隐藏技术详情' : '技术详情', run: () => toggleTechnical() },
|
|
6493
|
-
{ actionId: 'catalog-store-rules-back', label: '返回存储概览', run: back },
|
|
6354
|
+
{ role: 'navigation', actionId: 'catalog-store-rules-back', label: '返回存储概览', run: back },
|
|
6494
6355
|
];
|
|
6495
6356
|
content = _jsxs(Box, { flexDirection: "column", children: [!showTechnical ? _jsxs(_Fragment, { children: [_jsx(SectionCard, { title: "\u59CB\u7EC8\u4FDD\u7559 \u00B7 \u5F53\u524D\u4F7F\u7528\u7684\u76EE\u5F55\u4E0D\u4F1A\u5220\u9664", children: _jsx(StaticRow, { title: "\u4E0D\u5C5E\u4E8E AW\u3001\u65E0\u6CD5\u786E\u8BA4\u5B89\u5168\u6216\u4ECD\u5728\u4F7F\u7528\u7684\u5185\u5BB9\u4F1A\u4FDD\u7559", status: "muted", compact: true }) }), _jsxs(SectionCard, { title: "\u6EE1\u8DB3\u65F6\u95F4\u548C\u5B8C\u6574\u9A8C\u8BC1\u540E\u53EF\u56DE\u6536", children: [_jsx(StaticRow, { title: "\u65E7\u7248\u672C\u6EE1\u8DB3\u4FDD\u7559\u671F\u9650\u540E\u624D\u6E05\u7406", compact: true }), _jsx(StaticRow, { title: "\u672A\u5B8C\u6210\u7684\u4E0B\u8F7D\u6216\u66FF\u6362\u5185\u5BB9\u81F3\u5C11\u4FDD\u7559 24 \u5C0F\u65F6", compact: true }), _jsx(StaticRow, { title: "\u9694\u79BB\u5185\u5BB9\u81F3\u5C11\u4FDD\u7559 24 \u5C0F\u65F6", compact: true }), _jsx(StaticRow, { title: "\u5BF9\u5E94\u6B63\u5F0F\u7248\u672C\u5B8C\u6574\u53EF\u7528\u540E\u624D\u6E05\u7406", compact: true })] })] }) : null, showTechnical ? _jsxs(TechnicalDetails, { title: "\u6E05\u7406\u5224\u5B9A\u8BC1\u636E", children: [_jsx(StaticRow, { title: "\u9501", meta: "AW_HOME \u5199\u9501\u5185\u91CD\u65B0\u68C0\u67E5", compact: true }), _jsx(StaticRow, { title: "\u6B63\u5F0F\u76EE\u5F55\u7248\u672C", meta: "\u975E Active \u9879\u4FDD\u7559 30 \u5929", compact: true }), _jsx(StaticRow, { title: "staging\u3001replacement\u3001delete claim", meta: "\u4FDD\u7559 24 \u5C0F\u65F6", compact: true }), _jsx(StaticRow, { title: "quarantine", meta: "\u4FDD\u7559 24 \u5C0F\u65F6\uFF1B\u5BF9\u5E94\u6B63\u5F0F\u76EE\u5F55\u7248\u672C\u5FC5\u987B\u5B8C\u6574\u5065\u5EB7", compact: true }), _jsx(StaticRow, { title: "\u4FDD\u7559\u8282\u70B9", meta: "foreign\u3001\u7B26\u53F7\u94FE\u63A5\u3001unsafe\u3001\u635F\u574F\u6216\u672A\u77E5\u9879\u76EE", compact: true })] }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
6496
6357
|
}
|
|
@@ -6506,17 +6367,26 @@ export function ConsoleAppV4(props) {
|
|
|
6506
6367
|
&& generation?.configMismatch === true;
|
|
6507
6368
|
const logicalIdentityChanged = generation?.errorCode === 'catalogLogicalIdentityChanged';
|
|
6508
6369
|
const activationBlocked = props.controller.catalogSourceRecoveryBlockReason();
|
|
6370
|
+
const generationMissingCount = generation?.compatibility?.state === 'unsupported'
|
|
6371
|
+
? generation.compatibility.missingCapabilities.length : undefined;
|
|
6372
|
+
const freshnessMissingCount = freshness?.missingCapabilities?.length;
|
|
6509
6373
|
breadcrumb = `插件来源 / ${route.sourceId}`;
|
|
6510
6374
|
context = detail?.type === 'path' ? '本地目录' : 'Git';
|
|
6511
6375
|
title = route.sourceId;
|
|
6512
6376
|
description = generationState === 'incompatible'
|
|
6513
|
-
?
|
|
6377
|
+
? generationMissingCount && generationMissingCount > 0
|
|
6378
|
+
? `当前目录版本与 AW 不兼容;缺少 ${generationMissingCount} 项功能支持。`
|
|
6379
|
+
: '当前目录版本与 AW 不兼容;所需功能无法确认。'
|
|
6514
6380
|
: freshness?.state === 'incompatible'
|
|
6515
6381
|
? generationState === 'repairRequired'
|
|
6516
6382
|
? `待检查版本需要升级 AW 或修改来源后才能使用;损坏的当前启用版本仍可按旧版本精确修复。`
|
|
6517
6383
|
: activeVersion && generationState === 'ready'
|
|
6518
|
-
?
|
|
6519
|
-
|
|
6384
|
+
? freshnessMissingCount && freshnessMissingCount > 0
|
|
6385
|
+
? `当前 AW 缺少 ${freshnessMissingCount} 项待检查版本所需功能;当前目录版本 ${activeVersion} 仍可浏览和使用。`
|
|
6386
|
+
: `待检查版本所需功能无法确认;已验证的当前目录版本 ${activeVersion} 仍可浏览和使用。`
|
|
6387
|
+
: freshnessMissingCount && freshnessMissingCount > 0
|
|
6388
|
+
? `当前 AW 缺少 ${freshnessMissingCount} 项待检查版本所需功能;这个来源没有已验证可用的目录版本。`
|
|
6389
|
+
: '待检查版本所需功能无法确认;这个来源没有已验证可用的目录版本。'
|
|
6520
6390
|
: freshness?.state === 'checkFailed' && activeVersion && generationState === 'ready'
|
|
6521
6391
|
? `更新检查失败,但当前目录版本 ${activeVersion} 仍可浏览和使用。`
|
|
6522
6392
|
: freshness?.state === 'updateAvailable' && generationState === 'ready'
|
|
@@ -6529,7 +6399,7 @@ export function ConsoleAppV4(props) {
|
|
|
6529
6399
|
? '当前目录版本损坏,且来源配置已变化。验证待检查版本后可精确修复同一版本,或明确切换到新版本。'
|
|
6530
6400
|
: '当前目录版本缺失或损坏。可在这里精确修复。'
|
|
6531
6401
|
: generationState === 'configMismatch' ? '来源配置与当前启用版本不一致。可验证待检查版本并切换。'
|
|
6532
|
-
: logicalIdentityChanged ? '
|
|
6402
|
+
: logicalIdentityChanged ? '来源发布身份已变化;旧 Active 是否仍可用需要单独验证。请编辑来源,或移除后重新添加。'
|
|
6533
6403
|
: '来源没有可用的启用版本。可在这里取得并启用。';
|
|
6534
6404
|
help = '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
6535
6405
|
if (policy.mode === 'compact')
|
|
@@ -6626,6 +6496,12 @@ export function ConsoleAppV4(props) {
|
|
|
6626
6496
|
}]),
|
|
6627
6497
|
{ actionId: 'source-remove', label: '移除来源', description: '移除来源配置', status: 'error', disabled: props.controller.listSources().length <= 1 ? '至少保留一个来源' : detail?.primary ? '主来源不能直接移除' : undefined, run: () => beginReview({ kind: 'sourceMutation', action: 'remove', sourceId: route.sourceId, changes: [{ title: `移除来源 ${route.sourceId}` }] }) },
|
|
6628
6498
|
{ actionId: 'source-technical', label: '技术详情', description: '查看脱敏错误代码和当前版本证据', run: () => go({ name: 'sourceTechnical', sourceId: route.sourceId }) },
|
|
6499
|
+
...(freshness?.operationRecordId ? [{
|
|
6500
|
+
actionId: 'source-check-diagnostic',
|
|
6501
|
+
label: '查看检查诊断与报告',
|
|
6502
|
+
description: `安全记录 ${freshness.operationRecordId}`,
|
|
6503
|
+
run: () => go({ name: 'operationDiagnostic', recordId: freshness.operationRecordId }),
|
|
6504
|
+
}] : []),
|
|
6629
6505
|
...(generationState !== 'ready'
|
|
6630
6506
|
|| freshness?.state === 'updateAvailable'
|
|
6631
6507
|
|| freshness?.state === 'localChangesAvailable'
|
|
@@ -6638,13 +6514,6 @@ export function ConsoleAppV4(props) {
|
|
|
6638
6514
|
disabled: freshness?.state === 'checking' ? '检查正在进行' : undefined,
|
|
6639
6515
|
run: () => props.controller.recheckCatalogSource(route.sourceId),
|
|
6640
6516
|
}] : []),
|
|
6641
|
-
{
|
|
6642
|
-
actionId: 'source-full-validate',
|
|
6643
|
-
label: '完整验证',
|
|
6644
|
-
description: '强制重新取得并完整验证这个来源',
|
|
6645
|
-
disabled: freshness?.state === 'checking' ? '检查正在进行' : undefined,
|
|
6646
|
-
run: () => props.controller.fullValidateCatalogSource(route.sourceId),
|
|
6647
|
-
},
|
|
6648
6517
|
];
|
|
6649
6518
|
const sourcePrimaryAction = generationAction.length === 0 ? [] : [{
|
|
6650
6519
|
...generationAction[0],
|
|
@@ -6664,9 +6533,9 @@ export function ConsoleAppV4(props) {
|
|
|
6664
6533
|
: configuredSource?.type === 'git'
|
|
6665
6534
|
&& (configuredSource.url.startsWith('git@') || configuredSource.url.startsWith('ssh://'))
|
|
6666
6535
|
? 'SSH' : 'HTTPS';
|
|
6667
|
-
const versionPolicy = detail?.type === 'path' ? '当前本地内容'
|
|
6668
|
-
: detail?.refPolicy === 'cliChannel' ?
|
|
6669
|
-
:
|
|
6536
|
+
const versionPolicy = detail?.type === 'path' ? 'Path · 当前本地内容'
|
|
6537
|
+
: detail?.refPolicy === 'cliChannel' ? `跟随 AW 通道 · ${sourceRefSummary(detail.requestedRef)}`
|
|
6538
|
+
: `固定 ref · ${sourceRefSummary(detail?.explicitRef ?? detail?.requestedRef)}`;
|
|
6670
6539
|
const sourceCount = snapshot.viewModel?.sourceTabs.find((source) => source.id === route.sourceId)?.count;
|
|
6671
6540
|
const checkAction = {
|
|
6672
6541
|
actionId: 'source-check',
|
|
@@ -6675,16 +6544,20 @@ export function ConsoleAppV4(props) {
|
|
|
6675
6544
|
disabled: freshness?.state === 'checking' ? '检查正在进行' : undefined,
|
|
6676
6545
|
run: () => props.controller.recheckCatalogSource(route.sourceId),
|
|
6677
6546
|
};
|
|
6547
|
+
const viewPluginsAction = {
|
|
6548
|
+
actionId: 'source-view-plugins',
|
|
6549
|
+
label: '查看此来源插件',
|
|
6550
|
+
description: sourceCount === undefined ? '插件数未知' : `${sourceCount} 个插件`,
|
|
6551
|
+
run: () => go({ name: 'pluginList', mode: 'browse', sourceId: route.sourceId }),
|
|
6552
|
+
};
|
|
6553
|
+
const healthyWithoutUpdate = generationState === 'ready'
|
|
6554
|
+
&& (freshness?.state === 'current' || freshness?.state === 'fixed');
|
|
6678
6555
|
actions = [
|
|
6556
|
+
...(healthyWithoutUpdate ? [viewPluginsAction] : []),
|
|
6679
6557
|
...sourcePrimaryAction,
|
|
6680
6558
|
...(sourcePrimaryAction.some((action) => action.actionId === 'source-check')
|
|
6681
6559
|
? [] : [checkAction]),
|
|
6682
|
-
|
|
6683
|
-
actionId: 'source-view-plugins',
|
|
6684
|
-
label: '查看此来源插件',
|
|
6685
|
-
description: sourceCount === undefined ? '插件数未知' : `${sourceCount} 个插件`,
|
|
6686
|
-
run: () => go({ name: 'pluginList', mode: 'browse', sourceId: route.sourceId }),
|
|
6687
|
-
},
|
|
6560
|
+
...(healthyWithoutUpdate ? [] : [viewPluginsAction]),
|
|
6688
6561
|
managementActions[0],
|
|
6689
6562
|
managementActions.find((action) => action.actionId === 'source-remove'),
|
|
6690
6563
|
{
|
|
@@ -6706,7 +6579,9 @@ export function ConsoleAppV4(props) {
|
|
|
6706
6579
|
`${transport} · ${sourceLocationSummary(detail?.type ?? 'git', detail?.locationSummary)}`,
|
|
6707
6580
|
`当前 ${activeVersion ?? '未启用'}${candidateVersion ? ` → ${candidateVersion}` : ''} · ${sourceCount === undefined ? '插件数未知' : `${sourceCount} 个插件`}`,
|
|
6708
6581
|
`版本策略:${versionPolicy}`,
|
|
6709
|
-
`检查:${freshnessLabel} · ${freshness?.
|
|
6582
|
+
`检查:${freshnessLabel} · ${freshness?.state === 'checking'
|
|
6583
|
+
? '正在检查这个来源;必要时验证内容'
|
|
6584
|
+
: relativeCheckTime(freshness?.checkedAt)}`,
|
|
6710
6585
|
].join('\n');
|
|
6711
6586
|
const sourceCardHeight = objectCardRowLayout({
|
|
6712
6587
|
description: sourceSummary, width: size.columns - 2, hasTags: true,
|
|
@@ -6797,6 +6672,11 @@ export function ConsoleAppV4(props) {
|
|
|
6797
6672
|
run: () => props.controller.recheckCatalogSource(route.sourceId) },
|
|
6798
6673
|
{ label: '技术详情', description: '查看脱敏错误代码和版本证据',
|
|
6799
6674
|
run: () => go({ name: 'sourceTechnical', sourceId: route.sourceId }) },
|
|
6675
|
+
...(freshness?.operationRecordId ? [{
|
|
6676
|
+
label: '查看检查诊断与报告',
|
|
6677
|
+
description: `安全记录 ${freshness.operationRecordId}`,
|
|
6678
|
+
run: () => go({ name: 'operationDiagnostic', recordId: freshness.operationRecordId }),
|
|
6679
|
+
}] : []),
|
|
6800
6680
|
];
|
|
6801
6681
|
const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(1));
|
|
6802
6682
|
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit });
|
|
@@ -6814,7 +6694,7 @@ export function ConsoleAppV4(props) {
|
|
|
6814
6694
|
actions = [
|
|
6815
6695
|
{ label: 'p 上一页', run: () => setBatchTargetOffset((value) => Math.max(0, value - sourceTechnicalPageRows)) },
|
|
6816
6696
|
{ label: 'n 下一页', run: () => setBatchTargetOffset((value) => Math.min(sourceTechnicalLastOffset, value + sourceTechnicalPageRows)) },
|
|
6817
|
-
{ label: '返回来源详情', run: back },
|
|
6697
|
+
{ role: 'navigation', label: '返回来源详情', run: back },
|
|
6818
6698
|
];
|
|
6819
6699
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "\u5B8C\u6574\u5B89\u5168\u5B57\u6BB5", compact: true, children: lines.slice(offset, offset + sourceTechnicalPageRows).map((line, index) => _jsx(Text, { children: line }, offset + index)) }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
|
|
6820
6700
|
}
|
|
@@ -6970,7 +6850,7 @@ export function ConsoleAppV4(props) {
|
|
|
6970
6850
|
pageRows,
|
|
6971
6851
|
move: (direction) => moveBatchTargetPage(lines.length, pageRows, direction),
|
|
6972
6852
|
}),
|
|
6973
|
-
{ label: '返回修改汇总', run: back },
|
|
6853
|
+
{ role: 'navigation', label: '返回修改汇总', run: back },
|
|
6974
6854
|
];
|
|
6975
6855
|
content = _jsxs(Box, { flexDirection: "column", children: [detailOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${detailOffset} 行`, status: "muted", compact: true }) : null, visibleLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${detailOffset + index}:${line}`)), detailOffset + visibleLines.length < lines.length
|
|
6976
6856
|
? _jsx(StaticRow, { title: `↓ 后面还有 ${lines.length - detailOffset - visibleLines.length} 行`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
|
|
@@ -7022,7 +6902,7 @@ export function ConsoleAppV4(props) {
|
|
|
7022
6902
|
actions = [{ label: sourceDependenciesExpanded ? '收起依赖内容' : '查看依赖内容', description: '只显示插件、来源、平台、位置和类别聚合', run: () => {
|
|
7023
6903
|
setSourceDependenciesExpanded((value) => !value);
|
|
7024
6904
|
setBatchTargetOffset(0);
|
|
7025
|
-
} }, { label: '返回来源详情', run: back }];
|
|
6905
|
+
} }, { role: 'navigation', label: '返回来源详情', run: back }];
|
|
7026
6906
|
const countLabel = (value, unit) => value === undefined ? '未知' : `${value} ${unit}`;
|
|
7027
6907
|
const referenceLimit = Math.max(1, pageActionBudget(12));
|
|
7028
6908
|
const references = sourceReferenceSummary?.dependencies ?? [];
|
|
@@ -7053,7 +6933,7 @@ export function ConsoleAppV4(props) {
|
|
|
7053
6933
|
: '当前状态检查没有发现需要处理的安装、来源或设置问题。';
|
|
7054
6934
|
if (issues.length === 0) {
|
|
7055
6935
|
actions = [
|
|
7056
|
-
{ label: '返回首页', run: () => requestSessionNavigation('home') },
|
|
6936
|
+
{ role: 'navigation', label: '返回首页', run: () => requestSessionNavigation('home') },
|
|
7057
6937
|
{ label: '浏览插件', run: () => go({ name: 'pluginList', mode: 'browse' }) },
|
|
7058
6938
|
];
|
|
7059
6939
|
}
|
|
@@ -7073,8 +6953,18 @@ export function ConsoleAppV4(props) {
|
|
|
7073
6953
|
: go({ name: 'issueDetail', issueId: entry.issueId }),
|
|
7074
6954
|
}));
|
|
7075
6955
|
}
|
|
6956
|
+
const reminder = snapshot.projectIntentReminder;
|
|
6957
|
+
const pendingProjectTargets = (reminder?.actionableTargets.length ?? 0)
|
|
6958
|
+
+ (reminder?.blockedTargets.length ?? 0) + (reminder?.unconfirmedTargets.length ?? 0);
|
|
6959
|
+
if (snapshot.projectIntentIssue || pendingProjectTargets > 0) {
|
|
6960
|
+
title = '需要处理';
|
|
6961
|
+
description = '查看项目插件、安装、来源或设置问题。';
|
|
6962
|
+
actions.unshift({ actionId: 'project-status', label: '项目插件',
|
|
6963
|
+
description: snapshot.projectIntentIssue ? '项目声明需要检查' : `${pendingProjectTargets} 个位置待处理或未确认`,
|
|
6964
|
+
status: 'warning', run: () => go({ name: 'projectStatus' }) });
|
|
6965
|
+
}
|
|
7076
6966
|
const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(8, 12));
|
|
7077
|
-
if (issues.length === 0) {
|
|
6967
|
+
if (issues.length === 0 || snapshot.projectIntentIssue || pendingProjectTargets > 0) {
|
|
7078
6968
|
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit });
|
|
7079
6969
|
}
|
|
7080
6970
|
else {
|
|
@@ -7144,10 +7034,10 @@ export function ConsoleAppV4(props) {
|
|
|
7144
7034
|
|| entry.id === 'keepUserScope' || entry.id === 'keepProjectScope' ? 'error' : undefined,
|
|
7145
7035
|
run: () => runIssueAction(entry),
|
|
7146
7036
|
}));
|
|
7147
|
-
const issueDetailRows =
|
|
7037
|
+
const issueDetailRows = diagnosticDetailLines(issue.diagnostic, size.columns - 6).length;
|
|
7148
7038
|
const issueDetailPageRows = policy.mode === 'compact'
|
|
7149
7039
|
? 1
|
|
7150
|
-
: Math.max(1, responsiveBudget(
|
|
7040
|
+
: Math.max(1, responsiveBudget(1, 4));
|
|
7151
7041
|
const issuePaginationActions = showTechnical && issueDetailRows > issueDetailPageRows
|
|
7152
7042
|
? paginationActions({
|
|
7153
7043
|
offset: batchTargetOffset,
|
|
@@ -7159,20 +7049,18 @@ export function ConsoleAppV4(props) {
|
|
|
7159
7049
|
actions.push(...issuePaginationActions);
|
|
7160
7050
|
if (issuePaginationActions.length > 0) {
|
|
7161
7051
|
referenceDetailPagination = { total: issueDetailRows, pageRows: issueDetailPageRows };
|
|
7162
|
-
help = 'p/n
|
|
7052
|
+
help = 'p/n 或 PgUp/PgDn 阅读全部技术字段 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
7163
7053
|
}
|
|
7164
7054
|
const issuePlugin = issue.pluginId ? props.controller.getPluginOverview(issue.pluginId) : undefined;
|
|
7165
7055
|
const issueOverview = issue.pluginId ? props.controller.getPluginDependencyOverview(issue.pluginId) : undefined;
|
|
7166
|
-
const issueDiagnosticSummary = _jsx(DiagnosticSummary, { diagnostic: issue.diagnostic, technical: showTechnical, offset: showTechnical ? batchTargetOffset : undefined, limit: showTechnical ? issueDetailPageRows : undefined, compact: policy.mode === 'compact' || issue.category.startsWith('dependency')
|
|
7056
|
+
const issueDiagnosticSummary = _jsx(DiagnosticSummary, { diagnostic: issue.diagnostic, columns: size.columns, technical: showTechnical, offset: showTechnical ? batchTargetOffset : undefined, limit: showTechnical ? issueDetailPageRows : undefined, compact: policy.mode === 'compact' || issue.category.startsWith('dependency')
|
|
7167
7057
|
|| issue.category === 'scopeConflict' });
|
|
7168
7058
|
const issueActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(6));
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
: {};
|
|
7175
|
-
if (issue.category === 'dependencyStillRequired' && issuePlugin) {
|
|
7059
|
+
if (showTechnical) {
|
|
7060
|
+
const technicalActionViewport = actionViewport(actions, true, focus, scrollOffset, pageActionBudget(issueDetailPageRows + 6));
|
|
7061
|
+
content = _jsxs(Box, { flexDirection: "column", children: [issueDiagnosticSummary, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: technicalActionViewport.offset, limit: technicalActionViewport.limit })] });
|
|
7062
|
+
}
|
|
7063
|
+
else if (issue.category === 'dependencyStillRequired' && issuePlugin) {
|
|
7176
7064
|
const blockingDependents = issue.platform && issue.scope
|
|
7177
7065
|
? props.controller.getBlockingDependents(issuePlugin.pluginId, issue.platform, issue.scope)
|
|
7178
7066
|
: issueOverview?.dependents ?? [];
|
|
@@ -7197,7 +7085,7 @@ export function ConsoleAppV4(props) {
|
|
|
7197
7085
|
issue.dependencyPlatform ? platformLabel(issue.dependencyPlatform) : undefined,
|
|
7198
7086
|
issue.dependencyScope ? scopeLabel(issue.dependencyScope) : undefined,
|
|
7199
7087
|
].filter((entry) => Boolean(entry)).join(' · ');
|
|
7200
|
-
content = _jsxs(Box, { flexDirection: "column", children: [issueDiagnosticSummary, !showTechnical && policy.mode !== 'compact' ? _jsxs(StatusCard, { status: "warning", title: dependencyName, description: "\u53D7\u5F71\u54CD\u7684\u4F9D\u8D56\u76EE\u6807", children: [_jsx(StaticRow, { title: issuePlugin.displayName, description: "\u53D7\u5F71\u54CD\u7684\u6839\u63D2\u4EF6", meta: issue.platform && issue.scope ? `${platformLabel(issue.platform)} · ${scopeLabel(issue.scope)}` : undefined }), dependencyTarget ? _jsx(StaticRow, { title: "\u4F9D\u8D56\u76EE\u6807", meta: dependencyTarget, status: "warning" }) : null] }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact'
|
|
7088
|
+
content = _jsxs(Box, { flexDirection: "column", children: [issueDiagnosticSummary, !showTechnical && policy.mode !== 'compact' ? _jsxs(StatusCard, { status: "warning", title: dependencyName, description: "\u53D7\u5F71\u54CD\u7684\u4F9D\u8D56\u76EE\u6807", children: [_jsx(StaticRow, { title: issuePlugin.displayName, description: "\u53D7\u5F71\u54CD\u7684\u6839\u63D2\u4EF6", meta: issue.platform && issue.scope ? `${platformLabel(issue.platform)} · ${scopeLabel(issue.scope)}` : undefined }), dependencyTarget ? _jsx(StaticRow, { title: "\u4F9D\u8D56\u76EE\u6807", meta: dependencyTarget, status: "warning" }) : null] }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
7201
7089
|
}
|
|
7202
7090
|
else if (issue.category === 'dependencyTargetUnsupported' && issuePlugin) {
|
|
7203
7091
|
const issueScope = issue.scope ?? scope;
|
|
@@ -7269,7 +7157,7 @@ export function ConsoleAppV4(props) {
|
|
|
7269
7157
|
status: operationHistoryState(record).status,
|
|
7270
7158
|
run: () => go({ name: 'operationDiagnostic', recordId: record.recordId }),
|
|
7271
7159
|
})),
|
|
7272
|
-
{ label: '返回上一页', run: back },
|
|
7160
|
+
{ role: 'navigation', label: '返回上一页', run: back },
|
|
7273
7161
|
];
|
|
7274
7162
|
const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(4));
|
|
7275
7163
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: records.some((record) => record.state !== 'succeeded') ? 'warning' : 'success', title: records.length === 0 ? '没有可回看的安全结果' : '操作结果与问题', description: "\u9009\u62E9\u4E00\u9879\u53EF\u67E5\u770B\u5B8C\u6574\u5B89\u5168\u8BE6\u60C5\u6216\u62A5\u544A\u9884\u89C8\u3002", compact: policy.mode === 'compact' }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit })] });
|
|
@@ -7283,8 +7171,8 @@ export function ConsoleAppV4(props) {
|
|
|
7283
7171
|
? '可滚动查看所有目标、阶段、代码和已保留的安全原因。'
|
|
7284
7172
|
: '这项会话记录已经不再可用。';
|
|
7285
7173
|
const preview = detail ? props.controller.previewOperationReport(route.recordId) : undefined;
|
|
7286
|
-
const detailLineLimit =
|
|
7287
|
-
const detailLines = detail ? operationDiagnosticLineCount(detail) : 0;
|
|
7174
|
+
const detailLineLimit = operationDetailPageRows;
|
|
7175
|
+
const detailLines = detail ? operationDiagnosticLineCount(detail, size.columns) : 0;
|
|
7288
7176
|
const lastDetailOffset = Math.max(0, detailLines - detailLineLimit);
|
|
7289
7177
|
actions = detail ? [
|
|
7290
7178
|
preview
|
|
@@ -7292,10 +7180,10 @@ export function ConsoleAppV4(props) {
|
|
|
7292
7180
|
: { label: '报告当前不可用', disabled: '无法生成这项记录的报告' },
|
|
7293
7181
|
{ label: 'p 上一页', run: () => setScrollOffset((value) => Math.max(0, value - detailLineLimit)) },
|
|
7294
7182
|
{ label: 'n 下一页', run: () => setScrollOffset((value) => Math.min(lastDetailOffset, value + detailLineLimit)) },
|
|
7295
|
-
{ label: '返回操作记录', run: back },
|
|
7296
|
-
] : [{ label: '返回操作记录', run: back }];
|
|
7183
|
+
{ role: 'navigation', label: '返回操作记录', run: back },
|
|
7184
|
+
] : [{ role: 'navigation', label: '返回操作记录', run: back }];
|
|
7297
7185
|
const diagnosticActionViewport = actionViewport(actions, policy.mode === 'compact', focus, 0, policy.mode === 'compact' ? 2 : 3);
|
|
7298
|
-
content = detail ? _jsxs(Box, { flexDirection: "column", children: [_jsx(ContentViewport, { children: _jsx(OperationDiagnosticScreen, { detail: detail, compact: policy.mode === 'compact', offset: scrollOffset, limit: detailLineLimit }) }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: diagnosticActionViewport.offset, limit: diagnosticActionViewport.limit })] }) : _jsxs(Box, { flexDirection: "column", children: [_jsx(Callout, { status: "warning", title: "\u8BB0\u5F55\u5DF2\u4E0D\u53EF\u7528", description: "\u8FD4\u56DE\u64CD\u4F5C\u8BB0\u5F55\u540E\u53EF\u67E5\u770B\u4ECD\u5728\u672C\u6B21\u4F1A\u8BDD\u4E2D\u7684\u7ED3\u679C\u3002" }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
7186
|
+
content = detail ? _jsxs(Box, { flexDirection: "column", children: [_jsx(ContentViewport, { children: _jsx(OperationDiagnosticScreen, { detail: detail, compact: policy.mode === 'compact', columns: size.columns, offset: scrollOffset, limit: detailLineLimit }) }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: diagnosticActionViewport.offset, limit: diagnosticActionViewport.limit })] }) : _jsxs(Box, { flexDirection: "column", children: [_jsx(Callout, { status: "warning", title: "\u8BB0\u5F55\u5DF2\u4E0D\u53EF\u7528", description: "\u8FD4\u56DE\u64CD\u4F5C\u8BB0\u5F55\u540E\u53EF\u67E5\u770B\u4ECD\u5728\u672C\u6B21\u4F1A\u8BDD\u4E2D\u7684\u7ED3\u679C\u3002" }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
7299
7187
|
}
|
|
7300
7188
|
else if (route.name === 'operationReportPreview') {
|
|
7301
7189
|
const preview = props.controller.previewOperationReport(route.recordId);
|
|
@@ -7312,8 +7200,8 @@ export function ConsoleAppV4(props) {
|
|
|
7312
7200
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(InputCard, { title: "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84", focused: true, compact: policy.mode === 'compact', children: _jsx(InputDisplay, { value: reportSavePath, placeholder: "/tmp/aw-operation-report.md", columns: Math.max(12, size.columns - 10) }) }), reportSaveError ? _jsx(Callout, { status: "error", title: "\u62A5\u544A\u672A\u4FDD\u5B58", description: reportSaveError, compact: policy.mode === 'compact' }) : null, _jsx(StaticRow, { title: "\u4EC5\u4FDD\u5B58\u5F53\u524D\u9884\u89C8\u4E2D\u7684\u5B89\u5168\u5185\u5BB9\u3002", status: "muted", compact: true })] });
|
|
7313
7201
|
}
|
|
7314
7202
|
else if (preview) {
|
|
7315
|
-
const reportLineLimit =
|
|
7316
|
-
const reportLines = operationReportLineCount(preview);
|
|
7203
|
+
const reportLineLimit = operationDetailPageRows;
|
|
7204
|
+
const reportLines = operationReportLineCount(preview, size.columns);
|
|
7317
7205
|
const lastReportOffset = Math.max(0, reportLines - reportLineLimit);
|
|
7318
7206
|
actions = [
|
|
7319
7207
|
{ label: '选择本地保存位置', description: '保存前输入明确的文件路径', run: () => {
|
|
@@ -7331,16 +7219,16 @@ export function ConsoleAppV4(props) {
|
|
|
7331
7219
|
} },
|
|
7332
7220
|
{ label: 'p 上一页', run: () => setScrollOffset((value) => Math.max(0, value - reportLineLimit)) },
|
|
7333
7221
|
{ label: 'n 下一页', run: () => setScrollOffset((value) => Math.min(lastReportOffset, value + reportLineLimit)) },
|
|
7334
|
-
{ label: '返回技术详情', run: back },
|
|
7222
|
+
{ role: 'navigation', label: '返回技术详情', run: back },
|
|
7335
7223
|
];
|
|
7336
7224
|
const reportFeedbackVisible = Boolean(reportSaveResult || reportSaveError);
|
|
7337
7225
|
const compactReportActions = policy.mode === 'compact' || reportFeedbackVisible;
|
|
7338
7226
|
const reportActionLimit = policy.mode === 'compact' || reportFeedbackVisible ? 2 : 3;
|
|
7339
7227
|
const reportActionOffset = Math.min(Math.max(0, focus - 1), Math.max(0, actions.length - reportActionLimit));
|
|
7340
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(ContentViewport, { children: _jsx(OperationReportPreviewScreen, { preview: preview, compact: policy.mode === 'compact', offset: scrollOffset, limit: reportLineLimit }) }), reportSaveResult ? _jsx(Callout, { status: "success", title: "\u62A5\u544A\u5DF2\u4FDD\u5B58", description: reportSaveResult, compact: policy.mode === 'compact' }) : null, reportSaveError ? _jsx(Callout, { status: "error", title: "\u62A5\u544A\u672A\u4FDD\u5B58", description: reportSaveError, compact: policy.mode === 'compact' }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: compactReportActions, offset: reportActionOffset, limit: reportActionLimit })] });
|
|
7228
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(ContentViewport, { children: _jsx(OperationReportPreviewScreen, { preview: preview, compact: policy.mode === 'compact', columns: size.columns, offset: scrollOffset, limit: reportLineLimit }) }), reportSaveResult ? _jsx(Callout, { status: "success", title: "\u62A5\u544A\u5DF2\u4FDD\u5B58", description: reportSaveResult, compact: policy.mode === 'compact' }) : null, reportSaveError ? _jsx(Callout, { status: "error", title: "\u62A5\u544A\u672A\u4FDD\u5B58", description: reportSaveError, compact: policy.mode === 'compact' }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: compactReportActions, offset: reportActionOffset, limit: reportActionLimit })] });
|
|
7341
7229
|
}
|
|
7342
7230
|
else {
|
|
7343
|
-
actions = [{ label: '返回技术详情', run: back }];
|
|
7231
|
+
actions = [{ role: 'navigation', label: '返回技术详情', run: back }];
|
|
7344
7232
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(Callout, { status: "warning", title: "\u62A5\u544A\u5DF2\u4E0D\u53EF\u7528", description: "\u8FD4\u56DE\u6280\u672F\u8BE6\u60C5\u540E\u53EF\u67E5\u770B\u4ECD\u5728\u672C\u6B21\u4F1A\u8BDD\u4E2D\u7684\u8BB0\u5F55\u3002" }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
7345
7233
|
}
|
|
7346
7234
|
}
|
|
@@ -7698,6 +7586,18 @@ export function ConsoleAppV4(props) {
|
|
|
7698
7586
|
? `另有 ${hiddenTechnicalChanges} 项` : undefined, status: changeStatus(change), compact: false }, `${change.title}:${index}`);
|
|
7699
7587
|
});
|
|
7700
7588
|
const showEquivalentCommand = Boolean(review.equivalentCommand && showTechnical && !review.requiresConfirmation);
|
|
7589
|
+
const reviewRootPluginIds = taskReview || batchReview
|
|
7590
|
+
? review.rootSummary?.map((root) => root.pluginId) ?? [] : [];
|
|
7591
|
+
const reviewRootSummary = reviewRootPluginIds.length === 1
|
|
7592
|
+
? props.controller.getPluginOverview(reviewRootPluginIds[0])?.displayName
|
|
7593
|
+
?? reviewRootPluginIds[0].split('/').at(-1)
|
|
7594
|
+
: reviewRootPluginIds.length > 1 ? `${reviewRootPluginIds.length} 个` : undefined;
|
|
7595
|
+
const reviewVersionSummary = review.rootSummary && review.rootSummary.length > 0
|
|
7596
|
+
? [...new Set(review.rootSummary.map((root) => root.version ?? '未知'))].join('、')
|
|
7597
|
+
: undefined;
|
|
7598
|
+
const reviewRangeSummary = review.rootSummary && review.rootSummary.length > 0
|
|
7599
|
+
? [...new Set(review.rootSummary.flatMap((root) => root.targets.map((target) => `${target.platform === 'both' ? 'Codex/Claude Code' : platformLabel(target.platform)}/${scopeLabel(target.scope)}`)))].join('、')
|
|
7600
|
+
: undefined;
|
|
7701
7601
|
const installDependencyTargets = installReviewPluginId
|
|
7702
7602
|
? snapshot.installPlacementDraft?.targets ?? [] : [];
|
|
7703
7603
|
const installDependencyPluginIds = new Set(installDependencyTargets.map((target) => target.pluginId));
|
|
@@ -7713,7 +7613,7 @@ export function ConsoleAppV4(props) {
|
|
|
7713
7613
|
&& (review.changes.length > technicalChangeBudget || technicalDetails.length > technicalDetailLimit)) {
|
|
7714
7614
|
help = 'PgUp/PgDn 查看全部确认信息 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
7715
7615
|
}
|
|
7716
|
-
content = _jsx(Box, { flexDirection: "column", children: _jsxs(ReviewCard, { title: review.subject.name, meta: `${review.subject.sourceLabel ?? ''} ${review.subject.version ?? ''}`, description: showEquivalentCommand ? review.description : undefined, children: [showEquivalentCommand ? _jsxs(Text, { children: ["\u7B49\u4EF7\u547D\u4EE4\uFF1A", review.equivalentCommand] }) : null, portableReview ? _jsx(SemanticRows, { actions: actions, focus: operationConfirmation ? -1 : focus, kind: "action", compact: true, offset: reviewActionViewport.offset, limit: reviewActionViewport.limit }) : null, showTechnical && review.catalogBinding ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `Catalog:${review.catalogBinding.sourceId} ${review.catalogBinding.catalogVersion} · 当前使用`, meta: `generation ${review.catalogBinding.generationDigestShort}`, status: "success", compact: true }), _jsx(StaticRow, { title: "\u64CD\u4F5C\u671F\u95F4\u4E0D\u68C0\u67E5\u8FDC\u7AEF Catalog", status: "success", compact: true })] }) : null, installDependencyPluginIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `需要 ${installDependencyPluginIds.size} 个额外插件;${reusedDependencyPluginIds.size} 个复用、${newDependencyCount} 个新增`, status: "info", compact: true }), _jsx(StaticRow, { title: widenedDependencyCount > 0 ? `${widenedDependencyCount} 个依赖会扩大到所有项目` : '没有依赖会扩大到所有项目', status: widenedDependencyCount > 0 ? 'warning' : 'success', compact: true })] }) : null, review.requiresConfirmation ? _jsx(StaticRow, { title: review.operationKind === 'catalogStorePrune' ? '! 需要确认删除本次预览的可回收项目' : projectPreApplyConfirmation ? '! 需要确认当前项目同步脚本' : '! 需要确认会影响其他项目的内容', meta: review.sharedImpact.pluginIds.length > 0 ? `${review.sharedImpact.pluginIds.length} 个插件` : undefined, description: review.sharedImpact.warning, status: "warning", compact: true }) : null, showTechnical ? technicalChanges : changeGroups, portableReview ? null : _jsx(SemanticRows, { actions: actions, focus: operationConfirmation ? -1 : focus, kind: "action", compact: true, offset: reviewActionViewport.offset, limit: reviewActionViewport.limit }), compressedReview || showTechnical ? null : _jsx(StaticRow, { title: "\u6280\u672F\u8BE6\u60C5\uFF08d\uFF09", status: "muted" }), showTechnical ? _jsx(TechnicalDetails, { children: visibleTechnicalDetails.map((detail, index) => _jsx(StaticRow, { title: detail, meta: catalogReferenceDetailOffset >= 0 && batchTargetOffset + index >= catalogReferenceDetailOffset ? undefined : index === visibleTechnicalDetails.length - 1 && hiddenTechnicalDetails > 0 ? `另有 ${hiddenTechnicalDetails} 项` : undefined, compact: true }, `${batchTargetOffset + index}:${detail}`)) }) : null] }) });
|
|
7616
|
+
content = _jsx(Box, { flexDirection: "column", children: _jsxs(ReviewCard, { title: reviewRootSummary ? `本次插件 · ${reviewRootSummary}` : review.subject.name, meta: reviewRootSummary ? `版本 ${reviewVersionSummary} · 范围 ${reviewRangeSummary || '未知'}` : `${review.subject.sourceLabel ?? ''} ${review.subject.version ?? ''}`, description: showEquivalentCommand ? review.description : undefined, children: [showEquivalentCommand ? _jsxs(Text, { children: ["\u7B49\u4EF7\u547D\u4EE4\uFF1A", review.equivalentCommand] }) : null, portableReview ? _jsx(SemanticRows, { actions: actions, focus: operationConfirmation ? -1 : focus, kind: "action", compact: true, offset: reviewActionViewport.offset, limit: reviewActionViewport.limit }) : null, showTechnical && review.catalogBinding ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `Catalog:${review.catalogBinding.sourceId} ${review.catalogBinding.catalogVersion} · 当前使用`, meta: `generation ${review.catalogBinding.generationDigestShort}`, status: "success", compact: true }), _jsx(StaticRow, { title: "\u64CD\u4F5C\u671F\u95F4\u4E0D\u68C0\u67E5\u8FDC\u7AEF Catalog", status: "success", compact: true })] }) : null, installDependencyPluginIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `需要 ${installDependencyPluginIds.size} 个额外插件;${reusedDependencyPluginIds.size} 个复用、${newDependencyCount} 个新增`, status: "info", compact: true }), _jsx(StaticRow, { title: widenedDependencyCount > 0 ? `${widenedDependencyCount} 个依赖会扩大到所有项目` : '没有依赖会扩大到所有项目', status: widenedDependencyCount > 0 ? 'warning' : 'success', compact: true })] }) : null, review.requiresConfirmation ? _jsx(StaticRow, { title: review.operationKind === 'catalogStorePrune' ? '! 需要确认删除本次预览的可回收项目' : projectPreApplyConfirmation ? '! 需要确认当前项目同步脚本' : '! 需要确认会影响其他项目的内容', meta: review.sharedImpact.pluginIds.length > 0 ? `${review.sharedImpact.pluginIds.length} 个插件` : undefined, description: review.sharedImpact.warning, status: "warning", compact: true }) : null, showTechnical ? technicalChanges : changeGroups, portableReview ? null : _jsx(SemanticRows, { actions: actions, focus: operationConfirmation ? -1 : focus, kind: "action", compact: true, offset: reviewActionViewport.offset, limit: reviewActionViewport.limit }), compressedReview || showTechnical ? null : _jsx(StaticRow, { title: "\u6280\u672F\u8BE6\u60C5\uFF08d\uFF09", status: "muted" }), showTechnical ? _jsx(TechnicalDetails, { children: visibleTechnicalDetails.map((detail, index) => _jsx(StaticRow, { title: detail, meta: catalogReferenceDetailOffset >= 0 && batchTargetOffset + index >= catalogReferenceDetailOffset ? undefined : index === visibleTechnicalDetails.length - 1 && hiddenTechnicalDetails > 0 ? `另有 ${hiddenTechnicalDetails} 项` : undefined, compact: true }, `${batchTargetOffset + index}:${detail}`)) }) : null] }) });
|
|
7717
7617
|
}
|
|
7718
7618
|
else if (route.name === 'progress') {
|
|
7719
7619
|
const taskOperation = snapshot.activeReview?.operationKind === 'pluginWriteTask';
|
|
@@ -8117,11 +8017,20 @@ export function ConsoleAppV4(props) {
|
|
|
8117
8017
|
: [];
|
|
8118
8018
|
const safeCleanupKeys = new Set(props.controller.listPluginWriteBatchTargets('cleanup', [...new Set(failedUninstallTargets.map((target) => target.pluginId))]).map(batchTargetKey));
|
|
8119
8019
|
const failedCleanupTargets = failedUninstallTargets.filter((target) => safeCleanupKeys.has(batchTargetKey(target)));
|
|
8020
|
+
const sourceRecoveryRoute = 'returnRoute' in result && result.returnRoute?.name === 'sourceDetail'
|
|
8021
|
+
? result.returnRoute : undefined;
|
|
8022
|
+
const resumeConfigSourceDraft = operationKind === 'catalogGeneration'
|
|
8023
|
+
&& sourceRecoveryRoute !== undefined
|
|
8024
|
+
&& dirty
|
|
8025
|
+
&& draftOwner?.startsWith(`${sourceRecoveryRoute.sourceId}/`)
|
|
8026
|
+
&& props.controller.externalDrafts.some((draft) => draft.kind === 'configDraft' && draft.owner === draftOwner);
|
|
8120
8027
|
actions = storeOperation
|
|
8121
8028
|
? [
|
|
8122
|
-
{ label: '返回存储概览', run: () => leaveResult({ name: 'catalogStoreOverview' }) },
|
|
8123
|
-
{ label: '查看本次记录', run: () =>
|
|
8124
|
-
|
|
8029
|
+
{ role: 'navigation', label: '返回存储概览', run: () => leaveResult({ name: 'catalogStoreOverview' }) },
|
|
8030
|
+
{ label: '查看本次记录', run: () => {
|
|
8031
|
+
if (result.operationRecordId)
|
|
8032
|
+
go({ name: 'operationDiagnostic', recordId: result.operationRecordId });
|
|
8033
|
+
} },
|
|
8125
8034
|
]
|
|
8126
8035
|
: taskOperation
|
|
8127
8036
|
? [
|
|
@@ -8146,7 +8055,8 @@ export function ConsoleAppV4(props) {
|
|
|
8146
8055
|
status: 'warning',
|
|
8147
8056
|
run: () => leaveResult(taskReturnRoute),
|
|
8148
8057
|
}] : []),
|
|
8149
|
-
...(!nestedTaskReturn ? [{
|
|
8058
|
+
...(!nestedTaskReturn ? [{ role: result.state === 'succeeded' ? 'navigation' : undefined,
|
|
8059
|
+
label: '完成,返回我的插件', run: () => {
|
|
8150
8060
|
if (taskBatchOrigin?.owner === 'batch-write'
|
|
8151
8061
|
&& taskBatchOrigin.flowId === batchDraft?.flowId) {
|
|
8152
8062
|
setBatchDraft(undefined);
|
|
@@ -8154,8 +8064,10 @@ export function ConsoleAppV4(props) {
|
|
|
8154
8064
|
}
|
|
8155
8065
|
leaveResult({ name: 'pluginList', mode: 'installed' });
|
|
8156
8066
|
} }] : []),
|
|
8157
|
-
{ label: '查看本次记录', run: () =>
|
|
8158
|
-
|
|
8067
|
+
{ label: '查看本次记录', run: () => {
|
|
8068
|
+
if (result.operationRecordId)
|
|
8069
|
+
go({ name: 'operationDiagnostic', recordId: result.operationRecordId });
|
|
8070
|
+
} },
|
|
8159
8071
|
]
|
|
8160
8072
|
: batchOperation
|
|
8161
8073
|
? [
|
|
@@ -8168,9 +8080,12 @@ export function ConsoleAppV4(props) {
|
|
|
8168
8080
|
setScrollOffset(0);
|
|
8169
8081
|
},
|
|
8170
8082
|
}] : []),
|
|
8171
|
-
{
|
|
8172
|
-
|
|
8173
|
-
|
|
8083
|
+
{ role: result.state === 'succeeded' ? 'navigation' : undefined,
|
|
8084
|
+
label: '返回我的插件', run: () => leaveResult() },
|
|
8085
|
+
{ label: '查看本次记录', run: () => {
|
|
8086
|
+
if (result.operationRecordId)
|
|
8087
|
+
go({ name: 'operationDiagnostic', recordId: result.operationRecordId });
|
|
8088
|
+
} },
|
|
8174
8089
|
]
|
|
8175
8090
|
: portableOperation
|
|
8176
8091
|
? blocked || partial ? [
|
|
@@ -8220,7 +8135,7 @@ export function ConsoleAppV4(props) {
|
|
|
8220
8135
|
{ label: portableReturnLabel, run: () => { if (pluginId)
|
|
8221
8136
|
props.controller.resetPortableFlowToPreview(pluginId); } },
|
|
8222
8137
|
] : [
|
|
8223
|
-
{ label: portableReturnLabel, run: () => {
|
|
8138
|
+
{ role: 'navigation', label: portableReturnLabel, run: () => {
|
|
8224
8139
|
props.controller.discardPortableDraft();
|
|
8225
8140
|
leaveResult();
|
|
8226
8141
|
} },
|
|
@@ -8244,15 +8159,20 @@ export function ConsoleAppV4(props) {
|
|
|
8244
8159
|
{ label: '重新检查问题', run: () => leaveResult({ name: 'issueList' }) },
|
|
8245
8160
|
]
|
|
8246
8161
|
: [
|
|
8247
|
-
{ label: '查看问题列表', run: () => leaveResult({ name: 'issueList' }) },
|
|
8248
|
-
{ label: '返回首页', run: () => requestSessionNavigation('home') },
|
|
8162
|
+
{ role: 'navigation', label: '查看问题列表', run: () => leaveResult({ name: 'issueList' }) },
|
|
8163
|
+
{ role: 'navigation', label: '返回首页', run: () => requestSessionNavigation('home') },
|
|
8249
8164
|
]
|
|
8250
8165
|
: sourceOperation
|
|
8251
8166
|
? [{
|
|
8252
8167
|
label: !blocked && 'returnRoute' in result && result.returnRoute?.name === 'pluginWriteTask'
|
|
8253
|
-
? '重新准备插件更新' : blocked ? '返回修改' : partial ? '现在启用 / 重试'
|
|
8168
|
+
? '重新准备插件更新' : blocked ? '返回修改' : partial ? '现在启用 / 重试'
|
|
8169
|
+
: resumeConfigSourceDraft ? '继续编辑未保存设置' : '查看来源',
|
|
8170
|
+
role: !blocked && !partial && !resumeConfigSourceDraft
|
|
8171
|
+
&& !('returnRoute' in result && result.returnRoute?.name === 'pluginWriteTask')
|
|
8172
|
+
? 'navigation' : undefined,
|
|
8254
8173
|
run: () => blocked ? props.controller.resumeResultDraft() : leaveResult(),
|
|
8255
|
-
}, {
|
|
8174
|
+
}, { role: !blocked && !partial ? 'navigation' : undefined,
|
|
8175
|
+
label: '返回首页', run: () => requestSessionNavigation('home') }]
|
|
8256
8176
|
: configOperation && partial
|
|
8257
8177
|
? [
|
|
8258
8178
|
...configRetryScopes.map((scope) => ({
|
|
@@ -8277,7 +8197,8 @@ export function ConsoleAppV4(props) {
|
|
|
8277
8197
|
{ label: '返回设置', run: () => props.controller.resumeResultDraft() },
|
|
8278
8198
|
{ label: '返回首页', run: () => requestSessionNavigation('home') },
|
|
8279
8199
|
]
|
|
8280
|
-
: [{
|
|
8200
|
+
: [{ role: !partial && !blocked && !blockedDependencyFailure ? 'navigation' : undefined,
|
|
8201
|
+
label: partial || blockedDependencyFailure ? '查看失败项' : successfulConfigOperation && configOrigin
|
|
8281
8202
|
? configOrigin.name === 'pluginPreview' ? '返回插件预览'
|
|
8282
8203
|
: configOrigin.name === 'pluginWriteTask' ? '返回恢复任务' : '返回插件详情'
|
|
8283
8204
|
: configOperation ? '查看插件'
|
|
@@ -8317,7 +8238,8 @@ export function ConsoleAppV4(props) {
|
|
|
8317
8238
|
scope: failedTarget.scope,
|
|
8318
8239
|
});
|
|
8319
8240
|
},
|
|
8320
|
-
}] : []), {
|
|
8241
|
+
}] : []), { role: !partial && !blocked ? 'navigation' : undefined,
|
|
8242
|
+
label: '返回首页', run: () => requestSessionNavigation('home') }];
|
|
8321
8243
|
if (failedCleanupTargets.length > 0) {
|
|
8322
8244
|
actions.unshift({
|
|
8323
8245
|
label: '查看清理建议',
|
|
@@ -8587,46 +8509,51 @@ export function ConsoleAppV4(props) {
|
|
|
8587
8509
|
return _jsx(ResultRow, { title: rootName, description: `${requestedTargets.length} 个使用位置`, meta: rootState.label, status: rootState.status, compact: true }, `root:${root.pluginId}`);
|
|
8588
8510
|
});
|
|
8589
8511
|
const taskLocationRows = taskRootResults.flatMap((root) => {
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
const key = [
|
|
8512
|
+
return root.targets.map((target) => {
|
|
8513
|
+
const targetPluginId = target.pluginId ?? root.pluginId;
|
|
8514
|
+
const key = [targetPluginId, target.platform, target.scope].join('\0');
|
|
8593
8515
|
const blockedTarget = blockedTaskTargets.get(key);
|
|
8594
|
-
const targetResult = root.targets.find((entry) => entry.pluginId === target.pluginId && entry.platform === target.platform
|
|
8595
|
-
&& entry.scope === target.scope);
|
|
8596
8516
|
const targetState = blockedTarget ? { label: '待确认', status: 'warning' }
|
|
8597
|
-
:
|
|
8598
|
-
:
|
|
8599
|
-
:
|
|
8517
|
+
: target.state === 'completed' ? { label: '完成', status: 'success' }
|
|
8518
|
+
: target.state === 'kept' ? { label: '无需更改', status: 'success' }
|
|
8519
|
+
: target.state === 'failed' ? { label: '失败', status: 'error' }
|
|
8600
8520
|
: { label: '未开始', status: 'muted' };
|
|
8601
|
-
|
|
8521
|
+
const relation = target.relation === 'direct' ? '直接依赖'
|
|
8522
|
+
: target.relation === 'transitive' ? '间接依赖' : '所选插件位置';
|
|
8523
|
+
return _jsx(ResultRow, { title: `${root.pluginId}${targetPluginId === root.pluginId ? '' : ` → ${targetPluginId}`} · ${platformLabel(target.platform)} · ${scopeLabel(target.scope)}`, description: blockedTarget
|
|
8602
8524
|
? pluginWriteTaskBlockLabel(blockedTarget.reason)
|
|
8603
|
-
:
|
|
8525
|
+
: `${relation}${target.errorCode ? ` · ${target.errorCode}` : ''}`, meta: `${targetState.label}${target.errorCode ? ` · ${target.errorCode}` : ''}`, status: targetState.status, compact: !blockedTarget }, `target:${root.pluginId}:${key}`);
|
|
8604
8526
|
});
|
|
8605
8527
|
});
|
|
8606
|
-
const
|
|
8528
|
+
const batchPluginResultRows = (resultSummary?.batch?.rootResults ?? []).map((root) => {
|
|
8607
8529
|
const rootState = taskRootState(root.state);
|
|
8608
8530
|
const rootName = props.controller.getPluginOverview(root.pluginId)?.displayName
|
|
8609
8531
|
?? root.pluginId.split('/').at(-1);
|
|
8610
8532
|
return _jsx(ResultRow, { title: rootName, description: `${root.targets.length} 个使用位置`, meta: rootState.label, status: rootState.status, compact: true }, `batch-root:${root.pluginId}`);
|
|
8611
|
-
})
|
|
8533
|
+
});
|
|
8534
|
+
const batchLocationResultRows = prioritizedTargets.map((target) => {
|
|
8612
8535
|
const state = operationTargetStateLabel(target.state);
|
|
8613
8536
|
const relation = target.relation === 'requested' ? '你选择的插件'
|
|
8614
8537
|
: target.relation === 'direct' ? '直接依赖'
|
|
8615
8538
|
: target.relation === 'transitive' ? '间接依赖' : undefined;
|
|
8616
8539
|
return _jsx(ResultRow, { title: `${resultTargetName(target)} · ${platformLabel(target.platform)} · ${scopeLabel(target.scope)}`, description: relation, meta: state.label, status: state.status ?? 'muted', compact: true }, `batch-target:${target.pluginId ?? ''}:${target.platform}:${target.scope}`);
|
|
8617
|
-
})
|
|
8540
|
+
});
|
|
8618
8541
|
const taskResultLimit = Math.max(1, pageActionBudget(5) - resultActionViewport.limit);
|
|
8619
|
-
const
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
const taskResultOffset = Math.min(batchTargetOffset, Math.max(0,
|
|
8623
|
-
const
|
|
8542
|
+
const pluginResultRows = taskOperation ? taskSelectedPluginRows : batchPluginResultRows;
|
|
8543
|
+
const locationResultRows = taskOperation ? taskLocationRows : batchLocationResultRows;
|
|
8544
|
+
const combinedResultRows = [...pluginResultRows, ...locationResultRows];
|
|
8545
|
+
const taskResultOffset = Math.min(batchTargetOffset, Math.max(0, combinedResultRows.length - 1));
|
|
8546
|
+
const visiblePluginResultRows = taskResultOffset < pluginResultRows.length
|
|
8547
|
+
? pluginResultRows.slice(taskResultOffset, taskResultOffset + taskResultLimit) : [];
|
|
8548
|
+
const visibleLocationStart = Math.max(0, taskResultOffset - pluginResultRows.length);
|
|
8549
|
+
const remainingResultRows = taskResultLimit - visiblePluginResultRows.length;
|
|
8550
|
+
const visibleLocationResultRows = locationResultRows.slice(visibleLocationStart, visibleLocationStart + remainingResultRows);
|
|
8624
8551
|
if (taskOperation || batchOperation || resultTargets.length > resultTargetLimit
|
|
8625
8552
|
|| prioritizedPortablePairs.length > portableSkillLimit) {
|
|
8626
8553
|
help = 'p/n 查看全部项目 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
8627
8554
|
}
|
|
8628
|
-
content = taskOperation || batchOperation ? _jsxs(Box, { flexDirection: "column", children: [
|
|
8629
|
-
|
|
8555
|
+
content = taskOperation || batchOperation ? _jsxs(Box, { flexDirection: "column", children: [taskResultOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${taskResultOffset} 项`, status: "muted", compact: true }) : null, visiblePluginResultRows.length > 0 ? _jsx(ResultCard, { status: resultStatus, title: "\u63D2\u4EF6\u7ED3\u679C", meta: `${pluginResultRows.length} 个插件`, children: visiblePluginResultRows }) : null, visibleLocationResultRows.length > 0 ? _jsx(ResultCard, { status: resultStatus, title: "\u4F7F\u7528\u4F4D\u7F6E\u4E0E\u6240\u9700\u63D2\u4EF6", meta: `${locationResultRows.length} 项`, children: visibleLocationResultRows }) : null, combinedResultRows.length > taskResultOffset + visiblePluginResultRows.length + visibleLocationResultRows.length
|
|
8556
|
+
? _jsx(StaticRow, { title: "\u2193 \u540E\u9762\u8FD8\u6709", meta: `${combinedResultRows.length - taskResultOffset - visiblePluginResultRows.length - visibleLocationResultRows.length} 项`, status: "muted", compact: true }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true, offset: resultActionViewport.offset, limit: resultActionViewport.limit })] }) : portableOperation ? _jsxs(Box, { flexDirection: "column", children: [portableRecheckBusy
|
|
8630
8557
|
? _jsx(ProgressRow, { title: "\u6B63\u5728\u91CD\u65B0\u68C0\u67E5\u7ED3\u679C", description: "\u53EA\u8BFB\u53D6 Skills CLI \u5F53\u524D\u72B6\u6001\uFF0C\u4E0D\u6267\u884C\u5B89\u88C5", state: "active", compact: policy.mode === 'compact' })
|
|
8631
8558
|
: null, portableResultDetailOpen ? _jsxs(_Fragment, { children: [safePortableResultDetailOffset > 0
|
|
8632
8559
|
? _jsx(StaticRow, { title: `↑ 前面还有 ${safePortableResultDetailOffset} 行`, status: "muted", compact: true }) : null, visiblePortableResultDetailLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${safePortableResultDetailOffset + index}:${line}`)), safePortableResultDetailOffset + visiblePortableResultDetailLines.length
|
|
@@ -8653,7 +8580,6 @@ export function ConsoleAppV4(props) {
|
|
|
8653
8580
|
? '这里显示已验证目录包声明的组成,不读取或展示完整操作指令。'
|
|
8654
8581
|
: '当前没有可安全读取的目录内容。';
|
|
8655
8582
|
const contentNavigationActions = [
|
|
8656
|
-
{ label: '返回插件详情', run: back },
|
|
8657
8583
|
{ label: '查看技术详情', run: () => go({ name: 'pluginTechnical', pluginId: plugin.pluginId }) },
|
|
8658
8584
|
];
|
|
8659
8585
|
const contentTypeLabels = {
|
|
@@ -8665,41 +8591,27 @@ export function ConsoleAppV4(props) {
|
|
|
8665
8591
|
const versionDiffers = contentAvailable
|
|
8666
8592
|
&& installedVersions.some((version) => version !== overview.pluginVersion);
|
|
8667
8593
|
const items = overview?.items ?? [];
|
|
8668
|
-
const
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
}
|
|
8688
|
-
const contentViewport = actionViewport(actions, true, focus, scrollOffset, pageActionBudget(Math.min(items.length, pageRows) * 5 + 2));
|
|
8689
|
-
content = _jsxs(Box, { flexDirection: "column", children: [contentAvailable ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u7248\u672C\u8BC1\u636E", meta: `插件 ${overview.pluginVersion} · 目录 ${overview.catalogVersion}`, compact: true }), _jsx(StaticRow, { title: installedVersions.length > 0
|
|
8690
|
-
? `已安装 ${installedVersions.join('、')}`
|
|
8691
|
-
: '当前没有已确认的安装版本', description: versionDiffers
|
|
8692
|
-
? '以下是目录版本内容,不代表旧安装版本的内容。'
|
|
8693
|
-
: '内容来自当前已验证的目录包。', status: versionDiffers ? 'warning' : 'info', compact: true })] }) : contentState === 'loading'
|
|
8594
|
+
const itemActions = items.map((item) => ({
|
|
8595
|
+
actionId: `content:${item.id}`,
|
|
8596
|
+
label: item.name,
|
|
8597
|
+
description: `${contentTypeLabels[item.type]} · ${item.tools.join('、') || '适用工具待确认'} · ${item.description ?? '目录没有提供简短描述'}`,
|
|
8598
|
+
status: item.description ? undefined : 'warning',
|
|
8599
|
+
}));
|
|
8600
|
+
actions = [...itemActions, ...contentNavigationActions];
|
|
8601
|
+
const fixedContentRows = contentAvailable ? 4 : 3;
|
|
8602
|
+
currentActionViewportLineBudget = pageActionBudget(fixedContentRows + (overview?.notices.length ?? 0));
|
|
8603
|
+
const contentViewport = actionViewport(actions, false, focus, scrollOffset, currentActionViewportLineBudget);
|
|
8604
|
+
if (items.length > contentViewport.limit) {
|
|
8605
|
+
context = `${items.length} 项内容 · 上下键滚动`;
|
|
8606
|
+
help = '↑↓ 阅读全部内容 · Enter 选择 · Esc 返回';
|
|
8607
|
+
}
|
|
8608
|
+
content = _jsxs(Box, { flexDirection: "column", children: [contentAvailable ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u76EE\u5F55\u7248\u672C", meta: `${overview.pluginVersion} · Catalog ${overview.catalogVersion}`, compact: true }), _jsx(StaticRow, { title: installedVersions.length > 0
|
|
8609
|
+
? `安装版本 ${installedVersions.join('、')}`
|
|
8610
|
+
: '安装版本尚未确认', description: versionDiffers
|
|
8611
|
+
? '以下清单属于目录版本,不代表旧安装版本的内容。'
|
|
8612
|
+
: '以下清单来自当前已验证的目录包。', status: versionDiffers ? 'warning' : 'info', compact: true })] }) : contentState === 'loading'
|
|
8694
8613
|
? _jsx(Callout, { status: "info", title: "\u6B63\u5728\u8BFB\u53D6\u5185\u5BB9", description: "\u5B8C\u6210\u540E\u5C06\u5728\u5F53\u524D\u9875\u9762\u663E\u793A\u3002" })
|
|
8695
|
-
: _jsx(Callout, { status: "warning", title: "\u5185\u5BB9\u6682\u4E0D\u53EF\u7528", description: "\u53EF\u4EE5\u67E5\u770B\u6280\u672F\u8BE6\u60C5\u6216\u6062\u590D\u63D2\u4EF6\u6765\u6E90\u540E\u91CD\u8BD5\u3002" }),
|
|
8696
|
-
}
|
|
8697
|
-
else if (route.name === 'pluginAbout' && plugin) {
|
|
8698
|
-
breadcrumb = `${plugin.displayName} / 关于`;
|
|
8699
|
-
title = plugin.displayName;
|
|
8700
|
-
description = plugin.description;
|
|
8701
|
-
actions = [{ label: '查看技术详情', run: () => go({ name: 'pluginTechnical', pluginId: plugin.pluginId }) }, { label: '查看来源', run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }) }];
|
|
8702
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { children: [_jsx(StaticRow, { title: "\u7248\u672C", meta: plugin.version ?? '未知' }), _jsx(StaticRow, { title: "\u6765\u6E90", meta: plugin.sourceLabel }), _jsx(StaticRow, { title: "\u53EF\u7528\u76EE\u6807\u5E73\u53F0", meta: plugin.supportedPlatforms.map(platformLabel).join('、') }), _jsx(StaticRow, { title: "\u914D\u7F6E", meta: `${plugin.configFieldCount} 个字段` })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
8614
|
+
: _jsx(Callout, { status: "warning", title: "\u5185\u5BB9\u6682\u4E0D\u53EF\u7528", description: "\u53EF\u4EE5\u67E5\u770B\u6280\u672F\u8BE6\u60C5\u6216\u6062\u590D\u63D2\u4EF6\u6765\u6E90\u540E\u91CD\u8BD5\u3002" }), overview?.notices.map((notice, index) => _jsx(StaticRow, { title: notice, status: "warning", compact: true }, `${index}:${notice}`)), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: false, offset: contentViewport.offset, limit: contentViewport.limit })] });
|
|
8703
8615
|
}
|
|
8704
8616
|
else if (route.name === 'pluginTechnical' && plugin) {
|
|
8705
8617
|
breadcrumb = `${plugin.displayName} / 技术详情`;
|
|
@@ -8708,32 +8620,40 @@ export function ConsoleAppV4(props) {
|
|
|
8708
8620
|
description = plugin.capabilityUnsupported
|
|
8709
8621
|
? '当前 AW CLI 不支持此插件所需 capability。'
|
|
8710
8622
|
: '默认页面不会展示这些内部信息。';
|
|
8711
|
-
actions = [{ label: '返回插件', run: back }];
|
|
8623
|
+
actions = [{ role: 'navigation', label: '返回插件', run: back }];
|
|
8712
8624
|
const prioritizedComponents = [...plugin.technicalComponents].sort((left, right) => {
|
|
8713
8625
|
const priority = (state) => state === 'error' ? 0
|
|
8714
8626
|
: state === 'partial' ? 1 : state === 'absent' ? 2 : 3;
|
|
8715
8627
|
return priority(left.state) - priority(right.state);
|
|
8716
8628
|
});
|
|
8717
|
-
const
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
?
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8629
|
+
const technicalFields = [
|
|
8630
|
+
`canonical pluginId · ${plugin.pluginId}`,
|
|
8631
|
+
`来源 · ${plugin.sourceId}`,
|
|
8632
|
+
...prioritizedComponents.map((component) => `组件 · ${component.state === 'absent' ? '缺失' : component.state}${component.errorCode ? ` · ${component.errorCode}` : ''} · ${component.key} · ${platformLabel(component.platform)} · ${component.shared ? '平台共享' : scopeLabel(component.scope)}`),
|
|
8633
|
+
...(plugin.capabilityUnsupported ? [
|
|
8634
|
+
'failure code · awCapabilityUnsupported',
|
|
8635
|
+
'capability 状态 · 当前 AW CLI 不支持',
|
|
8636
|
+
`缺少 capability · ${plugin.missingCapabilities?.join('、') ?? 'Status 未提供具体 capability'}`,
|
|
8637
|
+
`恢复方向 · ${plugin.capabilityRecovery ?? '升级 AW CLI 到支持所需 capability 的版本后重试。'}`,
|
|
8638
|
+
] : []),
|
|
8639
|
+
...plugin.installedPlacements.map((placement) => `${platformLabel(placement.platform)} target · ${placementStatus(placement).value}`),
|
|
8640
|
+
];
|
|
8641
|
+
const technicalLines = technicalFields.flatMap((field) => wrapDisplayText(field, size.columns - 6));
|
|
8642
|
+
const technicalPageRows = Math.max(1, pageActionBudget(7));
|
|
8643
|
+
const technicalOffset = Math.min(batchTargetOffset, Math.max(0, technicalLines.length - 1));
|
|
8644
|
+
const visibleTechnicalLines = technicalLines.slice(technicalOffset, technicalOffset + technicalPageRows);
|
|
8645
|
+
if (technicalLines.length > technicalPageRows) {
|
|
8727
8646
|
actions.push(...paginationActions({
|
|
8728
|
-
offset:
|
|
8729
|
-
total:
|
|
8730
|
-
pageRows:
|
|
8731
|
-
move: (direction) => moveBatchTargetPage(
|
|
8647
|
+
offset: technicalOffset,
|
|
8648
|
+
total: technicalLines.length,
|
|
8649
|
+
pageRows: technicalPageRows,
|
|
8650
|
+
move: (direction) => moveBatchTargetPage(technicalLines.length, technicalPageRows, direction),
|
|
8732
8651
|
}));
|
|
8733
|
-
referenceDetailPagination = { total:
|
|
8734
|
-
help = 'p/n
|
|
8652
|
+
referenceDetailPagination = { total: technicalLines.length, pageRows: technicalPageRows };
|
|
8653
|
+
help = 'p/n 或 PgUp/PgDn 阅读技术字段 · ↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
8735
8654
|
}
|
|
8736
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(TechnicalDetails, { children: [
|
|
8655
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(TechnicalDetails, { children: [technicalOffset > 0 ? _jsx(StaticRow, { title: `↑ 前面还有 ${technicalOffset} 行`, status: "muted", compact: true }) : null, visibleTechnicalLines.map((line, index) => _jsx(StaticRow, { title: line, compact: true }, `${technicalOffset + index}:${line}`)), technicalOffset + visibleTechnicalLines.length < technicalLines.length
|
|
8656
|
+
? _jsx(StaticRow, { title: `↓ 后面还有 ${technicalLines.length - technicalOffset - visibleTechnicalLines.length} 行`, status: "muted", compact: true }) : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true })] });
|
|
8737
8657
|
}
|
|
8738
8658
|
else {
|
|
8739
8659
|
const missingPlugin = definition.entity === 'plugin' && plugin === undefined;
|
|
@@ -8759,13 +8679,12 @@ export function ConsoleAppV4(props) {
|
|
|
8759
8679
|
case 'pluginContent':
|
|
8760
8680
|
case 'pluginMore':
|
|
8761
8681
|
case 'platform':
|
|
8762
|
-
case 'pluginAbout':
|
|
8763
8682
|
case 'pluginTechnical':
|
|
8764
8683
|
case 'configLayer':
|
|
8765
8684
|
unavailable = missingPlugin ? 'plugin' : 'flow';
|
|
8766
8685
|
break;
|
|
8686
|
+
case 'portablePreparing':
|
|
8767
8687
|
case 'portableSkillSelect':
|
|
8768
|
-
case 'portableSkillSummary':
|
|
8769
8688
|
case 'portableDependencies':
|
|
8770
8689
|
case 'portableAgentMode':
|
|
8771
8690
|
case 'portableAgentInput':
|
|
@@ -8833,6 +8752,41 @@ export function ConsoleAppV4(props) {
|
|
|
8833
8752
|
: 'h/H 完成后导航'} · Esc 撤销等待 · ${help}`
|
|
8834
8753
|
: `h 首页 · H 重载 · ${help}`;
|
|
8835
8754
|
}
|
|
8755
|
+
const helpParts = help.split(' · ').map((part) => part.startsWith('p/n ') ? 'p/n 阅读' : part);
|
|
8756
|
+
const isRoutineKey = (part) => /^(↑|Enter|Space|Esc|Ctrl-C|p\/n)/u.test(part);
|
|
8757
|
+
help = [...helpParts.filter(isRoutineKey), ...helpParts.filter((part) => !isRoutineKey(part))].join(' · ');
|
|
8758
|
+
if (searchFocus)
|
|
8759
|
+
help = '←→ 光标 · ↑↓ 移动结果 · Enter/Esc 完成输入';
|
|
8760
|
+
else if (bottomActions.length > 0 && actions.length > 8)
|
|
8761
|
+
help += ' · a 下方操作';
|
|
8762
|
+
useEffect(() => {
|
|
8763
|
+
if ((bottomActions.length > 0 || route.name === 'issueList' || route.name === 'operationHistory')
|
|
8764
|
+
&& focus >= actions.length && actions.length > 0)
|
|
8765
|
+
setFocus(actions.length - 1);
|
|
8766
|
+
else if (actions[focus]?.role === 'navigation')
|
|
8767
|
+
setFocus(moveFocus(actions, focus, 1));
|
|
8768
|
+
}, [routeKey, focus, actions.length, actions.map((action) => action.role ?? '').join(',')]);
|
|
8769
|
+
const listCandidates = route.name === 'pluginList'
|
|
8770
|
+
|| route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
8771
|
+
? actions.filter((action) => action.pluginId !== undefined) : [];
|
|
8772
|
+
const listCandidateSignature = listCandidates.map((action) => action.pluginId).join('\0');
|
|
8773
|
+
useEffect(() => {
|
|
8774
|
+
if (route.name !== 'pluginList' && !(route.name === 'batchSelection' && batchDraft?.stage === 'select')) {
|
|
8775
|
+
listFocusAnchor.current = undefined;
|
|
8776
|
+
return;
|
|
8777
|
+
}
|
|
8778
|
+
const previous = listFocusAnchor.current;
|
|
8779
|
+
let nextFocus = focus;
|
|
8780
|
+
if (previous?.frameId === snapshot.router.currentFrameId && previous.ids !== listCandidateSignature
|
|
8781
|
+
&& previous.entityId) {
|
|
8782
|
+
const retained = listCandidates.findIndex((action) => action.pluginId === previous.entityId);
|
|
8783
|
+
nextFocus = retained >= 0 ? retained : Math.min(focus, Math.max(0, listCandidates.length - 1));
|
|
8784
|
+
if (nextFocus !== focus)
|
|
8785
|
+
setFocus(nextFocus);
|
|
8786
|
+
}
|
|
8787
|
+
listFocusAnchor.current = { frameId: snapshot.router.currentFrameId,
|
|
8788
|
+
ids: listCandidateSignature, entityId: listCandidates[nextFocus]?.pluginId };
|
|
8789
|
+
}, [snapshot.router.currentFrameId, route.name, batchDraft?.stage, listCandidateSignature, focus]);
|
|
8836
8790
|
const targetActionSignature = route.name === 'installTargets' && route.view !== 'blocked'
|
|
8837
8791
|
? actions.map((action) => String(Boolean(action.disabled))).join(',')
|
|
8838
8792
|
: '';
|
|
@@ -8895,7 +8849,7 @@ export function ConsoleAppV4(props) {
|
|
|
8895
8849
|
};
|
|
8896
8850
|
}, [dynamicActionSignature, routeKey]);
|
|
8897
8851
|
const runAction = (action) => {
|
|
8898
|
-
if (!action || action.disabled)
|
|
8852
|
+
if (!action || action.disabled || action.role === 'navigation')
|
|
8899
8853
|
return;
|
|
8900
8854
|
try {
|
|
8901
8855
|
const pending = action.run?.();
|
|
@@ -9194,35 +9148,6 @@ export function ConsoleAppV4(props) {
|
|
|
9194
9148
|
}
|
|
9195
9149
|
return;
|
|
9196
9150
|
}
|
|
9197
|
-
if (pluginListChooser) {
|
|
9198
|
-
const sourceIds = ['all', ...props.controller.listSources().map((source) => source.id)];
|
|
9199
|
-
const itemCount = pluginListChooser.kind === 'source' ? sourceIds.length : PLUGIN_FILTERS.length;
|
|
9200
|
-
if (key.escape) {
|
|
9201
|
-
setPluginListChooser(undefined);
|
|
9202
|
-
}
|
|
9203
|
-
else if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) {
|
|
9204
|
-
const direction = key.upArrow || key.leftArrow ? -1 : 1;
|
|
9205
|
-
setPluginListChooser((current) => current ? {
|
|
9206
|
-
...current,
|
|
9207
|
-
focus: moveIndex(itemCount, current.focus, direction),
|
|
9208
|
-
} : current);
|
|
9209
|
-
}
|
|
9210
|
-
else if (key.return) {
|
|
9211
|
-
const selectedIndex = Math.min(pluginListChooser.focus, Math.max(0, itemCount - 1));
|
|
9212
|
-
if (pluginListChooser.kind === 'source') {
|
|
9213
|
-
const selectedSourceId = sourceIds[selectedIndex];
|
|
9214
|
-
if (selectedSourceId)
|
|
9215
|
-
choosePluginListSource?.(selectedSourceId);
|
|
9216
|
-
}
|
|
9217
|
-
else {
|
|
9218
|
-
const selectedFilter = PLUGIN_FILTERS[selectedIndex];
|
|
9219
|
-
if (selectedFilter)
|
|
9220
|
-
choosePluginListFilter?.(selectedFilter);
|
|
9221
|
-
}
|
|
9222
|
-
setPluginListChooser(undefined);
|
|
9223
|
-
}
|
|
9224
|
-
return;
|
|
9225
|
-
}
|
|
9226
9151
|
if (overlay) {
|
|
9227
9152
|
if (input.toLowerCase() === 'q' || (key.ctrl && input.toLowerCase() === 'c')) {
|
|
9228
9153
|
if (overlay === 'sessionNavigation')
|
|
@@ -9349,17 +9274,27 @@ export function ConsoleAppV4(props) {
|
|
|
9349
9274
|
setPortableResultDetailOffset((value) => Math.min(Math.max(0, total - 1), Math.max(0, value + direction * pageRows)));
|
|
9350
9275
|
return;
|
|
9351
9276
|
}
|
|
9277
|
+
if ((key.pageUp || key.pageDown || input.toLowerCase() === 'p' || input.toLowerCase() === 'n')
|
|
9278
|
+
&& route.name === 'portableDependencies' && plugin) {
|
|
9279
|
+
const total = dependencyOverview(plugin)?.dependencies.length ?? 0;
|
|
9280
|
+
const pageRows = showTechnical ? 1 : responsiveBudget(2, 3);
|
|
9281
|
+
setBatchTargetOffset((value) => Math.min(Math.max(0, total - pageRows), Math.max(0, value + (key.pageUp || input.toLowerCase() === 'p' ? -pageRows : pageRows))));
|
|
9282
|
+
return;
|
|
9283
|
+
}
|
|
9352
9284
|
if ((key.pageUp || key.pageDown || input.toLowerCase() === 'p' || input.toLowerCase() === 'n')
|
|
9353
9285
|
&& (route.name === 'pluginContent'
|
|
9354
9286
|
|| route.name === 'pluginTechnical'
|
|
9355
9287
|
|| route.name === 'projectStatus' && showTechnical
|
|
9356
9288
|
|| route.name === 'issueDetail' && showTechnical
|
|
9289
|
+
|| route.name === 'portableBlocker' && showTechnical
|
|
9290
|
+
|| route.name === 'configUnavailable' && showTechnical
|
|
9357
9291
|
|| route.name === 'sourceRemoveBlocked' && sourceDependenciesExpanded
|
|
9358
9292
|
|| route.name === 'pluginDependencies' && route.view === 'removeBlocked' && !showTechnical
|
|
9359
9293
|
|| route.name === 'pluginDependencyNode'
|
|
9360
9294
|
&& (route.view === 'references' || route.view === 'details')
|
|
9361
9295
|
|| route.name === 'pluginDetail'
|
|
9362
9296
|
|| route.name === 'configSave' && route.view === 'changes'
|
|
9297
|
+
|| route.name === 'configFields' && route.view === 'values'
|
|
9363
9298
|
|| route.name === 'sourceSave' && route.view === 'changes'
|
|
9364
9299
|
|| route.name === 'review'
|
|
9365
9300
|
|| route.name === 'result')
|
|
@@ -9376,18 +9311,6 @@ export function ConsoleAppV4(props) {
|
|
|
9376
9311
|
setBatchTargetOffset((value) => Math.min(Math.max(0, total - 1), Math.max(0, value + (key.pageUp ? -1 : 1))));
|
|
9377
9312
|
return;
|
|
9378
9313
|
}
|
|
9379
|
-
if ((key.pageUp || key.pageDown) && route.name === 'pluginTechnical' && plugin) {
|
|
9380
|
-
const total = plugin.technicalComponents.length;
|
|
9381
|
-
const pageRows = 1;
|
|
9382
|
-
setBatchTargetOffset((value) => Math.min(Math.max(0, total - 1), Math.max(0, value + (key.pageUp ? -pageRows : pageRows))));
|
|
9383
|
-
return;
|
|
9384
|
-
}
|
|
9385
|
-
if ((key.pageUp || key.pageDown) && route.name === 'issueDetail' && issue && showTechnical) {
|
|
9386
|
-
const total = diagnosticDetailRowCount(issue.diagnostic);
|
|
9387
|
-
const pageRows = responsiveBudget(5, 10);
|
|
9388
|
-
setBatchTargetOffset((value) => Math.min(Math.max(0, total - pageRows), Math.max(0, value + (key.pageUp ? -pageRows : pageRows))));
|
|
9389
|
-
return;
|
|
9390
|
-
}
|
|
9391
9314
|
if ((key.pageUp || key.pageDown || input.toLowerCase() === 'p' || input.toLowerCase() === 'n')
|
|
9392
9315
|
&& route.name === 'sourceTechnical') {
|
|
9393
9316
|
const total = diagnosticDetailLines(resolveSourceTechnicalDiagnostic(route.sourceId), size.columns - 6).length;
|
|
@@ -9420,12 +9343,9 @@ export function ConsoleAppV4(props) {
|
|
|
9420
9343
|
? props.controller.getOperationDiagnostic(route.recordId) : undefined;
|
|
9421
9344
|
const preview = route.name === 'operationReportPreview'
|
|
9422
9345
|
? props.controller.previewOperationReport(route.recordId) : undefined;
|
|
9423
|
-
const total = detail ? operationDiagnosticLineCount(detail)
|
|
9424
|
-
: preview ? operationReportLineCount(preview) : 0;
|
|
9425
|
-
const
|
|
9426
|
-
const pageRows = key.pageUp || key.pageDown
|
|
9427
|
-
? policy.mode === 'compact' ? 2 : Math.max(1, pageActionBudget(5))
|
|
9428
|
-
: visibleRows;
|
|
9346
|
+
const total = detail ? operationDiagnosticLineCount(detail, size.columns)
|
|
9347
|
+
: preview ? operationReportLineCount(preview, size.columns) : 0;
|
|
9348
|
+
const pageRows = operationDetailPageRows;
|
|
9429
9349
|
setScrollOffset((value) => Math.min(Math.max(0, total - pageRows), Math.max(0, value + (key.pageUp || input.toLowerCase() === 'p' ? -pageRows : pageRows))));
|
|
9430
9350
|
return;
|
|
9431
9351
|
}
|
|
@@ -9575,9 +9495,18 @@ export function ConsoleAppV4(props) {
|
|
|
9575
9495
|
setSourceInputError(undefined);
|
|
9576
9496
|
return;
|
|
9577
9497
|
}
|
|
9498
|
+
if (route.name === 'configFieldEditor' && activeField && key.ctrl && input.toLowerCase() === 'r') {
|
|
9499
|
+
const canUnset = ['project', 'user'].some((scope) => configLayerPages[scope]?.groups.flatMap((group) => group.fields)
|
|
9500
|
+
.some((field) => field.key === activeField.key && configFieldCanUnset(field)));
|
|
9501
|
+
if (canUnset)
|
|
9502
|
+
removeDraft(activeField.key);
|
|
9503
|
+
return;
|
|
9504
|
+
}
|
|
9578
9505
|
if (route.name === 'configFieldEditor'
|
|
9579
9506
|
&& (route.editor === 'string' || route.editor === 'number')
|
|
9580
|
-
&& ((activeField?.choices?.length ?? 0) === 0 || route.mode === 'custom')
|
|
9507
|
+
&& ((activeField?.choices?.length ?? 0) === 0 || route.mode === 'custom')
|
|
9508
|
+
&& ['project', 'user'].some((scope) => configLayerPages[scope]?.groups.flatMap((group) => group.fields)
|
|
9509
|
+
.some((field) => field.key === activeField?.key && configFieldCanSet(field)))) {
|
|
9581
9510
|
if (key.escape) {
|
|
9582
9511
|
setConfigCandidate(undefined);
|
|
9583
9512
|
back();
|
|
@@ -9595,7 +9524,11 @@ export function ConsoleAppV4(props) {
|
|
|
9595
9524
|
}
|
|
9596
9525
|
let candidate = inputValue;
|
|
9597
9526
|
if (route.editor === 'number') {
|
|
9598
|
-
|
|
9527
|
+
if (parseConfigNumberInput(inputValue) === undefined) {
|
|
9528
|
+
setInputError('请输入数字;空输入不会保存为 0。');
|
|
9529
|
+
return;
|
|
9530
|
+
}
|
|
9531
|
+
candidate = parseConfigNumberInput(inputValue);
|
|
9599
9532
|
}
|
|
9600
9533
|
const issues = validatePluginConfigValue(activeField.definition, candidate, activeField.key);
|
|
9601
9534
|
if (issues.length > 0) {
|
|
@@ -9668,9 +9601,12 @@ export function ConsoleAppV4(props) {
|
|
|
9668
9601
|
back();
|
|
9669
9602
|
return;
|
|
9670
9603
|
}
|
|
9604
|
+
if (activePropertyDefinition.type === 'number' && parseConfigNumberInput(inputValue) === undefined) {
|
|
9605
|
+
setInputError('请输入数字;空输入不会保存为 0。');
|
|
9606
|
+
return;
|
|
9607
|
+
}
|
|
9671
9608
|
const candidate = activePropertyDefinition.type === 'number'
|
|
9672
|
-
?
|
|
9673
|
-
: inputValue;
|
|
9609
|
+
? parseConfigNumberInput(inputValue) : inputValue;
|
|
9674
9610
|
if (updateObjectProperty(route.propertyKey, candidate))
|
|
9675
9611
|
back();
|
|
9676
9612
|
return;
|
|
@@ -9683,197 +9619,82 @@ export function ConsoleAppV4(props) {
|
|
|
9683
9619
|
return;
|
|
9684
9620
|
}
|
|
9685
9621
|
if (searchFocus && (route.name === 'pluginList' || route.name === 'batchSelection')) {
|
|
9686
|
-
|
|
9622
|
+
const currentQuery = route.name === 'pluginList' ? query : batchDraft?.query ?? '';
|
|
9623
|
+
const parts = [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(currentQuery)]
|
|
9624
|
+
.map((part) => part.segment);
|
|
9625
|
+
const cursor = Math.min(searchCursor, parts.length);
|
|
9626
|
+
if (key.escape || key.return) {
|
|
9687
9627
|
setSearchFocus(false);
|
|
9688
9628
|
return;
|
|
9689
9629
|
}
|
|
9690
|
-
if (key.return) {
|
|
9691
|
-
setSearchFocus(false);
|
|
9692
|
-
if (route.name === 'pluginList') {
|
|
9693
|
-
const row = pluginRows[focus];
|
|
9694
|
-
if (row?.menuAction)
|
|
9695
|
-
row.menuAction();
|
|
9696
|
-
else if (row)
|
|
9697
|
-
go({ name: 'pluginDetail', pluginId: row.pluginId });
|
|
9698
|
-
}
|
|
9699
|
-
return;
|
|
9700
|
-
}
|
|
9701
9630
|
if (key.upArrow || key.downArrow) {
|
|
9702
9631
|
setSearchFocus(false);
|
|
9703
|
-
|
|
9632
|
+
const candidateCount = route.name === 'batchSelection' && batchDraft
|
|
9633
|
+
? batchCandidates(batchDraft).length : pluginRows.length;
|
|
9634
|
+
setFocus((value) => moveIndex(candidateCount, Math.min(value, Math.max(0, candidateCount - 1)), key.upArrow ? -1 : 1));
|
|
9704
9635
|
return;
|
|
9705
9636
|
}
|
|
9706
9637
|
if (key.leftArrow || key.rightArrow) {
|
|
9707
|
-
|
|
9708
|
-
const tabs = ['all', ...props.controller.listSources().map((source) => source.id)];
|
|
9709
|
-
const current = route.name === 'pluginList' ? route.sourceId ?? 'all' : batchDraft?.sourceId ?? 'all';
|
|
9710
|
-
const direction = key.leftArrow ? -1 : 1;
|
|
9711
|
-
const next = tabs[(tabs.indexOf(current) + direction + tabs.length) % tabs.length];
|
|
9712
|
-
if (route.name === 'pluginList') {
|
|
9713
|
-
props.controller.replace({ name: 'pluginList', mode: route.mode, ...(next !== 'all' ? { sourceId: next } : {}) }, { ...snapshot.router.current.context, query, installFilter, sourceTabId: next });
|
|
9714
|
-
}
|
|
9715
|
-
else {
|
|
9716
|
-
setBatchDraft((draft) => draft ? {
|
|
9717
|
-
...draft,
|
|
9718
|
-
...(next === 'all' ? { sourceId: undefined } : { sourceId: next }),
|
|
9719
|
-
showSelected: false,
|
|
9720
|
-
} : draft);
|
|
9721
|
-
}
|
|
9722
|
-
setFocus(0);
|
|
9723
|
-
setScrollOffset(0);
|
|
9638
|
+
setSearchCursor(Math.min(parts.length, Math.max(0, cursor + (key.leftArrow ? -1 : 1))));
|
|
9724
9639
|
return;
|
|
9725
9640
|
}
|
|
9641
|
+
let nextCursor = cursor;
|
|
9642
|
+
if (input === '\u0015' || input.toLowerCase() === 'u' && key.ctrl) {
|
|
9643
|
+
parts.splice(0);
|
|
9644
|
+
nextCursor = 0;
|
|
9645
|
+
}
|
|
9646
|
+
else if (key.backspace || key.delete) {
|
|
9647
|
+
if (cursor > 0)
|
|
9648
|
+
parts.splice(--nextCursor, 1);
|
|
9649
|
+
}
|
|
9650
|
+
else if (input && !key.ctrl && !key.meta && input >= ' ') {
|
|
9651
|
+
const inserted = [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(input)]
|
|
9652
|
+
.map((part) => part.segment);
|
|
9653
|
+
parts.splice(cursor, 0, ...inserted);
|
|
9654
|
+
nextCursor += inserted.length;
|
|
9655
|
+
}
|
|
9656
|
+
const nextQuery = parts.join('');
|
|
9657
|
+
setSearchCursor(nextCursor);
|
|
9726
9658
|
if (route.name === 'pluginList') {
|
|
9727
|
-
const nextQuery = input === '\u0015' || (input.toLowerCase() === 'u' && key.ctrl)
|
|
9728
|
-
? ''
|
|
9729
|
-
: key.backspace || key.delete
|
|
9730
|
-
? removeLastGrapheme(query)
|
|
9731
|
-
: input && !key.ctrl && !key.meta && input >= ' '
|
|
9732
|
-
? query + input : query;
|
|
9733
9659
|
setQuery(nextQuery);
|
|
9734
|
-
|
|
9735
|
-
mode: route.mode,
|
|
9736
|
-
...(route.sourceId ? { sourceId: route.sourceId } : {}),
|
|
9737
|
-
...(nextQuery ? { query: nextQuery } : {}),
|
|
9738
|
-
installFilter,
|
|
9739
|
-
});
|
|
9740
|
-
const matchingRows = pluginListRowIds(route.mode, matchingItems, nextQuery);
|
|
9741
|
-
setFocus(matchingItems[0] ? matchingRows.indexOf(matchingItems[0].pluginId) : 0);
|
|
9660
|
+
props.controller.updatePageContext({ query: nextQuery });
|
|
9742
9661
|
}
|
|
9743
9662
|
else {
|
|
9744
|
-
setBatchDraft((draft) => draft ? {
|
|
9745
|
-
...draft,
|
|
9746
|
-
query: input === '\u0015' || (input.toLowerCase() === 'u' && key.ctrl)
|
|
9747
|
-
? ''
|
|
9748
|
-
: key.backspace || key.delete
|
|
9749
|
-
? removeLastGrapheme(draft.query)
|
|
9750
|
-
: input && !key.ctrl && !key.meta && input >= ' '
|
|
9751
|
-
? draft.query + input : draft.query,
|
|
9752
|
-
showSelected: false,
|
|
9753
|
-
} : draft);
|
|
9663
|
+
setBatchDraft((draft) => draft ? { ...draft, query: nextQuery, showSelected: false } : draft);
|
|
9754
9664
|
}
|
|
9755
|
-
|
|
9756
|
-
setFocus(0);
|
|
9665
|
+
setFocus(0);
|
|
9757
9666
|
setScrollOffset(0);
|
|
9758
9667
|
return;
|
|
9759
9668
|
}
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
setConfigGroupChooserOpen(false);
|
|
9763
|
-
setFocusZone('actions');
|
|
9764
|
-
setPinnedActionFocus(1);
|
|
9765
|
-
}
|
|
9766
|
-
else if (key.upArrow || key.downArrow) {
|
|
9767
|
-
setConfigGroupChoiceFocus((value) => moveIndex(visibleConfigTabs.length, value, key.upArrow ? -1 : 1));
|
|
9768
|
-
}
|
|
9769
|
-
else if (key.return) {
|
|
9770
|
-
const selected = visibleConfigTabs[configGroupChoiceFocus];
|
|
9771
|
-
if (selected) {
|
|
9772
|
-
props.controller.updatePageContext({
|
|
9773
|
-
configGroupId: selected.id,
|
|
9774
|
-
focusIndex: 0,
|
|
9775
|
-
scrollOffset: 0,
|
|
9776
|
-
});
|
|
9777
|
-
setConfigGroupChooserOpen(false);
|
|
9778
|
-
setFocusZone('content');
|
|
9779
|
-
setFocus(0);
|
|
9780
|
-
setScrollOffset(0);
|
|
9781
|
-
}
|
|
9782
|
-
}
|
|
9783
|
-
return;
|
|
9784
|
-
}
|
|
9785
|
-
if ((route.name === 'pluginList' || route.name === 'sourceList' || route.name === 'projectStatus'
|
|
9786
|
-
|| route.name === 'batchInstallPlatforms' || route.name === 'batchInstallScope'
|
|
9787
|
-
|| route.name === 'batchPlacement' && pinnedActions.length > 0
|
|
9788
|
-
|| route.name === 'portableSkillSelect'
|
|
9789
|
-
|| route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
9790
|
-
|| route.name === 'installTargets' && route.view !== 'blocked') && key.tab) {
|
|
9791
|
-
setFocusZone((current) => current === 'content' ? 'actions' : 'content');
|
|
9792
|
-
return;
|
|
9793
|
-
}
|
|
9794
|
-
if (route.name === 'configFields' && key.tab) {
|
|
9795
|
-
setFocusZone((current) => current === 'content' ? 'actions' : 'content');
|
|
9669
|
+
// Paste and composed text are data, never multiple background commands.
|
|
9670
|
+
if (input.length > 1 && !key.ctrl && !key.meta)
|
|
9796
9671
|
return;
|
|
9797
|
-
|
|
9798
|
-
if (route.name === 'pluginList' && input.toLowerCase() === 'm') {
|
|
9799
|
-
openBatchSelection();
|
|
9672
|
+
if (key.tab)
|
|
9800
9673
|
return;
|
|
9801
|
-
}
|
|
9802
9674
|
if (route.name === 'pluginList' && input === '/') {
|
|
9803
|
-
|
|
9675
|
+
runAction(listQueryActions.find((action) => action.actionId === 'plugin-list-search'));
|
|
9804
9676
|
return;
|
|
9805
9677
|
}
|
|
9806
|
-
if (route.name === 'pluginList' &&
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
if (route.name === 'projectStatus' && focusZone === 'actions'
|
|
9827
|
-
&& (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow)) {
|
|
9828
|
-
setPinnedActionFocus((value) => moveFocus(pinnedActions, value, key.upArrow || key.leftArrow ? -1 : 1));
|
|
9829
|
-
return;
|
|
9830
|
-
}
|
|
9831
|
-
if (route.name === 'projectStatus' && focusZone === 'actions' && key.return) {
|
|
9832
|
-
runAction(pinnedActions[pinnedActionFocus]);
|
|
9833
|
-
return;
|
|
9834
|
-
}
|
|
9835
|
-
if (route.name === 'portableSkillSelect' && focusZone === 'actions'
|
|
9836
|
-
&& (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow)) {
|
|
9837
|
-
setPinnedActionFocus((value) => moveFocus(pinnedActions, value, key.upArrow || key.leftArrow ? -1 : 1));
|
|
9838
|
-
return;
|
|
9839
|
-
}
|
|
9840
|
-
if (route.name === 'portableSkillSelect' && focusZone === 'actions' && key.return) {
|
|
9841
|
-
runAction(pinnedActions[pinnedActionFocus]);
|
|
9842
|
-
return;
|
|
9843
|
-
}
|
|
9844
|
-
if ((route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
9845
|
-
|| route.name === 'installTargets' && route.view !== 'blocked')
|
|
9846
|
-
&& focusZone === 'actions'
|
|
9847
|
-
&& (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow)) {
|
|
9848
|
-
setPinnedActionFocus((value) => moveFocus(pinnedActions, value, key.upArrow || key.leftArrow ? -1 : 1));
|
|
9849
|
-
return;
|
|
9850
|
-
}
|
|
9851
|
-
if ((route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
9852
|
-
|| route.name === 'installTargets' && route.view !== 'blocked')
|
|
9853
|
-
&& focusZone === 'actions' && key.return) {
|
|
9854
|
-
runAction(pinnedActions[pinnedActionFocus]);
|
|
9855
|
-
return;
|
|
9856
|
-
}
|
|
9857
|
-
if ((route.name === 'batchInstallPlatforms' || route.name === 'batchInstallScope'
|
|
9858
|
-
|| route.name === 'batchPlacement' && pinnedActions.length > 0)
|
|
9859
|
-
&& focusZone === 'actions'
|
|
9860
|
-
&& (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow)) {
|
|
9861
|
-
setPinnedActionFocus((value) => moveFocus(pinnedActions, value, key.upArrow || key.leftArrow ? -1 : 1));
|
|
9862
|
-
return;
|
|
9863
|
-
}
|
|
9864
|
-
if ((route.name === 'batchInstallPlatforms' || route.name === 'batchInstallScope'
|
|
9865
|
-
|| route.name === 'batchPlacement' && pinnedActions.length > 0)
|
|
9866
|
-
&& focusZone === 'actions' && key.return) {
|
|
9867
|
-
runAction(pinnedActions[pinnedActionFocus]);
|
|
9868
|
-
return;
|
|
9869
|
-
}
|
|
9870
|
-
if (route.name === 'configFields' && focusZone === 'actions'
|
|
9871
|
-
&& (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow)) {
|
|
9872
|
-
setPinnedActionFocus((value) => moveFocus(pinnedActions, value, key.upArrow || key.leftArrow ? -1 : 1));
|
|
9873
|
-
return;
|
|
9874
|
-
}
|
|
9875
|
-
if (route.name === 'configFields' && focusZone === 'actions' && key.return) {
|
|
9876
|
-
runAction(pinnedActions[pinnedActionFocus]);
|
|
9678
|
+
if (route.name === 'pluginList' && input.toLowerCase() === 'm') {
|
|
9679
|
+
runAction(bottomActions.find((action) => action.actionId === 'plugin-list-multi'));
|
|
9680
|
+
return;
|
|
9681
|
+
}
|
|
9682
|
+
if (input.toLowerCase() === 'a' && bottomActions.length > 0) {
|
|
9683
|
+
const firstAction = actions.findIndex((action) => bottomActions.includes(action));
|
|
9684
|
+
if (firstAction >= 0) {
|
|
9685
|
+
const anchor = actionJumpAnchor.current;
|
|
9686
|
+
if (anchor?.routeKey === routeKey && focus >= firstAction) {
|
|
9687
|
+
const entityIndex = anchor.entityId
|
|
9688
|
+
? actions.findIndex((action) => action.pluginId === anchor.entityId) : -1;
|
|
9689
|
+
setFocus(entityIndex >= 0 ? entityIndex : Math.min(anchor.index, Math.max(0, firstAction - 1)));
|
|
9690
|
+
actionJumpAnchor.current = undefined;
|
|
9691
|
+
}
|
|
9692
|
+
else {
|
|
9693
|
+
actionJumpAnchor.current = { routeKey, index: focus, entityId: actions[focus]?.pluginId };
|
|
9694
|
+
setFocus(firstAction);
|
|
9695
|
+
}
|
|
9696
|
+
setScrollOffset(0);
|
|
9697
|
+
}
|
|
9877
9698
|
return;
|
|
9878
9699
|
}
|
|
9879
9700
|
if (key.tab && (route.name === 'configLayer'
|
|
@@ -9943,6 +9764,12 @@ export function ConsoleAppV4(props) {
|
|
|
9943
9764
|
setFocus(portableResultDetailReturnFocus.current);
|
|
9944
9765
|
setScrollOffset(0);
|
|
9945
9766
|
}
|
|
9767
|
+
else if (globalAction === 'back' && route.name === 'pluginDetail' && showTechnical) {
|
|
9768
|
+
setShowTechnical(false);
|
|
9769
|
+
setBatchTargetOffset(0);
|
|
9770
|
+
setFocus(0);
|
|
9771
|
+
setScrollOffset(0);
|
|
9772
|
+
}
|
|
9946
9773
|
else if (globalAction === 'back' && route.name === 'portableSkillSelect' && portableToolsOpen) {
|
|
9947
9774
|
setPortableToolsOpen(false);
|
|
9948
9775
|
setFocus(0);
|
|
@@ -10016,7 +9843,7 @@ export function ConsoleAppV4(props) {
|
|
|
10016
9843
|
back();
|
|
10017
9844
|
}
|
|
10018
9845
|
else if (route.name === 'pluginList' && input.toLowerCase() === 'f') {
|
|
10019
|
-
|
|
9846
|
+
runAction(listQueryActions.find((action) => action.actionId === 'plugin-list-filter'));
|
|
10020
9847
|
}
|
|
10021
9848
|
else if (route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
10022
9849
|
&& input.toLowerCase() === 'f') {
|
|
@@ -10030,26 +9857,12 @@ export function ConsoleAppV4(props) {
|
|
|
10030
9857
|
setFocus(0);
|
|
10031
9858
|
setScrollOffset(0);
|
|
10032
9859
|
}
|
|
10033
|
-
else if (route.name === 'pluginList' && route.mode === 'installed' && input.toLowerCase() === 'a') {
|
|
10034
|
-
prepareCurrentProjectPlugins();
|
|
10035
|
-
}
|
|
10036
9860
|
else if (route.name === 'projectStatus' && input.toLowerCase() === 'c') {
|
|
10037
|
-
runAction(
|
|
10038
|
-
}
|
|
10039
|
-
else if (route.name === 'batchSelection' && batchDraft?.stage === 'select' && input.toLowerCase() === 'a') {
|
|
10040
|
-
const candidates = batchCandidates(batchDraft)
|
|
10041
|
-
.filter((candidate) => batchCandidateBlockReason(batchDraft, candidate) === undefined);
|
|
10042
|
-
setBatchDraft((current) => current ? {
|
|
10043
|
-
...current,
|
|
10044
|
-
selectedPluginIds: [...new Set([
|
|
10045
|
-
...current.selectedPluginIds,
|
|
10046
|
-
...candidates.map((candidate) => candidate.pluginId),
|
|
10047
|
-
])],
|
|
10048
|
-
} : current);
|
|
9861
|
+
runAction(bottomActions.find((action) => action.actionId === 'project-sync-actionable'));
|
|
10049
9862
|
}
|
|
10050
9863
|
else if (route.name === 'installTargets' && route.view !== 'blocked'
|
|
10051
9864
|
&& input.toLowerCase() === 'c') {
|
|
10052
|
-
runAction(
|
|
9865
|
+
runAction(bottomActions.find((action) => action.actionId === 'confirm-install-platforms'));
|
|
10053
9866
|
}
|
|
10054
9867
|
else if (route.name === 'batchInstallPlatforms' && input.toLowerCase() === 'c') {
|
|
10055
9868
|
runAction(actions.find((action) => action.actionId === 'batch-install-platforms-confirm'));
|
|
@@ -10057,15 +9870,15 @@ export function ConsoleAppV4(props) {
|
|
|
10057
9870
|
else if (route.name === 'batchInstallScope' && input.toLowerCase() === 'c') {
|
|
10058
9871
|
runAction(actions.find((action) => action.actionId === 'batch-placement-confirm'));
|
|
10059
9872
|
}
|
|
10060
|
-
else if (route.name === 'batchPlacement' &&
|
|
9873
|
+
else if (route.name === 'batchPlacement' && bottomActions.length > 0
|
|
10061
9874
|
&& input.toLowerCase() === 'c') {
|
|
10062
9875
|
runAction(actions.find((action) => action.actionId === 'batch-placement-confirm'));
|
|
10063
9876
|
}
|
|
10064
9877
|
else if (route.name === 'batchSelection' && batchDraft?.stage === 'select' && input.toLowerCase() === 'c') {
|
|
10065
|
-
runAction(
|
|
9878
|
+
runAction(bottomActions.find((action) => action.actionId === 'batch-selection-continue'));
|
|
10066
9879
|
}
|
|
10067
9880
|
else if (route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
10068
|
-
&&
|
|
9881
|
+
&& input === ' ') {
|
|
10069
9882
|
const action = actions[normalizedEffectiveFocus];
|
|
10070
9883
|
if (action?.pluginId
|
|
10071
9884
|
&& (batchDraft.selectedPluginIds.includes(action.pluginId) || action.canSelectNew)) {
|
|
@@ -10073,12 +9886,20 @@ export function ConsoleAppV4(props) {
|
|
|
10073
9886
|
}
|
|
10074
9887
|
}
|
|
10075
9888
|
else if (route.name === 'installTargets' && route.view !== 'blocked'
|
|
10076
|
-
&&
|
|
9889
|
+
&& input === ' ') {
|
|
10077
9890
|
const action = actions[focus];
|
|
10078
9891
|
if (action?.actionId?.startsWith('install-platform-'))
|
|
10079
9892
|
runAction(action);
|
|
10080
9893
|
}
|
|
9894
|
+
else if (route.name === 'batchInstallPlatforms'
|
|
9895
|
+
&& input === ' ') {
|
|
9896
|
+
const action = actions[focus];
|
|
9897
|
+
if (action?.actionId === 'batch-install-platform-codex'
|
|
9898
|
+
|| action?.actionId === 'batch-install-platform-claude')
|
|
9899
|
+
runAction(action);
|
|
9900
|
+
}
|
|
10081
9901
|
else if (route.name === 'batchSelection' && batchDraft?.stage === 'select' && input === '/') {
|
|
9902
|
+
setSearchCursor([...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(batchDraft.query)].length);
|
|
10082
9903
|
setSearchFocus(true);
|
|
10083
9904
|
}
|
|
10084
9905
|
else if (route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
@@ -10096,7 +9917,7 @@ export function ConsoleAppV4(props) {
|
|
|
10096
9917
|
setScrollOffset(0);
|
|
10097
9918
|
}
|
|
10098
9919
|
else if (route.name === 'configFields' && input.toLowerCase() === 's') {
|
|
10099
|
-
runAction(
|
|
9920
|
+
runAction(bottomActions[0]);
|
|
10100
9921
|
}
|
|
10101
9922
|
else if (route.name === 'configFields' && input.toLowerCase() === 'u') {
|
|
10102
9923
|
const key = actions[focus]?.configKey;
|
|
@@ -10123,20 +9944,17 @@ export function ConsoleAppV4(props) {
|
|
|
10123
9944
|
}
|
|
10124
9945
|
else if ((input.toLowerCase() === 'r' || input.toLowerCase() === 'c')
|
|
10125
9946
|
&& route.name === 'sourceList') {
|
|
10126
|
-
|
|
9947
|
+
runAction(bottomActions.find((action) => action.actionId === 'source-check-all'));
|
|
10127
9948
|
}
|
|
10128
9949
|
else if (route.name === 'pluginList' && (key.leftArrow || key.rightArrow || input === '[' || input === ']')) {
|
|
10129
9950
|
const direction = key.leftArrow || input === '[' ? -1 : 1;
|
|
10130
9951
|
movePluginListSource?.(direction);
|
|
10131
9952
|
}
|
|
10132
9953
|
else if (input.toLowerCase() === 'c' && route.name === 'portableSkillSelect') {
|
|
10133
|
-
runAction(
|
|
10134
|
-
}
|
|
10135
|
-
else if (input.toLowerCase() === 'a' && route.name === 'portableSkillSelect') {
|
|
10136
|
-
runAction(selectAllPortableCandidates);
|
|
9954
|
+
runAction(bottomActions.find((action) => action.actionId === 'portable-selection-continue'));
|
|
10137
9955
|
}
|
|
10138
9956
|
else if (input === ' ' && route.name === 'portableSkillSelect'
|
|
10139
|
-
&&
|
|
9957
|
+
&& !portableToolsOpen) {
|
|
10140
9958
|
const candidate = portableVisibleCandidates[focus];
|
|
10141
9959
|
if (candidate)
|
|
10142
9960
|
props.controller.togglePortableSkill(candidate.name);
|
|
@@ -10148,9 +9966,8 @@ export function ConsoleAppV4(props) {
|
|
|
10148
9966
|
setFocus((value) => {
|
|
10149
9967
|
const current = route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
10150
9968
|
? normalizedEffectiveFocus : dynamicActionIds ? effectiveFocus : value;
|
|
10151
|
-
const next =
|
|
10152
|
-
:
|
|
10153
|
-
: moveFocus(actions, current, -1);
|
|
9969
|
+
const next = route.name === 'sourceDetail' ? moveIndex(actions.length, current, -1)
|
|
9970
|
+
: moveFocus(actions, current, -1);
|
|
10154
9971
|
if (dynamicActionIds && dynamicActionSignature !== undefined) {
|
|
10155
9972
|
dynamicMenuFocus.current = {
|
|
10156
9973
|
routeKey,
|
|
@@ -10158,17 +9975,7 @@ export function ConsoleAppV4(props) {
|
|
|
10158
9975
|
focusedActionId: dynamicActionIds[next],
|
|
10159
9976
|
};
|
|
10160
9977
|
}
|
|
10161
|
-
const viewport =
|
|
10162
|
-
? batchDraft.showSelectionTools
|
|
10163
|
-
? actionViewport(actions, policy.mode === 'compact', next, scrollOffset, Math.max(1, pageActionBudget(4)))
|
|
10164
|
-
: objectCardActionViewport(actions, Math.max(20, size.columns - 2), policy.mode === 'compact', next, scrollOffset, Math.max(1, pageActionBudget(4)))
|
|
10165
|
-
: route.name === 'portableSkillSelect' && snapshot.portableDraft && !portableToolsOpen
|
|
10166
|
-
? portableSkillCandidateViewport(actions.slice(0, portableVisibleCandidates.length), Math.max(20, size.columns - 2), policy.mode === 'compact', next, scrollOffset, pageActionBudget(actions.length - portableVisibleCandidates.length
|
|
10167
|
-
+ (portableVariantCandidates.length > 0 ? 3 : 0)))
|
|
10168
|
-
: route.name === 'installTargets' && route.view !== 'blocked'
|
|
10169
|
-
? objectCardActionViewport(actions, Math.max(20, size.columns - 2), policy.mode === 'compact', next, scrollOffset, Math.max(1, pageActionBudget((pinnedActions[0]?.disabled ? 2 : 1)
|
|
10170
|
-
+ (policy.mode === 'compact' ? 4 : 0))))
|
|
10171
|
-
: actionViewport(actions, route.name === 'pluginDetail' || policy.mode === 'compact', next, scrollOffset, currentActionViewportLineBudget);
|
|
9978
|
+
const viewport = actionViewport(actions, policy.mode === 'compact', next, scrollOffset, currentActionViewportLineBudget);
|
|
10172
9979
|
if (route.name === 'pluginDependencies' && route.view !== 'removeBlocked') {
|
|
10173
9980
|
const projection = buildUnifiedDependencyGraphProjection({
|
|
10174
9981
|
overviews: props.controller.listPluginDependencyOverviews(),
|
|
@@ -10180,7 +9987,8 @@ export function ConsoleAppV4(props) {
|
|
|
10180
9987
|
...projection.dependents.defaultExpandedPluginIds,
|
|
10181
9988
|
]), next, viewport.offset);
|
|
10182
9989
|
}
|
|
10183
|
-
|
|
9990
|
+
if (bottomActions.length === 0)
|
|
9991
|
+
setScrollOffset(viewport.offset);
|
|
10184
9992
|
return next;
|
|
10185
9993
|
});
|
|
10186
9994
|
}
|
|
@@ -10191,9 +9999,8 @@ export function ConsoleAppV4(props) {
|
|
|
10191
9999
|
setFocus((value) => {
|
|
10192
10000
|
const current = route.name === 'batchSelection' && batchDraft?.stage === 'select'
|
|
10193
10001
|
? normalizedEffectiveFocus : dynamicActionIds ? effectiveFocus : value;
|
|
10194
|
-
const next =
|
|
10195
|
-
:
|
|
10196
|
-
: moveFocus(actions, current, 1);
|
|
10002
|
+
const next = route.name === 'sourceDetail' ? moveIndex(actions.length, current, 1)
|
|
10003
|
+
: moveFocus(actions, current, 1);
|
|
10197
10004
|
if (dynamicActionIds && dynamicActionSignature !== undefined) {
|
|
10198
10005
|
dynamicMenuFocus.current = {
|
|
10199
10006
|
routeKey,
|
|
@@ -10201,17 +10008,7 @@ export function ConsoleAppV4(props) {
|
|
|
10201
10008
|
focusedActionId: dynamicActionIds[next],
|
|
10202
10009
|
};
|
|
10203
10010
|
}
|
|
10204
|
-
const viewport =
|
|
10205
|
-
? batchDraft.showSelectionTools
|
|
10206
|
-
? actionViewport(actions, policy.mode === 'compact', next, scrollOffset, Math.max(1, pageActionBudget(4)))
|
|
10207
|
-
: objectCardActionViewport(actions, Math.max(20, size.columns - 2), policy.mode === 'compact', next, scrollOffset, Math.max(1, pageActionBudget(4)))
|
|
10208
|
-
: route.name === 'portableSkillSelect' && snapshot.portableDraft && !portableToolsOpen
|
|
10209
|
-
? portableSkillCandidateViewport(actions.slice(0, portableVisibleCandidates.length), Math.max(20, size.columns - 2), policy.mode === 'compact', next, scrollOffset, pageActionBudget(actions.length - portableVisibleCandidates.length
|
|
10210
|
-
+ (portableVariantCandidates.length > 0 ? 3 : 0)))
|
|
10211
|
-
: route.name === 'installTargets' && route.view !== 'blocked'
|
|
10212
|
-
? objectCardActionViewport(actions, Math.max(20, size.columns - 2), policy.mode === 'compact', next, scrollOffset, Math.max(1, pageActionBudget((pinnedActions[0]?.disabled ? 2 : 1)
|
|
10213
|
-
+ (policy.mode === 'compact' ? 4 : 0))))
|
|
10214
|
-
: actionViewport(actions, route.name === 'pluginDetail' || policy.mode === 'compact', next, scrollOffset, currentActionViewportLineBudget);
|
|
10011
|
+
const viewport = actionViewport(actions, policy.mode === 'compact', next, scrollOffset, currentActionViewportLineBudget);
|
|
10215
10012
|
if (route.name === 'pluginDependencies' && route.view !== 'removeBlocked') {
|
|
10216
10013
|
const projection = buildUnifiedDependencyGraphProjection({
|
|
10217
10014
|
overviews: props.controller.listPluginDependencyOverviews(),
|
|
@@ -10223,17 +10020,11 @@ export function ConsoleAppV4(props) {
|
|
|
10223
10020
|
...projection.dependents.defaultExpandedPluginIds,
|
|
10224
10021
|
]), next, viewport.offset);
|
|
10225
10022
|
}
|
|
10226
|
-
|
|
10023
|
+
if (bottomActions.length === 0)
|
|
10024
|
+
setScrollOffset(viewport.offset);
|
|
10227
10025
|
return next;
|
|
10228
10026
|
});
|
|
10229
10027
|
}
|
|
10230
|
-
else if (key.return && route.name === 'pluginList' && focusZone === 'content' && pluginRows[focus]) {
|
|
10231
|
-
const row = pluginRows[focus];
|
|
10232
|
-
if (row.menuAction)
|
|
10233
|
-
row.menuAction();
|
|
10234
|
-
else
|
|
10235
|
-
go({ name: 'pluginDetail', pluginId: row.pluginId });
|
|
10236
|
-
}
|
|
10237
10028
|
else if (key.return) {
|
|
10238
10029
|
runAction(actions[normalizedEffectiveFocus]);
|
|
10239
10030
|
}
|
|
@@ -10345,33 +10136,6 @@ export function ConsoleAppV4(props) {
|
|
|
10345
10136
|
];
|
|
10346
10137
|
return _jsxs(Box, { position: "relative", width: size.columns, height: size.rows, children: [_jsx(Box, { children: base }), _jsx(Box, { position: "absolute", marginTop: 4, marginLeft: 2, width: size.columns - 4, flexDirection: "column", children: _jsxs(ReviewCard, { title: "\u9009\u62E9\u4E0B\u8F7D\u65B9\u5F0F", description: `当前草稿:${currentTransport ?? '未识别'};仅修改草稿,保存前可查看汇总。`, children: [_jsx(SemanticRows, { actions: transportActions, focus: overlayFocus, kind: "choice", compact: false }), _jsx(Text, { color: tuiTheme.colors.muted, children: "\u2191\u2193 \u9009\u62E9 \u00B7 Enter \u786E\u8BA4 \u00B7 Esc \u53D6\u6D88" })] }) })] });
|
|
10347
10138
|
}
|
|
10348
|
-
if (pluginListChooser && route.name === 'pluginList') {
|
|
10349
|
-
const sourceId = route.sourceId ?? 'all';
|
|
10350
|
-
const chooserActions = pluginListChooser.kind === 'source'
|
|
10351
|
-
? [
|
|
10352
|
-
{ label: '全部来源', selected: sourceId === 'all' },
|
|
10353
|
-
...props.controller.listSources().map((source) => ({
|
|
10354
|
-
label: source.label,
|
|
10355
|
-
meta: source.id === source.label ? undefined : source.id,
|
|
10356
|
-
selected: source.id === sourceId,
|
|
10357
|
-
})),
|
|
10358
|
-
]
|
|
10359
|
-
: PLUGIN_FILTERS.map((filter) => ({
|
|
10360
|
-
label: pluginFilterLabel(filter),
|
|
10361
|
-
selected: filter === installFilter,
|
|
10362
|
-
}));
|
|
10363
|
-
const chooserFocus = Math.min(pluginListChooser.focus, Math.max(0, chooserActions.length - 1));
|
|
10364
|
-
const chooserViewport = rowViewport({
|
|
10365
|
-
rowHeights: chooserActions.map(() => 1),
|
|
10366
|
-
focus: chooserFocus,
|
|
10367
|
-
requestedOffset: 0,
|
|
10368
|
-
rowBudget: responsiveBudget(6, 9),
|
|
10369
|
-
});
|
|
10370
|
-
const chooserWidth = Math.max(40, Math.floor(size.columns * 0.8));
|
|
10371
|
-
return _jsxs(Box, { position: "relative", width: size.columns, height: size.rows, children: [_jsx(Box, { children: base }), _jsx(Box, { position: "absolute", marginTop: policy.mode === 'compact' ? 2 : 5, marginLeft: Math.max(2, Math.floor((size.columns - chooserWidth) / 2)), width: chooserWidth, flexDirection: "column", children: _jsxs(ReviewCard, { title: pluginListChooser.kind === 'source' ? '选择插件来源' : '筛选插件', description: pluginListChooser.kind === 'status' ? '只改变列表,不改变插件详情。' : undefined, children: [_jsx(SemanticRows, { actions: chooserActions, focus: chooserFocus, kind: "choice", compact: true, offset: chooserViewport.offset, limit: chooserViewport.limit }), chooserActions.length > chooserViewport.limit
|
|
10372
|
-
? _jsx(StaticRow, { title: `${chooserViewport.position} / ${chooserViewport.total}`, status: "muted", compact: true })
|
|
10373
|
-
: null, _jsx(StaticRow, { title: "\u2191\u2193 \u9009\u62E9 \u00B7 Enter \u786E\u8BA4 \u00B7 Esc \u53D6\u6D88", status: "muted", compact: true })] }) })] });
|
|
10374
|
-
}
|
|
10375
10139
|
if (!overlay)
|
|
10376
10140
|
return base;
|
|
10377
10141
|
const helpRows = helpRowsForRoute(route, actions.length, supportsTechnicalDetails, busy, props.onSessionNavigation !== undefined);
|