@gaia-ai/addon-gaia-ui 0.9.2 → 0.11.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 (136) hide show
  1. package/dist/src/Component/footer-actions/index.d.ts +58 -0
  2. package/dist/src/Component/footer-actions/index.js +111 -0
  3. package/dist/src/Component/list-chrome/index.d.ts +19 -0
  4. package/dist/src/Component/list-chrome/index.js +61 -0
  5. package/dist/src/Component/markdown/index.d.ts +68 -0
  6. package/dist/src/Component/markdown/index.js +133 -0
  7. package/dist/src/Component/section-list/index.d.ts +115 -23
  8. package/dist/src/Component/section-list/index.js +120 -34
  9. package/dist/src/Component/top-tabs/index.d.ts +110 -7
  10. package/dist/src/Component/top-tabs/index.js +88 -9
  11. package/dist/src/Entity/collection.js +1 -1
  12. package/dist/src/Entity/conductor/Data/conductors.d.ts +4 -3
  13. package/dist/src/Entity/conductor/Data/conductors.js +76 -10
  14. package/dist/src/Entity/conductor/Data/own-conductor.js +7 -1
  15. package/dist/src/Entity/conductor/Screen/conductors.d.ts +26 -41
  16. package/dist/src/Entity/conductor/Screen/conductors.js +65 -123
  17. package/dist/src/Entity/project/Screen/project-picker.d.ts +20 -31
  18. package/dist/src/Entity/project/Screen/project-picker.js +48 -58
  19. package/dist/src/Entity/project/Screen/projects-screen.d.ts +4 -2
  20. package/dist/src/Entity/project/Screen/projects-screen.js +11 -8
  21. package/dist/src/Entity/run/Component/run-detail/index.js +15 -7
  22. package/dist/src/Entity/run/Data/query.d.ts +10 -0
  23. package/dist/src/Entity/run/Data/query.js +16 -1
  24. package/dist/src/Entity/run/Data/runs.d.ts +2 -0
  25. package/dist/src/Entity/run/Data/runs.js +19 -1
  26. package/dist/src/Entity/run/Screen/run-detail.d.ts +16 -23
  27. package/dist/src/Entity/run/Screen/run-detail.js +27 -34
  28. package/dist/src/Entity/run/Screen/runs.d.ts +7 -3
  29. package/dist/src/Entity/run/Screen/runs.js +31 -48
  30. package/dist/src/Entity/run/Screen/user-runs.d.ts +79 -0
  31. package/dist/src/Entity/run/Screen/user-runs.js +98 -0
  32. package/dist/src/Entity/statistics/Data/statistics.d.ts +111 -9
  33. package/dist/src/Entity/statistics/Data/statistics.js +121 -9
  34. package/dist/src/Entity/statistics/Screen/dashboard.d.ts +10 -2
  35. package/dist/src/Entity/statistics/Screen/dashboard.js +127 -36
  36. package/dist/src/Entity/team/Data/members.d.ts +30 -0
  37. package/dist/src/Entity/team/Data/members.js +83 -0
  38. package/dist/src/Entity/team/Data/team.d.ts +22 -0
  39. package/dist/src/Entity/team/Data/team.js +38 -0
  40. package/dist/src/Entity/team/Data/teams.d.ts +223 -0
  41. package/dist/src/Entity/team/Data/teams.js +267 -0
  42. package/dist/src/Entity/team/Screen/team-users.d.ts +76 -0
  43. package/dist/src/Entity/team/Screen/team-users.js +215 -0
  44. package/dist/src/Entity/team/Screen/teams-screen.d.ts +116 -0
  45. package/dist/src/Entity/team/Screen/teams-screen.js +349 -0
  46. package/dist/src/Entity/ticket/Component/comment-item/index.d.ts +14 -1
  47. package/dist/src/Entity/ticket/Component/comment-item/index.js +15 -1
  48. package/dist/src/Entity/ticket/Component/edit-form/index.d.ts +8 -3
  49. package/dist/src/Entity/ticket/Component/edit-form/index.js +4 -6
  50. package/dist/src/Entity/ticket/Component/sections/index.js +16 -1
  51. package/dist/src/Entity/ticket/Component/ticket-detail/index.d.ts +102 -13
  52. package/dist/src/Entity/ticket/Component/ticket-detail/index.js +440 -72
  53. package/dist/src/Entity/ticket/Data/detail.d.ts +19 -3
  54. package/dist/src/Entity/ticket/Data/detail.js +20 -4
  55. package/dist/src/Entity/ticket/Data/query.d.ts +7 -0
  56. package/dist/src/Entity/ticket/Data/query.js +18 -2
  57. package/dist/src/Entity/ticket/Data/tickets.d.ts +24 -0
  58. package/dist/src/Entity/ticket/Data/tickets.js +41 -1
  59. package/dist/src/Entity/ticket/Screen/create-ticket-form.d.ts +10 -4
  60. package/dist/src/Entity/ticket/Screen/create-ticket-form.js +37 -16
  61. package/dist/src/Entity/ticket/Screen/edit-assignment-form.d.ts +6 -4
  62. package/dist/src/Entity/ticket/Screen/edit-assignment-form.js +16 -16
  63. package/dist/src/Entity/ticket/Screen/parent-filter-form.d.ts +6 -4
  64. package/dist/src/Entity/ticket/Screen/parent-filter-form.js +14 -11
  65. package/dist/src/Entity/ticket/Screen/ticket-agents.d.ts +5 -2
  66. package/dist/src/Entity/ticket/Screen/ticket-agents.js +14 -14
  67. package/dist/src/Entity/ticket/Screen/ticket-detail.d.ts +89 -4
  68. package/dist/src/Entity/ticket/Screen/ticket-detail.js +295 -74
  69. package/dist/src/Entity/ticket/Screen/tickets.d.ts +66 -3
  70. package/dist/src/Entity/ticket/Screen/tickets.js +140 -76
  71. package/dist/src/Entity/ticket/Screen/user-tickets.d.ts +91 -0
  72. package/dist/src/Entity/ticket/Screen/user-tickets.js +94 -0
  73. package/dist/src/Entity/ticket/Screen/who-filter-form.d.ts +6 -4
  74. package/dist/src/Entity/ticket/Screen/who-filter-form.js +14 -11
  75. package/dist/src/Entity/transport.d.ts +14 -4
  76. package/dist/src/Entity/transport.js +2 -1
  77. package/dist/src/Entity/user/Data/users.d.ts +87 -0
  78. package/dist/src/Entity/user/Data/users.js +60 -0
  79. package/dist/src/Entity/user/Screen/user-overview.d.ts +33 -0
  80. package/dist/src/Entity/user/Screen/user-overview.js +159 -0
  81. package/dist/src/Entity/user/Screen/users.d.ts +39 -0
  82. package/dist/src/Entity/user/Screen/users.js +136 -0
  83. package/dist/src/Extension/contract.d.ts +58 -0
  84. package/dist/src/Extension/contract.js +1 -0
  85. package/dist/src/Extension/load.d.ts +10 -0
  86. package/dist/src/Extension/load.js +21 -0
  87. package/dist/src/Extension/store.d.ts +11 -0
  88. package/dist/src/Extension/store.js +44 -0
  89. package/dist/src/Kernel/chrome.d.ts +49 -12
  90. package/dist/src/Kernel/chrome.js +150 -57
  91. package/dist/src/Kernel/key-input.js +1 -1
  92. package/dist/src/Kernel/mount.d.ts +1 -1
  93. package/dist/src/Kernel/mount.js +1 -1
  94. package/dist/src/Kernel/regions.d.ts +64 -0
  95. package/dist/src/Kernel/regions.js +328 -0
  96. package/dist/src/Kernel/renderer.d.ts +25 -0
  97. package/dist/src/Kernel/renderer.js +142 -0
  98. package/dist/src/Kernel/splash.d.ts +27 -0
  99. package/dist/src/Kernel/splash.js +72 -0
  100. package/dist/src/Kernel/tui-kernel.js +139 -435
  101. package/dist/src/Routing/context.d.ts +5 -0
  102. package/dist/src/Routing/context.js +6 -0
  103. package/dist/src/Routing/registry.js +21 -2
  104. package/dist/src/Routing/router.js +5 -1
  105. package/dist/src/Routing/routes.js +19 -0
  106. package/dist/src/Screen/async-modal-screen.d.ts +26 -0
  107. package/dist/src/Screen/async-modal-screen.js +44 -0
  108. package/dist/src/Screen/async-screen.d.ts +32 -40
  109. package/dist/src/Screen/async-screen.js +45 -41
  110. package/dist/src/Screen/full-screen.d.ts +1 -0
  111. package/dist/src/Screen/full-screen.js +3 -0
  112. package/dist/src/Screen/list-screen.d.ts +7 -1
  113. package/dist/src/Screen/list-screen.js +17 -6
  114. package/dist/src/Screen/modal-screen.d.ts +6 -0
  115. package/dist/src/Screen/modal-screen.js +2 -0
  116. package/dist/src/Screen/screen.d.ts +42 -6
  117. package/dist/src/Screen/screen.js +2 -2
  118. package/dist/src/Widget/textarea.js +10 -14
  119. package/dist/src/Widget/types.d.ts +1 -1
  120. package/dist/src/launcher.d.ts +24 -26
  121. package/dist/src/launcher.js +11 -11
  122. package/dist/src/lib/format.js +1 -1
  123. package/dist/src/lib/markdown.d.ts +53 -0
  124. package/dist/src/lib/markdown.js +522 -0
  125. package/dist/src/lib/refresh-signal.d.ts +56 -0
  126. package/dist/src/lib/refresh-signal.js +85 -0
  127. package/dist/src/lib/theme.d.ts +36 -0
  128. package/dist/src/lib/theme.js +40 -0
  129. package/dist/src/lib/version.d.ts +5 -0
  130. package/dist/src/lib/version.js +46 -0
  131. package/dist/src/lib/vnode.d.ts +86 -63
  132. package/dist/src/lib/vnode.js +112 -85
  133. package/dist/src/types.d.ts +47 -12
  134. package/dist/src/ui.d.ts +2 -0
  135. package/dist/src/ui.js +1 -0
  136. package/package.json +4 -3
@@ -0,0 +1,76 @@
1
+ import type { VNode } from '@opentui/core';
2
+ import { AsyncScreen } from '../../../Screen/async-screen.js';
3
+ import type { FullScreenChrome } from '../../../Screen/full-screen.js';
4
+ import type { ScreenContext } from '../../../Screen/screen.js';
5
+ import { type UserListRow } from '../../user/Data/users.js';
6
+ /** The crew as rows, or the reason there are none. */
7
+ interface CrewList {
8
+ rows: UserListRow[];
9
+ /**
10
+ * Present only when the crew could not be ESTABLISHED — a refused membership
11
+ * read, a team that did not resolve, a refused user collection. Never set for
12
+ * a crew that is genuinely empty: that is `rows: []`, and the table's own
13
+ * `emptyMessage` says it.
14
+ */
15
+ error?: string;
16
+ /**
17
+ * No crew was named at all, which is NOT a failure — see
18
+ * {@link TeamUsersScreen.load}. Kept apart from `error` so the two are not
19
+ * reported in the same words: one says a read went wrong, the other says
20
+ * nothing has been chosen yet.
21
+ */
22
+ unscoped?: boolean;
23
+ }
24
+ /**
25
+ * ONE crew's people — the team level's `Users` tab.
26
+ *
27
+ * `fallback` points at the crews list: Escape lands where the operator came from,
28
+ * which after the ruling is Teams and no longer a root Users tab.
29
+ */
30
+ export declare class TeamUsersScreen extends AsyncScreen<CrewList> {
31
+ readonly frameId = "team-users";
32
+ topTab(): {
33
+ readonly level: "team";
34
+ readonly tab: "users";
35
+ };
36
+ reload(context: ScreenContext): void;
37
+ /**
38
+ * `id: 'users'` — the id GAIA-377's user-level screens already fall back to.
39
+ *
40
+ * There is exactly ONE users list now and this is it, so it keeps the id rather
41
+ * than taking a new one and stranding three `fallback: { routeId: 'users' }`
42
+ * declarations on a route that no longer exists (`Router.navigate` throws
43
+ * `unknown route` for one of those, on Escape, with no history). Those three
44
+ * carry no `teamId`, which is what {@link TeamUsersScreen.load} answers for.
45
+ */
46
+ static readonly route: {
47
+ id: string;
48
+ path: string;
49
+ tab: {
50
+ id: string;
51
+ label: string;
52
+ scope: string;
53
+ order: number;
54
+ };
55
+ fallback: {
56
+ routeId: string;
57
+ };
58
+ };
59
+ readonly id: string;
60
+ private readonly cursor;
61
+ get selectedIndex(): number;
62
+ set selectedIndex(value: number);
63
+ get rows(): readonly UserListRow[];
64
+ /** Whether the ready value is a CREW at all, rather than a notice about one. */
65
+ private get drawable();
66
+ protected load(context: ScreenContext): Promise<CrewList>;
67
+ protected renderLoading(): string[];
68
+ protected renderReady(result: CrewList): VNode;
69
+ protected chrome(context: ScreenContext): FullScreenChrome;
70
+ protected actions(): import("../../../Component/footer-actions/index.js").ActionItem[];
71
+ activate(index: number, context: ScreenContext): boolean;
72
+ select(index: number, context: ScreenContext): boolean;
73
+ handleInput(input: string, context: ScreenContext): boolean;
74
+ reset(): void;
75
+ }
76
+ export {};
@@ -0,0 +1,215 @@
1
+ import { actionItem } from '../../../Component/footer-actions/index.js';
2
+ import { sectionRowNode, } from '../../../Component/section-list/index.js';
3
+ import { ListCursor } from '../../../lib/cursor.js';
4
+ import { columnNode } from '../../../lib/vnode.js';
5
+ import { AsyncScreen } from '../../../Screen/async-screen.js';
6
+ import { listRowIds, listTableTree } from '../../collection.js';
7
+ import { closedPerRun, formatClosedPerRun, loadStatistics, } from '../../statistics/Data/statistics.js';
8
+ import { listUsers, TEAM_MEMBER_TABLE, } from '../../user/Data/users.js';
9
+ import { listTeamMemberIds } from '../Data/members.js';
10
+ import { TeamsScreen } from './teams-screen.js';
11
+ // GAIA-391 AC4 (second round) — the crew's people, on the TEAM level.
12
+ //
13
+ // This is where GAIA-377's `users` root tab went, by operator ruling: a person is
14
+ // reached through the crew they are in (Teams → one crew → Users → one person),
15
+ // so the users LIST is team-scoped and the user LEVEL below it is untouched.
16
+ //
17
+ // Three reads, because the answer needs three things and no two of them come
18
+ // from one resource:
19
+ //
20
+ // - WHO is in the crew `og_membership` (`Data/members.ts`)
21
+ // - what those people are the `user` collection — labels and uids
22
+ // - what they have done the team-scoped statistics' `by_user`
23
+ //
24
+ // The composition lives HERE rather than in `Data/`, and that is the boundary
25
+ // rule rather than taste: `Entity/*/Data/` may not reach into another slice
26
+ // (`tests/boundary.test.ts` G2), and `user` and `statistics` are two other
27
+ // slices. A screen crossing slices is ordinary; a data module doing it would need
28
+ // two new `ALLOWED_CROSS_SLICE` entries.
29
+ /** Rows that are plain text, keyed under one name: a failure state. */
30
+ const plainRows = (key, lines) => lines.map((text, index) => ({ key: `${key}-${index}`, text, bold: false }));
31
+ /** What this screen says when it was opened without a crew to open. */
32
+ const NO_CREW = 'Open a crew from Teams to see who is in it.';
33
+ /** One member's row: identity from the collection, figures from the document. */
34
+ function rowOf(user, statistics) {
35
+ const monthOf = (rows) => (rows ?? []).find((row) => row.id === user.id)?.month ?? 0;
36
+ const tickets30d = statistics === null ? 0 : monthOf(statistics.tickets.byUser);
37
+ const runs30d = statistics === null ? 0 : monthOf(statistics.runs.byUser);
38
+ return {
39
+ id: user.id,
40
+ label: user.label,
41
+ tickets30d,
42
+ runs30d,
43
+ closedPerRun30d: formatClosedPerRun(closedPerRun({ day: 0, week: 0, month: tickets30d }, { day: 0, week: 0, month: runs30d }).month),
44
+ };
45
+ }
46
+ /**
47
+ * ONE crew's people — the team level's `Users` tab.
48
+ *
49
+ * `fallback` points at the crews list: Escape lands where the operator came from,
50
+ * which after the ruling is Teams and no longer a root Users tab.
51
+ */
52
+ export class TeamUsersScreen extends AsyncScreen {
53
+ frameId = 'team-users';
54
+ topTab() {
55
+ return { level: 'team', tab: 'users' };
56
+ }
57
+ reload(context) {
58
+ this.retry(context);
59
+ }
60
+ /**
61
+ * `id: 'users'` — the id GAIA-377's user-level screens already fall back to.
62
+ *
63
+ * There is exactly ONE users list now and this is it, so it keeps the id rather
64
+ * than taking a new one and stranding three `fallback: { routeId: 'users' }`
65
+ * declarations on a route that no longer exists (`Router.navigate` throws
66
+ * `unknown route` for one of those, on Escape, with no history). Those three
67
+ * carry no `teamId`, which is what {@link TeamUsersScreen.load} answers for.
68
+ */
69
+ static route = {
70
+ id: 'users',
71
+ path: '/teams/:teamId/users',
72
+ tab: { id: 'users', label: 'Users', scope: 'team', order: 20 },
73
+ fallback: { routeId: TeamsScreen.route.id },
74
+ };
75
+ id = TeamUsersScreen.route.id;
76
+ cursor = new ListCursor();
77
+ get selectedIndex() {
78
+ return this.cursor.index;
79
+ }
80
+ set selectedIndex(value) {
81
+ this.cursor.index = value;
82
+ }
83
+ get rows() {
84
+ return this.drawable ? (this.readyValue?.rows ?? []) : [];
85
+ }
86
+ /** Whether the ready value is a CREW at all, rather than a notice about one. */
87
+ get drawable() {
88
+ const result = this.readyValue;
89
+ return (result !== undefined && result.error === undefined && !result.unscoped);
90
+ }
91
+ async load(context) {
92
+ if (!context.services)
93
+ throw new Error('Team users requires services');
94
+ const teamId = context.params?.teamId;
95
+ // Reached without a crew — the shape the user level's `fallback` produces,
96
+ // because a person's route carries `userId` and never a `teamId`. A notice
97
+ // rather than a throw: there is nothing wrong here, there is just no crew
98
+ // chosen yet, and the operator needs to be told where to choose one.
99
+ if (!teamId)
100
+ return { rows: [], unscoped: true };
101
+ const client = context.services.client;
102
+ const [members, users, statistics] = await Promise.all([
103
+ listTeamMemberIds(client, teamId),
104
+ listUsers(client),
105
+ loadStatistics(client, undefined, undefined, teamId),
106
+ ]);
107
+ // Either failure leaves the crew unknown, and an unknown crew must not be
108
+ // drawn as an empty one: without the memberships there is nobody to keep,
109
+ // and without the collection there is nobody to name.
110
+ if (members.ids === null)
111
+ return {
112
+ rows: [],
113
+ // `listTeamMemberIds` always names a reason beside a null crew, but the
114
+ // type does not promise it — so a missing one becomes a stated unknown
115
+ // rather than a screen with a blank explanation.
116
+ error: members.error ?? 'the crew could not be established',
117
+ };
118
+ if (users.error !== undefined)
119
+ return { rows: [], error: users.error };
120
+ const crew = new Set(members.ids);
121
+ const figures = statistics.kind === 'ok' ? statistics.statistics : null;
122
+ return {
123
+ rows: users.rows
124
+ // Anonymous (0) and Drupal uid 1 are never operator rows — the rule the
125
+ // root list carried, kept where the list now lives.
126
+ .filter((user) => crew.has(user.id) && user.uid !== 0 && user.uid !== 1)
127
+ .map((user) => rowOf(user, figures)),
128
+ };
129
+ }
130
+ renderLoading() {
131
+ return ['Loading crew…'];
132
+ }
133
+ renderReady(result) {
134
+ const notice = (key, lines) => columnNode('team-users', ...plainRows(key, lines).map((row) => sectionRowNode('team-users', row)));
135
+ if (result.unscoped)
136
+ return notice('team-users-unscoped', [NO_CREW]);
137
+ if (result.error !== undefined)
138
+ return notice('team-users-error', [
139
+ 'Could not read the crew.',
140
+ '',
141
+ result.error,
142
+ ]);
143
+ return listTableTree(TEAM_MEMBER_TABLE, result.rows, undefined, {
144
+ selectedIndex: this.selectedIndex,
145
+ });
146
+ }
147
+ chrome(context) {
148
+ const rows = this.rows;
149
+ const result = this.readyValue;
150
+ const name = context.params?.teamName ?? context.params?.teamId ?? 'team';
151
+ if (result?.unscoped)
152
+ return {
153
+ selectable: 0,
154
+ selectedIndex: 0,
155
+ rowIds: [],
156
+ title: 'GAIA crew',
157
+ meta: 'no crew chosen',
158
+ };
159
+ if (result?.error !== undefined)
160
+ return {
161
+ selectable: 0,
162
+ selectedIndex: 0,
163
+ rowIds: [],
164
+ title: `${name} · users`,
165
+ meta: 'crew unavailable',
166
+ };
167
+ return {
168
+ selectable: rows.length,
169
+ selectedIndex: this.selectedIndex,
170
+ rowIds: listRowIds(TEAM_MEMBER_TABLE, rows),
171
+ title: `${name} · users`,
172
+ meta: `${rows.length} member(s)`,
173
+ };
174
+ }
175
+ actions() {
176
+ return [
177
+ actionItem('team-users-enter', 'Enter', 'open'),
178
+ actionItem('team-users-tab', 'Tab', 'tabs'),
179
+ ];
180
+ }
181
+ activate(index, context) {
182
+ const row = this.rows[index];
183
+ if (!row || !context.navigate)
184
+ return false;
185
+ context.navigate('user.overview', {
186
+ userId: row.id,
187
+ userName: row.label,
188
+ });
189
+ return true;
190
+ }
191
+ select(index, context) {
192
+ if (index < 0 || index >= this.rows.length)
193
+ return false;
194
+ this.selectedIndex = index;
195
+ context.requestDraw();
196
+ return true;
197
+ }
198
+ handleInput(input, context) {
199
+ if (super.handleInput(input, context))
200
+ return true;
201
+ if (this.readyValue === undefined)
202
+ return false;
203
+ if (this.cursor.handle(input, this.rows.length)) {
204
+ context.requestDraw();
205
+ return true;
206
+ }
207
+ if (input === 'enter')
208
+ return this.activate(this.selectedIndex, context);
209
+ return false;
210
+ }
211
+ reset() {
212
+ this.cursor.reset();
213
+ super.reset();
214
+ }
215
+ }
@@ -0,0 +1,116 @@
1
+ import type { VNode } from '@opentui/core';
2
+ import { AsyncScreen } from '../../../Screen/async-screen.js';
3
+ import type { FullScreenChrome } from '../../../Screen/full-screen.js';
4
+ import type { ScreenContext } from '../../../Screen/screen.js';
5
+ import { type StatisticsResult } from '../../statistics/Data/statistics.js';
6
+ import { type ResolvedTeam } from '../Data/team.js';
7
+ import { type TeamListResult, type TeamListRow } from '../Data/teams.js';
8
+ /**
9
+ * The Teams list — a ROOT tab, which is what makes it reachable.
10
+ *
11
+ * Root rather than project level, by the argument GAIA-232 used for Conductors: a
12
+ * team cuts ACROSS customer projects (it is the level that does, per GAIA-321), so
13
+ * "which crews are there" must be answerable without first choosing a project.
14
+ *
15
+ * `order: 50` puts it last, after Users. People, then the crews they are in — and
16
+ * appending rather than inserting keeps every exact-bar assertion in the vitest
17
+ * and Bun suites reading one unchanged prefix.
18
+ */
19
+ export declare class TeamsScreen extends AsyncScreen<TeamListResult> {
20
+ readonly frameId = "teams";
21
+ topTab(): {
22
+ readonly level: "root";
23
+ readonly tab: "teams";
24
+ };
25
+ reload(context: ScreenContext): void;
26
+ static readonly route: {
27
+ id: string;
28
+ path: string;
29
+ tab: {
30
+ id: string;
31
+ label: string;
32
+ scope: string;
33
+ order: number;
34
+ };
35
+ };
36
+ readonly id: string;
37
+ private readonly cursor;
38
+ get selectedIndex(): number;
39
+ set selectedIndex(value: number);
40
+ saveState(): {
41
+ selectedIndex: number;
42
+ };
43
+ restoreState(token: unknown): void;
44
+ get rows(): readonly TeamListRow[];
45
+ protected load(context: ScreenContext): Promise<TeamListResult>;
46
+ protected renderLoading(): string[];
47
+ protected renderReady(result: TeamListResult): VNode;
48
+ protected chrome(context: ScreenContext): FullScreenChrome;
49
+ protected actions(): import("../../../Component/footer-actions/index.js").ActionItem[];
50
+ activate(index: number, context: ScreenContext): boolean;
51
+ select(index: number, context: ScreenContext): boolean;
52
+ handleInput(input: string, context: ScreenContext): boolean;
53
+ reset(): void;
54
+ }
55
+ /**
56
+ * What one team's page is made of: who the crew is, and what it did.
57
+ *
58
+ * Carried as one value because the screen draws both, and because keeping the
59
+ * resolved identity beside the figures is what stops the header from falling back
60
+ * to a uuid when only the statistics read failed.
61
+ */
62
+ interface TeamOverview {
63
+ team: ResolvedTeam;
64
+ statistics: StatisticsResult;
65
+ }
66
+ /**
67
+ * ONE team's report: the crew's identity plus the team-scoped statistics, read
68
+ * through the `?team_id=` the control plane has served since GAIA-321.
69
+ *
70
+ * `fallback` points at the list, so Escape from a deep link lands somewhere real
71
+ * rather than on the default route — the rule `UserOverviewScreen` follows.
72
+ */
73
+ export declare class TeamOverviewScreen extends AsyncScreen<TeamOverview> {
74
+ readonly frameId = "team-overview";
75
+ /**
76
+ * GAIA-391 AC4 (second round) — the team level's landing tab.
77
+ *
78
+ * The earlier round declared no `tab` here and argued a team owns no LEVEL
79
+ * because "there is nothing under it to tab between". The operator's ruling is
80
+ * the opposite: the users level is under it, so the crew has a bar of its own
81
+ * (Overview · Users) and this screen is its first entry.
82
+ */
83
+ topTab(): {
84
+ readonly level: "team";
85
+ readonly tab: "overview";
86
+ };
87
+ reload(context: ScreenContext): void;
88
+ static readonly route: {
89
+ id: string;
90
+ path: string;
91
+ tab: {
92
+ id: string;
93
+ label: string;
94
+ scope: string;
95
+ order: number;
96
+ };
97
+ fallback: {
98
+ routeId: string;
99
+ };
100
+ };
101
+ readonly id: string;
102
+ /**
103
+ * The crew's identity AND its figures, read in parallel.
104
+ *
105
+ * Two reads because they answer two questions and fail independently: a
106
+ * control plane that cannot serve statistics still knows who is in the team,
107
+ * and the header must not fall back to a uuid because a count timed out.
108
+ */
109
+ protected load(context: ScreenContext): Promise<TeamOverview>;
110
+ protected renderLoading(): string[];
111
+ private readyRows;
112
+ protected renderReady(result: TeamOverview): VNode;
113
+ protected chrome(context: ScreenContext): FullScreenChrome;
114
+ protected actions(): import("../../../Component/footer-actions/index.js").ActionItem[];
115
+ }
116
+ export {};