pi-codex-marketplace 0.1.8 → 0.1.9
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/extensions/pi/bridge-ledger.ts +375 -202
- package/extensions/pi/git-registration.ts +66 -50
- package/extensions/pi/index.ts +44 -2
- package/extensions/pi/installation.ts +124 -63
- package/extensions/pi/journal.ts +88 -57
- package/extensions/pi/lifecycle.ts +172 -86
- package/extensions/pi/registration.ts +59 -42
- package/extensions/pi/scope-overrides.ts +81 -43
- package/extensions/pi/terminal-presentation.ts +119 -0
- package/extensions/pi/transaction-sheet.ts +121 -52
- package/extensions/pi/ui-strings.ts +694 -0
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
10
|
-
import { Key, matchesKey, type Component, type TUI } from '@earendil-works/pi-tui';
|
|
10
|
+
import { Key, matchesKey, wrapTextWithAnsi, type Component, type TUI } from '@earendil-works/pi-tui';
|
|
11
11
|
|
|
12
12
|
import { checkGlobalPendingBarrier, type GlobalBarrierStatus } from '../../src/barrier/global-barrier.js';
|
|
13
13
|
import { readBothStates } from '../../src/bridge-state/store.js';
|
|
@@ -34,9 +34,13 @@ import type { ValidationFinding } from '../../src/registration/findings.js';
|
|
|
34
34
|
import type { AttemptReceipt } from '../../src/registration/receipt.js';
|
|
35
35
|
import {
|
|
36
36
|
fitTerminalLine,
|
|
37
|
-
padTerminalLine,
|
|
38
37
|
quoteTerminalText,
|
|
38
|
+
renderBadge,
|
|
39
|
+
renderPanel,
|
|
40
|
+
renderSelectableRow,
|
|
41
|
+
renderSideBySidePanels,
|
|
39
42
|
} from './terminal-presentation.js';
|
|
43
|
+
import { attemptSummaryText, findingOutcomeText, uiText } from './ui-strings.js';
|
|
40
44
|
|
|
41
45
|
export type LedgerSectionId =
|
|
42
46
|
| 'observe'
|
|
@@ -283,14 +287,16 @@ function rail(scope: Scope, result: ReadResult, projectTrusted: boolean): Ledger
|
|
|
283
287
|
? 'indeterminate'
|
|
284
288
|
: 'healthy';
|
|
285
289
|
const healthText = health === 'healthy'
|
|
286
|
-
? result.status === 'missing'
|
|
290
|
+
? result.status === 'missing'
|
|
291
|
+
? uiText('ledger.rail.health.healthyEmpty')
|
|
292
|
+
: uiText('ledger.rail.health.healthy')
|
|
287
293
|
: health === 'incompatible'
|
|
288
|
-
?
|
|
289
|
-
:
|
|
294
|
+
? uiText('ledger.rail.health.incompatible', { error: result.error ?? uiText('common.unknown') })
|
|
295
|
+
: uiText('ledger.rail.health.indeterminate', { error: result.error ?? uiText('common.unknown') });
|
|
290
296
|
return {
|
|
291
297
|
scope,
|
|
292
|
-
label: scope === 'global' ? '
|
|
293
|
-
revision: state?.stateRevision ?? 'unavailable',
|
|
298
|
+
label: scope === 'global' ? uiText('common.scope.global') : uiText('common.scope.project'),
|
|
299
|
+
revision: state?.stateRevision ?? uiText('ledger.revision.unavailable'),
|
|
294
300
|
registrationCount: state?.registrations.length ?? 0,
|
|
295
301
|
installationEnabledCount:
|
|
296
302
|
state?.installations.filter((item) => item.installationState === 'enabled').length ?? 0,
|
|
@@ -300,8 +306,8 @@ function rail(scope: Scope, result: ReadResult, projectTrusted: boolean): Ledger
|
|
|
300
306
|
health,
|
|
301
307
|
healthText,
|
|
302
308
|
trustText: scope === 'global'
|
|
303
|
-
? '
|
|
304
|
-
: projectTrusted ? '
|
|
309
|
+
? uiText('ledger.rail.trust.notApplicable')
|
|
310
|
+
: projectTrusted ? uiText('ledger.rail.trust.granted') : uiText('ledger.rail.trust.notGranted'),
|
|
305
311
|
};
|
|
306
312
|
}
|
|
307
313
|
|
|
@@ -313,14 +319,15 @@ function availability(
|
|
|
313
319
|
if (intent.scope === 'project' && snapshot.barrier.active) {
|
|
314
320
|
return {
|
|
315
321
|
enabled: false,
|
|
316
|
-
disabledReason:
|
|
317
|
-
|
|
322
|
+
disabledReason: uiText('ledger.disabledReason.barrier', {
|
|
323
|
+
reason: snapshot.barrier.reason ?? uiText('ledger.barrier.defaultReason'),
|
|
324
|
+
}),
|
|
318
325
|
};
|
|
319
326
|
}
|
|
320
327
|
if (intent.scope === 'project' && !snapshot.projectTrusted) {
|
|
321
328
|
return {
|
|
322
329
|
enabled: false,
|
|
323
|
-
disabledReason: '
|
|
330
|
+
disabledReason: uiText('ledger.disabledReason.trust'),
|
|
324
331
|
};
|
|
325
332
|
}
|
|
326
333
|
const authority = intent.scope === 'global' ? snapshot.global : snapshot.project;
|
|
@@ -331,7 +338,7 @@ function availability(
|
|
|
331
338
|
if (!chain?.receipts[0]?.validationSnapshot) {
|
|
332
339
|
return {
|
|
333
340
|
enabled: false,
|
|
334
|
-
disabledReason: '
|
|
341
|
+
disabledReason: uiText('ledger.disabledReason.retryNoSnapshot'),
|
|
335
342
|
};
|
|
336
343
|
}
|
|
337
344
|
}
|
|
@@ -340,7 +347,9 @@ function availability(
|
|
|
340
347
|
if (authority.status === 'incompatible') {
|
|
341
348
|
return {
|
|
342
349
|
enabled: false,
|
|
343
|
-
disabledReason:
|
|
350
|
+
disabledReason: uiText('ledger.disabledReason.incompatible', {
|
|
351
|
+
error: authority.error ?? uiText('common.unknown'),
|
|
352
|
+
}),
|
|
344
353
|
};
|
|
345
354
|
}
|
|
346
355
|
if (snapshot.journals[intent.scope].isDegraded) return { enabled: true };
|
|
@@ -350,52 +359,56 @@ function availability(
|
|
|
350
359
|
if (repairable) return { enabled: true };
|
|
351
360
|
const activeConditions = snapshot.journals[intent.scope].activeChains.map((chain) =>
|
|
352
361
|
chain.condition === 'pending-application'
|
|
353
|
-
? '
|
|
362
|
+
? uiText('ledger.condition.pending-application')
|
|
354
363
|
: chain.condition === 'persistence-failed'
|
|
355
|
-
? '
|
|
364
|
+
? uiText('ledger.condition.persistence-failed')
|
|
356
365
|
: chain.condition,
|
|
357
366
|
);
|
|
358
367
|
return {
|
|
359
368
|
enabled: false,
|
|
360
369
|
disabledReason: activeConditions.length > 0
|
|
361
|
-
?
|
|
362
|
-
: '
|
|
370
|
+
? uiText('ledger.disabledReason.repairIneligible', { conditions: activeConditions.join(', ') })
|
|
371
|
+
: uiText('ledger.disabledReason.repairNothing'),
|
|
363
372
|
};
|
|
364
373
|
}
|
|
365
374
|
if (authority.status === 'incompatible') {
|
|
366
375
|
return {
|
|
367
376
|
enabled: false,
|
|
368
|
-
disabledReason:
|
|
377
|
+
disabledReason: uiText('ledger.disabledReason.incompatibleMutation', {
|
|
378
|
+
error: authority.error ?? uiText('common.unknown'),
|
|
379
|
+
}),
|
|
369
380
|
};
|
|
370
381
|
}
|
|
371
382
|
if (authority.status === 'corrupted') {
|
|
372
383
|
return {
|
|
373
384
|
enabled: false,
|
|
374
|
-
disabledReason:
|
|
385
|
+
disabledReason: uiText('ledger.disabledReason.corrupted', {
|
|
386
|
+
error: authority.error ?? uiText('ledger.disabledReason.corruptState'),
|
|
387
|
+
}),
|
|
375
388
|
};
|
|
376
389
|
}
|
|
377
390
|
return { enabled: true };
|
|
378
391
|
}
|
|
379
392
|
|
|
380
393
|
const ACTION_LABELS: Record<LedgerActionId, string> = {
|
|
381
|
-
'observe-partitions': '
|
|
382
|
-
'observe-effective-state': '
|
|
383
|
-
'register-local': '
|
|
384
|
-
'register-git': '
|
|
385
|
-
'refresh-registration': '
|
|
386
|
-
'rebind-registration': '
|
|
387
|
-
'remove-registration': '
|
|
388
|
-
'install-disabled': '
|
|
389
|
-
'install-and-enable': '
|
|
390
|
-
'enable-installation': '
|
|
391
|
-
'disable-installation': '
|
|
392
|
-
'remove-installation': '
|
|
393
|
-
'create-scope-override': '
|
|
394
|
-
'remove-scope-override': '
|
|
395
|
-
'view-receipt-journal': '
|
|
396
|
-
'repair-state': '
|
|
397
|
-
'retry-application': '
|
|
398
|
-
'inspect-receipt': '
|
|
394
|
+
'observe-partitions': uiText('ledger.action.observe-partitions'),
|
|
395
|
+
'observe-effective-state': uiText('ledger.action.observe-effective-state'),
|
|
396
|
+
'register-local': uiText('ledger.action.register-local'),
|
|
397
|
+
'register-git': uiText('ledger.action.register-git'),
|
|
398
|
+
'refresh-registration': uiText('ledger.action.refresh-registration'),
|
|
399
|
+
'rebind-registration': uiText('ledger.action.rebind-registration'),
|
|
400
|
+
'remove-registration': uiText('ledger.action.remove-registration'),
|
|
401
|
+
'install-disabled': uiText('ledger.action.install-disabled'),
|
|
402
|
+
'install-and-enable': uiText('ledger.action.install-and-enable'),
|
|
403
|
+
'enable-installation': uiText('ledger.action.enable-installation'),
|
|
404
|
+
'disable-installation': uiText('ledger.action.disable-installation'),
|
|
405
|
+
'remove-installation': uiText('ledger.action.remove-installation'),
|
|
406
|
+
'create-scope-override': uiText('ledger.action.create-scope-override'),
|
|
407
|
+
'remove-scope-override': uiText('ledger.action.remove-scope-override'),
|
|
408
|
+
'view-receipt-journal': uiText('ledger.action.view-receipt-journal'),
|
|
409
|
+
'repair-state': uiText('ledger.action.repair-state'),
|
|
410
|
+
'retry-application': uiText('ledger.action.retry-application'),
|
|
411
|
+
'inspect-receipt': uiText('ledger.action.inspect-receipt'),
|
|
399
412
|
};
|
|
400
413
|
|
|
401
414
|
function action(snapshot: BridgeLedgerSnapshot, intent: LedgerActionIntent): LedgerActionRow {
|
|
@@ -429,7 +442,9 @@ function scopeRegistrationRows(
|
|
|
429
442
|
): LedgerObjectRow[] {
|
|
430
443
|
const createRow: LedgerObjectRow = {
|
|
431
444
|
id: `registration-create:${scope}`,
|
|
432
|
-
label:
|
|
445
|
+
label: uiText('ledger.row.registrationActions', {
|
|
446
|
+
scopeWord: scope === 'global' ? uiText('common.scope.word.global') : uiText('common.scope.word.project'),
|
|
447
|
+
}),
|
|
433
448
|
scope,
|
|
434
449
|
targetKind: 'scope',
|
|
435
450
|
targetId: scope,
|
|
@@ -441,7 +456,7 @@ function scopeRegistrationRows(
|
|
|
441
456
|
const records = (state?.registrations ?? []).map((registration): LedgerObjectRow => ({
|
|
442
457
|
id: `registration:${scope}:${registration.id}`,
|
|
443
458
|
label: registrationName(registration),
|
|
444
|
-
detail: `${registration.sourceKind ?? '
|
|
459
|
+
detail: `${registration.sourceKind ?? uiText('ledger.row.registration.sourceUnknown')} · ${registration.source ?? uiText('ledger.row.registration.sourceUnavailable')}`,
|
|
445
460
|
scope,
|
|
446
461
|
targetKind: 'registration',
|
|
447
462
|
targetId: registration.id,
|
|
@@ -463,13 +478,13 @@ function pluginRows(
|
|
|
463
478
|
if (!('marketplaceEntryId' in entry)) {
|
|
464
479
|
const findings = entry.findings.length > 0
|
|
465
480
|
? entry.findings.map((finding) =>
|
|
466
|
-
`${finding.code} · ${finding.rule} · ${finding
|
|
481
|
+
`${finding.code} · ${finding.rule} · ${findingOutcomeText(finding)}`,
|
|
467
482
|
).join('; ')
|
|
468
|
-
: '
|
|
483
|
+
: uiText('ledger.row.diagnostic.noEntries');
|
|
469
484
|
return {
|
|
470
485
|
id: `marketplace-diagnostic:${scope}:${entry.registrationId}`,
|
|
471
486
|
label: entry.name,
|
|
472
|
-
detail:
|
|
487
|
+
detail: uiText('ledger.row.diagnostic.unavailable', { findings }),
|
|
473
488
|
scope,
|
|
474
489
|
targetKind: 'registration',
|
|
475
490
|
targetId: entry.registrationId,
|
|
@@ -484,15 +499,21 @@ function pluginRows(
|
|
|
484
499
|
installation.pluginId === compatiblePluginId);
|
|
485
500
|
const skillDetail = entry.plugin?.skills.length
|
|
486
501
|
? entry.plugin.skills.map((skill) =>
|
|
487
|
-
|
|
502
|
+
uiText('ledger.row.skills.resources', {
|
|
503
|
+
name: skill.name,
|
|
504
|
+
policy: skill.invocationPolicy,
|
|
505
|
+
resources: skill.resources.length > 0 ? skill.resources.join(', ') : uiText('ledger.row.skills.noResources'),
|
|
506
|
+
}),
|
|
488
507
|
).join('; ')
|
|
489
|
-
: 'skills
|
|
508
|
+
: uiText('ledger.row.skills.none');
|
|
490
509
|
const unavailableReason = installed
|
|
491
|
-
? '
|
|
510
|
+
? uiText('ledger.row.install.alreadyInstalled')
|
|
492
511
|
: entry.unavailableReason
|
|
493
512
|
?? (entry.classification === 'compatible' && !entry.validationSnapshot
|
|
494
|
-
? '
|
|
495
|
-
: entry.classification === 'compatible'
|
|
513
|
+
? uiText('ledger.row.install.snapshotMissing')
|
|
514
|
+
: entry.classification === 'compatible'
|
|
515
|
+
? undefined
|
|
516
|
+
: uiText('ledger.row.install.classification', { classification: entry.classification }));
|
|
496
517
|
const installAction = (
|
|
497
518
|
actionId: 'install-disabled' | 'install-and-enable',
|
|
498
519
|
desiredInstallationState: 'disabled' | 'enabled',
|
|
@@ -557,7 +578,7 @@ function createOverrideRow(
|
|
|
557
578
|
return {
|
|
558
579
|
id: `inherited:${kind}:${targetId}`,
|
|
559
580
|
label,
|
|
560
|
-
detail:
|
|
581
|
+
detail: uiText('ledger.row.override.inherited', { kind, targetId }),
|
|
561
582
|
scope: 'global',
|
|
562
583
|
targetKind: kind,
|
|
563
584
|
targetId,
|
|
@@ -597,8 +618,8 @@ function overrideRows(
|
|
|
597
618
|
const canonicalOverrideId = `${override.kind}/${override.targetId}`;
|
|
598
619
|
return {
|
|
599
620
|
id: `scope-override:${canonicalOverrideId}`,
|
|
600
|
-
label:
|
|
601
|
-
detail:
|
|
621
|
+
label: uiText('ledger.row.override.label', { kind: override.kind }),
|
|
622
|
+
detail: uiText('ledger.row.override.suppresses', { targetId: override.targetId }),
|
|
602
623
|
scope: 'project',
|
|
603
624
|
targetKind: 'scope-override',
|
|
604
625
|
targetId: canonicalOverrideId,
|
|
@@ -619,7 +640,7 @@ function overrideRows(
|
|
|
619
640
|
function receiptRow(receipt: AttemptReceipt, snapshot: BridgeLedgerSnapshot): LedgerObjectRow {
|
|
620
641
|
return {
|
|
621
642
|
id: `receipt:${receipt.scope}:${receipt.id}`,
|
|
622
|
-
label: `${receipt.summary} · ${receipt.operation}`,
|
|
643
|
+
label: `${attemptSummaryText(receipt.summary)} · ${receipt.operation}`,
|
|
623
644
|
detail: `${receipt.createdAt} · ${receipt.id}`,
|
|
624
645
|
scope: receipt.scope,
|
|
625
646
|
targetKind: 'receipt',
|
|
@@ -636,8 +657,13 @@ function retryApplicationRows(snapshot: BridgeLedgerSnapshot): LedgerObjectRow[]
|
|
|
636
657
|
.filter((chain) => chain.condition === 'pending-application')
|
|
637
658
|
.map((chain): LedgerObjectRow => ({
|
|
638
659
|
id: `retry-application:${scope}:${chain.rootReceiptId}`,
|
|
639
|
-
label:
|
|
640
|
-
|
|
660
|
+
label: uiText('ledger.row.retry.label', {
|
|
661
|
+
scopeWord: scope === 'global' ? uiText('common.scope.word.global') : uiText('common.scope.word.project'),
|
|
662
|
+
}),
|
|
663
|
+
detail: uiText('ledger.row.retry.detail', {
|
|
664
|
+
receiptId: chain.rootReceiptId,
|
|
665
|
+
revision: chain.stateRevision,
|
|
666
|
+
}),
|
|
641
667
|
scope,
|
|
642
668
|
targetKind: 'receipt',
|
|
643
669
|
targetId: chain.rootReceiptId,
|
|
@@ -658,30 +684,35 @@ export function buildBridgeLedgerModel(snapshot: BridgeLedgerSnapshot): BridgeLe
|
|
|
658
684
|
const effective = snapshot.effective;
|
|
659
685
|
const observe: LedgerSection = {
|
|
660
686
|
id: 'observe',
|
|
661
|
-
label: '
|
|
662
|
-
description: '
|
|
687
|
+
label: uiText('ledger.section.observe.label'),
|
|
688
|
+
description: uiText('ledger.section.observe.description'),
|
|
663
689
|
rows: [
|
|
664
690
|
{
|
|
665
691
|
id: 'observe:partitions',
|
|
666
|
-
label: '
|
|
667
|
-
detail:
|
|
668
|
-
|
|
692
|
+
label: uiText('ledger.row.observe.partitions'),
|
|
693
|
+
detail: uiText('ledger.row.observe.partitionsDetail', {
|
|
694
|
+
global: snapshot.global.state?.stateRevision ?? uiText('ledger.revision.unavailable'),
|
|
695
|
+
project: snapshot.project.state?.stateRevision ?? uiText('ledger.revision.unavailable'),
|
|
696
|
+
}),
|
|
669
697
|
actions: [action(snapshot, { actionId: 'observe-partitions', mode: 'read' })],
|
|
670
698
|
},
|
|
671
699
|
{
|
|
672
700
|
id: 'observe:effective',
|
|
673
|
-
label: '
|
|
674
|
-
detail:
|
|
675
|
-
|
|
676
|
-
|
|
701
|
+
label: uiText('ledger.row.observe.effective'),
|
|
702
|
+
detail: uiText('ledger.row.observe.effectiveDetail', {
|
|
703
|
+
registrations: effective?.registrations.length ?? 0,
|
|
704
|
+
installations: effective?.installations.length ?? 0,
|
|
705
|
+
suppressed: effective?.suppressed.length ?? 0,
|
|
706
|
+
excluded: effective?.excluded.length ?? 0,
|
|
707
|
+
}),
|
|
677
708
|
actions: [action(snapshot, { actionId: 'observe-effective-state', mode: 'read' })],
|
|
678
709
|
},
|
|
679
710
|
],
|
|
680
711
|
};
|
|
681
712
|
const sources: LedgerSection = {
|
|
682
713
|
id: 'sources',
|
|
683
|
-
label: '
|
|
684
|
-
description: '
|
|
714
|
+
label: uiText('ledger.section.sources.label'),
|
|
715
|
+
description: uiText('ledger.section.sources.description'),
|
|
685
716
|
rows: [
|
|
686
717
|
...scopeRegistrationRows('global', globalState, snapshot),
|
|
687
718
|
...scopeRegistrationRows('project', projectState, snapshot),
|
|
@@ -690,8 +721,8 @@ export function buildBridgeLedgerModel(snapshot: BridgeLedgerSnapshot): BridgeLe
|
|
|
690
721
|
let pluginRowCache: LedgerObjectRow[] | undefined;
|
|
691
722
|
const plugins: LedgerSection = {
|
|
692
723
|
id: 'plugins',
|
|
693
|
-
label: '
|
|
694
|
-
description: '
|
|
724
|
+
label: uiText('ledger.section.plugins.label'),
|
|
725
|
+
description: uiText('ledger.section.plugins.description'),
|
|
695
726
|
get rows() {
|
|
696
727
|
pluginRowCache ??= [
|
|
697
728
|
...pluginRows('global', globalState, snapshot),
|
|
@@ -702,22 +733,26 @@ export function buildBridgeLedgerModel(snapshot: BridgeLedgerSnapshot): BridgeLe
|
|
|
702
733
|
};
|
|
703
734
|
const inheritance: LedgerSection = {
|
|
704
735
|
id: 'scope-inheritance',
|
|
705
|
-
label: '
|
|
706
|
-
description: '
|
|
736
|
+
label: uiText('ledger.section.scope-inheritance.label'),
|
|
737
|
+
description: uiText('ledger.section.scope-inheritance.description'),
|
|
707
738
|
rows: overrideRows(globalState, projectState, snapshot),
|
|
708
739
|
};
|
|
709
740
|
const recovery: LedgerSection = {
|
|
710
741
|
id: 'recovery-receipts',
|
|
711
|
-
label: '
|
|
712
|
-
description: '
|
|
742
|
+
label: uiText('ledger.section.recovery-receipts.label'),
|
|
743
|
+
description: uiText('ledger.section.recovery-receipts.description'),
|
|
713
744
|
rows: [
|
|
714
745
|
...(['global', 'project'] as const).flatMap((scope): LedgerObjectRow[] => [
|
|
715
746
|
{
|
|
716
747
|
id: `journal:${scope}`,
|
|
717
|
-
label:
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
748
|
+
label: uiText('ledger.row.journal.label', {
|
|
749
|
+
scopeWord: scope === 'global' ? uiText('common.scope.word.global') : uiText('common.scope.word.project'),
|
|
750
|
+
}),
|
|
751
|
+
detail: uiText('ledger.row.journal.detail', {
|
|
752
|
+
receipts: snapshot.journals[scope].receipts.length,
|
|
753
|
+
chains: snapshot.journals[scope].activeChains.length,
|
|
754
|
+
degraded: snapshot.journals[scope].isDegraded ? uiText('common.yes') : uiText('common.no'),
|
|
755
|
+
}),
|
|
721
756
|
scope,
|
|
722
757
|
targetKind: 'scope',
|
|
723
758
|
targetId: scope,
|
|
@@ -725,7 +760,9 @@ export function buildBridgeLedgerModel(snapshot: BridgeLedgerSnapshot): BridgeLe
|
|
|
725
760
|
},
|
|
726
761
|
{
|
|
727
762
|
id: `repair:${scope}`,
|
|
728
|
-
label:
|
|
763
|
+
label: uiText('ledger.row.repair.label', {
|
|
764
|
+
scopeWord: scope === 'global' ? uiText('common.scope.word.global') : uiText('common.scope.word.project'),
|
|
765
|
+
}),
|
|
729
766
|
scope,
|
|
730
767
|
targetKind: 'scope',
|
|
731
768
|
targetId: scope,
|
|
@@ -747,8 +784,8 @@ export function buildBridgeLedgerModel(snapshot: BridgeLedgerSnapshot): BridgeLe
|
|
|
747
784
|
barrier: {
|
|
748
785
|
active: snapshot.barrier.active,
|
|
749
786
|
text: snapshot.barrier.active
|
|
750
|
-
? snapshot.barrier.reason ?? '
|
|
751
|
-
: '
|
|
787
|
+
? snapshot.barrier.reason ?? uiText('ledger.barrier.defaultReason')
|
|
788
|
+
: uiText('ledger.barrier.clear'),
|
|
752
789
|
},
|
|
753
790
|
effective: {
|
|
754
791
|
registrationCount: effective?.registrations.length ?? 0,
|
|
@@ -762,6 +799,21 @@ export function buildBridgeLedgerModel(snapshot: BridgeLedgerSnapshot): BridgeLe
|
|
|
762
799
|
|
|
763
800
|
// The custom component is added below the presentation model so callers can use the
|
|
764
801
|
// pure buildBridgeLedgerModel seam independently of Pi's runtime objects.
|
|
802
|
+
|
|
803
|
+
/** Widths at or above this breakpoint render the two-column panel workspace. */
|
|
804
|
+
const WIDE_WORKSPACE_WIDTH = 96;
|
|
805
|
+
|
|
806
|
+
const HEALTH_BADGES: Record<LedgerHealth, { tone: 'success' | 'warning' | 'error'; labelId: Parameters<typeof uiText>[0] }> = {
|
|
807
|
+
healthy: { tone: 'success', labelId: 'ledger.badge.healthy' },
|
|
808
|
+
incompatible: { tone: 'error', labelId: 'ledger.badge.incompatible' },
|
|
809
|
+
indeterminate: { tone: 'warning', labelId: 'ledger.badge.indeterminate' },
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
const AVAILABILITY = {
|
|
813
|
+
ready: { icon: '\u25cf', token: 'success', word: uiText('ledger.availability.ready') },
|
|
814
|
+
blocked: { icon: '\u25cb', token: 'warning', word: uiText('ledger.availability.blocked') },
|
|
815
|
+
} as const;
|
|
816
|
+
|
|
765
817
|
export class BridgeLedgerComponent implements Component {
|
|
766
818
|
private readonly model: BridgeLedgerModel;
|
|
767
819
|
private readonly theme: Theme;
|
|
@@ -771,7 +823,10 @@ export class BridgeLedgerComponent implements Component {
|
|
|
771
823
|
private rowIndex = 0;
|
|
772
824
|
private browseFocus: Scope = 'global';
|
|
773
825
|
private helpVisible = false;
|
|
774
|
-
|
|
826
|
+
/** Single-column drill-down state for sub-96-column workspaces. */
|
|
827
|
+
private sectionDetail = false;
|
|
828
|
+
/** Expanded metadata layer for the selected entry; never consulted by dispatch. */
|
|
829
|
+
private metadataExpanded = false;
|
|
775
830
|
private lastWidth = 80;
|
|
776
831
|
|
|
777
832
|
constructor(
|
|
@@ -799,64 +854,75 @@ export class BridgeLedgerComponent implements Component {
|
|
|
799
854
|
if (matchesKey(data, Key.escape)) {
|
|
800
855
|
if (this.helpVisible) {
|
|
801
856
|
this.helpVisible = false;
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
857
|
+
} else if (this.metadataExpanded) {
|
|
858
|
+
this.metadataExpanded = false;
|
|
859
|
+
} else if (this.lastWidth < WIDE_WORKSPACE_WIDTH && this.sectionDetail) {
|
|
860
|
+
this.sectionDetail = false;
|
|
805
861
|
this.rowIndex = 0;
|
|
806
|
-
this.tui.requestRender();
|
|
807
862
|
} else {
|
|
808
863
|
this.onDone(undefined);
|
|
864
|
+
return;
|
|
809
865
|
}
|
|
866
|
+
this.tui.requestRender();
|
|
810
867
|
return;
|
|
811
868
|
}
|
|
869
|
+
if (this.helpVisible) return;
|
|
870
|
+
|
|
812
871
|
if (matchesKey(data, 'g') || matchesKey(data, 'p')) {
|
|
813
872
|
const nextFocus: Scope = matchesKey(data, 'g') ? 'global' : 'project';
|
|
814
873
|
if (nextFocus !== this.browseFocus) {
|
|
815
874
|
this.browseFocus = nextFocus;
|
|
816
875
|
this.rowIndex = 0;
|
|
876
|
+
this.metadataExpanded = false;
|
|
817
877
|
this.tui.requestRender();
|
|
818
878
|
}
|
|
819
879
|
return;
|
|
820
880
|
}
|
|
821
|
-
if (
|
|
881
|
+
if (matchesKey(data, 'i')) {
|
|
882
|
+
this.metadataExpanded = !this.metadataExpanded;
|
|
883
|
+
this.tui.requestRender();
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
822
886
|
|
|
823
|
-
const
|
|
887
|
+
const wide = this.lastWidth >= WIDE_WORKSPACE_WIDTH;
|
|
824
888
|
if (matchesKey(data, Key.right)) {
|
|
825
|
-
if (this.
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
} else {
|
|
889
|
+
if (!wide && !this.sectionDetail) {
|
|
890
|
+
this.sectionDetail = true;
|
|
891
|
+
this.rowIndex = 0;
|
|
892
|
+
this.metadataExpanded = false;
|
|
893
|
+
this.tui.requestRender();
|
|
894
|
+
} else if (wide) {
|
|
832
895
|
this.moveSection(1);
|
|
833
896
|
}
|
|
834
897
|
return;
|
|
835
898
|
}
|
|
836
899
|
if (matchesKey(data, Key.left)) {
|
|
837
|
-
if (
|
|
838
|
-
this.
|
|
900
|
+
if (!wide && this.sectionDetail) {
|
|
901
|
+
this.sectionDetail = false;
|
|
839
902
|
this.rowIndex = 0;
|
|
903
|
+
this.metadataExpanded = false;
|
|
840
904
|
this.tui.requestRender();
|
|
841
|
-
} else if (
|
|
905
|
+
} else if (wide) {
|
|
842
906
|
this.moveSection(-1);
|
|
843
907
|
}
|
|
844
908
|
return;
|
|
845
909
|
}
|
|
910
|
+
const listView = !wide && !this.sectionDetail;
|
|
846
911
|
if (matchesKey(data, 'j') || matchesKey(data, Key.down)) {
|
|
847
|
-
if (
|
|
912
|
+
if (listView) this.moveSection(1);
|
|
848
913
|
else this.moveRow(1);
|
|
849
914
|
return;
|
|
850
915
|
}
|
|
851
916
|
if (matchesKey(data, 'k') || matchesKey(data, Key.up)) {
|
|
852
|
-
if (
|
|
917
|
+
if (listView) this.moveSection(-1);
|
|
853
918
|
else this.moveRow(-1);
|
|
854
919
|
return;
|
|
855
920
|
}
|
|
856
921
|
if (matchesKey(data, Key.enter)) {
|
|
857
|
-
if (
|
|
858
|
-
this.
|
|
922
|
+
if (listView) {
|
|
923
|
+
this.sectionDetail = true;
|
|
859
924
|
this.rowIndex = 0;
|
|
925
|
+
this.metadataExpanded = false;
|
|
860
926
|
this.tui.requestRender();
|
|
861
927
|
return;
|
|
862
928
|
}
|
|
@@ -872,13 +938,20 @@ export class BridgeLedgerComponent implements Component {
|
|
|
872
938
|
|
|
873
939
|
render(width: number): string[] {
|
|
874
940
|
this.lastWidth = Math.max(1, Math.floor(width));
|
|
875
|
-
const out =
|
|
941
|
+
const out = [
|
|
942
|
+
this.fit('CODEX MARKETPLACE / BRIDGE LEDGER', this.lastWidth, 'accent'),
|
|
943
|
+
...this.railPanels(this.lastWidth),
|
|
944
|
+
];
|
|
876
945
|
if (this.helpVisible) {
|
|
877
|
-
out.push(...
|
|
878
|
-
|
|
946
|
+
out.push(...renderPanel(this.theme, {
|
|
947
|
+
title: uiText('ledger.panel.help'),
|
|
948
|
+
lines: this.helpLines().map((line) => this.fit(line, Math.max(1, this.lastWidth - 3), 'text')),
|
|
949
|
+
width: this.lastWidth,
|
|
950
|
+
}));
|
|
951
|
+
} else if (this.lastWidth >= WIDE_WORKSPACE_WIDTH) {
|
|
879
952
|
out.push(...this.wideWorkspace(this.lastWidth));
|
|
880
953
|
} else {
|
|
881
|
-
out.push(...this.
|
|
954
|
+
out.push(...this.drilldownWorkspace(this.lastWidth));
|
|
882
955
|
}
|
|
883
956
|
out.push(this.fit(this.statusText(), this.lastWidth, 'dim'));
|
|
884
957
|
out.push(this.fit(this.keyHints(), this.lastWidth, 'dim'));
|
|
@@ -895,6 +968,7 @@ export class BridgeLedgerComponent implements Component {
|
|
|
895
968
|
if (count === 0) return;
|
|
896
969
|
this.sectionIndex = (this.sectionIndex + delta + count) % count;
|
|
897
970
|
this.rowIndex = 0;
|
|
971
|
+
this.metadataExpanded = false;
|
|
898
972
|
this.tui.requestRender();
|
|
899
973
|
}
|
|
900
974
|
|
|
@@ -902,6 +976,7 @@ export class BridgeLedgerComponent implements Component {
|
|
|
902
976
|
const count = this.actionEntries().length;
|
|
903
977
|
if (count === 0) return;
|
|
904
978
|
this.rowIndex = (this.rowIndex + delta + count) % count;
|
|
979
|
+
this.metadataExpanded = false;
|
|
905
980
|
this.tui.requestRender();
|
|
906
981
|
}
|
|
907
982
|
|
|
@@ -909,117 +984,209 @@ export class BridgeLedgerComponent implements Component {
|
|
|
909
984
|
return fitTerminalLine(this.theme.fg(token, text), width);
|
|
910
985
|
}
|
|
911
986
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
987
|
+
// --- Authority rails -----------------------------------------------------
|
|
988
|
+
|
|
989
|
+
private railPanels(width: number): string[] {
|
|
990
|
+
if (width < WIDE_WORKSPACE_WIDTH) {
|
|
991
|
+
return [
|
|
992
|
+
...renderPanel(this.theme, {
|
|
993
|
+
title: this.model.rails.global.label,
|
|
994
|
+
lines: this.railContentLines('global', width - 3),
|
|
995
|
+
width,
|
|
996
|
+
borderToken: 'borderMuted',
|
|
997
|
+
}),
|
|
998
|
+
...renderPanel(this.theme, {
|
|
999
|
+
title: this.model.rails.project.label,
|
|
1000
|
+
lines: this.railContentLines('project', width - 3),
|
|
1001
|
+
width,
|
|
1002
|
+
borderToken: 'borderAccent',
|
|
1003
|
+
}),
|
|
1004
|
+
];
|
|
1005
|
+
}
|
|
1006
|
+
const leftWidth = Math.max(24, Math.floor((width - 2) / 2));
|
|
1007
|
+
const rightWidth = Math.max(24, width - 2 - leftWidth);
|
|
1008
|
+
return renderSideBySidePanels(this.theme, {
|
|
1009
|
+
left: {
|
|
1010
|
+
title: this.model.rails.global.label,
|
|
1011
|
+
lines: this.railContentLines('global', leftWidth - 3),
|
|
1012
|
+
width: leftWidth,
|
|
1013
|
+
borderToken: 'borderMuted',
|
|
1014
|
+
},
|
|
1015
|
+
right: {
|
|
1016
|
+
title: this.model.rails.project.label,
|
|
1017
|
+
lines: this.railContentLines('project', rightWidth - 3),
|
|
1018
|
+
width: rightWidth,
|
|
1019
|
+
borderToken: 'borderAccent',
|
|
1020
|
+
},
|
|
1021
|
+
totalWidth: width,
|
|
1022
|
+
});
|
|
938
1023
|
}
|
|
939
1024
|
|
|
940
|
-
private
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1025
|
+
private railBadge(scope: Scope): string {
|
|
1026
|
+
const rail = scope === 'global' ? this.model.rails.global : this.model.rails.project;
|
|
1027
|
+
const badges = [renderBadge(this.theme, HEALTH_BADGES[rail.health].tone, uiText(HEALTH_BADGES[rail.health].labelId))];
|
|
1028
|
+
if (scope === 'project') {
|
|
1029
|
+
badges.push(renderBadge(
|
|
1030
|
+
this.theme,
|
|
1031
|
+
this.model.projectTrusted ? 'success' : 'warning',
|
|
1032
|
+
this.model.projectTrusted ? uiText('ledger.badge.trustGranted') : uiText('ledger.badge.noTrust'),
|
|
1033
|
+
));
|
|
1034
|
+
} else {
|
|
1035
|
+
badges.push(renderBadge(this.theme, this.model.barrier.active ? 'error' : 'success',
|
|
1036
|
+
this.model.barrier.active ? uiText('ledger.badge.barrierActive') : uiText('ledger.badge.barrierClear')));
|
|
1037
|
+
}
|
|
1038
|
+
return badges.join(' ');
|
|
949
1039
|
}
|
|
950
1040
|
|
|
951
|
-
private
|
|
952
|
-
const
|
|
953
|
-
const
|
|
954
|
-
const
|
|
955
|
-
const
|
|
956
|
-
this.
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
this.theme.fg('accent', section.label),
|
|
964
|
-
this.theme.fg('dim', section.description),
|
|
965
|
-
...this.actionLines(section),
|
|
1041
|
+
private railContentLines(scope: Scope, width: number): string[] {
|
|
1042
|
+
const rail = scope === 'global' ? this.model.rails.global : this.model.rails.project;
|
|
1043
|
+
const marker = scope === 'global' ? 'G' : 'P';
|
|
1044
|
+
const fitDim = (text: string): string => this.fit(text, width, 'dim');
|
|
1045
|
+
const lines = [
|
|
1046
|
+
this.railBadge(scope),
|
|
1047
|
+
uiText('ledger.rail.revision', { marker, revision: quoteTerminalText(rail.revision) }),
|
|
1048
|
+
uiText('ledger.rail.registrations', { count: rail.registrationCount }),
|
|
1049
|
+
uiText('ledger.rail.installations', {
|
|
1050
|
+
enabled: rail.installationEnabledCount,
|
|
1051
|
+
disabled: rail.installationDisabledCount,
|
|
1052
|
+
}),
|
|
966
1053
|
];
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1054
|
+
if (scope === 'project') lines.push(uiText('ledger.rail.overrides', { count: rail.overrideCount }));
|
|
1055
|
+
if (rail.health !== 'healthy') lines.push(fitDim(quoteTerminalText(rail.healthText)));
|
|
1056
|
+
if (scope === 'project') lines.push(fitDim(rail.trustText));
|
|
1057
|
+
if (scope === 'global' && this.model.barrier.active) {
|
|
1058
|
+
lines.push(this.fit(
|
|
1059
|
+
uiText('ledger.rail.barrierReason', { reason: quoteTerminalText(this.model.barrier.text) }),
|
|
1060
|
+
width, 'warning',
|
|
1061
|
+
));
|
|
973
1062
|
}
|
|
974
1063
|
return lines;
|
|
975
1064
|
}
|
|
976
1065
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1066
|
+
// --- Workspaces ----------------------------------------------------------
|
|
1067
|
+
|
|
1068
|
+
private sectionNavLines(width: number): string[] {
|
|
1069
|
+
return this.model.sections.map((section, index) =>
|
|
1070
|
+
renderSelectableRow(this.theme, {
|
|
1071
|
+
selected: index === this.sectionIndex,
|
|
1072
|
+
text: this.theme.fg(index === this.sectionIndex ? 'accent' : 'text', section.label),
|
|
1073
|
+
width,
|
|
1074
|
+
}));
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
private wideWorkspace(width: number): string[] {
|
|
1078
|
+
const navWidth = Math.min(34, Math.max(22, Math.floor(width * 0.28)));
|
|
1079
|
+
const detailWidth = Math.max(24, width - navWidth - 2);
|
|
1080
|
+
const section = this.currentSection();
|
|
1081
|
+
return renderSideBySidePanels(this.theme, {
|
|
1082
|
+
left: {
|
|
1083
|
+
title: uiText('ledger.panel.navigation'),
|
|
1084
|
+
lines: this.sectionNavLines(navWidth - 3),
|
|
1085
|
+
width: navWidth,
|
|
1086
|
+
borderToken: 'borderMuted',
|
|
1087
|
+
},
|
|
1088
|
+
right: {
|
|
1089
|
+
title: section.label,
|
|
1090
|
+
lines: [
|
|
1091
|
+
this.fit(section.description, detailWidth - 3, 'dim'),
|
|
1092
|
+
'',
|
|
1093
|
+
...this.actionEntryLines(detailWidth - 3),
|
|
1094
|
+
],
|
|
1095
|
+
width: detailWidth,
|
|
1096
|
+
borderToken: 'borderAccent',
|
|
1097
|
+
},
|
|
1098
|
+
totalWidth: width,
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
private drilldownWorkspace(width: number): string[] {
|
|
1103
|
+
if (!this.sectionDetail) {
|
|
1104
|
+
return renderPanel(this.theme, {
|
|
1105
|
+
title: uiText('ledger.panel.sections'),
|
|
1106
|
+
lines: this.sectionNavLines(Math.max(1, width - 3)),
|
|
1107
|
+
width,
|
|
1108
|
+
borderToken: 'borderAccent',
|
|
1109
|
+
});
|
|
985
1110
|
}
|
|
986
1111
|
const section = this.currentSection();
|
|
987
|
-
return
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1112
|
+
return renderPanel(this.theme, {
|
|
1113
|
+
title: section.label,
|
|
1114
|
+
lines: [
|
|
1115
|
+
this.fit(section.description, Math.max(1, width - 3), 'dim'),
|
|
1116
|
+
'',
|
|
1117
|
+
...this.actionEntryLines(Math.max(1, width - 3)),
|
|
1118
|
+
],
|
|
1119
|
+
width,
|
|
1120
|
+
borderToken: 'borderAccent',
|
|
1121
|
+
});
|
|
992
1122
|
}
|
|
993
1123
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1124
|
+
// --- Action entries ------------------------------------------------------
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Renders every visible row in the panel visual language: availability is an
|
|
1128
|
+
* icon+token+word state, selection combines a background wash with a text
|
|
1129
|
+
* cursor, and structured field dumps live only in the expandable metadata layer.
|
|
1130
|
+
*/
|
|
1131
|
+
private actionEntryLines(width: number): string[] {
|
|
1132
|
+
const rows = this.visibleRows();
|
|
1133
|
+
if (rows.length === 0) return [this.fit(uiText('ledger.rows.empty'), width, 'muted')];
|
|
997
1134
|
let actionIndex = 0;
|
|
998
|
-
|
|
1135
|
+
const lines: string[] = [];
|
|
1136
|
+
for (const row of rows) {
|
|
999
1137
|
if (row.actions.length === 0) {
|
|
1000
|
-
|
|
1001
|
-
this.
|
|
1002
|
-
this.
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
];
|
|
1138
|
+
lines.push(
|
|
1139
|
+
this.fit(`${AVAILABILITY.blocked.icon} ${uiText('ledger.entry.unavailableRow', { label: quoteTerminalText(row.label) })}`, width, 'warning'),
|
|
1140
|
+
this.fit(` ${quoteTerminalText(row.detail ?? uiText('ledger.entry.noFindings'))}`, width, 'dim'),
|
|
1141
|
+
);
|
|
1142
|
+
continue;
|
|
1006
1143
|
}
|
|
1007
|
-
|
|
1144
|
+
for (const action of row.actions) {
|
|
1008
1145
|
const selected = actionIndex === this.rowIndex;
|
|
1009
1146
|
actionIndex += 1;
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1147
|
+
const availability = action.enabled ? AVAILABILITY.ready : AVAILABILITY.blocked;
|
|
1148
|
+
const text =
|
|
1149
|
+
this.theme.fg(availability.token, `${availability.icon} ${availability.word} ${action.label}`) +
|
|
1150
|
+
this.theme.fg('dim', ` \u00b7 ${quoteTerminalText(row.label)}`);
|
|
1151
|
+
lines.push(renderSelectableRow(this.theme, { selected, text, width }));
|
|
1152
|
+
if (!selected) continue;
|
|
1153
|
+
if (!action.enabled) {
|
|
1154
|
+
lines.push(...this.wrapContext(
|
|
1155
|
+
`\u21b3 ${uiText('ledger.entry.blocked', { reason: quoteTerminalText(action.disabledReason ?? uiText('common.unavailable')) })}`,
|
|
1156
|
+
width, 'warning', 4));
|
|
1157
|
+
}
|
|
1158
|
+
if (this.metadataExpanded) {
|
|
1159
|
+
const intent = action.intent;
|
|
1160
|
+
const meta = [
|
|
1161
|
+
uiText('ledger.meta.target', {
|
|
1162
|
+
kind: intent.targetKind ?? row.targetKind ?? uiText('common.none'),
|
|
1163
|
+
target: quoteTerminalText(intent.targetId ?? row.targetId ?? uiText('common.none')),
|
|
1164
|
+
}),
|
|
1165
|
+
uiText('ledger.meta.scope', { scope: intent.scope ?? row.scope ?? uiText('common.none') }),
|
|
1166
|
+
uiText('ledger.meta.mode', { mode: intent.mode }),
|
|
1167
|
+
];
|
|
1168
|
+
if (row.detail !== undefined) meta.push(uiText('ledger.meta.detail', { detail: quoteTerminalText(row.detail) }));
|
|
1169
|
+
lines.push(...meta.flatMap((entry) => this.wrapContext(` ${entry}`, width, 'muted', 4)));
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return lines;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
private wrapContext(text: string, width: number, token: Parameters<Theme['fg']>[0], maxLines: number): string[] {
|
|
1177
|
+
const wrapped = wrapTextWithAnsi(this.theme.fg(token, text), Math.max(1, width)).slice(0, maxLines);
|
|
1178
|
+
return wrapped.map((line) => fitTerminalLine(line, width));
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
private helpLines(): string[] {
|
|
1182
|
+
return [
|
|
1183
|
+
uiText('ledger.help.move'),
|
|
1184
|
+
uiText('ledger.help.sections'),
|
|
1185
|
+
uiText('ledger.help.enter'),
|
|
1186
|
+
uiText('ledger.help.metadata'),
|
|
1187
|
+
uiText('ledger.help.browse'),
|
|
1188
|
+
uiText('ledger.help.close'),
|
|
1189
|
+
];
|
|
1023
1190
|
}
|
|
1024
1191
|
|
|
1025
1192
|
private visibleRows(section = this.currentSection()): LedgerObjectRow[] {
|
|
@@ -1042,15 +1209,21 @@ export class BridgeLedgerComponent implements Component {
|
|
|
1042
1209
|
|
|
1043
1210
|
private statusText(): string {
|
|
1044
1211
|
const section = this.currentSection();
|
|
1045
|
-
const pane = this.lastWidth
|
|
1046
|
-
|
|
1212
|
+
const pane = this.lastWidth >= WIDE_WORKSPACE_WIDTH || this.sectionDetail
|
|
1213
|
+
? uiText('ledger.status.pane.actions')
|
|
1214
|
+
: uiText('ledger.status.pane.sections');
|
|
1215
|
+
return uiText('ledger.status.browsing', {
|
|
1216
|
+
marker: this.browseFocus === 'global' ? 'G' : 'P',
|
|
1217
|
+
section: section.label,
|
|
1218
|
+
pane,
|
|
1219
|
+
});
|
|
1047
1220
|
}
|
|
1048
1221
|
|
|
1049
1222
|
private keyHints(): string {
|
|
1050
|
-
if (this.helpVisible) return '
|
|
1051
|
-
if (this.lastWidth <
|
|
1052
|
-
return '
|
|
1223
|
+
if (this.helpVisible) return uiText('ledger.keys.help');
|
|
1224
|
+
if (this.lastWidth < WIDE_WORKSPACE_WIDTH && !this.sectionDetail) {
|
|
1225
|
+
return uiText('ledger.keys.drilldown');
|
|
1053
1226
|
}
|
|
1054
|
-
return '
|
|
1227
|
+
return uiText('ledger.keys.wide');
|
|
1055
1228
|
}
|
|
1056
1229
|
}
|