@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.
Files changed (181) hide show
  1. package/dist/src/Agent/launch.d.ts +4 -4
  2. package/dist/src/Agent/launch.js +14 -7
  3. package/dist/src/Component/section-list/index.d.ts +117 -8
  4. package/dist/src/Component/section-list/index.js +118 -46
  5. package/dist/src/Component/stats-panel/index.d.ts +17 -5
  6. package/dist/src/Component/stats-panel/index.js +50 -52
  7. package/dist/src/Component/top-tabs/index.d.ts +95 -23
  8. package/dist/src/Component/top-tabs/index.js +87 -41
  9. package/dist/src/Entity/collection.d.ts +279 -0
  10. package/dist/src/Entity/collection.js +377 -0
  11. package/dist/src/Entity/conductor/Component/conductor-list/index.d.ts +25 -0
  12. package/dist/src/Entity/conductor/Component/conductor-list/index.js +60 -0
  13. package/dist/src/Entity/conductor/Data/conductors.d.ts +216 -0
  14. package/dist/src/Entity/conductor/Data/conductors.js +280 -0
  15. package/dist/src/Entity/conductor/Data/liveness.d.ts +2 -1
  16. package/dist/src/Entity/conductor/Data/liveness.js +12 -16
  17. package/dist/src/Entity/conductor/Data/log-tail.d.ts +25 -0
  18. package/dist/src/Entity/conductor/Data/log-tail.js +133 -0
  19. package/dist/src/Entity/conductor/Data/own-conductor.d.ts +30 -0
  20. package/dist/src/Entity/conductor/Data/own-conductor.js +73 -0
  21. package/dist/src/Entity/conductor/Data/process.d.ts +78 -0
  22. package/dist/src/Entity/conductor/Data/process.js +101 -0
  23. package/dist/src/Entity/conductor/Screen/conductors.d.ts +67 -0
  24. package/dist/src/Entity/conductor/Screen/conductors.js +233 -0
  25. package/dist/src/Entity/cycle.d.ts +18 -0
  26. package/dist/src/Entity/cycle.js +30 -0
  27. package/dist/src/Entity/project/Data/project.d.ts +8 -0
  28. package/dist/src/Entity/project/Data/project.js +12 -0
  29. package/dist/src/Entity/project/Data/projects.d.ts +121 -0
  30. package/dist/src/Entity/project/Data/projects.js +115 -0
  31. package/dist/src/Entity/project/Data/with-tickets.d.ts +5 -0
  32. package/dist/src/Entity/project/Data/with-tickets.js +15 -13
  33. package/dist/src/Entity/project/Screen/project-picker.d.ts +80 -0
  34. package/dist/src/Entity/project/Screen/project-picker.js +191 -0
  35. package/dist/src/Entity/project/Screen/projects-screen.d.ts +52 -0
  36. package/dist/src/Entity/project/Screen/projects-screen.js +122 -0
  37. package/dist/src/Entity/run/Component/run-detail/index.d.ts +26 -10
  38. package/dist/src/Entity/run/Component/run-detail/index.js +147 -39
  39. package/dist/src/Entity/run/Component/run-table/index.d.ts +5 -7
  40. package/dist/src/Entity/run/Component/run-table/index.js +9 -18
  41. package/dist/src/Entity/run/Data/query.d.ts +22 -0
  42. package/dist/src/Entity/run/Data/query.js +41 -0
  43. package/dist/src/Entity/run/Data/runs.d.ts +192 -4
  44. package/dist/src/Entity/run/Data/runs.js +188 -27
  45. package/dist/src/Entity/run/Screen/run-detail.d.ts +53 -0
  46. package/dist/src/Entity/run/Screen/run-detail.js +70 -0
  47. package/dist/src/Entity/run/Screen/runs.d.ts +86 -0
  48. package/dist/src/Entity/run/Screen/runs.js +169 -0
  49. package/dist/src/Entity/statistics/Screen/dashboard.d.ts +78 -0
  50. package/dist/src/Entity/statistics/Screen/dashboard.js +228 -0
  51. package/dist/src/Entity/ticket/Component/comment-item/index.d.ts +12 -9
  52. package/dist/src/Entity/ticket/Component/comment-item/index.js +18 -13
  53. package/dist/src/Entity/ticket/Component/create-form/index.d.ts +16 -3
  54. package/dist/src/Entity/ticket/Component/create-form/index.js +28 -14
  55. package/dist/src/Entity/ticket/Component/edit-form/index.d.ts +11 -6
  56. package/dist/src/Entity/ticket/Component/edit-form/index.js +77 -29
  57. package/dist/src/Entity/ticket/Component/sections/index.d.ts +8 -0
  58. package/dist/src/Entity/ticket/Component/sections/index.js +42 -0
  59. package/dist/src/Entity/ticket/Component/tab-bar/index.js +6 -0
  60. package/dist/src/Entity/ticket/Component/ticket-detail/index.d.ts +65 -8
  61. package/dist/src/Entity/ticket/Component/ticket-detail/index.js +171 -84
  62. package/dist/src/Entity/ticket/Component/ticket-table/index.d.ts +4 -2
  63. package/dist/src/Entity/ticket/Component/ticket-table/index.js +8 -12
  64. package/dist/src/Entity/ticket/Component/ticket-teaser/index.d.ts +47 -3
  65. package/dist/src/Entity/ticket/Component/ticket-teaser/index.js +76 -22
  66. package/dist/src/Entity/ticket/Data/parents.d.ts +13 -1
  67. package/dist/src/Entity/ticket/Data/parents.js +64 -12
  68. package/dist/src/Entity/ticket/Data/query.d.ts +44 -7
  69. package/dist/src/Entity/ticket/Data/query.js +60 -26
  70. package/dist/src/Entity/ticket/Data/tickets.d.ts +170 -4
  71. package/dist/src/Entity/ticket/Data/tickets.js +200 -12
  72. package/dist/src/Entity/ticket/Data/url.d.ts +16 -0
  73. package/dist/src/Entity/ticket/Data/url.js +20 -0
  74. package/dist/src/Entity/ticket/Data/workflow.d.ts +1 -5
  75. package/dist/src/Entity/ticket/Data/workflow.js +5 -13
  76. package/dist/src/Entity/ticket/Data/write.d.ts +32 -0
  77. package/dist/src/Entity/ticket/Data/write.js +80 -0
  78. package/dist/src/Entity/ticket/Form/create-data.d.ts +1 -11
  79. package/dist/src/Entity/ticket/Form/create-data.js +7 -36
  80. package/dist/src/Entity/ticket/Form/create.d.ts +45 -5
  81. package/dist/src/Entity/ticket/Form/create.js +45 -8
  82. package/dist/src/Entity/ticket/Form/edit-data.d.ts +1 -1
  83. package/dist/src/Entity/ticket/Form/edit-data.js +4 -0
  84. package/dist/src/Entity/ticket/Form/edit.d.ts +79 -12
  85. package/dist/src/Entity/ticket/Form/edit.js +165 -18
  86. package/dist/src/Entity/ticket/Form/keys.d.ts +7 -0
  87. package/dist/src/Entity/ticket/Form/keys.js +7 -0
  88. package/dist/src/Entity/ticket/Form/parent-filter.d.ts +36 -0
  89. package/dist/src/Entity/ticket/Form/parent-filter.js +37 -0
  90. package/dist/src/Entity/ticket/Form/parent-source.d.ts +27 -0
  91. package/dist/src/Entity/ticket/Form/parent-source.js +56 -0
  92. package/dist/src/Entity/ticket/Form/who-filter.d.ts +33 -0
  93. package/dist/src/Entity/ticket/Form/who-filter.js +33 -0
  94. package/dist/src/Entity/ticket/Form/who-source.d.ts +18 -0
  95. package/dist/src/Entity/ticket/Form/who-source.js +38 -0
  96. package/dist/src/Entity/ticket/Screen/create-ticket-form.d.ts +81 -0
  97. package/dist/src/Entity/ticket/Screen/create-ticket-form.js +356 -0
  98. package/dist/src/Entity/ticket/Screen/edit-assignment-form.d.ts +92 -0
  99. package/dist/src/Entity/ticket/Screen/edit-assignment-form.js +220 -0
  100. package/dist/src/Entity/ticket/Screen/parent-filter-form.d.ts +44 -0
  101. package/dist/src/Entity/ticket/Screen/parent-filter-form.js +200 -0
  102. package/dist/src/Entity/ticket/Screen/ticket-agents.d.ts +136 -0
  103. package/dist/src/Entity/ticket/Screen/ticket-agents.js +257 -0
  104. package/dist/src/Entity/ticket/Screen/ticket-detail.d.ts +125 -0
  105. package/dist/src/Entity/ticket/Screen/ticket-detail.js +415 -0
  106. package/dist/src/Entity/ticket/Screen/tickets.d.ts +145 -0
  107. package/dist/src/Entity/ticket/Screen/tickets.js +538 -0
  108. package/dist/src/Entity/ticket/Screen/who-filter-form.d.ts +41 -0
  109. package/dist/src/Entity/ticket/Screen/who-filter-form.js +174 -0
  110. package/dist/src/Entity/user/Data/users.d.ts +17 -0
  111. package/dist/src/Entity/user/Data/users.js +66 -6
  112. package/dist/src/Form/field.d.ts +3 -1
  113. package/dist/src/Form/field.js +1 -0
  114. package/dist/src/Form/form.d.ts +1 -1
  115. package/dist/src/Form/form.js +61 -9
  116. package/dist/src/Form/keys.d.ts +23 -1
  117. package/dist/src/Form/keys.js +78 -23
  118. package/dist/src/Kernel/chrome.d.ts +289 -0
  119. package/dist/src/Kernel/chrome.js +404 -0
  120. package/dist/src/Kernel/clipboard.d.ts +30 -0
  121. package/dist/src/Kernel/clipboard.js +51 -0
  122. package/dist/src/Kernel/key-input.d.ts +50 -0
  123. package/dist/src/Kernel/key-input.js +158 -0
  124. package/dist/src/Kernel/mount.d.ts +187 -0
  125. package/dist/src/Kernel/mount.js +399 -0
  126. package/dist/src/Kernel/tui-kernel.d.ts +0 -11
  127. package/dist/src/Kernel/tui-kernel.js +778 -2367
  128. package/dist/src/Routing/context.d.ts +31 -0
  129. package/dist/src/Routing/context.js +52 -0
  130. package/dist/src/Routing/registry.d.ts +19 -0
  131. package/dist/src/Routing/registry.js +97 -0
  132. package/dist/src/Routing/route.d.ts +35 -0
  133. package/dist/src/Routing/route.js +1 -0
  134. package/dist/src/Routing/router.d.ts +49 -0
  135. package/dist/src/Routing/router.js +123 -0
  136. package/dist/src/Routing/routes.d.ts +17 -0
  137. package/dist/src/Routing/routes.js +57 -0
  138. package/dist/src/Screen/async-screen.d.ts +87 -0
  139. package/dist/src/Screen/async-screen.js +206 -0
  140. package/dist/src/Screen/list-screen.d.ts +193 -0
  141. package/dist/src/Screen/list-screen.js +261 -0
  142. package/dist/src/Screen/screen.d.ts +240 -0
  143. package/dist/src/Screen/screen.js +34 -0
  144. package/dist/src/Tui/controller.d.ts +13 -0
  145. package/dist/src/Tui/controller.js +1794 -0
  146. package/dist/src/Widget/autocomplete.js +75 -3
  147. package/dist/src/Widget/index.d.ts +3 -2
  148. package/dist/src/Widget/index.js +2 -1
  149. package/dist/src/Widget/option-source.d.ts +12 -1
  150. package/dist/src/Widget/option-source.js +14 -1
  151. package/dist/src/Widget/render.d.ts +23 -8
  152. package/dist/src/Widget/render.js +108 -41
  153. package/dist/src/Widget/text.js +94 -5
  154. package/dist/src/Widget/textarea.d.ts +45 -0
  155. package/dist/src/Widget/textarea.js +115 -0
  156. package/dist/src/Widget/types.d.ts +64 -1
  157. package/dist/src/launcher.d.ts +9 -2
  158. package/dist/src/launcher.js +2 -1
  159. package/dist/src/lib/ansi.js +13 -5
  160. package/dist/src/lib/clipboard.d.ts +41 -0
  161. package/dist/src/lib/clipboard.js +65 -0
  162. package/dist/src/lib/cursor.d.ts +31 -0
  163. package/dist/src/lib/cursor.js +45 -0
  164. package/dist/src/lib/format.d.ts +21 -13
  165. package/dist/src/lib/format.js +76 -28
  166. package/dist/src/lib/hyperlink.d.ts +58 -0
  167. package/dist/src/lib/hyperlink.js +104 -0
  168. package/dist/src/lib/input-trace.d.ts +48 -0
  169. package/dist/src/lib/input-trace.js +47 -0
  170. package/dist/src/lib/key-vocabulary.d.ts +19 -0
  171. package/dist/src/lib/key-vocabulary.js +25 -0
  172. package/dist/src/lib/table.d.ts +37 -0
  173. package/dist/src/lib/table.js +20 -0
  174. package/dist/src/lib/vnode.d.ts +217 -0
  175. package/dist/src/lib/vnode.js +456 -0
  176. package/dist/src/lib/width.d.ts +25 -1
  177. package/dist/src/lib/width.js +93 -12
  178. package/dist/src/plugin.js +26 -1
  179. package/dist/src/types.d.ts +67 -2
  180. package/dist/src/types.js +0 -4
  181. 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 hit map, built from the SAME `segment`/`SEPARATOR` that level's
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 three spans on the root screen too, so a click at
111
- * the column where `Ticket-Agents` used to sit would open a tab that screen does
112
- * not draw — the very defect this ticket removes, arriving through the mouse.
113
- * A map and a bar of two different levels is now a TS2345, not a silent
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 topTabSpans<L extends TabLevel>(level: L, activeId: TabIdOf<L>): TopTabSpan<TabIdOf<L>>[];
188
+ export declare function topTabParts<L extends TabLevel>(level: L, activeId: TabIdOf<L>): TabBarPart<TabIdOf<L>>[];
117
189
  /**
118
- * The same hit map, for a caller holding a whole {@link TabLocation} — the
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 tabSpansFor(location: TabLocation): TopTabSpan[];
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 ticket → the DETAIL tabs, drawn as the
10
- // header box's meta row, so no
11
- // top-level bar at all
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. `gotoTopTab` was its only caller, and it only ever moves within one
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` on
34
- // the root level, `Conductors` on the project level) arrives with its own ticket
35
- // and adds its entry here then — a tab drawn before its screen exists would
36
- // advertise navigation the operator cannot take, which is the very defect
37
- // GAIA-239 removes.
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 renderBar = (tabs, activeId) => tabs.map((t) => segment(t, activeId)).join(SEPARATOR);
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
- const renderSpans = (tabs, activeId) => {
87
- const spans = [];
88
- let start = 0;
89
- tabs.forEach((tab, index) => {
90
- if (index > 0)
91
- start += displayWidth(SEPARATOR);
92
- const width = displayWidth(segment(tab, activeId));
93
- spans.push({ id: tab.id, start, end: start + width });
94
- start += width;
95
- });
96
- return spans;
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 hit map, built from the SAME `segment`/`SEPARATOR` that level's
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 three spans on the root screen too, so a click at
112
- * the column where `Ticket-Agents` used to sit would open a tab that screen does
113
- * not draw — the very defect this ticket removes, arriving through the mouse.
114
- * A map and a bar of two different levels is now a TS2345, not a silent
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 topTabSpans(level, activeId) {
118
- return renderSpans(TAB_LEVELS[level], activeId);
163
+ export function topTabParts(level, activeId) {
164
+ return renderParts(TAB_LEVELS[level], activeId);
119
165
  }
120
166
  /**
121
- * The same hit map, for a caller holding a whole {@link TabLocation} — the
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 tabSpansFor(location) {
127
- return renderSpans(TAB_LEVELS[location.level], location.tab);
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>>;