dev-cockpit 0.1.0
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/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/bin/dev-cockpit.mjs +20 -0
- package/dist/buildCli.d.ts +17 -0
- package/dist/buildCli.d.ts.map +1 -0
- package/dist/buildCli.js +107 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cockpit/Cockpit.d.ts +33 -0
- package/dist/cockpit/Cockpit.d.ts.map +1 -0
- package/dist/cockpit/Cockpit.js +73 -0
- package/dist/cockpit/Footer.d.ts +22 -0
- package/dist/cockpit/Footer.d.ts.map +1 -0
- package/dist/cockpit/Footer.js +33 -0
- package/dist/cockpit/TabBar.d.ts +3 -0
- package/dist/cockpit/TabBar.d.ts.map +1 -0
- package/dist/cockpit/TabBar.js +12 -0
- package/dist/cockpit/help/content.d.ts +12 -0
- package/dist/cockpit/help/content.d.ts.map +1 -0
- package/dist/cockpit/help/content.js +22 -0
- package/dist/cockpit/help/loader.d.ts +65 -0
- package/dist/cockpit/help/loader.d.ts.map +1 -0
- package/dist/cockpit/help/loader.js +118 -0
- package/dist/cockpit/help/renderer.d.ts +16 -0
- package/dist/cockpit/help/renderer.d.ts.map +1 -0
- package/dist/cockpit/help/renderer.js +35 -0
- package/dist/cockpit/help/types.d.ts +12 -0
- package/dist/cockpit/help/types.d.ts.map +1 -0
- package/dist/cockpit/help/types.js +1 -0
- package/dist/cockpit/hooks/useCockpitStore.d.ts +3 -0
- package/dist/cockpit/hooks/useCockpitStore.d.ts.map +1 -0
- package/dist/cockpit/hooks/useCockpitStore.js +5 -0
- package/dist/cockpit/hooks/useGlobalKeys.d.ts +56 -0
- package/dist/cockpit/hooks/useGlobalKeys.d.ts.map +1 -0
- package/dist/cockpit/hooks/useGlobalKeys.js +173 -0
- package/dist/cockpit/panes/FilterModal.d.ts +3 -0
- package/dist/cockpit/panes/FilterModal.d.ts.map +1 -0
- package/dist/cockpit/panes/FilterModal.js +22 -0
- package/dist/cockpit/panes/Health.d.ts +13 -0
- package/dist/cockpit/panes/Health.d.ts.map +1 -0
- package/dist/cockpit/panes/Health.js +30 -0
- package/dist/cockpit/panes/Help.d.ts +14 -0
- package/dist/cockpit/panes/Help.d.ts.map +1 -0
- package/dist/cockpit/panes/Help.js +81 -0
- package/dist/cockpit/panes/Output.d.ts +14 -0
- package/dist/cockpit/panes/Output.d.ts.map +1 -0
- package/dist/cockpit/panes/Output.js +108 -0
- package/dist/cockpit/panes/Repos.d.ts +3 -0
- package/dist/cockpit/panes/Repos.d.ts.map +1 -0
- package/dist/cockpit/panes/Repos.js +48 -0
- package/dist/cockpit/panes/SearchModal.d.ts +3 -0
- package/dist/cockpit/panes/SearchModal.d.ts.map +1 -0
- package/dist/cockpit/panes/SearchModal.js +31 -0
- package/dist/cockpit/state/store.d.ts +93 -0
- package/dist/cockpit/state/store.d.ts.map +1 -0
- package/dist/cockpit/state/store.js +111 -0
- package/dist/cockpit/tab-state.d.ts +4 -0
- package/dist/cockpit/tab-state.d.ts.map +1 -0
- package/dist/cockpit/tab-state.js +7 -0
- package/dist/commands/dev.d.ts +20 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +158 -0
- package/dist/commands/doctor.d.ts +20 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +66 -0
- package/dist/commands/init-config-wizard.d.ts +84 -0
- package/dist/commands/init-config-wizard.d.ts.map +1 -0
- package/dist/commands/init-config-wizard.js +818 -0
- package/dist/commands/init-config.d.ts +35 -0
- package/dist/commands/init-config.d.ts.map +1 -0
- package/dist/commands/init-config.js +131 -0
- package/dist/commands/mount.d.ts +48 -0
- package/dist/commands/mount.d.ts.map +1 -0
- package/dist/commands/mount.js +150 -0
- package/dist/core/config.d.ts +391 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +152 -0
- package/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +38 -0
- package/dist/core/notifier.d.ts +23 -0
- package/dist/core/notifier.d.ts.map +1 -0
- package/dist/core/notifier.js +100 -0
- package/dist/core/paths.d.ts +15 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +18 -0
- package/dist/core/subprocess.d.ts +20 -0
- package/dist/core/subprocess.d.ts.map +1 -0
- package/dist/core/subprocess.js +82 -0
- package/dist/core/types.d.ts +125 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/docker/highlights.d.ts +48 -0
- package/dist/docker/highlights.d.ts.map +1 -0
- package/dist/docker/highlights.js +79 -0
- package/dist/docker/logs.d.ts +84 -0
- package/dist/docker/logs.d.ts.map +1 -0
- package/dist/docker/logs.js +172 -0
- package/dist/docker/restart.d.ts +26 -0
- package/dist/docker/restart.d.ts.map +1 -0
- package/dist/docker/restart.js +45 -0
- package/dist/docker/stack-trace.d.ts +25 -0
- package/dist/docker/stack-trace.d.ts.map +1 -0
- package/dist/docker/stack-trace.js +44 -0
- package/dist/health/builtin.d.ts +8 -0
- package/dist/health/builtin.d.ts.map +1 -0
- package/dist/health/builtin.js +144 -0
- package/dist/health/context.d.ts +3 -0
- package/dist/health/context.d.ts.map +1 -0
- package/dist/health/context.js +31 -0
- package/dist/health/notify-resolver.d.ts +18 -0
- package/dist/health/notify-resolver.d.ts.map +1 -0
- package/dist/health/notify-resolver.js +28 -0
- package/dist/health/registry.d.ts +20 -0
- package/dist/health/registry.d.ts.map +1 -0
- package/dist/health/registry.js +64 -0
- package/dist/health/remediations.d.ts +6 -0
- package/dist/health/remediations.d.ts.map +1 -0
- package/dist/health/remediations.js +41 -0
- package/dist/health/runner.d.ts +4 -0
- package/dist/health/runner.d.ts.map +1 -0
- package/dist/health/runner.js +22 -0
- package/dist/health/scheduler.d.ts +41 -0
- package/dist/health/scheduler.d.ts.map +1 -0
- package/dist/health/scheduler.js +107 -0
- package/dist/health/types.d.ts +73 -0
- package/dist/health/types.d.ts.map +1 -0
- package/dist/health/types.js +1 -0
- package/dist/health/useHealth.d.ts +40 -0
- package/dist/health/useHealth.d.ts.map +1 -0
- package/dist/health/useHealth.js +122 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/ink.d.ts +3 -0
- package/dist/ink.d.ts.map +1 -0
- package/dist/ink.js +1 -0
- package/dist/lint/reactive.d.ts +38 -0
- package/dist/lint/reactive.d.ts.map +1 -0
- package/dist/lint/reactive.js +131 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +1 -0
- package/dist/runCockpit.d.ts +34 -0
- package/dist/runCockpit.d.ts.map +1 -0
- package/dist/runCockpit.js +75 -0
- package/dist/watchers/manager.d.ts +63 -0
- package/dist/watchers/manager.d.ts.map +1 -0
- package/dist/watchers/manager.js +239 -0
- package/dist/watchers/path-mapper.d.ts +23 -0
- package/dist/watchers/path-mapper.d.ts.map +1 -0
- package/dist/watchers/path-mapper.js +29 -0
- package/dist/watchers/types.d.ts +22 -0
- package/dist/watchers/types.d.ts.map +1 -0
- package/dist/watchers/types.js +9 -0
- package/docs/commands.md +71 -0
- package/docs/config-reference.md +20 -0
- package/docs/getting-started.md +39 -0
- package/docs/health.md +120 -0
- package/docs/index.md +13 -0
- package/docs/init-config.md +46 -0
- package/docs/mount.md +55 -0
- package/docs/notifications.md +39 -0
- package/docs/panes.md +45 -0
- package/docs/watchers.md +27 -0
- package/examples/cockpit.yaml +116 -0
- package/package.json +91 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Help-tab content loader.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a docs/ folder by walking up from a given module URL, looking for
|
|
5
|
+
* a directory containing both `package.json` and `docs/index.md`. This works
|
|
6
|
+
* across three contexts:
|
|
7
|
+
* - tsx-from-source → src/cockpit/help/loader.ts → ../../../docs
|
|
8
|
+
* - dist/-from-build → dist/cockpit/help/loader.js → ../../../docs
|
|
9
|
+
* - npm i installed → node_modules/<pkg>/dist/.../loader.js → <pkg>/docs
|
|
10
|
+
*
|
|
11
|
+
* The loader supports merging multiple sources: core docs first, then any
|
|
12
|
+
* profile-supplied sources (paths or inline pages). Sources later in the list
|
|
13
|
+
* override earlier ones by slug. A source with `omit: true` removes that slug.
|
|
14
|
+
*
|
|
15
|
+
* `docs/index.md` defines the ordered page list for that source. Each entry
|
|
16
|
+
* is a markdown bullet of the form:
|
|
17
|
+
* - [Title](./slug.md) — optional summary
|
|
18
|
+
*
|
|
19
|
+
* The index page is itself returned as the first HelpPage (slug = 'index').
|
|
20
|
+
*/
|
|
21
|
+
import type { HelpPage } from './types.js';
|
|
22
|
+
/** Walk up from `startUrl` (or this module by default) for package.json + docs/index.md. */
|
|
23
|
+
export declare function resolveDocsRoot(startUrl?: string): string | null;
|
|
24
|
+
/** Parse the markdown index into an ordered list of page slugs. */
|
|
25
|
+
export declare function parseIndex(indexBody: string): Array<{
|
|
26
|
+
slug: string;
|
|
27
|
+
title: string;
|
|
28
|
+
}>;
|
|
29
|
+
/** Load all pages (in index order) from a single docs/ directory. */
|
|
30
|
+
export declare function loadPagesFromDir(docsRoot: string): HelpPage[];
|
|
31
|
+
/** A help source contributed by config or a profile. */
|
|
32
|
+
export interface HelpSourceInput {
|
|
33
|
+
/** Filesystem path to a docs/ directory. */
|
|
34
|
+
path?: string;
|
|
35
|
+
/** Inline page; if `id`/`slug` matches an existing page, replaces it. */
|
|
36
|
+
page?: HelpPage;
|
|
37
|
+
/** Slug to omit from the merged list. Use with `omit: true`. */
|
|
38
|
+
id?: string;
|
|
39
|
+
/** When true, removes the page with this id from the merged list. */
|
|
40
|
+
omit?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface LoadHelpPagesOptions {
|
|
43
|
+
/**
|
|
44
|
+
* Module URL whose docs/ should be loaded as the **core** source.
|
|
45
|
+
* Default: this module's URL — i.e., dev-cockpit's bundled docs.
|
|
46
|
+
*/
|
|
47
|
+
coreUrl?: string;
|
|
48
|
+
/** Additional sources applied AFTER core. Later sources override earlier ones by slug. */
|
|
49
|
+
sources?: HelpSourceInput[];
|
|
50
|
+
/** Slug to land on first. If absent, the first page is used. */
|
|
51
|
+
defaultPage?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface LoadHelpPagesResult {
|
|
54
|
+
pages: HelpPage[];
|
|
55
|
+
defaultIndex: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Load and merge help pages from core + any contributed sources.
|
|
59
|
+
*
|
|
60
|
+
* Returns `null` only if the core docs root cannot be found AND no sources
|
|
61
|
+
* provide pages. Otherwise returns a non-empty merged list with `defaultIndex`
|
|
62
|
+
* pointing at `defaultPage` (or 0 when `defaultPage` is absent / unknown).
|
|
63
|
+
*/
|
|
64
|
+
export declare function loadHelpPages(opts?: LoadHelpPagesOptions): LoadHelpPagesResult | null;
|
|
65
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/cockpit/help/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAAwB,GAAG,MAAM,GAAG,IAAI,CAWjF;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAUpF;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,CAsB7D;AAED,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,oBAAyB,GAAG,mBAAmB,GAAG,IAAI,CA2CzF"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Help-tab content loader.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a docs/ folder by walking up from a given module URL, looking for
|
|
5
|
+
* a directory containing both `package.json` and `docs/index.md`. This works
|
|
6
|
+
* across three contexts:
|
|
7
|
+
* - tsx-from-source → src/cockpit/help/loader.ts → ../../../docs
|
|
8
|
+
* - dist/-from-build → dist/cockpit/help/loader.js → ../../../docs
|
|
9
|
+
* - npm i installed → node_modules/<pkg>/dist/.../loader.js → <pkg>/docs
|
|
10
|
+
*
|
|
11
|
+
* The loader supports merging multiple sources: core docs first, then any
|
|
12
|
+
* profile-supplied sources (paths or inline pages). Sources later in the list
|
|
13
|
+
* override earlier ones by slug. A source with `omit: true` removes that slug.
|
|
14
|
+
*
|
|
15
|
+
* `docs/index.md` defines the ordered page list for that source. Each entry
|
|
16
|
+
* is a markdown bullet of the form:
|
|
17
|
+
* - [Title](./slug.md) — optional summary
|
|
18
|
+
*
|
|
19
|
+
* The index page is itself returned as the first HelpPage (slug = 'index').
|
|
20
|
+
*/
|
|
21
|
+
import fs from 'node:fs';
|
|
22
|
+
import path from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
/** Walk up from `startUrl` (or this module by default) for package.json + docs/index.md. */
|
|
25
|
+
export function resolveDocsRoot(startUrl = import.meta.url) {
|
|
26
|
+
let dir = path.dirname(fileURLToPath(startUrl));
|
|
27
|
+
while (dir !== path.dirname(dir)) {
|
|
28
|
+
const pkgJson = path.join(dir, 'package.json');
|
|
29
|
+
const docsIndex = path.join(dir, 'docs', 'index.md');
|
|
30
|
+
if (fs.existsSync(pkgJson) && fs.existsSync(docsIndex)) {
|
|
31
|
+
return path.join(dir, 'docs');
|
|
32
|
+
}
|
|
33
|
+
dir = path.dirname(dir);
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/** Parse the markdown index into an ordered list of page slugs. */
|
|
38
|
+
export function parseIndex(indexBody) {
|
|
39
|
+
const out = [];
|
|
40
|
+
const linkRe = /^\s*[-*]\s+\[([^\]]+)\]\((?:\.\/)?([^)]+?)\.md\)/;
|
|
41
|
+
for (const line of indexBody.split(/\r?\n/)) {
|
|
42
|
+
const match = linkRe.exec(line);
|
|
43
|
+
if (match && match[1] && match[2]) {
|
|
44
|
+
out.push({ title: match[1], slug: match[2] });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
/** Load all pages (in index order) from a single docs/ directory. */
|
|
50
|
+
export function loadPagesFromDir(docsRoot) {
|
|
51
|
+
const indexPath = path.join(docsRoot, 'index.md');
|
|
52
|
+
let indexBody;
|
|
53
|
+
try {
|
|
54
|
+
indexBody = fs.readFileSync(indexPath, 'utf8');
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const pages = [{ slug: 'index', title: 'Index', path: indexPath, body: indexBody }];
|
|
60
|
+
for (const entry of parseIndex(indexBody)) {
|
|
61
|
+
const pagePath = path.join(docsRoot, `${entry.slug}.md`);
|
|
62
|
+
try {
|
|
63
|
+
const body = fs.readFileSync(pagePath, 'utf8');
|
|
64
|
+
pages.push({ slug: entry.slug, title: entry.title, path: pagePath, body });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Missing page file — skip silently.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return pages;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Load and merge help pages from core + any contributed sources.
|
|
74
|
+
*
|
|
75
|
+
* Returns `null` only if the core docs root cannot be found AND no sources
|
|
76
|
+
* provide pages. Otherwise returns a non-empty merged list with `defaultIndex`
|
|
77
|
+
* pointing at `defaultPage` (or 0 when `defaultPage` is absent / unknown).
|
|
78
|
+
*/
|
|
79
|
+
export function loadHelpPages(opts = {}) {
|
|
80
|
+
const coreUrl = opts.coreUrl ?? import.meta.url;
|
|
81
|
+
const corePages = [];
|
|
82
|
+
const coreRoot = resolveDocsRoot(coreUrl);
|
|
83
|
+
if (coreRoot) {
|
|
84
|
+
corePages.push(...loadPagesFromDir(coreRoot));
|
|
85
|
+
}
|
|
86
|
+
// Merge sources in order. Map keyed by slug preserves first-write insertion
|
|
87
|
+
// order; later sources REPLACE by re-assigning the same key.
|
|
88
|
+
const merged = new Map();
|
|
89
|
+
for (const page of corePages) {
|
|
90
|
+
merged.set(page.slug, page);
|
|
91
|
+
}
|
|
92
|
+
for (const src of opts.sources ?? []) {
|
|
93
|
+
if (src.omit && src.id) {
|
|
94
|
+
merged.delete(src.id);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (src.page) {
|
|
98
|
+
merged.set(src.page.slug, src.page);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (src.path) {
|
|
102
|
+
const pages = loadPagesFromDir(src.path);
|
|
103
|
+
for (const p of pages) {
|
|
104
|
+
merged.set(p.slug, p);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const pages = Array.from(merged.values());
|
|
109
|
+
if (pages.length === 0)
|
|
110
|
+
return null;
|
|
111
|
+
let defaultIndex = 0;
|
|
112
|
+
if (opts.defaultPage) {
|
|
113
|
+
const idx = pages.findIndex((p) => p.slug === opts.defaultPage);
|
|
114
|
+
if (idx >= 0)
|
|
115
|
+
defaultIndex = idx;
|
|
116
|
+
}
|
|
117
|
+
return { pages, defaultIndex };
|
|
118
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown → terminal ANSI renderer.
|
|
3
|
+
*
|
|
4
|
+
* marked + marked-terminal — the latter emits an ANSI string handed to Ink's
|
|
5
|
+
* <Text>. Ink passes ANSI through to stdout. Tradeoff accepted: long lines
|
|
6
|
+
* wrap at the terminal column boundary, which is fine for prose docs.
|
|
7
|
+
*
|
|
8
|
+
* Renderer is configured once at module load (marked-terminal mutates the
|
|
9
|
+
* shared marked instance).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Render a markdown string to ANSI-colored terminal output.
|
|
13
|
+
* Always returns a string; never throws on well-formed markdown.
|
|
14
|
+
*/
|
|
15
|
+
export declare function renderMarkdown(markdown: string): string;
|
|
16
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/cockpit/help/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAaH;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASvD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown → terminal ANSI renderer.
|
|
3
|
+
*
|
|
4
|
+
* marked + marked-terminal — the latter emits an ANSI string handed to Ink's
|
|
5
|
+
* <Text>. Ink passes ANSI through to stdout. Tradeoff accepted: long lines
|
|
6
|
+
* wrap at the terminal column boundary, which is fine for prose docs.
|
|
7
|
+
*
|
|
8
|
+
* Renderer is configured once at module load (marked-terminal mutates the
|
|
9
|
+
* shared marked instance).
|
|
10
|
+
*/
|
|
11
|
+
import { marked } from 'marked';
|
|
12
|
+
import { markedTerminal } from 'marked-terminal';
|
|
13
|
+
let configured = false;
|
|
14
|
+
function ensureConfigured() {
|
|
15
|
+
if (configured)
|
|
16
|
+
return;
|
|
17
|
+
marked.use(markedTerminal());
|
|
18
|
+
configured = true;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Render a markdown string to ANSI-colored terminal output.
|
|
22
|
+
* Always returns a string; never throws on well-formed markdown.
|
|
23
|
+
*/
|
|
24
|
+
export function renderMarkdown(markdown) {
|
|
25
|
+
ensureConfigured();
|
|
26
|
+
if (!markdown)
|
|
27
|
+
return '';
|
|
28
|
+
try {
|
|
29
|
+
const out = marked.parse(markdown);
|
|
30
|
+
return typeof out === 'string' ? out : markdown;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return markdown;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** A markdown page loaded from a docs/ directory. */
|
|
2
|
+
export interface HelpPage {
|
|
3
|
+
/** Filename minus extension, e.g. "install". Used as the merge id. */
|
|
4
|
+
slug: string;
|
|
5
|
+
/** Human-readable title shown in the page selector. */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Absolute path to the source file (used for diagnostics). Empty when content is inline. */
|
|
8
|
+
path: string;
|
|
9
|
+
/** Raw markdown body. */
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cockpit/help/types.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCockpitStore.d.ts","sourceRoot":"","sources":["../../../src/cockpit/hooks/useCockpitStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,CAAC,GAAG,CAAC,CAE1E"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global keyboard handler for the cockpit TUI.
|
|
3
|
+
*
|
|
4
|
+
* Globals (active in every tab):
|
|
5
|
+
* ← / → cycle tabs (backward / forward)
|
|
6
|
+
* tab / shift+tab cycle tabs (alias) — except inside Help, where these
|
|
7
|
+
* are repurposed for page navigation. Use ←/→ to leave.
|
|
8
|
+
* q onQuit()
|
|
9
|
+
* n toggleSessionNotifications
|
|
10
|
+
*
|
|
11
|
+
* Per-tab keys are dispatched to the relevant handler callback. Domain-aware
|
|
12
|
+
* behavior (rebuild, lint, remediation lookup, editor launch) lives in the
|
|
13
|
+
* profile / consumer; this hook just routes keystrokes to the handlers and
|
|
14
|
+
* manages the minimum-visibility-hold for in-flight banners.
|
|
15
|
+
*/
|
|
16
|
+
import type { RepoState } from '../state/store.js';
|
|
17
|
+
/** Result of a kicked-off async action — the hook tracks its in-flight state. */
|
|
18
|
+
export interface AsyncActionDispatch {
|
|
19
|
+
/** Banner / row label while the action is in flight. */
|
|
20
|
+
label: string;
|
|
21
|
+
/** Promise resolving when the action completes (success or failure). */
|
|
22
|
+
promise: Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export interface RemediationDispatch extends AsyncActionDispatch {
|
|
25
|
+
healthId: string;
|
|
26
|
+
healthLabel: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UseGlobalKeysOptions {
|
|
29
|
+
onQuit: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Triggered by `r` on Repos pane. Returns dispatch info if the action started,
|
|
32
|
+
* or null to skip (e.g., docker entry with no restart handler wired).
|
|
33
|
+
*/
|
|
34
|
+
runRepoAction?: (repoKey: string, repo: RepoState) => AsyncActionDispatch | null;
|
|
35
|
+
/** Triggered by `w` on Repos for repo-kind entries. Fire-and-forget. */
|
|
36
|
+
onWatchToggle?: (repoKey: string, repo: RepoState) => void;
|
|
37
|
+
/** Triggered by `l` on Repos for repo-kind entries. Fire-and-forget. */
|
|
38
|
+
onLint?: (repoKey: string, repo: RepoState) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Triggered by `e` on Output pane. Receives the most recent error with file:line
|
|
41
|
+
* (or `null` if no such error exists). Synchronous.
|
|
42
|
+
*/
|
|
43
|
+
onOpenError?: (error: {
|
|
44
|
+
file: string;
|
|
45
|
+
line: number;
|
|
46
|
+
service: string;
|
|
47
|
+
text: string;
|
|
48
|
+
} | null) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Triggered by an uppercase letter on Health pane. Returns dispatch info
|
|
51
|
+
* with healthId/healthLabel if a check matched, or null to skip.
|
|
52
|
+
*/
|
|
53
|
+
runRemediation?: (remediationKey: string) => RemediationDispatch | null;
|
|
54
|
+
}
|
|
55
|
+
export declare function useGlobalKeys(opts: UseGlobalKeysOptions): void;
|
|
56
|
+
//# sourceMappingURL=useGlobalKeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useGlobalKeys.d.ts","sourceRoot":"","sources":["../../../src/cockpit/hooks/useGlobalKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AASnD,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,mBAAmB,GAAG,IAAI,CAAC;IACjF,wEAAwE;IACxE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAC3D,wEAAwE;IACxE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAEpD;;;OAGG;IACH,WAAW,CAAC,EAAE,CACZ,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KACxE,IAAI,CAAC;IAEV;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,mBAAmB,GAAG,IAAI,CAAC;CACzE;AAYD,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAwJ9D"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global keyboard handler for the cockpit TUI.
|
|
3
|
+
*
|
|
4
|
+
* Globals (active in every tab):
|
|
5
|
+
* ← / → cycle tabs (backward / forward)
|
|
6
|
+
* tab / shift+tab cycle tabs (alias) — except inside Help, where these
|
|
7
|
+
* are repurposed for page navigation. Use ←/→ to leave.
|
|
8
|
+
* q onQuit()
|
|
9
|
+
* n toggleSessionNotifications
|
|
10
|
+
*
|
|
11
|
+
* Per-tab keys are dispatched to the relevant handler callback. Domain-aware
|
|
12
|
+
* behavior (rebuild, lint, remediation lookup, editor launch) lives in the
|
|
13
|
+
* profile / consumer; this hook just routes keystrokes to the handlers and
|
|
14
|
+
* manages the minimum-visibility-hold for in-flight banners.
|
|
15
|
+
*/
|
|
16
|
+
import { useInput } from 'ink';
|
|
17
|
+
import { cockpitStore } from '../state/store.js';
|
|
18
|
+
/**
|
|
19
|
+
* Minimum time an in-flight-action banner stays visible, even if the
|
|
20
|
+
* underlying work completes faster. Without this, fast-finishing actions
|
|
21
|
+
* (instant failures, no-op installs) flash by unnoticed.
|
|
22
|
+
*/
|
|
23
|
+
const MIN_ACTION_BANNER_MS = 1500;
|
|
24
|
+
function withMinHold(promise, onDone) {
|
|
25
|
+
const startedAt = Date.now();
|
|
26
|
+
void promise.finally(() => {
|
|
27
|
+
const elapsed = Date.now() - startedAt;
|
|
28
|
+
const remaining = Math.max(0, MIN_ACTION_BANNER_MS - elapsed);
|
|
29
|
+
if (remaining === 0)
|
|
30
|
+
onDone();
|
|
31
|
+
else
|
|
32
|
+
setTimeout(onDone, remaining);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function useGlobalKeys(opts) {
|
|
36
|
+
const { onQuit, runRepoAction, onWatchToggle, onLint, onOpenError, runRemediation } = opts;
|
|
37
|
+
useInput((input, key) => {
|
|
38
|
+
const state = cockpitStore.getState();
|
|
39
|
+
// Modal is open — don't process global keys.
|
|
40
|
+
if (state.activeModal !== null)
|
|
41
|
+
return;
|
|
42
|
+
// Tab navigation (always available)
|
|
43
|
+
if (key.leftArrow) {
|
|
44
|
+
state.cycleFocus('backward');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (key.rightArrow) {
|
|
48
|
+
state.cycleFocus('forward');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Tab / Shift-Tab cycle tabs globally — but inside Help they're aliased
|
|
52
|
+
// to page navigation by the Help pane itself.
|
|
53
|
+
if (state.focus !== 'help') {
|
|
54
|
+
if (key.tab && key.shift) {
|
|
55
|
+
state.cycleFocus('backward');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (key.tab) {
|
|
59
|
+
state.cycleFocus('forward');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (input === 'q') {
|
|
64
|
+
onQuit();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (input === 'n') {
|
|
68
|
+
state.toggleSessionNotifications();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// ── Repos ─────────────────────────────────────────────────────────────
|
|
72
|
+
if (state.focus === 'repos') {
|
|
73
|
+
if (key.upArrow) {
|
|
74
|
+
state.moveSelection('up');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (key.downArrow) {
|
|
78
|
+
state.moveSelection('down');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const selectedKey = state.repoOrder[state.selectedRepoIndex];
|
|
82
|
+
const selectedEntry = selectedKey ? state.repos[selectedKey] : undefined;
|
|
83
|
+
if (input === 'r') {
|
|
84
|
+
if (!selectedKey || !selectedEntry || !runRepoAction)
|
|
85
|
+
return;
|
|
86
|
+
const dispatch = runRepoAction(selectedKey, selectedEntry);
|
|
87
|
+
if (!dispatch)
|
|
88
|
+
return;
|
|
89
|
+
state.setActiveRepoAction({ repoKey: selectedKey, label: dispatch.label });
|
|
90
|
+
withMinHold(dispatch.promise, () => cockpitStore.getState().setActiveRepoAction(null));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (input === 'w') {
|
|
94
|
+
if (selectedKey && selectedEntry && selectedEntry.kind === 'repo' && onWatchToggle) {
|
|
95
|
+
onWatchToggle(selectedKey, selectedEntry);
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (input === 'l') {
|
|
100
|
+
if (selectedKey && selectedEntry && selectedEntry.kind === 'repo' && onLint) {
|
|
101
|
+
onLint(selectedKey, selectedEntry);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// ── Output ────────────────────────────────────────────────────────────
|
|
107
|
+
if (state.focus === 'output') {
|
|
108
|
+
if (input === 'c') {
|
|
109
|
+
state.clearOutput();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (input === '/') {
|
|
113
|
+
state.setActiveModal('search');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (input === 'f') {
|
|
117
|
+
state.setActiveModal('filter');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (input === 'e' && onOpenError) {
|
|
121
|
+
const target = state.recentErrors.find((er) => er.file && typeof er.line === 'number');
|
|
122
|
+
if (target?.file && typeof target.line === 'number') {
|
|
123
|
+
onOpenError({
|
|
124
|
+
file: target.file,
|
|
125
|
+
line: target.line,
|
|
126
|
+
service: target.service,
|
|
127
|
+
text: target.text,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
onOpenError(null);
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ── Health ────────────────────────────────────────────────────────────
|
|
137
|
+
if (state.focus === 'health') {
|
|
138
|
+
if (key.upArrow) {
|
|
139
|
+
state.moveHealthSelection('up');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (key.downArrow) {
|
|
143
|
+
state.moveHealthSelection('down');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (key.return) {
|
|
147
|
+
const selectedCheck = state.health[state.selectedHealthIndex];
|
|
148
|
+
if (selectedCheck) {
|
|
149
|
+
state.toggleHealthExpand(selectedCheck.id);
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Any single letter is treated as a potential remediation key.
|
|
154
|
+
// The input is uppercased so users can press the key without Shift —
|
|
155
|
+
// a remediation declared with `key: 'R'` matches both `r` and `R`.
|
|
156
|
+
const upperInput = input.toUpperCase();
|
|
157
|
+
if (runRemediation &&
|
|
158
|
+
upperInput.length === 1 &&
|
|
159
|
+
upperInput >= 'A' &&
|
|
160
|
+
upperInput <= 'Z') {
|
|
161
|
+
const dispatch = runRemediation(upperInput);
|
|
162
|
+
if (!dispatch)
|
|
163
|
+
return;
|
|
164
|
+
state.setActiveRemediation({
|
|
165
|
+
healthId: dispatch.healthId,
|
|
166
|
+
healthLabel: dispatch.healthLabel,
|
|
167
|
+
});
|
|
168
|
+
withMinHold(dispatch.promise, () => cockpitStore.getState().setActiveRemediation(null));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterModal.d.ts","sourceRoot":"","sources":["../../../src/cockpit/panes/FilterModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAMxC,wBAAgB,WAAW,IAAI,KAAK,CAAC,YAAY,CAuChD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import { cockpitStore } from '../state/store.js';
|
|
5
|
+
import { useCockpitStore } from '../hooks/useCockpitStore.js';
|
|
6
|
+
export function FilterModal() {
|
|
7
|
+
const outputFilter = useCockpitStore((s) => s.outputFilter);
|
|
8
|
+
const [severityDraft, setSeverityDraft] = useState(outputFilter.severity);
|
|
9
|
+
const SEVERITIES = [undefined, 'info', 'warn', 'error'];
|
|
10
|
+
useInput((input, key) => {
|
|
11
|
+
if (input === 's') {
|
|
12
|
+
const idx = SEVERITIES.indexOf(severityDraft);
|
|
13
|
+
const next = SEVERITIES[(idx + 1) % SEVERITIES.length];
|
|
14
|
+
setSeverityDraft(next);
|
|
15
|
+
}
|
|
16
|
+
if (key.return || key.escape) {
|
|
17
|
+
cockpitStore.getState().setFilter({ ...outputFilter, severity: severityDraft });
|
|
18
|
+
cockpitStore.getState().setActiveModal(null);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return (_jsx(Box, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsx(Text, { bold: true, children: " Filter Output " }), _jsx(Text, { children: " " }), _jsxs(Box, { children: [_jsx(Text, { children: "Severity (s to cycle): " }), _jsx(Text, { color: "cyan", children: severityDraft ?? 'all' })] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Enter = apply \u00B7 Esc = cancel" })] }) }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health pane — renders health checks with severity-colored glyphs, labels,
|
|
3
|
+
* and remediation keys.
|
|
4
|
+
*
|
|
5
|
+
* In-flight remediation feedback: when activeRemediation is set, a banner
|
|
6
|
+
* appears at the top and the running check's row shows "…" + "(running…)"
|
|
7
|
+
* inline. Subprocess output streams to the Output tab.
|
|
8
|
+
*
|
|
9
|
+
* Severity glyphs: ok = ✓ (green), warn = ⚠ (yellow), error = ✗ (red).
|
|
10
|
+
*/
|
|
11
|
+
import React from 'react';
|
|
12
|
+
export declare function Health(): React.ReactElement;
|
|
13
|
+
//# sourceMappingURL=Health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Health.d.ts","sourceRoot":"","sources":["../../../src/cockpit/panes/Health.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,wBAAgB,MAAM,IAAI,KAAK,CAAC,YAAY,CAgE3C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { useCockpitStore } from '../hooks/useCockpitStore.js';
|
|
4
|
+
const SEVERITY_GLYPH = { ok: '✓', warn: '⚠', error: '✗' };
|
|
5
|
+
const SEVERITY_COLOR = {
|
|
6
|
+
ok: 'green',
|
|
7
|
+
warn: 'yellow',
|
|
8
|
+
error: 'red',
|
|
9
|
+
};
|
|
10
|
+
export function Health() {
|
|
11
|
+
const health = useCockpitStore((s) => s.health);
|
|
12
|
+
const selectedHealthIndex = useCockpitStore((s) => s.selectedHealthIndex);
|
|
13
|
+
const expandedHealthId = useCockpitStore((s) => s.expandedHealthId);
|
|
14
|
+
const focus = useCockpitStore((s) => s.focus);
|
|
15
|
+
const notificationsEnabledSession = useCockpitStore((s) => s.notificationsEnabledSession);
|
|
16
|
+
const activeRemediation = useCockpitStore((s) => s.activeRemediation);
|
|
17
|
+
const isFocused = focus === 'health';
|
|
18
|
+
if (health.length === 0) {
|
|
19
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { dimColor: true, children: "running health checks\u2026" }) }));
|
|
20
|
+
}
|
|
21
|
+
return (_jsxs(Box, { flexDirection: "column", children: [activeRemediation && (_jsx(Box, { marginBottom: 1, paddingX: 1, children: _jsxs(Text, { color: "yellow", children: ['… ', activeRemediation.healthLabel, ' running — switch to Output (←) to watch'] }) })), health.map((item, idx) => {
|
|
22
|
+
const isSelected = isFocused && idx === selectedHealthIndex;
|
|
23
|
+
const isExpanded = expandedHealthId === item.id;
|
|
24
|
+
const isRunning = activeRemediation?.healthId === item.id;
|
|
25
|
+
const glyph = isRunning ? '…' : (SEVERITY_GLYPH[item.severity] ?? '?');
|
|
26
|
+
const color = isRunning ? 'yellow' : (SEVERITY_COLOR[item.severity] ?? 'white');
|
|
27
|
+
const remKey = item.remediationKey ? ` [${item.remediationKey}]` : '';
|
|
28
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: isSelected ? 'cyan' : undefined, children: isSelected ? '▶ ' : ' ' }), _jsxs(Text, { color: color, children: [glyph, " "] }), _jsx(Text, { bold: isSelected, children: item.label }), _jsx(Text, { dimColor: true, children: remKey }), isRunning && _jsx(Text, { color: "yellow", children: ' (running…)' })] }), isExpanded && (_jsx(Box, { paddingLeft: 4, children: _jsx(Text, { dimColor: true, children: item.detail }) }))] }, item.id));
|
|
29
|
+
}), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ['notifications: ', _jsx(Text, { color: notificationsEnabledSession ? 'green' : 'yellow', children: notificationsEnabledSession ? 'on' : 'off (session)' })] }) })] }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Help pane — reads pages merged via loader.ts (core docs + profile sources)
|
|
3
|
+
* and renders the active page through marked-terminal.
|
|
4
|
+
*
|
|
5
|
+
* Per-tab keys:
|
|
6
|
+
* ↑/↓ scroll body up/down
|
|
7
|
+
* j / k previous / next page
|
|
8
|
+
* shift+tab / tab same as j / k (alias for non-vim users; the global
|
|
9
|
+
* tab-cycle handler suspends on Help)
|
|
10
|
+
* g / G jump to top / bottom of body
|
|
11
|
+
*/
|
|
12
|
+
import React from 'react';
|
|
13
|
+
export declare function Help(): React.ReactElement;
|
|
14
|
+
//# sourceMappingURL=Help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Help.d.ts","sourceRoot":"","sources":["../../../src/cockpit/panes/Help.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAA+C,MAAM,OAAO,CAAC;AAQpE,wBAAgB,IAAI,IAAI,KAAK,CAAC,YAAY,CAkGzC"}
|