@gaia-ai/addon-gaia-ui 0.11.2 → 0.11.4
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/src/Component/top-tabs/index.d.ts +18 -1
- package/dist/src/Component/top-tabs/index.js +15 -2
- package/dist/src/Entity/conductor/Data/conductors.d.ts +174 -15
- package/dist/src/Entity/conductor/Data/conductors.js +74 -16
- package/dist/src/Entity/conductor/Data/own-conductor.js +17 -3
- package/dist/src/Entity/conductor/Data/process.d.ts +29 -2
- package/dist/src/Entity/conductor/Data/process.js +40 -4
- package/dist/src/Entity/conductor/Screen/conductors.d.ts +43 -0
- package/dist/src/Entity/conductor/Screen/conductors.js +113 -32
- package/dist/src/Entity/conductor/Screen/project-conductors.d.ts +87 -0
- package/dist/src/Entity/conductor/Screen/project-conductors.js +245 -0
- package/dist/src/Entity/project/Data/projects.d.ts +7 -5
- package/dist/src/Entity/project/Data/projects.js +8 -6
- package/dist/src/Kernel/splash.d.ts +8 -0
- package/dist/src/Kernel/splash.js +11 -1
- package/dist/src/Routing/routes.js +2 -0
- package/package.json +2 -2
- package/dist/src/Agent/Component/agent-list/index.d.ts +0 -6
- package/dist/src/Agent/Component/agent-list/index.js +0 -14
- package/dist/src/Component/agent-list/index.d.ts +0 -6
- package/dist/src/Component/agent-list/index.js +0 -14
- package/dist/src/Component/comment-item/index.d.ts +0 -21
- package/dist/src/Component/comment-item/index.js +0 -39
- package/dist/src/Component/create-form/index.d.ts +0 -3
- package/dist/src/Component/create-form/index.js +0 -26
- package/dist/src/Component/dashboard-list/index.d.ts +0 -8
- package/dist/src/Component/dashboard-list/index.js +0 -7
- package/dist/src/Component/project-picker/index.d.ts +0 -15
- package/dist/src/Component/project-picker/index.js +0 -42
- package/dist/src/Component/run-table/index.d.ts +0 -10
- package/dist/src/Component/run-table/index.js +0 -20
- package/dist/src/Component/tab-bar/index.d.ts +0 -20
- package/dist/src/Component/tab-bar/index.js +0 -42
- package/dist/src/Component/ticket-detail/index.d.ts +0 -38
- package/dist/src/Component/ticket-detail/index.js +0 -193
- package/dist/src/Component/ticket-table/index.d.ts +0 -5
- package/dist/src/Component/ticket-table/index.js +0 -14
- package/dist/src/Component/ticket-teaser/index.d.ts +0 -7
- package/dist/src/Component/ticket-teaser/index.js +0 -76
- package/dist/src/Deriver/liveness.d.ts +0 -12
- package/dist/src/Deriver/liveness.js +0 -34
- package/dist/src/Deriver/run-status.d.ts +0 -12
- package/dist/src/Deriver/run-status.js +0 -36
- package/dist/src/Entity/conductor/Component/conductor-list/index.d.ts +0 -25
- package/dist/src/Entity/conductor/Component/conductor-list/index.js +0 -60
- package/dist/src/Entity/project/Component/dashboard-list/index.d.ts +0 -8
- package/dist/src/Entity/project/Component/dashboard-list/index.js +0 -7
- package/dist/src/Entity/project/Component/project-list/index.d.ts +0 -8
- package/dist/src/Entity/project/Component/project-list/index.js +0 -7
- package/dist/src/Entity/project/Component/project-picker/index.d.ts +0 -15
- package/dist/src/Entity/project/Component/project-picker/index.js +0 -42
- package/dist/src/Entity/run/Component/run-table/index.d.ts +0 -8
- package/dist/src/Entity/run/Component/run-table/index.js +0 -11
- package/dist/src/Entity/ticket/Component/tab-bar/index.d.ts +0 -20
- package/dist/src/Entity/ticket/Component/tab-bar/index.js +0 -71
- package/dist/src/Entity/ticket/Component/ticket-table/index.d.ts +0 -7
- package/dist/src/Entity/ticket/Component/ticket-table/index.js +0 -10
- package/dist/src/Entity/user/Screen/users.d.ts +0 -39
- package/dist/src/Entity/user/Screen/users.js +0 -136
- package/dist/src/Screen/dashboard.d.ts +0 -1
- package/dist/src/Screen/dashboard.js +0 -1
- package/dist/src/Screen/project.d.ts +0 -1
- package/dist/src/Screen/project.js +0 -1
- package/dist/src/Screen/projects.d.ts +0 -1
- package/dist/src/Screen/projects.js +0 -1
- package/dist/src/Screen/ticket.d.ts +0 -1
- package/dist/src/Screen/ticket.js +0 -1
- package/dist/src/Service/agent.d.ts +0 -17
- package/dist/src/Service/agent.js +0 -28
- package/dist/src/Service/create-form-data.d.ts +0 -10
- package/dist/src/Service/create-form-data.js +0 -52
- package/dist/src/Service/create-form.d.ts +0 -52
- package/dist/src/Service/create-form.js +0 -98
- package/dist/src/Service/project-data.d.ts +0 -48
- package/dist/src/Service/project-data.js +0 -92
- package/dist/src/Service/projects.d.ts +0 -21
- package/dist/src/Service/projects.js +0 -80
- package/dist/src/Service/route.d.ts +0 -11
- package/dist/src/Service/route.js +0 -215
- package/dist/src/Service/run-data.d.ts +0 -35
- package/dist/src/Service/run-data.js +0 -62
- package/dist/src/Service/ticket-data.d.ts +0 -6
- package/dist/src/Service/ticket-data.js +0 -7
- package/dist/src/Tui/controller.d.ts +0 -13
- package/dist/src/Tui/controller.js +0 -1794
- package/dist/src/lib/ansi.d.ts +0 -34
- package/dist/src/lib/ansi.js +0 -97
- package/dist/src/lib/hit-test.d.ts +0 -138
- package/dist/src/lib/hit-test.js +0 -138
- package/dist/src/lib/mouse.d.ts +0 -35
- package/dist/src/lib/mouse.js +0 -89
- package/dist/src/lib/table.d.ts +0 -37
- package/dist/src/lib/table.js +0 -20
- package/dist/src/lib/ticket-query.d.ts +0 -21
- package/dist/src/lib/ticket-query.js +0 -72
|
@@ -92,10 +92,12 @@ export declare const PROJECT_TABLE: {
|
|
|
92
92
|
* A CLOSED VOCABULARY, and deliberately unbounded for that reason — the
|
|
93
93
|
* same shape of argument the run list's STATE gives.
|
|
94
94
|
*
|
|
95
|
-
* `
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
95
|
+
* `ConductorLiveness` is `online | stale | offline` (GAIA-450 D11 renamed
|
|
96
|
+
* the fresh state from `running`; the `registry-only` fourth state went
|
|
97
|
+
* with the local registry), whose longest member is 7 characters, so the
|
|
98
|
+
* width of 14 this column has always had shows every one of them whole
|
|
99
|
+
* with room to spare. A `max` would be a constant nobody reads and a
|
|
100
|
+
* `grow` would have nothing left to reach.
|
|
99
101
|
*/
|
|
100
102
|
readonly key: "status";
|
|
101
103
|
readonly label: "STATUS";
|
|
@@ -133,7 +135,7 @@ export declare const PROJECT_TABLE: {
|
|
|
133
135
|
* `gaia_conductor` entities (read is owner-gated, so this is already scoped to
|
|
134
136
|
* the current user's conductors — no local registry needed), sideload their
|
|
135
137
|
* `project_id`, group by project name, and report each project's liveliest
|
|
136
|
-
* conductor (
|
|
138
|
+
* conductor (online > stale > offline). Everything is a Drupal entity read
|
|
137
139
|
* through `services.client` (AC-5); the screen itself stays a screen/route.
|
|
138
140
|
*/
|
|
139
141
|
export declare function loadProjectRows({ client, nowSeconds, }: {
|
|
@@ -22,7 +22,7 @@ function singleRelId(rel) {
|
|
|
22
22
|
// Most-alive-first ranking so a project with several conductors reports its
|
|
23
23
|
// liveliest one, not whichever the collection happened to return first.
|
|
24
24
|
const STATUS_RANK = {
|
|
25
|
-
|
|
25
|
+
online: 0,
|
|
26
26
|
stale: 1,
|
|
27
27
|
offline: 2,
|
|
28
28
|
'registry-only': 3,
|
|
@@ -101,10 +101,12 @@ export const PROJECT_TABLE = {
|
|
|
101
101
|
* A CLOSED VOCABULARY, and deliberately unbounded for that reason — the
|
|
102
102
|
* same shape of argument the run list's STATE gives.
|
|
103
103
|
*
|
|
104
|
-
* `
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
104
|
+
* `ConductorLiveness` is `online | stale | offline` (GAIA-450 D11 renamed
|
|
105
|
+
* the fresh state from `running`; the `registry-only` fourth state went
|
|
106
|
+
* with the local registry), whose longest member is 7 characters, so the
|
|
107
|
+
* width of 14 this column has always had shows every one of them whole
|
|
108
|
+
* with room to spare. A `max` would be a constant nobody reads and a
|
|
109
|
+
* `grow` would have nothing left to reach.
|
|
108
110
|
*/
|
|
109
111
|
key: 'status',
|
|
110
112
|
label: 'STATUS',
|
|
@@ -144,7 +146,7 @@ export const PROJECT_TABLE = {
|
|
|
144
146
|
* `gaia_conductor` entities (read is owner-gated, so this is already scoped to
|
|
145
147
|
* the current user's conductors — no local registry needed), sideload their
|
|
146
148
|
* `project_id`, group by project name, and report each project's liveliest
|
|
147
|
-
* conductor (
|
|
149
|
+
* conductor (online > stale > offline). Everything is a Drupal entity read
|
|
148
150
|
* through `services.client` (AC-5); the screen itself stays a screen/route.
|
|
149
151
|
*/
|
|
150
152
|
export async function loadProjectRows({ client, nowSeconds, }) {
|
|
@@ -15,6 +15,14 @@ export declare const SPLASH_FRAME_WIDTH: number;
|
|
|
15
15
|
/**
|
|
16
16
|
* Centered BORDER box with an ASCIIFont GAIA mark — modal-like, not a wash.
|
|
17
17
|
* Font is OpenTUI block letters; the terminal typeface is unchanged.
|
|
18
|
+
*
|
|
19
|
+
* `position: 'absolute'` is load-bearing: the splash is mounted into the SAME
|
|
20
|
+
* `shell` that `createRegions` has already filled with `region-chrome`,
|
|
21
|
+
* `region-body` (`flexGrow: 1`) and `region-footer`. A column child would take a
|
|
22
|
+
* SLICE of the terminal beside the body's grow and land off-centre; out of the
|
|
23
|
+
* flow it fills the whole shell (`inset 0`, `100%` × `100%`) and its own
|
|
24
|
+
* `justifyContent`/`alignItems: center` place the frame in the true middle —
|
|
25
|
+
* the same treatment `region-modal` gets (`regions.ts`).
|
|
18
26
|
*/
|
|
19
27
|
export declare const splashTree: () => VNode;
|
|
20
28
|
export type SplashWait = (ms: number) => Promise<void>;
|
|
@@ -21,11 +21,21 @@ export const SPLASH_FRAME_WIDTH = splashMarkSize.width + SPLASH_FRAME_PAD_X * 2
|
|
|
21
21
|
/**
|
|
22
22
|
* Centered BORDER box with an ASCIIFont GAIA mark — modal-like, not a wash.
|
|
23
23
|
* Font is OpenTUI block letters; the terminal typeface is unchanged.
|
|
24
|
+
*
|
|
25
|
+
* `position: 'absolute'` is load-bearing: the splash is mounted into the SAME
|
|
26
|
+
* `shell` that `createRegions` has already filled with `region-chrome`,
|
|
27
|
+
* `region-body` (`flexGrow: 1`) and `region-footer`. A column child would take a
|
|
28
|
+
* SLICE of the terminal beside the body's grow and land off-centre; out of the
|
|
29
|
+
* flow it fills the whole shell (`inset 0`, `100%` × `100%`) and its own
|
|
30
|
+
* `justifyContent`/`alignItems: center` place the frame in the true middle —
|
|
31
|
+
* the same treatment `region-modal` gets (`regions.ts`).
|
|
24
32
|
*/
|
|
25
33
|
export const splashTree = () => h(BoxRenderable, {
|
|
26
34
|
id: 'splash-root',
|
|
35
|
+
position: 'absolute',
|
|
36
|
+
left: 0,
|
|
37
|
+
top: 0,
|
|
27
38
|
flexDirection: 'column',
|
|
28
|
-
flexGrow: 1,
|
|
29
39
|
width: '100%',
|
|
30
40
|
height: '100%',
|
|
31
41
|
justifyContent: 'center',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConductorsScreen } from '../Entity/conductor/Screen/conductors.js';
|
|
2
|
+
import { ProjectConductorsScreen } from '../Entity/conductor/Screen/project-conductors.js';
|
|
2
3
|
import { ProjectPickerScreen } from '../Entity/project/Screen/project-picker.js';
|
|
3
4
|
import { ProjectsScreen } from '../Entity/project/Screen/projects-screen.js';
|
|
4
5
|
import { RunDetailScreen } from '../Entity/run/Screen/run-detail.js';
|
|
@@ -65,6 +66,7 @@ export const routes = defineRoutes([
|
|
|
65
66
|
TicketAgentsScreen,
|
|
66
67
|
WhoFilterScreen,
|
|
67
68
|
RunsScreen,
|
|
69
|
+
ProjectConductorsScreen,
|
|
68
70
|
TicketDetailScreen,
|
|
69
71
|
RunDetailScreen,
|
|
70
72
|
// No instance-wide `UsersScreen` any more: the users LIST is the team
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaia-ai/addon-gaia-ui",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
4
4
|
"description": "GAIA TUI: interactive terminal UI (dashboard, projects, tickets) as a dropsh `tui` renderer plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,6 @@
|
|
|
26
26
|
"drupal-jsonapi-params": "^3.0.1"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@gaia-ai/core": "^0.11.
|
|
29
|
+
"@gaia-ai/core": "^0.11.4"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { HostedAgent } from '../../../types.js';
|
|
2
|
-
/** A fixed-column flat table for the Ticket-Agents screen: header + one line per
|
|
3
|
-
* live agent (its label · the project/group it runs for). One physical row per
|
|
4
|
-
* entry, so the Kernel's `1 + index` selection math holds. The agents are the
|
|
5
|
-
* host's live set (from `list(group)`); a finished agent drops out on refresh. */
|
|
6
|
-
export declare function agentListRows(agents: HostedAgent[]): string[];
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { pad } from '../../../lib/format.js';
|
|
2
|
-
/** A fixed-column flat table for the Ticket-Agents screen: header + one line per
|
|
3
|
-
* live agent (its label · the project/group it runs for). One physical row per
|
|
4
|
-
* entry, so the Kernel's `1 + index` selection math holds. The agents are the
|
|
5
|
-
* host's live set (from `list(group)`); a finished agent drops out on refresh. */
|
|
6
|
-
export function agentListRows(agents) {
|
|
7
|
-
const header = `${pad('AGENT', 32)} PROJECT`;
|
|
8
|
-
if (agents.length === 0)
|
|
9
|
-
return [header, 'No ticket agents.'];
|
|
10
|
-
return [
|
|
11
|
-
header,
|
|
12
|
-
...agents.map((a) => `${pad(a.label || a.id, 32)} ${a.group}`),
|
|
13
|
-
];
|
|
14
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { HostedAgent } from '../../types.js';
|
|
2
|
-
/** A fixed-column flat table for the Ticket-Agents screen: header + one line per
|
|
3
|
-
* live agent (its label · the project/group it runs for). One physical row per
|
|
4
|
-
* entry, so the Kernel's `1 + index` selection math holds. The agents are the
|
|
5
|
-
* host's live set (from `list(group)`); a finished agent drops out on refresh. */
|
|
6
|
-
export declare function agentListRows(agents: HostedAgent[]): string[];
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { pad } from '../../lib/format.js';
|
|
2
|
-
/** A fixed-column flat table for the Ticket-Agents screen: header + one line per
|
|
3
|
-
* live agent (its label · the project/group it runs for). One physical row per
|
|
4
|
-
* entry, so the Kernel's `1 + index` selection math holds. The agents are the
|
|
5
|
-
* host's live set (from `list(group)`); a finished agent drops out on refresh. */
|
|
6
|
-
export function agentListRows(agents) {
|
|
7
|
-
const header = `${pad('AGENT', 32)} PROJECT`;
|
|
8
|
-
if (agents.length === 0)
|
|
9
|
-
return [header, 'No ticket agents.'];
|
|
10
|
-
return [
|
|
11
|
-
header,
|
|
12
|
-
...agents.map((a) => `${pad(a.label || a.id, 32)} ${a.group}`),
|
|
13
|
-
];
|
|
14
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** One collapsible comment entry for the Comments tab. */
|
|
2
|
-
export interface CommentItem {
|
|
3
|
-
type: string;
|
|
4
|
-
author: string;
|
|
5
|
-
created: string | null;
|
|
6
|
-
bodyLines: string[];
|
|
7
|
-
preview: string;
|
|
8
|
-
}
|
|
9
|
-
/** The rendered Comments-tab view. */
|
|
10
|
-
export interface CommentsTabView {
|
|
11
|
-
lines: string[];
|
|
12
|
-
boldRows: Set<number>;
|
|
13
|
-
headerRows: number[];
|
|
14
|
-
selectable: number;
|
|
15
|
-
}
|
|
16
|
-
/** The relative age of a comment's ISO `created`, or '—' when unknown. */
|
|
17
|
-
export declare function relativeCreated(created: string | null | undefined, nowSeconds: number): string;
|
|
18
|
-
export declare function commentsTabView(items: CommentItem[], { expanded, nowSeconds, }?: {
|
|
19
|
-
expanded?: Set<number>;
|
|
20
|
-
nowSeconds?: number;
|
|
21
|
-
}): CommentsTabView;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { humanizeAge } from '../../Deriver/liveness.js';
|
|
2
|
-
/** The relative age of a comment's ISO `created`, or '—' when unknown. */
|
|
3
|
-
export function relativeCreated(created, nowSeconds) {
|
|
4
|
-
const ms = created ? Date.parse(created) : Number.NaN;
|
|
5
|
-
return Number.isNaN(ms)
|
|
6
|
-
? '—'
|
|
7
|
-
: humanizeAge(Math.floor(ms / 1000), nowSeconds);
|
|
8
|
-
}
|
|
9
|
-
// The Comments tab: one collapsible entry per comment. Collapsed = a single
|
|
10
|
-
// caret header row (`▸ type · author · age · preview`); expanded (`▾`) appends
|
|
11
|
-
// the full body, one physical row per body line. `headerRows[i]` is the row
|
|
12
|
-
// index of comment i's header (for selection highlight + scroll).
|
|
13
|
-
export function commentsTabView(items, { expanded = new Set(), nowSeconds = 0, } = {}) {
|
|
14
|
-
if (!items.length) {
|
|
15
|
-
return {
|
|
16
|
-
lines: ['No comments.'],
|
|
17
|
-
boldRows: new Set(),
|
|
18
|
-
headerRows: [],
|
|
19
|
-
selectable: 0,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
const lines = [];
|
|
23
|
-
const boldRows = new Set();
|
|
24
|
-
const headerRows = [];
|
|
25
|
-
items.forEach((item, i) => {
|
|
26
|
-
headerRows.push(lines.length);
|
|
27
|
-
boldRows.add(lines.length);
|
|
28
|
-
const caret = expanded.has(i) ? '▾' : '▸';
|
|
29
|
-
const age = relativeCreated(item.created, nowSeconds);
|
|
30
|
-
const author = item.author || '—';
|
|
31
|
-
lines.push(`${caret} ${item.type} · ${author} · ${age} · ${item.preview}`);
|
|
32
|
-
if (expanded.has(i)) {
|
|
33
|
-
for (const bodyLine of item.bodyLines)
|
|
34
|
-
lines.push(` ${bodyLine}`);
|
|
35
|
-
lines.push('');
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
return { lines, boldRows, headerRows, selectable: items.length };
|
|
39
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const labelOf = (list, id) => list.find((o) => o.id === id)?.label ?? '—';
|
|
2
|
-
/** Render the "New ticket" popup form as plain rows (the kernel frames it). */
|
|
3
|
-
export function createFormLines(s, opts) {
|
|
4
|
-
const mark = (i) => (s.active === i ? '▸ ' : ' ');
|
|
5
|
-
const lines = [];
|
|
6
|
-
lines.push(`${mark(0)}Description:`);
|
|
7
|
-
const body = s.description.length ? s.description.split('\n') : ['<empty>'];
|
|
8
|
-
for (const line of body)
|
|
9
|
-
lines.push(` ${line}`);
|
|
10
|
-
lines.push(`${mark(1)}Assignee: < ${labelOf(opts.users, s.assignee)} >`);
|
|
11
|
-
lines.push(`${mark(2)}Conductor: < ${labelOf(opts.conductors, s.conductor)} >`);
|
|
12
|
-
lines.push(`${mark(3)}Labels:`);
|
|
13
|
-
if (opts.labels.length === 0) {
|
|
14
|
-
lines.push(' (none available)');
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
opts.labels.forEach((o, i) => {
|
|
18
|
-
const box = s.labels.has(o.id) ? '[x]' : '[ ]';
|
|
19
|
-
const cursor = s.active === 3 && s.labelCursor === i ? '›' : ' ';
|
|
20
|
-
lines.push(` ${cursor}${box} ${o.label}`);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
lines.push(`${mark(4)}Workflow: < ${labelOf(opts.workflows, s.workflow)} >`);
|
|
24
|
-
lines.push(`${mark(5)}[ Create ticket ]`);
|
|
25
|
-
return lines;
|
|
26
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/** The minimum shape a dashboard row needs to render. */
|
|
2
|
-
export interface DashboardRowInput {
|
|
3
|
-
project: string;
|
|
4
|
-
derivedStatus: string;
|
|
5
|
-
ageLabel: string;
|
|
6
|
-
}
|
|
7
|
-
/** One line per project: name, derived status, relative age. */
|
|
8
|
-
export declare function dashboardRows(projects: DashboardRowInput[]): string[];
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { pad } from '../../lib/format.js';
|
|
2
|
-
/** One line per project: name, derived status, relative age. */
|
|
3
|
-
export function dashboardRows(projects) {
|
|
4
|
-
if (projects.length === 0)
|
|
5
|
-
return ['No projects.'];
|
|
6
|
-
return projects.map((p) => `${pad(p.project, 24)} ${pad(p.derivedStatus, 14)} ${p.ageLabel}`);
|
|
7
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/** A project that claims the repo. */
|
|
2
|
-
export interface PickerCandidate {
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* The picker screen's rows: a heading naming the repo, then one row per
|
|
8
|
-
* candidate with `▸` on the selected one.
|
|
9
|
-
*/
|
|
10
|
-
export declare function projectPickerRows(candidates: PickerCandidate[], repo: string, selected: number): string[];
|
|
11
|
-
/**
|
|
12
|
-
* The non-TTY form (spec Decision 11): the candidate list plus the direct
|
|
13
|
-
* command, printed once so `gaia ui --here | cat` stays scriptable — no prompt.
|
|
14
|
-
*/
|
|
15
|
-
export declare function projectPickerHint(candidates: PickerCandidate[], repo: string): string;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// GAIA-223 AC-8 (spec Decision 14) — the picker `gaia ui --here` shows when the
|
|
2
|
-
// cwd's repo is claimed by MORE THAN ONE gaia project.
|
|
3
|
-
//
|
|
4
|
-
// One repo mapping to several projects is designed for, not an edge case:
|
|
5
|
-
// GAIA-126/137 let `.gaia/` hold one conductor config per project, which is how
|
|
6
|
-
// a Drupal multisite repo maps each site to its own GAIA project. Erroring on
|
|
7
|
-
// N>1 would fail permanently, by design, in exactly the repos the feature is
|
|
8
|
-
// most useful in — so the ambiguity is shown rather than resolved behind the
|
|
9
|
-
// user's back.
|
|
10
|
-
//
|
|
11
|
-
// Pure, like every other Component: candidates in, rows out. The kernel owns
|
|
12
|
-
// selection state, Enter and Esc.
|
|
13
|
-
/** Clamp a selection index into the candidate range (0 when there are none). */
|
|
14
|
-
function clamp(selected, length) {
|
|
15
|
-
if (length <= 0)
|
|
16
|
-
return 0;
|
|
17
|
-
return Math.max(0, Math.min(Math.trunc(selected), length - 1));
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* The picker screen's rows: a heading naming the repo, then one row per
|
|
21
|
-
* candidate with `▸` on the selected one.
|
|
22
|
-
*/
|
|
23
|
-
export function projectPickerRows(candidates, repo, selected) {
|
|
24
|
-
const heading = [`Several gaia projects claim ${repo} — which one?`, ''];
|
|
25
|
-
if (candidates.length === 0) {
|
|
26
|
-
return [...heading, 'No projects.'];
|
|
27
|
-
}
|
|
28
|
-
const index = clamp(selected, candidates.length);
|
|
29
|
-
return [
|
|
30
|
-
...heading,
|
|
31
|
-
...candidates.map((c, i) => `${i === index ? '▸' : ' '} ${c.name}`),
|
|
32
|
-
];
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* The non-TTY form (spec Decision 11): the candidate list plus the direct
|
|
36
|
-
* command, printed once so `gaia ui --here | cat` stays scriptable — no prompt.
|
|
37
|
-
*/
|
|
38
|
-
export function projectPickerHint(candidates, repo) {
|
|
39
|
-
const names = candidates.map((c) => ` ${c.name}`).join('\n');
|
|
40
|
-
return (`Several gaia projects claim ${repo}:\n${names}\n` +
|
|
41
|
-
"Open one directly with 'gaia ui project:<name>'.");
|
|
42
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { RunRow } from '../../Service/run-data.js';
|
|
2
|
-
/**
|
|
3
|
-
* A fixed-column flat table of a project's runs: header + one line per run.
|
|
4
|
-
* Columns RUN · TICKET · STATE · PHASE · AGENT · STARTED, mirroring
|
|
5
|
-
* `ticketTableRows` (1 logical entry = 1 physical row). STATE is the derived
|
|
6
|
-
* liveness status and STARTED is the relative start age.
|
|
7
|
-
*/
|
|
8
|
-
export declare function runTableRows(runs: RunRow[], nowSeconds: number, { emptyMessage }?: {
|
|
9
|
-
emptyMessage?: string | undefined;
|
|
10
|
-
}): string[];
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { deriveRunStatus, runStartedAge } from '../../Deriver/run-status.js';
|
|
2
|
-
import { pad } from '../../lib/format.js';
|
|
3
|
-
/**
|
|
4
|
-
* A fixed-column flat table of a project's runs: header + one line per run.
|
|
5
|
-
* Columns RUN · TICKET · STATE · PHASE · AGENT · STARTED, mirroring
|
|
6
|
-
* `ticketTableRows` (1 logical entry = 1 physical row). STATE is the derived
|
|
7
|
-
* liveness status and STARTED is the relative start age.
|
|
8
|
-
*/
|
|
9
|
-
export function runTableRows(runs, nowSeconds, { emptyMessage } = {}) {
|
|
10
|
-
const header = `${pad('RUN', 8)} ${pad('TICKET', 10)} ${pad('STATE', 8)} ${pad('PHASE', 10)} ${pad('AGENT', 8)} STARTED`;
|
|
11
|
-
if (runs.length === 0)
|
|
12
|
-
return [header, emptyMessage ?? 'No runs for this project.'];
|
|
13
|
-
return [
|
|
14
|
-
header,
|
|
15
|
-
...runs.map((r) => {
|
|
16
|
-
const run = `#${r.drupalId ?? r.id.slice(0, 6)}`;
|
|
17
|
-
return `${pad(run, 8)} ${pad(r.ticketIdentifier, 10)} ${pad(deriveRunStatus(r, nowSeconds), 8)} ${pad(r.phase, 10)} ${pad(r.agent, 8)} ${runStartedAge(r, nowSeconds)}`;
|
|
18
|
-
}),
|
|
19
|
-
];
|
|
20
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/** One ticket-detail tab: its id, label, and the section headings it groups. */
|
|
2
|
-
export interface DetailTab {
|
|
3
|
-
id: string;
|
|
4
|
-
label: string;
|
|
5
|
-
headings: string[];
|
|
6
|
-
}
|
|
7
|
-
export declare const DETAIL_TABS: DetailTab[];
|
|
8
|
-
/** The tab bar as a single row; the active tab is bracketed. */
|
|
9
|
-
export declare function tabBar(activeIndex: number): string;
|
|
10
|
-
/** Where one detail tab sits inside the bar: `[start, end)` in display columns
|
|
11
|
-
* from the bar's own first column. */
|
|
12
|
-
export interface DetailTabSpan {
|
|
13
|
-
index: number;
|
|
14
|
-
start: number;
|
|
15
|
-
end: number;
|
|
16
|
-
}
|
|
17
|
-
/** The bar's own hit map, built from the SAME `segment`/`SEPARATOR` the rendered
|
|
18
|
-
* bar is joined from — see `Component/top-tabs/index.ts`'s `topTabSpans` for the
|
|
19
|
-
* full argument. */
|
|
20
|
-
export declare function detailTabSpans(activeIndex: number): DetailTabSpan[];
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { displayWidth } from '../../lib/width.js';
|
|
2
|
-
// The ticket-detail screen is split into tabs so only one tab's content draws at
|
|
3
|
-
// a time (keeps the fixed-height window small) — Sub-tickets + Referenced share a
|
|
4
|
-
// Related tab, Comments is its own tab with collapsible entries (owned by the
|
|
5
|
-
// plugin's draw loop, which needs the interactive expand state).
|
|
6
|
-
export const DETAIL_TABS = [
|
|
7
|
-
{
|
|
8
|
-
id: 'overview',
|
|
9
|
-
label: 'Overview',
|
|
10
|
-
headings: ['Description', 'Branch', 'Links', 'Environments'],
|
|
11
|
-
},
|
|
12
|
-
{ id: 'comments', label: 'Comments', headings: [] },
|
|
13
|
-
{
|
|
14
|
-
id: 'related',
|
|
15
|
-
label: 'Related',
|
|
16
|
-
headings: ['Sub-tickets', 'Referenced tickets'],
|
|
17
|
-
},
|
|
18
|
-
{ id: 'runs', label: 'Runs', headings: ['Runs'] },
|
|
19
|
-
];
|
|
20
|
-
/** What joins two tabs in the rendered bar — part of neither tab's span. */
|
|
21
|
-
const SEPARATOR = ' ';
|
|
22
|
-
/** One tab's rendered segment: bracketed when active, space-padded otherwise. */
|
|
23
|
-
const segment = (tab, index, activeIndex) => index === activeIndex ? `[${tab.label}]` : ` ${tab.label} `;
|
|
24
|
-
/** The tab bar as a single row; the active tab is bracketed. */
|
|
25
|
-
export function tabBar(activeIndex) {
|
|
26
|
-
return DETAIL_TABS.map((t, i) => segment(t, i, activeIndex)).join(SEPARATOR);
|
|
27
|
-
}
|
|
28
|
-
/** The bar's own hit map, built from the SAME `segment`/`SEPARATOR` the rendered
|
|
29
|
-
* bar is joined from — see `Component/top-tabs/index.ts`'s `topTabSpans` for the
|
|
30
|
-
* full argument. */
|
|
31
|
-
export function detailTabSpans(activeIndex) {
|
|
32
|
-
const spans = [];
|
|
33
|
-
let start = 0;
|
|
34
|
-
DETAIL_TABS.forEach((tab, index) => {
|
|
35
|
-
if (index > 0)
|
|
36
|
-
start += displayWidth(SEPARATOR);
|
|
37
|
-
const width = displayWidth(segment(tab, index, activeIndex));
|
|
38
|
-
spans.push({ index, start, end: start + width });
|
|
39
|
-
start += width;
|
|
40
|
-
});
|
|
41
|
-
return spans;
|
|
42
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { TicketDetailDocument } from '../../types.js';
|
|
2
|
-
import type { CommentItem } from '../comment-item/index.js';
|
|
3
|
-
import type { Section } from '../section-list/index.js';
|
|
4
|
-
/**
|
|
5
|
-
* The `expandedComments` set a freshly opened ticket detail starts with: the
|
|
6
|
-
* newest comment expanded, every older one collapsed.
|
|
7
|
-
*
|
|
8
|
-
* It lives beside the sort on purpose — "index 0 is the newest" is one module's
|
|
9
|
-
* invariant, so the kernel never needs to know which index that is.
|
|
10
|
-
*/
|
|
11
|
-
export declare function initialExpandedComments(document: TicketDetailDocument): Set<number>;
|
|
12
|
-
/**
|
|
13
|
-
* The ticket detail sections, each with an explicit empty state:
|
|
14
|
-
* Description, Comments, Sub-tickets, Runs, Referenced tickets, Links,
|
|
15
|
-
* Branch, Environments.
|
|
16
|
-
*/
|
|
17
|
-
export declare function detailSections(document: TicketDetailDocument): Section[];
|
|
18
|
-
/** The detailSections that belong to a given (non-comments) tab, in tab order. */
|
|
19
|
-
export declare function sectionsForTab(document: TicketDetailDocument, tabIndex: number): Section[];
|
|
20
|
-
/**
|
|
21
|
-
* One item per comment for the collapsible Comments tab: type, author, created
|
|
22
|
-
* (raw ISO — the plugin formats the relative age), the body split into physical
|
|
23
|
-
* lines, and a first-line preview for the collapsed header.
|
|
24
|
-
*/
|
|
25
|
-
export declare function commentItems(document: TicketDetailDocument): CommentItem[];
|
|
26
|
-
export declare function detailLines(detail?: TicketDetailDocument | null): {
|
|
27
|
-
lines: string[];
|
|
28
|
-
boldRows: Set<number>;
|
|
29
|
-
};
|
|
30
|
-
export declare function tabViewLines(detail: TicketDetailDocument | null | undefined, tabIndex: number, { expanded, nowSeconds, }?: {
|
|
31
|
-
expanded?: Set<number>;
|
|
32
|
-
nowSeconds?: number;
|
|
33
|
-
}): {
|
|
34
|
-
lines: string[];
|
|
35
|
-
boldRows: Set<number>;
|
|
36
|
-
headerRows: number[];
|
|
37
|
-
selectable: number;
|
|
38
|
-
};
|