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