@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.cjs
CHANGED
|
@@ -38,6 +38,8 @@ __export(react_exports, {
|
|
|
38
38
|
CommentComposer: () => CommentComposer,
|
|
39
39
|
CommentThread: () => CommentThread,
|
|
40
40
|
DefaultEntityIcon: () => DefaultEntityIcon,
|
|
41
|
+
DefaultWindowShell: () => DefaultWindowShell,
|
|
42
|
+
DoorControlsSlot: () => DoorControlsSlot,
|
|
41
43
|
DoorRef: () => DoorRef,
|
|
42
44
|
PrimaryEntityProvider: () => PrimaryEntityProvider,
|
|
43
45
|
UniversalAssociationPicker: () => UniversalAssociationPicker,
|
|
@@ -46,8 +48,11 @@ __export(react_exports, {
|
|
|
46
48
|
buildCommentTree: () => buildCommentTree,
|
|
47
49
|
formatRelativeTime: () => formatRelativeTime,
|
|
48
50
|
getContentRoleMeta: () => getContentRoleMeta,
|
|
51
|
+
lazyPickerOverride: () => lazyPickerOverride,
|
|
52
|
+
lazyWindowShell: () => lazyWindowShell,
|
|
49
53
|
useAssociationCandidates: () => useAssociationCandidates,
|
|
50
54
|
useAssociationEntitySelectAdapter: () => useAssociationEntitySelectAdapter,
|
|
55
|
+
useAssociationPickerBridge: () => useAssociationPickerBridge,
|
|
51
56
|
useAssociations: () => useAssociations,
|
|
52
57
|
useAssociationsStore: () => useAssociationsStore,
|
|
53
58
|
useAssociationsUiPorts: () => useAssociationsUiPorts,
|
|
@@ -65,12 +70,185 @@ module.exports = __toCommonJS(react_exports);
|
|
|
65
70
|
|
|
66
71
|
// src/react/context.tsx
|
|
67
72
|
var import_react = require("react");
|
|
73
|
+
|
|
74
|
+
// src/demanded-rpcs.generated.ts
|
|
75
|
+
var DEMANDED_RPC_NAMES = [
|
|
76
|
+
"assoc_add",
|
|
77
|
+
"assoc_remove",
|
|
78
|
+
"assoc_set_targets",
|
|
79
|
+
"assoc_remove_for_entity",
|
|
80
|
+
"assoc_for_entity",
|
|
81
|
+
"assoc_for_targets",
|
|
82
|
+
"assoc_for_sources",
|
|
83
|
+
"assoc_members_visible",
|
|
84
|
+
"conversation_file_add",
|
|
85
|
+
"conversation_file_remove",
|
|
86
|
+
"conversation_files",
|
|
87
|
+
"agent_resource_add",
|
|
88
|
+
"agent_resource_remove",
|
|
89
|
+
"cat_list",
|
|
90
|
+
"cat_create",
|
|
91
|
+
"cat_update",
|
|
92
|
+
"cat_reparent",
|
|
93
|
+
"cat_delete",
|
|
94
|
+
"ues_set",
|
|
95
|
+
"ues_list",
|
|
96
|
+
"ues_get_bulk",
|
|
97
|
+
"ues_touch",
|
|
98
|
+
"reference_search_candidates",
|
|
99
|
+
"cmt_list",
|
|
100
|
+
"cmt_add",
|
|
101
|
+
"cmt_edit",
|
|
102
|
+
"cmt_delete"
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
// src/core/assertDemandedSchema.ts
|
|
106
|
+
var BAD_UUID = "__not_a_uuid__";
|
|
107
|
+
var SELF_TEST_MISSING_RPC = "assoc_probe_self_test_missing_fn";
|
|
108
|
+
var PROBE_ARGS = {
|
|
109
|
+
// edges — writes
|
|
110
|
+
assoc_add: {
|
|
111
|
+
p_source_type: "note",
|
|
112
|
+
p_source_id: BAD_UUID,
|
|
113
|
+
p_target_type: "task",
|
|
114
|
+
p_target_id: BAD_UUID
|
|
115
|
+
},
|
|
116
|
+
assoc_remove: {
|
|
117
|
+
p_source_type: "note",
|
|
118
|
+
p_source_id: BAD_UUID,
|
|
119
|
+
p_target_type: "task",
|
|
120
|
+
p_target_id: BAD_UUID
|
|
121
|
+
},
|
|
122
|
+
assoc_set_targets: {
|
|
123
|
+
p_source_type: "note",
|
|
124
|
+
p_source_id: BAD_UUID,
|
|
125
|
+
p_target_type: "task",
|
|
126
|
+
p_target_ids: [BAD_UUID]
|
|
127
|
+
},
|
|
128
|
+
assoc_remove_for_entity: { p_type: "note", p_id: BAD_UUID },
|
|
129
|
+
// edges — reads
|
|
130
|
+
assoc_for_entity: { p_type: "note", p_id: BAD_UUID },
|
|
131
|
+
assoc_for_targets: { p_target_type: "task", p_target_ids: [BAD_UUID] },
|
|
132
|
+
assoc_for_sources: { p_source_type: "note", p_source_ids: [BAD_UUID] },
|
|
133
|
+
assoc_members_visible: { p_target_type: "task", p_target_ids: [BAD_UUID] },
|
|
134
|
+
// conversation files
|
|
135
|
+
conversation_file_add: {
|
|
136
|
+
p_conversation_id: BAD_UUID,
|
|
137
|
+
p_file_id: BAD_UUID
|
|
138
|
+
},
|
|
139
|
+
conversation_file_remove: {
|
|
140
|
+
p_conversation_id: BAD_UUID,
|
|
141
|
+
p_file_id: BAD_UUID
|
|
142
|
+
},
|
|
143
|
+
conversation_files: { p_conversation_id: BAD_UUID },
|
|
144
|
+
// agent resources
|
|
145
|
+
agent_resource_add: {
|
|
146
|
+
p_agent_id: BAD_UUID,
|
|
147
|
+
p_source_type: "note",
|
|
148
|
+
p_source_id: BAD_UUID
|
|
149
|
+
},
|
|
150
|
+
agent_resource_remove: {
|
|
151
|
+
p_agent_id: BAD_UUID,
|
|
152
|
+
p_source_type: "note",
|
|
153
|
+
p_source_id: BAD_UUID
|
|
154
|
+
},
|
|
155
|
+
// categories
|
|
156
|
+
cat_list: {},
|
|
157
|
+
cat_create: { p_dimension: "", p_name: "", p_org_id: BAD_UUID },
|
|
158
|
+
cat_update: { p_category_id: BAD_UUID, p_name: "__probe__" },
|
|
159
|
+
cat_reparent: { p_category_id: BAD_UUID },
|
|
160
|
+
cat_delete: { p_category_id: BAD_UUID },
|
|
161
|
+
// favorites / recents
|
|
162
|
+
ues_set: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
|
|
163
|
+
ues_list: {},
|
|
164
|
+
ues_get_bulk: { p_entity_type: "__probe__", p_entity_ids: [BAD_UUID] },
|
|
165
|
+
ues_touch: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
|
|
166
|
+
// candidates
|
|
167
|
+
reference_search_candidates: { p_token: "__probe__", p_limit: 1 },
|
|
168
|
+
// comments (W6) — every fn takes a uuid arg, so the unparseable sentinel
|
|
169
|
+
// guarantees 22P02 before any SECURITY DEFINER body runs (no write occurs).
|
|
170
|
+
cmt_list: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
|
|
171
|
+
cmt_add: {
|
|
172
|
+
p_entity_type: "__probe__",
|
|
173
|
+
p_entity_id: BAD_UUID,
|
|
174
|
+
p_body: "__probe__"
|
|
175
|
+
},
|
|
176
|
+
cmt_edit: { p_id: BAD_UUID, p_body: "__probe__" },
|
|
177
|
+
cmt_delete: { p_id: BAD_UUID }
|
|
178
|
+
};
|
|
179
|
+
function isMissingFunctionError(error) {
|
|
180
|
+
if (!error || typeof error !== "object") return false;
|
|
181
|
+
return error.code === "PGRST202";
|
|
182
|
+
}
|
|
183
|
+
async function assertDemandedSchema(dataSource, options = {}) {
|
|
184
|
+
const { selfTest = false, concurrency = 6, throwOnViolation = true } = options;
|
|
185
|
+
const names = [...DEMANDED_RPC_NAMES];
|
|
186
|
+
if (selfTest) names.push(SELF_TEST_MISSING_RPC);
|
|
187
|
+
const missing = [];
|
|
188
|
+
const unreachable = [];
|
|
189
|
+
const answered = [];
|
|
190
|
+
let cursor = 0;
|
|
191
|
+
async function worker() {
|
|
192
|
+
while (cursor < names.length) {
|
|
193
|
+
const fn = names[cursor];
|
|
194
|
+
cursor += 1;
|
|
195
|
+
if (!fn) continue;
|
|
196
|
+
const args = fn === SELF_TEST_MISSING_RPC ? {} : PROBE_ARGS[fn];
|
|
197
|
+
try {
|
|
198
|
+
const { error } = await dataSource.rpc(fn, args);
|
|
199
|
+
if (error == null) answered.push(fn);
|
|
200
|
+
else if (isMissingFunctionError(error)) missing.push(fn);
|
|
201
|
+
else answered.push(fn);
|
|
202
|
+
} catch (e) {
|
|
203
|
+
unreachable.push({ fn, error: e });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
await Promise.all(
|
|
208
|
+
Array.from({ length: Math.min(concurrency, names.length) }, worker)
|
|
209
|
+
);
|
|
210
|
+
if (selfTest) {
|
|
211
|
+
const selfTestMissing = missing.includes(SELF_TEST_MISSING_RPC);
|
|
212
|
+
const idx = missing.indexOf(SELF_TEST_MISSING_RPC);
|
|
213
|
+
if (idx >= 0) missing.splice(idx, 1);
|
|
214
|
+
const answeredIdx = answered.indexOf(SELF_TEST_MISSING_RPC);
|
|
215
|
+
if (answeredIdx >= 0) answered.splice(answeredIdx, 1);
|
|
216
|
+
if (!selfTestMissing) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`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.`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (unreachable.length > 0) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`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.`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const ok = missing.length === 0;
|
|
228
|
+
const report = { ok, missing, unreachable, answered };
|
|
229
|
+
if (!ok && throwOnViolation) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`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.`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return report;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/react/context.tsx
|
|
68
238
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
69
239
|
var AssociationsReactContext = (0, import_react.createContext)(
|
|
70
240
|
null
|
|
71
241
|
);
|
|
242
|
+
function isDevelopmentBuild() {
|
|
243
|
+
try {
|
|
244
|
+
return typeof process !== "undefined" && true;
|
|
245
|
+
} catch {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
72
249
|
function AssociationsProvider({
|
|
73
250
|
store,
|
|
251
|
+
probeSchema,
|
|
74
252
|
notifier,
|
|
75
253
|
windowShell,
|
|
76
254
|
capture,
|
|
@@ -80,6 +258,28 @@ function AssociationsProvider({
|
|
|
80
258
|
children
|
|
81
259
|
}) {
|
|
82
260
|
const notifierWarned = (0, import_react.useRef)(false);
|
|
261
|
+
const shouldProbe = probeSchema ?? isDevelopmentBuild();
|
|
262
|
+
(0, import_react.useEffect)(() => {
|
|
263
|
+
if (!shouldProbe) return;
|
|
264
|
+
let stale = false;
|
|
265
|
+
void (async () => {
|
|
266
|
+
try {
|
|
267
|
+
await assertDemandedSchema(store.dataSource);
|
|
268
|
+
} catch (error) {
|
|
269
|
+
if (stale) return;
|
|
270
|
+
store.errorSink({
|
|
271
|
+
code: "demanded_schema_violation",
|
|
272
|
+
message: error instanceof Error ? error.message : "assertDemandedSchema failed",
|
|
273
|
+
context: {
|
|
274
|
+
remedy: "Run the platform.associations schema (README \xA7 The demanded schema) on the database this dataSource points at."
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
})();
|
|
279
|
+
return () => {
|
|
280
|
+
stale = true;
|
|
281
|
+
};
|
|
282
|
+
}, [shouldProbe, store]);
|
|
83
283
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
84
284
|
AssociationsReactContext.Provider,
|
|
85
285
|
{
|
|
@@ -264,6 +464,7 @@ var ENTITY_TYPE_TOKENS = [
|
|
|
264
464
|
"commerce_marketplace_site",
|
|
265
465
|
"commerce_marketplace_sync_run",
|
|
266
466
|
"commerce_prediction_outcome",
|
|
467
|
+
"commerce_print_order",
|
|
267
468
|
"commerce_product",
|
|
268
469
|
"commerce_product_channel_ref",
|
|
269
470
|
"commerce_product_media",
|
|
@@ -1471,7 +1672,11 @@ function usePrimaryEntity() {
|
|
|
1471
1672
|
}
|
|
1472
1673
|
|
|
1473
1674
|
// src/react/components/AssociationWindow.tsx
|
|
1675
|
+
var import_react12 = require("react");
|
|
1676
|
+
|
|
1677
|
+
// src/react/components/DefaultWindowShell.tsx
|
|
1474
1678
|
var import_react11 = require("react");
|
|
1679
|
+
var import_react_dom = require("react-dom");
|
|
1475
1680
|
var import_design_system = require("@ai-matrx/design-system");
|
|
1476
1681
|
|
|
1477
1682
|
// src/react/icons.tsx
|
|
@@ -1590,9 +1795,246 @@ function DefaultEntityIcon(props) {
|
|
|
1590
1795
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 13.5V8" })
|
|
1591
1796
|
] });
|
|
1592
1797
|
}
|
|
1798
|
+
function MaximizeIcon(props) {
|
|
1799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1800
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M15 3h6v6" }),
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M9 21H3v-6" }),
|
|
1802
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 3l-7 7" }),
|
|
1803
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 21l7-7" })
|
|
1804
|
+
] });
|
|
1805
|
+
}
|
|
1806
|
+
function RestoreIcon(props) {
|
|
1807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1808
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M4 14h6v6" }),
|
|
1809
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M20 10h-6V4" }),
|
|
1810
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M14 10l7-7" }),
|
|
1811
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 21l7-7" })
|
|
1812
|
+
] });
|
|
1813
|
+
}
|
|
1814
|
+
function GripResizeIcon(props) {
|
|
1815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1816
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 15 15 21" }),
|
|
1817
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 20 20 21" })
|
|
1818
|
+
] });
|
|
1819
|
+
}
|
|
1593
1820
|
|
|
1594
|
-
// src/react/components/
|
|
1821
|
+
// src/react/components/DefaultWindowShell.tsx
|
|
1595
1822
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1823
|
+
var DEFAULT_WIDTH = 440;
|
|
1824
|
+
var DEFAULT_HEIGHT = 580;
|
|
1825
|
+
var MIN_WIDTH = 330;
|
|
1826
|
+
var MIN_HEIGHT = 380;
|
|
1827
|
+
var MOBILE_MAX_WIDTH = 640;
|
|
1828
|
+
var EDGE_KEEP = 48;
|
|
1829
|
+
function viewport() {
|
|
1830
|
+
if (typeof window === "undefined") {
|
|
1831
|
+
return { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
|
|
1832
|
+
}
|
|
1833
|
+
return { width: window.innerWidth, height: window.innerHeight };
|
|
1834
|
+
}
|
|
1835
|
+
function clamp(rect) {
|
|
1836
|
+
const { width: vw, height: vh } = viewport();
|
|
1837
|
+
const width = Math.min(Math.max(rect.width, MIN_WIDTH), Math.max(vw, MIN_WIDTH));
|
|
1838
|
+
const height = Math.min(
|
|
1839
|
+
Math.max(rect.height, MIN_HEIGHT),
|
|
1840
|
+
Math.max(vh, MIN_HEIGHT)
|
|
1841
|
+
);
|
|
1842
|
+
return {
|
|
1843
|
+
width,
|
|
1844
|
+
height,
|
|
1845
|
+
x: Math.min(Math.max(rect.x, EDGE_KEEP - width), Math.max(vw - EDGE_KEEP, 0)),
|
|
1846
|
+
y: Math.min(Math.max(rect.y, 0), Math.max(vh - EDGE_KEEP, 0))
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
function centred() {
|
|
1850
|
+
const { width: vw, height: vh } = viewport();
|
|
1851
|
+
const width = Math.min(DEFAULT_WIDTH, Math.max(vw - 32, MIN_WIDTH));
|
|
1852
|
+
const height = Math.min(DEFAULT_HEIGHT, Math.max(vh - 32, MIN_HEIGHT));
|
|
1853
|
+
return clamp({
|
|
1854
|
+
width,
|
|
1855
|
+
height,
|
|
1856
|
+
x: Math.round((vw - width) / 2),
|
|
1857
|
+
y: Math.round((vh - height) / 2)
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
function DefaultWindowShell({
|
|
1861
|
+
id,
|
|
1862
|
+
title,
|
|
1863
|
+
onClose,
|
|
1864
|
+
icon,
|
|
1865
|
+
children,
|
|
1866
|
+
className
|
|
1867
|
+
}) {
|
|
1868
|
+
const panelRef = (0, import_react11.useRef)(null);
|
|
1869
|
+
const [mounted, setMounted] = (0, import_react11.useState)(false);
|
|
1870
|
+
const [isMobile, setIsMobile] = (0, import_react11.useState)(false);
|
|
1871
|
+
const [rect, setRect] = (0, import_react11.useState)(() => centred());
|
|
1872
|
+
const [maximized, setMaximized] = (0, import_react11.useState)(false);
|
|
1873
|
+
const gesture = (0, import_react11.useRef)(null);
|
|
1874
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
1875
|
+
setMounted(true);
|
|
1876
|
+
setIsMobile(window.innerWidth < MOBILE_MAX_WIDTH);
|
|
1877
|
+
setRect(centred());
|
|
1878
|
+
}, []);
|
|
1879
|
+
(0, import_react11.useEffect)(() => {
|
|
1880
|
+
if (!mounted) return;
|
|
1881
|
+
const onResize = () => {
|
|
1882
|
+
setIsMobile(window.innerWidth < MOBILE_MAX_WIDTH);
|
|
1883
|
+
setRect((current) => clamp(current));
|
|
1884
|
+
};
|
|
1885
|
+
window.addEventListener("resize", onResize);
|
|
1886
|
+
return () => window.removeEventListener("resize", onResize);
|
|
1887
|
+
}, [mounted]);
|
|
1888
|
+
(0, import_react11.useEffect)(() => {
|
|
1889
|
+
const onKeyDown = (event) => {
|
|
1890
|
+
if (event.key === "Escape") onClose();
|
|
1891
|
+
};
|
|
1892
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1893
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
1894
|
+
}, [onClose]);
|
|
1895
|
+
(0, import_react11.useEffect)(() => {
|
|
1896
|
+
panelRef.current?.focus({ preventScroll: true });
|
|
1897
|
+
}, [mounted]);
|
|
1898
|
+
const beginGesture = (0, import_react11.useCallback)(
|
|
1899
|
+
(mode) => (event) => {
|
|
1900
|
+
if (isMobile || maximized || event.button !== 0) return;
|
|
1901
|
+
event.preventDefault();
|
|
1902
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1903
|
+
gesture.current = {
|
|
1904
|
+
mode,
|
|
1905
|
+
pointerId: event.pointerId,
|
|
1906
|
+
startX: event.clientX,
|
|
1907
|
+
startY: event.clientY,
|
|
1908
|
+
origin: rect
|
|
1909
|
+
};
|
|
1910
|
+
},
|
|
1911
|
+
[isMobile, maximized, rect]
|
|
1912
|
+
);
|
|
1913
|
+
const onPointerMove = (0, import_react11.useCallback)((event) => {
|
|
1914
|
+
const active = gesture.current;
|
|
1915
|
+
if (!active || active.pointerId !== event.pointerId) return;
|
|
1916
|
+
const dx = event.clientX - active.startX;
|
|
1917
|
+
const dy = event.clientY - active.startY;
|
|
1918
|
+
setRect(
|
|
1919
|
+
clamp(
|
|
1920
|
+
active.mode === "move" ? { ...active.origin, x: active.origin.x + dx, y: active.origin.y + dy } : {
|
|
1921
|
+
...active.origin,
|
|
1922
|
+
width: active.origin.width + dx,
|
|
1923
|
+
height: active.origin.height + dy
|
|
1924
|
+
}
|
|
1925
|
+
)
|
|
1926
|
+
);
|
|
1927
|
+
}, []);
|
|
1928
|
+
const endGesture = (0, import_react11.useCallback)((event) => {
|
|
1929
|
+
const active = gesture.current;
|
|
1930
|
+
if (!active || active.pointerId !== event.pointerId) return;
|
|
1931
|
+
gesture.current = null;
|
|
1932
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
1933
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
1934
|
+
}
|
|
1935
|
+
}, []);
|
|
1936
|
+
if (!mounted || typeof document === "undefined") return null;
|
|
1937
|
+
const labelId = `assoc-window-title:${id}`;
|
|
1938
|
+
const style = isMobile ? {} : maximized ? { inset: "1rem", width: "auto", height: "auto" } : {
|
|
1939
|
+
left: rect.x,
|
|
1940
|
+
top: rect.y,
|
|
1941
|
+
width: rect.width,
|
|
1942
|
+
height: rect.height
|
|
1943
|
+
};
|
|
1944
|
+
return (0, import_react_dom.createPortal)(
|
|
1945
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1946
|
+
"div",
|
|
1947
|
+
{
|
|
1948
|
+
ref: panelRef,
|
|
1949
|
+
role: "dialog",
|
|
1950
|
+
"aria-labelledby": labelId,
|
|
1951
|
+
tabIndex: -1,
|
|
1952
|
+
style,
|
|
1953
|
+
className: (0, import_design_system.cn)(
|
|
1954
|
+
// Non-modal by design: no backdrop element exists, so the page
|
|
1955
|
+
// behind keeps every click. `pointer-events-auto` re-asserts our
|
|
1956
|
+
// own subtree in case a Radix surface left <body> inert.
|
|
1957
|
+
"pointer-events-auto fixed z-50 flex flex-col overflow-hidden border border-border bg-card text-card-foreground shadow-xl outline-none",
|
|
1958
|
+
isMobile ? "inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl" : "rounded-xl",
|
|
1959
|
+
className
|
|
1960
|
+
),
|
|
1961
|
+
children: [
|
|
1962
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1963
|
+
"header",
|
|
1964
|
+
{
|
|
1965
|
+
onPointerDown: beginGesture("move"),
|
|
1966
|
+
onPointerMove,
|
|
1967
|
+
onPointerUp: endGesture,
|
|
1968
|
+
onPointerCancel: endGesture,
|
|
1969
|
+
onDoubleClick: () => {
|
|
1970
|
+
if (!isMobile) setMaximized((v) => !v);
|
|
1971
|
+
},
|
|
1972
|
+
className: (0, import_design_system.cn)(
|
|
1973
|
+
"flex shrink-0 items-center justify-between gap-2 border-b border-border px-3 py-2 select-none",
|
|
1974
|
+
isMobile ? "" : "cursor-move touch-none"
|
|
1975
|
+
),
|
|
1976
|
+
children: [
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1978
|
+
"span",
|
|
1979
|
+
{
|
|
1980
|
+
id: labelId,
|
|
1981
|
+
className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-foreground",
|
|
1982
|
+
children: [
|
|
1983
|
+
icon,
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate", children: title })
|
|
1985
|
+
]
|
|
1986
|
+
}
|
|
1987
|
+
),
|
|
1988
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex shrink-0 items-center gap-0.5", children: [
|
|
1989
|
+
isMobile ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1990
|
+
"button",
|
|
1991
|
+
{
|
|
1992
|
+
type: "button",
|
|
1993
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
1994
|
+
onClick: () => setMaximized((v) => !v),
|
|
1995
|
+
"aria-label": maximized ? "Restore window" : "Maximize window",
|
|
1996
|
+
className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1997
|
+
children: maximized ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RestoreIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MaximizeIcon, { className: "h-3.5 w-3.5" })
|
|
1998
|
+
}
|
|
1999
|
+
),
|
|
2000
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2001
|
+
"button",
|
|
2002
|
+
{
|
|
2003
|
+
type: "button",
|
|
2004
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
2005
|
+
onClick: onClose,
|
|
2006
|
+
"aria-label": "Close",
|
|
2007
|
+
className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
2008
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(XIcon, { className: "h-3.5 w-3.5" })
|
|
2009
|
+
}
|
|
2010
|
+
)
|
|
2011
|
+
] })
|
|
2012
|
+
]
|
|
2013
|
+
}
|
|
2014
|
+
),
|
|
2015
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-h-0 flex-1 overflow-hidden", children }),
|
|
2016
|
+
isMobile || maximized ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2017
|
+
"button",
|
|
2018
|
+
{
|
|
2019
|
+
type: "button",
|
|
2020
|
+
"aria-label": "Resize window",
|
|
2021
|
+
onPointerDown: beginGesture("resize"),
|
|
2022
|
+
onPointerMove,
|
|
2023
|
+
onPointerUp: endGesture,
|
|
2024
|
+
onPointerCancel: endGesture,
|
|
2025
|
+
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",
|
|
2026
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GripResizeIcon, { className: "h-3 w-3" })
|
|
2027
|
+
}
|
|
2028
|
+
)
|
|
2029
|
+
]
|
|
2030
|
+
}
|
|
2031
|
+
),
|
|
2032
|
+
document.body
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// src/react/components/AssociationWindow.tsx
|
|
2037
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1596
2038
|
function AssociationWindow({
|
|
1597
2039
|
open,
|
|
1598
2040
|
onClose,
|
|
@@ -1602,81 +2044,54 @@ function AssociationWindow({
|
|
|
1602
2044
|
subtitle,
|
|
1603
2045
|
children
|
|
1604
2046
|
}) {
|
|
1605
|
-
const instanceId = (0,
|
|
2047
|
+
const instanceId = (0, import_react12.useId)();
|
|
1606
2048
|
const { windowShell } = useAssociationsUiPorts();
|
|
1607
2049
|
if (!open) return null;
|
|
1608
|
-
const body = /* @__PURE__ */ (0,
|
|
1609
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
2050
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex h-full min-h-0 flex-col gap-2 p-3", children: [
|
|
2051
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "shrink-0 text-xs text-muted-foreground", children: subtitle }) : null,
|
|
1610
2052
|
children
|
|
1611
2053
|
] });
|
|
2054
|
+
const windowId = `association:${scopeId}:${instanceId}`;
|
|
1612
2055
|
if (windowShell) {
|
|
1613
2056
|
const HostWindow = windowShell.Window;
|
|
1614
|
-
return /* @__PURE__ */ (0,
|
|
1615
|
-
HostWindow,
|
|
1616
|
-
{
|
|
1617
|
-
id: `association:${scopeId}:${instanceId}`,
|
|
1618
|
-
title,
|
|
1619
|
-
onClose,
|
|
1620
|
-
children: body
|
|
1621
|
-
}
|
|
1622
|
-
);
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HostWindow, { id: windowId, title, onClose, children: body });
|
|
1623
2058
|
}
|
|
1624
|
-
return /* @__PURE__ */ (0,
|
|
1625
|
-
|
|
2059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2060
|
+
DefaultWindowShell,
|
|
1626
2061
|
{
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
style: { height: "min(580px, 85dvh)" },
|
|
1633
|
-
children: [
|
|
1634
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
|
|
1635
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-foreground", children: [
|
|
1636
|
-
icon,
|
|
1637
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate", children: title })
|
|
1638
|
-
] }),
|
|
1639
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1640
|
-
"button",
|
|
1641
|
-
{
|
|
1642
|
-
type: "button",
|
|
1643
|
-
onClick: onClose,
|
|
1644
|
-
"aria-label": "Close",
|
|
1645
|
-
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",
|
|
1646
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(XIcon, { className: "h-3.5 w-3.5" })
|
|
1647
|
-
}
|
|
1648
|
-
)
|
|
1649
|
-
] }),
|
|
1650
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-h-0 flex-1", children: body })
|
|
1651
|
-
]
|
|
2062
|
+
id: windowId,
|
|
2063
|
+
title,
|
|
2064
|
+
onClose,
|
|
2065
|
+
...icon !== void 0 ? { icon } : {},
|
|
2066
|
+
children: body
|
|
1652
2067
|
}
|
|
1653
2068
|
);
|
|
1654
2069
|
}
|
|
1655
2070
|
|
|
1656
2071
|
// src/react/components/AssociationPicker.tsx
|
|
1657
|
-
var
|
|
2072
|
+
var import_react13 = require("react");
|
|
1658
2073
|
var import_design_system2 = require("@ai-matrx/design-system");
|
|
1659
|
-
var
|
|
2074
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1660
2075
|
function AssociationPicker(props) {
|
|
1661
2076
|
const store = useAssociationsStore();
|
|
1662
2077
|
const { pickerOverrides } = useAssociationsUiPorts();
|
|
1663
2078
|
const info = store.registry.getEntityInfo(props.token);
|
|
1664
2079
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
1665
2080
|
const Override = pickerOverrides?.[props.token];
|
|
1666
|
-
if (Override) return /* @__PURE__ */ (0,
|
|
2081
|
+
if (Override) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Override, { ...props });
|
|
1667
2082
|
const title = `Add ${info.labelPlural}`;
|
|
1668
2083
|
const subtitle = props.containerLabel ? `Attach to ${props.containerLabel}` : "Click an item to attach or detach it";
|
|
1669
2084
|
if (!props.open) return null;
|
|
1670
|
-
return /* @__PURE__ */ (0,
|
|
2085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1671
2086
|
AssociationWindow,
|
|
1672
2087
|
{
|
|
1673
2088
|
open: props.open,
|
|
1674
2089
|
onClose: () => props.onOpenChange(false),
|
|
1675
2090
|
scopeId: `picker:${props.token}`,
|
|
1676
2091
|
title,
|
|
1677
|
-
icon: /* @__PURE__ */ (0,
|
|
2092
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "size-3.5 text-primary" }),
|
|
1678
2093
|
subtitle,
|
|
1679
|
-
children: /* @__PURE__ */ (0,
|
|
2094
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1680
2095
|
AssociationCandidateBody,
|
|
1681
2096
|
{
|
|
1682
2097
|
token: props.token,
|
|
@@ -1701,7 +2116,7 @@ function AssociationCandidateBody({
|
|
|
1701
2116
|
onClose
|
|
1702
2117
|
}) {
|
|
1703
2118
|
void onClose;
|
|
1704
|
-
return /* @__PURE__ */ (0,
|
|
2119
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1705
2120
|
EntityCandidateList,
|
|
1706
2121
|
{
|
|
1707
2122
|
token,
|
|
@@ -1723,8 +2138,8 @@ function EntityCandidateList({
|
|
|
1723
2138
|
}) {
|
|
1724
2139
|
const store = useAssociationsStore();
|
|
1725
2140
|
const notifier = useNotifier();
|
|
1726
|
-
const [search, setSearch] = (0,
|
|
1727
|
-
const [busyId, setBusyId] = (0,
|
|
2141
|
+
const [search, setSearch] = (0, import_react13.useState)("");
|
|
2142
|
+
const [busyId, setBusyId] = (0, import_react13.useState)(null);
|
|
1728
2143
|
const info = store.registry.getEntityInfo(token);
|
|
1729
2144
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
1730
2145
|
const { candidates, loading, error, reload } = useAssociationCandidates({
|
|
@@ -1748,10 +2163,10 @@ function EntityCandidateList({
|
|
|
1748
2163
|
setBusyId(null);
|
|
1749
2164
|
}
|
|
1750
2165
|
};
|
|
1751
|
-
return /* @__PURE__ */ (0,
|
|
1752
|
-
/* @__PURE__ */ (0,
|
|
1753
|
-
/* @__PURE__ */ (0,
|
|
1754
|
-
/* @__PURE__ */ (0,
|
|
2166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2167
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative mb-2", children: [
|
|
2168
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SearchIcon, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
2169
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1755
2170
|
import_design_system2.Input,
|
|
1756
2171
|
{
|
|
1757
2172
|
value: search,
|
|
@@ -1762,13 +2177,13 @@ function EntityCandidateList({
|
|
|
1762
2177
|
}
|
|
1763
2178
|
)
|
|
1764
2179
|
] }),
|
|
1765
|
-
/* @__PURE__ */ (0,
|
|
1766
|
-
/* @__PURE__ */ (0,
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: loading && candidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(ListMessage, { children: [
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
|
|
1767
2182
|
"Loading\u2026"
|
|
1768
|
-
] }) : error ? /* @__PURE__ */ (0,
|
|
1769
|
-
/* @__PURE__ */ (0,
|
|
1770
|
-
/* @__PURE__ */ (0,
|
|
1771
|
-
/* @__PURE__ */ (0,
|
|
2183
|
+
] }) : error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
|
|
2184
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "font-medium", children: "Couldn\u2019t load items" }),
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "opacity-80", children: error }),
|
|
2186
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1772
2187
|
"button",
|
|
1773
2188
|
{
|
|
1774
2189
|
type: "button",
|
|
@@ -1777,10 +2192,10 @@ function EntityCandidateList({
|
|
|
1777
2192
|
children: "Retry"
|
|
1778
2193
|
}
|
|
1779
2194
|
)
|
|
1780
|
-
] }) : candidates.length === 0 ? /* @__PURE__ */ (0,
|
|
2195
|
+
] }) : candidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ListMessage, { children: canCreate ? `Nothing to attach yet \u2014 create a new ${info.label.toLowerCase()} below.` : "Nothing to attach." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "space-y-0.5", children: candidates.map((c) => {
|
|
1781
2196
|
const attached = attachedIds.has(c.id);
|
|
1782
2197
|
const busy = busyId === c.id;
|
|
1783
|
-
return /* @__PURE__ */ (0,
|
|
2198
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1784
2199
|
"button",
|
|
1785
2200
|
{
|
|
1786
2201
|
type: "button",
|
|
@@ -1792,23 +2207,23 @@ function EntityCandidateList({
|
|
|
1792
2207
|
attached && "bg-accent/40"
|
|
1793
2208
|
),
|
|
1794
2209
|
children: [
|
|
1795
|
-
/* @__PURE__ */ (0,
|
|
1796
|
-
/* @__PURE__ */ (0,
|
|
1797
|
-
/* @__PURE__ */ (0,
|
|
2210
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "flex-1 min-w-0 truncate text-foreground", children: c.title }),
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1798
2213
|
"span",
|
|
1799
2214
|
{
|
|
1800
2215
|
className: (0, import_design_system2.cn)(
|
|
1801
2216
|
"flex h-5 w-5 items-center justify-center rounded-full shrink-0",
|
|
1802
2217
|
attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
|
|
1803
2218
|
),
|
|
1804
|
-
children: busy ? /* @__PURE__ */ (0,
|
|
2219
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, { className: "h-3 w-3" })
|
|
1805
2220
|
}
|
|
1806
2221
|
)
|
|
1807
2222
|
]
|
|
1808
2223
|
}
|
|
1809
2224
|
) }, c.id);
|
|
1810
2225
|
}) }) }),
|
|
1811
|
-
canCreate && /* @__PURE__ */ (0,
|
|
2226
|
+
canCreate && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1812
2227
|
CreateAndAttachFooter,
|
|
1813
2228
|
{
|
|
1814
2229
|
token,
|
|
@@ -1830,9 +2245,9 @@ function CreateAndAttachFooter({
|
|
|
1830
2245
|
const store = useAssociationsStore();
|
|
1831
2246
|
const notifier = useNotifier();
|
|
1832
2247
|
const info = store.registry.getEntityInfo(token);
|
|
1833
|
-
const [editing, setEditing] = (0,
|
|
1834
|
-
const [name, setName] = (0,
|
|
1835
|
-
const [busy, setBusy] = (0,
|
|
2248
|
+
const [editing, setEditing] = (0, import_react13.useState)(false);
|
|
2249
|
+
const [name, setName] = (0, import_react13.useState)("");
|
|
2250
|
+
const [busy, setBusy] = (0, import_react13.useState)(false);
|
|
1836
2251
|
const submit = async () => {
|
|
1837
2252
|
const title = name.trim();
|
|
1838
2253
|
if (!title || busy) return;
|
|
@@ -1867,7 +2282,7 @@ function CreateAndAttachFooter({
|
|
|
1867
2282
|
}
|
|
1868
2283
|
};
|
|
1869
2284
|
if (!editing) {
|
|
1870
|
-
return /* @__PURE__ */ (0,
|
|
2285
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1871
2286
|
"button",
|
|
1872
2287
|
{
|
|
1873
2288
|
type: "button",
|
|
@@ -1877,10 +2292,10 @@ function CreateAndAttachFooter({
|
|
|
1877
2292
|
},
|
|
1878
2293
|
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",
|
|
1879
2294
|
children: [
|
|
1880
|
-
/* @__PURE__ */ (0,
|
|
2295
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, { className: "h-4 w-4" }),
|
|
1881
2296
|
"New ",
|
|
1882
2297
|
info.label,
|
|
1883
|
-
seed ? /* @__PURE__ */ (0,
|
|
2298
|
+
seed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "max-w-40 truncate text-muted-foreground/70", children: [
|
|
1884
2299
|
"\u201C",
|
|
1885
2300
|
seed,
|
|
1886
2301
|
"\u201D"
|
|
@@ -1889,8 +2304,8 @@ function CreateAndAttachFooter({
|
|
|
1889
2304
|
}
|
|
1890
2305
|
);
|
|
1891
2306
|
}
|
|
1892
|
-
return /* @__PURE__ */ (0,
|
|
1893
|
-
/* @__PURE__ */ (0,
|
|
2307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mt-2 flex shrink-0 items-center gap-1.5", children: [
|
|
2308
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1894
2309
|
import_design_system2.Input,
|
|
1895
2310
|
{
|
|
1896
2311
|
autoFocus: true,
|
|
@@ -1909,17 +2324,17 @@ function CreateAndAttachFooter({
|
|
|
1909
2324
|
style: { fontSize: 16 }
|
|
1910
2325
|
}
|
|
1911
2326
|
),
|
|
1912
|
-
/* @__PURE__ */ (0,
|
|
2327
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1913
2328
|
"button",
|
|
1914
2329
|
{
|
|
1915
2330
|
type: "button",
|
|
1916
2331
|
disabled: busy || !name.trim(),
|
|
1917
2332
|
onClick: () => void submit(),
|
|
1918
2333
|
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",
|
|
1919
|
-
children: busy ? /* @__PURE__ */ (0,
|
|
2334
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : "Create"
|
|
1920
2335
|
}
|
|
1921
2336
|
),
|
|
1922
|
-
/* @__PURE__ */ (0,
|
|
2337
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1923
2338
|
"button",
|
|
1924
2339
|
{
|
|
1925
2340
|
type: "button",
|
|
@@ -1930,38 +2345,122 @@ function CreateAndAttachFooter({
|
|
|
1930
2345
|
},
|
|
1931
2346
|
title: "Cancel",
|
|
1932
2347
|
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",
|
|
1933
|
-
children: /* @__PURE__ */ (0,
|
|
2348
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(XIcon, { className: "h-4 w-4" })
|
|
1934
2349
|
}
|
|
1935
2350
|
)
|
|
1936
2351
|
] });
|
|
1937
2352
|
}
|
|
1938
2353
|
function ListMessage({ children }) {
|
|
1939
|
-
return /* @__PURE__ */ (0,
|
|
2354
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children });
|
|
1940
2355
|
}
|
|
1941
2356
|
|
|
1942
2357
|
// src/react/components/UniversalAssociationPicker.tsx
|
|
1943
|
-
var
|
|
2358
|
+
var import_react14 = require("react");
|
|
2359
|
+
var import_design_system4 = require("@ai-matrx/design-system");
|
|
2360
|
+
|
|
2361
|
+
// src/react/components/entityDoors.tsx
|
|
1944
2362
|
var import_design_system3 = require("@ai-matrx/design-system");
|
|
1945
|
-
var
|
|
2363
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2364
|
+
function DoorRef(props) {
|
|
2365
|
+
const { onOpen, ...refProps } = props;
|
|
2366
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
2367
|
+
const store = useAssociationsStore();
|
|
2368
|
+
const HostRef = entityDoors?.EntityRef;
|
|
2369
|
+
if (HostRef) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HostRef, { ...refProps });
|
|
2370
|
+
const name = refProps.name ?? null;
|
|
2371
|
+
const href = store.registry.tryGetEntityInfo(refProps.token)?.hrefFor?.(refProps.id) ?? null;
|
|
2372
|
+
if (onOpen) {
|
|
2373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2374
|
+
"button",
|
|
2375
|
+
{
|
|
2376
|
+
type: "button",
|
|
2377
|
+
onClick: onOpen,
|
|
2378
|
+
className: (0, import_design_system3.cn)(
|
|
2379
|
+
"min-w-0 truncate text-left underline-offset-2 hover:underline",
|
|
2380
|
+
refProps.className
|
|
2381
|
+
),
|
|
2382
|
+
children: name
|
|
2383
|
+
}
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
2386
|
+
if (href) {
|
|
2387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2388
|
+
"a",
|
|
2389
|
+
{
|
|
2390
|
+
href,
|
|
2391
|
+
target: refProps.openInNewTab === false ? void 0 : "_blank",
|
|
2392
|
+
rel: "noopener noreferrer",
|
|
2393
|
+
className: (0, import_design_system3.cn)(
|
|
2394
|
+
"inline-flex min-w-0 items-center gap-1 truncate underline-offset-2 hover:underline",
|
|
2395
|
+
refProps.className
|
|
2396
|
+
),
|
|
2397
|
+
children: [
|
|
2398
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "min-w-0 truncate", children: name }),
|
|
2399
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExternalLinkIcon, { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-60" })
|
|
2400
|
+
]
|
|
2401
|
+
}
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: (0, import_design_system3.cn)("min-w-0 truncate", refProps.className), children: name });
|
|
2405
|
+
}
|
|
2406
|
+
function UnresolvedRef({ token, id }) {
|
|
2407
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
2408
|
+
const HostUnresolved = entityDoors?.UnresolvedRef;
|
|
2409
|
+
if (HostUnresolved) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HostUnresolved, { token, id });
|
|
2410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2411
|
+
"span",
|
|
2412
|
+
{
|
|
2413
|
+
className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 text-[11px] text-muted-foreground",
|
|
2414
|
+
title: `This ${token} could not be read \u2014 it may be deleted or not shared with you.`,
|
|
2415
|
+
children: "Unavailable"
|
|
2416
|
+
}
|
|
2417
|
+
);
|
|
2418
|
+
}
|
|
2419
|
+
function DoorControlsSlot(props) {
|
|
2420
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
2421
|
+
const store = useAssociationsStore();
|
|
2422
|
+
const HostControls = entityDoors?.DoorControls;
|
|
2423
|
+
if (HostControls) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HostControls, { ...props });
|
|
2424
|
+
const href = store.registry.tryGetEntityInfo(props.token)?.hrefFor?.(props.id) ?? null;
|
|
2425
|
+
if (!href) return null;
|
|
2426
|
+
const label = props.name ? `Open ${props.name}` : `Open this ${props.token}`;
|
|
2427
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2428
|
+
"a",
|
|
2429
|
+
{
|
|
2430
|
+
href,
|
|
2431
|
+
target: "_blank",
|
|
2432
|
+
rel: "noopener noreferrer",
|
|
2433
|
+
"aria-label": label,
|
|
2434
|
+
title: label,
|
|
2435
|
+
className: (0, import_design_system3.cn)(
|
|
2436
|
+
"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
2437
|
+
props.className
|
|
2438
|
+
),
|
|
2439
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExternalLinkIcon, { className: "h-3 w-3" })
|
|
2440
|
+
}
|
|
2441
|
+
);
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
// src/react/components/UniversalAssociationPicker.tsx
|
|
2445
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1946
2446
|
function attachedKey(token, id) {
|
|
1947
2447
|
return `${token}:${id}`;
|
|
1948
2448
|
}
|
|
1949
2449
|
function UniversalAssociationPicker(props) {
|
|
1950
2450
|
const { attachedKeys, onAttach, onDetach, ownerId, orgId, className } = props;
|
|
1951
2451
|
const store = useAssociationsStore();
|
|
1952
|
-
const {
|
|
2452
|
+
const { pickerOverrides } = useAssociationsUiPorts();
|
|
1953
2453
|
const notifier = useNotifier();
|
|
1954
2454
|
const tokens = props.tokens ?? store.registry.curatedTokens();
|
|
1955
|
-
const [query, setQuery] = (0,
|
|
1956
|
-
const [browseToken, setBrowseToken] = (0,
|
|
1957
|
-
const [busyKey, setBusyKey] = (0,
|
|
2455
|
+
const [query, setQuery] = (0, import_react14.useState)("");
|
|
2456
|
+
const [browseToken, setBrowseToken] = (0, import_react14.useState)(null);
|
|
2457
|
+
const [busyKey, setBusyKey] = (0, import_react14.useState)(null);
|
|
1958
2458
|
const { results, loading, isRecents } = useUniversalEntitySearch({
|
|
1959
2459
|
query,
|
|
1960
2460
|
tokens,
|
|
1961
2461
|
ownerId: ownerId ?? null,
|
|
1962
2462
|
enabled: browseToken === null
|
|
1963
2463
|
});
|
|
1964
|
-
const DoorControls = entityDoors?.DoorControls;
|
|
1965
2464
|
const toggle = async (c) => {
|
|
1966
2465
|
const key = attachedKey(c.token, c.id);
|
|
1967
2466
|
if (busyKey) return;
|
|
@@ -1985,11 +2484,11 @@ function UniversalAssociationPicker(props) {
|
|
|
1985
2484
|
groups.set(r.token, list);
|
|
1986
2485
|
}
|
|
1987
2486
|
const BrowseOverride = browseToken ? pickerOverrides?.[browseToken] : void 0;
|
|
1988
|
-
return /* @__PURE__ */ (0,
|
|
1989
|
-
/* @__PURE__ */ (0,
|
|
1990
|
-
/* @__PURE__ */ (0,
|
|
1991
|
-
/* @__PURE__ */ (0,
|
|
1992
|
-
|
|
2487
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: (0, import_design_system4.cn)("flex min-h-0 flex-1 flex-col gap-2", className), children: [
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative", children: [
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SearchIcon, { className: "absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
2490
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2491
|
+
import_design_system4.Input,
|
|
1993
2492
|
{
|
|
1994
2493
|
value: query,
|
|
1995
2494
|
onChange: (e) => {
|
|
@@ -2001,23 +2500,23 @@ function UniversalAssociationPicker(props) {
|
|
|
2001
2500
|
style: { fontSize: 16 }
|
|
2002
2501
|
}
|
|
2003
2502
|
),
|
|
2004
|
-
loading && browseToken === null && /* @__PURE__ */ (0,
|
|
2503
|
+
loading && browseToken === null && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SpinnerIcon, { className: "absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-muted-foreground" })
|
|
2005
2504
|
] }),
|
|
2006
|
-
/* @__PURE__ */ (0,
|
|
2505
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex flex-wrap gap-1", children: tokens.map((t) => {
|
|
2007
2506
|
const info = store.registry.getEntityInfo(t);
|
|
2008
2507
|
const ChipIcon = info.Icon ?? DefaultEntityIcon;
|
|
2009
2508
|
const active = browseToken === t;
|
|
2010
|
-
return /* @__PURE__ */ (0,
|
|
2509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2011
2510
|
"button",
|
|
2012
2511
|
{
|
|
2013
2512
|
type: "button",
|
|
2014
2513
|
onClick: () => setBrowseToken(active ? null : t),
|
|
2015
|
-
className: (0,
|
|
2514
|
+
className: (0, import_design_system4.cn)(
|
|
2016
2515
|
"inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-[11px] transition-colors",
|
|
2017
2516
|
active ? "border-primary/50 bg-primary/10 text-foreground" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent"
|
|
2018
2517
|
),
|
|
2019
2518
|
children: [
|
|
2020
|
-
/* @__PURE__ */ (0,
|
|
2519
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChipIcon, { className: "h-3 w-3" }),
|
|
2021
2520
|
info.labelPlural
|
|
2022
2521
|
]
|
|
2023
2522
|
},
|
|
@@ -2027,7 +2526,7 @@ function UniversalAssociationPicker(props) {
|
|
|
2027
2526
|
browseToken && BrowseOverride ? (
|
|
2028
2527
|
// The token's canonical host picker (e.g. the stored-files browser)
|
|
2029
2528
|
// owns per-token browsing when registered — never a plain list twin.
|
|
2030
|
-
/* @__PURE__ */ (0,
|
|
2529
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2031
2530
|
BrowseOverride,
|
|
2032
2531
|
{
|
|
2033
2532
|
open: true,
|
|
@@ -2043,7 +2542,7 @@ function UniversalAssociationPicker(props) {
|
|
|
2043
2542
|
onDetach: (id) => onDetach(browseToken, id)
|
|
2044
2543
|
}
|
|
2045
2544
|
)
|
|
2046
|
-
) : browseToken ? /* @__PURE__ */ (0,
|
|
2545
|
+
) : browseToken ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2047
2546
|
AssociationCandidateBody,
|
|
2048
2547
|
{
|
|
2049
2548
|
token: browseToken,
|
|
@@ -2056,63 +2555,63 @@ function UniversalAssociationPicker(props) {
|
|
|
2056
2555
|
onAttach: (id, title) => onAttach(browseToken, id, title),
|
|
2057
2556
|
onDetach: (id) => onDetach(browseToken, id)
|
|
2058
2557
|
}
|
|
2059
|
-
) }) : /* @__PURE__ */ (0,
|
|
2060
|
-
isRecents && /* @__PURE__ */ (0,
|
|
2558
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1", children: results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("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__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
|
|
2559
|
+
isRecents && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: "Recent" }),
|
|
2061
2560
|
[...groups.entries()].map(([token, items]) => {
|
|
2062
2561
|
const info = store.registry.getEntityInfo(token);
|
|
2063
2562
|
const GroupIcon = info.Icon ?? DefaultEntityIcon;
|
|
2064
|
-
return /* @__PURE__ */ (0,
|
|
2065
|
-
/* @__PURE__ */ (0,
|
|
2066
|
-
/* @__PURE__ */ (0,
|
|
2563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-0.5", children: [
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { className: "flex items-center gap-1 px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: [
|
|
2565
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(GroupIcon, { className: "h-3 w-3" }),
|
|
2067
2566
|
info.labelPlural
|
|
2068
2567
|
] }),
|
|
2069
|
-
/* @__PURE__ */ (0,
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "space-y-0.5", children: items.map((c) => {
|
|
2070
2569
|
const key = attachedKey(c.token, c.id);
|
|
2071
2570
|
const attached = attachedKeys.has(key);
|
|
2072
2571
|
const busy = busyKey === key;
|
|
2073
|
-
return /* @__PURE__ */ (0,
|
|
2572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2074
2573
|
"li",
|
|
2075
2574
|
{
|
|
2076
|
-
className: (0,
|
|
2575
|
+
className: (0, import_design_system4.cn)(
|
|
2077
2576
|
"group/entity-ref group flex items-center gap-1 rounded-md pr-1.5 transition-colors",
|
|
2078
2577
|
"hover:bg-accent",
|
|
2079
2578
|
attached && "bg-accent/40"
|
|
2080
2579
|
),
|
|
2081
2580
|
children: [
|
|
2082
|
-
/* @__PURE__ */ (0,
|
|
2581
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2083
2582
|
"button",
|
|
2084
2583
|
{
|
|
2085
2584
|
type: "button",
|
|
2086
2585
|
disabled: busy,
|
|
2087
2586
|
onClick: () => toggle(c),
|
|
2088
2587
|
title: attached ? `Detach "${c.title}"` : `Attach "${c.title}"`,
|
|
2089
|
-
className: (0,
|
|
2588
|
+
className: (0, import_design_system4.cn)(
|
|
2090
2589
|
"flex min-w-0 flex-1 items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm",
|
|
2091
2590
|
"disabled:opacity-50"
|
|
2092
2591
|
),
|
|
2093
2592
|
children: [
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2095
|
-
/* @__PURE__ */ (0,
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "min-w-0 flex-1 truncate text-foreground", children: c.title }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2096
2595
|
"span",
|
|
2097
2596
|
{
|
|
2098
|
-
className: (0,
|
|
2597
|
+
className: (0, import_design_system4.cn)(
|
|
2099
2598
|
"flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
|
|
2100
2599
|
attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
|
|
2101
2600
|
),
|
|
2102
|
-
children: busy ? /* @__PURE__ */ (0,
|
|
2601
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PlusIcon, { className: "h-3 w-3" })
|
|
2103
2602
|
}
|
|
2104
2603
|
)
|
|
2105
2604
|
]
|
|
2106
2605
|
}
|
|
2107
2606
|
),
|
|
2108
|
-
|
|
2109
|
-
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2608
|
+
DoorControlsSlot,
|
|
2110
2609
|
{
|
|
2111
2610
|
token: c.token,
|
|
2112
2611
|
id: c.id,
|
|
2113
2612
|
name: c.title
|
|
2114
2613
|
}
|
|
2115
|
-
)
|
|
2614
|
+
)
|
|
2116
2615
|
]
|
|
2117
2616
|
},
|
|
2118
2617
|
key
|
|
@@ -2125,79 +2624,18 @@ function UniversalAssociationPicker(props) {
|
|
|
2125
2624
|
}
|
|
2126
2625
|
|
|
2127
2626
|
// src/react/components/AttachedItemsSheet.tsx
|
|
2128
|
-
var
|
|
2627
|
+
var import_react15 = require("react");
|
|
2129
2628
|
var import_design_system5 = require("@ai-matrx/design-system");
|
|
2130
|
-
|
|
2131
|
-
// src/react/components/entityDoors.tsx
|
|
2132
|
-
var import_design_system4 = require("@ai-matrx/design-system");
|
|
2133
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2134
|
-
function DoorRef(props) {
|
|
2135
|
-
const { onOpen, ...refProps } = props;
|
|
2136
|
-
const { entityDoors } = useAssociationsUiPorts();
|
|
2137
|
-
const store = useAssociationsStore();
|
|
2138
|
-
const HostRef = entityDoors?.EntityRef;
|
|
2139
|
-
if (HostRef) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HostRef, { ...refProps });
|
|
2140
|
-
const name = refProps.name ?? null;
|
|
2141
|
-
const href = store.registry.tryGetEntityInfo(refProps.token)?.hrefFor?.(refProps.id) ?? null;
|
|
2142
|
-
if (onOpen) {
|
|
2143
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2144
|
-
"button",
|
|
2145
|
-
{
|
|
2146
|
-
type: "button",
|
|
2147
|
-
onClick: onOpen,
|
|
2148
|
-
className: (0, import_design_system4.cn)(
|
|
2149
|
-
"min-w-0 truncate text-left underline-offset-2 hover:underline",
|
|
2150
|
-
refProps.className
|
|
2151
|
-
),
|
|
2152
|
-
children: name
|
|
2153
|
-
}
|
|
2154
|
-
);
|
|
2155
|
-
}
|
|
2156
|
-
if (href) {
|
|
2157
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2158
|
-
"a",
|
|
2159
|
-
{
|
|
2160
|
-
href,
|
|
2161
|
-
target: refProps.openInNewTab === false ? void 0 : "_blank",
|
|
2162
|
-
rel: "noopener noreferrer",
|
|
2163
|
-
className: (0, import_design_system4.cn)(
|
|
2164
|
-
"inline-flex min-w-0 items-center gap-1 truncate underline-offset-2 hover:underline",
|
|
2165
|
-
refProps.className
|
|
2166
|
-
),
|
|
2167
|
-
children: [
|
|
2168
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "min-w-0 truncate", children: name }),
|
|
2169
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ExternalLinkIcon, { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-60" })
|
|
2170
|
-
]
|
|
2171
|
-
}
|
|
2172
|
-
);
|
|
2173
|
-
}
|
|
2174
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: (0, import_design_system4.cn)("min-w-0 truncate", refProps.className), children: name });
|
|
2175
|
-
}
|
|
2176
|
-
function UnresolvedRef({ token, id }) {
|
|
2177
|
-
const { entityDoors } = useAssociationsUiPorts();
|
|
2178
|
-
const HostUnresolved = entityDoors?.UnresolvedRef;
|
|
2179
|
-
if (HostUnresolved) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HostUnresolved, { token, id });
|
|
2180
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2181
|
-
"span",
|
|
2182
|
-
{
|
|
2183
|
-
className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 text-[11px] text-muted-foreground",
|
|
2184
|
-
title: `This ${token} could not be read \u2014 it may be deleted or not shared with you.`,
|
|
2185
|
-
children: "Unavailable"
|
|
2186
|
-
}
|
|
2187
|
-
);
|
|
2188
|
-
}
|
|
2189
|
-
|
|
2190
|
-
// src/react/components/AttachedItemsSheet.tsx
|
|
2191
|
-
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2629
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2192
2630
|
function AttachedItemsSheet(props) {
|
|
2193
2631
|
const store = useAssociationsStore();
|
|
2194
2632
|
const info = store.registry.getEntityInfo(props.token);
|
|
2195
2633
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2196
2634
|
const title = info.labelPlural;
|
|
2197
2635
|
const containerName = props.container?.label ?? props.containerLabel;
|
|
2198
|
-
const subtitle = props.container ? /* @__PURE__ */ (0,
|
|
2636
|
+
const subtitle = props.container ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "inline-flex min-w-0 max-w-full items-center gap-1", children: [
|
|
2199
2637
|
"Attached to",
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2201
2639
|
DoorRef,
|
|
2202
2640
|
{
|
|
2203
2641
|
token: props.container.type,
|
|
@@ -2208,16 +2646,16 @@ function AttachedItemsSheet(props) {
|
|
|
2208
2646
|
)
|
|
2209
2647
|
] }) : props.containerLabel ? `Attached to ${props.containerLabel}` : "Attached items";
|
|
2210
2648
|
if (!props.open) return null;
|
|
2211
|
-
return /* @__PURE__ */ (0,
|
|
2649
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2212
2650
|
AssociationWindow,
|
|
2213
2651
|
{
|
|
2214
2652
|
open: props.open,
|
|
2215
2653
|
onClose: () => props.onOpenChange(false),
|
|
2216
2654
|
scopeId: `attached:${props.token}`,
|
|
2217
2655
|
title,
|
|
2218
|
-
icon: /* @__PURE__ */ (0,
|
|
2656
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { className: "size-3.5 text-primary" }),
|
|
2219
2657
|
subtitle,
|
|
2220
|
-
children: /* @__PURE__ */ (0,
|
|
2658
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2221
2659
|
AttachedItemsBody,
|
|
2222
2660
|
{
|
|
2223
2661
|
token: props.token,
|
|
@@ -2241,11 +2679,11 @@ function AttachedItemsBody({
|
|
|
2241
2679
|
const notifier = useNotifier();
|
|
2242
2680
|
const info = store.registry.getEntityInfo(token);
|
|
2243
2681
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2244
|
-
const [titles, setTitles] = (0,
|
|
2245
|
-
const [titleError, setTitleError] = (0,
|
|
2246
|
-
const [busyId, setBusyId] = (0,
|
|
2682
|
+
const [titles, setTitles] = (0, import_react15.useState)(null);
|
|
2683
|
+
const [titleError, setTitleError] = (0, import_react15.useState)(null);
|
|
2684
|
+
const [busyId, setBusyId] = (0, import_react15.useState)(null);
|
|
2247
2685
|
const idKey = links.map((l) => l.resourceId).sort().join(",");
|
|
2248
|
-
(0,
|
|
2686
|
+
(0, import_react15.useEffect)(() => {
|
|
2249
2687
|
if (!enabled) return;
|
|
2250
2688
|
const ids = idKey ? idKey.split(",") : [];
|
|
2251
2689
|
if (ids.length === 0) {
|
|
@@ -2289,30 +2727,30 @@ function AttachedItemsBody({
|
|
|
2289
2727
|
setBusyId(null);
|
|
2290
2728
|
}
|
|
2291
2729
|
};
|
|
2292
|
-
return /* @__PURE__ */ (0,
|
|
2293
|
-
titleError ? /* @__PURE__ */ (0,
|
|
2730
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2731
|
+
titleError ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mb-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
|
|
2294
2732
|
"Showing names recorded at attach time \u2014 they may be out of date.",
|
|
2295
2733
|
" ",
|
|
2296
2734
|
titleError
|
|
2297
2735
|
] }) : null,
|
|
2298
|
-
/* @__PURE__ */ (0,
|
|
2299
|
-
/* @__PURE__ */ (0,
|
|
2736
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: links.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center justify-center py-8 text-[13px] text-muted-foreground", children: "Nothing attached yet." }) : titles === null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children: [
|
|
2737
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
|
|
2300
2738
|
"Loading\u2026"
|
|
2301
|
-
] }) : /* @__PURE__ */ (0,
|
|
2739
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: "space-y-0.5", children: links.map((link) => {
|
|
2302
2740
|
const resolved = titles.get(link.resourceId);
|
|
2303
2741
|
const missing = !titles.has(link.resourceId);
|
|
2304
2742
|
const name = resolved ?? link.label ?? (missing ? null : "Untitled");
|
|
2305
2743
|
const busy = busyId === link.resourceId;
|
|
2306
|
-
return /* @__PURE__ */ (0,
|
|
2744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2307
2745
|
"li",
|
|
2308
2746
|
{
|
|
2309
2747
|
className: "group/entity-ref group flex items-center gap-2 rounded-md px-2.5 py-2 text-sm transition-colors hover:bg-accent",
|
|
2310
2748
|
children: [
|
|
2311
|
-
/* @__PURE__ */ (0,
|
|
2312
|
-
/* @__PURE__ */ (0,
|
|
2749
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
2750
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "flex-1 min-w-0 truncate", children: name === null ? (
|
|
2313
2751
|
// The X beside the row stays the one-click detach.
|
|
2314
|
-
/* @__PURE__ */ (0,
|
|
2315
|
-
) : /* @__PURE__ */ (0,
|
|
2752
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UnresolvedRef, { token, id: link.resourceId })
|
|
2753
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2316
2754
|
DoorRef,
|
|
2317
2755
|
{
|
|
2318
2756
|
token,
|
|
@@ -2322,7 +2760,7 @@ function AttachedItemsBody({
|
|
|
2322
2760
|
className: "text-foreground"
|
|
2323
2761
|
}
|
|
2324
2762
|
) }),
|
|
2325
|
-
/* @__PURE__ */ (0,
|
|
2763
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2326
2764
|
"button",
|
|
2327
2765
|
{
|
|
2328
2766
|
type: "button",
|
|
@@ -2333,7 +2771,7 @@ function AttachedItemsBody({
|
|
|
2333
2771
|
"flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
|
|
2334
2772
|
"hover:bg-destructive/10 hover:text-destructive disabled:opacity-50"
|
|
2335
2773
|
),
|
|
2336
|
-
children: busy ? /* @__PURE__ */ (0,
|
|
2774
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(XIcon, { className: "h-3.5 w-3.5" })
|
|
2337
2775
|
}
|
|
2338
2776
|
)
|
|
2339
2777
|
]
|
|
@@ -2341,14 +2779,14 @@ function AttachedItemsBody({
|
|
|
2341
2779
|
link.edgeId
|
|
2342
2780
|
);
|
|
2343
2781
|
}) }) }),
|
|
2344
|
-
onAdd ? /* @__PURE__ */ (0,
|
|
2782
|
+
onAdd ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2345
2783
|
"button",
|
|
2346
2784
|
{
|
|
2347
2785
|
type: "button",
|
|
2348
2786
|
onClick: onAdd,
|
|
2349
2787
|
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",
|
|
2350
2788
|
children: [
|
|
2351
|
-
/* @__PURE__ */ (0,
|
|
2789
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PlusIcon, { className: "h-4 w-4" }),
|
|
2352
2790
|
"Attach ",
|
|
2353
2791
|
info.labelPlural.toLowerCase()
|
|
2354
2792
|
]
|
|
@@ -2358,7 +2796,7 @@ function AttachedItemsBody({
|
|
|
2358
2796
|
}
|
|
2359
2797
|
|
|
2360
2798
|
// src/react/components/AssociationCard.tsx
|
|
2361
|
-
var
|
|
2799
|
+
var import_react16 = require("react");
|
|
2362
2800
|
var import_design_system6 = require("@ai-matrx/design-system");
|
|
2363
2801
|
|
|
2364
2802
|
// src/react/contentRoles.ts
|
|
@@ -2409,7 +2847,7 @@ function getContentRoleMeta(role) {
|
|
|
2409
2847
|
}
|
|
2410
2848
|
|
|
2411
2849
|
// src/react/components/AssociationCard.tsx
|
|
2412
|
-
var
|
|
2850
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2413
2851
|
function AssociationCard({
|
|
2414
2852
|
token,
|
|
2415
2853
|
container: containerProp,
|
|
@@ -2418,11 +2856,11 @@ function AssociationCard({
|
|
|
2418
2856
|
const store = useAssociationsStore();
|
|
2419
2857
|
const fromCtx = usePrimaryEntity();
|
|
2420
2858
|
const container = containerProp ?? fromCtx;
|
|
2421
|
-
const [open, setOpen] = (0,
|
|
2859
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
2422
2860
|
const info = store.registry.getEntityInfo(token);
|
|
2423
2861
|
const role = getContentRoleMeta(info.contentRole);
|
|
2424
2862
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2425
|
-
const [listOpen, setListOpen] = (0,
|
|
2863
|
+
const [listOpen, setListOpen] = (0, import_react16.useState)(false);
|
|
2426
2864
|
const { status, countFor, attachedIdsFor, linksFor, attach, detach } = useContainerLinks({
|
|
2427
2865
|
containerType: container?.type ?? "organization",
|
|
2428
2866
|
containerId: container?.id ?? null,
|
|
@@ -2440,8 +2878,8 @@ function AssociationCard({
|
|
|
2440
2878
|
const loading = status === "loading" || status === "idle";
|
|
2441
2879
|
const canAttach = info.canListCandidates;
|
|
2442
2880
|
const canDrillIn = count > 0;
|
|
2443
|
-
return /* @__PURE__ */ (0,
|
|
2444
|
-
/* @__PURE__ */ (0,
|
|
2881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2882
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2445
2883
|
"div",
|
|
2446
2884
|
{
|
|
2447
2885
|
className: (0, import_design_system6.cn)(
|
|
@@ -2449,7 +2887,7 @@ function AssociationCard({
|
|
|
2449
2887
|
className
|
|
2450
2888
|
),
|
|
2451
2889
|
children: [
|
|
2452
|
-
/* @__PURE__ */ (0,
|
|
2890
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2453
2891
|
"span",
|
|
2454
2892
|
{
|
|
2455
2893
|
className: (0, import_design_system6.cn)(
|
|
@@ -2458,7 +2896,7 @@ function AssociationCard({
|
|
|
2458
2896
|
)
|
|
2459
2897
|
}
|
|
2460
2898
|
),
|
|
2461
|
-
/* @__PURE__ */ (0,
|
|
2899
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2462
2900
|
"button",
|
|
2463
2901
|
{
|
|
2464
2902
|
type: "button",
|
|
@@ -2470,7 +2908,7 @@ function AssociationCard({
|
|
|
2470
2908
|
canDrillIn ? "cursor-pointer" : "cursor-default"
|
|
2471
2909
|
),
|
|
2472
2910
|
children: [
|
|
2473
|
-
/* @__PURE__ */ (0,
|
|
2911
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2474
2912
|
"span",
|
|
2475
2913
|
{
|
|
2476
2914
|
className: (0, import_design_system6.cn)(
|
|
@@ -2478,20 +2916,20 @@ function AssociationCard({
|
|
|
2478
2916
|
role.accentBg,
|
|
2479
2917
|
role.accentText
|
|
2480
2918
|
),
|
|
2481
|
-
children: /* @__PURE__ */ (0,
|
|
2919
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { className: "h-4 w-4" })
|
|
2482
2920
|
}
|
|
2483
2921
|
),
|
|
2484
|
-
/* @__PURE__ */ (0,
|
|
2485
|
-
/* @__PURE__ */ (0,
|
|
2486
|
-
/* @__PURE__ */ (0,
|
|
2487
|
-
/* @__PURE__ */ (0,
|
|
2922
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "min-w-0 flex-1", children: [
|
|
2923
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "block truncate text-sm font-medium text-foreground", children: info.labelPlural }),
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "block text-[11px] text-muted-foreground tabular-nums", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
2925
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }),
|
|
2488
2926
|
"Loading\u2026"
|
|
2489
2927
|
] }) : `${count} attached` })
|
|
2490
2928
|
] })
|
|
2491
2929
|
]
|
|
2492
2930
|
}
|
|
2493
2931
|
),
|
|
2494
|
-
canAttach && /* @__PURE__ */ (0,
|
|
2932
|
+
canAttach && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2495
2933
|
"button",
|
|
2496
2934
|
{
|
|
2497
2935
|
type: "button",
|
|
@@ -2499,13 +2937,13 @@ function AssociationCard({
|
|
|
2499
2937
|
"aria-label": `Attach ${info.labelPlural.toLowerCase()}`,
|
|
2500
2938
|
title: `Attach ${info.labelPlural.toLowerCase()}`,
|
|
2501
2939
|
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",
|
|
2502
|
-
children: /* @__PURE__ */ (0,
|
|
2940
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PlusIcon, { className: "h-4 w-4" })
|
|
2503
2941
|
}
|
|
2504
2942
|
)
|
|
2505
2943
|
]
|
|
2506
2944
|
}
|
|
2507
2945
|
),
|
|
2508
|
-
listOpen && /* @__PURE__ */ (0,
|
|
2946
|
+
listOpen && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2509
2947
|
AttachedItemsSheet,
|
|
2510
2948
|
{
|
|
2511
2949
|
open: listOpen,
|
|
@@ -2523,7 +2961,7 @@ function AssociationCard({
|
|
|
2523
2961
|
onDetach: (resourceId) => detach(token, resourceId)
|
|
2524
2962
|
}
|
|
2525
2963
|
),
|
|
2526
|
-
canAttach && /* @__PURE__ */ (0,
|
|
2964
|
+
canAttach && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2527
2965
|
AssociationPicker,
|
|
2528
2966
|
{
|
|
2529
2967
|
open,
|
|
@@ -2541,7 +2979,7 @@ function AssociationCard({
|
|
|
2541
2979
|
|
|
2542
2980
|
// src/react/components/AssociationCardGrid.tsx
|
|
2543
2981
|
var import_design_system7 = require("@ai-matrx/design-system");
|
|
2544
|
-
var
|
|
2982
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2545
2983
|
function AssociationCardGrid({
|
|
2546
2984
|
tokens,
|
|
2547
2985
|
excludeTokens,
|
|
@@ -2552,33 +2990,33 @@ function AssociationCardGrid({
|
|
|
2552
2990
|
const list = (tokens ?? store.registry.curatedTokens()).filter(
|
|
2553
2991
|
(token) => !excluded.has(token)
|
|
2554
2992
|
);
|
|
2555
|
-
return /* @__PURE__ */ (0,
|
|
2993
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: (0, import_design_system7.cn)("space-y-5", className), children: CONTENT_ROLES.map((role) => {
|
|
2556
2994
|
const inRole = list.filter(
|
|
2557
2995
|
(token) => store.registry.getEntityInfo(token).contentRole === role.id
|
|
2558
2996
|
);
|
|
2559
2997
|
if (inRole.length === 0) return null;
|
|
2560
|
-
return /* @__PURE__ */ (0,
|
|
2561
|
-
/* @__PURE__ */ (0,
|
|
2562
|
-
/* @__PURE__ */ (0,
|
|
2563
|
-
/* @__PURE__ */ (0,
|
|
2998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { children: [
|
|
2999
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mb-2.5 flex items-baseline gap-3 pl-1.5", children: [
|
|
3000
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3001
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2564
3002
|
"span",
|
|
2565
3003
|
{
|
|
2566
3004
|
className: (0, import_design_system7.cn)("h-2.5 w-2.5 rounded-full", role.accentBar)
|
|
2567
3005
|
}
|
|
2568
3006
|
),
|
|
2569
|
-
/* @__PURE__ */ (0,
|
|
3007
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-sm font-semibold text-foreground", children: role.title })
|
|
2570
3008
|
] }),
|
|
2571
|
-
/* @__PURE__ */ (0,
|
|
3009
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "hidden text-xs text-muted-foreground sm:block", children: role.tagline })
|
|
2572
3010
|
] }),
|
|
2573
|
-
/* @__PURE__ */ (0,
|
|
3011
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3", children: inRole.map((token) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AssociationCard, { token }, token)) })
|
|
2574
3012
|
] }, role.id);
|
|
2575
3013
|
}) });
|
|
2576
3014
|
}
|
|
2577
3015
|
|
|
2578
3016
|
// src/react/components/AssociationList.tsx
|
|
2579
|
-
var
|
|
3017
|
+
var import_react17 = require("react");
|
|
2580
3018
|
var import_design_system8 = require("@ai-matrx/design-system");
|
|
2581
|
-
var
|
|
3019
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2582
3020
|
function useContainerLinksAdapter(container, tokens) {
|
|
2583
3021
|
const store = useAssociationsStore();
|
|
2584
3022
|
const links = useContainerLinks({
|
|
@@ -2616,9 +3054,9 @@ function AssociationList(props) {
|
|
|
2616
3054
|
const adapter = props.adapter ?? defaultAdapter;
|
|
2617
3055
|
const variant = props.variant ?? "full";
|
|
2618
3056
|
const tokenFilter = props.tokens ?? null;
|
|
2619
|
-
const [pickerToken, setPickerToken] = (0,
|
|
2620
|
-
const [showUniversal, setShowUniversal] = (0,
|
|
2621
|
-
const [removingKeys, setRemovingKeys] = (0,
|
|
3057
|
+
const [pickerToken, setPickerToken] = (0, import_react17.useState)(null);
|
|
3058
|
+
const [showUniversal, setShowUniversal] = (0, import_react17.useState)(false);
|
|
3059
|
+
const [removingKeys, setRemovingKeys] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
|
|
2622
3060
|
const rows = tokenFilter ? adapter.rows.filter((r) => tokenFilter.includes(r.token)) : adapter.rows;
|
|
2623
3061
|
const visibleRows = rows.filter((r) => !removingKeys.has(r.key));
|
|
2624
3062
|
const { titleFor } = useEntityTitles(
|
|
@@ -2656,15 +3094,15 @@ function AssociationList(props) {
|
|
|
2656
3094
|
const grouped = groupRows(store, visibleRows);
|
|
2657
3095
|
const isLoading = adapter.status === "loading" || adapter.status === "idle";
|
|
2658
3096
|
const attachableTokens = tokenFilter ?? store.registry.curatedTokens();
|
|
2659
|
-
return /* @__PURE__ */ (0,
|
|
2660
|
-
/* @__PURE__ */ (0,
|
|
2661
|
-
/* @__PURE__ */ (0,
|
|
2662
|
-
/* @__PURE__ */ (0,
|
|
3097
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: (0, import_design_system8.cn)("flex flex-col gap-2 text-foreground", props.className), children: [
|
|
3098
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between gap-2 px-1", children: [
|
|
3099
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("h3", { className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: [
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Link2Icon, { className: "h-3.5 w-3.5" }),
|
|
2663
3101
|
"Resources",
|
|
2664
|
-
visibleRows.length > 0 && /* @__PURE__ */ (0,
|
|
3102
|
+
visibleRows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rounded bg-muted px-1 text-[10px] font-medium text-muted-foreground", children: visibleRows.length })
|
|
2665
3103
|
] }),
|
|
2666
|
-
/* @__PURE__ */ (0,
|
|
2667
|
-
/* @__PURE__ */ (0,
|
|
3104
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
3105
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2668
3106
|
"button",
|
|
2669
3107
|
{
|
|
2670
3108
|
type: "button",
|
|
@@ -2674,19 +3112,19 @@ function AssociationList(props) {
|
|
|
2674
3112
|
showUniversal ? "bg-accent text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
2675
3113
|
),
|
|
2676
3114
|
children: [
|
|
2677
|
-
/* @__PURE__ */ (0,
|
|
3115
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PlusIcon, { className: "h-3 w-3" }),
|
|
2678
3116
|
"Add"
|
|
2679
3117
|
]
|
|
2680
3118
|
}
|
|
2681
3119
|
),
|
|
2682
|
-
/* @__PURE__ */ (0,
|
|
3120
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2683
3121
|
"button",
|
|
2684
3122
|
{
|
|
2685
3123
|
type: "button",
|
|
2686
3124
|
onClick: () => void adapter.reload(),
|
|
2687
3125
|
title: "Refresh",
|
|
2688
3126
|
className: "text-muted-foreground/60 transition-colors hover:text-foreground",
|
|
2689
|
-
children: /* @__PURE__ */ (0,
|
|
3127
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2690
3128
|
RefreshIcon,
|
|
2691
3129
|
{
|
|
2692
3130
|
className: (0, import_design_system8.cn)(
|
|
@@ -2699,7 +3137,7 @@ function AssociationList(props) {
|
|
|
2699
3137
|
)
|
|
2700
3138
|
] })
|
|
2701
3139
|
] }),
|
|
2702
|
-
showUniversal && /* @__PURE__ */ (0,
|
|
3140
|
+
showUniversal && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-md border border-border/60 bg-muted/30 p-2 max-h-80 flex flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2703
3141
|
UniversalAssociationPicker,
|
|
2704
3142
|
{
|
|
2705
3143
|
tokens: attachableTokens,
|
|
@@ -2709,9 +3147,9 @@ function AssociationList(props) {
|
|
|
2709
3147
|
onDetach: (token, id) => adapter.detach(token, id)
|
|
2710
3148
|
}
|
|
2711
3149
|
) }),
|
|
2712
|
-
adapter.status === "error" && /* @__PURE__ */ (0,
|
|
2713
|
-
/* @__PURE__ */ (0,
|
|
2714
|
-
/* @__PURE__ */ (0,
|
|
3150
|
+
adapter.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-2.5 py-2", children: [
|
|
3151
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "truncate text-[11px] text-destructive", children: adapter.error || "Failed to load resources" }),
|
|
3152
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2715
3153
|
"button",
|
|
2716
3154
|
{
|
|
2717
3155
|
type: "button",
|
|
@@ -2721,17 +3159,17 @@ function AssociationList(props) {
|
|
|
2721
3159
|
}
|
|
2722
3160
|
)
|
|
2723
3161
|
] }),
|
|
2724
|
-
adapter.status !== "error" && isLoading && visibleRows.length === 0 && /* @__PURE__ */ (0,
|
|
2725
|
-
/* @__PURE__ */ (0,
|
|
2726
|
-
/* @__PURE__ */ (0,
|
|
2727
|
-
/* @__PURE__ */ (0,
|
|
3162
|
+
adapter.status !== "error" && isLoading && visibleRows.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-1.5 px-1", children: [
|
|
3163
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_design_system8.Skeleton, { className: "h-3 w-20" }),
|
|
3164
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_design_system8.Skeleton, { className: "h-7 w-full rounded-md" }),
|
|
3165
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_design_system8.Skeleton, { className: "h-7 w-3/4 rounded-md" })
|
|
2728
3166
|
] }),
|
|
2729
|
-
adapter.status === "ready" && visibleRows.length === 0 && /* @__PURE__ */ (0,
|
|
2730
|
-
visibleRows.length > 0 && /* @__PURE__ */ (0,
|
|
3167
|
+
adapter.status === "ready" && visibleRows.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "px-1 py-1 text-[11px] text-muted-foreground", children: "Nothing attached yet \u2014 use Add to link anything." }),
|
|
3168
|
+
visibleRows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "space-y-2.5", children: grouped.map(({ role, tokens: tokenGroups }) => {
|
|
2731
3169
|
const roleMeta = getContentRoleMeta(role);
|
|
2732
|
-
return /* @__PURE__ */ (0,
|
|
2733
|
-
variant === "full" && /* @__PURE__ */ (0,
|
|
2734
|
-
/* @__PURE__ */ (0,
|
|
3170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-1.5", children: [
|
|
3171
|
+
variant === "full" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1.5 px-1", children: [
|
|
3172
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2735
3173
|
"span",
|
|
2736
3174
|
{
|
|
2737
3175
|
className: (0, import_design_system8.cn)(
|
|
@@ -2740,7 +3178,7 @@ function AssociationList(props) {
|
|
|
2740
3178
|
)
|
|
2741
3179
|
}
|
|
2742
3180
|
),
|
|
2743
|
-
/* @__PURE__ */ (0,
|
|
3181
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2744
3182
|
"p",
|
|
2745
3183
|
{
|
|
2746
3184
|
className: (0, import_design_system8.cn)(
|
|
@@ -2753,28 +3191,28 @@ function AssociationList(props) {
|
|
|
2753
3191
|
] }),
|
|
2754
3192
|
tokenGroups.map(({ info, token, rows: tokenRows }) => {
|
|
2755
3193
|
const TokenIcon = info?.Icon ?? null;
|
|
2756
|
-
return /* @__PURE__ */ (0,
|
|
2757
|
-
/* @__PURE__ */ (0,
|
|
2758
|
-
/* @__PURE__ */ (0,
|
|
2759
|
-
TokenIcon ? /* @__PURE__ */ (0,
|
|
3194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-0.5", children: [
|
|
3195
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between gap-1 px-1", children: [
|
|
3196
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "flex items-center gap-1 text-[10px] font-medium text-muted-foreground/80", children: [
|
|
3197
|
+
TokenIcon ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TokenIcon, { className: "h-3 w-3" }) : null,
|
|
2760
3198
|
info?.labelPlural ?? titleize(token),
|
|
2761
|
-
/* @__PURE__ */ (0,
|
|
3199
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-muted-foreground/50", children: tokenRows.length })
|
|
2762
3200
|
] }),
|
|
2763
|
-
/* @__PURE__ */ (0,
|
|
3201
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
2764
3202
|
props.renderSectionActions && info ? props.renderSectionActions(info.token) : null,
|
|
2765
|
-
info?.canListCandidates && /* @__PURE__ */ (0,
|
|
3203
|
+
info?.canListCandidates && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2766
3204
|
"button",
|
|
2767
3205
|
{
|
|
2768
3206
|
type: "button",
|
|
2769
3207
|
onClick: () => setPickerToken(info.token),
|
|
2770
3208
|
title: `Add ${info.labelPlural}`,
|
|
2771
3209
|
className: "rounded p-0.5 text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground",
|
|
2772
|
-
children: /* @__PURE__ */ (0,
|
|
3210
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PlusIcon, { className: "h-3 w-3" })
|
|
2773
3211
|
}
|
|
2774
3212
|
)
|
|
2775
3213
|
] })
|
|
2776
3214
|
] }),
|
|
2777
|
-
/* @__PURE__ */ (0,
|
|
3215
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className: "space-y-0.5", children: tokenRows.map((row) => {
|
|
2778
3216
|
const busy = removingKeys.has(row.key);
|
|
2779
3217
|
const custom = props.renderRow?.(row, {
|
|
2780
3218
|
title: titleFor({
|
|
@@ -2787,9 +3225,9 @@ function AssociationList(props) {
|
|
|
2787
3225
|
onOpen: () => openRow(row)
|
|
2788
3226
|
});
|
|
2789
3227
|
if (custom != null) {
|
|
2790
|
-
return /* @__PURE__ */ (0,
|
|
3228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("li", { children: custom }, row.key);
|
|
2791
3229
|
}
|
|
2792
|
-
return /* @__PURE__ */ (0,
|
|
3230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2793
3231
|
"div",
|
|
2794
3232
|
{
|
|
2795
3233
|
className: (0, import_design_system8.cn)(
|
|
@@ -2797,7 +3235,7 @@ function AssociationList(props) {
|
|
|
2797
3235
|
busy && "opacity-50"
|
|
2798
3236
|
),
|
|
2799
3237
|
children: [
|
|
2800
|
-
/* @__PURE__ */ (0,
|
|
3238
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2801
3239
|
DoorRef,
|
|
2802
3240
|
{
|
|
2803
3241
|
token: row.token,
|
|
@@ -2813,9 +3251,9 @@ function AssociationList(props) {
|
|
|
2813
3251
|
className: "min-w-0 flex-1 text-foreground"
|
|
2814
3252
|
}
|
|
2815
3253
|
),
|
|
2816
|
-
row.originRefs && row.originRefs.length > 0 ? /* @__PURE__ */ (0,
|
|
3254
|
+
row.originRefs && row.originRefs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex shrink-0 items-center gap-1 text-[10px] text-muted-foreground/60", children: [
|
|
2817
3255
|
"via",
|
|
2818
|
-
row.originRefs.map((origin) => /* @__PURE__ */ (0,
|
|
3256
|
+
row.originRefs.map((origin) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2819
3257
|
DoorRef,
|
|
2820
3258
|
{
|
|
2821
3259
|
token: origin.token,
|
|
@@ -2827,8 +3265,8 @@ function AssociationList(props) {
|
|
|
2827
3265
|
},
|
|
2828
3266
|
`${origin.token}:${origin.id}`
|
|
2829
3267
|
))
|
|
2830
|
-
] }) : row.originNote ? /* @__PURE__ */ (0,
|
|
2831
|
-
adapter.setPinned && info && row.removable && /* @__PURE__ */ (0,
|
|
3268
|
+
] }) : row.originNote ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: row.originNote }) : null,
|
|
3269
|
+
adapter.setPinned && info && row.removable && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2832
3270
|
"button",
|
|
2833
3271
|
{
|
|
2834
3272
|
type: "button",
|
|
@@ -2843,7 +3281,7 @@ function AssociationList(props) {
|
|
|
2843
3281
|
"shrink-0 rounded p-0.5 transition-colors hover:!text-foreground",
|
|
2844
3282
|
row.pinned ? "text-primary" : "text-muted-foreground/0 group-hover:text-muted-foreground"
|
|
2845
3283
|
),
|
|
2846
|
-
children: /* @__PURE__ */ (0,
|
|
3284
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2847
3285
|
PinIcon,
|
|
2848
3286
|
{
|
|
2849
3287
|
className: (0, import_design_system8.cn)(
|
|
@@ -2854,7 +3292,7 @@ function AssociationList(props) {
|
|
|
2854
3292
|
)
|
|
2855
3293
|
}
|
|
2856
3294
|
),
|
|
2857
|
-
row.removable && /* @__PURE__ */ (0,
|
|
3295
|
+
row.removable && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2858
3296
|
"button",
|
|
2859
3297
|
{
|
|
2860
3298
|
type: "button",
|
|
@@ -2863,7 +3301,7 @@ function AssociationList(props) {
|
|
|
2863
3301
|
title: "Detach",
|
|
2864
3302
|
"aria-label": "Detach",
|
|
2865
3303
|
className: "shrink-0 rounded p-0.5 text-muted-foreground/0 transition-colors group-hover:text-muted-foreground hover:!text-destructive disabled:opacity-50",
|
|
2866
|
-
children: busy ? /* @__PURE__ */ (0,
|
|
3304
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(XIcon, { className: "h-3 w-3" })
|
|
2867
3305
|
}
|
|
2868
3306
|
)
|
|
2869
3307
|
]
|
|
@@ -2874,7 +3312,7 @@ function AssociationList(props) {
|
|
|
2874
3312
|
})
|
|
2875
3313
|
] }, role);
|
|
2876
3314
|
}) }),
|
|
2877
|
-
pickerToken && /* @__PURE__ */ (0,
|
|
3315
|
+
pickerToken && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2878
3316
|
AssociationPicker,
|
|
2879
3317
|
{
|
|
2880
3318
|
open: true,
|
|
@@ -2930,9 +3368,9 @@ function titleize(token) {
|
|
|
2930
3368
|
}
|
|
2931
3369
|
|
|
2932
3370
|
// src/react/components/AssociationCaptureToolbar.tsx
|
|
2933
|
-
var
|
|
3371
|
+
var import_react18 = require("react");
|
|
2934
3372
|
var import_design_system9 = require("@ai-matrx/design-system");
|
|
2935
|
-
var
|
|
3373
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2936
3374
|
function AssociationCaptureToolbar({
|
|
2937
3375
|
attach,
|
|
2938
3376
|
uploadFolderPath,
|
|
@@ -2950,21 +3388,43 @@ function AssociationCaptureToolbar({
|
|
|
2950
3388
|
const store = useAssociationsStore();
|
|
2951
3389
|
const { capture } = useAssociationsUiPorts();
|
|
2952
3390
|
const notifier = useNotifier();
|
|
2953
|
-
const fileInputRef = (0,
|
|
2954
|
-
const [isUploading, setIsUploading] = (0,
|
|
2955
|
-
const [isDragOver, setIsDragOver] = (0,
|
|
2956
|
-
const [isPicking, setIsPicking] = (0,
|
|
2957
|
-
const [namingDoc, setNamingDoc] = (0,
|
|
2958
|
-
const [docName, setDocName] = (0,
|
|
2959
|
-
const [creatingDoc, setCreatingDoc] = (0,
|
|
3391
|
+
const fileInputRef = (0, import_react18.useRef)(null);
|
|
3392
|
+
const [isUploading, setIsUploading] = (0, import_react18.useState)(false);
|
|
3393
|
+
const [isDragOver, setIsDragOver] = (0, import_react18.useState)(false);
|
|
3394
|
+
const [isPicking, setIsPicking] = (0, import_react18.useState)(false);
|
|
3395
|
+
const [namingDoc, setNamingDoc] = (0, import_react18.useState)(false);
|
|
3396
|
+
const [docName, setDocName] = (0, import_react18.useState)("");
|
|
3397
|
+
const [creatingDoc, setCreatingDoc] = (0, import_react18.useState)(false);
|
|
3398
|
+
const hostRequestUpload = capture?.requestUpload;
|
|
3399
|
+
const hostUploadFile = capture?.uploadFile;
|
|
3400
|
+
const requestUploadPath = hostRequestUpload ? (opts) => hostRequestUpload(opts) : hostUploadFile ? async (opts) => {
|
|
3401
|
+
const uploaded = [];
|
|
3402
|
+
const failed = [];
|
|
3403
|
+
for (const file of opts.files) {
|
|
3404
|
+
try {
|
|
3405
|
+
const result = await hostUploadFile(file, {
|
|
3406
|
+
folderPath: opts.folderPath,
|
|
3407
|
+
...opts.visibility !== void 0 ? { visibility: opts.visibility } : {}
|
|
3408
|
+
});
|
|
3409
|
+
if (result.ok) uploaded.push(result.id);
|
|
3410
|
+
else failed.push({ name: file.name, error: result.error });
|
|
3411
|
+
} catch (err) {
|
|
3412
|
+
failed.push({
|
|
3413
|
+
name: file.name,
|
|
3414
|
+
error: err instanceof Error && err.message ? err.message : "Upload failed"
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
return { uploaded, aliased: [], failed };
|
|
3419
|
+
} : void 0;
|
|
2960
3420
|
const actions = {
|
|
2961
|
-
upload: (showActions?.upload ?? true) && Boolean(
|
|
3421
|
+
upload: (showActions?.upload ?? true) && Boolean(requestUploadPath),
|
|
2962
3422
|
addFile: (showActions?.addFile ?? true) && Boolean(capture?.openFilePicker),
|
|
2963
3423
|
newDocument: (showActions?.newDocument ?? true) && Boolean(capture?.createDataTable)
|
|
2964
3424
|
};
|
|
2965
|
-
const canDrop = Boolean(
|
|
3425
|
+
const canDrop = Boolean(requestUploadPath);
|
|
2966
3426
|
const uploadAndAttach = async (files) => {
|
|
2967
|
-
const requestUpload =
|
|
3427
|
+
const requestUpload = requestUploadPath;
|
|
2968
3428
|
if (files.length === 0 || !requestUpload) return;
|
|
2969
3429
|
setIsUploading(true);
|
|
2970
3430
|
const watchdog = setTimeout(() => {
|
|
@@ -3122,7 +3582,7 @@ function AssociationCaptureToolbar({
|
|
|
3122
3582
|
}
|
|
3123
3583
|
};
|
|
3124
3584
|
const anyBuiltIn = actions.upload || actions.addFile || actions.newDocument;
|
|
3125
|
-
return /* @__PURE__ */ (0,
|
|
3585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3126
3586
|
"div",
|
|
3127
3587
|
{
|
|
3128
3588
|
className: (0, import_design_system9.cn)(
|
|
@@ -3143,11 +3603,11 @@ function AssociationCaptureToolbar({
|
|
|
3143
3603
|
},
|
|
3144
3604
|
onDrop: handleDrop,
|
|
3145
3605
|
children: [
|
|
3146
|
-
isDragOver ? /* @__PURE__ */ (0,
|
|
3147
|
-
/* @__PURE__ */ (0,
|
|
3606
|
+
isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "pointer-events-none absolute inset-0 z-10 grid place-items-center bg-background/70", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
|
|
3607
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(UploadIcon, { className: "size-3.5 text-primary" }),
|
|
3148
3608
|
"Drop to upload & attach"
|
|
3149
3609
|
] }) }) : null,
|
|
3150
|
-
/* @__PURE__ */ (0,
|
|
3610
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3151
3611
|
"input",
|
|
3152
3612
|
{
|
|
3153
3613
|
ref: fileInputRef,
|
|
@@ -3157,8 +3617,8 @@ function AssociationCaptureToolbar({
|
|
|
3157
3617
|
onChange: handleFilesSelected
|
|
3158
3618
|
}
|
|
3159
3619
|
),
|
|
3160
|
-
showToolbar && (anyBuiltIn || extraActions) ? /* @__PURE__ */ (0,
|
|
3161
|
-
/* @__PURE__ */ (0,
|
|
3620
|
+
showToolbar && (anyBuiltIn || extraActions) ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex flex-wrap items-center gap-0.5 border-b border-border/60 px-1.5 py-1", children: namingDoc ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-1 items-center gap-1.5 py-0.5", children: [
|
|
3621
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3162
3622
|
import_design_system9.Input,
|
|
3163
3623
|
{
|
|
3164
3624
|
autoFocus: true,
|
|
@@ -3177,17 +3637,17 @@ function AssociationCaptureToolbar({
|
|
|
3177
3637
|
style: { fontSize: 16 }
|
|
3178
3638
|
}
|
|
3179
3639
|
),
|
|
3180
|
-
/* @__PURE__ */ (0,
|
|
3640
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3181
3641
|
"button",
|
|
3182
3642
|
{
|
|
3183
3643
|
type: "button",
|
|
3184
3644
|
disabled: creatingDoc || !docName.trim(),
|
|
3185
3645
|
onClick: () => void handleCreateDoc(),
|
|
3186
3646
|
className: "flex h-7 items-center rounded-md bg-primary px-2 text-[11px] font-medium text-primary-foreground disabled:opacity-50",
|
|
3187
|
-
children: creatingDoc ? /* @__PURE__ */ (0,
|
|
3647
|
+
children: creatingDoc ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SpinnerIcon, { className: "size-3.5 animate-spin" }) : "Create"
|
|
3188
3648
|
}
|
|
3189
3649
|
),
|
|
3190
|
-
/* @__PURE__ */ (0,
|
|
3650
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3191
3651
|
"button",
|
|
3192
3652
|
{
|
|
3193
3653
|
type: "button",
|
|
@@ -3200,8 +3660,8 @@ function AssociationCaptureToolbar({
|
|
|
3200
3660
|
children: "Cancel"
|
|
3201
3661
|
}
|
|
3202
3662
|
)
|
|
3203
|
-
] }) : /* @__PURE__ */ (0,
|
|
3204
|
-
actions.upload ? /* @__PURE__ */ (0,
|
|
3663
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
3664
|
+
actions.upload ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3205
3665
|
CaptureToolbarAction,
|
|
3206
3666
|
{
|
|
3207
3667
|
icon: isUploading ? SpinnerIcon : UploadIcon,
|
|
@@ -3211,7 +3671,7 @@ function AssociationCaptureToolbar({
|
|
|
3211
3671
|
disabled: isPicking || isUploading
|
|
3212
3672
|
}
|
|
3213
3673
|
) : null,
|
|
3214
|
-
actions.addFile ? /* @__PURE__ */ (0,
|
|
3674
|
+
actions.addFile ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3215
3675
|
CaptureToolbarAction,
|
|
3216
3676
|
{
|
|
3217
3677
|
icon: isPicking ? SpinnerIcon : FolderOpenIcon,
|
|
@@ -3221,8 +3681,8 @@ function AssociationCaptureToolbar({
|
|
|
3221
3681
|
disabled: isPicking || isUploading
|
|
3222
3682
|
}
|
|
3223
3683
|
) : null,
|
|
3224
|
-
(actions.upload || actions.addFile) && actions.newDocument ? /* @__PURE__ */ (0,
|
|
3225
|
-
actions.newDocument ? /* @__PURE__ */ (0,
|
|
3684
|
+
(actions.upload || actions.addFile) && actions.newDocument ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
3685
|
+
actions.newDocument ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3226
3686
|
CaptureToolbarAction,
|
|
3227
3687
|
{
|
|
3228
3688
|
icon: creatingDoc ? SpinnerIcon : PlusIcon,
|
|
@@ -3246,7 +3706,7 @@ function CaptureToolbarAction({
|
|
|
3246
3706
|
disabled,
|
|
3247
3707
|
spinning
|
|
3248
3708
|
}) {
|
|
3249
|
-
return /* @__PURE__ */ (0,
|
|
3709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3250
3710
|
import_design_system9.Button,
|
|
3251
3711
|
{
|
|
3252
3712
|
type: "button",
|
|
@@ -3256,17 +3716,147 @@ function CaptureToolbarAction({
|
|
|
3256
3716
|
disabled,
|
|
3257
3717
|
className: "h-7 gap-1 px-2 text-[11px] text-muted-foreground hover:text-foreground",
|
|
3258
3718
|
children: [
|
|
3259
|
-
/* @__PURE__ */ (0,
|
|
3719
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { className: (0, import_design_system9.cn)("size-3.5", spinning && "animate-spin") }),
|
|
3260
3720
|
label
|
|
3261
3721
|
]
|
|
3262
3722
|
}
|
|
3263
3723
|
);
|
|
3264
3724
|
}
|
|
3265
3725
|
|
|
3726
|
+
// src/react/lazyPorts.tsx
|
|
3727
|
+
var import_react19 = require("react");
|
|
3728
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3729
|
+
function lazyComponent(load) {
|
|
3730
|
+
return (0, import_react19.lazy)(async () => {
|
|
3731
|
+
const loaded = await load();
|
|
3732
|
+
return typeof loaded === "function" ? { default: loaded } : loaded;
|
|
3733
|
+
});
|
|
3734
|
+
}
|
|
3735
|
+
function lazyWindowShell(load) {
|
|
3736
|
+
const Loaded = lazyComponent(load);
|
|
3737
|
+
return function LazyWindowShell(props) {
|
|
3738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react19.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Loaded, { ...props }) });
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3741
|
+
function lazyPickerOverride(load) {
|
|
3742
|
+
const Loaded = lazyComponent(load);
|
|
3743
|
+
return function LazyPickerOverride(props) {
|
|
3744
|
+
if (!props.open) return null;
|
|
3745
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react19.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Loaded, { ...props }) });
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3749
|
+
// src/react/hooks/useAssociationPickerBridge.ts
|
|
3750
|
+
var import_react20 = require("react");
|
|
3751
|
+
function useAssociationPickerBridge(props, options = {}) {
|
|
3752
|
+
const store = useAssociationsStore();
|
|
3753
|
+
const notifier = useNotifier();
|
|
3754
|
+
const [busy, setBusy] = (0, import_react20.useState)(false);
|
|
3755
|
+
const { attachedIds, onAttach, onDetach, token } = props;
|
|
3756
|
+
const {
|
|
3757
|
+
createdLocationLabel,
|
|
3758
|
+
openCreatedLocation,
|
|
3759
|
+
itemNoun = "item"
|
|
3760
|
+
} = options;
|
|
3761
|
+
const attachMany = (0, import_react20.useCallback)(
|
|
3762
|
+
async (items) => {
|
|
3763
|
+
if (items.length === 0) return;
|
|
3764
|
+
setBusy(true);
|
|
3765
|
+
const failed = [];
|
|
3766
|
+
try {
|
|
3767
|
+
for (const item of items) {
|
|
3768
|
+
try {
|
|
3769
|
+
const result = await onAttach(item.id, item.name);
|
|
3770
|
+
if (!result.ok) {
|
|
3771
|
+
failed.push({ name: item.name, error: result.error });
|
|
3772
|
+
}
|
|
3773
|
+
} catch (error) {
|
|
3774
|
+
store.errorSink({
|
|
3775
|
+
code: "picker_attach_threw",
|
|
3776
|
+
message: `[associations] attaching ${itemNoun} "${item.name}" threw`,
|
|
3777
|
+
context: { token, id: item.id, detail: error }
|
|
3778
|
+
});
|
|
3779
|
+
failed.push({
|
|
3780
|
+
name: item.name,
|
|
3781
|
+
error: error instanceof Error ? error.message : void 0
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
const attached = items.length - failed.length;
|
|
3786
|
+
if (attached > 0) {
|
|
3787
|
+
notifier.success(
|
|
3788
|
+
attached === 1 ? `Attached 1 ${itemNoun}` : `Attached ${attached} ${itemNoun}s`
|
|
3789
|
+
);
|
|
3790
|
+
}
|
|
3791
|
+
if (failed.length > 0) {
|
|
3792
|
+
const first = failed[0];
|
|
3793
|
+
const detail = first?.error ? ` (${first.error})` : "";
|
|
3794
|
+
notifier.error(
|
|
3795
|
+
failed.length === 1 ? `Couldn't attach "${first?.name ?? itemNoun}"${detail}` : `Couldn't attach ${failed.length} ${itemNoun}s${detail}`,
|
|
3796
|
+
{
|
|
3797
|
+
...createdLocationLabel ? {
|
|
3798
|
+
description: `The ${failed.length === 1 ? itemNoun + " is" : itemNoun + "s are"} safe in ${createdLocationLabel}. You can retry the association here.`
|
|
3799
|
+
} : {},
|
|
3800
|
+
...openCreatedLocation ? { action: openCreatedLocation } : {}
|
|
3801
|
+
}
|
|
3802
|
+
);
|
|
3803
|
+
store.errorSink({
|
|
3804
|
+
code: "picker_attach_partial",
|
|
3805
|
+
message: `[associations] ${failed.length} of ${items.length} ${itemNoun}s were not attached`,
|
|
3806
|
+
context: { token, failed }
|
|
3807
|
+
});
|
|
3808
|
+
}
|
|
3809
|
+
} finally {
|
|
3810
|
+
setBusy(false);
|
|
3811
|
+
}
|
|
3812
|
+
},
|
|
3813
|
+
[
|
|
3814
|
+
createdLocationLabel,
|
|
3815
|
+
itemNoun,
|
|
3816
|
+
notifier,
|
|
3817
|
+
onAttach,
|
|
3818
|
+
openCreatedLocation,
|
|
3819
|
+
store,
|
|
3820
|
+
token
|
|
3821
|
+
]
|
|
3822
|
+
);
|
|
3823
|
+
const toggle = (0, import_react20.useCallback)(
|
|
3824
|
+
async (item) => {
|
|
3825
|
+
setBusy(true);
|
|
3826
|
+
try {
|
|
3827
|
+
const detaching = attachedIds.has(item.id);
|
|
3828
|
+
const result = detaching ? await onDetach(item.id) : await onAttach(item.id, item.name);
|
|
3829
|
+
if (!result.ok) {
|
|
3830
|
+
const verb = detaching ? "detach" : "attach";
|
|
3831
|
+
notifier.error(
|
|
3832
|
+
`Couldn't ${verb} "${item.name}"` + (result.error ? `: ${result.error}` : "")
|
|
3833
|
+
);
|
|
3834
|
+
store.errorSink({
|
|
3835
|
+
code: detaching ? "picker_detach_failed" : "picker_attach_failed",
|
|
3836
|
+
message: `[associations] ${verb} refused for "${item.name}"`,
|
|
3837
|
+
context: { token, id: item.id, error: result.error }
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3840
|
+
} catch (error) {
|
|
3841
|
+
store.errorSink({
|
|
3842
|
+
code: "picker_toggle_threw",
|
|
3843
|
+
message: `[associations] toggling ${itemNoun} "${item.name}" threw`,
|
|
3844
|
+
context: { token, id: item.id, detail: error }
|
|
3845
|
+
});
|
|
3846
|
+
notifier.error(`Couldn't update "${item.name}"`);
|
|
3847
|
+
} finally {
|
|
3848
|
+
setBusy(false);
|
|
3849
|
+
}
|
|
3850
|
+
},
|
|
3851
|
+
[attachedIds, itemNoun, notifier, onAttach, onDetach, store, token]
|
|
3852
|
+
);
|
|
3853
|
+
return { attachMany, toggle, busy };
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3266
3856
|
// src/react/components/AssociationEntitySelect.tsx
|
|
3267
|
-
var
|
|
3857
|
+
var import_react21 = require("react");
|
|
3268
3858
|
var import_design_system10 = require("@ai-matrx/design-system");
|
|
3269
|
-
var
|
|
3859
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
3270
3860
|
function AssociationEntitySelect({
|
|
3271
3861
|
token,
|
|
3272
3862
|
adapter,
|
|
@@ -3280,19 +3870,17 @@ function AssociationEntitySelect({
|
|
|
3280
3870
|
createSlot
|
|
3281
3871
|
}) {
|
|
3282
3872
|
const store = useAssociationsStore();
|
|
3283
|
-
const { entityDoors } = useAssociationsUiPorts();
|
|
3284
3873
|
const notifier = useNotifier();
|
|
3285
3874
|
const info = store.registry.getEntityInfo(token);
|
|
3286
3875
|
const InfoIcon = info.Icon ?? DefaultEntityIcon;
|
|
3287
|
-
const DoorControls = entityDoors?.DoorControls;
|
|
3288
3876
|
const { items, activeId } = adapter;
|
|
3289
3877
|
const active = items.find((i) => i.id === activeId) ?? null;
|
|
3290
3878
|
const activeIndex = active ? items.indexOf(active) : -1;
|
|
3291
|
-
const [open, setOpen] = (0,
|
|
3292
|
-
const [query, setQuery] = (0,
|
|
3293
|
-
const [creating, setCreating] = (0,
|
|
3294
|
-
const [draftName, setDraftName] = (0,
|
|
3295
|
-
const [busy, setBusy] = (0,
|
|
3879
|
+
const [open, setOpen] = (0, import_react21.useState)(false);
|
|
3880
|
+
const [query, setQuery] = (0, import_react21.useState)("");
|
|
3881
|
+
const [creating, setCreating] = (0, import_react21.useState)(false);
|
|
3882
|
+
const [draftName, setDraftName] = (0, import_react21.useState)("");
|
|
3883
|
+
const [busy, setBusy] = (0, import_react21.useState)(false);
|
|
3296
3884
|
const entityLabel = info.label.toLowerCase();
|
|
3297
3885
|
const close = () => {
|
|
3298
3886
|
setOpen(false);
|
|
@@ -3309,7 +3897,7 @@ function AssociationEntitySelect({
|
|
|
3309
3897
|
if (id) close();
|
|
3310
3898
|
else notifier.error(`Couldn't create the ${entityLabel}`);
|
|
3311
3899
|
};
|
|
3312
|
-
return /* @__PURE__ */ (0,
|
|
3900
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3313
3901
|
"div",
|
|
3314
3902
|
{
|
|
3315
3903
|
className: (0, import_design_system10.cn)(
|
|
@@ -3317,7 +3905,7 @@ function AssociationEntitySelect({
|
|
|
3317
3905
|
className
|
|
3318
3906
|
),
|
|
3319
3907
|
children: [
|
|
3320
|
-
showIcon ? /* @__PURE__ */ (0,
|
|
3908
|
+
showIcon ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3321
3909
|
InfoIcon,
|
|
3322
3910
|
{
|
|
3323
3911
|
className: (0, import_design_system10.cn)(
|
|
@@ -3327,7 +3915,7 @@ function AssociationEntitySelect({
|
|
|
3327
3915
|
"aria-hidden": true
|
|
3328
3916
|
}
|
|
3329
3917
|
) : null,
|
|
3330
|
-
active ? /* @__PURE__ */ (0,
|
|
3918
|
+
active ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3331
3919
|
import_design_system10.EditableLabel,
|
|
3332
3920
|
{
|
|
3333
3921
|
value: active.title,
|
|
@@ -3346,8 +3934,8 @@ function AssociationEntitySelect({
|
|
|
3346
3934
|
inputClassName: "text-xs font-medium"
|
|
3347
3935
|
}
|
|
3348
3936
|
) : null,
|
|
3349
|
-
active
|
|
3350
|
-
!active ? /* @__PURE__ */ (0,
|
|
3937
|
+
active ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DoorControlsSlot, { token, id: active.id, name: active.title }) : null,
|
|
3938
|
+
!active ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3351
3939
|
"span",
|
|
3352
3940
|
{
|
|
3353
3941
|
className: (0, import_design_system10.cn)(
|
|
@@ -3357,13 +3945,13 @@ function AssociationEntitySelect({
|
|
|
3357
3945
|
children: adapter.loading ? "\u2026" : emptyLabel ?? info.labelPlural
|
|
3358
3946
|
}
|
|
3359
3947
|
) : null,
|
|
3360
|
-
/* @__PURE__ */ (0,
|
|
3948
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3361
3949
|
import_design_system10.Popover,
|
|
3362
3950
|
{
|
|
3363
3951
|
open,
|
|
3364
3952
|
onOpenChange: (next) => next ? setOpen(true) : close(),
|
|
3365
3953
|
children: [
|
|
3366
|
-
/* @__PURE__ */ (0,
|
|
3954
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system10.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3367
3955
|
"button",
|
|
3368
3956
|
{
|
|
3369
3957
|
type: "button",
|
|
@@ -3371,17 +3959,17 @@ function AssociationEntitySelect({
|
|
|
3371
3959
|
title: `Switch or add ${info.labelPlural.toLowerCase()}`,
|
|
3372
3960
|
"aria-label": `Switch or add ${info.labelPlural.toLowerCase()}`,
|
|
3373
3961
|
children: [
|
|
3374
|
-
items.length > 1 ? /* @__PURE__ */ (0,
|
|
3962
|
+
items.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "tabular-nums", children: [
|
|
3375
3963
|
activeIndex >= 0 ? activeIndex + 1 : "\u2014",
|
|
3376
3964
|
"/",
|
|
3377
3965
|
items.length
|
|
3378
3966
|
] }) : null,
|
|
3379
|
-
/* @__PURE__ */ (0,
|
|
3967
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ChevronDownIcon, { className: "size-3 opacity-60" })
|
|
3380
3968
|
]
|
|
3381
3969
|
}
|
|
3382
3970
|
) }),
|
|
3383
|
-
/* @__PURE__ */ (0,
|
|
3384
|
-
items.length > 5 ? /* @__PURE__ */ (0,
|
|
3971
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system10.PopoverContent, { className: "w-60 p-0", align, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system10.Command, { children: [
|
|
3972
|
+
items.length > 5 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3385
3973
|
import_design_system10.CommandInput,
|
|
3386
3974
|
{
|
|
3387
3975
|
value: query,
|
|
@@ -3389,9 +3977,9 @@ function AssociationEntitySelect({
|
|
|
3389
3977
|
placeholder: `Search ${info.labelPlural.toLowerCase()}\u2026`
|
|
3390
3978
|
}
|
|
3391
3979
|
) : null,
|
|
3392
|
-
/* @__PURE__ */ (0,
|
|
3393
|
-
/* @__PURE__ */ (0,
|
|
3394
|
-
items.length > 0 ? /* @__PURE__ */ (0,
|
|
3980
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system10.CommandList, { children: [
|
|
3981
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system10.CommandEmpty, { children: "No match." }),
|
|
3982
|
+
items.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system10.CommandGroup, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3395
3983
|
import_design_system10.CommandItem,
|
|
3396
3984
|
{
|
|
3397
3985
|
value: `${item.title} ${item.id}`,
|
|
@@ -3402,7 +3990,7 @@ function AssociationEntitySelect({
|
|
|
3402
3990
|
},
|
|
3403
3991
|
className: "group/entity-ref group gap-2",
|
|
3404
3992
|
children: [
|
|
3405
|
-
/* @__PURE__ */ (0,
|
|
3993
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3406
3994
|
CheckIcon,
|
|
3407
3995
|
{
|
|
3408
3996
|
className: (0, import_design_system10.cn)(
|
|
@@ -3411,8 +3999,8 @@ function AssociationEntitySelect({
|
|
|
3411
3999
|
)
|
|
3412
4000
|
}
|
|
3413
4001
|
),
|
|
3414
|
-
/* @__PURE__ */ (0,
|
|
3415
|
-
|
|
4002
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.title }),
|
|
4003
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3416
4004
|
"span",
|
|
3417
4005
|
{
|
|
3418
4006
|
className: "inline-flex shrink-0 items-center",
|
|
@@ -3420,8 +4008,8 @@ function AssociationEntitySelect({
|
|
|
3420
4008
|
e.preventDefault();
|
|
3421
4009
|
e.stopPropagation();
|
|
3422
4010
|
},
|
|
3423
|
-
children: /* @__PURE__ */ (0,
|
|
3424
|
-
|
|
4011
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4012
|
+
DoorControlsSlot,
|
|
3425
4013
|
{
|
|
3426
4014
|
token,
|
|
3427
4015
|
id: item.id,
|
|
@@ -3429,8 +4017,8 @@ function AssociationEntitySelect({
|
|
|
3429
4017
|
}
|
|
3430
4018
|
)
|
|
3431
4019
|
}
|
|
3432
|
-
)
|
|
3433
|
-
adapter.detach && item.id !== activeId ? /* @__PURE__ */ (0,
|
|
4020
|
+
),
|
|
4021
|
+
adapter.detach && item.id !== activeId ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3434
4022
|
"button",
|
|
3435
4023
|
{
|
|
3436
4024
|
type: "button",
|
|
@@ -3445,7 +4033,7 @@ function AssociationEntitySelect({
|
|
|
3445
4033
|
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",
|
|
3446
4034
|
title: `Remove this ${entityLabel} from here (does not delete it)`,
|
|
3447
4035
|
"aria-label": `Remove ${item.title}`,
|
|
3448
|
-
children: /* @__PURE__ */ (0,
|
|
4036
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(XIcon, { className: "size-3" })
|
|
3449
4037
|
}
|
|
3450
4038
|
) : null
|
|
3451
4039
|
]
|
|
@@ -3453,9 +4041,9 @@ function AssociationEntitySelect({
|
|
|
3453
4041
|
item.id
|
|
3454
4042
|
)) }) : null
|
|
3455
4043
|
] }),
|
|
3456
|
-
createSlot !== void 0 ? /* @__PURE__ */ (0,
|
|
3457
|
-
createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */ (0,
|
|
3458
|
-
/* @__PURE__ */ (0,
|
|
4044
|
+
createSlot !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "border-t border-border p-1", children: typeof createSlot === "function" ? createSlot(close) : createSlot }) : null,
|
|
4045
|
+
createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "border-t border-border p-1", children: creating ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1 px-1 py-0.5", children: [
|
|
4046
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3459
4047
|
"input",
|
|
3460
4048
|
{
|
|
3461
4049
|
autoFocus: true,
|
|
@@ -3479,17 +4067,17 @@ function AssociationEntitySelect({
|
|
|
3479
4067
|
"aria-label": `New ${entityLabel} name`
|
|
3480
4068
|
}
|
|
3481
4069
|
),
|
|
3482
|
-
/* @__PURE__ */ (0,
|
|
4070
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3483
4071
|
"button",
|
|
3484
4072
|
{
|
|
3485
4073
|
type: "button",
|
|
3486
4074
|
disabled: busy || !draftName.trim(),
|
|
3487
4075
|
onClick: () => void create(draftName),
|
|
3488
4076
|
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",
|
|
3489
|
-
children: busy ? /* @__PURE__ */ (0,
|
|
4077
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SpinnerIcon, { className: "size-3 animate-spin" }) : "Create"
|
|
3490
4078
|
}
|
|
3491
4079
|
)
|
|
3492
|
-
] }) : /* @__PURE__ */ (0,
|
|
4080
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3493
4081
|
"button",
|
|
3494
4082
|
{
|
|
3495
4083
|
type: "button",
|
|
@@ -3500,7 +4088,7 @@ function AssociationEntitySelect({
|
|
|
3500
4088
|
},
|
|
3501
4089
|
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",
|
|
3502
4090
|
children: [
|
|
3503
|
-
busy ? /* @__PURE__ */ (0,
|
|
4091
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SpinnerIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PlusIcon, { className: "size-3.5" }),
|
|
3504
4092
|
query.trim() ? `Create "${query.trim()}"` : `New ${info.label}`
|
|
3505
4093
|
]
|
|
3506
4094
|
}
|
|
@@ -3515,7 +4103,7 @@ function AssociationEntitySelect({
|
|
|
3515
4103
|
}
|
|
3516
4104
|
|
|
3517
4105
|
// src/react/components/CategorySelect.tsx
|
|
3518
|
-
var
|
|
4106
|
+
var import_react22 = require("react");
|
|
3519
4107
|
var import_design_system11 = require("@ai-matrx/design-system");
|
|
3520
4108
|
|
|
3521
4109
|
// src/core/categoryHierarchy.ts
|
|
@@ -3583,7 +4171,7 @@ function buildCategoryHierarchy(categories) {
|
|
|
3583
4171
|
}
|
|
3584
4172
|
|
|
3585
4173
|
// src/react/components/CategorySelect.tsx
|
|
3586
|
-
var
|
|
4174
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3587
4175
|
var NONE = "__none__";
|
|
3588
4176
|
var ROOT_PARENT = "__root__";
|
|
3589
4177
|
function plural(noun) {
|
|
@@ -3610,7 +4198,7 @@ function CategorySelect({
|
|
|
3610
4198
|
reload
|
|
3611
4199
|
} = useCategories({ dimension });
|
|
3612
4200
|
const hierarchy = buildCategoryHierarchy(categories);
|
|
3613
|
-
const [createParentId, setCreateParentId] = (0,
|
|
4201
|
+
const [createParentId, setCreateParentId] = (0, import_react22.useState)(ROOT_PARENT);
|
|
3614
4202
|
const options = [
|
|
3615
4203
|
...allowNone ? [{ value: NONE, label: "None", keywords: "none clear empty" }] : [],
|
|
3616
4204
|
...hierarchy.hasHierarchy ? hierarchy.items.map(({ category, depth, parent }) => ({
|
|
@@ -3619,9 +4207,9 @@ function CategorySelect({
|
|
|
3619
4207
|
// The type-ahead matches the parent's name too, so someone who knows
|
|
3620
4208
|
// the branch but not the leaf still finds it.
|
|
3621
4209
|
keywords: parent ? parent.name : "",
|
|
3622
|
-
render: depth === 0 ? /* @__PURE__ */ (0,
|
|
3623
|
-
/* @__PURE__ */ (0,
|
|
3624
|
-
/* @__PURE__ */ (0,
|
|
4210
|
+
render: depth === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-medium", children: category.name }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "flex items-center gap-1.5 pl-3 text-muted-foreground", children: [
|
|
4211
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CornerDownRightIcon, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
4212
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-foreground", children: category.name })
|
|
3625
4213
|
] })
|
|
3626
4214
|
})) : categories.map((category) => ({
|
|
3627
4215
|
value: category.id,
|
|
@@ -3668,8 +4256,8 @@ function CategorySelect({
|
|
|
3668
4256
|
);
|
|
3669
4257
|
return result.id;
|
|
3670
4258
|
};
|
|
3671
|
-
return /* @__PURE__ */ (0,
|
|
3672
|
-
/* @__PURE__ */ (0,
|
|
4259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
4260
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3673
4261
|
import_design_system11.CreatablePicker,
|
|
3674
4262
|
{
|
|
3675
4263
|
value: value ?? (allowNone ? NONE : null),
|
|
@@ -3685,18 +4273,18 @@ function CategorySelect({
|
|
|
3685
4273
|
emptyLabel: `No ${noun} matches that.`,
|
|
3686
4274
|
...allowCreate ? { onCreate: create } : {},
|
|
3687
4275
|
...allowCreate && hierarchy.hasHierarchy ? {
|
|
3688
|
-
createExtra: /* @__PURE__ */ (0,
|
|
3689
|
-
/* @__PURE__ */ (0,
|
|
4276
|
+
createExtra: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_design_system11.Select, { value: createParentId, onValueChange: setCreateParentId, children: [
|
|
4277
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3690
4278
|
import_design_system11.SelectTrigger,
|
|
3691
4279
|
{
|
|
3692
4280
|
className: "h-7 text-xs",
|
|
3693
4281
|
"aria-label": `Put the new ${noun} under`,
|
|
3694
|
-
children: /* @__PURE__ */ (0,
|
|
4282
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_design_system11.SelectValue, {})
|
|
3695
4283
|
}
|
|
3696
4284
|
),
|
|
3697
|
-
/* @__PURE__ */ (0,
|
|
3698
|
-
/* @__PURE__ */ (0,
|
|
3699
|
-
hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */ (0,
|
|
4285
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_design_system11.SelectContent, { children: [
|
|
4286
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_design_system11.SelectItem, { value: ROOT_PARENT, className: "text-xs", children: "Top level" }),
|
|
4287
|
+
hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
3700
4288
|
import_design_system11.SelectItem,
|
|
3701
4289
|
{
|
|
3702
4290
|
value: item.category.id,
|
|
@@ -3716,20 +4304,20 @@ function CategorySelect({
|
|
|
3716
4304
|
selected === null && value !== null ? (
|
|
3717
4305
|
// A stored id whose row this reader cannot see is not "nothing chosen":
|
|
3718
4306
|
// saying so beats a blank box that looks like an unsaved field.
|
|
3719
|
-
/* @__PURE__ */ (0,
|
|
4307
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
3720
4308
|
"This ",
|
|
3721
4309
|
noun,
|
|
3722
4310
|
" is no longer available to you."
|
|
3723
4311
|
] })
|
|
3724
4312
|
) : null,
|
|
3725
|
-
error ? /* @__PURE__ */ (0,
|
|
4313
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mt-1 text-xs text-destructive", children: error }) : null
|
|
3726
4314
|
] });
|
|
3727
4315
|
}
|
|
3728
4316
|
|
|
3729
4317
|
// src/react/components/CategoryTagPicker.tsx
|
|
3730
|
-
var
|
|
4318
|
+
var import_react23 = require("react");
|
|
3731
4319
|
var import_design_system12 = require("@ai-matrx/design-system");
|
|
3732
|
-
var
|
|
4320
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3733
4321
|
var ROOT_PARENT2 = "__root__";
|
|
3734
4322
|
function CategoryTagPicker({
|
|
3735
4323
|
entityType,
|
|
@@ -3745,11 +4333,11 @@ function CategoryTagPicker({
|
|
|
3745
4333
|
}) {
|
|
3746
4334
|
const store = useAssociationsStore();
|
|
3747
4335
|
const notifier = useNotifier();
|
|
3748
|
-
const [open, setOpen] = (0,
|
|
3749
|
-
const [creating, setCreating] = (0,
|
|
3750
|
-
const [writing, setWriting] = (0,
|
|
3751
|
-
const [search, setSearch] = (0,
|
|
3752
|
-
const [createParentId, setCreateParentId] = (0,
|
|
4336
|
+
const [open, setOpen] = (0, import_react23.useState)(false);
|
|
4337
|
+
const [creating, setCreating] = (0, import_react23.useState)(false);
|
|
4338
|
+
const [writing, setWriting] = (0, import_react23.useState)(false);
|
|
4339
|
+
const [search, setSearch] = (0, import_react23.useState)("");
|
|
4340
|
+
const [createParentId, setCreateParentId] = (0, import_react23.useState)(ROOT_PARENT2);
|
|
3753
4341
|
const {
|
|
3754
4342
|
categories,
|
|
3755
4343
|
create: createCategory,
|
|
@@ -3853,44 +4441,44 @@ function CategoryTagPicker({
|
|
|
3853
4441
|
const exactMatch = categories.some(
|
|
3854
4442
|
(c) => c.name.toLowerCase() === search.trim().toLowerCase()
|
|
3855
4443
|
);
|
|
3856
|
-
return /* @__PURE__ */ (0,
|
|
3857
|
-
selected.map((c) => /* @__PURE__ */ (0,
|
|
4444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
4445
|
+
selected.map((c) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3858
4446
|
import_design_system12.Badge,
|
|
3859
4447
|
{
|
|
3860
4448
|
variant: "secondary",
|
|
3861
4449
|
className: "gap-1 pr-1 text-xs font-medium",
|
|
3862
4450
|
children: [
|
|
3863
4451
|
showHierarchy ? hierarchyById.get(c.id)?.displayName ?? c.name : c.name,
|
|
3864
|
-
/* @__PURE__ */ (0,
|
|
4452
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3865
4453
|
"button",
|
|
3866
4454
|
{
|
|
3867
4455
|
type: "button",
|
|
3868
4456
|
onClick: () => void toggle(c.id),
|
|
3869
4457
|
className: "ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20",
|
|
3870
4458
|
"aria-label": `Remove ${c.name}`,
|
|
3871
|
-
children: /* @__PURE__ */ (0,
|
|
4459
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(XIcon, { className: "h-2.5 w-2.5" })
|
|
3872
4460
|
}
|
|
3873
4461
|
)
|
|
3874
4462
|
]
|
|
3875
4463
|
},
|
|
3876
4464
|
c.id
|
|
3877
4465
|
)),
|
|
3878
|
-
/* @__PURE__ */ (0,
|
|
3879
|
-
/* @__PURE__ */ (0,
|
|
4466
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_design_system12.Popover, { open, onOpenChange: setOpen, children: [
|
|
4467
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3880
4468
|
import_design_system12.Button,
|
|
3881
4469
|
{
|
|
3882
4470
|
variant: "outline",
|
|
3883
4471
|
size: "sm",
|
|
3884
4472
|
className: "h-7 gap-1 px-2 text-xs",
|
|
3885
4473
|
children: [
|
|
3886
|
-
/* @__PURE__ */ (0,
|
|
4474
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { className: "h-3.5 w-3.5" }),
|
|
3887
4475
|
selected.length === 0 ? addLabel : "Edit",
|
|
3888
|
-
/* @__PURE__ */ (0,
|
|
4476
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChevronsUpDownIcon, { className: "h-3 w-3 opacity-50" })
|
|
3889
4477
|
]
|
|
3890
4478
|
}
|
|
3891
4479
|
) }),
|
|
3892
|
-
/* @__PURE__ */ (0,
|
|
3893
|
-
/* @__PURE__ */ (0,
|
|
4480
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.PopoverContent, { className: "w-56 p-0", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_design_system12.Command, { shouldFilter: false, children: [
|
|
4481
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3894
4482
|
import_design_system12.CommandInput,
|
|
3895
4483
|
{
|
|
3896
4484
|
placeholder: allowCreate ? "Search or create..." : "Search...",
|
|
@@ -3898,9 +4486,9 @@ function CategoryTagPicker({
|
|
|
3898
4486
|
onValueChange: setSearch
|
|
3899
4487
|
}
|
|
3900
4488
|
),
|
|
3901
|
-
/* @__PURE__ */ (0,
|
|
3902
|
-
/* @__PURE__ */ (0,
|
|
3903
|
-
/* @__PURE__ */ (0,
|
|
4489
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_design_system12.CommandList, { children: [
|
|
4490
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.CommandEmpty, { className: "px-2 py-3 text-xs text-muted-foreground", children: search.trim() ? "No match." : emptyText }),
|
|
4491
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.CommandGroup, { children: showHierarchy ? filteredHierarchy.map(({ category, depth, parent }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3904
4492
|
import_design_system12.CommandItem,
|
|
3905
4493
|
{
|
|
3906
4494
|
value: category.id,
|
|
@@ -3908,7 +4496,7 @@ function CategoryTagPicker({
|
|
|
3908
4496
|
onSelect: () => void toggle(category.id),
|
|
3909
4497
|
className: (0, import_design_system12.cn)("text-xs", depth === 1 && "pl-6"),
|
|
3910
4498
|
children: [
|
|
3911
|
-
/* @__PURE__ */ (0,
|
|
4499
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3912
4500
|
CheckIcon,
|
|
3913
4501
|
{
|
|
3914
4502
|
className: (0, import_design_system12.cn)(
|
|
@@ -3917,19 +4505,19 @@ function CategoryTagPicker({
|
|
|
3917
4505
|
)
|
|
3918
4506
|
}
|
|
3919
4507
|
),
|
|
3920
|
-
depth === 1 ? /* @__PURE__ */ (0,
|
|
3921
|
-
/* @__PURE__ */ (0,
|
|
4508
|
+
depth === 1 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CornerDownRightIcon, { className: "mr-1.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }) : null,
|
|
4509
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: (0, import_design_system12.cn)(depth === 0 && "font-medium"), children: category.name })
|
|
3922
4510
|
]
|
|
3923
4511
|
},
|
|
3924
4512
|
category.id
|
|
3925
|
-
)) : filtered.map((c) => /* @__PURE__ */ (0,
|
|
4513
|
+
)) : filtered.map((c) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3926
4514
|
import_design_system12.CommandItem,
|
|
3927
4515
|
{
|
|
3928
4516
|
value: c.id,
|
|
3929
4517
|
onSelect: () => void toggle(c.id),
|
|
3930
4518
|
className: "text-xs",
|
|
3931
4519
|
children: [
|
|
3932
|
-
/* @__PURE__ */ (0,
|
|
4520
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3933
4521
|
CheckIcon,
|
|
3934
4522
|
{
|
|
3935
4523
|
className: (0, import_design_system12.cn)(
|
|
@@ -3943,25 +4531,25 @@ function CategoryTagPicker({
|
|
|
3943
4531
|
},
|
|
3944
4532
|
c.id
|
|
3945
4533
|
)) }),
|
|
3946
|
-
allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */ (0,
|
|
3947
|
-
showHierarchy ? /* @__PURE__ */ (0,
|
|
3948
|
-
/* @__PURE__ */ (0,
|
|
3949
|
-
/* @__PURE__ */ (0,
|
|
4534
|
+
allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_design_system12.CommandGroup, { children: [
|
|
4535
|
+
showHierarchy ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-1.5 px-2 pb-2", children: [
|
|
4536
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Place in" }),
|
|
4537
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3950
4538
|
import_design_system12.Select,
|
|
3951
4539
|
{
|
|
3952
4540
|
value: createParentId,
|
|
3953
4541
|
onValueChange: setCreateParentId,
|
|
3954
4542
|
children: [
|
|
3955
|
-
/* @__PURE__ */ (0,
|
|
3956
|
-
/* @__PURE__ */ (0,
|
|
3957
|
-
/* @__PURE__ */ (0,
|
|
3958
|
-
hierarchy.roots.map((root) => /* @__PURE__ */ (0,
|
|
4543
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.SelectTrigger, { size: "sm", className: "bg-background", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.SelectValue, {}) }),
|
|
4544
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_design_system12.SelectContent, { children: [
|
|
4545
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.SelectItem, { value: ROOT_PARENT2, children: "Top level" }),
|
|
4546
|
+
hierarchy.roots.map((root) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_design_system12.SelectItem, { value: root.id, children: root.name }, root.id))
|
|
3959
4547
|
] })
|
|
3960
4548
|
]
|
|
3961
4549
|
}
|
|
3962
4550
|
)
|
|
3963
4551
|
] }) : null,
|
|
3964
|
-
/* @__PURE__ */ (0,
|
|
4552
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3965
4553
|
import_design_system12.CommandItem,
|
|
3966
4554
|
{
|
|
3967
4555
|
value: `__create__${search}`,
|
|
@@ -3969,7 +4557,7 @@ function CategoryTagPicker({
|
|
|
3969
4557
|
disabled: creating,
|
|
3970
4558
|
className: "text-xs text-primary",
|
|
3971
4559
|
children: [
|
|
3972
|
-
creating ? /* @__PURE__ */ (0,
|
|
4560
|
+
creating ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SpinnerIcon, { className: "mr-2 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { className: "mr-2 h-3.5 w-3.5" }),
|
|
3973
4561
|
"Create \u201C",
|
|
3974
4562
|
search.trim(),
|
|
3975
4563
|
"\u201D"
|
|
@@ -3984,7 +4572,7 @@ function CategoryTagPicker({
|
|
|
3984
4572
|
}
|
|
3985
4573
|
|
|
3986
4574
|
// src/react/components/CommentThread.tsx
|
|
3987
|
-
var
|
|
4575
|
+
var import_react24 = require("react");
|
|
3988
4576
|
var import_design_system13 = require("@ai-matrx/design-system");
|
|
3989
4577
|
|
|
3990
4578
|
// src/react/relativeTime.ts
|
|
@@ -4012,7 +4600,7 @@ function formatRelativeTime(iso, now = Date.now()) {
|
|
|
4012
4600
|
}
|
|
4013
4601
|
|
|
4014
4602
|
// src/react/components/CommentThread.tsx
|
|
4015
|
-
var
|
|
4603
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
4016
4604
|
var AUTHOR_DOOR_TOKEN = "user";
|
|
4017
4605
|
function resolveAuthor(comment, authorDisplay) {
|
|
4018
4606
|
const base2 = {
|
|
@@ -4031,7 +4619,7 @@ function resolveAuthor(comment, authorDisplay) {
|
|
|
4031
4619
|
}
|
|
4032
4620
|
function AuthorAvatar({ author }) {
|
|
4033
4621
|
if (author.avatarUrl) {
|
|
4034
|
-
return /* @__PURE__ */ (0,
|
|
4622
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4035
4623
|
"img",
|
|
4036
4624
|
{
|
|
4037
4625
|
src: author.avatarUrl,
|
|
@@ -4040,7 +4628,7 @@ function AuthorAvatar({ author }) {
|
|
|
4040
4628
|
}
|
|
4041
4629
|
);
|
|
4042
4630
|
}
|
|
4043
|
-
return /* @__PURE__ */ (0,
|
|
4631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4044
4632
|
"span",
|
|
4045
4633
|
{
|
|
4046
4634
|
"aria-hidden": true,
|
|
@@ -4055,7 +4643,7 @@ function AuthorName({
|
|
|
4055
4643
|
}) {
|
|
4056
4644
|
const DoorRef2 = entityDoors?.EntityRef;
|
|
4057
4645
|
if (DoorRef2 && author.userId) {
|
|
4058
|
-
return /* @__PURE__ */ (0,
|
|
4646
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4059
4647
|
DoorRef2,
|
|
4060
4648
|
{
|
|
4061
4649
|
token: AUTHOR_DOOR_TOKEN,
|
|
@@ -4066,7 +4654,7 @@ function AuthorName({
|
|
|
4066
4654
|
}
|
|
4067
4655
|
);
|
|
4068
4656
|
}
|
|
4069
|
-
return /* @__PURE__ */ (0,
|
|
4657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-sm font-medium text-foreground", children: author.name });
|
|
4070
4658
|
}
|
|
4071
4659
|
function CommentComposer({
|
|
4072
4660
|
onSubmit,
|
|
@@ -4077,9 +4665,9 @@ function CommentComposer({
|
|
|
4077
4665
|
autoFocus = false
|
|
4078
4666
|
}) {
|
|
4079
4667
|
const notifier = useNotifier();
|
|
4080
|
-
const [body, setBody] = (0,
|
|
4081
|
-
const [submitting, setSubmitting] = (0,
|
|
4082
|
-
const [error, setError] = (0,
|
|
4668
|
+
const [body, setBody] = (0, import_react24.useState)(initialValue);
|
|
4669
|
+
const [submitting, setSubmitting] = (0, import_react24.useState)(false);
|
|
4670
|
+
const [error, setError] = (0, import_react24.useState)(null);
|
|
4083
4671
|
async function submit(e) {
|
|
4084
4672
|
e?.preventDefault();
|
|
4085
4673
|
const trimmed = body.trim();
|
|
@@ -4096,8 +4684,8 @@ function CommentComposer({
|
|
|
4096
4684
|
}
|
|
4097
4685
|
setBody("");
|
|
4098
4686
|
}
|
|
4099
|
-
return /* @__PURE__ */ (0,
|
|
4100
|
-
/* @__PURE__ */ (0,
|
|
4687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("form", { onSubmit: submit, className: "flex flex-col gap-1.5", children: [
|
|
4688
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4101
4689
|
"textarea",
|
|
4102
4690
|
{
|
|
4103
4691
|
value: body,
|
|
@@ -4112,10 +4700,10 @@ function CommentComposer({
|
|
|
4112
4700
|
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"
|
|
4113
4701
|
}
|
|
4114
4702
|
),
|
|
4115
|
-
error && /* @__PURE__ */ (0,
|
|
4116
|
-
/* @__PURE__ */ (0,
|
|
4117
|
-
/* @__PURE__ */ (0,
|
|
4118
|
-
submitting && /* @__PURE__ */ (0,
|
|
4703
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "alert", className: "text-xs text-destructive", children: error }),
|
|
4704
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
4705
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_design_system13.Button, { type: "submit", size: "sm", disabled: !body.trim() || submitting, children: [
|
|
4706
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
|
|
4119
4707
|
submitLabel
|
|
4120
4708
|
] }),
|
|
4121
4709
|
trailing
|
|
@@ -4131,10 +4719,10 @@ function CommentItem({
|
|
|
4131
4719
|
}) {
|
|
4132
4720
|
const { authorDisplay, entityDoors } = useAssociationsUiPorts();
|
|
4133
4721
|
const notifier = useNotifier();
|
|
4134
|
-
const [replying, setReplying] = (0,
|
|
4135
|
-
const [editing, setEditing] = (0,
|
|
4136
|
-
const [confirmingDelete, setConfirmingDelete] = (0,
|
|
4137
|
-
const [deleting, setDeleting] = (0,
|
|
4722
|
+
const [replying, setReplying] = (0, import_react24.useState)(false);
|
|
4723
|
+
const [editing, setEditing] = (0, import_react24.useState)(false);
|
|
4724
|
+
const [confirmingDelete, setConfirmingDelete] = (0, import_react24.useState)(false);
|
|
4725
|
+
const [deleting, setDeleting] = (0, import_react24.useState)(false);
|
|
4138
4726
|
const author = resolveAuthor(comment, authorDisplay);
|
|
4139
4727
|
const isOwn = thread.currentUserId !== null && comment.createdBy === thread.currentUserId;
|
|
4140
4728
|
const edited = comment.updatedAt !== comment.createdAt;
|
|
@@ -4148,7 +4736,7 @@ function CommentItem({
|
|
|
4148
4736
|
notifier.error(res.error ?? "Could not delete the comment");
|
|
4149
4737
|
}
|
|
4150
4738
|
}
|
|
4151
|
-
return /* @__PURE__ */ (0,
|
|
4739
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4152
4740
|
"div",
|
|
4153
4741
|
{
|
|
4154
4742
|
"data-comment-id": comment.id,
|
|
@@ -4157,10 +4745,10 @@ function CommentItem({
|
|
|
4157
4745
|
depth > 0 && "border-l border-border pl-3"
|
|
4158
4746
|
),
|
|
4159
4747
|
children: [
|
|
4160
|
-
/* @__PURE__ */ (0,
|
|
4161
|
-
/* @__PURE__ */ (0,
|
|
4162
|
-
/* @__PURE__ */ (0,
|
|
4163
|
-
/* @__PURE__ */ (0,
|
|
4748
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
4749
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AuthorAvatar, { author }),
|
|
4750
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AuthorName, { author, entityDoors }),
|
|
4751
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4164
4752
|
"span",
|
|
4165
4753
|
{
|
|
4166
4754
|
className: "text-xs text-muted-foreground",
|
|
@@ -4168,7 +4756,7 @@ function CommentItem({
|
|
|
4168
4756
|
children: formatRelativeTime(comment.createdAt)
|
|
4169
4757
|
}
|
|
4170
4758
|
),
|
|
4171
|
-
edited && /* @__PURE__ */ (0,
|
|
4759
|
+
edited && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4172
4760
|
"span",
|
|
4173
4761
|
{
|
|
4174
4762
|
className: "text-xs text-muted-foreground",
|
|
@@ -4177,7 +4765,7 @@ function CommentItem({
|
|
|
4177
4765
|
}
|
|
4178
4766
|
)
|
|
4179
4767
|
] }),
|
|
4180
|
-
editing ? /* @__PURE__ */ (0,
|
|
4768
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "pl-8", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4181
4769
|
CommentComposer,
|
|
4182
4770
|
{
|
|
4183
4771
|
initialValue: comment.body,
|
|
@@ -4189,7 +4777,7 @@ function CommentItem({
|
|
|
4189
4777
|
if (res.ok) setEditing(false);
|
|
4190
4778
|
return res;
|
|
4191
4779
|
},
|
|
4192
|
-
trailing: /* @__PURE__ */ (0,
|
|
4780
|
+
trailing: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4193
4781
|
import_design_system13.Button,
|
|
4194
4782
|
{
|
|
4195
4783
|
type: "button",
|
|
@@ -4200,10 +4788,10 @@ function CommentItem({
|
|
|
4200
4788
|
}
|
|
4201
4789
|
)
|
|
4202
4790
|
}
|
|
4203
|
-
) }) : /* @__PURE__ */ (0,
|
|
4204
|
-
!editing && /* @__PURE__ */ (0,
|
|
4205
|
-
/* @__PURE__ */ (0,
|
|
4206
|
-
/* @__PURE__ */ (0,
|
|
4791
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "whitespace-pre-wrap pl-8 text-sm text-foreground", children: comment.body }),
|
|
4792
|
+
!editing && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex items-center gap-1 pl-7", children: confirmingDelete ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
4793
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-xs text-destructive", children: "Deletes this comment for everyone." }),
|
|
4794
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4207
4795
|
import_design_system13.Button,
|
|
4208
4796
|
{
|
|
4209
4797
|
type: "button",
|
|
@@ -4212,12 +4800,12 @@ function CommentItem({
|
|
|
4212
4800
|
disabled: deleting,
|
|
4213
4801
|
onClick: () => void confirmDelete(),
|
|
4214
4802
|
children: [
|
|
4215
|
-
deleting && /* @__PURE__ */ (0,
|
|
4803
|
+
deleting && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
|
|
4216
4804
|
"Delete"
|
|
4217
4805
|
]
|
|
4218
4806
|
}
|
|
4219
4807
|
),
|
|
4220
|
-
/* @__PURE__ */ (0,
|
|
4808
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4221
4809
|
import_design_system13.Button,
|
|
4222
4810
|
{
|
|
4223
4811
|
type: "button",
|
|
@@ -4228,8 +4816,8 @@ function CommentItem({
|
|
|
4228
4816
|
children: "Cancel"
|
|
4229
4817
|
}
|
|
4230
4818
|
)
|
|
4231
|
-
] }) : /* @__PURE__ */ (0,
|
|
4232
|
-
/* @__PURE__ */ (0,
|
|
4819
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
4820
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4233
4821
|
"button",
|
|
4234
4822
|
{
|
|
4235
4823
|
type: "button",
|
|
@@ -4238,8 +4826,8 @@ function CommentItem({
|
|
|
4238
4826
|
children: "Reply"
|
|
4239
4827
|
}
|
|
4240
4828
|
),
|
|
4241
|
-
isOwn && /* @__PURE__ */ (0,
|
|
4242
|
-
/* @__PURE__ */ (0,
|
|
4829
|
+
isOwn && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
4830
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4243
4831
|
"button",
|
|
4244
4832
|
{
|
|
4245
4833
|
type: "button",
|
|
@@ -4248,7 +4836,7 @@ function CommentItem({
|
|
|
4248
4836
|
children: "Edit"
|
|
4249
4837
|
}
|
|
4250
4838
|
),
|
|
4251
|
-
/* @__PURE__ */ (0,
|
|
4839
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4252
4840
|
"button",
|
|
4253
4841
|
{
|
|
4254
4842
|
type: "button",
|
|
@@ -4259,9 +4847,9 @@ function CommentItem({
|
|
|
4259
4847
|
)
|
|
4260
4848
|
] })
|
|
4261
4849
|
] }) }),
|
|
4262
|
-
replying && /* @__PURE__ */ (0,
|
|
4263
|
-
/* @__PURE__ */ (0,
|
|
4264
|
-
/* @__PURE__ */ (0,
|
|
4850
|
+
replying && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-start gap-2 pl-8 pt-1", children: [
|
|
4851
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CornerDownRightIcon, { className: "mt-2 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
4852
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4265
4853
|
CommentComposer,
|
|
4266
4854
|
{
|
|
4267
4855
|
submitLabel: "Reply",
|
|
@@ -4275,7 +4863,7 @@ function CommentItem({
|
|
|
4275
4863
|
if (res.ok) setReplying(false);
|
|
4276
4864
|
return res;
|
|
4277
4865
|
},
|
|
4278
|
-
trailing: /* @__PURE__ */ (0,
|
|
4866
|
+
trailing: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4279
4867
|
import_design_system13.Button,
|
|
4280
4868
|
{
|
|
4281
4869
|
type: "button",
|
|
@@ -4288,7 +4876,7 @@ function CommentItem({
|
|
|
4288
4876
|
}
|
|
4289
4877
|
) })
|
|
4290
4878
|
] }),
|
|
4291
|
-
replies.length > 0 && /* @__PURE__ */ (0,
|
|
4879
|
+
replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex flex-col gap-3 pl-8 pt-1", children: replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4292
4880
|
CommentItem,
|
|
4293
4881
|
{
|
|
4294
4882
|
comment: reply,
|
|
@@ -4328,11 +4916,11 @@ function CommentThread({
|
|
|
4328
4916
|
const thread = useComments({ token, id });
|
|
4329
4917
|
const { roots, childrenOf } = buildCommentTree(thread.comments);
|
|
4330
4918
|
const loading = (thread.status === "loading" || thread.status === "idle") && thread.comments.length === 0;
|
|
4331
|
-
return /* @__PURE__ */ (0,
|
|
4332
|
-
showHeader && /* @__PURE__ */ (0,
|
|
4333
|
-
/* @__PURE__ */ (0,
|
|
4334
|
-
/* @__PURE__ */ (0,
|
|
4335
|
-
/* @__PURE__ */ (0,
|
|
4919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: (0, import_design_system13.cn)("flex flex-col gap-3", className), children: [
|
|
4920
|
+
showHeader && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
4921
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "text-sm font-semibold text-foreground", children: "Comments" }),
|
|
4922
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-xs text-muted-foreground tabular-nums", children: thread.comments.length }),
|
|
4923
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4336
4924
|
"button",
|
|
4337
4925
|
{
|
|
4338
4926
|
type: "button",
|
|
@@ -4340,18 +4928,18 @@ function CommentThread({
|
|
|
4340
4928
|
"aria-label": "Refresh comments",
|
|
4341
4929
|
title: "Refresh comments",
|
|
4342
4930
|
className: "ml-auto flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
4343
|
-
children: thread.status === "loading" ? /* @__PURE__ */ (0,
|
|
4931
|
+
children: thread.status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(RefreshIcon, { className: "h-3.5 w-3.5" })
|
|
4344
4932
|
}
|
|
4345
4933
|
)
|
|
4346
4934
|
] }),
|
|
4347
|
-
thread.error && /* @__PURE__ */ (0,
|
|
4935
|
+
thread.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
4348
4936
|
"div",
|
|
4349
4937
|
{
|
|
4350
4938
|
role: "alert",
|
|
4351
4939
|
className: "flex items-center gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
4352
4940
|
children: [
|
|
4353
|
-
/* @__PURE__ */ (0,
|
|
4354
|
-
/* @__PURE__ */ (0,
|
|
4941
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "min-w-0 flex-1", children: thread.error }),
|
|
4942
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4355
4943
|
import_design_system13.Button,
|
|
4356
4944
|
{
|
|
4357
4945
|
type: "button",
|
|
@@ -4365,10 +4953,10 @@ function CommentThread({
|
|
|
4365
4953
|
]
|
|
4366
4954
|
}
|
|
4367
4955
|
),
|
|
4368
|
-
loading ? /* @__PURE__ */ (0,
|
|
4369
|
-
/* @__PURE__ */ (0,
|
|
4370
|
-
/* @__PURE__ */ (0,
|
|
4371
|
-
] }) : roots.length === 0 && !thread.error ? /* @__PURE__ */ (0,
|
|
4956
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col gap-3", "aria-hidden": true, "data-testid": "comments-loading", children: [
|
|
4957
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system13.Skeleton, { className: "h-12 w-full" }),
|
|
4958
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_design_system13.Skeleton, { className: "h-12 w-4/5" })
|
|
4959
|
+
] }) : roots.length === 0 && !thread.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-muted-foreground", children: "No comments yet." }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex flex-col gap-4", children: roots.map((comment) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4372
4960
|
CommentItem,
|
|
4373
4961
|
{
|
|
4374
4962
|
comment,
|
|
@@ -4379,7 +4967,7 @@ function CommentThread({
|
|
|
4379
4967
|
},
|
|
4380
4968
|
comment.id
|
|
4381
4969
|
)) }),
|
|
4382
|
-
/* @__PURE__ */ (0,
|
|
4970
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4383
4971
|
CommentComposer,
|
|
4384
4972
|
{
|
|
4385
4973
|
onSubmit: (body) => thread.add(body, { orgId: orgId ?? null })
|