@gaia-ai/addon-gaia-ui 0.7.0 → 0.9.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/dist/src/Agent/launch.d.ts +4 -4
- package/dist/src/Agent/launch.js +14 -7
- package/dist/src/Component/section-list/index.d.ts +117 -8
- package/dist/src/Component/section-list/index.js +118 -46
- package/dist/src/Component/stats-panel/index.d.ts +17 -5
- package/dist/src/Component/stats-panel/index.js +50 -52
- package/dist/src/Component/top-tabs/index.d.ts +95 -23
- package/dist/src/Component/top-tabs/index.js +87 -41
- package/dist/src/Entity/collection.d.ts +279 -0
- package/dist/src/Entity/collection.js +377 -0
- package/dist/src/Entity/conductor/Component/conductor-list/index.d.ts +25 -0
- package/dist/src/Entity/conductor/Component/conductor-list/index.js +60 -0
- package/dist/src/Entity/conductor/Data/conductors.d.ts +216 -0
- package/dist/src/Entity/conductor/Data/conductors.js +280 -0
- package/dist/src/Entity/conductor/Data/liveness.d.ts +2 -1
- package/dist/src/Entity/conductor/Data/liveness.js +12 -16
- package/dist/src/Entity/conductor/Data/log-tail.d.ts +25 -0
- package/dist/src/Entity/conductor/Data/log-tail.js +133 -0
- package/dist/src/Entity/conductor/Data/own-conductor.d.ts +30 -0
- package/dist/src/Entity/conductor/Data/own-conductor.js +73 -0
- package/dist/src/Entity/conductor/Data/process.d.ts +78 -0
- package/dist/src/Entity/conductor/Data/process.js +101 -0
- package/dist/src/Entity/conductor/Screen/conductors.d.ts +67 -0
- package/dist/src/Entity/conductor/Screen/conductors.js +233 -0
- package/dist/src/Entity/cycle.d.ts +18 -0
- package/dist/src/Entity/cycle.js +30 -0
- package/dist/src/Entity/project/Data/project.d.ts +8 -0
- package/dist/src/Entity/project/Data/project.js +12 -0
- package/dist/src/Entity/project/Data/projects.d.ts +121 -0
- package/dist/src/Entity/project/Data/projects.js +115 -0
- package/dist/src/Entity/project/Data/with-tickets.d.ts +5 -0
- package/dist/src/Entity/project/Data/with-tickets.js +15 -13
- package/dist/src/Entity/project/Screen/project-picker.d.ts +80 -0
- package/dist/src/Entity/project/Screen/project-picker.js +191 -0
- package/dist/src/Entity/project/Screen/projects-screen.d.ts +52 -0
- package/dist/src/Entity/project/Screen/projects-screen.js +122 -0
- package/dist/src/Entity/run/Component/run-detail/index.d.ts +26 -10
- package/dist/src/Entity/run/Component/run-detail/index.js +147 -39
- package/dist/src/Entity/run/Component/run-table/index.d.ts +5 -7
- package/dist/src/Entity/run/Component/run-table/index.js +9 -18
- package/dist/src/Entity/run/Data/query.d.ts +22 -0
- package/dist/src/Entity/run/Data/query.js +41 -0
- package/dist/src/Entity/run/Data/runs.d.ts +192 -4
- package/dist/src/Entity/run/Data/runs.js +188 -27
- package/dist/src/Entity/run/Screen/run-detail.d.ts +53 -0
- package/dist/src/Entity/run/Screen/run-detail.js +70 -0
- package/dist/src/Entity/run/Screen/runs.d.ts +86 -0
- package/dist/src/Entity/run/Screen/runs.js +169 -0
- package/dist/src/Entity/statistics/Screen/dashboard.d.ts +78 -0
- package/dist/src/Entity/statistics/Screen/dashboard.js +228 -0
- package/dist/src/Entity/ticket/Component/comment-item/index.d.ts +12 -9
- package/dist/src/Entity/ticket/Component/comment-item/index.js +18 -13
- package/dist/src/Entity/ticket/Component/create-form/index.d.ts +16 -3
- package/dist/src/Entity/ticket/Component/create-form/index.js +28 -14
- package/dist/src/Entity/ticket/Component/edit-form/index.d.ts +11 -6
- package/dist/src/Entity/ticket/Component/edit-form/index.js +77 -29
- package/dist/src/Entity/ticket/Component/sections/index.d.ts +8 -0
- package/dist/src/Entity/ticket/Component/sections/index.js +42 -0
- package/dist/src/Entity/ticket/Component/tab-bar/index.js +6 -0
- package/dist/src/Entity/ticket/Component/ticket-detail/index.d.ts +65 -8
- package/dist/src/Entity/ticket/Component/ticket-detail/index.js +171 -84
- package/dist/src/Entity/ticket/Component/ticket-table/index.d.ts +4 -2
- package/dist/src/Entity/ticket/Component/ticket-table/index.js +8 -12
- package/dist/src/Entity/ticket/Component/ticket-teaser/index.d.ts +47 -3
- package/dist/src/Entity/ticket/Component/ticket-teaser/index.js +76 -22
- package/dist/src/Entity/ticket/Data/parents.d.ts +13 -1
- package/dist/src/Entity/ticket/Data/parents.js +64 -12
- package/dist/src/Entity/ticket/Data/query.d.ts +44 -7
- package/dist/src/Entity/ticket/Data/query.js +60 -26
- package/dist/src/Entity/ticket/Data/tickets.d.ts +170 -4
- package/dist/src/Entity/ticket/Data/tickets.js +200 -12
- package/dist/src/Entity/ticket/Data/url.d.ts +16 -0
- package/dist/src/Entity/ticket/Data/url.js +20 -0
- package/dist/src/Entity/ticket/Data/workflow.d.ts +1 -5
- package/dist/src/Entity/ticket/Data/workflow.js +5 -13
- package/dist/src/Entity/ticket/Data/write.d.ts +32 -0
- package/dist/src/Entity/ticket/Data/write.js +80 -0
- package/dist/src/Entity/ticket/Form/create-data.d.ts +1 -11
- package/dist/src/Entity/ticket/Form/create-data.js +7 -36
- package/dist/src/Entity/ticket/Form/create.d.ts +45 -5
- package/dist/src/Entity/ticket/Form/create.js +45 -8
- package/dist/src/Entity/ticket/Form/edit-data.d.ts +1 -1
- package/dist/src/Entity/ticket/Form/edit-data.js +4 -0
- package/dist/src/Entity/ticket/Form/edit.d.ts +79 -12
- package/dist/src/Entity/ticket/Form/edit.js +165 -18
- package/dist/src/Entity/ticket/Form/keys.d.ts +7 -0
- package/dist/src/Entity/ticket/Form/keys.js +7 -0
- package/dist/src/Entity/ticket/Form/parent-filter.d.ts +36 -0
- package/dist/src/Entity/ticket/Form/parent-filter.js +37 -0
- package/dist/src/Entity/ticket/Form/parent-source.d.ts +27 -0
- package/dist/src/Entity/ticket/Form/parent-source.js +56 -0
- package/dist/src/Entity/ticket/Form/who-filter.d.ts +33 -0
- package/dist/src/Entity/ticket/Form/who-filter.js +33 -0
- package/dist/src/Entity/ticket/Form/who-source.d.ts +18 -0
- package/dist/src/Entity/ticket/Form/who-source.js +38 -0
- package/dist/src/Entity/ticket/Screen/create-ticket-form.d.ts +81 -0
- package/dist/src/Entity/ticket/Screen/create-ticket-form.js +356 -0
- package/dist/src/Entity/ticket/Screen/edit-assignment-form.d.ts +92 -0
- package/dist/src/Entity/ticket/Screen/edit-assignment-form.js +220 -0
- package/dist/src/Entity/ticket/Screen/parent-filter-form.d.ts +44 -0
- package/dist/src/Entity/ticket/Screen/parent-filter-form.js +200 -0
- package/dist/src/Entity/ticket/Screen/ticket-agents.d.ts +136 -0
- package/dist/src/Entity/ticket/Screen/ticket-agents.js +257 -0
- package/dist/src/Entity/ticket/Screen/ticket-detail.d.ts +125 -0
- package/dist/src/Entity/ticket/Screen/ticket-detail.js +415 -0
- package/dist/src/Entity/ticket/Screen/tickets.d.ts +145 -0
- package/dist/src/Entity/ticket/Screen/tickets.js +538 -0
- package/dist/src/Entity/ticket/Screen/who-filter-form.d.ts +41 -0
- package/dist/src/Entity/ticket/Screen/who-filter-form.js +174 -0
- package/dist/src/Entity/user/Data/users.d.ts +17 -0
- package/dist/src/Entity/user/Data/users.js +66 -6
- package/dist/src/Form/field.d.ts +3 -1
- package/dist/src/Form/field.js +1 -0
- package/dist/src/Form/form.d.ts +1 -1
- package/dist/src/Form/form.js +61 -9
- package/dist/src/Form/keys.d.ts +23 -1
- package/dist/src/Form/keys.js +78 -23
- package/dist/src/Kernel/chrome.d.ts +289 -0
- package/dist/src/Kernel/chrome.js +404 -0
- package/dist/src/Kernel/clipboard.d.ts +30 -0
- package/dist/src/Kernel/clipboard.js +51 -0
- package/dist/src/Kernel/key-input.d.ts +50 -0
- package/dist/src/Kernel/key-input.js +158 -0
- package/dist/src/Kernel/mount.d.ts +187 -0
- package/dist/src/Kernel/mount.js +399 -0
- package/dist/src/Kernel/tui-kernel.d.ts +0 -11
- package/dist/src/Kernel/tui-kernel.js +778 -2367
- package/dist/src/Routing/context.d.ts +31 -0
- package/dist/src/Routing/context.js +52 -0
- package/dist/src/Routing/registry.d.ts +19 -0
- package/dist/src/Routing/registry.js +97 -0
- package/dist/src/Routing/route.d.ts +35 -0
- package/dist/src/Routing/route.js +1 -0
- package/dist/src/Routing/router.d.ts +49 -0
- package/dist/src/Routing/router.js +123 -0
- package/dist/src/Routing/routes.d.ts +17 -0
- package/dist/src/Routing/routes.js +57 -0
- package/dist/src/Screen/async-screen.d.ts +87 -0
- package/dist/src/Screen/async-screen.js +206 -0
- package/dist/src/Screen/list-screen.d.ts +193 -0
- package/dist/src/Screen/list-screen.js +261 -0
- package/dist/src/Screen/screen.d.ts +240 -0
- package/dist/src/Screen/screen.js +34 -0
- package/dist/src/Tui/controller.d.ts +13 -0
- package/dist/src/Tui/controller.js +1794 -0
- package/dist/src/Widget/autocomplete.js +75 -3
- package/dist/src/Widget/index.d.ts +3 -2
- package/dist/src/Widget/index.js +2 -1
- package/dist/src/Widget/option-source.d.ts +12 -1
- package/dist/src/Widget/option-source.js +14 -1
- package/dist/src/Widget/render.d.ts +23 -8
- package/dist/src/Widget/render.js +108 -41
- package/dist/src/Widget/text.js +94 -5
- package/dist/src/Widget/textarea.d.ts +45 -0
- package/dist/src/Widget/textarea.js +115 -0
- package/dist/src/Widget/types.d.ts +64 -1
- package/dist/src/launcher.d.ts +9 -2
- package/dist/src/launcher.js +2 -1
- package/dist/src/lib/ansi.js +13 -5
- package/dist/src/lib/clipboard.d.ts +41 -0
- package/dist/src/lib/clipboard.js +65 -0
- package/dist/src/lib/cursor.d.ts +31 -0
- package/dist/src/lib/cursor.js +45 -0
- package/dist/src/lib/format.d.ts +21 -13
- package/dist/src/lib/format.js +76 -28
- package/dist/src/lib/hyperlink.d.ts +58 -0
- package/dist/src/lib/hyperlink.js +104 -0
- package/dist/src/lib/input-trace.d.ts +48 -0
- package/dist/src/lib/input-trace.js +47 -0
- package/dist/src/lib/key-vocabulary.d.ts +19 -0
- package/dist/src/lib/key-vocabulary.js +25 -0
- package/dist/src/lib/table.d.ts +37 -0
- package/dist/src/lib/table.js +20 -0
- package/dist/src/lib/vnode.d.ts +217 -0
- package/dist/src/lib/vnode.js +456 -0
- package/dist/src/lib/width.d.ts +25 -1
- package/dist/src/lib/width.js +93 -12
- package/dist/src/plugin.js +26 -1
- package/dist/src/types.d.ts +67 -2
- package/dist/src/types.js +0 -4
- package/package.json +4 -2
|
@@ -10,6 +10,9 @@ export declare const ROOT_TABS: readonly [{
|
|
|
10
10
|
}, {
|
|
11
11
|
readonly id: "projects";
|
|
12
12
|
readonly label: "Projects";
|
|
13
|
+
}, {
|
|
14
|
+
readonly id: "conductors";
|
|
15
|
+
readonly label: "Conductors";
|
|
13
16
|
}];
|
|
14
17
|
/** The project level: the tabs of an opened project. */
|
|
15
18
|
export declare const PROJECT_TABS: readonly [{
|
|
@@ -25,6 +28,40 @@ export declare const PROJECT_TABS: readonly [{
|
|
|
25
28
|
readonly id: "runs";
|
|
26
29
|
readonly label: "Runs";
|
|
27
30
|
}];
|
|
31
|
+
/**
|
|
32
|
+
* The ticket level: the sections of ONE OPEN TICKET — GAIA-346.
|
|
33
|
+
*
|
|
34
|
+
* The third level this file's GAIA-239 comment has described since it was
|
|
35
|
+
* written, arriving with the change that needed it. What is new is not the level
|
|
36
|
+
* but where it is DRAWN: that comment reserved it for "the header box's meta row,
|
|
37
|
+
* so no top-level bar at all", and the operator's ruling is the opposite — the
|
|
38
|
+
* sections belong in the bar every other level uses, and the ticket detail keeps
|
|
39
|
+
* no tab row of its own.
|
|
40
|
+
*
|
|
41
|
+
* These entries are NOT destinations. A section is a mode of the one ticket
|
|
42
|
+
* route: switching one runs no `Router.navigate`, so the screen instance, its
|
|
43
|
+
* document and its per-section state are untouched (spec D1/F3). The kernel
|
|
44
|
+
* learns that from the screen, through `Screen.selectTopTab`, and not from a
|
|
45
|
+
* level name — nothing in this file distinguishes a mode from a destination, and
|
|
46
|
+
* nothing should.
|
|
47
|
+
*
|
|
48
|
+
* `runs` is declared here AND on the project level, which GAIA-256 D2 already
|
|
49
|
+
* made legal: ids are not globally unique, every function is level-parameterised,
|
|
50
|
+
* and one bar is on screen at a time.
|
|
51
|
+
*/
|
|
52
|
+
export declare const TICKET_TABS: readonly [{
|
|
53
|
+
readonly id: "overview";
|
|
54
|
+
readonly label: "Overview";
|
|
55
|
+
}, {
|
|
56
|
+
readonly id: "comments";
|
|
57
|
+
readonly label: "Comments";
|
|
58
|
+
}, {
|
|
59
|
+
readonly id: "related";
|
|
60
|
+
readonly label: "Related";
|
|
61
|
+
}, {
|
|
62
|
+
readonly id: "runs";
|
|
63
|
+
readonly label: "Runs";
|
|
64
|
+
}];
|
|
28
65
|
/** The tab bars, keyed by level — the one place a level is named. */
|
|
29
66
|
export declare const TAB_LEVELS: {
|
|
30
67
|
readonly root: readonly [{
|
|
@@ -33,6 +70,9 @@ export declare const TAB_LEVELS: {
|
|
|
33
70
|
}, {
|
|
34
71
|
readonly id: "projects";
|
|
35
72
|
readonly label: "Projects";
|
|
73
|
+
}, {
|
|
74
|
+
readonly id: "conductors";
|
|
75
|
+
readonly label: "Conductors";
|
|
36
76
|
}];
|
|
37
77
|
readonly project: readonly [{
|
|
38
78
|
readonly id: "dashboard";
|
|
@@ -47,6 +87,19 @@ export declare const TAB_LEVELS: {
|
|
|
47
87
|
readonly id: "runs";
|
|
48
88
|
readonly label: "Runs";
|
|
49
89
|
}];
|
|
90
|
+
readonly ticket: readonly [{
|
|
91
|
+
readonly id: "overview";
|
|
92
|
+
readonly label: "Overview";
|
|
93
|
+
}, {
|
|
94
|
+
readonly id: "comments";
|
|
95
|
+
readonly label: "Comments";
|
|
96
|
+
}, {
|
|
97
|
+
readonly id: "related";
|
|
98
|
+
readonly label: "Related";
|
|
99
|
+
}, {
|
|
100
|
+
readonly id: "runs";
|
|
101
|
+
readonly label: "Runs";
|
|
102
|
+
}];
|
|
50
103
|
};
|
|
51
104
|
/** The name of a level that carries a top-level tab bar. */
|
|
52
105
|
export type TabLevel = keyof typeof TAB_LEVELS;
|
|
@@ -71,6 +124,29 @@ export type TabLocation = {
|
|
|
71
124
|
tab: TabIdOf<L>;
|
|
72
125
|
};
|
|
73
126
|
}[TabLevel];
|
|
127
|
+
/**
|
|
128
|
+
* The bar as the PIECES it is drawn from: one part per tab, carrying that tab's
|
|
129
|
+
* id, with the joins between them carrying none.
|
|
130
|
+
*
|
|
131
|
+
* GAIA-340 Task 11 (spec D6) — this replaces `topTabSpans`, which published the
|
|
132
|
+
* same layout as `[start, end)` COLUMN ranges for the kernel to resolve a click
|
|
133
|
+
* against. The bar is a row of renderables now (`Kernel/chrome.ts`), so "which
|
|
134
|
+
* tab is under the pointer" is answered by the renderer's own hit test — the
|
|
135
|
+
* part the pointer landed on IS a node, and its id names its tab. A column map
|
|
136
|
+
* beside that would be a second answer to a question the renderer already
|
|
137
|
+
* answers, and it needed `displayWidth` to build, which is exactly the string
|
|
138
|
+
* measurement this ticket exists to delete (R5/D8).
|
|
139
|
+
*
|
|
140
|
+
* The argument the spans made survives unchanged, and is why the parts are here
|
|
141
|
+
* rather than in the chrome: {@link topTabBar} is these parts JOINED, so the
|
|
142
|
+
* rendered bar and the clickable pieces are two readings of one expression and
|
|
143
|
+
* cannot drift apart.
|
|
144
|
+
*/
|
|
145
|
+
export interface TabBarPart<Id extends string = TopTabId> {
|
|
146
|
+
/** The tab this piece is, or absent for the join between two tabs. */
|
|
147
|
+
readonly tab?: Id;
|
|
148
|
+
readonly text: string;
|
|
149
|
+
}
|
|
74
150
|
/**
|
|
75
151
|
* One level's tab bar as a single row; the active tab is bracketed.
|
|
76
152
|
*
|
|
@@ -78,6 +154,17 @@ export type TabLocation = {
|
|
|
78
154
|
* at compile time now that there is more than one bar. `topTabBar('root', 'runs')`
|
|
79
155
|
* is a TS2345 naming the root level's valid ids — not a bar that silently
|
|
80
156
|
* brackets nothing.
|
|
157
|
+
*
|
|
158
|
+
* NO PRODUCT CALLER SINCE GAIA-340 Task 11, and KEPT — the decision, so it is not
|
|
159
|
+
* re-litigated. The chrome draws the bar as one node per tab (`tabPartsFor`), so
|
|
160
|
+
* the only readers of this and of {@link tabBarFor} are four suites that pin the
|
|
161
|
+
* bar's picture. They are what those pins compare the RENDERED row against, and
|
|
162
|
+
* the alternative is transcribing the bar into each of them as a literal — a
|
|
163
|
+
* hand-copied reference cannot notice a label change, where this one is
|
|
164
|
+
* `renderParts(…).join('')`, i.e. the same expression the chrome's nodes come
|
|
165
|
+
* from. Two readings of one source cannot drift into two answers; a literal and a
|
|
166
|
+
* source can. That is the same argument spec D6 makes for moving an independent
|
|
167
|
+
* reference rather than dropping it, and it costs ten lines and no measurement.
|
|
81
168
|
*/
|
|
82
169
|
export declare function topTabBar<L extends TabLevel>(level: L, activeId: TabIdOf<L>): string;
|
|
83
170
|
/**
|
|
@@ -87,37 +174,22 @@ export declare function topTabBar<L extends TabLevel>(level: L, activeId: TabIdO
|
|
|
87
174
|
* not ask the compiler to correlate two independently narrowed properties.
|
|
88
175
|
*/
|
|
89
176
|
export declare function tabBarFor(location: TabLocation): string;
|
|
90
|
-
/** Where one tab sits inside the bar: `[start, end)` in display columns from the
|
|
91
|
-
* bar's own first column. */
|
|
92
|
-
export interface TopTabSpan<Id extends string = TopTabId> {
|
|
93
|
-
id: Id;
|
|
94
|
-
start: number;
|
|
95
|
-
end: number;
|
|
96
|
-
}
|
|
97
177
|
/**
|
|
98
|
-
* One level's own
|
|
99
|
-
* rendered bar is joined from — so the layout and the click mapping are two
|
|
100
|
-
* readings of one expression and cannot drift apart. That is the argument
|
|
101
|
-
* `lib/hit-test.ts` makes for the body rows, applied to a column axis.
|
|
102
|
-
*
|
|
103
|
-
* Offsets are display columns, which is the unit a mouse report carries. For the
|
|
104
|
-
* current ASCII labels that coincides with string offsets, which is what lets
|
|
105
|
-
* the test slice `topTabBar()` with a span and compare.
|
|
178
|
+
* One level's own bar as its clickable pieces — see {@link TabBarPart}.
|
|
106
179
|
*
|
|
107
180
|
* GAIA-239: the LEVEL is part of the signature, exactly as it is for
|
|
108
181
|
* {@link topTabBar}, and for the same reason twice over. GAIA-241 shipped one
|
|
109
182
|
* `topTabSpans(activeId)` over the single flat bar; read level-blind it would
|
|
110
|
-
* publish the project bar's
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* mis-click.
|
|
183
|
+
* publish the project bar's pieces on the root screen too, so a click where
|
|
184
|
+
* `Ticket-Agents` sits on the other level would open a tab that screen does not
|
|
185
|
+
* draw — the very defect GAIA-239 removed, arriving through the mouse. Pieces
|
|
186
|
+
* and bar of two different levels is a TS2345, not a silent mis-click.
|
|
115
187
|
*/
|
|
116
|
-
export declare function
|
|
188
|
+
export declare function topTabParts<L extends TabLevel>(level: L, activeId: TabIdOf<L>): TabBarPart<TabIdOf<L>>[];
|
|
117
189
|
/**
|
|
118
|
-
* The same
|
|
190
|
+
* The same pieces, for a caller holding a whole {@link TabLocation} — the
|
|
119
191
|
* companion of {@link tabBarFor}, and the pairing it needs was already checked
|
|
120
192
|
* when the location was built. Keeping the two in step is what makes "the bar you
|
|
121
193
|
* see is the bar you click" true by construction: both read `location`.
|
|
122
194
|
*/
|
|
123
|
-
export declare function
|
|
195
|
+
export declare function tabPartsFor(location: TabLocation): TabBarPart[];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { displayWidth } from '../../lib/width.js';
|
|
2
1
|
// GAIA-239: THE registry — the single place the set, the order and the labels of
|
|
3
2
|
// the top-level tabs are written. Navigation has THREE levels, and every screen
|
|
4
3
|
// shows exactly ONE tab bar: the one of its own level.
|
|
@@ -6,9 +5,9 @@ import { displayWidth } from '../../lib/width.js';
|
|
|
6
5
|
// root dashboard, projects, project-picker → Dashboard · Projects
|
|
7
6
|
// project dashboard, project, ticket-agents, → Dashboard · Tickets ·
|
|
8
7
|
// project-runs Ticket-Agents · Runs
|
|
9
|
-
// ticket
|
|
10
|
-
//
|
|
11
|
-
//
|
|
8
|
+
// ticket overview, comments, related, runs → the sections of one open
|
|
9
|
+
// ticket, in the bar row every
|
|
10
|
+
// other level uses (GAIA-346)
|
|
12
11
|
//
|
|
13
12
|
// `tickets` is the project/ticket drill-down; `ticket-agents` is the managed
|
|
14
13
|
// create-agent list (GAIA-190); `runs` is the project-scoped run overview
|
|
@@ -26,15 +25,23 @@ import { displayWidth } from '../../lib/width.js';
|
|
|
26
25
|
// `topTabSpans(level, id)`, `tabBarFor(location)`, `TabIdOf<L>`). It was a
|
|
27
26
|
// property of ONE function, the level-blind `locateTab`, which walked the levels
|
|
28
27
|
// in key order and would now resolve the project level's `dashboard` to the ROOT
|
|
29
|
-
// location.
|
|
28
|
+
// location. Top-tab navigation was its only caller, and it only moves within one
|
|
30
29
|
// level — the bar you Tab through or click IS the current level's bar — so it
|
|
31
30
|
// pairs the target with `here.level` directly and `locateTab` is deleted.
|
|
32
31
|
//
|
|
33
|
-
// Only tabs that are actually navigable are listed. A planned screen (`Users`
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
32
|
+
// Only tabs that are actually navigable are listed. A planned screen (`Users`)
|
|
33
|
+
// arrives with its own ticket and adds its entry here then — a tab drawn before
|
|
34
|
+
// its screen exists would advertise navigation the operator cannot take, which
|
|
35
|
+
// is the very defect GAIA-239 removes.
|
|
36
|
+
//
|
|
37
|
+
// GAIA-232 added `conductors`, and put it on the ROOT level although the note
|
|
38
|
+
// above once reserved it for the project level. A conductor is an operator
|
|
39
|
+
// concern: "is my conductor alive?" has to be answerable without first choosing
|
|
40
|
+
// a project, and one conductor commonly serves work across a checkout rather
|
|
41
|
+
// than sitting inside one project's screen. Which project it serves is a COLUMN
|
|
42
|
+
// of that screen, not a navigation level above it. Being an ordinary entry here
|
|
43
|
+
// is also what keeps it inside the derived id union and gives it GAIA-241's
|
|
44
|
+
// click spans for free.
|
|
38
45
|
//
|
|
39
46
|
// `as const satisfies` is load-bearing on both halves: `satisfies` still
|
|
40
47
|
// shape-checks every entry against `TopTab`, while `as const` keeps the literal
|
|
@@ -45,6 +52,7 @@ import { displayWidth } from '../../lib/width.js';
|
|
|
45
52
|
export const ROOT_TABS = [
|
|
46
53
|
{ id: 'dashboard', label: 'Dashboard' },
|
|
47
54
|
{ id: 'projects', label: 'Projects' },
|
|
55
|
+
{ id: 'conductors', label: 'Conductors' },
|
|
48
56
|
];
|
|
49
57
|
/** The project level: the tabs of an opened project. */
|
|
50
58
|
export const PROJECT_TABS = [
|
|
@@ -53,16 +61,49 @@ export const PROJECT_TABS = [
|
|
|
53
61
|
{ id: 'ticket-agents', label: 'Ticket-Agents' },
|
|
54
62
|
{ id: 'runs', label: 'Runs' },
|
|
55
63
|
];
|
|
64
|
+
/**
|
|
65
|
+
* The ticket level: the sections of ONE OPEN TICKET — GAIA-346.
|
|
66
|
+
*
|
|
67
|
+
* The third level this file's GAIA-239 comment has described since it was
|
|
68
|
+
* written, arriving with the change that needed it. What is new is not the level
|
|
69
|
+
* but where it is DRAWN: that comment reserved it for "the header box's meta row,
|
|
70
|
+
* so no top-level bar at all", and the operator's ruling is the opposite — the
|
|
71
|
+
* sections belong in the bar every other level uses, and the ticket detail keeps
|
|
72
|
+
* no tab row of its own.
|
|
73
|
+
*
|
|
74
|
+
* These entries are NOT destinations. A section is a mode of the one ticket
|
|
75
|
+
* route: switching one runs no `Router.navigate`, so the screen instance, its
|
|
76
|
+
* document and its per-section state are untouched (spec D1/F3). The kernel
|
|
77
|
+
* learns that from the screen, through `Screen.selectTopTab`, and not from a
|
|
78
|
+
* level name — nothing in this file distinguishes a mode from a destination, and
|
|
79
|
+
* nothing should.
|
|
80
|
+
*
|
|
81
|
+
* `runs` is declared here AND on the project level, which GAIA-256 D2 already
|
|
82
|
+
* made legal: ids are not globally unique, every function is level-parameterised,
|
|
83
|
+
* and one bar is on screen at a time.
|
|
84
|
+
*/
|
|
85
|
+
export const TICKET_TABS = [
|
|
86
|
+
{ id: 'overview', label: 'Overview' },
|
|
87
|
+
{ id: 'comments', label: 'Comments' },
|
|
88
|
+
{ id: 'related', label: 'Related' },
|
|
89
|
+
{ id: 'runs', label: 'Runs' },
|
|
90
|
+
];
|
|
56
91
|
/** The tab bars, keyed by level — the one place a level is named. */
|
|
57
92
|
export const TAB_LEVELS = {
|
|
58
93
|
root: ROOT_TABS,
|
|
59
94
|
project: PROJECT_TABS,
|
|
95
|
+
ticket: TICKET_TABS,
|
|
60
96
|
};
|
|
61
97
|
/** What joins two tabs in the rendered bar — part of neither tab's span. */
|
|
62
98
|
const SEPARATOR = ' ';
|
|
63
99
|
/** One tab's rendered segment: bracketed when active, space-padded otherwise. */
|
|
64
100
|
const segment = (tab, activeId) => tab.id === activeId ? `[${tab.label}]` : ` ${tab.label} `;
|
|
65
|
-
const
|
|
101
|
+
const renderParts = (tabs, activeId) => tabs.flatMap((tab, index) => index === 0
|
|
102
|
+
? [{ tab: tab.id, text: segment(tab, activeId) }]
|
|
103
|
+
: [{ text: SEPARATOR }, { tab: tab.id, text: segment(tab, activeId) }]);
|
|
104
|
+
const renderBar = (tabs, activeId) => renderParts(tabs, activeId)
|
|
105
|
+
.map((part) => part.text)
|
|
106
|
+
.join('');
|
|
66
107
|
/**
|
|
67
108
|
* One level's tab bar as a single row; the active tab is bracketed.
|
|
68
109
|
*
|
|
@@ -70,6 +111,17 @@ const renderBar = (tabs, activeId) => tabs.map((t) => segment(t, activeId)).join
|
|
|
70
111
|
* at compile time now that there is more than one bar. `topTabBar('root', 'runs')`
|
|
71
112
|
* is a TS2345 naming the root level's valid ids — not a bar that silently
|
|
72
113
|
* brackets nothing.
|
|
114
|
+
*
|
|
115
|
+
* NO PRODUCT CALLER SINCE GAIA-340 Task 11, and KEPT — the decision, so it is not
|
|
116
|
+
* re-litigated. The chrome draws the bar as one node per tab (`tabPartsFor`), so
|
|
117
|
+
* the only readers of this and of {@link tabBarFor} are four suites that pin the
|
|
118
|
+
* bar's picture. They are what those pins compare the RENDERED row against, and
|
|
119
|
+
* the alternative is transcribing the bar into each of them as a literal — a
|
|
120
|
+
* hand-copied reference cannot notice a label change, where this one is
|
|
121
|
+
* `renderParts(…).join('')`, i.e. the same expression the chrome's nodes come
|
|
122
|
+
* from. Two readings of one source cannot drift into two answers; a literal and a
|
|
123
|
+
* source can. That is the same argument spec D6 makes for moving an independent
|
|
124
|
+
* reference rather than dropping it, and it costs ten lines and no measurement.
|
|
73
125
|
*/
|
|
74
126
|
export function topTabBar(level, activeId) {
|
|
75
127
|
return renderBar(TAB_LEVELS[level], activeId);
|
|
@@ -83,46 +135,40 @@ export function topTabBar(level, activeId) {
|
|
|
83
135
|
export function tabBarFor(location) {
|
|
84
136
|
return renderBar(TAB_LEVELS[location.level], location.tab);
|
|
85
137
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
138
|
+
// GAIA-256 spec D2 — `locateTab` USED TO LIVE HERE and is deliberately gone.
|
|
139
|
+
//
|
|
140
|
+
// It answered "which level declares this tab id" by walking `TAB_LEVELS` in key
|
|
141
|
+
// order, which made it level-blind and made globally-unique ids a requirement of
|
|
142
|
+
// the whole model. Its single caller was top-tab navigation (no test covered it),
|
|
143
|
+
// and that was always the wrong tool there: navigation moves within ONE level,
|
|
144
|
+
// so the level is already in its hand. There are three levels and TWO shared ids
|
|
145
|
+
// now: `root` and `project` both name a `dashboard`, and since GAIA-346 `project`
|
|
146
|
+
// and `ticket` both name a `runs`. A level-blind walk in key order would resolve
|
|
147
|
+
// the project Dashboard to the ROOT location, and the ticket's Runs SECTION to
|
|
148
|
+
// the project's Runs SCREEN — each drawing the wrong bar for a whole load. The
|
|
149
|
+
// kernel pairs the target with `here.level` instead — sound by construction,
|
|
150
|
+
// because the target came from that level's own registry in both callers — and
|
|
151
|
+
// the requirement disappears with the function.
|
|
98
152
|
/**
|
|
99
|
-
* One level's own
|
|
100
|
-
* rendered bar is joined from — so the layout and the click mapping are two
|
|
101
|
-
* readings of one expression and cannot drift apart. That is the argument
|
|
102
|
-
* `lib/hit-test.ts` makes for the body rows, applied to a column axis.
|
|
103
|
-
*
|
|
104
|
-
* Offsets are display columns, which is the unit a mouse report carries. For the
|
|
105
|
-
* current ASCII labels that coincides with string offsets, which is what lets
|
|
106
|
-
* the test slice `topTabBar()` with a span and compare.
|
|
153
|
+
* One level's own bar as its clickable pieces — see {@link TabBarPart}.
|
|
107
154
|
*
|
|
108
155
|
* GAIA-239: the LEVEL is part of the signature, exactly as it is for
|
|
109
156
|
* {@link topTabBar}, and for the same reason twice over. GAIA-241 shipped one
|
|
110
157
|
* `topTabSpans(activeId)` over the single flat bar; read level-blind it would
|
|
111
|
-
* publish the project bar's
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* mis-click.
|
|
158
|
+
* publish the project bar's pieces on the root screen too, so a click where
|
|
159
|
+
* `Ticket-Agents` sits on the other level would open a tab that screen does not
|
|
160
|
+
* draw — the very defect GAIA-239 removed, arriving through the mouse. Pieces
|
|
161
|
+
* and bar of two different levels is a TS2345, not a silent mis-click.
|
|
116
162
|
*/
|
|
117
|
-
export function
|
|
118
|
-
return
|
|
163
|
+
export function topTabParts(level, activeId) {
|
|
164
|
+
return renderParts(TAB_LEVELS[level], activeId);
|
|
119
165
|
}
|
|
120
166
|
/**
|
|
121
|
-
* The same
|
|
167
|
+
* The same pieces, for a caller holding a whole {@link TabLocation} — the
|
|
122
168
|
* companion of {@link tabBarFor}, and the pairing it needs was already checked
|
|
123
169
|
* when the location was built. Keeping the two in step is what makes "the bar you
|
|
124
170
|
* see is the bar you click" true by construction: both read `location`.
|
|
125
171
|
*/
|
|
126
|
-
export function
|
|
127
|
-
return
|
|
172
|
+
export function tabPartsFor(location) {
|
|
173
|
+
return renderParts(TAB_LEVELS[location.level], location.tab);
|
|
128
174
|
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { VNode } from '@opentui/core';
|
|
2
|
+
import type { SectionLine } from '../Component/section-list/index.js';
|
|
3
|
+
import type { DropshClient, JsonApiResource } from '../types.js';
|
|
4
|
+
/** A JSON:API collection document (the raw shape `client.get` returns). */
|
|
5
|
+
export interface JsonApiCollectionDoc {
|
|
6
|
+
data?: JsonApiResource[];
|
|
7
|
+
included?: JsonApiResource[];
|
|
8
|
+
/**
|
|
9
|
+
* The document-level `meta`. GAIA-305 makes every `gaia_*` collection report its
|
|
10
|
+
* total here (`GaiaResourceType::includeCount()` -> TRUE, applied by
|
|
11
|
+
* `GaiaResourceTypeRepository::countsCollections()`); see {@link Page.total}.
|
|
12
|
+
*
|
|
13
|
+
* Optional and loosely typed on purpose: a control plane that predates GAIA-305
|
|
14
|
+
* answers either with no `meta` at all or with a `meta` carrying only `omitted`
|
|
15
|
+
* — both measured this session — and neither is an error.
|
|
16
|
+
*/
|
|
17
|
+
meta?: {
|
|
18
|
+
count?: unknown;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* JSON:API's own paging links. `next` is the ONLY valid end-of-list signal, and
|
|
22
|
+
* it stays so after GAIA-305: a page can simply BE the last one, and `next` is
|
|
23
|
+
* what says whether it is. `rows.length === limit` cannot answer that — a full
|
|
24
|
+
* page is exactly as consistent with "more follows" as with "that was all", and
|
|
25
|
+
* the run collection's last page is short for the ordinary reason that
|
|
26
|
+
* collections do not divide evenly.
|
|
27
|
+
*
|
|
28
|
+
* (GAIA-305 does retire the older reason given here — that access filtering
|
|
29
|
+
* emptied pages after `page[limit]` had bounded the query, so a SHORT page said
|
|
30
|
+
* nothing at all. Its query-level access filtering makes pages full again. The
|
|
31
|
+
* conclusion is unchanged; only the argument for it is.)
|
|
32
|
+
*
|
|
33
|
+
* Optional, because the three non-paged readers (the parent picker, the projects
|
|
34
|
+
* screen, the own-conductor lookup) read one bounded bag and never page.
|
|
35
|
+
*/
|
|
36
|
+
links?: {
|
|
37
|
+
next?: unknown;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The window a paged read ASKED the server for: the request's own `page[offset]`
|
|
42
|
+
* and `page[limit]` (GAIA-312 D3).
|
|
43
|
+
*
|
|
44
|
+
* A fact about the REQUEST, never an inference about the pages before it. Both
|
|
45
|
+
* list queries send `page[limit]=size` and `page[offset]=index * size`
|
|
46
|
+
* (`Entity/*/Data/query.ts`), and since GAIA-305 the server skips and counts the
|
|
47
|
+
* same access-filtered collection — which is what lets a screen turn an offset
|
|
48
|
+
* into a position at all.
|
|
49
|
+
*/
|
|
50
|
+
export interface PageWindow {
|
|
51
|
+
/** Rows of the collection the request told the server to skip. */
|
|
52
|
+
offset: number;
|
|
53
|
+
/** Rows the request told the server to return at most. */
|
|
54
|
+
limit: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* One page of rows plus everything the screen states about it.
|
|
58
|
+
*
|
|
59
|
+
* Carried together so a `hasNext`, a page number or a total cannot go stale beside
|
|
60
|
+
* fresh rows (GAIA-292 D4/D4a).
|
|
61
|
+
*/
|
|
62
|
+
export interface Page<Row> {
|
|
63
|
+
rows: Row[];
|
|
64
|
+
hasNext: boolean;
|
|
65
|
+
/** The page these rows CAME FROM, not the one most recently requested. */
|
|
66
|
+
page: number;
|
|
67
|
+
/**
|
|
68
|
+
* The size of the filtered collection as the SERVER reported it, or null when it
|
|
69
|
+
* reported none (GAIA-292 D6e).
|
|
70
|
+
*
|
|
71
|
+
* It rides the page response's `meta.count`, so it costs no read of its own and
|
|
72
|
+
* cannot describe a different collection than the rows beside it: the server
|
|
73
|
+
* applied one query and answered both from it. That is why the earlier background
|
|
74
|
+
* walk — 28 sequential reads for the open-run collection — is gone rather than
|
|
75
|
+
* kept as a fallback.
|
|
76
|
+
*
|
|
77
|
+
* A number renders as `20 of 107 ticket(s)`; `null` renders as `20 of ?
|
|
78
|
+
* ticket(s)` (D6d), which is a visible statement that this control plane reports
|
|
79
|
+
* no total — never a number nobody established.
|
|
80
|
+
*/
|
|
81
|
+
total: number | null;
|
|
82
|
+
/**
|
|
83
|
+
* The window these rows were read with, or `null` when they no longer fill a
|
|
84
|
+
* window that positions them (GAIA-312 D3/D4).
|
|
85
|
+
*
|
|
86
|
+
* Required and explicitly nullable, exactly like {@link Page.total}: "not
|
|
87
|
+
* established" occupies the field's own place instead of being spelled by an
|
|
88
|
+
* absent key. `null` means the screen states a row COUNT; a window means it may
|
|
89
|
+
* state a RANGE, under the test in `ListScreen.countLabel`.
|
|
90
|
+
*/
|
|
91
|
+
window: PageWindow | null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One column of a flat list table (GAIA-294).
|
|
95
|
+
*
|
|
96
|
+
* `fields` is the load-bearing member and the reason this type is not just a
|
|
97
|
+
* `{label, width, get}` triple: it names the JSON:API attributes and
|
|
98
|
+
* relationships this column's value is built from, so a slice can DERIVE its
|
|
99
|
+
* sparse fieldset from its column set instead of maintaining a second list beside
|
|
100
|
+
* it. A column that is not requested cannot exist, because the column IS the
|
|
101
|
+
* request (GAIA-292 AC 5 made the mismatch a compile error; this makes it
|
|
102
|
+
* unrepresentable).
|
|
103
|
+
*
|
|
104
|
+
* One column may name SEVERAL fields — the run list's STATE reads `state`,
|
|
105
|
+
* `heartbeat` and `claim_expires_at` through `deriveRunStatus` — and the fieldset
|
|
106
|
+
* is a superset of the columns' union, because some fields are requested for the
|
|
107
|
+
* client-side predicates and rendered by nothing.
|
|
108
|
+
*
|
|
109
|
+
* GAIA-340 Task 7 — it outlived `lib/table.ts`, whose `renderTable` the tree
|
|
110
|
+
* replaced, and it lives HERE rather than beside its one renderer in
|
|
111
|
+
* `Screen/list-screen.ts` (which is where the plan put it) because the two column
|
|
112
|
+
* SETS are declared in `Entity/*/Data/`, and `tests/boundary.test.ts` G2 forbids a
|
|
113
|
+
* data module the `Screen/` directory outright. This file is the placement that
|
|
114
|
+
* rule leaves — the same one its own header argues for.
|
|
115
|
+
*/
|
|
116
|
+
export interface ListColumn<Row, Ctx = void> {
|
|
117
|
+
/** Stable identity for the column; not rendered, and the id its cells carry. */
|
|
118
|
+
readonly key: string;
|
|
119
|
+
readonly label: string;
|
|
120
|
+
/** Display columns to lay out; **0** is the trailing column, which takes the
|
|
121
|
+
* rest of the row. */
|
|
122
|
+
readonly width: number;
|
|
123
|
+
/** The attributes/relationships this column's value is built from. */
|
|
124
|
+
readonly fields: readonly string[];
|
|
125
|
+
/**
|
|
126
|
+
* GAIA-345 D3 — the column's LAYOUT, DECLARED and never measured.
|
|
127
|
+
*
|
|
128
|
+
* `width` above is the Yoga basis it has today. `min` is what the column is
|
|
129
|
+
* never squeezed below, `max` what it never grows past, and `grow` its share of
|
|
130
|
+
* the row's surplus (0 or absent = never grows). A column that declares none of
|
|
131
|
+
* the three renders exactly as it did before this ticket, which is what keeps
|
|
132
|
+
* the current appearance a DECISION rather than an accident of the refactor.
|
|
133
|
+
*
|
|
134
|
+
* A BOUND ON THE WRONG SIDE OF `width` IS MEANINGFUL, and since the third pass
|
|
135
|
+
* of GAIA-345 the code honours it rather than half-honouring it (see the
|
|
136
|
+
* `declared` derivation in {@link tableRow}). Both readings are of the resolved
|
|
137
|
+
* width, not of the basis:
|
|
138
|
+
*
|
|
139
|
+
* - `max` BELOW `width` NARROWS the column to `max`, because Yoga's `maxWidth`
|
|
140
|
+
* clamps the basis whether or not the cell may shrink. It is the way to say
|
|
141
|
+
* "this column is `max` wide" for a column that is also a grower elsewhere,
|
|
142
|
+
* and it is what the value is cut against — the ellipsis falls at `max`, not
|
|
143
|
+
* at the unreachable `width`.
|
|
144
|
+
* - `min` ABOVE `width` WIDENS it to `min`, because `minWidth` wins over both
|
|
145
|
+
* the basis and the cap. So `{ width: 5, min: 20 }` is a 20-column column
|
|
146
|
+
* that a shrink may take back down to 20 and no further — which is to say
|
|
147
|
+
* it is simply 20 wide.
|
|
148
|
+
*
|
|
149
|
+
* Neither is a shape any column ships today; both are honoured so that the
|
|
150
|
+
* first one to declare it gets what it declared. The pair is pinned on the real
|
|
151
|
+
* renderer in `tests-bun/Screen/list-table-layout.test.ts`.
|
|
152
|
+
*
|
|
153
|
+
* A `max` is a DOMAIN constant — `qualification` is the longest member of the
|
|
154
|
+
* ticket workflow's state_flow, hence STATE's 13 — and never a measurement of
|
|
155
|
+
* the page. Sizing a column from its content is the property GAIA-340 measured
|
|
156
|
+
* `TextTableRenderable` for and rejected it over: the columns shift under the
|
|
157
|
+
* operator every time the page's data changes (spec D4).
|
|
158
|
+
*/
|
|
159
|
+
readonly min?: number;
|
|
160
|
+
readonly max?: number;
|
|
161
|
+
readonly grow?: number;
|
|
162
|
+
get(row: Row, ctx: Ctx): unknown;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* GAIA-345 D2 — one list, declared once.
|
|
166
|
+
*
|
|
167
|
+
* The three members that describe THE LIST move off the per-call options object,
|
|
168
|
+
* because they are not properties of this frame: `noun` prefixes every node id
|
|
169
|
+
* the tree declares AND names the count the footer states, `emptyMessage` is what
|
|
170
|
+
* stands in place of the rows, and `header` says whether this list has one.
|
|
171
|
+
* `selectedIndex` stays a per-call option — it is the only one that changes
|
|
172
|
+
* between two frames of the same list.
|
|
173
|
+
*
|
|
174
|
+
* That split is the mechanism behind the id rule: {@link listRowIds} and
|
|
175
|
+
* {@link listTableTree} read ONE `noun`, so a screen can no longer key its rows
|
|
176
|
+
* `project-picker-candidate-<id>` while publishing `project-picker-row-<id>` as
|
|
177
|
+
* the node a click lands on — a mismatch whose only symptom is a click that
|
|
178
|
+
* resolves to nothing.
|
|
179
|
+
*
|
|
180
|
+
* `Row extends { id: string }` sits here rather than being restated per screen
|
|
181
|
+
* for the same reason: every list's row identity is `rowNodeId(noun, row.id)`.
|
|
182
|
+
*/
|
|
183
|
+
export interface ListTable<Row extends {
|
|
184
|
+
id: string;
|
|
185
|
+
}, Ctx = void> {
|
|
186
|
+
/** The id prefix every node of this list carries — `ticket`, `run`, `project`. */
|
|
187
|
+
readonly noun: string;
|
|
188
|
+
readonly columns: readonly ListColumn<Row, Ctx>[];
|
|
189
|
+
/** The one row shown in place of the rows when there are none. */
|
|
190
|
+
readonly emptyMessage: string;
|
|
191
|
+
/** A bold header row above the data rows. Default true; the project picker is
|
|
192
|
+
* the one list that declares it away — it is a question, not a record set. */
|
|
193
|
+
readonly header?: boolean;
|
|
194
|
+
}
|
|
195
|
+
/** A column-driven list's row ids in selection order — see `lib/vnode.ts`'s
|
|
196
|
+
* `rowNodeId`. Beside {@link listTableTree}, which keys the rows under it, and
|
|
197
|
+
* reading the SAME `noun` off the same configuration (GAIA-345 D2). */
|
|
198
|
+
export declare const listRowIds: <Row extends {
|
|
199
|
+
id: string;
|
|
200
|
+
}, Ctx>(table: ListTable<Row, Ctx>, rows: readonly Row[]) => string[];
|
|
201
|
+
/** What {@link listTableTree} needs beyond the configuration and the rows: the
|
|
202
|
+
* one member that is per-FRAME rather than per-list (GAIA-345 D2). */
|
|
203
|
+
export interface ListTableOptions {
|
|
204
|
+
/** The row the cursor stands on, or -1 for none. */
|
|
205
|
+
readonly selectedIndex: number;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* GAIA-340 D1 — a column-driven list as the renderable tree a screen hands over.
|
|
209
|
+
*
|
|
210
|
+
* One node per row, keyed `<noun>-row-<entity id>` (D4/R4) and never by position:
|
|
211
|
+
* a list re-sorts on every search, page and reload, and a positional key would
|
|
212
|
+
* move one ticket's cells onto another ticket's node with nothing on screen to
|
|
213
|
+
* say so. The cells are keyed within their row by the COLUMN's own `key`, which
|
|
214
|
+
* is what makes the whole set unique by construction.
|
|
215
|
+
*
|
|
216
|
+
* MEASURED, so the choice is not re-litigated: `TextTableRenderable` was tried and
|
|
217
|
+
* rejected. It is ONE renderable whose rows are internal cell views, so no row can
|
|
218
|
+
* carry a `props.id` — the identity `Kernel/mount.ts` patches by, and the identity
|
|
219
|
+
* the mouse will need when it moves onto the renderables — and its column widths
|
|
220
|
+
* are computed from the CONTENT, so the columns would shift every time the page's
|
|
221
|
+
* data changes.
|
|
222
|
+
*
|
|
223
|
+
* THE HIGHLIGHT IS A FULL-WIDTH BAR, and GAIA-345 is where that was decided.
|
|
224
|
+
* Until then this file argued the opposite — that a bar "needs the row's blank
|
|
225
|
+
* columns painted, and the only ways to paint them are a padded string or a fixed
|
|
226
|
+
* colour, and both are worse". The operator overruled it on sight: a highlight
|
|
227
|
+
* covering only the glyphs came out as one fragment per cell, 58 of 120 columns
|
|
228
|
+
* in eight pieces, and read as "only the title of the row is active". The two
|
|
229
|
+
* costs that argument weighed are not the ones that were paid, either. The fill
|
|
230
|
+
* is a blank run as long as a number the COLUMN DECLARES, so no value is measured
|
|
231
|
+
* to build it and `lib/width.ts` is not resurrected under a new name (see
|
|
232
|
+
* {@link tableRow}); and the paint is still the operator's own inverse attribute,
|
|
233
|
+
* so no colour is frozen and the GAIA-326 regression stays fixed. What the
|
|
234
|
+
* argument got right is that the row's blank columns have to be painted — it was
|
|
235
|
+
* wrong that the only ways of doing it were the two bad ones.
|
|
236
|
+
*
|
|
237
|
+
* GAIA-340 Task 8 moved it HERE from `Screen/list-screen.ts`, where Task 7 first
|
|
238
|
+
* wrote it, for the reason {@link ListColumn} gives above it: the run table has a
|
|
239
|
+
* SECOND consumer in the ticket detail's Runs tab (GAIA-255 AC-6 renders a run
|
|
240
|
+
* the same way on both screens), that consumer is a `Component/`, and
|
|
241
|
+
* `tests/boundary.test.ts` G5 forbids anything but an entity-local `Screen/` the
|
|
242
|
+
* `Screen/` directory. Duplicating the renderer instead would have made "one
|
|
243
|
+
* renderer, so the two screens cannot disagree" false.
|
|
244
|
+
*/
|
|
245
|
+
export declare function listTableTree<Row extends {
|
|
246
|
+
id: string;
|
|
247
|
+
}, Ctx>(table: ListTable<Row, Ctx>, rows: readonly Row[], ctx: Ctx, { selectedIndex }: ListTableOptions): VNode;
|
|
248
|
+
/**
|
|
249
|
+
* GAIA-345 D7 — the SAME list for the surface that has no layout:
|
|
250
|
+
* `gaia ui GAIA-nnn | cat`.
|
|
251
|
+
*
|
|
252
|
+
* GAIA-340 F5 keeps the pipe's own output, and this keeps its BYTES while
|
|
253
|
+
* retiring the last per-entity column→row mapper (`run-table`'s `runTableRows`):
|
|
254
|
+
* each cell carries the value and the column's own budget exactly as that emitted
|
|
255
|
+
* them, and `Component/section-list`'s `lineText` still joins them with ONE
|
|
256
|
+
* space. A configuration therefore feeds both surfaces, which is what makes "one
|
|
257
|
+
* component renders every list" true of the run table rather than of its terminal
|
|
258
|
+
* half only.
|
|
259
|
+
*
|
|
260
|
+
* The values are RAW here where {@link listTableTree} runs them through
|
|
261
|
+
* {@link cellText}. That is not an oversight and not a second rendering rule: the
|
|
262
|
+
* ellipsis exists because a Yoga budget cuts silently, and a pipe has no budget
|
|
263
|
+
* to cut against — it prints whatever it is given, at whatever width the reader's
|
|
264
|
+
* terminal or file happens to be. Cutting here would be a cut nobody asked for.
|
|
265
|
+
*
|
|
266
|
+
* The header follows `table.header`, so a headerless list prints headerless and
|
|
267
|
+
* the two surfaces cannot disagree about whether this list has one.
|
|
268
|
+
*/
|
|
269
|
+
export declare function listTableRows<Row extends {
|
|
270
|
+
id: string;
|
|
271
|
+
}, Ctx>(table: ListTable<Row, Ctx>, rows: readonly Row[], ctx: Ctx): SectionLine[];
|
|
272
|
+
/**
|
|
273
|
+
* Read one page of a collection and map it to rows.
|
|
274
|
+
*
|
|
275
|
+
* `mapRows` receives `data` AND `included` so each slice keeps its own sideload
|
|
276
|
+
* indexing — the ticket list indexes every include by id, the run list builds a
|
|
277
|
+
* ticket-only map — without this function knowing either.
|
|
278
|
+
*/
|
|
279
|
+
export declare function loadPage<Row>(client: DropshClient, path: string, params: unknown, mapRows: (data: JsonApiResource[], included: JsonApiResource[]) => Row[], page: number, window: PageWindow): Promise<Page<Row>>;
|