@ai-matrx/associations 0.5.2 → 0.6.1
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/CHANGELOG.md +109 -0
- package/README.md +51 -13
- package/dist/CommentThread-E0zSQBbc.d.cts +1905 -0
- package/dist/CommentThread-E0zSQBbc.d.ts +1905 -0
- package/dist/core/index.cjs +23 -6
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +18 -5
- package/dist/core/index.d.ts +18 -5
- package/dist/core/index.js +23 -6
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -17
- package/dist/index.d.ts +66 -17
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +1039 -451
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +79 -1854
- package/dist/react/index.d.ts +79 -1854
- package/dist/react/index.js +1064 -465
- package/dist/react/index.js.map +1 -1
- package/dist/react/lazy/index.cjs +89 -0
- package/dist/react/lazy/index.cjs.map +1 -0
- package/dist/react/lazy/index.d.cts +17 -0
- package/dist/react/lazy/index.d.ts +17 -0
- package/dist/react/lazy/index.js +59 -0
- package/dist/react/lazy/index.js.map +1 -0
- package/package.json +18 -4
package/dist/react/index.js
CHANGED
|
@@ -1,13 +1,191 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/react/context.tsx
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
useContext,
|
|
7
|
+
useEffect,
|
|
8
|
+
useRef
|
|
9
|
+
} from "react";
|
|
10
|
+
|
|
11
|
+
// src/demanded-rpcs.generated.ts
|
|
12
|
+
var DEMANDED_RPC_NAMES = [
|
|
13
|
+
"assoc_add",
|
|
14
|
+
"assoc_remove",
|
|
15
|
+
"assoc_set_targets",
|
|
16
|
+
"assoc_remove_for_entity",
|
|
17
|
+
"assoc_for_entity",
|
|
18
|
+
"assoc_for_targets",
|
|
19
|
+
"assoc_for_sources",
|
|
20
|
+
"assoc_members_visible",
|
|
21
|
+
"conversation_file_add",
|
|
22
|
+
"conversation_file_remove",
|
|
23
|
+
"conversation_files",
|
|
24
|
+
"agent_resource_add",
|
|
25
|
+
"agent_resource_remove",
|
|
26
|
+
"cat_list",
|
|
27
|
+
"cat_create",
|
|
28
|
+
"cat_update",
|
|
29
|
+
"cat_reparent",
|
|
30
|
+
"cat_delete",
|
|
31
|
+
"ues_set",
|
|
32
|
+
"ues_list",
|
|
33
|
+
"ues_get_bulk",
|
|
34
|
+
"ues_touch",
|
|
35
|
+
"reference_search_candidates",
|
|
36
|
+
"cmt_list",
|
|
37
|
+
"cmt_add",
|
|
38
|
+
"cmt_edit",
|
|
39
|
+
"cmt_delete"
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
// src/core/assertDemandedSchema.ts
|
|
43
|
+
var BAD_UUID = "__not_a_uuid__";
|
|
44
|
+
var SELF_TEST_MISSING_RPC = "assoc_probe_self_test_missing_fn";
|
|
45
|
+
var PROBE_ARGS = {
|
|
46
|
+
// edges — writes
|
|
47
|
+
assoc_add: {
|
|
48
|
+
p_source_type: "note",
|
|
49
|
+
p_source_id: BAD_UUID,
|
|
50
|
+
p_target_type: "task",
|
|
51
|
+
p_target_id: BAD_UUID
|
|
52
|
+
},
|
|
53
|
+
assoc_remove: {
|
|
54
|
+
p_source_type: "note",
|
|
55
|
+
p_source_id: BAD_UUID,
|
|
56
|
+
p_target_type: "task",
|
|
57
|
+
p_target_id: BAD_UUID
|
|
58
|
+
},
|
|
59
|
+
assoc_set_targets: {
|
|
60
|
+
p_source_type: "note",
|
|
61
|
+
p_source_id: BAD_UUID,
|
|
62
|
+
p_target_type: "task",
|
|
63
|
+
p_target_ids: [BAD_UUID]
|
|
64
|
+
},
|
|
65
|
+
assoc_remove_for_entity: { p_type: "note", p_id: BAD_UUID },
|
|
66
|
+
// edges — reads
|
|
67
|
+
assoc_for_entity: { p_type: "note", p_id: BAD_UUID },
|
|
68
|
+
assoc_for_targets: { p_target_type: "task", p_target_ids: [BAD_UUID] },
|
|
69
|
+
assoc_for_sources: { p_source_type: "note", p_source_ids: [BAD_UUID] },
|
|
70
|
+
assoc_members_visible: { p_target_type: "task", p_target_ids: [BAD_UUID] },
|
|
71
|
+
// conversation files
|
|
72
|
+
conversation_file_add: {
|
|
73
|
+
p_conversation_id: BAD_UUID,
|
|
74
|
+
p_file_id: BAD_UUID
|
|
75
|
+
},
|
|
76
|
+
conversation_file_remove: {
|
|
77
|
+
p_conversation_id: BAD_UUID,
|
|
78
|
+
p_file_id: BAD_UUID
|
|
79
|
+
},
|
|
80
|
+
conversation_files: { p_conversation_id: BAD_UUID },
|
|
81
|
+
// agent resources
|
|
82
|
+
agent_resource_add: {
|
|
83
|
+
p_agent_id: BAD_UUID,
|
|
84
|
+
p_source_type: "note",
|
|
85
|
+
p_source_id: BAD_UUID
|
|
86
|
+
},
|
|
87
|
+
agent_resource_remove: {
|
|
88
|
+
p_agent_id: BAD_UUID,
|
|
89
|
+
p_source_type: "note",
|
|
90
|
+
p_source_id: BAD_UUID
|
|
91
|
+
},
|
|
92
|
+
// categories
|
|
93
|
+
cat_list: {},
|
|
94
|
+
cat_create: { p_dimension: "", p_name: "", p_org_id: BAD_UUID },
|
|
95
|
+
cat_update: { p_category_id: BAD_UUID, p_name: "__probe__" },
|
|
96
|
+
cat_reparent: { p_category_id: BAD_UUID },
|
|
97
|
+
cat_delete: { p_category_id: BAD_UUID },
|
|
98
|
+
// favorites / recents
|
|
99
|
+
ues_set: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
|
|
100
|
+
ues_list: {},
|
|
101
|
+
ues_get_bulk: { p_entity_type: "__probe__", p_entity_ids: [BAD_UUID] },
|
|
102
|
+
ues_touch: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
|
|
103
|
+
// candidates
|
|
104
|
+
reference_search_candidates: { p_token: "__probe__", p_limit: 1 },
|
|
105
|
+
// comments (W6) — every fn takes a uuid arg, so the unparseable sentinel
|
|
106
|
+
// guarantees 22P02 before any SECURITY DEFINER body runs (no write occurs).
|
|
107
|
+
cmt_list: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
|
|
108
|
+
cmt_add: {
|
|
109
|
+
p_entity_type: "__probe__",
|
|
110
|
+
p_entity_id: BAD_UUID,
|
|
111
|
+
p_body: "__probe__"
|
|
112
|
+
},
|
|
113
|
+
cmt_edit: { p_id: BAD_UUID, p_body: "__probe__" },
|
|
114
|
+
cmt_delete: { p_id: BAD_UUID }
|
|
115
|
+
};
|
|
116
|
+
function isMissingFunctionError(error) {
|
|
117
|
+
if (!error || typeof error !== "object") return false;
|
|
118
|
+
return error.code === "PGRST202";
|
|
119
|
+
}
|
|
120
|
+
async function assertDemandedSchema(dataSource, options = {}) {
|
|
121
|
+
const { selfTest = false, concurrency = 6, throwOnViolation = true } = options;
|
|
122
|
+
const names = [...DEMANDED_RPC_NAMES];
|
|
123
|
+
if (selfTest) names.push(SELF_TEST_MISSING_RPC);
|
|
124
|
+
const missing = [];
|
|
125
|
+
const unreachable = [];
|
|
126
|
+
const answered = [];
|
|
127
|
+
let cursor = 0;
|
|
128
|
+
async function worker() {
|
|
129
|
+
while (cursor < names.length) {
|
|
130
|
+
const fn = names[cursor];
|
|
131
|
+
cursor += 1;
|
|
132
|
+
if (!fn) continue;
|
|
133
|
+
const args = fn === SELF_TEST_MISSING_RPC ? {} : PROBE_ARGS[fn];
|
|
134
|
+
try {
|
|
135
|
+
const { error } = await dataSource.rpc(fn, args);
|
|
136
|
+
if (error == null) answered.push(fn);
|
|
137
|
+
else if (isMissingFunctionError(error)) missing.push(fn);
|
|
138
|
+
else answered.push(fn);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
unreachable.push({ fn, error: e });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
await Promise.all(
|
|
145
|
+
Array.from({ length: Math.min(concurrency, names.length) }, worker)
|
|
146
|
+
);
|
|
147
|
+
if (selfTest) {
|
|
148
|
+
const selfTestMissing = missing.includes(SELF_TEST_MISSING_RPC);
|
|
149
|
+
const idx = missing.indexOf(SELF_TEST_MISSING_RPC);
|
|
150
|
+
if (idx >= 0) missing.splice(idx, 1);
|
|
151
|
+
const answeredIdx = answered.indexOf(SELF_TEST_MISSING_RPC);
|
|
152
|
+
if (answeredIdx >= 0) answered.splice(answeredIdx, 1);
|
|
153
|
+
if (!selfTestMissing) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`assertDemandedSchema self-test FAILED: the fabricated function "${SELF_TEST_MISSING_RPC}" did not come back as missing (PGRST202). This probe cannot currently fail, so its green result proves nothing \u2014 the dataSource is swallowing or faking errors.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (unreachable.length > 0) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`assertDemandedSchema could not complete: ${unreachable.length} probe call(s) failed to reach the database (${unreachable.map((u) => u.fn).join(", ")}). This is NOT a schema verdict \u2014 fix connectivity and re-run.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const ok = missing.length === 0;
|
|
165
|
+
const report = { ok, missing, unreachable, answered };
|
|
166
|
+
if (!ok && throwOnViolation) {
|
|
167
|
+
throw new Error(
|
|
168
|
+
`DEMANDED SCHEMA VIOLATION: the database this dataSource points at cannot answer ${missing.length} demanded @ai-matrx/associations function(s): ${missing.join(", ")}. This package demands the AI Matrx platform schema (README \xA7 The demanded schema); a database without it is not this package's database.`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return report;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/react/context.tsx
|
|
5
175
|
import { jsx } from "react/jsx-runtime";
|
|
6
176
|
var AssociationsReactContext = createContext(
|
|
7
177
|
null
|
|
8
178
|
);
|
|
179
|
+
function isDevelopmentBuild() {
|
|
180
|
+
try {
|
|
181
|
+
return typeof process !== "undefined" && true;
|
|
182
|
+
} catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
9
186
|
function AssociationsProvider({
|
|
10
187
|
store,
|
|
188
|
+
probeSchema,
|
|
11
189
|
notifier,
|
|
12
190
|
windowShell,
|
|
13
191
|
capture,
|
|
@@ -17,6 +195,28 @@ function AssociationsProvider({
|
|
|
17
195
|
children
|
|
18
196
|
}) {
|
|
19
197
|
const notifierWarned = useRef(false);
|
|
198
|
+
const shouldProbe = probeSchema ?? isDevelopmentBuild();
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
if (!shouldProbe) return;
|
|
201
|
+
let stale = false;
|
|
202
|
+
void (async () => {
|
|
203
|
+
try {
|
|
204
|
+
await assertDemandedSchema(store.dataSource);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (stale) return;
|
|
207
|
+
store.errorSink({
|
|
208
|
+
code: "demanded_schema_violation",
|
|
209
|
+
message: error instanceof Error ? error.message : "assertDemandedSchema failed",
|
|
210
|
+
context: {
|
|
211
|
+
remedy: "Run the platform.associations schema (README \xA7 The demanded schema) on the database this dataSource points at."
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
})();
|
|
216
|
+
return () => {
|
|
217
|
+
stale = true;
|
|
218
|
+
};
|
|
219
|
+
}, [shouldProbe, store]);
|
|
20
220
|
return /* @__PURE__ */ jsx(
|
|
21
221
|
AssociationsReactContext.Provider,
|
|
22
222
|
{
|
|
@@ -78,7 +278,7 @@ function useNotifier() {
|
|
|
78
278
|
}
|
|
79
279
|
|
|
80
280
|
// src/react/hooks/useAssociations.ts
|
|
81
|
-
import { useEffect, useRef as useRef2, useSyncExternalStore } from "react";
|
|
281
|
+
import { useEffect as useEffect2, useRef as useRef2, useSyncExternalStore } from "react";
|
|
82
282
|
|
|
83
283
|
// src/results.ts
|
|
84
284
|
function isAssociationsRpcErr(r) {
|
|
@@ -201,6 +401,7 @@ var ENTITY_TYPE_TOKENS = [
|
|
|
201
401
|
"commerce_marketplace_site",
|
|
202
402
|
"commerce_marketplace_sync_run",
|
|
203
403
|
"commerce_prediction_outcome",
|
|
404
|
+
"commerce_print_order",
|
|
204
405
|
"commerce_product",
|
|
205
406
|
"commerce_product_channel_ref",
|
|
206
407
|
"commerce_product_media",
|
|
@@ -789,7 +990,7 @@ function useAssociations(args) {
|
|
|
789
990
|
() => store.getEdges(type, id ?? "")
|
|
790
991
|
);
|
|
791
992
|
const loadedKey = useRef2(null);
|
|
792
|
-
|
|
993
|
+
useEffect2(() => {
|
|
793
994
|
if (!autoLoad || !type || !id) return;
|
|
794
995
|
const k = associationsKey(type, id);
|
|
795
996
|
if (loadedKey.current === k) return;
|
|
@@ -845,7 +1046,7 @@ var useEntityRelationships = useAssociations;
|
|
|
845
1046
|
// src/react/hooks/useContainerLinks.ts
|
|
846
1047
|
import {
|
|
847
1048
|
useCallback,
|
|
848
|
-
useEffect as
|
|
1049
|
+
useEffect as useEffect3,
|
|
849
1050
|
useLayoutEffect,
|
|
850
1051
|
useRef as useRef3,
|
|
851
1052
|
useState
|
|
@@ -910,7 +1111,7 @@ function useContainerLinks(args) {
|
|
|
910
1111
|
loading: false
|
|
911
1112
|
});
|
|
912
1113
|
}, [containerId, conversationKey, store]);
|
|
913
|
-
|
|
1114
|
+
useEffect3(() => {
|
|
914
1115
|
const timeout = setTimeout(() => {
|
|
915
1116
|
void loadConversationFiles();
|
|
916
1117
|
}, 0);
|
|
@@ -993,7 +1194,7 @@ function useContainerLinks(args) {
|
|
|
993
1194
|
}
|
|
994
1195
|
|
|
995
1196
|
// src/react/hooks/useEntityTitles.ts
|
|
996
|
-
import { useEffect as
|
|
1197
|
+
import { useEffect as useEffect4, useState as useState2 } from "react";
|
|
997
1198
|
function useEntityTitles(refs) {
|
|
998
1199
|
const store = useAssociationsStore();
|
|
999
1200
|
const [resolved, setResolved] = useState2({});
|
|
@@ -1003,7 +1204,7 @@ function useEntityTitles(refs) {
|
|
|
1003
1204
|
(r) => store.registry.tryGetEntityInfo(r.token)?.titleColumn != null && store.titles.get(r.token, r.id) == null && !attempted[entityTitleCacheKey(r.token, r.id)]
|
|
1004
1205
|
);
|
|
1005
1206
|
const neededKey = needed.map((r) => entityTitleCacheKey(r.token, r.id)).sort().join("|");
|
|
1006
|
-
|
|
1207
|
+
useEffect4(() => {
|
|
1007
1208
|
if (!neededKey) return;
|
|
1008
1209
|
let cancelled = false;
|
|
1009
1210
|
setLoading(true);
|
|
@@ -1067,7 +1268,7 @@ function useEntityTitles(refs) {
|
|
|
1067
1268
|
}
|
|
1068
1269
|
|
|
1069
1270
|
// src/react/hooks/useCategories.ts
|
|
1070
|
-
import { useEffect as
|
|
1271
|
+
import { useEffect as useEffect5, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
1071
1272
|
var noopSubscribe2 = () => () => {
|
|
1072
1273
|
};
|
|
1073
1274
|
function useCategories(args) {
|
|
@@ -1079,7 +1280,7 @@ function useCategories(args) {
|
|
|
1079
1280
|
() => store.getCategories(dimension ?? "")
|
|
1080
1281
|
);
|
|
1081
1282
|
const loadedKey = useRef4(null);
|
|
1082
|
-
|
|
1283
|
+
useEffect5(() => {
|
|
1083
1284
|
if (!autoLoad || !dimension) return;
|
|
1084
1285
|
if (loadedKey.current === dimension) return;
|
|
1085
1286
|
loadedKey.current = dimension;
|
|
@@ -1130,7 +1331,7 @@ function useCategories(args) {
|
|
|
1130
1331
|
}
|
|
1131
1332
|
|
|
1132
1333
|
// src/react/hooks/useUniversalEntitySearch.ts
|
|
1133
|
-
import { useEffect as
|
|
1334
|
+
import { useEffect as useEffect6, useRef as useRef5, useState as useState3 } from "react";
|
|
1134
1335
|
var DEBOUNCE_MS = 250;
|
|
1135
1336
|
var RECENTS_LIMIT = 12;
|
|
1136
1337
|
function useUniversalEntitySearch(args) {
|
|
@@ -1148,7 +1349,7 @@ function useUniversalEntitySearch(args) {
|
|
|
1148
1349
|
const [isRecents, setIsRecents] = useState3(true);
|
|
1149
1350
|
const runRef = useRef5(0);
|
|
1150
1351
|
const tokensKey = (tokens ?? []).join(",");
|
|
1151
|
-
|
|
1352
|
+
useEffect6(() => {
|
|
1152
1353
|
if (!enabled) return;
|
|
1153
1354
|
const run = ++runRef.current;
|
|
1154
1355
|
const trimmed = query.trim();
|
|
@@ -1210,7 +1411,7 @@ async function loadRecents(store, tokens) {
|
|
|
1210
1411
|
}
|
|
1211
1412
|
|
|
1212
1413
|
// src/react/hooks/useAssociationCandidates.ts
|
|
1213
|
-
import { useEffect as
|
|
1414
|
+
import { useEffect as useEffect7, useState as useState4 } from "react";
|
|
1214
1415
|
function useAssociationCandidates(args) {
|
|
1215
1416
|
const { token, enabled = true, search, limit } = args;
|
|
1216
1417
|
const store = useAssociationsStore();
|
|
@@ -1219,7 +1420,7 @@ function useAssociationCandidates(args) {
|
|
|
1219
1420
|
const [loading, setLoading] = useState4(false);
|
|
1220
1421
|
const [error, setError] = useState4(null);
|
|
1221
1422
|
const [tick, setTick] = useState4(0);
|
|
1222
|
-
|
|
1423
|
+
useEffect7(() => {
|
|
1223
1424
|
if (!enabled) return void 0;
|
|
1224
1425
|
let cancelled = false;
|
|
1225
1426
|
void (async () => {
|
|
@@ -1260,7 +1461,7 @@ function currentUserIdOrNull(store) {
|
|
|
1260
1461
|
}
|
|
1261
1462
|
|
|
1262
1463
|
// src/react/hooks/useComments.ts
|
|
1263
|
-
import { useEffect as
|
|
1464
|
+
import { useEffect as useEffect8, useRef as useRef6, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1264
1465
|
var noopSubscribe3 = () => () => {
|
|
1265
1466
|
};
|
|
1266
1467
|
function useComments(args) {
|
|
@@ -1273,7 +1474,7 @@ function useComments(args) {
|
|
|
1273
1474
|
() => store.getComments(token, id ?? "")
|
|
1274
1475
|
);
|
|
1275
1476
|
const loadedKey = useRef6(null);
|
|
1276
|
-
|
|
1477
|
+
useEffect8(() => {
|
|
1277
1478
|
if (!autoLoad || !key || !id) return;
|
|
1278
1479
|
if (loadedKey.current === key) return;
|
|
1279
1480
|
loadedKey.current = key;
|
|
@@ -1415,6 +1616,16 @@ function usePrimaryEntity() {
|
|
|
1415
1616
|
|
|
1416
1617
|
// src/react/components/AssociationWindow.tsx
|
|
1417
1618
|
import { useId } from "react";
|
|
1619
|
+
|
|
1620
|
+
// src/react/components/DefaultWindowShell.tsx
|
|
1621
|
+
import {
|
|
1622
|
+
useCallback as useCallback2,
|
|
1623
|
+
useEffect as useEffect9,
|
|
1624
|
+
useLayoutEffect as useLayoutEffect2,
|
|
1625
|
+
useRef as useRef7,
|
|
1626
|
+
useState as useState6
|
|
1627
|
+
} from "react";
|
|
1628
|
+
import { createPortal } from "react-dom";
|
|
1418
1629
|
import { cn } from "@ai-matrx/design-system";
|
|
1419
1630
|
|
|
1420
1631
|
// src/react/icons.tsx
|
|
@@ -1533,9 +1744,246 @@ function DefaultEntityIcon(props) {
|
|
|
1533
1744
|
/* @__PURE__ */ jsx3("path", { d: "M12 13.5V8" })
|
|
1534
1745
|
] });
|
|
1535
1746
|
}
|
|
1747
|
+
function MaximizeIcon(props) {
|
|
1748
|
+
return /* @__PURE__ */ jsxs("svg", { ...base(props), children: [
|
|
1749
|
+
/* @__PURE__ */ jsx3("path", { d: "M15 3h6v6" }),
|
|
1750
|
+
/* @__PURE__ */ jsx3("path", { d: "M9 21H3v-6" }),
|
|
1751
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 3l-7 7" }),
|
|
1752
|
+
/* @__PURE__ */ jsx3("path", { d: "M3 21l7-7" })
|
|
1753
|
+
] });
|
|
1754
|
+
}
|
|
1755
|
+
function RestoreIcon(props) {
|
|
1756
|
+
return /* @__PURE__ */ jsxs("svg", { ...base(props), children: [
|
|
1757
|
+
/* @__PURE__ */ jsx3("path", { d: "M4 14h6v6" }),
|
|
1758
|
+
/* @__PURE__ */ jsx3("path", { d: "M20 10h-6V4" }),
|
|
1759
|
+
/* @__PURE__ */ jsx3("path", { d: "M14 10l7-7" }),
|
|
1760
|
+
/* @__PURE__ */ jsx3("path", { d: "M3 21l7-7" })
|
|
1761
|
+
] });
|
|
1762
|
+
}
|
|
1763
|
+
function GripResizeIcon(props) {
|
|
1764
|
+
return /* @__PURE__ */ jsxs("svg", { ...base(props), children: [
|
|
1765
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 15 15 21" }),
|
|
1766
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 20 20 21" })
|
|
1767
|
+
] });
|
|
1768
|
+
}
|
|
1536
1769
|
|
|
1537
|
-
// src/react/components/
|
|
1770
|
+
// src/react/components/DefaultWindowShell.tsx
|
|
1538
1771
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1772
|
+
var DEFAULT_WIDTH = 440;
|
|
1773
|
+
var DEFAULT_HEIGHT = 580;
|
|
1774
|
+
var MIN_WIDTH = 330;
|
|
1775
|
+
var MIN_HEIGHT = 380;
|
|
1776
|
+
var MOBILE_MAX_WIDTH = 640;
|
|
1777
|
+
var EDGE_KEEP = 48;
|
|
1778
|
+
function viewport() {
|
|
1779
|
+
if (typeof window === "undefined") {
|
|
1780
|
+
return { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
|
|
1781
|
+
}
|
|
1782
|
+
return { width: window.innerWidth, height: window.innerHeight };
|
|
1783
|
+
}
|
|
1784
|
+
function clamp(rect) {
|
|
1785
|
+
const { width: vw, height: vh } = viewport();
|
|
1786
|
+
const width = Math.min(Math.max(rect.width, MIN_WIDTH), Math.max(vw, MIN_WIDTH));
|
|
1787
|
+
const height = Math.min(
|
|
1788
|
+
Math.max(rect.height, MIN_HEIGHT),
|
|
1789
|
+
Math.max(vh, MIN_HEIGHT)
|
|
1790
|
+
);
|
|
1791
|
+
return {
|
|
1792
|
+
width,
|
|
1793
|
+
height,
|
|
1794
|
+
x: Math.min(Math.max(rect.x, EDGE_KEEP - width), Math.max(vw - EDGE_KEEP, 0)),
|
|
1795
|
+
y: Math.min(Math.max(rect.y, 0), Math.max(vh - EDGE_KEEP, 0))
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
function centred() {
|
|
1799
|
+
const { width: vw, height: vh } = viewport();
|
|
1800
|
+
const width = Math.min(DEFAULT_WIDTH, Math.max(vw - 32, MIN_WIDTH));
|
|
1801
|
+
const height = Math.min(DEFAULT_HEIGHT, Math.max(vh - 32, MIN_HEIGHT));
|
|
1802
|
+
return clamp({
|
|
1803
|
+
width,
|
|
1804
|
+
height,
|
|
1805
|
+
x: Math.round((vw - width) / 2),
|
|
1806
|
+
y: Math.round((vh - height) / 2)
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
function DefaultWindowShell({
|
|
1810
|
+
id,
|
|
1811
|
+
title,
|
|
1812
|
+
onClose,
|
|
1813
|
+
icon,
|
|
1814
|
+
children,
|
|
1815
|
+
className
|
|
1816
|
+
}) {
|
|
1817
|
+
const panelRef = useRef7(null);
|
|
1818
|
+
const [mounted, setMounted] = useState6(false);
|
|
1819
|
+
const [isMobile, setIsMobile] = useState6(false);
|
|
1820
|
+
const [rect, setRect] = useState6(() => centred());
|
|
1821
|
+
const [maximized, setMaximized] = useState6(false);
|
|
1822
|
+
const gesture = useRef7(null);
|
|
1823
|
+
useLayoutEffect2(() => {
|
|
1824
|
+
setMounted(true);
|
|
1825
|
+
setIsMobile(window.innerWidth < MOBILE_MAX_WIDTH);
|
|
1826
|
+
setRect(centred());
|
|
1827
|
+
}, []);
|
|
1828
|
+
useEffect9(() => {
|
|
1829
|
+
if (!mounted) return;
|
|
1830
|
+
const onResize = () => {
|
|
1831
|
+
setIsMobile(window.innerWidth < MOBILE_MAX_WIDTH);
|
|
1832
|
+
setRect((current) => clamp(current));
|
|
1833
|
+
};
|
|
1834
|
+
window.addEventListener("resize", onResize);
|
|
1835
|
+
return () => window.removeEventListener("resize", onResize);
|
|
1836
|
+
}, [mounted]);
|
|
1837
|
+
useEffect9(() => {
|
|
1838
|
+
const onKeyDown = (event) => {
|
|
1839
|
+
if (event.key === "Escape") onClose();
|
|
1840
|
+
};
|
|
1841
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1842
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
1843
|
+
}, [onClose]);
|
|
1844
|
+
useEffect9(() => {
|
|
1845
|
+
panelRef.current?.focus({ preventScroll: true });
|
|
1846
|
+
}, [mounted]);
|
|
1847
|
+
const beginGesture = useCallback2(
|
|
1848
|
+
(mode) => (event) => {
|
|
1849
|
+
if (isMobile || maximized || event.button !== 0) return;
|
|
1850
|
+
event.preventDefault();
|
|
1851
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1852
|
+
gesture.current = {
|
|
1853
|
+
mode,
|
|
1854
|
+
pointerId: event.pointerId,
|
|
1855
|
+
startX: event.clientX,
|
|
1856
|
+
startY: event.clientY,
|
|
1857
|
+
origin: rect
|
|
1858
|
+
};
|
|
1859
|
+
},
|
|
1860
|
+
[isMobile, maximized, rect]
|
|
1861
|
+
);
|
|
1862
|
+
const onPointerMove = useCallback2((event) => {
|
|
1863
|
+
const active = gesture.current;
|
|
1864
|
+
if (!active || active.pointerId !== event.pointerId) return;
|
|
1865
|
+
const dx = event.clientX - active.startX;
|
|
1866
|
+
const dy = event.clientY - active.startY;
|
|
1867
|
+
setRect(
|
|
1868
|
+
clamp(
|
|
1869
|
+
active.mode === "move" ? { ...active.origin, x: active.origin.x + dx, y: active.origin.y + dy } : {
|
|
1870
|
+
...active.origin,
|
|
1871
|
+
width: active.origin.width + dx,
|
|
1872
|
+
height: active.origin.height + dy
|
|
1873
|
+
}
|
|
1874
|
+
)
|
|
1875
|
+
);
|
|
1876
|
+
}, []);
|
|
1877
|
+
const endGesture = useCallback2((event) => {
|
|
1878
|
+
const active = gesture.current;
|
|
1879
|
+
if (!active || active.pointerId !== event.pointerId) return;
|
|
1880
|
+
gesture.current = null;
|
|
1881
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
1882
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
1883
|
+
}
|
|
1884
|
+
}, []);
|
|
1885
|
+
if (!mounted || typeof document === "undefined") return null;
|
|
1886
|
+
const labelId = `assoc-window-title:${id}`;
|
|
1887
|
+
const style = isMobile ? {} : maximized ? { inset: "1rem", width: "auto", height: "auto" } : {
|
|
1888
|
+
left: rect.x,
|
|
1889
|
+
top: rect.y,
|
|
1890
|
+
width: rect.width,
|
|
1891
|
+
height: rect.height
|
|
1892
|
+
};
|
|
1893
|
+
return createPortal(
|
|
1894
|
+
/* @__PURE__ */ jsxs2(
|
|
1895
|
+
"div",
|
|
1896
|
+
{
|
|
1897
|
+
ref: panelRef,
|
|
1898
|
+
role: "dialog",
|
|
1899
|
+
"aria-labelledby": labelId,
|
|
1900
|
+
tabIndex: -1,
|
|
1901
|
+
style,
|
|
1902
|
+
className: cn(
|
|
1903
|
+
// Non-modal by design: no backdrop element exists, so the page
|
|
1904
|
+
// behind keeps every click. `pointer-events-auto` re-asserts our
|
|
1905
|
+
// own subtree in case a Radix surface left <body> inert.
|
|
1906
|
+
"pointer-events-auto fixed z-50 flex flex-col overflow-hidden border border-border bg-card text-card-foreground shadow-xl outline-none",
|
|
1907
|
+
isMobile ? "inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl" : "rounded-xl",
|
|
1908
|
+
className
|
|
1909
|
+
),
|
|
1910
|
+
children: [
|
|
1911
|
+
/* @__PURE__ */ jsxs2(
|
|
1912
|
+
"header",
|
|
1913
|
+
{
|
|
1914
|
+
onPointerDown: beginGesture("move"),
|
|
1915
|
+
onPointerMove,
|
|
1916
|
+
onPointerUp: endGesture,
|
|
1917
|
+
onPointerCancel: endGesture,
|
|
1918
|
+
onDoubleClick: () => {
|
|
1919
|
+
if (!isMobile) setMaximized((v) => !v);
|
|
1920
|
+
},
|
|
1921
|
+
className: cn(
|
|
1922
|
+
"flex shrink-0 items-center justify-between gap-2 border-b border-border px-3 py-2 select-none",
|
|
1923
|
+
isMobile ? "" : "cursor-move touch-none"
|
|
1924
|
+
),
|
|
1925
|
+
children: [
|
|
1926
|
+
/* @__PURE__ */ jsxs2(
|
|
1927
|
+
"span",
|
|
1928
|
+
{
|
|
1929
|
+
id: labelId,
|
|
1930
|
+
className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-foreground",
|
|
1931
|
+
children: [
|
|
1932
|
+
icon,
|
|
1933
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate", children: title })
|
|
1934
|
+
]
|
|
1935
|
+
}
|
|
1936
|
+
),
|
|
1937
|
+
/* @__PURE__ */ jsxs2("span", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
1938
|
+
isMobile ? null : /* @__PURE__ */ jsx4(
|
|
1939
|
+
"button",
|
|
1940
|
+
{
|
|
1941
|
+
type: "button",
|
|
1942
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
1943
|
+
onClick: () => setMaximized((v) => !v),
|
|
1944
|
+
"aria-label": maximized ? "Restore window" : "Maximize window",
|
|
1945
|
+
className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1946
|
+
children: maximized ? /* @__PURE__ */ jsx4(RestoreIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx4(MaximizeIcon, { className: "h-3.5 w-3.5" })
|
|
1947
|
+
}
|
|
1948
|
+
),
|
|
1949
|
+
/* @__PURE__ */ jsx4(
|
|
1950
|
+
"button",
|
|
1951
|
+
{
|
|
1952
|
+
type: "button",
|
|
1953
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
1954
|
+
onClick: onClose,
|
|
1955
|
+
"aria-label": "Close",
|
|
1956
|
+
className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1957
|
+
children: /* @__PURE__ */ jsx4(XIcon, { className: "h-3.5 w-3.5" })
|
|
1958
|
+
}
|
|
1959
|
+
)
|
|
1960
|
+
] })
|
|
1961
|
+
]
|
|
1962
|
+
}
|
|
1963
|
+
),
|
|
1964
|
+
/* @__PURE__ */ jsx4("div", { className: "min-h-0 flex-1 overflow-hidden", children }),
|
|
1965
|
+
isMobile || maximized ? null : /* @__PURE__ */ jsx4(
|
|
1966
|
+
"button",
|
|
1967
|
+
{
|
|
1968
|
+
type: "button",
|
|
1969
|
+
"aria-label": "Resize window",
|
|
1970
|
+
onPointerDown: beginGesture("resize"),
|
|
1971
|
+
onPointerMove,
|
|
1972
|
+
onPointerUp: endGesture,
|
|
1973
|
+
onPointerCancel: endGesture,
|
|
1974
|
+
className: "absolute bottom-0 right-0 flex h-4 w-4 cursor-nwse-resize touch-none items-center justify-center text-muted-foreground/60 hover:text-foreground",
|
|
1975
|
+
children: /* @__PURE__ */ jsx4(GripResizeIcon, { className: "h-3 w-3" })
|
|
1976
|
+
}
|
|
1977
|
+
)
|
|
1978
|
+
]
|
|
1979
|
+
}
|
|
1980
|
+
),
|
|
1981
|
+
document.body
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// src/react/components/AssociationWindow.tsx
|
|
1986
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1539
1987
|
function AssociationWindow({
|
|
1540
1988
|
open,
|
|
1541
1989
|
onClose,
|
|
@@ -1548,78 +1996,51 @@ function AssociationWindow({
|
|
|
1548
1996
|
const instanceId = useId();
|
|
1549
1997
|
const { windowShell } = useAssociationsUiPorts();
|
|
1550
1998
|
if (!open) return null;
|
|
1551
|
-
const body = /* @__PURE__ */
|
|
1552
|
-
subtitle ? /* @__PURE__ */
|
|
1999
|
+
const body = /* @__PURE__ */ jsxs3("div", { className: "flex h-full min-h-0 flex-col gap-2 p-3", children: [
|
|
2000
|
+
subtitle ? /* @__PURE__ */ jsx5("div", { className: "shrink-0 text-xs text-muted-foreground", children: subtitle }) : null,
|
|
1553
2001
|
children
|
|
1554
2002
|
] });
|
|
2003
|
+
const windowId = `association:${scopeId}:${instanceId}`;
|
|
1555
2004
|
if (windowShell) {
|
|
1556
2005
|
const HostWindow = windowShell.Window;
|
|
1557
|
-
return /* @__PURE__ */
|
|
1558
|
-
HostWindow,
|
|
1559
|
-
{
|
|
1560
|
-
id: `association:${scopeId}:${instanceId}`,
|
|
1561
|
-
title,
|
|
1562
|
-
onClose,
|
|
1563
|
-
children: body
|
|
1564
|
-
}
|
|
1565
|
-
);
|
|
2006
|
+
return /* @__PURE__ */ jsx5(HostWindow, { id: windowId, title, onClose, children: body });
|
|
1566
2007
|
}
|
|
1567
|
-
return /* @__PURE__ */
|
|
1568
|
-
|
|
2008
|
+
return /* @__PURE__ */ jsx5(
|
|
2009
|
+
DefaultWindowShell,
|
|
1569
2010
|
{
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
style: { height: "min(580px, 85dvh)" },
|
|
1576
|
-
children: [
|
|
1577
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
|
|
1578
|
-
/* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-foreground", children: [
|
|
1579
|
-
icon,
|
|
1580
|
-
/* @__PURE__ */ jsx4("span", { className: "truncate", children: title })
|
|
1581
|
-
] }),
|
|
1582
|
-
/* @__PURE__ */ jsx4(
|
|
1583
|
-
"button",
|
|
1584
|
-
{
|
|
1585
|
-
type: "button",
|
|
1586
|
-
onClick: onClose,
|
|
1587
|
-
"aria-label": "Close",
|
|
1588
|
-
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1589
|
-
children: /* @__PURE__ */ jsx4(XIcon, { className: "h-3.5 w-3.5" })
|
|
1590
|
-
}
|
|
1591
|
-
)
|
|
1592
|
-
] }),
|
|
1593
|
-
/* @__PURE__ */ jsx4("div", { className: "min-h-0 flex-1", children: body })
|
|
1594
|
-
]
|
|
2011
|
+
id: windowId,
|
|
2012
|
+
title,
|
|
2013
|
+
onClose,
|
|
2014
|
+
...icon !== void 0 ? { icon } : {},
|
|
2015
|
+
children: body
|
|
1595
2016
|
}
|
|
1596
2017
|
);
|
|
1597
2018
|
}
|
|
1598
2019
|
|
|
1599
2020
|
// src/react/components/AssociationPicker.tsx
|
|
1600
|
-
import { useState as
|
|
2021
|
+
import { useState as useState7 } from "react";
|
|
1601
2022
|
import { cn as cn2, Input } from "@ai-matrx/design-system";
|
|
1602
|
-
import { Fragment, jsx as
|
|
2023
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1603
2024
|
function AssociationPicker(props) {
|
|
1604
2025
|
const store = useAssociationsStore();
|
|
1605
2026
|
const { pickerOverrides } = useAssociationsUiPorts();
|
|
1606
2027
|
const info = store.registry.getEntityInfo(props.token);
|
|
1607
2028
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
1608
2029
|
const Override = pickerOverrides?.[props.token];
|
|
1609
|
-
if (Override) return /* @__PURE__ */
|
|
2030
|
+
if (Override) return /* @__PURE__ */ jsx6(Override, { ...props });
|
|
1610
2031
|
const title = `Add ${info.labelPlural}`;
|
|
1611
2032
|
const subtitle = props.containerLabel ? `Attach to ${props.containerLabel}` : "Click an item to attach or detach it";
|
|
1612
2033
|
if (!props.open) return null;
|
|
1613
|
-
return /* @__PURE__ */
|
|
2034
|
+
return /* @__PURE__ */ jsx6(
|
|
1614
2035
|
AssociationWindow,
|
|
1615
2036
|
{
|
|
1616
2037
|
open: props.open,
|
|
1617
2038
|
onClose: () => props.onOpenChange(false),
|
|
1618
2039
|
scopeId: `picker:${props.token}`,
|
|
1619
2040
|
title,
|
|
1620
|
-
icon: /* @__PURE__ */
|
|
2041
|
+
icon: /* @__PURE__ */ jsx6(Icon, { className: "size-3.5 text-primary" }),
|
|
1621
2042
|
subtitle,
|
|
1622
|
-
children: /* @__PURE__ */
|
|
2043
|
+
children: /* @__PURE__ */ jsx6(
|
|
1623
2044
|
AssociationCandidateBody,
|
|
1624
2045
|
{
|
|
1625
2046
|
token: props.token,
|
|
@@ -1644,7 +2065,7 @@ function AssociationCandidateBody({
|
|
|
1644
2065
|
onClose
|
|
1645
2066
|
}) {
|
|
1646
2067
|
void onClose;
|
|
1647
|
-
return /* @__PURE__ */
|
|
2068
|
+
return /* @__PURE__ */ jsx6(
|
|
1648
2069
|
EntityCandidateList,
|
|
1649
2070
|
{
|
|
1650
2071
|
token,
|
|
@@ -1666,8 +2087,8 @@ function EntityCandidateList({
|
|
|
1666
2087
|
}) {
|
|
1667
2088
|
const store = useAssociationsStore();
|
|
1668
2089
|
const notifier = useNotifier();
|
|
1669
|
-
const [search, setSearch] =
|
|
1670
|
-
const [busyId, setBusyId] =
|
|
2090
|
+
const [search, setSearch] = useState7("");
|
|
2091
|
+
const [busyId, setBusyId] = useState7(null);
|
|
1671
2092
|
const info = store.registry.getEntityInfo(token);
|
|
1672
2093
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
1673
2094
|
const { candidates, loading, error, reload } = useAssociationCandidates({
|
|
@@ -1691,10 +2112,10 @@ function EntityCandidateList({
|
|
|
1691
2112
|
setBusyId(null);
|
|
1692
2113
|
}
|
|
1693
2114
|
};
|
|
1694
|
-
return /* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
1696
|
-
/* @__PURE__ */
|
|
1697
|
-
/* @__PURE__ */
|
|
2115
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
2116
|
+
/* @__PURE__ */ jsxs4("div", { className: "relative mb-2", children: [
|
|
2117
|
+
/* @__PURE__ */ jsx6(SearchIcon, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
2118
|
+
/* @__PURE__ */ jsx6(
|
|
1698
2119
|
Input,
|
|
1699
2120
|
{
|
|
1700
2121
|
value: search,
|
|
@@ -1705,13 +2126,13 @@ function EntityCandidateList({
|
|
|
1705
2126
|
}
|
|
1706
2127
|
)
|
|
1707
2128
|
] }),
|
|
1708
|
-
/* @__PURE__ */
|
|
1709
|
-
/* @__PURE__ */
|
|
2129
|
+
/* @__PURE__ */ jsx6("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: loading && candidates.length === 0 ? /* @__PURE__ */ jsxs4(ListMessage, { children: [
|
|
2130
|
+
/* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
|
|
1710
2131
|
"Loading\u2026"
|
|
1711
|
-
] }) : error ? /* @__PURE__ */
|
|
1712
|
-
/* @__PURE__ */
|
|
1713
|
-
/* @__PURE__ */
|
|
1714
|
-
/* @__PURE__ */
|
|
2132
|
+
] }) : error ? /* @__PURE__ */ jsxs4("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
|
|
2133
|
+
/* @__PURE__ */ jsx6("p", { className: "font-medium", children: "Couldn\u2019t load items" }),
|
|
2134
|
+
/* @__PURE__ */ jsx6("p", { className: "opacity-80", children: error }),
|
|
2135
|
+
/* @__PURE__ */ jsx6(
|
|
1715
2136
|
"button",
|
|
1716
2137
|
{
|
|
1717
2138
|
type: "button",
|
|
@@ -1720,10 +2141,10 @@ function EntityCandidateList({
|
|
|
1720
2141
|
children: "Retry"
|
|
1721
2142
|
}
|
|
1722
2143
|
)
|
|
1723
|
-
] }) : candidates.length === 0 ? /* @__PURE__ */
|
|
2144
|
+
] }) : candidates.length === 0 ? /* @__PURE__ */ jsx6(ListMessage, { children: canCreate ? `Nothing to attach yet \u2014 create a new ${info.label.toLowerCase()} below.` : "Nothing to attach." }) : /* @__PURE__ */ jsx6("ul", { className: "space-y-0.5", children: candidates.map((c) => {
|
|
1724
2145
|
const attached = attachedIds.has(c.id);
|
|
1725
2146
|
const busy = busyId === c.id;
|
|
1726
|
-
return /* @__PURE__ */
|
|
2147
|
+
return /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsxs4(
|
|
1727
2148
|
"button",
|
|
1728
2149
|
{
|
|
1729
2150
|
type: "button",
|
|
@@ -1735,23 +2156,23 @@ function EntityCandidateList({
|
|
|
1735
2156
|
attached && "bg-accent/40"
|
|
1736
2157
|
),
|
|
1737
2158
|
children: [
|
|
1738
|
-
/* @__PURE__ */
|
|
1739
|
-
/* @__PURE__ */
|
|
1740
|
-
/* @__PURE__ */
|
|
2159
|
+
/* @__PURE__ */ jsx6(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
2160
|
+
/* @__PURE__ */ jsx6("span", { className: "flex-1 min-w-0 truncate text-foreground", children: c.title }),
|
|
2161
|
+
/* @__PURE__ */ jsx6(
|
|
1741
2162
|
"span",
|
|
1742
2163
|
{
|
|
1743
2164
|
className: cn2(
|
|
1744
2165
|
"flex h-5 w-5 items-center justify-center rounded-full shrink-0",
|
|
1745
2166
|
attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
|
|
1746
2167
|
),
|
|
1747
|
-
children: busy ? /* @__PURE__ */
|
|
2168
|
+
children: busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx6(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx6(PlusIcon, { className: "h-3 w-3" })
|
|
1748
2169
|
}
|
|
1749
2170
|
)
|
|
1750
2171
|
]
|
|
1751
2172
|
}
|
|
1752
2173
|
) }, c.id);
|
|
1753
2174
|
}) }) }),
|
|
1754
|
-
canCreate && /* @__PURE__ */
|
|
2175
|
+
canCreate && /* @__PURE__ */ jsx6(
|
|
1755
2176
|
CreateAndAttachFooter,
|
|
1756
2177
|
{
|
|
1757
2178
|
token,
|
|
@@ -1773,9 +2194,9 @@ function CreateAndAttachFooter({
|
|
|
1773
2194
|
const store = useAssociationsStore();
|
|
1774
2195
|
const notifier = useNotifier();
|
|
1775
2196
|
const info = store.registry.getEntityInfo(token);
|
|
1776
|
-
const [editing, setEditing] =
|
|
1777
|
-
const [name, setName] =
|
|
1778
|
-
const [busy, setBusy] =
|
|
2197
|
+
const [editing, setEditing] = useState7(false);
|
|
2198
|
+
const [name, setName] = useState7("");
|
|
2199
|
+
const [busy, setBusy] = useState7(false);
|
|
1779
2200
|
const submit = async () => {
|
|
1780
2201
|
const title = name.trim();
|
|
1781
2202
|
if (!title || busy) return;
|
|
@@ -1810,7 +2231,7 @@ function CreateAndAttachFooter({
|
|
|
1810
2231
|
}
|
|
1811
2232
|
};
|
|
1812
2233
|
if (!editing) {
|
|
1813
|
-
return /* @__PURE__ */
|
|
2234
|
+
return /* @__PURE__ */ jsxs4(
|
|
1814
2235
|
"button",
|
|
1815
2236
|
{
|
|
1816
2237
|
type: "button",
|
|
@@ -1820,10 +2241,10 @@ function CreateAndAttachFooter({
|
|
|
1820
2241
|
},
|
|
1821
2242
|
className: "mt-2 flex min-h-11 w-full shrink-0 items-center justify-center gap-1.5 rounded-md border border-dashed border-border px-3 py-2 text-sm text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground md:min-h-0",
|
|
1822
2243
|
children: [
|
|
1823
|
-
/* @__PURE__ */
|
|
2244
|
+
/* @__PURE__ */ jsx6(PlusIcon, { className: "h-4 w-4" }),
|
|
1824
2245
|
"New ",
|
|
1825
2246
|
info.label,
|
|
1826
|
-
seed ? /* @__PURE__ */
|
|
2247
|
+
seed ? /* @__PURE__ */ jsxs4("span", { className: "max-w-40 truncate text-muted-foreground/70", children: [
|
|
1827
2248
|
"\u201C",
|
|
1828
2249
|
seed,
|
|
1829
2250
|
"\u201D"
|
|
@@ -1832,8 +2253,8 @@ function CreateAndAttachFooter({
|
|
|
1832
2253
|
}
|
|
1833
2254
|
);
|
|
1834
2255
|
}
|
|
1835
|
-
return /* @__PURE__ */
|
|
1836
|
-
/* @__PURE__ */
|
|
2256
|
+
return /* @__PURE__ */ jsxs4("div", { className: "mt-2 flex shrink-0 items-center gap-1.5", children: [
|
|
2257
|
+
/* @__PURE__ */ jsx6(
|
|
1837
2258
|
Input,
|
|
1838
2259
|
{
|
|
1839
2260
|
autoFocus: true,
|
|
@@ -1852,17 +2273,17 @@ function CreateAndAttachFooter({
|
|
|
1852
2273
|
style: { fontSize: 16 }
|
|
1853
2274
|
}
|
|
1854
2275
|
),
|
|
1855
|
-
/* @__PURE__ */
|
|
2276
|
+
/* @__PURE__ */ jsx6(
|
|
1856
2277
|
"button",
|
|
1857
2278
|
{
|
|
1858
2279
|
type: "button",
|
|
1859
2280
|
disabled: busy || !name.trim(),
|
|
1860
2281
|
onClick: () => void submit(),
|
|
1861
2282
|
className: "flex h-11 items-center gap-1 rounded-md bg-primary px-2.5 text-sm font-medium text-primary-foreground transition-opacity disabled:opacity-50 md:h-8",
|
|
1862
|
-
children: busy ? /* @__PURE__ */
|
|
2283
|
+
children: busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : "Create"
|
|
1863
2284
|
}
|
|
1864
2285
|
),
|
|
1865
|
-
/* @__PURE__ */
|
|
2286
|
+
/* @__PURE__ */ jsx6(
|
|
1866
2287
|
"button",
|
|
1867
2288
|
{
|
|
1868
2289
|
type: "button",
|
|
@@ -1873,38 +2294,122 @@ function CreateAndAttachFooter({
|
|
|
1873
2294
|
},
|
|
1874
2295
|
title: "Cancel",
|
|
1875
2296
|
className: "flex h-11 w-11 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50 md:h-8 md:w-8",
|
|
1876
|
-
children: /* @__PURE__ */
|
|
2297
|
+
children: /* @__PURE__ */ jsx6(XIcon, { className: "h-4 w-4" })
|
|
1877
2298
|
}
|
|
1878
2299
|
)
|
|
1879
2300
|
] });
|
|
1880
2301
|
}
|
|
1881
2302
|
function ListMessage({ children }) {
|
|
1882
|
-
return /* @__PURE__ */
|
|
2303
|
+
return /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children });
|
|
1883
2304
|
}
|
|
1884
2305
|
|
|
1885
2306
|
// src/react/components/UniversalAssociationPicker.tsx
|
|
1886
|
-
import { useState as
|
|
1887
|
-
import { cn as
|
|
1888
|
-
|
|
2307
|
+
import { useState as useState8 } from "react";
|
|
2308
|
+
import { cn as cn4, Input as Input2 } from "@ai-matrx/design-system";
|
|
2309
|
+
|
|
2310
|
+
// src/react/components/entityDoors.tsx
|
|
2311
|
+
import { cn as cn3 } from "@ai-matrx/design-system";
|
|
2312
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2313
|
+
function DoorRef(props) {
|
|
2314
|
+
const { onOpen, ...refProps } = props;
|
|
2315
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
2316
|
+
const store = useAssociationsStore();
|
|
2317
|
+
const HostRef = entityDoors?.EntityRef;
|
|
2318
|
+
if (HostRef) return /* @__PURE__ */ jsx7(HostRef, { ...refProps });
|
|
2319
|
+
const name = refProps.name ?? null;
|
|
2320
|
+
const href = store.registry.tryGetEntityInfo(refProps.token)?.hrefFor?.(refProps.id) ?? null;
|
|
2321
|
+
if (onOpen) {
|
|
2322
|
+
return /* @__PURE__ */ jsx7(
|
|
2323
|
+
"button",
|
|
2324
|
+
{
|
|
2325
|
+
type: "button",
|
|
2326
|
+
onClick: onOpen,
|
|
2327
|
+
className: cn3(
|
|
2328
|
+
"min-w-0 truncate text-left underline-offset-2 hover:underline",
|
|
2329
|
+
refProps.className
|
|
2330
|
+
),
|
|
2331
|
+
children: name
|
|
2332
|
+
}
|
|
2333
|
+
);
|
|
2334
|
+
}
|
|
2335
|
+
if (href) {
|
|
2336
|
+
return /* @__PURE__ */ jsxs5(
|
|
2337
|
+
"a",
|
|
2338
|
+
{
|
|
2339
|
+
href,
|
|
2340
|
+
target: refProps.openInNewTab === false ? void 0 : "_blank",
|
|
2341
|
+
rel: "noopener noreferrer",
|
|
2342
|
+
className: cn3(
|
|
2343
|
+
"inline-flex min-w-0 items-center gap-1 truncate underline-offset-2 hover:underline",
|
|
2344
|
+
refProps.className
|
|
2345
|
+
),
|
|
2346
|
+
children: [
|
|
2347
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: name }),
|
|
2348
|
+
/* @__PURE__ */ jsx7(ExternalLinkIcon, { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-60" })
|
|
2349
|
+
]
|
|
2350
|
+
}
|
|
2351
|
+
);
|
|
2352
|
+
}
|
|
2353
|
+
return /* @__PURE__ */ jsx7("span", { className: cn3("min-w-0 truncate", refProps.className), children: name });
|
|
2354
|
+
}
|
|
2355
|
+
function UnresolvedRef({ token, id }) {
|
|
2356
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
2357
|
+
const HostUnresolved = entityDoors?.UnresolvedRef;
|
|
2358
|
+
if (HostUnresolved) return /* @__PURE__ */ jsx7(HostUnresolved, { token, id });
|
|
2359
|
+
return /* @__PURE__ */ jsx7(
|
|
2360
|
+
"span",
|
|
2361
|
+
{
|
|
2362
|
+
className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 text-[11px] text-muted-foreground",
|
|
2363
|
+
title: `This ${token} could not be read \u2014 it may be deleted or not shared with you.`,
|
|
2364
|
+
children: "Unavailable"
|
|
2365
|
+
}
|
|
2366
|
+
);
|
|
2367
|
+
}
|
|
2368
|
+
function DoorControlsSlot(props) {
|
|
2369
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
2370
|
+
const store = useAssociationsStore();
|
|
2371
|
+
const HostControls = entityDoors?.DoorControls;
|
|
2372
|
+
if (HostControls) return /* @__PURE__ */ jsx7(HostControls, { ...props });
|
|
2373
|
+
const href = store.registry.tryGetEntityInfo(props.token)?.hrefFor?.(props.id) ?? null;
|
|
2374
|
+
if (!href) return null;
|
|
2375
|
+
const label = props.name ? `Open ${props.name}` : `Open this ${props.token}`;
|
|
2376
|
+
return /* @__PURE__ */ jsx7(
|
|
2377
|
+
"a",
|
|
2378
|
+
{
|
|
2379
|
+
href,
|
|
2380
|
+
target: "_blank",
|
|
2381
|
+
rel: "noopener noreferrer",
|
|
2382
|
+
"aria-label": label,
|
|
2383
|
+
title: label,
|
|
2384
|
+
className: cn3(
|
|
2385
|
+
"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
2386
|
+
props.className
|
|
2387
|
+
),
|
|
2388
|
+
children: /* @__PURE__ */ jsx7(ExternalLinkIcon, { className: "h-3 w-3" })
|
|
2389
|
+
}
|
|
2390
|
+
);
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
// src/react/components/UniversalAssociationPicker.tsx
|
|
2394
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1889
2395
|
function attachedKey(token, id) {
|
|
1890
2396
|
return `${token}:${id}`;
|
|
1891
2397
|
}
|
|
1892
2398
|
function UniversalAssociationPicker(props) {
|
|
1893
2399
|
const { attachedKeys, onAttach, onDetach, ownerId, orgId, className } = props;
|
|
1894
2400
|
const store = useAssociationsStore();
|
|
1895
|
-
const {
|
|
2401
|
+
const { pickerOverrides } = useAssociationsUiPorts();
|
|
1896
2402
|
const notifier = useNotifier();
|
|
1897
2403
|
const tokens = props.tokens ?? store.registry.curatedTokens();
|
|
1898
|
-
const [query, setQuery] =
|
|
1899
|
-
const [browseToken, setBrowseToken] =
|
|
1900
|
-
const [busyKey, setBusyKey] =
|
|
2404
|
+
const [query, setQuery] = useState8("");
|
|
2405
|
+
const [browseToken, setBrowseToken] = useState8(null);
|
|
2406
|
+
const [busyKey, setBusyKey] = useState8(null);
|
|
1901
2407
|
const { results, loading, isRecents } = useUniversalEntitySearch({
|
|
1902
2408
|
query,
|
|
1903
2409
|
tokens,
|
|
1904
2410
|
ownerId: ownerId ?? null,
|
|
1905
2411
|
enabled: browseToken === null
|
|
1906
2412
|
});
|
|
1907
|
-
const DoorControls = entityDoors?.DoorControls;
|
|
1908
2413
|
const toggle = async (c) => {
|
|
1909
2414
|
const key = attachedKey(c.token, c.id);
|
|
1910
2415
|
if (busyKey) return;
|
|
@@ -1928,10 +2433,10 @@ function UniversalAssociationPicker(props) {
|
|
|
1928
2433
|
groups.set(r.token, list);
|
|
1929
2434
|
}
|
|
1930
2435
|
const BrowseOverride = browseToken ? pickerOverrides?.[browseToken] : void 0;
|
|
1931
|
-
return /* @__PURE__ */
|
|
1932
|
-
/* @__PURE__ */
|
|
1933
|
-
/* @__PURE__ */
|
|
1934
|
-
/* @__PURE__ */
|
|
2436
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn4("flex min-h-0 flex-1 flex-col gap-2", className), children: [
|
|
2437
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative", children: [
|
|
2438
|
+
/* @__PURE__ */ jsx8(SearchIcon, { className: "absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
2439
|
+
/* @__PURE__ */ jsx8(
|
|
1935
2440
|
Input2,
|
|
1936
2441
|
{
|
|
1937
2442
|
value: query,
|
|
@@ -1944,23 +2449,23 @@ function UniversalAssociationPicker(props) {
|
|
|
1944
2449
|
style: { fontSize: 16 }
|
|
1945
2450
|
}
|
|
1946
2451
|
),
|
|
1947
|
-
loading && browseToken === null && /* @__PURE__ */
|
|
2452
|
+
loading && browseToken === null && /* @__PURE__ */ jsx8(SpinnerIcon, { className: "absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-muted-foreground" })
|
|
1948
2453
|
] }),
|
|
1949
|
-
/* @__PURE__ */
|
|
2454
|
+
/* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-1", children: tokens.map((t) => {
|
|
1950
2455
|
const info = store.registry.getEntityInfo(t);
|
|
1951
2456
|
const ChipIcon = info.Icon ?? DefaultEntityIcon;
|
|
1952
2457
|
const active = browseToken === t;
|
|
1953
|
-
return /* @__PURE__ */
|
|
2458
|
+
return /* @__PURE__ */ jsxs6(
|
|
1954
2459
|
"button",
|
|
1955
2460
|
{
|
|
1956
2461
|
type: "button",
|
|
1957
2462
|
onClick: () => setBrowseToken(active ? null : t),
|
|
1958
|
-
className:
|
|
2463
|
+
className: cn4(
|
|
1959
2464
|
"inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-[11px] transition-colors",
|
|
1960
2465
|
active ? "border-primary/50 bg-primary/10 text-foreground" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent"
|
|
1961
2466
|
),
|
|
1962
2467
|
children: [
|
|
1963
|
-
/* @__PURE__ */
|
|
2468
|
+
/* @__PURE__ */ jsx8(ChipIcon, { className: "h-3 w-3" }),
|
|
1964
2469
|
info.labelPlural
|
|
1965
2470
|
]
|
|
1966
2471
|
},
|
|
@@ -1970,7 +2475,7 @@ function UniversalAssociationPicker(props) {
|
|
|
1970
2475
|
browseToken && BrowseOverride ? (
|
|
1971
2476
|
// The token's canonical host picker (e.g. the stored-files browser)
|
|
1972
2477
|
// owns per-token browsing when registered — never a plain list twin.
|
|
1973
|
-
/* @__PURE__ */
|
|
2478
|
+
/* @__PURE__ */ jsx8(
|
|
1974
2479
|
BrowseOverride,
|
|
1975
2480
|
{
|
|
1976
2481
|
open: true,
|
|
@@ -1986,7 +2491,7 @@ function UniversalAssociationPicker(props) {
|
|
|
1986
2491
|
onDetach: (id) => onDetach(browseToken, id)
|
|
1987
2492
|
}
|
|
1988
2493
|
)
|
|
1989
|
-
) : browseToken ? /* @__PURE__ */
|
|
2494
|
+
) : browseToken ? /* @__PURE__ */ jsx8("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx8(
|
|
1990
2495
|
AssociationCandidateBody,
|
|
1991
2496
|
{
|
|
1992
2497
|
token: browseToken,
|
|
@@ -1999,63 +2504,63 @@ function UniversalAssociationPicker(props) {
|
|
|
1999
2504
|
onAttach: (id, title) => onAttach(browseToken, id, title),
|
|
2000
2505
|
onDetach: (id) => onDetach(browseToken, id)
|
|
2001
2506
|
}
|
|
2002
|
-
) }) : /* @__PURE__ */
|
|
2003
|
-
isRecents && /* @__PURE__ */
|
|
2507
|
+
) }) : /* @__PURE__ */ jsx8("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1", children: results.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "py-6 text-center text-[12px] text-muted-foreground", children: loading ? "Searching\u2026" : query.trim() ? "No matches \u2014 narrow with a type chip to browse." : "No recent items. Type to search, or pick a type to browse." }) : /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
|
|
2508
|
+
isRecents && /* @__PURE__ */ jsx8("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: "Recent" }),
|
|
2004
2509
|
[...groups.entries()].map(([token, items]) => {
|
|
2005
2510
|
const info = store.registry.getEntityInfo(token);
|
|
2006
2511
|
const GroupIcon = info.Icon ?? DefaultEntityIcon;
|
|
2007
|
-
return /* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2009
|
-
/* @__PURE__ */
|
|
2512
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-0.5", children: [
|
|
2513
|
+
/* @__PURE__ */ jsxs6("p", { className: "flex items-center gap-1 px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: [
|
|
2514
|
+
/* @__PURE__ */ jsx8(GroupIcon, { className: "h-3 w-3" }),
|
|
2010
2515
|
info.labelPlural
|
|
2011
2516
|
] }),
|
|
2012
|
-
/* @__PURE__ */
|
|
2517
|
+
/* @__PURE__ */ jsx8("ul", { className: "space-y-0.5", children: items.map((c) => {
|
|
2013
2518
|
const key = attachedKey(c.token, c.id);
|
|
2014
2519
|
const attached = attachedKeys.has(key);
|
|
2015
2520
|
const busy = busyKey === key;
|
|
2016
|
-
return /* @__PURE__ */
|
|
2521
|
+
return /* @__PURE__ */ jsxs6(
|
|
2017
2522
|
"li",
|
|
2018
2523
|
{
|
|
2019
|
-
className:
|
|
2524
|
+
className: cn4(
|
|
2020
2525
|
"group/entity-ref group flex items-center gap-1 rounded-md pr-1.5 transition-colors",
|
|
2021
2526
|
"hover:bg-accent",
|
|
2022
2527
|
attached && "bg-accent/40"
|
|
2023
2528
|
),
|
|
2024
2529
|
children: [
|
|
2025
|
-
/* @__PURE__ */
|
|
2530
|
+
/* @__PURE__ */ jsxs6(
|
|
2026
2531
|
"button",
|
|
2027
2532
|
{
|
|
2028
2533
|
type: "button",
|
|
2029
2534
|
disabled: busy,
|
|
2030
2535
|
onClick: () => toggle(c),
|
|
2031
2536
|
title: attached ? `Detach "${c.title}"` : `Attach "${c.title}"`,
|
|
2032
|
-
className:
|
|
2537
|
+
className: cn4(
|
|
2033
2538
|
"flex min-w-0 flex-1 items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm",
|
|
2034
2539
|
"disabled:opacity-50"
|
|
2035
2540
|
),
|
|
2036
2541
|
children: [
|
|
2037
|
-
/* @__PURE__ */
|
|
2038
|
-
/* @__PURE__ */
|
|
2542
|
+
/* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate text-foreground", children: c.title }),
|
|
2543
|
+
/* @__PURE__ */ jsx8(
|
|
2039
2544
|
"span",
|
|
2040
2545
|
{
|
|
2041
|
-
className:
|
|
2546
|
+
className: cn4(
|
|
2042
2547
|
"flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
|
|
2043
2548
|
attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
|
|
2044
2549
|
),
|
|
2045
|
-
children: busy ? /* @__PURE__ */
|
|
2550
|
+
children: busy ? /* @__PURE__ */ jsx8(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx8(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(PlusIcon, { className: "h-3 w-3" })
|
|
2046
2551
|
}
|
|
2047
2552
|
)
|
|
2048
2553
|
]
|
|
2049
2554
|
}
|
|
2050
2555
|
),
|
|
2051
|
-
|
|
2052
|
-
|
|
2556
|
+
/* @__PURE__ */ jsx8(
|
|
2557
|
+
DoorControlsSlot,
|
|
2053
2558
|
{
|
|
2054
2559
|
token: c.token,
|
|
2055
2560
|
id: c.id,
|
|
2056
2561
|
name: c.title
|
|
2057
2562
|
}
|
|
2058
|
-
)
|
|
2563
|
+
)
|
|
2059
2564
|
]
|
|
2060
2565
|
},
|
|
2061
2566
|
key
|
|
@@ -2068,79 +2573,18 @@ function UniversalAssociationPicker(props) {
|
|
|
2068
2573
|
}
|
|
2069
2574
|
|
|
2070
2575
|
// src/react/components/AttachedItemsSheet.tsx
|
|
2071
|
-
import { useEffect as
|
|
2576
|
+
import { useEffect as useEffect10, useState as useState9 } from "react";
|
|
2072
2577
|
import { cn as cn5 } from "@ai-matrx/design-system";
|
|
2073
|
-
|
|
2074
|
-
// src/react/components/entityDoors.tsx
|
|
2075
|
-
import { cn as cn4 } from "@ai-matrx/design-system";
|
|
2076
|
-
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2077
|
-
function DoorRef(props) {
|
|
2078
|
-
const { onOpen, ...refProps } = props;
|
|
2079
|
-
const { entityDoors } = useAssociationsUiPorts();
|
|
2080
|
-
const store = useAssociationsStore();
|
|
2081
|
-
const HostRef = entityDoors?.EntityRef;
|
|
2082
|
-
if (HostRef) return /* @__PURE__ */ jsx7(HostRef, { ...refProps });
|
|
2083
|
-
const name = refProps.name ?? null;
|
|
2084
|
-
const href = store.registry.tryGetEntityInfo(refProps.token)?.hrefFor?.(refProps.id) ?? null;
|
|
2085
|
-
if (onOpen) {
|
|
2086
|
-
return /* @__PURE__ */ jsx7(
|
|
2087
|
-
"button",
|
|
2088
|
-
{
|
|
2089
|
-
type: "button",
|
|
2090
|
-
onClick: onOpen,
|
|
2091
|
-
className: cn4(
|
|
2092
|
-
"min-w-0 truncate text-left underline-offset-2 hover:underline",
|
|
2093
|
-
refProps.className
|
|
2094
|
-
),
|
|
2095
|
-
children: name
|
|
2096
|
-
}
|
|
2097
|
-
);
|
|
2098
|
-
}
|
|
2099
|
-
if (href) {
|
|
2100
|
-
return /* @__PURE__ */ jsxs5(
|
|
2101
|
-
"a",
|
|
2102
|
-
{
|
|
2103
|
-
href,
|
|
2104
|
-
target: refProps.openInNewTab === false ? void 0 : "_blank",
|
|
2105
|
-
rel: "noopener noreferrer",
|
|
2106
|
-
className: cn4(
|
|
2107
|
-
"inline-flex min-w-0 items-center gap-1 truncate underline-offset-2 hover:underline",
|
|
2108
|
-
refProps.className
|
|
2109
|
-
),
|
|
2110
|
-
children: [
|
|
2111
|
-
/* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: name }),
|
|
2112
|
-
/* @__PURE__ */ jsx7(ExternalLinkIcon, { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-60" })
|
|
2113
|
-
]
|
|
2114
|
-
}
|
|
2115
|
-
);
|
|
2116
|
-
}
|
|
2117
|
-
return /* @__PURE__ */ jsx7("span", { className: cn4("min-w-0 truncate", refProps.className), children: name });
|
|
2118
|
-
}
|
|
2119
|
-
function UnresolvedRef({ token, id }) {
|
|
2120
|
-
const { entityDoors } = useAssociationsUiPorts();
|
|
2121
|
-
const HostUnresolved = entityDoors?.UnresolvedRef;
|
|
2122
|
-
if (HostUnresolved) return /* @__PURE__ */ jsx7(HostUnresolved, { token, id });
|
|
2123
|
-
return /* @__PURE__ */ jsx7(
|
|
2124
|
-
"span",
|
|
2125
|
-
{
|
|
2126
|
-
className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 text-[11px] text-muted-foreground",
|
|
2127
|
-
title: `This ${token} could not be read \u2014 it may be deleted or not shared with you.`,
|
|
2128
|
-
children: "Unavailable"
|
|
2129
|
-
}
|
|
2130
|
-
);
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2133
|
-
// src/react/components/AttachedItemsSheet.tsx
|
|
2134
|
-
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2578
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2135
2579
|
function AttachedItemsSheet(props) {
|
|
2136
2580
|
const store = useAssociationsStore();
|
|
2137
2581
|
const info = store.registry.getEntityInfo(props.token);
|
|
2138
2582
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2139
2583
|
const title = info.labelPlural;
|
|
2140
2584
|
const containerName = props.container?.label ?? props.containerLabel;
|
|
2141
|
-
const subtitle = props.container ? /* @__PURE__ */
|
|
2585
|
+
const subtitle = props.container ? /* @__PURE__ */ jsxs7("span", { className: "inline-flex min-w-0 max-w-full items-center gap-1", children: [
|
|
2142
2586
|
"Attached to",
|
|
2143
|
-
/* @__PURE__ */
|
|
2587
|
+
/* @__PURE__ */ jsx9(
|
|
2144
2588
|
DoorRef,
|
|
2145
2589
|
{
|
|
2146
2590
|
token: props.container.type,
|
|
@@ -2151,16 +2595,16 @@ function AttachedItemsSheet(props) {
|
|
|
2151
2595
|
)
|
|
2152
2596
|
] }) : props.containerLabel ? `Attached to ${props.containerLabel}` : "Attached items";
|
|
2153
2597
|
if (!props.open) return null;
|
|
2154
|
-
return /* @__PURE__ */
|
|
2598
|
+
return /* @__PURE__ */ jsx9(
|
|
2155
2599
|
AssociationWindow,
|
|
2156
2600
|
{
|
|
2157
2601
|
open: props.open,
|
|
2158
2602
|
onClose: () => props.onOpenChange(false),
|
|
2159
2603
|
scopeId: `attached:${props.token}`,
|
|
2160
2604
|
title,
|
|
2161
|
-
icon: /* @__PURE__ */
|
|
2605
|
+
icon: /* @__PURE__ */ jsx9(Icon, { className: "size-3.5 text-primary" }),
|
|
2162
2606
|
subtitle,
|
|
2163
|
-
children: /* @__PURE__ */
|
|
2607
|
+
children: /* @__PURE__ */ jsx9(
|
|
2164
2608
|
AttachedItemsBody,
|
|
2165
2609
|
{
|
|
2166
2610
|
token: props.token,
|
|
@@ -2184,11 +2628,11 @@ function AttachedItemsBody({
|
|
|
2184
2628
|
const notifier = useNotifier();
|
|
2185
2629
|
const info = store.registry.getEntityInfo(token);
|
|
2186
2630
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2187
|
-
const [titles, setTitles] =
|
|
2188
|
-
const [titleError, setTitleError] =
|
|
2189
|
-
const [busyId, setBusyId] =
|
|
2631
|
+
const [titles, setTitles] = useState9(null);
|
|
2632
|
+
const [titleError, setTitleError] = useState9(null);
|
|
2633
|
+
const [busyId, setBusyId] = useState9(null);
|
|
2190
2634
|
const idKey = links.map((l) => l.resourceId).sort().join(",");
|
|
2191
|
-
|
|
2635
|
+
useEffect10(() => {
|
|
2192
2636
|
if (!enabled) return;
|
|
2193
2637
|
const ids = idKey ? idKey.split(",") : [];
|
|
2194
2638
|
if (ids.length === 0) {
|
|
@@ -2232,30 +2676,30 @@ function AttachedItemsBody({
|
|
|
2232
2676
|
setBusyId(null);
|
|
2233
2677
|
}
|
|
2234
2678
|
};
|
|
2235
|
-
return /* @__PURE__ */
|
|
2236
|
-
titleError ? /* @__PURE__ */
|
|
2679
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
2680
|
+
titleError ? /* @__PURE__ */ jsxs7("div", { className: "mb-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
|
|
2237
2681
|
"Showing names recorded at attach time \u2014 they may be out of date.",
|
|
2238
2682
|
" ",
|
|
2239
2683
|
titleError
|
|
2240
2684
|
] }) : null,
|
|
2241
|
-
/* @__PURE__ */
|
|
2242
|
-
/* @__PURE__ */
|
|
2685
|
+
/* @__PURE__ */ jsx9("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: links.length === 0 ? /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-center py-8 text-[13px] text-muted-foreground", children: "Nothing attached yet." }) : titles === null ? /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children: [
|
|
2686
|
+
/* @__PURE__ */ jsx9(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
|
|
2243
2687
|
"Loading\u2026"
|
|
2244
|
-
] }) : /* @__PURE__ */
|
|
2688
|
+
] }) : /* @__PURE__ */ jsx9("ul", { className: "space-y-0.5", children: links.map((link) => {
|
|
2245
2689
|
const resolved = titles.get(link.resourceId);
|
|
2246
2690
|
const missing = !titles.has(link.resourceId);
|
|
2247
2691
|
const name = resolved ?? link.label ?? (missing ? null : "Untitled");
|
|
2248
2692
|
const busy = busyId === link.resourceId;
|
|
2249
|
-
return /* @__PURE__ */
|
|
2693
|
+
return /* @__PURE__ */ jsxs7(
|
|
2250
2694
|
"li",
|
|
2251
2695
|
{
|
|
2252
2696
|
className: "group/entity-ref group flex items-center gap-2 rounded-md px-2.5 py-2 text-sm transition-colors hover:bg-accent",
|
|
2253
2697
|
children: [
|
|
2254
|
-
/* @__PURE__ */
|
|
2255
|
-
/* @__PURE__ */
|
|
2698
|
+
/* @__PURE__ */ jsx9(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
2699
|
+
/* @__PURE__ */ jsx9("span", { className: "flex-1 min-w-0 truncate", children: name === null ? (
|
|
2256
2700
|
// The X beside the row stays the one-click detach.
|
|
2257
|
-
/* @__PURE__ */
|
|
2258
|
-
) : /* @__PURE__ */
|
|
2701
|
+
/* @__PURE__ */ jsx9(UnresolvedRef, { token, id: link.resourceId })
|
|
2702
|
+
) : /* @__PURE__ */ jsx9(
|
|
2259
2703
|
DoorRef,
|
|
2260
2704
|
{
|
|
2261
2705
|
token,
|
|
@@ -2265,7 +2709,7 @@ function AttachedItemsBody({
|
|
|
2265
2709
|
className: "text-foreground"
|
|
2266
2710
|
}
|
|
2267
2711
|
) }),
|
|
2268
|
-
/* @__PURE__ */
|
|
2712
|
+
/* @__PURE__ */ jsx9(
|
|
2269
2713
|
"button",
|
|
2270
2714
|
{
|
|
2271
2715
|
type: "button",
|
|
@@ -2276,7 +2720,7 @@ function AttachedItemsBody({
|
|
|
2276
2720
|
"flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
|
|
2277
2721
|
"hover:bg-destructive/10 hover:text-destructive disabled:opacity-50"
|
|
2278
2722
|
),
|
|
2279
|
-
children: busy ? /* @__PURE__ */
|
|
2723
|
+
children: busy ? /* @__PURE__ */ jsx9(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx9(XIcon, { className: "h-3.5 w-3.5" })
|
|
2280
2724
|
}
|
|
2281
2725
|
)
|
|
2282
2726
|
]
|
|
@@ -2284,14 +2728,14 @@ function AttachedItemsBody({
|
|
|
2284
2728
|
link.edgeId
|
|
2285
2729
|
);
|
|
2286
2730
|
}) }) }),
|
|
2287
|
-
onAdd ? /* @__PURE__ */
|
|
2731
|
+
onAdd ? /* @__PURE__ */ jsxs7(
|
|
2288
2732
|
"button",
|
|
2289
2733
|
{
|
|
2290
2734
|
type: "button",
|
|
2291
2735
|
onClick: onAdd,
|
|
2292
2736
|
className: "mt-2 flex w-full items-center justify-center gap-1.5 rounded-md border border-border px-3 py-2 text-sm text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground",
|
|
2293
2737
|
children: [
|
|
2294
|
-
/* @__PURE__ */
|
|
2738
|
+
/* @__PURE__ */ jsx9(PlusIcon, { className: "h-4 w-4" }),
|
|
2295
2739
|
"Attach ",
|
|
2296
2740
|
info.labelPlural.toLowerCase()
|
|
2297
2741
|
]
|
|
@@ -2301,7 +2745,7 @@ function AttachedItemsBody({
|
|
|
2301
2745
|
}
|
|
2302
2746
|
|
|
2303
2747
|
// src/react/components/AssociationCard.tsx
|
|
2304
|
-
import { useState as
|
|
2748
|
+
import { useState as useState10 } from "react";
|
|
2305
2749
|
import { cn as cn6 } from "@ai-matrx/design-system";
|
|
2306
2750
|
|
|
2307
2751
|
// src/react/contentRoles.ts
|
|
@@ -2352,7 +2796,7 @@ function getContentRoleMeta(role) {
|
|
|
2352
2796
|
}
|
|
2353
2797
|
|
|
2354
2798
|
// src/react/components/AssociationCard.tsx
|
|
2355
|
-
import { Fragment as Fragment3, jsx as
|
|
2799
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2356
2800
|
function AssociationCard({
|
|
2357
2801
|
token,
|
|
2358
2802
|
container: containerProp,
|
|
@@ -2361,11 +2805,11 @@ function AssociationCard({
|
|
|
2361
2805
|
const store = useAssociationsStore();
|
|
2362
2806
|
const fromCtx = usePrimaryEntity();
|
|
2363
2807
|
const container = containerProp ?? fromCtx;
|
|
2364
|
-
const [open, setOpen] =
|
|
2808
|
+
const [open, setOpen] = useState10(false);
|
|
2365
2809
|
const info = store.registry.getEntityInfo(token);
|
|
2366
2810
|
const role = getContentRoleMeta(info.contentRole);
|
|
2367
2811
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2368
|
-
const [listOpen, setListOpen] =
|
|
2812
|
+
const [listOpen, setListOpen] = useState10(false);
|
|
2369
2813
|
const { status, countFor, attachedIdsFor, linksFor, attach, detach } = useContainerLinks({
|
|
2370
2814
|
containerType: container?.type ?? "organization",
|
|
2371
2815
|
containerId: container?.id ?? null,
|
|
@@ -2383,8 +2827,8 @@ function AssociationCard({
|
|
|
2383
2827
|
const loading = status === "loading" || status === "idle";
|
|
2384
2828
|
const canAttach = info.canListCandidates;
|
|
2385
2829
|
const canDrillIn = count > 0;
|
|
2386
|
-
return /* @__PURE__ */
|
|
2387
|
-
/* @__PURE__ */
|
|
2830
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
2831
|
+
/* @__PURE__ */ jsxs8(
|
|
2388
2832
|
"div",
|
|
2389
2833
|
{
|
|
2390
2834
|
className: cn6(
|
|
@@ -2392,7 +2836,7 @@ function AssociationCard({
|
|
|
2392
2836
|
className
|
|
2393
2837
|
),
|
|
2394
2838
|
children: [
|
|
2395
|
-
/* @__PURE__ */
|
|
2839
|
+
/* @__PURE__ */ jsx10(
|
|
2396
2840
|
"span",
|
|
2397
2841
|
{
|
|
2398
2842
|
className: cn6(
|
|
@@ -2401,7 +2845,7 @@ function AssociationCard({
|
|
|
2401
2845
|
)
|
|
2402
2846
|
}
|
|
2403
2847
|
),
|
|
2404
|
-
/* @__PURE__ */
|
|
2848
|
+
/* @__PURE__ */ jsxs8(
|
|
2405
2849
|
"button",
|
|
2406
2850
|
{
|
|
2407
2851
|
type: "button",
|
|
@@ -2413,7 +2857,7 @@ function AssociationCard({
|
|
|
2413
2857
|
canDrillIn ? "cursor-pointer" : "cursor-default"
|
|
2414
2858
|
),
|
|
2415
2859
|
children: [
|
|
2416
|
-
/* @__PURE__ */
|
|
2860
|
+
/* @__PURE__ */ jsx10(
|
|
2417
2861
|
"span",
|
|
2418
2862
|
{
|
|
2419
2863
|
className: cn6(
|
|
@@ -2421,20 +2865,20 @@ function AssociationCard({
|
|
|
2421
2865
|
role.accentBg,
|
|
2422
2866
|
role.accentText
|
|
2423
2867
|
),
|
|
2424
|
-
children: /* @__PURE__ */
|
|
2868
|
+
children: /* @__PURE__ */ jsx10(Icon, { className: "h-4 w-4" })
|
|
2425
2869
|
}
|
|
2426
2870
|
),
|
|
2427
|
-
/* @__PURE__ */
|
|
2428
|
-
/* @__PURE__ */
|
|
2429
|
-
/* @__PURE__ */
|
|
2430
|
-
/* @__PURE__ */
|
|
2871
|
+
/* @__PURE__ */ jsxs8("span", { className: "min-w-0 flex-1", children: [
|
|
2872
|
+
/* @__PURE__ */ jsx10("span", { className: "block truncate text-sm font-medium text-foreground", children: info.labelPlural }),
|
|
2873
|
+
/* @__PURE__ */ jsx10("span", { className: "block text-[11px] text-muted-foreground tabular-nums", children: loading ? /* @__PURE__ */ jsxs8("span", { className: "inline-flex items-center gap-1", children: [
|
|
2874
|
+
/* @__PURE__ */ jsx10(SpinnerIcon, { className: "h-3 w-3 animate-spin" }),
|
|
2431
2875
|
"Loading\u2026"
|
|
2432
2876
|
] }) : `${count} attached` })
|
|
2433
2877
|
] })
|
|
2434
2878
|
]
|
|
2435
2879
|
}
|
|
2436
2880
|
),
|
|
2437
|
-
canAttach && /* @__PURE__ */
|
|
2881
|
+
canAttach && /* @__PURE__ */ jsx10(
|
|
2438
2882
|
"button",
|
|
2439
2883
|
{
|
|
2440
2884
|
type: "button",
|
|
@@ -2442,13 +2886,13 @@ function AssociationCard({
|
|
|
2442
2886
|
"aria-label": `Attach ${info.labelPlural.toLowerCase()}`,
|
|
2443
2887
|
title: `Attach ${info.labelPlural.toLowerCase()}`,
|
|
2444
2888
|
className: "mr-2 flex h-11 w-11 shrink-0 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground lg:mr-3 lg:h-7 lg:w-7",
|
|
2445
|
-
children: /* @__PURE__ */
|
|
2889
|
+
children: /* @__PURE__ */ jsx10(PlusIcon, { className: "h-4 w-4" })
|
|
2446
2890
|
}
|
|
2447
2891
|
)
|
|
2448
2892
|
]
|
|
2449
2893
|
}
|
|
2450
2894
|
),
|
|
2451
|
-
listOpen && /* @__PURE__ */
|
|
2895
|
+
listOpen && /* @__PURE__ */ jsx10(
|
|
2452
2896
|
AttachedItemsSheet,
|
|
2453
2897
|
{
|
|
2454
2898
|
open: listOpen,
|
|
@@ -2466,7 +2910,7 @@ function AssociationCard({
|
|
|
2466
2910
|
onDetach: (resourceId) => detach(token, resourceId)
|
|
2467
2911
|
}
|
|
2468
2912
|
),
|
|
2469
|
-
canAttach && /* @__PURE__ */
|
|
2913
|
+
canAttach && /* @__PURE__ */ jsx10(
|
|
2470
2914
|
AssociationPicker,
|
|
2471
2915
|
{
|
|
2472
2916
|
open,
|
|
@@ -2484,7 +2928,7 @@ function AssociationCard({
|
|
|
2484
2928
|
|
|
2485
2929
|
// src/react/components/AssociationCardGrid.tsx
|
|
2486
2930
|
import { cn as cn7 } from "@ai-matrx/design-system";
|
|
2487
|
-
import { jsx as
|
|
2931
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2488
2932
|
function AssociationCardGrid({
|
|
2489
2933
|
tokens,
|
|
2490
2934
|
excludeTokens,
|
|
@@ -2495,33 +2939,33 @@ function AssociationCardGrid({
|
|
|
2495
2939
|
const list = (tokens ?? store.registry.curatedTokens()).filter(
|
|
2496
2940
|
(token) => !excluded.has(token)
|
|
2497
2941
|
);
|
|
2498
|
-
return /* @__PURE__ */
|
|
2942
|
+
return /* @__PURE__ */ jsx11("div", { className: cn7("space-y-5", className), children: CONTENT_ROLES.map((role) => {
|
|
2499
2943
|
const inRole = list.filter(
|
|
2500
2944
|
(token) => store.registry.getEntityInfo(token).contentRole === role.id
|
|
2501
2945
|
);
|
|
2502
2946
|
if (inRole.length === 0) return null;
|
|
2503
|
-
return /* @__PURE__ */
|
|
2504
|
-
/* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
/* @__PURE__ */
|
|
2947
|
+
return /* @__PURE__ */ jsxs9("section", { children: [
|
|
2948
|
+
/* @__PURE__ */ jsxs9("div", { className: "mb-2.5 flex items-baseline gap-3 pl-1.5", children: [
|
|
2949
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
2950
|
+
/* @__PURE__ */ jsx11(
|
|
2507
2951
|
"span",
|
|
2508
2952
|
{
|
|
2509
2953
|
className: cn7("h-2.5 w-2.5 rounded-full", role.accentBar)
|
|
2510
2954
|
}
|
|
2511
2955
|
),
|
|
2512
|
-
/* @__PURE__ */
|
|
2956
|
+
/* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold text-foreground", children: role.title })
|
|
2513
2957
|
] }),
|
|
2514
|
-
/* @__PURE__ */
|
|
2958
|
+
/* @__PURE__ */ jsx11("p", { className: "hidden text-xs text-muted-foreground sm:block", children: role.tagline })
|
|
2515
2959
|
] }),
|
|
2516
|
-
/* @__PURE__ */
|
|
2960
|
+
/* @__PURE__ */ jsx11("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3", children: inRole.map((token) => /* @__PURE__ */ jsx11(AssociationCard, { token }, token)) })
|
|
2517
2961
|
] }, role.id);
|
|
2518
2962
|
}) });
|
|
2519
2963
|
}
|
|
2520
2964
|
|
|
2521
2965
|
// src/react/components/AssociationList.tsx
|
|
2522
|
-
import { useState as
|
|
2966
|
+
import { useState as useState11 } from "react";
|
|
2523
2967
|
import { cn as cn8, Skeleton } from "@ai-matrx/design-system";
|
|
2524
|
-
import { jsx as
|
|
2968
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2525
2969
|
function useContainerLinksAdapter(container, tokens) {
|
|
2526
2970
|
const store = useAssociationsStore();
|
|
2527
2971
|
const links = useContainerLinks({
|
|
@@ -2559,9 +3003,9 @@ function AssociationList(props) {
|
|
|
2559
3003
|
const adapter = props.adapter ?? defaultAdapter;
|
|
2560
3004
|
const variant = props.variant ?? "full";
|
|
2561
3005
|
const tokenFilter = props.tokens ?? null;
|
|
2562
|
-
const [pickerToken, setPickerToken] =
|
|
2563
|
-
const [showUniversal, setShowUniversal] =
|
|
2564
|
-
const [removingKeys, setRemovingKeys] =
|
|
3006
|
+
const [pickerToken, setPickerToken] = useState11(null);
|
|
3007
|
+
const [showUniversal, setShowUniversal] = useState11(false);
|
|
3008
|
+
const [removingKeys, setRemovingKeys] = useState11(/* @__PURE__ */ new Set());
|
|
2565
3009
|
const rows = tokenFilter ? adapter.rows.filter((r) => tokenFilter.includes(r.token)) : adapter.rows;
|
|
2566
3010
|
const visibleRows = rows.filter((r) => !removingKeys.has(r.key));
|
|
2567
3011
|
const { titleFor } = useEntityTitles(
|
|
@@ -2599,15 +3043,15 @@ function AssociationList(props) {
|
|
|
2599
3043
|
const grouped = groupRows(store, visibleRows);
|
|
2600
3044
|
const isLoading = adapter.status === "loading" || adapter.status === "idle";
|
|
2601
3045
|
const attachableTokens = tokenFilter ?? store.registry.curatedTokens();
|
|
2602
|
-
return /* @__PURE__ */
|
|
2603
|
-
/* @__PURE__ */
|
|
2604
|
-
/* @__PURE__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
3046
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn8("flex flex-col gap-2 text-foreground", props.className), children: [
|
|
3047
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
3048
|
+
/* @__PURE__ */ jsxs10("h3", { className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: [
|
|
3049
|
+
/* @__PURE__ */ jsx12(Link2Icon, { className: "h-3.5 w-3.5" }),
|
|
2606
3050
|
"Resources",
|
|
2607
|
-
visibleRows.length > 0 && /* @__PURE__ */
|
|
3051
|
+
visibleRows.length > 0 && /* @__PURE__ */ jsx12("span", { className: "rounded bg-muted px-1 text-[10px] font-medium text-muted-foreground", children: visibleRows.length })
|
|
2608
3052
|
] }),
|
|
2609
|
-
/* @__PURE__ */
|
|
2610
|
-
/* @__PURE__ */
|
|
3053
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5", children: [
|
|
3054
|
+
/* @__PURE__ */ jsxs10(
|
|
2611
3055
|
"button",
|
|
2612
3056
|
{
|
|
2613
3057
|
type: "button",
|
|
@@ -2617,19 +3061,19 @@ function AssociationList(props) {
|
|
|
2617
3061
|
showUniversal ? "bg-accent text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
2618
3062
|
),
|
|
2619
3063
|
children: [
|
|
2620
|
-
/* @__PURE__ */
|
|
3064
|
+
/* @__PURE__ */ jsx12(PlusIcon, { className: "h-3 w-3" }),
|
|
2621
3065
|
"Add"
|
|
2622
3066
|
]
|
|
2623
3067
|
}
|
|
2624
3068
|
),
|
|
2625
|
-
/* @__PURE__ */
|
|
3069
|
+
/* @__PURE__ */ jsx12(
|
|
2626
3070
|
"button",
|
|
2627
3071
|
{
|
|
2628
3072
|
type: "button",
|
|
2629
3073
|
onClick: () => void adapter.reload(),
|
|
2630
3074
|
title: "Refresh",
|
|
2631
3075
|
className: "text-muted-foreground/60 transition-colors hover:text-foreground",
|
|
2632
|
-
children: /* @__PURE__ */
|
|
3076
|
+
children: /* @__PURE__ */ jsx12(
|
|
2633
3077
|
RefreshIcon,
|
|
2634
3078
|
{
|
|
2635
3079
|
className: cn8(
|
|
@@ -2642,7 +3086,7 @@ function AssociationList(props) {
|
|
|
2642
3086
|
)
|
|
2643
3087
|
] })
|
|
2644
3088
|
] }),
|
|
2645
|
-
showUniversal && /* @__PURE__ */
|
|
3089
|
+
showUniversal && /* @__PURE__ */ jsx12("div", { className: "rounded-md border border-border/60 bg-muted/30 p-2 max-h-80 flex flex-col", children: /* @__PURE__ */ jsx12(
|
|
2646
3090
|
UniversalAssociationPicker,
|
|
2647
3091
|
{
|
|
2648
3092
|
tokens: attachableTokens,
|
|
@@ -2652,9 +3096,9 @@ function AssociationList(props) {
|
|
|
2652
3096
|
onDetach: (token, id) => adapter.detach(token, id)
|
|
2653
3097
|
}
|
|
2654
3098
|
) }),
|
|
2655
|
-
adapter.status === "error" && /* @__PURE__ */
|
|
2656
|
-
/* @__PURE__ */
|
|
2657
|
-
/* @__PURE__ */
|
|
3099
|
+
adapter.status === "error" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-2.5 py-2", children: [
|
|
3100
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate text-[11px] text-destructive", children: adapter.error || "Failed to load resources" }),
|
|
3101
|
+
/* @__PURE__ */ jsx12(
|
|
2658
3102
|
"button",
|
|
2659
3103
|
{
|
|
2660
3104
|
type: "button",
|
|
@@ -2664,17 +3108,17 @@ function AssociationList(props) {
|
|
|
2664
3108
|
}
|
|
2665
3109
|
)
|
|
2666
3110
|
] }),
|
|
2667
|
-
adapter.status !== "error" && isLoading && visibleRows.length === 0 && /* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
3111
|
+
adapter.status !== "error" && isLoading && visibleRows.length === 0 && /* @__PURE__ */ jsxs10("div", { className: "space-y-1.5 px-1", children: [
|
|
3112
|
+
/* @__PURE__ */ jsx12(Skeleton, { className: "h-3 w-20" }),
|
|
3113
|
+
/* @__PURE__ */ jsx12(Skeleton, { className: "h-7 w-full rounded-md" }),
|
|
3114
|
+
/* @__PURE__ */ jsx12(Skeleton, { className: "h-7 w-3/4 rounded-md" })
|
|
2671
3115
|
] }),
|
|
2672
|
-
adapter.status === "ready" && visibleRows.length === 0 && /* @__PURE__ */
|
|
2673
|
-
visibleRows.length > 0 && /* @__PURE__ */
|
|
3116
|
+
adapter.status === "ready" && visibleRows.length === 0 && /* @__PURE__ */ jsx12("p", { className: "px-1 py-1 text-[11px] text-muted-foreground", children: "Nothing attached yet \u2014 use Add to link anything." }),
|
|
3117
|
+
visibleRows.length > 0 && /* @__PURE__ */ jsx12("div", { className: "space-y-2.5", children: grouped.map(({ role, tokens: tokenGroups }) => {
|
|
2674
3118
|
const roleMeta = getContentRoleMeta(role);
|
|
2675
|
-
return /* @__PURE__ */
|
|
2676
|
-
variant === "full" && /* @__PURE__ */
|
|
2677
|
-
/* @__PURE__ */
|
|
3119
|
+
return /* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
|
|
3120
|
+
variant === "full" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5 px-1", children: [
|
|
3121
|
+
/* @__PURE__ */ jsx12(
|
|
2678
3122
|
"span",
|
|
2679
3123
|
{
|
|
2680
3124
|
className: cn8(
|
|
@@ -2683,7 +3127,7 @@ function AssociationList(props) {
|
|
|
2683
3127
|
)
|
|
2684
3128
|
}
|
|
2685
3129
|
),
|
|
2686
|
-
/* @__PURE__ */
|
|
3130
|
+
/* @__PURE__ */ jsx12(
|
|
2687
3131
|
"p",
|
|
2688
3132
|
{
|
|
2689
3133
|
className: cn8(
|
|
@@ -2696,28 +3140,28 @@ function AssociationList(props) {
|
|
|
2696
3140
|
] }),
|
|
2697
3141
|
tokenGroups.map(({ info, token, rows: tokenRows }) => {
|
|
2698
3142
|
const TokenIcon = info?.Icon ?? null;
|
|
2699
|
-
return /* @__PURE__ */
|
|
2700
|
-
/* @__PURE__ */
|
|
2701
|
-
/* @__PURE__ */
|
|
2702
|
-
TokenIcon ? /* @__PURE__ */
|
|
3143
|
+
return /* @__PURE__ */ jsxs10("div", { className: "space-y-0.5", children: [
|
|
3144
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-1 px-1", children: [
|
|
3145
|
+
/* @__PURE__ */ jsxs10("p", { className: "flex items-center gap-1 text-[10px] font-medium text-muted-foreground/80", children: [
|
|
3146
|
+
TokenIcon ? /* @__PURE__ */ jsx12(TokenIcon, { className: "h-3 w-3" }) : null,
|
|
2703
3147
|
info?.labelPlural ?? titleize(token),
|
|
2704
|
-
/* @__PURE__ */
|
|
3148
|
+
/* @__PURE__ */ jsx12("span", { className: "text-muted-foreground/50", children: tokenRows.length })
|
|
2705
3149
|
] }),
|
|
2706
|
-
/* @__PURE__ */
|
|
3150
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
|
|
2707
3151
|
props.renderSectionActions && info ? props.renderSectionActions(info.token) : null,
|
|
2708
|
-
info?.canListCandidates && /* @__PURE__ */
|
|
3152
|
+
info?.canListCandidates && /* @__PURE__ */ jsx12(
|
|
2709
3153
|
"button",
|
|
2710
3154
|
{
|
|
2711
3155
|
type: "button",
|
|
2712
3156
|
onClick: () => setPickerToken(info.token),
|
|
2713
3157
|
title: `Add ${info.labelPlural}`,
|
|
2714
3158
|
className: "rounded p-0.5 text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground",
|
|
2715
|
-
children: /* @__PURE__ */
|
|
3159
|
+
children: /* @__PURE__ */ jsx12(PlusIcon, { className: "h-3 w-3" })
|
|
2716
3160
|
}
|
|
2717
3161
|
)
|
|
2718
3162
|
] })
|
|
2719
3163
|
] }),
|
|
2720
|
-
/* @__PURE__ */
|
|
3164
|
+
/* @__PURE__ */ jsx12("ul", { className: "space-y-0.5", children: tokenRows.map((row) => {
|
|
2721
3165
|
const busy = removingKeys.has(row.key);
|
|
2722
3166
|
const custom = props.renderRow?.(row, {
|
|
2723
3167
|
title: titleFor({
|
|
@@ -2730,9 +3174,9 @@ function AssociationList(props) {
|
|
|
2730
3174
|
onOpen: () => openRow(row)
|
|
2731
3175
|
});
|
|
2732
3176
|
if (custom != null) {
|
|
2733
|
-
return /* @__PURE__ */
|
|
3177
|
+
return /* @__PURE__ */ jsx12("li", { children: custom }, row.key);
|
|
2734
3178
|
}
|
|
2735
|
-
return /* @__PURE__ */
|
|
3179
|
+
return /* @__PURE__ */ jsx12("li", { children: /* @__PURE__ */ jsxs10(
|
|
2736
3180
|
"div",
|
|
2737
3181
|
{
|
|
2738
3182
|
className: cn8(
|
|
@@ -2740,7 +3184,7 @@ function AssociationList(props) {
|
|
|
2740
3184
|
busy && "opacity-50"
|
|
2741
3185
|
),
|
|
2742
3186
|
children: [
|
|
2743
|
-
/* @__PURE__ */
|
|
3187
|
+
/* @__PURE__ */ jsx12(
|
|
2744
3188
|
DoorRef,
|
|
2745
3189
|
{
|
|
2746
3190
|
token: row.token,
|
|
@@ -2756,9 +3200,9 @@ function AssociationList(props) {
|
|
|
2756
3200
|
className: "min-w-0 flex-1 text-foreground"
|
|
2757
3201
|
}
|
|
2758
3202
|
),
|
|
2759
|
-
row.originRefs && row.originRefs.length > 0 ? /* @__PURE__ */
|
|
3203
|
+
row.originRefs && row.originRefs.length > 0 ? /* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1 text-[10px] text-muted-foreground/60", children: [
|
|
2760
3204
|
"via",
|
|
2761
|
-
row.originRefs.map((origin) => /* @__PURE__ */
|
|
3205
|
+
row.originRefs.map((origin) => /* @__PURE__ */ jsx12(
|
|
2762
3206
|
DoorRef,
|
|
2763
3207
|
{
|
|
2764
3208
|
token: origin.token,
|
|
@@ -2770,8 +3214,8 @@ function AssociationList(props) {
|
|
|
2770
3214
|
},
|
|
2771
3215
|
`${origin.token}:${origin.id}`
|
|
2772
3216
|
))
|
|
2773
|
-
] }) : row.originNote ? /* @__PURE__ */
|
|
2774
|
-
adapter.setPinned && info && row.removable && /* @__PURE__ */
|
|
3217
|
+
] }) : row.originNote ? /* @__PURE__ */ jsx12("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: row.originNote }) : null,
|
|
3218
|
+
adapter.setPinned && info && row.removable && /* @__PURE__ */ jsx12(
|
|
2775
3219
|
"button",
|
|
2776
3220
|
{
|
|
2777
3221
|
type: "button",
|
|
@@ -2786,7 +3230,7 @@ function AssociationList(props) {
|
|
|
2786
3230
|
"shrink-0 rounded p-0.5 transition-colors hover:!text-foreground",
|
|
2787
3231
|
row.pinned ? "text-primary" : "text-muted-foreground/0 group-hover:text-muted-foreground"
|
|
2788
3232
|
),
|
|
2789
|
-
children: /* @__PURE__ */
|
|
3233
|
+
children: /* @__PURE__ */ jsx12(
|
|
2790
3234
|
PinIcon,
|
|
2791
3235
|
{
|
|
2792
3236
|
className: cn8(
|
|
@@ -2797,7 +3241,7 @@ function AssociationList(props) {
|
|
|
2797
3241
|
)
|
|
2798
3242
|
}
|
|
2799
3243
|
),
|
|
2800
|
-
row.removable && /* @__PURE__ */
|
|
3244
|
+
row.removable && /* @__PURE__ */ jsx12(
|
|
2801
3245
|
"button",
|
|
2802
3246
|
{
|
|
2803
3247
|
type: "button",
|
|
@@ -2806,7 +3250,7 @@ function AssociationList(props) {
|
|
|
2806
3250
|
title: "Detach",
|
|
2807
3251
|
"aria-label": "Detach",
|
|
2808
3252
|
className: "shrink-0 rounded p-0.5 text-muted-foreground/0 transition-colors group-hover:text-muted-foreground hover:!text-destructive disabled:opacity-50",
|
|
2809
|
-
children: busy ? /* @__PURE__ */
|
|
3253
|
+
children: busy ? /* @__PURE__ */ jsx12(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx12(XIcon, { className: "h-3 w-3" })
|
|
2810
3254
|
}
|
|
2811
3255
|
)
|
|
2812
3256
|
]
|
|
@@ -2817,7 +3261,7 @@ function AssociationList(props) {
|
|
|
2817
3261
|
})
|
|
2818
3262
|
] }, role);
|
|
2819
3263
|
}) }),
|
|
2820
|
-
pickerToken && /* @__PURE__ */
|
|
3264
|
+
pickerToken && /* @__PURE__ */ jsx12(
|
|
2821
3265
|
AssociationPicker,
|
|
2822
3266
|
{
|
|
2823
3267
|
open: true,
|
|
@@ -2873,9 +3317,9 @@ function titleize(token) {
|
|
|
2873
3317
|
}
|
|
2874
3318
|
|
|
2875
3319
|
// src/react/components/AssociationCaptureToolbar.tsx
|
|
2876
|
-
import { useRef as
|
|
3320
|
+
import { useRef as useRef8, useState as useState12 } from "react";
|
|
2877
3321
|
import { Button, cn as cn9, Input as Input3 } from "@ai-matrx/design-system";
|
|
2878
|
-
import { Fragment as Fragment4, jsx as
|
|
3322
|
+
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2879
3323
|
function AssociationCaptureToolbar({
|
|
2880
3324
|
attach,
|
|
2881
3325
|
uploadFolderPath,
|
|
@@ -2893,21 +3337,43 @@ function AssociationCaptureToolbar({
|
|
|
2893
3337
|
const store = useAssociationsStore();
|
|
2894
3338
|
const { capture } = useAssociationsUiPorts();
|
|
2895
3339
|
const notifier = useNotifier();
|
|
2896
|
-
const fileInputRef =
|
|
2897
|
-
const [isUploading, setIsUploading] =
|
|
2898
|
-
const [isDragOver, setIsDragOver] =
|
|
2899
|
-
const [isPicking, setIsPicking] =
|
|
2900
|
-
const [namingDoc, setNamingDoc] =
|
|
2901
|
-
const [docName, setDocName] =
|
|
2902
|
-
const [creatingDoc, setCreatingDoc] =
|
|
3340
|
+
const fileInputRef = useRef8(null);
|
|
3341
|
+
const [isUploading, setIsUploading] = useState12(false);
|
|
3342
|
+
const [isDragOver, setIsDragOver] = useState12(false);
|
|
3343
|
+
const [isPicking, setIsPicking] = useState12(false);
|
|
3344
|
+
const [namingDoc, setNamingDoc] = useState12(false);
|
|
3345
|
+
const [docName, setDocName] = useState12("");
|
|
3346
|
+
const [creatingDoc, setCreatingDoc] = useState12(false);
|
|
3347
|
+
const hostRequestUpload = capture?.requestUpload;
|
|
3348
|
+
const hostUploadFile = capture?.uploadFile;
|
|
3349
|
+
const requestUploadPath = hostRequestUpload ? (opts) => hostRequestUpload(opts) : hostUploadFile ? async (opts) => {
|
|
3350
|
+
const uploaded = [];
|
|
3351
|
+
const failed = [];
|
|
3352
|
+
for (const file of opts.files) {
|
|
3353
|
+
try {
|
|
3354
|
+
const result = await hostUploadFile(file, {
|
|
3355
|
+
folderPath: opts.folderPath,
|
|
3356
|
+
...opts.visibility !== void 0 ? { visibility: opts.visibility } : {}
|
|
3357
|
+
});
|
|
3358
|
+
if (result.ok) uploaded.push(result.id);
|
|
3359
|
+
else failed.push({ name: file.name, error: result.error });
|
|
3360
|
+
} catch (err) {
|
|
3361
|
+
failed.push({
|
|
3362
|
+
name: file.name,
|
|
3363
|
+
error: err instanceof Error && err.message ? err.message : "Upload failed"
|
|
3364
|
+
});
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
return { uploaded, aliased: [], failed };
|
|
3368
|
+
} : void 0;
|
|
2903
3369
|
const actions = {
|
|
2904
|
-
upload: (showActions?.upload ?? true) && Boolean(
|
|
3370
|
+
upload: (showActions?.upload ?? true) && Boolean(requestUploadPath),
|
|
2905
3371
|
addFile: (showActions?.addFile ?? true) && Boolean(capture?.openFilePicker),
|
|
2906
3372
|
newDocument: (showActions?.newDocument ?? true) && Boolean(capture?.createDataTable)
|
|
2907
3373
|
};
|
|
2908
|
-
const canDrop = Boolean(
|
|
3374
|
+
const canDrop = Boolean(requestUploadPath);
|
|
2909
3375
|
const uploadAndAttach = async (files) => {
|
|
2910
|
-
const requestUpload =
|
|
3376
|
+
const requestUpload = requestUploadPath;
|
|
2911
3377
|
if (files.length === 0 || !requestUpload) return;
|
|
2912
3378
|
setIsUploading(true);
|
|
2913
3379
|
const watchdog = setTimeout(() => {
|
|
@@ -3065,7 +3531,7 @@ function AssociationCaptureToolbar({
|
|
|
3065
3531
|
}
|
|
3066
3532
|
};
|
|
3067
3533
|
const anyBuiltIn = actions.upload || actions.addFile || actions.newDocument;
|
|
3068
|
-
return /* @__PURE__ */
|
|
3534
|
+
return /* @__PURE__ */ jsxs11(
|
|
3069
3535
|
"div",
|
|
3070
3536
|
{
|
|
3071
3537
|
className: cn9(
|
|
@@ -3086,11 +3552,11 @@ function AssociationCaptureToolbar({
|
|
|
3086
3552
|
},
|
|
3087
3553
|
onDrop: handleDrop,
|
|
3088
3554
|
children: [
|
|
3089
|
-
isDragOver ? /* @__PURE__ */
|
|
3090
|
-
/* @__PURE__ */
|
|
3555
|
+
isDragOver ? /* @__PURE__ */ jsx13("div", { className: "pointer-events-none absolute inset-0 z-10 grid place-items-center bg-background/70", children: /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2 rounded-md border border-primary/40 bg-card px-3 py-1.5 text-xs font-medium text-foreground", children: [
|
|
3556
|
+
/* @__PURE__ */ jsx13(UploadIcon, { className: "size-3.5 text-primary" }),
|
|
3091
3557
|
"Drop to upload & attach"
|
|
3092
3558
|
] }) }) : null,
|
|
3093
|
-
/* @__PURE__ */
|
|
3559
|
+
/* @__PURE__ */ jsx13(
|
|
3094
3560
|
"input",
|
|
3095
3561
|
{
|
|
3096
3562
|
ref: fileInputRef,
|
|
@@ -3100,8 +3566,8 @@ function AssociationCaptureToolbar({
|
|
|
3100
3566
|
onChange: handleFilesSelected
|
|
3101
3567
|
}
|
|
3102
3568
|
),
|
|
3103
|
-
showToolbar && (anyBuiltIn || extraActions) ? /* @__PURE__ */
|
|
3104
|
-
/* @__PURE__ */
|
|
3569
|
+
showToolbar && (anyBuiltIn || extraActions) ? /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap items-center gap-0.5 border-b border-border/60 px-1.5 py-1", children: namingDoc ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 items-center gap-1.5 py-0.5", children: [
|
|
3570
|
+
/* @__PURE__ */ jsx13(
|
|
3105
3571
|
Input3,
|
|
3106
3572
|
{
|
|
3107
3573
|
autoFocus: true,
|
|
@@ -3120,17 +3586,17 @@ function AssociationCaptureToolbar({
|
|
|
3120
3586
|
style: { fontSize: 16 }
|
|
3121
3587
|
}
|
|
3122
3588
|
),
|
|
3123
|
-
/* @__PURE__ */
|
|
3589
|
+
/* @__PURE__ */ jsx13(
|
|
3124
3590
|
"button",
|
|
3125
3591
|
{
|
|
3126
3592
|
type: "button",
|
|
3127
3593
|
disabled: creatingDoc || !docName.trim(),
|
|
3128
3594
|
onClick: () => void handleCreateDoc(),
|
|
3129
3595
|
className: "flex h-7 items-center rounded-md bg-primary px-2 text-[11px] font-medium text-primary-foreground disabled:opacity-50",
|
|
3130
|
-
children: creatingDoc ? /* @__PURE__ */
|
|
3596
|
+
children: creatingDoc ? /* @__PURE__ */ jsx13(SpinnerIcon, { className: "size-3.5 animate-spin" }) : "Create"
|
|
3131
3597
|
}
|
|
3132
3598
|
),
|
|
3133
|
-
/* @__PURE__ */
|
|
3599
|
+
/* @__PURE__ */ jsx13(
|
|
3134
3600
|
"button",
|
|
3135
3601
|
{
|
|
3136
3602
|
type: "button",
|
|
@@ -3143,8 +3609,8 @@ function AssociationCaptureToolbar({
|
|
|
3143
3609
|
children: "Cancel"
|
|
3144
3610
|
}
|
|
3145
3611
|
)
|
|
3146
|
-
] }) : /* @__PURE__ */
|
|
3147
|
-
actions.upload ? /* @__PURE__ */
|
|
3612
|
+
] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
3613
|
+
actions.upload ? /* @__PURE__ */ jsx13(
|
|
3148
3614
|
CaptureToolbarAction,
|
|
3149
3615
|
{
|
|
3150
3616
|
icon: isUploading ? SpinnerIcon : UploadIcon,
|
|
@@ -3154,7 +3620,7 @@ function AssociationCaptureToolbar({
|
|
|
3154
3620
|
disabled: isPicking || isUploading
|
|
3155
3621
|
}
|
|
3156
3622
|
) : null,
|
|
3157
|
-
actions.addFile ? /* @__PURE__ */
|
|
3623
|
+
actions.addFile ? /* @__PURE__ */ jsx13(
|
|
3158
3624
|
CaptureToolbarAction,
|
|
3159
3625
|
{
|
|
3160
3626
|
icon: isPicking ? SpinnerIcon : FolderOpenIcon,
|
|
@@ -3164,8 +3630,8 @@ function AssociationCaptureToolbar({
|
|
|
3164
3630
|
disabled: isPicking || isUploading
|
|
3165
3631
|
}
|
|
3166
3632
|
) : null,
|
|
3167
|
-
(actions.upload || actions.addFile) && actions.newDocument ? /* @__PURE__ */
|
|
3168
|
-
actions.newDocument ? /* @__PURE__ */
|
|
3633
|
+
(actions.upload || actions.addFile) && actions.newDocument ? /* @__PURE__ */ jsx13("span", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
3634
|
+
actions.newDocument ? /* @__PURE__ */ jsx13(
|
|
3169
3635
|
CaptureToolbarAction,
|
|
3170
3636
|
{
|
|
3171
3637
|
icon: creatingDoc ? SpinnerIcon : PlusIcon,
|
|
@@ -3189,7 +3655,7 @@ function CaptureToolbarAction({
|
|
|
3189
3655
|
disabled,
|
|
3190
3656
|
spinning
|
|
3191
3657
|
}) {
|
|
3192
|
-
return /* @__PURE__ */
|
|
3658
|
+
return /* @__PURE__ */ jsxs11(
|
|
3193
3659
|
Button,
|
|
3194
3660
|
{
|
|
3195
3661
|
type: "button",
|
|
@@ -3199,15 +3665,145 @@ function CaptureToolbarAction({
|
|
|
3199
3665
|
disabled,
|
|
3200
3666
|
className: "h-7 gap-1 px-2 text-[11px] text-muted-foreground hover:text-foreground",
|
|
3201
3667
|
children: [
|
|
3202
|
-
/* @__PURE__ */
|
|
3668
|
+
/* @__PURE__ */ jsx13(Icon, { className: cn9("size-3.5", spinning && "animate-spin") }),
|
|
3203
3669
|
label
|
|
3204
3670
|
]
|
|
3205
3671
|
}
|
|
3206
3672
|
);
|
|
3207
3673
|
}
|
|
3208
3674
|
|
|
3675
|
+
// src/react/lazyPorts.tsx
|
|
3676
|
+
import { Suspense, lazy } from "react";
|
|
3677
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
3678
|
+
function lazyComponent(load) {
|
|
3679
|
+
return lazy(async () => {
|
|
3680
|
+
const loaded = await load();
|
|
3681
|
+
return typeof loaded === "function" ? { default: loaded } : loaded;
|
|
3682
|
+
});
|
|
3683
|
+
}
|
|
3684
|
+
function lazyWindowShell(load) {
|
|
3685
|
+
const Loaded = lazyComponent(load);
|
|
3686
|
+
return function LazyWindowShell(props) {
|
|
3687
|
+
return /* @__PURE__ */ jsx14(Suspense, { fallback: null, children: /* @__PURE__ */ jsx14(Loaded, { ...props }) });
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
function lazyPickerOverride(load) {
|
|
3691
|
+
const Loaded = lazyComponent(load);
|
|
3692
|
+
return function LazyPickerOverride(props) {
|
|
3693
|
+
if (!props.open) return null;
|
|
3694
|
+
return /* @__PURE__ */ jsx14(Suspense, { fallback: null, children: /* @__PURE__ */ jsx14(Loaded, { ...props }) });
|
|
3695
|
+
};
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3698
|
+
// src/react/hooks/useAssociationPickerBridge.ts
|
|
3699
|
+
import { useCallback as useCallback3, useState as useState13 } from "react";
|
|
3700
|
+
function useAssociationPickerBridge(props, options = {}) {
|
|
3701
|
+
const store = useAssociationsStore();
|
|
3702
|
+
const notifier = useNotifier();
|
|
3703
|
+
const [busy, setBusy] = useState13(false);
|
|
3704
|
+
const { attachedIds, onAttach, onDetach, token } = props;
|
|
3705
|
+
const {
|
|
3706
|
+
createdLocationLabel,
|
|
3707
|
+
openCreatedLocation,
|
|
3708
|
+
itemNoun = "item"
|
|
3709
|
+
} = options;
|
|
3710
|
+
const attachMany = useCallback3(
|
|
3711
|
+
async (items) => {
|
|
3712
|
+
if (items.length === 0) return;
|
|
3713
|
+
setBusy(true);
|
|
3714
|
+
const failed = [];
|
|
3715
|
+
try {
|
|
3716
|
+
for (const item of items) {
|
|
3717
|
+
try {
|
|
3718
|
+
const result = await onAttach(item.id, item.name);
|
|
3719
|
+
if (!result.ok) {
|
|
3720
|
+
failed.push({ name: item.name, error: result.error });
|
|
3721
|
+
}
|
|
3722
|
+
} catch (error) {
|
|
3723
|
+
store.errorSink({
|
|
3724
|
+
code: "picker_attach_threw",
|
|
3725
|
+
message: `[associations] attaching ${itemNoun} "${item.name}" threw`,
|
|
3726
|
+
context: { token, id: item.id, detail: error }
|
|
3727
|
+
});
|
|
3728
|
+
failed.push({
|
|
3729
|
+
name: item.name,
|
|
3730
|
+
error: error instanceof Error ? error.message : void 0
|
|
3731
|
+
});
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
const attached = items.length - failed.length;
|
|
3735
|
+
if (attached > 0) {
|
|
3736
|
+
notifier.success(
|
|
3737
|
+
attached === 1 ? `Attached 1 ${itemNoun}` : `Attached ${attached} ${itemNoun}s`
|
|
3738
|
+
);
|
|
3739
|
+
}
|
|
3740
|
+
if (failed.length > 0) {
|
|
3741
|
+
const first = failed[0];
|
|
3742
|
+
const detail = first?.error ? ` (${first.error})` : "";
|
|
3743
|
+
notifier.error(
|
|
3744
|
+
failed.length === 1 ? `Couldn't attach "${first?.name ?? itemNoun}"${detail}` : `Couldn't attach ${failed.length} ${itemNoun}s${detail}`,
|
|
3745
|
+
{
|
|
3746
|
+
...createdLocationLabel ? {
|
|
3747
|
+
description: `The ${failed.length === 1 ? itemNoun + " is" : itemNoun + "s are"} safe in ${createdLocationLabel}. You can retry the association here.`
|
|
3748
|
+
} : {},
|
|
3749
|
+
...openCreatedLocation ? { action: openCreatedLocation } : {}
|
|
3750
|
+
}
|
|
3751
|
+
);
|
|
3752
|
+
store.errorSink({
|
|
3753
|
+
code: "picker_attach_partial",
|
|
3754
|
+
message: `[associations] ${failed.length} of ${items.length} ${itemNoun}s were not attached`,
|
|
3755
|
+
context: { token, failed }
|
|
3756
|
+
});
|
|
3757
|
+
}
|
|
3758
|
+
} finally {
|
|
3759
|
+
setBusy(false);
|
|
3760
|
+
}
|
|
3761
|
+
},
|
|
3762
|
+
[
|
|
3763
|
+
createdLocationLabel,
|
|
3764
|
+
itemNoun,
|
|
3765
|
+
notifier,
|
|
3766
|
+
onAttach,
|
|
3767
|
+
openCreatedLocation,
|
|
3768
|
+
store,
|
|
3769
|
+
token
|
|
3770
|
+
]
|
|
3771
|
+
);
|
|
3772
|
+
const toggle = useCallback3(
|
|
3773
|
+
async (item) => {
|
|
3774
|
+
setBusy(true);
|
|
3775
|
+
try {
|
|
3776
|
+
const detaching = attachedIds.has(item.id);
|
|
3777
|
+
const result = detaching ? await onDetach(item.id) : await onAttach(item.id, item.name);
|
|
3778
|
+
if (!result.ok) {
|
|
3779
|
+
const verb = detaching ? "detach" : "attach";
|
|
3780
|
+
notifier.error(
|
|
3781
|
+
`Couldn't ${verb} "${item.name}"` + (result.error ? `: ${result.error}` : "")
|
|
3782
|
+
);
|
|
3783
|
+
store.errorSink({
|
|
3784
|
+
code: detaching ? "picker_detach_failed" : "picker_attach_failed",
|
|
3785
|
+
message: `[associations] ${verb} refused for "${item.name}"`,
|
|
3786
|
+
context: { token, id: item.id, error: result.error }
|
|
3787
|
+
});
|
|
3788
|
+
}
|
|
3789
|
+
} catch (error) {
|
|
3790
|
+
store.errorSink({
|
|
3791
|
+
code: "picker_toggle_threw",
|
|
3792
|
+
message: `[associations] toggling ${itemNoun} "${item.name}" threw`,
|
|
3793
|
+
context: { token, id: item.id, detail: error }
|
|
3794
|
+
});
|
|
3795
|
+
notifier.error(`Couldn't update "${item.name}"`);
|
|
3796
|
+
} finally {
|
|
3797
|
+
setBusy(false);
|
|
3798
|
+
}
|
|
3799
|
+
},
|
|
3800
|
+
[attachedIds, itemNoun, notifier, onAttach, onDetach, store, token]
|
|
3801
|
+
);
|
|
3802
|
+
return { attachMany, toggle, busy };
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3209
3805
|
// src/react/components/AssociationEntitySelect.tsx
|
|
3210
|
-
import { useState as
|
|
3806
|
+
import { useState as useState14 } from "react";
|
|
3211
3807
|
import {
|
|
3212
3808
|
cn as cn10,
|
|
3213
3809
|
Command,
|
|
@@ -3221,7 +3817,7 @@ import {
|
|
|
3221
3817
|
PopoverContent,
|
|
3222
3818
|
PopoverTrigger
|
|
3223
3819
|
} from "@ai-matrx/design-system";
|
|
3224
|
-
import { jsx as
|
|
3820
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3225
3821
|
function AssociationEntitySelect({
|
|
3226
3822
|
token,
|
|
3227
3823
|
adapter,
|
|
@@ -3235,19 +3831,17 @@ function AssociationEntitySelect({
|
|
|
3235
3831
|
createSlot
|
|
3236
3832
|
}) {
|
|
3237
3833
|
const store = useAssociationsStore();
|
|
3238
|
-
const { entityDoors } = useAssociationsUiPorts();
|
|
3239
3834
|
const notifier = useNotifier();
|
|
3240
3835
|
const info = store.registry.getEntityInfo(token);
|
|
3241
3836
|
const InfoIcon = info.Icon ?? DefaultEntityIcon;
|
|
3242
|
-
const DoorControls = entityDoors?.DoorControls;
|
|
3243
3837
|
const { items, activeId } = adapter;
|
|
3244
3838
|
const active = items.find((i) => i.id === activeId) ?? null;
|
|
3245
3839
|
const activeIndex = active ? items.indexOf(active) : -1;
|
|
3246
|
-
const [open, setOpen] =
|
|
3247
|
-
const [query, setQuery] =
|
|
3248
|
-
const [creating, setCreating] =
|
|
3249
|
-
const [draftName, setDraftName] =
|
|
3250
|
-
const [busy, setBusy] =
|
|
3840
|
+
const [open, setOpen] = useState14(false);
|
|
3841
|
+
const [query, setQuery] = useState14("");
|
|
3842
|
+
const [creating, setCreating] = useState14(false);
|
|
3843
|
+
const [draftName, setDraftName] = useState14("");
|
|
3844
|
+
const [busy, setBusy] = useState14(false);
|
|
3251
3845
|
const entityLabel = info.label.toLowerCase();
|
|
3252
3846
|
const close = () => {
|
|
3253
3847
|
setOpen(false);
|
|
@@ -3264,7 +3858,7 @@ function AssociationEntitySelect({
|
|
|
3264
3858
|
if (id) close();
|
|
3265
3859
|
else notifier.error(`Couldn't create the ${entityLabel}`);
|
|
3266
3860
|
};
|
|
3267
|
-
return /* @__PURE__ */
|
|
3861
|
+
return /* @__PURE__ */ jsxs12(
|
|
3268
3862
|
"div",
|
|
3269
3863
|
{
|
|
3270
3864
|
className: cn10(
|
|
@@ -3272,7 +3866,7 @@ function AssociationEntitySelect({
|
|
|
3272
3866
|
className
|
|
3273
3867
|
),
|
|
3274
3868
|
children: [
|
|
3275
|
-
showIcon ? /* @__PURE__ */
|
|
3869
|
+
showIcon ? /* @__PURE__ */ jsx15(
|
|
3276
3870
|
InfoIcon,
|
|
3277
3871
|
{
|
|
3278
3872
|
className: cn10(
|
|
@@ -3282,7 +3876,7 @@ function AssociationEntitySelect({
|
|
|
3282
3876
|
"aria-hidden": true
|
|
3283
3877
|
}
|
|
3284
3878
|
) : null,
|
|
3285
|
-
active ? /* @__PURE__ */
|
|
3879
|
+
active ? /* @__PURE__ */ jsx15(
|
|
3286
3880
|
EditableLabel,
|
|
3287
3881
|
{
|
|
3288
3882
|
value: active.title,
|
|
@@ -3301,8 +3895,8 @@ function AssociationEntitySelect({
|
|
|
3301
3895
|
inputClassName: "text-xs font-medium"
|
|
3302
3896
|
}
|
|
3303
3897
|
) : null,
|
|
3304
|
-
active
|
|
3305
|
-
!active ? /* @__PURE__ */
|
|
3898
|
+
active ? /* @__PURE__ */ jsx15(DoorControlsSlot, { token, id: active.id, name: active.title }) : null,
|
|
3899
|
+
!active ? /* @__PURE__ */ jsx15(
|
|
3306
3900
|
"span",
|
|
3307
3901
|
{
|
|
3308
3902
|
className: cn10(
|
|
@@ -3312,13 +3906,13 @@ function AssociationEntitySelect({
|
|
|
3312
3906
|
children: adapter.loading ? "\u2026" : emptyLabel ?? info.labelPlural
|
|
3313
3907
|
}
|
|
3314
3908
|
) : null,
|
|
3315
|
-
/* @__PURE__ */
|
|
3909
|
+
/* @__PURE__ */ jsxs12(
|
|
3316
3910
|
Popover,
|
|
3317
3911
|
{
|
|
3318
3912
|
open,
|
|
3319
3913
|
onOpenChange: (next) => next ? setOpen(true) : close(),
|
|
3320
3914
|
children: [
|
|
3321
|
-
/* @__PURE__ */
|
|
3915
|
+
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
|
|
3322
3916
|
"button",
|
|
3323
3917
|
{
|
|
3324
3918
|
type: "button",
|
|
@@ -3326,17 +3920,17 @@ function AssociationEntitySelect({
|
|
|
3326
3920
|
title: `Switch or add ${info.labelPlural.toLowerCase()}`,
|
|
3327
3921
|
"aria-label": `Switch or add ${info.labelPlural.toLowerCase()}`,
|
|
3328
3922
|
children: [
|
|
3329
|
-
items.length > 1 ? /* @__PURE__ */
|
|
3923
|
+
items.length > 1 ? /* @__PURE__ */ jsxs12("span", { className: "tabular-nums", children: [
|
|
3330
3924
|
activeIndex >= 0 ? activeIndex + 1 : "\u2014",
|
|
3331
3925
|
"/",
|
|
3332
3926
|
items.length
|
|
3333
3927
|
] }) : null,
|
|
3334
|
-
/* @__PURE__ */
|
|
3928
|
+
/* @__PURE__ */ jsx15(ChevronDownIcon, { className: "size-3 opacity-60" })
|
|
3335
3929
|
]
|
|
3336
3930
|
}
|
|
3337
3931
|
) }),
|
|
3338
|
-
/* @__PURE__ */
|
|
3339
|
-
items.length > 5 ? /* @__PURE__ */
|
|
3932
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "w-60 p-0", align, children: /* @__PURE__ */ jsxs12(Command, { children: [
|
|
3933
|
+
items.length > 5 ? /* @__PURE__ */ jsx15(
|
|
3340
3934
|
CommandInput,
|
|
3341
3935
|
{
|
|
3342
3936
|
value: query,
|
|
@@ -3344,9 +3938,9 @@ function AssociationEntitySelect({
|
|
|
3344
3938
|
placeholder: `Search ${info.labelPlural.toLowerCase()}\u2026`
|
|
3345
3939
|
}
|
|
3346
3940
|
) : null,
|
|
3347
|
-
/* @__PURE__ */
|
|
3348
|
-
/* @__PURE__ */
|
|
3349
|
-
items.length > 0 ? /* @__PURE__ */
|
|
3941
|
+
/* @__PURE__ */ jsxs12(CommandList, { children: [
|
|
3942
|
+
/* @__PURE__ */ jsx15(CommandEmpty, { children: "No match." }),
|
|
3943
|
+
items.length > 0 ? /* @__PURE__ */ jsx15(CommandGroup, { children: items.map((item) => /* @__PURE__ */ jsxs12(
|
|
3350
3944
|
CommandItem,
|
|
3351
3945
|
{
|
|
3352
3946
|
value: `${item.title} ${item.id}`,
|
|
@@ -3357,7 +3951,7 @@ function AssociationEntitySelect({
|
|
|
3357
3951
|
},
|
|
3358
3952
|
className: "group/entity-ref group gap-2",
|
|
3359
3953
|
children: [
|
|
3360
|
-
/* @__PURE__ */
|
|
3954
|
+
/* @__PURE__ */ jsx15(
|
|
3361
3955
|
CheckIcon,
|
|
3362
3956
|
{
|
|
3363
3957
|
className: cn10(
|
|
@@ -3366,8 +3960,8 @@ function AssociationEntitySelect({
|
|
|
3366
3960
|
)
|
|
3367
3961
|
}
|
|
3368
3962
|
),
|
|
3369
|
-
/* @__PURE__ */
|
|
3370
|
-
|
|
3963
|
+
/* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 truncate", children: item.title }),
|
|
3964
|
+
/* @__PURE__ */ jsx15(
|
|
3371
3965
|
"span",
|
|
3372
3966
|
{
|
|
3373
3967
|
className: "inline-flex shrink-0 items-center",
|
|
@@ -3375,8 +3969,8 @@ function AssociationEntitySelect({
|
|
|
3375
3969
|
e.preventDefault();
|
|
3376
3970
|
e.stopPropagation();
|
|
3377
3971
|
},
|
|
3378
|
-
children: /* @__PURE__ */
|
|
3379
|
-
|
|
3972
|
+
children: /* @__PURE__ */ jsx15(
|
|
3973
|
+
DoorControlsSlot,
|
|
3380
3974
|
{
|
|
3381
3975
|
token,
|
|
3382
3976
|
id: item.id,
|
|
@@ -3384,8 +3978,8 @@ function AssociationEntitySelect({
|
|
|
3384
3978
|
}
|
|
3385
3979
|
)
|
|
3386
3980
|
}
|
|
3387
|
-
)
|
|
3388
|
-
adapter.detach && item.id !== activeId ? /* @__PURE__ */
|
|
3981
|
+
),
|
|
3982
|
+
adapter.detach && item.id !== activeId ? /* @__PURE__ */ jsx15(
|
|
3389
3983
|
"button",
|
|
3390
3984
|
{
|
|
3391
3985
|
type: "button",
|
|
@@ -3400,7 +3994,7 @@ function AssociationEntitySelect({
|
|
|
3400
3994
|
className: "grid size-5 shrink-0 place-items-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-destructive group-hover:opacity-100",
|
|
3401
3995
|
title: `Remove this ${entityLabel} from here (does not delete it)`,
|
|
3402
3996
|
"aria-label": `Remove ${item.title}`,
|
|
3403
|
-
children: /* @__PURE__ */
|
|
3997
|
+
children: /* @__PURE__ */ jsx15(XIcon, { className: "size-3" })
|
|
3404
3998
|
}
|
|
3405
3999
|
) : null
|
|
3406
4000
|
]
|
|
@@ -3408,9 +4002,9 @@ function AssociationEntitySelect({
|
|
|
3408
4002
|
item.id
|
|
3409
4003
|
)) }) : null
|
|
3410
4004
|
] }),
|
|
3411
|
-
createSlot !== void 0 ? /* @__PURE__ */
|
|
3412
|
-
createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */
|
|
3413
|
-
/* @__PURE__ */
|
|
4005
|
+
createSlot !== void 0 ? /* @__PURE__ */ jsx15("div", { className: "border-t border-border p-1", children: typeof createSlot === "function" ? createSlot(close) : createSlot }) : null,
|
|
4006
|
+
createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */ jsx15("div", { className: "border-t border-border p-1", children: creating ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1 px-1 py-0.5", children: [
|
|
4007
|
+
/* @__PURE__ */ jsx15(
|
|
3414
4008
|
"input",
|
|
3415
4009
|
{
|
|
3416
4010
|
autoFocus: true,
|
|
@@ -3434,17 +4028,17 @@ function AssociationEntitySelect({
|
|
|
3434
4028
|
"aria-label": `New ${entityLabel} name`
|
|
3435
4029
|
}
|
|
3436
4030
|
),
|
|
3437
|
-
/* @__PURE__ */
|
|
4031
|
+
/* @__PURE__ */ jsx15(
|
|
3438
4032
|
"button",
|
|
3439
4033
|
{
|
|
3440
4034
|
type: "button",
|
|
3441
4035
|
disabled: busy || !draftName.trim(),
|
|
3442
4036
|
onClick: () => void create(draftName),
|
|
3443
4037
|
className: "inline-flex h-6 shrink-0 items-center rounded-md px-1.5 text-[10px] font-medium text-primary transition-colors hover:bg-accent disabled:opacity-50",
|
|
3444
|
-
children: busy ? /* @__PURE__ */
|
|
4038
|
+
children: busy ? /* @__PURE__ */ jsx15(SpinnerIcon, { className: "size-3 animate-spin" }) : "Create"
|
|
3445
4039
|
}
|
|
3446
4040
|
)
|
|
3447
|
-
] }) : /* @__PURE__ */
|
|
4041
|
+
] }) : /* @__PURE__ */ jsxs12(
|
|
3448
4042
|
"button",
|
|
3449
4043
|
{
|
|
3450
4044
|
type: "button",
|
|
@@ -3455,7 +4049,7 @@ function AssociationEntitySelect({
|
|
|
3455
4049
|
},
|
|
3456
4050
|
className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
3457
4051
|
children: [
|
|
3458
|
-
busy ? /* @__PURE__ */
|
|
4052
|
+
busy ? /* @__PURE__ */ jsx15(SpinnerIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx15(PlusIcon, { className: "size-3.5" }),
|
|
3459
4053
|
query.trim() ? `Create "${query.trim()}"` : `New ${info.label}`
|
|
3460
4054
|
]
|
|
3461
4055
|
}
|
|
@@ -3470,7 +4064,7 @@ function AssociationEntitySelect({
|
|
|
3470
4064
|
}
|
|
3471
4065
|
|
|
3472
4066
|
// src/react/components/CategorySelect.tsx
|
|
3473
|
-
import { useState as
|
|
4067
|
+
import { useState as useState15 } from "react";
|
|
3474
4068
|
import {
|
|
3475
4069
|
CreatablePicker,
|
|
3476
4070
|
Select,
|
|
@@ -3545,7 +4139,7 @@ function buildCategoryHierarchy(categories) {
|
|
|
3545
4139
|
}
|
|
3546
4140
|
|
|
3547
4141
|
// src/react/components/CategorySelect.tsx
|
|
3548
|
-
import { jsx as
|
|
4142
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3549
4143
|
var NONE = "__none__";
|
|
3550
4144
|
var ROOT_PARENT = "__root__";
|
|
3551
4145
|
function plural(noun) {
|
|
@@ -3572,7 +4166,7 @@ function CategorySelect({
|
|
|
3572
4166
|
reload
|
|
3573
4167
|
} = useCategories({ dimension });
|
|
3574
4168
|
const hierarchy = buildCategoryHierarchy(categories);
|
|
3575
|
-
const [createParentId, setCreateParentId] =
|
|
4169
|
+
const [createParentId, setCreateParentId] = useState15(ROOT_PARENT);
|
|
3576
4170
|
const options = [
|
|
3577
4171
|
...allowNone ? [{ value: NONE, label: "None", keywords: "none clear empty" }] : [],
|
|
3578
4172
|
...hierarchy.hasHierarchy ? hierarchy.items.map(({ category, depth, parent }) => ({
|
|
@@ -3581,9 +4175,9 @@ function CategorySelect({
|
|
|
3581
4175
|
// The type-ahead matches the parent's name too, so someone who knows
|
|
3582
4176
|
// the branch but not the leaf still finds it.
|
|
3583
4177
|
keywords: parent ? parent.name : "",
|
|
3584
|
-
render: depth === 0 ? /* @__PURE__ */
|
|
3585
|
-
/* @__PURE__ */
|
|
3586
|
-
/* @__PURE__ */
|
|
4178
|
+
render: depth === 0 ? /* @__PURE__ */ jsx16("span", { className: "font-medium", children: category.name }) : /* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-1.5 pl-3 text-muted-foreground", children: [
|
|
4179
|
+
/* @__PURE__ */ jsx16(CornerDownRightIcon, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
4180
|
+
/* @__PURE__ */ jsx16("span", { className: "text-foreground", children: category.name })
|
|
3587
4181
|
] })
|
|
3588
4182
|
})) : categories.map((category) => ({
|
|
3589
4183
|
value: category.id,
|
|
@@ -3630,8 +4224,8 @@ function CategorySelect({
|
|
|
3630
4224
|
);
|
|
3631
4225
|
return result.id;
|
|
3632
4226
|
};
|
|
3633
|
-
return /* @__PURE__ */
|
|
3634
|
-
/* @__PURE__ */
|
|
4227
|
+
return /* @__PURE__ */ jsxs13("div", { children: [
|
|
4228
|
+
/* @__PURE__ */ jsx16(
|
|
3635
4229
|
CreatablePicker,
|
|
3636
4230
|
{
|
|
3637
4231
|
value: value ?? (allowNone ? NONE : null),
|
|
@@ -3647,18 +4241,18 @@ function CategorySelect({
|
|
|
3647
4241
|
emptyLabel: `No ${noun} matches that.`,
|
|
3648
4242
|
...allowCreate ? { onCreate: create } : {},
|
|
3649
4243
|
...allowCreate && hierarchy.hasHierarchy ? {
|
|
3650
|
-
createExtra: /* @__PURE__ */
|
|
3651
|
-
/* @__PURE__ */
|
|
4244
|
+
createExtra: /* @__PURE__ */ jsxs13(Select, { value: createParentId, onValueChange: setCreateParentId, children: [
|
|
4245
|
+
/* @__PURE__ */ jsx16(
|
|
3652
4246
|
SelectTrigger,
|
|
3653
4247
|
{
|
|
3654
4248
|
className: "h-7 text-xs",
|
|
3655
4249
|
"aria-label": `Put the new ${noun} under`,
|
|
3656
|
-
children: /* @__PURE__ */
|
|
4250
|
+
children: /* @__PURE__ */ jsx16(SelectValue, {})
|
|
3657
4251
|
}
|
|
3658
4252
|
),
|
|
3659
|
-
/* @__PURE__ */
|
|
3660
|
-
/* @__PURE__ */
|
|
3661
|
-
hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */
|
|
4253
|
+
/* @__PURE__ */ jsxs13(SelectContent, { children: [
|
|
4254
|
+
/* @__PURE__ */ jsx16(SelectItem, { value: ROOT_PARENT, className: "text-xs", children: "Top level" }),
|
|
4255
|
+
hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */ jsxs13(
|
|
3662
4256
|
SelectItem,
|
|
3663
4257
|
{
|
|
3664
4258
|
value: item.category.id,
|
|
@@ -3678,18 +4272,18 @@ function CategorySelect({
|
|
|
3678
4272
|
selected === null && value !== null ? (
|
|
3679
4273
|
// A stored id whose row this reader cannot see is not "nothing chosen":
|
|
3680
4274
|
// saying so beats a blank box that looks like an unsaved field.
|
|
3681
|
-
/* @__PURE__ */
|
|
4275
|
+
/* @__PURE__ */ jsxs13("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
3682
4276
|
"This ",
|
|
3683
4277
|
noun,
|
|
3684
4278
|
" is no longer available to you."
|
|
3685
4279
|
] })
|
|
3686
4280
|
) : null,
|
|
3687
|
-
error ? /* @__PURE__ */
|
|
4281
|
+
error ? /* @__PURE__ */ jsx16("p", { className: "mt-1 text-xs text-destructive", children: error }) : null
|
|
3688
4282
|
] });
|
|
3689
4283
|
}
|
|
3690
4284
|
|
|
3691
4285
|
// src/react/components/CategoryTagPicker.tsx
|
|
3692
|
-
import { useState as
|
|
4286
|
+
import { useState as useState16 } from "react";
|
|
3693
4287
|
import {
|
|
3694
4288
|
Badge,
|
|
3695
4289
|
Button as Button2,
|
|
@@ -3709,7 +4303,7 @@ import {
|
|
|
3709
4303
|
SelectTrigger as SelectTrigger2,
|
|
3710
4304
|
SelectValue as SelectValue2
|
|
3711
4305
|
} from "@ai-matrx/design-system";
|
|
3712
|
-
import { jsx as
|
|
4306
|
+
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3713
4307
|
var ROOT_PARENT2 = "__root__";
|
|
3714
4308
|
function CategoryTagPicker({
|
|
3715
4309
|
entityType,
|
|
@@ -3725,11 +4319,11 @@ function CategoryTagPicker({
|
|
|
3725
4319
|
}) {
|
|
3726
4320
|
const store = useAssociationsStore();
|
|
3727
4321
|
const notifier = useNotifier();
|
|
3728
|
-
const [open, setOpen] =
|
|
3729
|
-
const [creating, setCreating] =
|
|
3730
|
-
const [writing, setWriting] =
|
|
3731
|
-
const [search, setSearch] =
|
|
3732
|
-
const [createParentId, setCreateParentId] =
|
|
4322
|
+
const [open, setOpen] = useState16(false);
|
|
4323
|
+
const [creating, setCreating] = useState16(false);
|
|
4324
|
+
const [writing, setWriting] = useState16(false);
|
|
4325
|
+
const [search, setSearch] = useState16("");
|
|
4326
|
+
const [createParentId, setCreateParentId] = useState16(ROOT_PARENT2);
|
|
3733
4327
|
const {
|
|
3734
4328
|
categories,
|
|
3735
4329
|
create: createCategory,
|
|
@@ -3833,44 +4427,44 @@ function CategoryTagPicker({
|
|
|
3833
4427
|
const exactMatch = categories.some(
|
|
3834
4428
|
(c) => c.name.toLowerCase() === search.trim().toLowerCase()
|
|
3835
4429
|
);
|
|
3836
|
-
return /* @__PURE__ */
|
|
3837
|
-
selected.map((c) => /* @__PURE__ */
|
|
4430
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
4431
|
+
selected.map((c) => /* @__PURE__ */ jsxs14(
|
|
3838
4432
|
Badge,
|
|
3839
4433
|
{
|
|
3840
4434
|
variant: "secondary",
|
|
3841
4435
|
className: "gap-1 pr-1 text-xs font-medium",
|
|
3842
4436
|
children: [
|
|
3843
4437
|
showHierarchy ? hierarchyById.get(c.id)?.displayName ?? c.name : c.name,
|
|
3844
|
-
/* @__PURE__ */
|
|
4438
|
+
/* @__PURE__ */ jsx17(
|
|
3845
4439
|
"button",
|
|
3846
4440
|
{
|
|
3847
4441
|
type: "button",
|
|
3848
4442
|
onClick: () => void toggle(c.id),
|
|
3849
4443
|
className: "ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20",
|
|
3850
4444
|
"aria-label": `Remove ${c.name}`,
|
|
3851
|
-
children: /* @__PURE__ */
|
|
4445
|
+
children: /* @__PURE__ */ jsx17(XIcon, { className: "h-2.5 w-2.5" })
|
|
3852
4446
|
}
|
|
3853
4447
|
)
|
|
3854
4448
|
]
|
|
3855
4449
|
},
|
|
3856
4450
|
c.id
|
|
3857
4451
|
)),
|
|
3858
|
-
/* @__PURE__ */
|
|
3859
|
-
/* @__PURE__ */
|
|
4452
|
+
/* @__PURE__ */ jsxs14(Popover2, { open, onOpenChange: setOpen, children: [
|
|
4453
|
+
/* @__PURE__ */ jsx17(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs14(
|
|
3860
4454
|
Button2,
|
|
3861
4455
|
{
|
|
3862
4456
|
variant: "outline",
|
|
3863
4457
|
size: "sm",
|
|
3864
4458
|
className: "h-7 gap-1 px-2 text-xs",
|
|
3865
4459
|
children: [
|
|
3866
|
-
/* @__PURE__ */
|
|
4460
|
+
/* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5" }),
|
|
3867
4461
|
selected.length === 0 ? addLabel : "Edit",
|
|
3868
|
-
/* @__PURE__ */
|
|
4462
|
+
/* @__PURE__ */ jsx17(ChevronsUpDownIcon, { className: "h-3 w-3 opacity-50" })
|
|
3869
4463
|
]
|
|
3870
4464
|
}
|
|
3871
4465
|
) }),
|
|
3872
|
-
/* @__PURE__ */
|
|
3873
|
-
/* @__PURE__ */
|
|
4466
|
+
/* @__PURE__ */ jsx17(PopoverContent2, { className: "w-56 p-0", align: "start", children: /* @__PURE__ */ jsxs14(Command2, { shouldFilter: false, children: [
|
|
4467
|
+
/* @__PURE__ */ jsx17(
|
|
3874
4468
|
CommandInput2,
|
|
3875
4469
|
{
|
|
3876
4470
|
placeholder: allowCreate ? "Search or create..." : "Search...",
|
|
@@ -3878,9 +4472,9 @@ function CategoryTagPicker({
|
|
|
3878
4472
|
onValueChange: setSearch
|
|
3879
4473
|
}
|
|
3880
4474
|
),
|
|
3881
|
-
/* @__PURE__ */
|
|
3882
|
-
/* @__PURE__ */
|
|
3883
|
-
/* @__PURE__ */
|
|
4475
|
+
/* @__PURE__ */ jsxs14(CommandList2, { children: [
|
|
4476
|
+
/* @__PURE__ */ jsx17(CommandEmpty2, { className: "px-2 py-3 text-xs text-muted-foreground", children: search.trim() ? "No match." : emptyText }),
|
|
4477
|
+
/* @__PURE__ */ jsx17(CommandGroup2, { children: showHierarchy ? filteredHierarchy.map(({ category, depth, parent }) => /* @__PURE__ */ jsxs14(
|
|
3884
4478
|
CommandItem2,
|
|
3885
4479
|
{
|
|
3886
4480
|
value: category.id,
|
|
@@ -3888,7 +4482,7 @@ function CategoryTagPicker({
|
|
|
3888
4482
|
onSelect: () => void toggle(category.id),
|
|
3889
4483
|
className: cn11("text-xs", depth === 1 && "pl-6"),
|
|
3890
4484
|
children: [
|
|
3891
|
-
/* @__PURE__ */
|
|
4485
|
+
/* @__PURE__ */ jsx17(
|
|
3892
4486
|
CheckIcon,
|
|
3893
4487
|
{
|
|
3894
4488
|
className: cn11(
|
|
@@ -3897,19 +4491,19 @@ function CategoryTagPicker({
|
|
|
3897
4491
|
)
|
|
3898
4492
|
}
|
|
3899
4493
|
),
|
|
3900
|
-
depth === 1 ? /* @__PURE__ */
|
|
3901
|
-
/* @__PURE__ */
|
|
4494
|
+
depth === 1 ? /* @__PURE__ */ jsx17(CornerDownRightIcon, { className: "mr-1.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }) : null,
|
|
4495
|
+
/* @__PURE__ */ jsx17("span", { className: cn11(depth === 0 && "font-medium"), children: category.name })
|
|
3902
4496
|
]
|
|
3903
4497
|
},
|
|
3904
4498
|
category.id
|
|
3905
|
-
)) : filtered.map((c) => /* @__PURE__ */
|
|
4499
|
+
)) : filtered.map((c) => /* @__PURE__ */ jsxs14(
|
|
3906
4500
|
CommandItem2,
|
|
3907
4501
|
{
|
|
3908
4502
|
value: c.id,
|
|
3909
4503
|
onSelect: () => void toggle(c.id),
|
|
3910
4504
|
className: "text-xs",
|
|
3911
4505
|
children: [
|
|
3912
|
-
/* @__PURE__ */
|
|
4506
|
+
/* @__PURE__ */ jsx17(
|
|
3913
4507
|
CheckIcon,
|
|
3914
4508
|
{
|
|
3915
4509
|
className: cn11(
|
|
@@ -3923,25 +4517,25 @@ function CategoryTagPicker({
|
|
|
3923
4517
|
},
|
|
3924
4518
|
c.id
|
|
3925
4519
|
)) }),
|
|
3926
|
-
allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */
|
|
3927
|
-
showHierarchy ? /* @__PURE__ */
|
|
3928
|
-
/* @__PURE__ */
|
|
3929
|
-
/* @__PURE__ */
|
|
4520
|
+
allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */ jsxs14(CommandGroup2, { children: [
|
|
4521
|
+
showHierarchy ? /* @__PURE__ */ jsxs14("div", { className: "space-y-1.5 px-2 pb-2", children: [
|
|
4522
|
+
/* @__PURE__ */ jsx17("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Place in" }),
|
|
4523
|
+
/* @__PURE__ */ jsxs14(
|
|
3930
4524
|
Select2,
|
|
3931
4525
|
{
|
|
3932
4526
|
value: createParentId,
|
|
3933
4527
|
onValueChange: setCreateParentId,
|
|
3934
4528
|
children: [
|
|
3935
|
-
/* @__PURE__ */
|
|
3936
|
-
/* @__PURE__ */
|
|
3937
|
-
/* @__PURE__ */
|
|
3938
|
-
hierarchy.roots.map((root) => /* @__PURE__ */
|
|
4529
|
+
/* @__PURE__ */ jsx17(SelectTrigger2, { size: "sm", className: "bg-background", children: /* @__PURE__ */ jsx17(SelectValue2, {}) }),
|
|
4530
|
+
/* @__PURE__ */ jsxs14(SelectContent2, { children: [
|
|
4531
|
+
/* @__PURE__ */ jsx17(SelectItem2, { value: ROOT_PARENT2, children: "Top level" }),
|
|
4532
|
+
hierarchy.roots.map((root) => /* @__PURE__ */ jsx17(SelectItem2, { value: root.id, children: root.name }, root.id))
|
|
3939
4533
|
] })
|
|
3940
4534
|
]
|
|
3941
4535
|
}
|
|
3942
4536
|
)
|
|
3943
4537
|
] }) : null,
|
|
3944
|
-
/* @__PURE__ */
|
|
4538
|
+
/* @__PURE__ */ jsxs14(
|
|
3945
4539
|
CommandItem2,
|
|
3946
4540
|
{
|
|
3947
4541
|
value: `__create__${search}`,
|
|
@@ -3949,7 +4543,7 @@ function CategoryTagPicker({
|
|
|
3949
4543
|
disabled: creating,
|
|
3950
4544
|
className: "text-xs text-primary",
|
|
3951
4545
|
children: [
|
|
3952
|
-
creating ? /* @__PURE__ */
|
|
4546
|
+
creating ? /* @__PURE__ */ jsx17(SpinnerIcon, { className: "mr-2 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx17(Icon, { className: "mr-2 h-3.5 w-3.5" }),
|
|
3953
4547
|
"Create \u201C",
|
|
3954
4548
|
search.trim(),
|
|
3955
4549
|
"\u201D"
|
|
@@ -3964,7 +4558,7 @@ function CategoryTagPicker({
|
|
|
3964
4558
|
}
|
|
3965
4559
|
|
|
3966
4560
|
// src/react/components/CommentThread.tsx
|
|
3967
|
-
import { useState as
|
|
4561
|
+
import { useState as useState17 } from "react";
|
|
3968
4562
|
import { Button as Button3, Skeleton as Skeleton2, cn as cn12 } from "@ai-matrx/design-system";
|
|
3969
4563
|
|
|
3970
4564
|
// src/react/relativeTime.ts
|
|
@@ -3992,7 +4586,7 @@ function formatRelativeTime(iso, now = Date.now()) {
|
|
|
3992
4586
|
}
|
|
3993
4587
|
|
|
3994
4588
|
// src/react/components/CommentThread.tsx
|
|
3995
|
-
import { Fragment as Fragment5, jsx as
|
|
4589
|
+
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3996
4590
|
var AUTHOR_DOOR_TOKEN = "user";
|
|
3997
4591
|
function resolveAuthor(comment, authorDisplay) {
|
|
3998
4592
|
const base2 = {
|
|
@@ -4011,7 +4605,7 @@ function resolveAuthor(comment, authorDisplay) {
|
|
|
4011
4605
|
}
|
|
4012
4606
|
function AuthorAvatar({ author }) {
|
|
4013
4607
|
if (author.avatarUrl) {
|
|
4014
|
-
return /* @__PURE__ */
|
|
4608
|
+
return /* @__PURE__ */ jsx18(
|
|
4015
4609
|
"img",
|
|
4016
4610
|
{
|
|
4017
4611
|
src: author.avatarUrl,
|
|
@@ -4020,7 +4614,7 @@ function AuthorAvatar({ author }) {
|
|
|
4020
4614
|
}
|
|
4021
4615
|
);
|
|
4022
4616
|
}
|
|
4023
|
-
return /* @__PURE__ */
|
|
4617
|
+
return /* @__PURE__ */ jsx18(
|
|
4024
4618
|
"span",
|
|
4025
4619
|
{
|
|
4026
4620
|
"aria-hidden": true,
|
|
@@ -4035,7 +4629,7 @@ function AuthorName({
|
|
|
4035
4629
|
}) {
|
|
4036
4630
|
const DoorRef2 = entityDoors?.EntityRef;
|
|
4037
4631
|
if (DoorRef2 && author.userId) {
|
|
4038
|
-
return /* @__PURE__ */
|
|
4632
|
+
return /* @__PURE__ */ jsx18(
|
|
4039
4633
|
DoorRef2,
|
|
4040
4634
|
{
|
|
4041
4635
|
token: AUTHOR_DOOR_TOKEN,
|
|
@@ -4046,7 +4640,7 @@ function AuthorName({
|
|
|
4046
4640
|
}
|
|
4047
4641
|
);
|
|
4048
4642
|
}
|
|
4049
|
-
return /* @__PURE__ */
|
|
4643
|
+
return /* @__PURE__ */ jsx18("span", { className: "text-sm font-medium text-foreground", children: author.name });
|
|
4050
4644
|
}
|
|
4051
4645
|
function CommentComposer({
|
|
4052
4646
|
onSubmit,
|
|
@@ -4057,9 +4651,9 @@ function CommentComposer({
|
|
|
4057
4651
|
autoFocus = false
|
|
4058
4652
|
}) {
|
|
4059
4653
|
const notifier = useNotifier();
|
|
4060
|
-
const [body, setBody] =
|
|
4061
|
-
const [submitting, setSubmitting] =
|
|
4062
|
-
const [error, setError] =
|
|
4654
|
+
const [body, setBody] = useState17(initialValue);
|
|
4655
|
+
const [submitting, setSubmitting] = useState17(false);
|
|
4656
|
+
const [error, setError] = useState17(null);
|
|
4063
4657
|
async function submit(e) {
|
|
4064
4658
|
e?.preventDefault();
|
|
4065
4659
|
const trimmed = body.trim();
|
|
@@ -4076,8 +4670,8 @@ function CommentComposer({
|
|
|
4076
4670
|
}
|
|
4077
4671
|
setBody("");
|
|
4078
4672
|
}
|
|
4079
|
-
return /* @__PURE__ */
|
|
4080
|
-
/* @__PURE__ */
|
|
4673
|
+
return /* @__PURE__ */ jsxs15("form", { onSubmit: submit, className: "flex flex-col gap-1.5", children: [
|
|
4674
|
+
/* @__PURE__ */ jsx18(
|
|
4081
4675
|
"textarea",
|
|
4082
4676
|
{
|
|
4083
4677
|
value: body,
|
|
@@ -4092,10 +4686,10 @@ function CommentComposer({
|
|
|
4092
4686
|
className: "w-full resize-y rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
4093
4687
|
}
|
|
4094
4688
|
),
|
|
4095
|
-
error && /* @__PURE__ */
|
|
4096
|
-
/* @__PURE__ */
|
|
4097
|
-
/* @__PURE__ */
|
|
4098
|
-
submitting && /* @__PURE__ */
|
|
4689
|
+
error && /* @__PURE__ */ jsx18("p", { role: "alert", className: "text-xs text-destructive", children: error }),
|
|
4690
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
|
|
4691
|
+
/* @__PURE__ */ jsxs15(Button3, { type: "submit", size: "sm", disabled: !body.trim() || submitting, children: [
|
|
4692
|
+
submitting && /* @__PURE__ */ jsx18(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
|
|
4099
4693
|
submitLabel
|
|
4100
4694
|
] }),
|
|
4101
4695
|
trailing
|
|
@@ -4111,10 +4705,10 @@ function CommentItem({
|
|
|
4111
4705
|
}) {
|
|
4112
4706
|
const { authorDisplay, entityDoors } = useAssociationsUiPorts();
|
|
4113
4707
|
const notifier = useNotifier();
|
|
4114
|
-
const [replying, setReplying] =
|
|
4115
|
-
const [editing, setEditing] =
|
|
4116
|
-
const [confirmingDelete, setConfirmingDelete] =
|
|
4117
|
-
const [deleting, setDeleting] =
|
|
4708
|
+
const [replying, setReplying] = useState17(false);
|
|
4709
|
+
const [editing, setEditing] = useState17(false);
|
|
4710
|
+
const [confirmingDelete, setConfirmingDelete] = useState17(false);
|
|
4711
|
+
const [deleting, setDeleting] = useState17(false);
|
|
4118
4712
|
const author = resolveAuthor(comment, authorDisplay);
|
|
4119
4713
|
const isOwn = thread.currentUserId !== null && comment.createdBy === thread.currentUserId;
|
|
4120
4714
|
const edited = comment.updatedAt !== comment.createdAt;
|
|
@@ -4128,7 +4722,7 @@ function CommentItem({
|
|
|
4128
4722
|
notifier.error(res.error ?? "Could not delete the comment");
|
|
4129
4723
|
}
|
|
4130
4724
|
}
|
|
4131
|
-
return /* @__PURE__ */
|
|
4725
|
+
return /* @__PURE__ */ jsxs15(
|
|
4132
4726
|
"div",
|
|
4133
4727
|
{
|
|
4134
4728
|
"data-comment-id": comment.id,
|
|
@@ -4137,10 +4731,10 @@ function CommentItem({
|
|
|
4137
4731
|
depth > 0 && "border-l border-border pl-3"
|
|
4138
4732
|
),
|
|
4139
4733
|
children: [
|
|
4140
|
-
/* @__PURE__ */
|
|
4141
|
-
/* @__PURE__ */
|
|
4142
|
-
/* @__PURE__ */
|
|
4143
|
-
/* @__PURE__ */
|
|
4734
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
|
|
4735
|
+
/* @__PURE__ */ jsx18(AuthorAvatar, { author }),
|
|
4736
|
+
/* @__PURE__ */ jsx18(AuthorName, { author, entityDoors }),
|
|
4737
|
+
/* @__PURE__ */ jsx18(
|
|
4144
4738
|
"span",
|
|
4145
4739
|
{
|
|
4146
4740
|
className: "text-xs text-muted-foreground",
|
|
@@ -4148,7 +4742,7 @@ function CommentItem({
|
|
|
4148
4742
|
children: formatRelativeTime(comment.createdAt)
|
|
4149
4743
|
}
|
|
4150
4744
|
),
|
|
4151
|
-
edited && /* @__PURE__ */
|
|
4745
|
+
edited && /* @__PURE__ */ jsx18(
|
|
4152
4746
|
"span",
|
|
4153
4747
|
{
|
|
4154
4748
|
className: "text-xs text-muted-foreground",
|
|
@@ -4157,7 +4751,7 @@ function CommentItem({
|
|
|
4157
4751
|
}
|
|
4158
4752
|
)
|
|
4159
4753
|
] }),
|
|
4160
|
-
editing ? /* @__PURE__ */
|
|
4754
|
+
editing ? /* @__PURE__ */ jsx18("div", { className: "pl-8", children: /* @__PURE__ */ jsx18(
|
|
4161
4755
|
CommentComposer,
|
|
4162
4756
|
{
|
|
4163
4757
|
initialValue: comment.body,
|
|
@@ -4169,7 +4763,7 @@ function CommentItem({
|
|
|
4169
4763
|
if (res.ok) setEditing(false);
|
|
4170
4764
|
return res;
|
|
4171
4765
|
},
|
|
4172
|
-
trailing: /* @__PURE__ */
|
|
4766
|
+
trailing: /* @__PURE__ */ jsx18(
|
|
4173
4767
|
Button3,
|
|
4174
4768
|
{
|
|
4175
4769
|
type: "button",
|
|
@@ -4180,10 +4774,10 @@ function CommentItem({
|
|
|
4180
4774
|
}
|
|
4181
4775
|
)
|
|
4182
4776
|
}
|
|
4183
|
-
) }) : /* @__PURE__ */
|
|
4184
|
-
!editing && /* @__PURE__ */
|
|
4185
|
-
/* @__PURE__ */
|
|
4186
|
-
/* @__PURE__ */
|
|
4777
|
+
) }) : /* @__PURE__ */ jsx18("p", { className: "whitespace-pre-wrap pl-8 text-sm text-foreground", children: comment.body }),
|
|
4778
|
+
!editing && /* @__PURE__ */ jsx18("div", { className: "flex items-center gap-1 pl-7", children: confirmingDelete ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
4779
|
+
/* @__PURE__ */ jsx18("span", { className: "text-xs text-destructive", children: "Deletes this comment for everyone." }),
|
|
4780
|
+
/* @__PURE__ */ jsxs15(
|
|
4187
4781
|
Button3,
|
|
4188
4782
|
{
|
|
4189
4783
|
type: "button",
|
|
@@ -4192,12 +4786,12 @@ function CommentItem({
|
|
|
4192
4786
|
disabled: deleting,
|
|
4193
4787
|
onClick: () => void confirmDelete(),
|
|
4194
4788
|
children: [
|
|
4195
|
-
deleting && /* @__PURE__ */
|
|
4789
|
+
deleting && /* @__PURE__ */ jsx18(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
|
|
4196
4790
|
"Delete"
|
|
4197
4791
|
]
|
|
4198
4792
|
}
|
|
4199
4793
|
),
|
|
4200
|
-
/* @__PURE__ */
|
|
4794
|
+
/* @__PURE__ */ jsx18(
|
|
4201
4795
|
Button3,
|
|
4202
4796
|
{
|
|
4203
4797
|
type: "button",
|
|
@@ -4208,8 +4802,8 @@ function CommentItem({
|
|
|
4208
4802
|
children: "Cancel"
|
|
4209
4803
|
}
|
|
4210
4804
|
)
|
|
4211
|
-
] }) : /* @__PURE__ */
|
|
4212
|
-
/* @__PURE__ */
|
|
4805
|
+
] }) : /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
4806
|
+
/* @__PURE__ */ jsx18(
|
|
4213
4807
|
"button",
|
|
4214
4808
|
{
|
|
4215
4809
|
type: "button",
|
|
@@ -4218,8 +4812,8 @@ function CommentItem({
|
|
|
4218
4812
|
children: "Reply"
|
|
4219
4813
|
}
|
|
4220
4814
|
),
|
|
4221
|
-
isOwn && /* @__PURE__ */
|
|
4222
|
-
/* @__PURE__ */
|
|
4815
|
+
isOwn && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
4816
|
+
/* @__PURE__ */ jsx18(
|
|
4223
4817
|
"button",
|
|
4224
4818
|
{
|
|
4225
4819
|
type: "button",
|
|
@@ -4228,7 +4822,7 @@ function CommentItem({
|
|
|
4228
4822
|
children: "Edit"
|
|
4229
4823
|
}
|
|
4230
4824
|
),
|
|
4231
|
-
/* @__PURE__ */
|
|
4825
|
+
/* @__PURE__ */ jsx18(
|
|
4232
4826
|
"button",
|
|
4233
4827
|
{
|
|
4234
4828
|
type: "button",
|
|
@@ -4239,9 +4833,9 @@ function CommentItem({
|
|
|
4239
4833
|
)
|
|
4240
4834
|
] })
|
|
4241
4835
|
] }) }),
|
|
4242
|
-
replying && /* @__PURE__ */
|
|
4243
|
-
/* @__PURE__ */
|
|
4244
|
-
/* @__PURE__ */
|
|
4836
|
+
replying && /* @__PURE__ */ jsxs15("div", { className: "flex items-start gap-2 pl-8 pt-1", children: [
|
|
4837
|
+
/* @__PURE__ */ jsx18(CornerDownRightIcon, { className: "mt-2 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
4838
|
+
/* @__PURE__ */ jsx18("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx18(
|
|
4245
4839
|
CommentComposer,
|
|
4246
4840
|
{
|
|
4247
4841
|
submitLabel: "Reply",
|
|
@@ -4255,7 +4849,7 @@ function CommentItem({
|
|
|
4255
4849
|
if (res.ok) setReplying(false);
|
|
4256
4850
|
return res;
|
|
4257
4851
|
},
|
|
4258
|
-
trailing: /* @__PURE__ */
|
|
4852
|
+
trailing: /* @__PURE__ */ jsx18(
|
|
4259
4853
|
Button3,
|
|
4260
4854
|
{
|
|
4261
4855
|
type: "button",
|
|
@@ -4268,7 +4862,7 @@ function CommentItem({
|
|
|
4268
4862
|
}
|
|
4269
4863
|
) })
|
|
4270
4864
|
] }),
|
|
4271
|
-
replies.length > 0 && /* @__PURE__ */
|
|
4865
|
+
replies.length > 0 && /* @__PURE__ */ jsx18("div", { className: "flex flex-col gap-3 pl-8 pt-1", children: replies.map((reply) => /* @__PURE__ */ jsx18(
|
|
4272
4866
|
CommentItem,
|
|
4273
4867
|
{
|
|
4274
4868
|
comment: reply,
|
|
@@ -4308,11 +4902,11 @@ function CommentThread({
|
|
|
4308
4902
|
const thread = useComments({ token, id });
|
|
4309
4903
|
const { roots, childrenOf } = buildCommentTree(thread.comments);
|
|
4310
4904
|
const loading = (thread.status === "loading" || thread.status === "idle") && thread.comments.length === 0;
|
|
4311
|
-
return /* @__PURE__ */
|
|
4312
|
-
showHeader && /* @__PURE__ */
|
|
4313
|
-
/* @__PURE__ */
|
|
4314
|
-
/* @__PURE__ */
|
|
4315
|
-
/* @__PURE__ */
|
|
4905
|
+
return /* @__PURE__ */ jsxs15("section", { className: cn12("flex flex-col gap-3", className), children: [
|
|
4906
|
+
showHeader && /* @__PURE__ */ jsxs15("header", { className: "flex items-center gap-2", children: [
|
|
4907
|
+
/* @__PURE__ */ jsx18("h3", { className: "text-sm font-semibold text-foreground", children: "Comments" }),
|
|
4908
|
+
/* @__PURE__ */ jsx18("span", { className: "text-xs text-muted-foreground tabular-nums", children: thread.comments.length }),
|
|
4909
|
+
/* @__PURE__ */ jsx18(
|
|
4316
4910
|
"button",
|
|
4317
4911
|
{
|
|
4318
4912
|
type: "button",
|
|
@@ -4320,18 +4914,18 @@ function CommentThread({
|
|
|
4320
4914
|
"aria-label": "Refresh comments",
|
|
4321
4915
|
title: "Refresh comments",
|
|
4322
4916
|
className: "ml-auto flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
4323
|
-
children: thread.status === "loading" ? /* @__PURE__ */
|
|
4917
|
+
children: thread.status === "loading" ? /* @__PURE__ */ jsx18(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx18(RefreshIcon, { className: "h-3.5 w-3.5" })
|
|
4324
4918
|
}
|
|
4325
4919
|
)
|
|
4326
4920
|
] }),
|
|
4327
|
-
thread.error && /* @__PURE__ */
|
|
4921
|
+
thread.error && /* @__PURE__ */ jsxs15(
|
|
4328
4922
|
"div",
|
|
4329
4923
|
{
|
|
4330
4924
|
role: "alert",
|
|
4331
4925
|
className: "flex items-center gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
4332
4926
|
children: [
|
|
4333
|
-
/* @__PURE__ */
|
|
4334
|
-
/* @__PURE__ */
|
|
4927
|
+
/* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1", children: thread.error }),
|
|
4928
|
+
/* @__PURE__ */ jsx18(
|
|
4335
4929
|
Button3,
|
|
4336
4930
|
{
|
|
4337
4931
|
type: "button",
|
|
@@ -4345,10 +4939,10 @@ function CommentThread({
|
|
|
4345
4939
|
]
|
|
4346
4940
|
}
|
|
4347
4941
|
),
|
|
4348
|
-
loading ? /* @__PURE__ */
|
|
4349
|
-
/* @__PURE__ */
|
|
4350
|
-
/* @__PURE__ */
|
|
4351
|
-
] }) : roots.length === 0 && !thread.error ? /* @__PURE__ */
|
|
4942
|
+
loading ? /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3", "aria-hidden": true, "data-testid": "comments-loading", children: [
|
|
4943
|
+
/* @__PURE__ */ jsx18(Skeleton2, { className: "h-12 w-full" }),
|
|
4944
|
+
/* @__PURE__ */ jsx18(Skeleton2, { className: "h-12 w-4/5" })
|
|
4945
|
+
] }) : roots.length === 0 && !thread.error ? /* @__PURE__ */ jsx18("p", { className: "text-sm text-muted-foreground", children: "No comments yet." }) : /* @__PURE__ */ jsx18("div", { className: "flex flex-col gap-4", children: roots.map((comment) => /* @__PURE__ */ jsx18(
|
|
4352
4946
|
CommentItem,
|
|
4353
4947
|
{
|
|
4354
4948
|
comment,
|
|
@@ -4359,7 +4953,7 @@ function CommentThread({
|
|
|
4359
4953
|
},
|
|
4360
4954
|
comment.id
|
|
4361
4955
|
)) }),
|
|
4362
|
-
/* @__PURE__ */
|
|
4956
|
+
/* @__PURE__ */ jsx18(
|
|
4363
4957
|
CommentComposer,
|
|
4364
4958
|
{
|
|
4365
4959
|
onSubmit: (body) => thread.add(body, { orgId: orgId ?? null })
|
|
@@ -4385,6 +4979,8 @@ export {
|
|
|
4385
4979
|
CommentComposer,
|
|
4386
4980
|
CommentThread,
|
|
4387
4981
|
DefaultEntityIcon,
|
|
4982
|
+
DefaultWindowShell,
|
|
4983
|
+
DoorControlsSlot,
|
|
4388
4984
|
DoorRef,
|
|
4389
4985
|
PrimaryEntityProvider,
|
|
4390
4986
|
UniversalAssociationPicker,
|
|
@@ -4393,8 +4989,11 @@ export {
|
|
|
4393
4989
|
buildCommentTree,
|
|
4394
4990
|
formatRelativeTime,
|
|
4395
4991
|
getContentRoleMeta,
|
|
4992
|
+
lazyPickerOverride,
|
|
4993
|
+
lazyWindowShell,
|
|
4396
4994
|
useAssociationCandidates,
|
|
4397
4995
|
useAssociationEntitySelectAdapter,
|
|
4996
|
+
useAssociationPickerBridge,
|
|
4398
4997
|
useAssociations,
|
|
4399
4998
|
useAssociationsStore,
|
|
4400
4999
|
useAssociationsUiPorts,
|