@anchrd/intel-ui 0.7.2 → 0.8.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anchrd/intel-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"typecheck": "tsc --noEmit"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@anchrd/intel-contract": "^0.
|
|
31
|
+
"@anchrd/intel-contract": "^0.4.0",
|
|
32
32
|
"@blocknote/core": "^0.52.1",
|
|
33
33
|
"@blocknote/react": "^0.52.1",
|
|
34
34
|
"@blocknote/shadcn": "^0.52.1",
|
|
@@ -119,6 +119,14 @@ export function AppTree() {
|
|
|
119
119
|
// ⚠️ The whole point of #11: one query per level, and a level only exists while its folder is
|
|
120
120
|
// open. A recursive load would put an N+1 on every page of the app, because the tree is now on
|
|
121
121
|
// every page.
|
|
122
|
+
// Ein aufgeklappter Flow zeigt, was er ruft — mit demselben Pfeil-Versprechen eine Ebene tiefer:
|
|
123
|
+
// ein gerufener Flow, der selbst ruft, lässt sich weiter aufklappen (#59).
|
|
124
|
+
async function flowCallRows(flowId: string): Promise<TreeEntry[]> {
|
|
125
|
+
const calls = await data.listFlowCalls(flowId);
|
|
126
|
+
const openable = new Set(calls.withCalls);
|
|
127
|
+
return calls.items.map((flow) => flowEntry(flow, openable.has(flow.id)));
|
|
128
|
+
}
|
|
129
|
+
|
|
122
130
|
const parents: Level[] = [{ id: null, type: "folder" }, ...expanded];
|
|
123
131
|
const levels = useQueries({
|
|
124
132
|
queries: parents.map((parent) => ({
|
|
@@ -128,7 +136,7 @@ export function AppTree() {
|
|
|
128
136
|
? // The same row a folder's level builds for a flow, from the same function: what hangs
|
|
129
137
|
// under an expanded flow differs in where the flows come from, never in what a flow row
|
|
130
138
|
// is (#30).
|
|
131
|
-
|
|
139
|
+
await flowCallRows(parent.id)
|
|
132
140
|
: await data.listTreeChildren(parent.id),
|
|
133
141
|
})),
|
|
134
142
|
});
|
|
@@ -338,17 +346,14 @@ export function AppTree() {
|
|
|
338
346
|
// now is that a row already on the path from the root is not rendered again.
|
|
339
347
|
const entries = level.data?.filter((entry) => !ancestors.has(entry.id)) ?? [];
|
|
340
348
|
if (entries.length === 0) {
|
|
341
|
-
// ⚠️
|
|
342
|
-
// answer
|
|
343
|
-
// and
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
: parent.id === null
|
|
350
|
-
? i18n.t("tree.empty")
|
|
351
|
-
: null;
|
|
349
|
+
// ⚠️ Nothing that is empty says so any more (#59). "This flow calls no other flow" used to
|
|
350
|
+
// stand here as an answer rather than filler — but a row that cannot be opened is the answer,
|
|
351
|
+
// and now no such row can be opened: the chevron only appears where there is something under
|
|
352
|
+
// it. The sentence would only ever be read by somebody who got here another way.
|
|
353
|
+
//
|
|
354
|
+
// `tree.empty` at the ROOT stays, and for a different reason that still holds: a completely
|
|
355
|
+
// blank sidebar on a fresh installation leaves a new user without any way in.
|
|
356
|
+
const message = parent.type === "folder" && parent.id === null ? i18n.t("tree.empty") : null;
|
|
352
357
|
// The folder keeps its list, empty. The structure is what carries "there is nothing here" to
|
|
353
358
|
// a screen reader — "list, 0 items" — which is the same answer the missing rows give a reader
|
|
354
359
|
// who can see them, and neither of them is a sentence.
|
|
@@ -374,7 +379,10 @@ export function AppTree() {
|
|
|
374
379
|
// from `parent_id`. A flow reused by three callers therefore shows up under all three, which is
|
|
375
380
|
// the answer to "what do I run, and how" (ADR-0004 §3).
|
|
376
381
|
const level: Level & { id: string } = { id: entry.id, type: isFolder ? "folder" : "flow" };
|
|
377
|
-
|
|
382
|
+
// ⚠️ Nicht mehr „ist von einer Art, die sich aufklappen lässt", sondern „hat etwas zum
|
|
383
|
+
// Aufklappen, das dieser Leser sehen darf" (#59). Der Unterschied ist ein Pfeil, der hält, was
|
|
384
|
+
// er verspricht — vorher stand er an jedem Ordner und jedem Flow, auch an leeren.
|
|
385
|
+
const expandable = entry.openable;
|
|
378
386
|
const isOpen =
|
|
379
387
|
expandable && expanded.some((open) => open.id === entry.id && open.type === level.type);
|
|
380
388
|
const Icon = isOpen && isFolder ? FolderOpen : icons[entry.kind];
|
|
@@ -80,8 +80,12 @@ export function loginPath(returnTo?: string): string {
|
|
|
80
80
|
* copies of this would keep returning something plausible and slowly stop agreeing on what a flow
|
|
81
81
|
* row is (#30).
|
|
82
82
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// ⚠️ `openable` ist hier voreingestellt falsch — genauer: unbekannt. Wer die Ebene kennt, setzt es
|
|
84
|
+
// (`listTreeChildren`); wer nur eine einzelne Zeile baut, weiß es nicht und behauptet deshalb das
|
|
85
|
+
// Zurückhaltendere. Ein Pfeil, der zu Unrecht fehlt, kostet einen Klick auf die Zeile; einer, der
|
|
86
|
+
// zu Unrecht steht, kostet Vertrauen (#59).
|
|
87
|
+
export function flowEntry(flow: Flow, openable = false): TreeEntry {
|
|
88
|
+
return { type: "flow", id: flow.id, title: flow.title, kind: "flow", openable, flow };
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
export function createIntelDataProvider(
|
|
@@ -181,15 +185,20 @@ export function createIntelDataProvider(
|
|
|
181
185
|
listKnowledge({ parentId }),
|
|
182
186
|
listFlows({ parentId }),
|
|
183
187
|
]);
|
|
188
|
+
// ⚠️ Beide Seiten sagen, welche ihrer Zeilen etwas zum Aufklappen haben (#59) — für DIESEN
|
|
189
|
+
// Leser. Der Baum weiß es damit beim Zeichnen, ohne die Ebene darunter vorzuladen: Das wäre
|
|
190
|
+
// ein Ladevorgang pro Zeile statt pro Ordner.
|
|
191
|
+
const openable = new Set([...knowledge.withChildren, ...flows.withCalls]);
|
|
184
192
|
const entries: TreeEntry[] = [
|
|
185
193
|
...knowledge.items.map((node) => ({
|
|
186
194
|
type: "knowledge" as const,
|
|
187
195
|
id: node.id,
|
|
188
196
|
title: node.title,
|
|
189
197
|
kind: node.kind,
|
|
198
|
+
openable: openable.has(node.id),
|
|
190
199
|
node,
|
|
191
200
|
})),
|
|
192
|
-
...flows.items.map(flowEntry),
|
|
201
|
+
...flows.items.map((flow) => flowEntry(flow, openable.has(flow.id))),
|
|
193
202
|
];
|
|
194
203
|
// Folders first, then everything else by title: a document and a flow sit side by side, and
|
|
195
204
|
// the icon is what tells them apart.
|
|
@@ -51,9 +51,19 @@ import type {
|
|
|
51
51
|
|
|
52
52
|
// One row of the shared tree. Knowledge and Flows share the folder, not their nature (ADR-0004), so
|
|
53
53
|
// this is a union that keeps each side's record whole — never a merged "node" that is a bit of both.
|
|
54
|
+
// ⚠️ `openable` heißt „hat etwas zum Aufklappen, das DIESER Leser sehen darf" (#59) — nicht „ist
|
|
55
|
+
// von einer Art, die sich aufklappen lässt". Der Unterschied ist der ganze Sinn: Ein Pfeil an einer
|
|
56
|
+
// Zeile, unter der nichts liegt, verspricht Inhalt, den das Aufklappen nicht liefert.
|
|
54
57
|
export type TreeEntry =
|
|
55
|
-
| {
|
|
56
|
-
|
|
58
|
+
| {
|
|
59
|
+
type: "knowledge";
|
|
60
|
+
id: string;
|
|
61
|
+
title: string;
|
|
62
|
+
kind: KnowledgeNodeKind;
|
|
63
|
+
openable: boolean;
|
|
64
|
+
node: KnowledgeNode;
|
|
65
|
+
}
|
|
66
|
+
| { type: "flow"; id: string; title: string; kind: "flow"; openable: boolean; flow: Flow };
|
|
57
67
|
|
|
58
68
|
export interface IntelDataProvider {
|
|
59
69
|
getSession(): Promise<SessionUser>;
|
package/src/i18n/en.json
CHANGED
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"tree.collapse": "Hide what is inside {title}",
|
|
33
33
|
"tree.expandCalls": "Show the flows {title} calls",
|
|
34
34
|
"tree.collapseCalls": "Hide the flows {title} calls",
|
|
35
|
-
"tree.noCalls": "This flow calls no other flow.",
|
|
36
35
|
"tree.add": "Add to {title}",
|
|
37
36
|
"tree.addRoot": "Add at the top level",
|
|
38
37
|
"tree.new.folder": "New folder",
|
|
@@ -61,6 +61,8 @@ function entryOf(target: ResourceTarget): TreeEntry {
|
|
|
61
61
|
id: target.node.id,
|
|
62
62
|
title: target.node.title,
|
|
63
63
|
kind: target.node.kind,
|
|
64
|
+
// Ein Menü verschiebt eine Zeile; ob sie sich aufklappen lässt, spielt dabei keine Rolle.
|
|
65
|
+
openable: false,
|
|
64
66
|
node: target.node,
|
|
65
67
|
};
|
|
66
68
|
}
|