@mulmoclaude/collection-plugin 0.8.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +12 -0
- package/dist/vue/components/CollectionMutateParamsModal.vue.d.ts +19 -0
- package/dist/vue/components/CollectionMutateParamsModal.vue.d.ts.map +1 -0
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts +73 -8
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts.map +1 -1
- package/dist/vue/components/CollectionView.vue.d.ts.map +1 -1
- package/dist/vue/uiContext.d.ts +26 -5
- package/dist/vue/uiContext.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.d.ts +10 -0
- package/dist/vue/useCollectionRendering.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.helpers.d.ts +4 -3
- package/dist/vue/useCollectionRendering.helpers.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.renderers.d.ts +17 -1
- package/dist/vue/useCollectionRendering.renderers.d.ts.map +1 -1
- package/dist/vue.cjs +815 -457
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +817 -459
- package/dist/vue.js.map +1 -1
- package/package.json +3 -3
package/dist/vue.cjs
CHANGED
|
@@ -1233,6 +1233,338 @@ var CollectionRecordModal_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1233
1233
|
}
|
|
1234
1234
|
});
|
|
1235
1235
|
//#endregion
|
|
1236
|
+
//#region src/vue/useCollectionRendering.helpers.ts
|
|
1237
|
+
var EM_DASH = "—";
|
|
1238
|
+
var DEFAULT_CURRENCY = "USD";
|
|
1239
|
+
var MARKDOWN_CELL_PREVIEW_MAX = 80;
|
|
1240
|
+
function stepForFieldType(type) {
|
|
1241
|
+
if (type === "money") return "0.01";
|
|
1242
|
+
if (type === "number") return "any";
|
|
1243
|
+
}
|
|
1244
|
+
function inputTypeFor(type) {
|
|
1245
|
+
if (type === "email") return "email";
|
|
1246
|
+
if (type === "number") return "number";
|
|
1247
|
+
if (type === "money") return "number";
|
|
1248
|
+
if (type === "date") return "date";
|
|
1249
|
+
if (type === "datetime") return "datetime-local";
|
|
1250
|
+
return "text";
|
|
1251
|
+
}
|
|
1252
|
+
function isExternalUrl(value) {
|
|
1253
|
+
return typeof value === "string" && /^https?:\/\//i.test(value);
|
|
1254
|
+
}
|
|
1255
|
+
function detailText(value) {
|
|
1256
|
+
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
1257
|
+
return String(value);
|
|
1258
|
+
}
|
|
1259
|
+
function formatCell(value, type) {
|
|
1260
|
+
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
1261
|
+
if (type === "markdown" && typeof value === "string") return value.length > MARKDOWN_CELL_PREVIEW_MAX ? `${value.slice(0, MARKDOWN_CELL_PREVIEW_MAX)}…` : value;
|
|
1262
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
1263
|
+
return JSON.stringify(value);
|
|
1264
|
+
}
|
|
1265
|
+
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
1266
|
+
* `currencyField` (when present and non-blank) wins over the field's
|
|
1267
|
+
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
1268
|
+
* keys; any other field resolves to undefined (the formatter's USD
|
|
1269
|
+
* fallback), as before. */
|
|
1270
|
+
function resolveCurrency(field, record) {
|
|
1271
|
+
if (field.type !== "money" && field.type !== "derived") return void 0;
|
|
1272
|
+
if (field.currencyField && record) {
|
|
1273
|
+
const code = record[field.currencyField];
|
|
1274
|
+
if (typeof code === "string" && code.trim().length > 0) return code;
|
|
1275
|
+
}
|
|
1276
|
+
return field.currency;
|
|
1277
|
+
}
|
|
1278
|
+
function formatMoney(value, currency, displayLocale) {
|
|
1279
|
+
if (value === void 0 || value === "") return EM_DASH;
|
|
1280
|
+
const amount = typeof value === "number" ? value : Number(value);
|
|
1281
|
+
if (!Number.isFinite(amount)) return String(value);
|
|
1282
|
+
const currencyCode = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
1283
|
+
try {
|
|
1284
|
+
return new Intl.NumberFormat(displayLocale, {
|
|
1285
|
+
style: "currency",
|
|
1286
|
+
currency: currencyCode
|
|
1287
|
+
}).format(amount);
|
|
1288
|
+
} catch {
|
|
1289
|
+
return String(amount);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
function currencySymbolForLocale(currency, locale) {
|
|
1293
|
+
const code = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
1294
|
+
try {
|
|
1295
|
+
return new Intl.NumberFormat(locale, {
|
|
1296
|
+
style: "currency",
|
|
1297
|
+
currency: code
|
|
1298
|
+
}).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
|
|
1299
|
+
} catch {
|
|
1300
|
+
return code;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function tableRows(value) {
|
|
1304
|
+
if (!Array.isArray(value)) return [];
|
|
1305
|
+
return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
|
|
1306
|
+
}
|
|
1307
|
+
function hasTableRows(value) {
|
|
1308
|
+
return tableRows(value).length > 0;
|
|
1309
|
+
}
|
|
1310
|
+
/** Pick the field used to label a referenced/embedded record: prefer a
|
|
1311
|
+
* `name` field, then `title`, else fall back to the primary key. */
|
|
1312
|
+
function displayFieldFor(fields, primaryKey) {
|
|
1313
|
+
if ("name" in fields) return "name";
|
|
1314
|
+
if ("title" in fields) return "title";
|
|
1315
|
+
return primaryKey;
|
|
1316
|
+
}
|
|
1317
|
+
function uniqueRefTargets(schema) {
|
|
1318
|
+
const targets = /* @__PURE__ */ new Set();
|
|
1319
|
+
const walk = (fields) => {
|
|
1320
|
+
for (const field of Object.values(fields)) {
|
|
1321
|
+
if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
1322
|
+
if (field.type === "table" && field.of) walk(field.of);
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
walk(schema.fields);
|
|
1326
|
+
return [...targets];
|
|
1327
|
+
}
|
|
1328
|
+
function uniqueEmbedTargets(schema) {
|
|
1329
|
+
const targets = /* @__PURE__ */ new Set();
|
|
1330
|
+
for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
1331
|
+
return [...targets];
|
|
1332
|
+
}
|
|
1333
|
+
/** Slugs of every SOURCE collection a `backlinks` or `rollup` field
|
|
1334
|
+
* reverses over (the two share one load). Top-level only, like `embed`
|
|
1335
|
+
* (the schema rejects both inside a table's `of`). Mirrors the server's
|
|
1336
|
+
* `uniqueBacklinkSources`. */
|
|
1337
|
+
function uniqueBacklinkSources(schema) {
|
|
1338
|
+
const sources = /* @__PURE__ */ new Set();
|
|
1339
|
+
for (const field of Object.values(schema.fields)) if ((field.type === "backlinks" || field.type === "rollup") && field.from.length > 0) sources.add(field.from);
|
|
1340
|
+
return [...sources];
|
|
1341
|
+
}
|
|
1342
|
+
function buildRefDisplayMap(detail) {
|
|
1343
|
+
const { fields, primaryKey } = detail.collection.schema;
|
|
1344
|
+
const displayField = displayFieldFor(fields, primaryKey);
|
|
1345
|
+
const map = {};
|
|
1346
|
+
for (const item of detail.items) {
|
|
1347
|
+
const slugRaw = item[primaryKey];
|
|
1348
|
+
if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
|
|
1349
|
+
const displayRaw = item[displayField];
|
|
1350
|
+
map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
|
|
1351
|
+
}
|
|
1352
|
+
return map;
|
|
1353
|
+
}
|
|
1354
|
+
/** Index DERIVED records by primary key — the client mirror of the
|
|
1355
|
+
* server's `loadTarget` indexing: string non-empty ids only, one record
|
|
1356
|
+
* per id (a duplicate keeps the LAST record in its FIRST position —
|
|
1357
|
+
* plain-object key semantics). Shared by the ref-record cache and the
|
|
1358
|
+
* backlinks view so every client consumer agrees with server enrichment
|
|
1359
|
+
* on which source records exist. */
|
|
1360
|
+
function derivedRecordsById(schema, items) {
|
|
1361
|
+
const map = {};
|
|
1362
|
+
for (const item of items) {
|
|
1363
|
+
const slugRaw = item[schema.primaryKey];
|
|
1364
|
+
if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = (0, _mulmoclaude_core_collection.deriveAll)(schema, item, {});
|
|
1365
|
+
}
|
|
1366
|
+
return map;
|
|
1367
|
+
}
|
|
1368
|
+
function buildRefRecordMap(detail) {
|
|
1369
|
+
return derivedRecordsById(detail.collection.schema, detail.items);
|
|
1370
|
+
}
|
|
1371
|
+
function sortedRefOptions(map) {
|
|
1372
|
+
return Object.entries(map).map(([slug, display]) => ({
|
|
1373
|
+
slug,
|
|
1374
|
+
display
|
|
1375
|
+
})).sort((left, right) => left.display.localeCompare(right.display));
|
|
1376
|
+
}
|
|
1377
|
+
/** Dropdown options for an `embed` field's per-record picker: every
|
|
1378
|
+
* record in the target collection, labelled by its name/title (or
|
|
1379
|
+
* primary key), skipping records without a slug and sorted by label. */
|
|
1380
|
+
function buildEmbedOptions(schema, items) {
|
|
1381
|
+
const { fields, primaryKey } = schema;
|
|
1382
|
+
const displayField = displayFieldFor(fields, primaryKey);
|
|
1383
|
+
return items.map((item) => {
|
|
1384
|
+
const slug = String(item[primaryKey] ?? "");
|
|
1385
|
+
const labelRaw = item[displayField];
|
|
1386
|
+
return {
|
|
1387
|
+
slug,
|
|
1388
|
+
display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
|
|
1389
|
+
};
|
|
1390
|
+
}).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
|
|
1391
|
+
}
|
|
1392
|
+
//#endregion
|
|
1393
|
+
//#region src/vue/components/CollectionMutateParamsModal.vue?vue&type=script&setup=true&lang.ts
|
|
1394
|
+
var _hoisted_1$16 = { class: "flex items-center justify-between px-6 pt-5 pb-3" };
|
|
1395
|
+
var _hoisted_2$15 = { class: "text-sm font-bold text-slate-800 flex items-center gap-1.5" };
|
|
1396
|
+
var _hoisted_3$15 = {
|
|
1397
|
+
key: 0,
|
|
1398
|
+
class: "material-icons text-base text-indigo-600"
|
|
1399
|
+
};
|
|
1400
|
+
var _hoisted_4$15 = ["aria-label"];
|
|
1401
|
+
var _hoisted_5$14 = { class: "flex flex-col gap-4 px-6 pb-2" };
|
|
1402
|
+
var _hoisted_6$13 = ["for"];
|
|
1403
|
+
var _hoisted_7$11 = {
|
|
1404
|
+
key: 0,
|
|
1405
|
+
class: "text-rose-500 font-bold"
|
|
1406
|
+
};
|
|
1407
|
+
var _hoisted_8$11 = {
|
|
1408
|
+
key: 0,
|
|
1409
|
+
class: "inline-flex items-center gap-2.5 cursor-pointer select-none"
|
|
1410
|
+
};
|
|
1411
|
+
var _hoisted_9$11 = [
|
|
1412
|
+
"id",
|
|
1413
|
+
"onUpdate:modelValue",
|
|
1414
|
+
"data-testid",
|
|
1415
|
+
"onChange"
|
|
1416
|
+
];
|
|
1417
|
+
var _hoisted_10$11 = [
|
|
1418
|
+
"id",
|
|
1419
|
+
"onUpdate:modelValue",
|
|
1420
|
+
"required",
|
|
1421
|
+
"data-testid"
|
|
1422
|
+
];
|
|
1423
|
+
var _hoisted_11$11 = { value: "" };
|
|
1424
|
+
var _hoisted_12$10 = ["value"];
|
|
1425
|
+
var _hoisted_13$9 = [
|
|
1426
|
+
"id",
|
|
1427
|
+
"onUpdate:modelValue",
|
|
1428
|
+
"required",
|
|
1429
|
+
"data-testid"
|
|
1430
|
+
];
|
|
1431
|
+
var _hoisted_14$8 = [
|
|
1432
|
+
"id",
|
|
1433
|
+
"onUpdate:modelValue",
|
|
1434
|
+
"type",
|
|
1435
|
+
"step",
|
|
1436
|
+
"required",
|
|
1437
|
+
"data-testid"
|
|
1438
|
+
];
|
|
1439
|
+
var _hoisted_15$8 = {
|
|
1440
|
+
key: 0,
|
|
1441
|
+
class: "text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl",
|
|
1442
|
+
"data-testid": "collections-mutate-error"
|
|
1443
|
+
};
|
|
1444
|
+
var _hoisted_16$7 = { class: "flex items-center justify-end gap-2 px-6 py-4" };
|
|
1445
|
+
var _hoisted_17$7 = ["disabled"];
|
|
1446
|
+
var _hoisted_18$6 = {
|
|
1447
|
+
key: 0,
|
|
1448
|
+
class: "material-icons text-sm animate-spin"
|
|
1449
|
+
};
|
|
1450
|
+
//#endregion
|
|
1451
|
+
//#region src/vue/components/CollectionMutateParamsModal.vue
|
|
1452
|
+
var CollectionMutateParamsModal_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1453
|
+
__name: "CollectionMutateParamsModal",
|
|
1454
|
+
props: {
|
|
1455
|
+
action: {},
|
|
1456
|
+
pending: { type: Boolean },
|
|
1457
|
+
error: {}
|
|
1458
|
+
},
|
|
1459
|
+
emits: ["close", "submit"],
|
|
1460
|
+
setup(__props, { emit: __emit }) {
|
|
1461
|
+
const props = __props;
|
|
1462
|
+
const emit = __emit;
|
|
1463
|
+
const { t } = useCollectionI18n();
|
|
1464
|
+
const text = (0, vue.reactive)({});
|
|
1465
|
+
const bool = (0, vue.reactive)({});
|
|
1466
|
+
const boolTouched = (0, vue.reactive)({});
|
|
1467
|
+
for (const [key, spec] of Object.entries(props.action.params ?? {})) if (spec.type === "boolean") bool[key] = false;
|
|
1468
|
+
else text[key] = "";
|
|
1469
|
+
/** Convert the draft to the submitted params: numbers parsed, booleans
|
|
1470
|
+
* included only when touched or required, empty optionals OMITTED (the
|
|
1471
|
+
* server treats an absent param as "don't write" for `$params` refs —
|
|
1472
|
+
* merge semantics). */
|
|
1473
|
+
function submit() {
|
|
1474
|
+
const params = {};
|
|
1475
|
+
for (const [key, spec] of Object.entries(props.action.params ?? {})) {
|
|
1476
|
+
if (spec.type === "boolean") {
|
|
1477
|
+
if (boolTouched[key] || spec.required) params[key] = bool[key] === true;
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
const raw = (text[key] ?? "").trim();
|
|
1481
|
+
if (raw === "") continue;
|
|
1482
|
+
if (spec.type === "number" || spec.type === "money") {
|
|
1483
|
+
const num = Number(raw);
|
|
1484
|
+
params[key] = Number.isFinite(num) ? num : raw;
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
params[key] = raw;
|
|
1488
|
+
}
|
|
1489
|
+
emit("submit", params);
|
|
1490
|
+
}
|
|
1491
|
+
return (_ctx, _cache) => {
|
|
1492
|
+
return (0, vue.openBlock)(), (0, vue.createBlock)(CollectionRecordModal_default, { onClose: _cache[2] || (_cache[2] = ($event) => emit("close")) }, {
|
|
1493
|
+
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("form", {
|
|
1494
|
+
class: "flex flex-col overflow-y-auto",
|
|
1495
|
+
"data-testid": "collections-mutate-modal",
|
|
1496
|
+
onSubmit: (0, vue.withModifiers)(submit, ["prevent"])
|
|
1497
|
+
}, [
|
|
1498
|
+
(0, vue.createElementVNode)("div", _hoisted_1$16, [(0, vue.createElementVNode)("h2", _hoisted_2$15, [__props.action.icon ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_3$15, (0, vue.toDisplayString)(__props.action.icon), 1)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(__props.action.label), 1)]), (0, vue.createElementVNode)("button", {
|
|
1499
|
+
type: "button",
|
|
1500
|
+
class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors",
|
|
1501
|
+
"aria-label": (0, vue.unref)(t)("common.close"),
|
|
1502
|
+
"data-testid": "collections-mutate-close",
|
|
1503
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
|
|
1504
|
+
}, [..._cache[3] || (_cache[3] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_4$15)]),
|
|
1505
|
+
(0, vue.createElementVNode)("div", _hoisted_5$14, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.action.params, (spec, key) => {
|
|
1506
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
1507
|
+
key,
|
|
1508
|
+
class: "flex flex-col gap-1.5"
|
|
1509
|
+
}, [(0, vue.createElementVNode)("label", {
|
|
1510
|
+
class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider",
|
|
1511
|
+
for: `collections-mutate-${key}`
|
|
1512
|
+
}, [(0, vue.createTextVNode)((0, vue.toDisplayString)(spec.label) + " ", 1), spec.required ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_7$11, "*")) : (0, vue.createCommentVNode)("", true)], 8, _hoisted_6$13), spec.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("label", _hoisted_8$11, [(0, vue.withDirectives)((0, vue.createElementVNode)("input", {
|
|
1513
|
+
id: `collections-mutate-${key}`,
|
|
1514
|
+
"onUpdate:modelValue": ($event) => bool[key] = $event,
|
|
1515
|
+
type: "checkbox",
|
|
1516
|
+
class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
1517
|
+
"data-testid": `collections-mutate-input-${key}`,
|
|
1518
|
+
onChange: ($event) => boolTouched[String(key)] = true
|
|
1519
|
+
}, null, 40, _hoisted_9$11), [[vue.vModelCheckbox, bool[key]]]), (0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["text-xs font-semibold", bool[key] ? "text-indigo-600" : "text-slate-500"]) }, (0, vue.toDisplayString)(bool[key] ? (0, vue.unref)(t)("common.yes") : (0, vue.unref)(t)("common.no")), 3)])) : spec.type === "enum" ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
1520
|
+
key: 1,
|
|
1521
|
+
id: `collections-mutate-${key}`,
|
|
1522
|
+
"onUpdate:modelValue": ($event) => text[key] = $event,
|
|
1523
|
+
required: spec.required,
|
|
1524
|
+
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs bg-slate-50 focus:bg-white focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none transition-all cursor-pointer font-medium text-slate-700",
|
|
1525
|
+
"data-testid": `collections-mutate-input-${key}`
|
|
1526
|
+
}, [(0, vue.createElementVNode)("option", _hoisted_11$11, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(spec.values, (value) => {
|
|
1527
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
1528
|
+
key: value,
|
|
1529
|
+
value
|
|
1530
|
+
}, (0, vue.toDisplayString)(value), 9, _hoisted_12$10);
|
|
1531
|
+
}), 128))], 8, _hoisted_10$11)), [[vue.vModelSelect, text[key]]]) : spec.type === "text" || spec.type === "markdown" ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("textarea", {
|
|
1532
|
+
key: 2,
|
|
1533
|
+
id: `collections-mutate-${key}`,
|
|
1534
|
+
"onUpdate:modelValue": ($event) => text[key] = $event,
|
|
1535
|
+
required: spec.required,
|
|
1536
|
+
rows: "3",
|
|
1537
|
+
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none font-medium text-slate-700 transition-all",
|
|
1538
|
+
"data-testid": `collections-mutate-input-${key}`
|
|
1539
|
+
}, null, 8, _hoisted_13$9)), [[vue.vModelText, text[key]]]) : (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
|
|
1540
|
+
key: 3,
|
|
1541
|
+
id: `collections-mutate-${key}`,
|
|
1542
|
+
"onUpdate:modelValue": ($event) => text[key] = $event,
|
|
1543
|
+
type: (0, vue.unref)(inputTypeFor)(spec.type),
|
|
1544
|
+
step: (0, vue.unref)(stepForFieldType)(spec.type),
|
|
1545
|
+
required: spec.required,
|
|
1546
|
+
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none font-medium text-slate-700 transition-all",
|
|
1547
|
+
"data-testid": `collections-mutate-input-${key}`
|
|
1548
|
+
}, null, 8, _hoisted_14$8)), [[vue.vModelDynamic, text[key]]])]);
|
|
1549
|
+
}), 128)), __props.error ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_15$8, (0, vue.toDisplayString)(__props.error), 1)) : (0, vue.createCommentVNode)("", true)]),
|
|
1550
|
+
(0, vue.createElementVNode)("div", _hoisted_16$7, [(0, vue.createElementVNode)("button", {
|
|
1551
|
+
type: "button",
|
|
1552
|
+
class: "h-8 px-3 rounded border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 font-bold text-xs transition-colors",
|
|
1553
|
+
"data-testid": "collections-mutate-cancel",
|
|
1554
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
|
|
1555
|
+
}, (0, vue.toDisplayString)((0, vue.unref)(t)("common.cancel")), 1), (0, vue.createElementVNode)("button", {
|
|
1556
|
+
type: "submit",
|
|
1557
|
+
class: "h-8 px-3 rounded bg-indigo-600 hover:bg-indigo-700 text-white font-bold text-xs transition-colors shadow-sm disabled:opacity-50 flex items-center gap-1",
|
|
1558
|
+
disabled: __props.pending,
|
|
1559
|
+
"data-testid": "collections-mutate-submit"
|
|
1560
|
+
}, [__props.pending ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_18$6, "progress_activity")) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(__props.action.label), 1)], 8, _hoisted_17$7)])
|
|
1561
|
+
], 32)]),
|
|
1562
|
+
_: 1
|
|
1563
|
+
});
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
//#endregion
|
|
1236
1568
|
//#region src/vue/components/CollectionCalendarView.vue?vue&type=script&setup=true&lang.ts
|
|
1237
1569
|
var _hoisted_1$15 = {
|
|
1238
1570
|
class: "flex flex-col gap-3",
|
|
@@ -1538,6 +1870,7 @@ var CollectionDayView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1538
1870
|
"table",
|
|
1539
1871
|
"embed",
|
|
1540
1872
|
"backlinks",
|
|
1873
|
+
"rollup",
|
|
1541
1874
|
"image",
|
|
1542
1875
|
"markdown"
|
|
1543
1876
|
]);
|
|
@@ -2058,111 +2391,115 @@ var _hoisted_7$6 = [
|
|
|
2058
2391
|
];
|
|
2059
2392
|
var _hoisted_8$6 = {
|
|
2060
2393
|
key: 0,
|
|
2394
|
+
class: "material-icons text-sm animate-spin"
|
|
2395
|
+
};
|
|
2396
|
+
var _hoisted_9$6 = {
|
|
2397
|
+
key: 1,
|
|
2061
2398
|
class: "material-icons text-sm"
|
|
2062
2399
|
};
|
|
2063
|
-
var
|
|
2064
|
-
var
|
|
2400
|
+
var _hoisted_10$6 = ["aria-label"];
|
|
2401
|
+
var _hoisted_11$6 = {
|
|
2065
2402
|
key: 0,
|
|
2066
2403
|
class: "mb-3 text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl shadow-sm",
|
|
2067
2404
|
"data-testid": "collections-detail-action-error"
|
|
2068
2405
|
};
|
|
2069
|
-
var
|
|
2070
|
-
var
|
|
2071
|
-
var
|
|
2406
|
+
var _hoisted_12$6 = { class: "grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4 bg-white rounded-2xl border border-slate-200/60 p-6 shadow-sm" };
|
|
2407
|
+
var _hoisted_13$5 = ["for"];
|
|
2408
|
+
var _hoisted_14$5 = {
|
|
2072
2409
|
key: 0,
|
|
2073
2410
|
class: "text-rose-500 font-bold"
|
|
2074
2411
|
};
|
|
2075
|
-
var
|
|
2412
|
+
var _hoisted_15$5 = [
|
|
2076
2413
|
"id",
|
|
2077
2414
|
"onUpdate:modelValue",
|
|
2078
2415
|
"required",
|
|
2079
2416
|
"data-testid"
|
|
2080
2417
|
];
|
|
2081
|
-
var
|
|
2082
|
-
var
|
|
2083
|
-
var
|
|
2418
|
+
var _hoisted_16$5 = { value: "" };
|
|
2419
|
+
var _hoisted_17$5 = ["value"];
|
|
2420
|
+
var _hoisted_18$5 = [
|
|
2084
2421
|
"id",
|
|
2085
2422
|
"onUpdate:modelValue",
|
|
2086
2423
|
"required",
|
|
2087
2424
|
"placeholder",
|
|
2088
2425
|
"data-testid"
|
|
2089
2426
|
];
|
|
2090
|
-
var
|
|
2427
|
+
var _hoisted_19$3 = {
|
|
2091
2428
|
key: 0,
|
|
2092
2429
|
class: "inline-flex items-center gap-2.5 text-sm text-slate-700 cursor-pointer select-none"
|
|
2093
2430
|
};
|
|
2094
|
-
var
|
|
2431
|
+
var _hoisted_20$3 = [
|
|
2095
2432
|
"id",
|
|
2096
2433
|
"onUpdate:modelValue",
|
|
2097
2434
|
"data-testid",
|
|
2098
2435
|
"onChange"
|
|
2099
2436
|
];
|
|
2100
|
-
var
|
|
2437
|
+
var _hoisted_21$3 = [
|
|
2101
2438
|
"id",
|
|
2102
2439
|
"onUpdate:modelValue",
|
|
2103
2440
|
"required",
|
|
2104
2441
|
"data-testid"
|
|
2105
2442
|
];
|
|
2106
|
-
var
|
|
2107
|
-
var
|
|
2108
|
-
var
|
|
2443
|
+
var _hoisted_22$3 = { value: "" };
|
|
2444
|
+
var _hoisted_23$3 = ["value"];
|
|
2445
|
+
var _hoisted_24$2 = [
|
|
2109
2446
|
"id",
|
|
2110
2447
|
"onUpdate:modelValue",
|
|
2111
2448
|
"required",
|
|
2112
2449
|
"data-testid"
|
|
2113
2450
|
];
|
|
2114
|
-
var
|
|
2115
|
-
var
|
|
2116
|
-
var
|
|
2117
|
-
var
|
|
2451
|
+
var _hoisted_25$2 = { value: "" };
|
|
2452
|
+
var _hoisted_26$2 = ["value"];
|
|
2453
|
+
var _hoisted_27$2 = ["data-testid"];
|
|
2454
|
+
var _hoisted_28$1 = {
|
|
2118
2455
|
key: 0,
|
|
2119
2456
|
class: "overflow-hidden border border-slate-200 rounded-lg shadow-sm"
|
|
2120
2457
|
};
|
|
2121
|
-
var
|
|
2122
|
-
var
|
|
2123
|
-
var
|
|
2124
|
-
var
|
|
2125
|
-
var
|
|
2126
|
-
var
|
|
2127
|
-
var
|
|
2128
|
-
var
|
|
2129
|
-
var
|
|
2130
|
-
var
|
|
2131
|
-
var
|
|
2458
|
+
var _hoisted_29$1 = { class: "w-full text-xs text-slate-600 bg-white" };
|
|
2459
|
+
var _hoisted_30$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
|
|
2460
|
+
var _hoisted_31$1 = { class: "divide-y divide-slate-100" };
|
|
2461
|
+
var _hoisted_32$1 = ["onUpdate:modelValue", "onChange"];
|
|
2462
|
+
var _hoisted_33$1 = ["onUpdate:modelValue", "required"];
|
|
2463
|
+
var _hoisted_34$1 = { value: "" };
|
|
2464
|
+
var _hoisted_35$1 = ["value"];
|
|
2465
|
+
var _hoisted_36$1 = ["onUpdate:modelValue", "required"];
|
|
2466
|
+
var _hoisted_37$1 = { value: "" };
|
|
2467
|
+
var _hoisted_38$1 = ["value"];
|
|
2468
|
+
var _hoisted_39$1 = {
|
|
2132
2469
|
key: 3,
|
|
2133
2470
|
class: "relative flex items-center"
|
|
2134
2471
|
};
|
|
2135
|
-
var
|
|
2136
|
-
var
|
|
2137
|
-
var
|
|
2472
|
+
var _hoisted_40$1 = { class: "absolute left-1.5 text-[10px] text-slate-400 font-bold pr-1 border-r border-slate-200" };
|
|
2473
|
+
var _hoisted_41$1 = ["onUpdate:modelValue", "required"];
|
|
2474
|
+
var _hoisted_42$1 = [
|
|
2138
2475
|
"onUpdate:modelValue",
|
|
2139
2476
|
"type",
|
|
2140
2477
|
"step",
|
|
2141
2478
|
"required"
|
|
2142
2479
|
];
|
|
2143
|
-
var
|
|
2144
|
-
var
|
|
2480
|
+
var _hoisted_43$1 = { class: "text-center px-1" };
|
|
2481
|
+
var _hoisted_44$1 = [
|
|
2145
2482
|
"aria-label",
|
|
2146
2483
|
"data-testid",
|
|
2147
2484
|
"onClick"
|
|
2148
2485
|
];
|
|
2149
|
-
var
|
|
2486
|
+
var _hoisted_45$1 = {
|
|
2150
2487
|
key: 1,
|
|
2151
2488
|
class: "text-xs text-slate-400 italic"
|
|
2152
2489
|
};
|
|
2153
|
-
var
|
|
2154
|
-
var
|
|
2490
|
+
var _hoisted_46$1 = ["data-testid", "onClick"];
|
|
2491
|
+
var _hoisted_47$1 = {
|
|
2155
2492
|
key: 4,
|
|
2156
2493
|
class: "relative flex items-center"
|
|
2157
2494
|
};
|
|
2158
|
-
var
|
|
2159
|
-
var
|
|
2495
|
+
var _hoisted_48$1 = { class: "absolute left-3 text-slate-400 font-bold text-xs select-none pr-1.5 border-r border-slate-200" };
|
|
2496
|
+
var _hoisted_49$1 = [
|
|
2160
2497
|
"id",
|
|
2161
2498
|
"onUpdate:modelValue",
|
|
2162
2499
|
"required",
|
|
2163
2500
|
"data-testid"
|
|
2164
2501
|
];
|
|
2165
|
-
var
|
|
2502
|
+
var _hoisted_50$1 = [
|
|
2166
2503
|
"id",
|
|
2167
2504
|
"onUpdate:modelValue",
|
|
2168
2505
|
"type",
|
|
@@ -2171,104 +2508,105 @@ var _hoisted_49$1 = [
|
|
|
2171
2508
|
"disabled",
|
|
2172
2509
|
"data-testid"
|
|
2173
2510
|
];
|
|
2174
|
-
var
|
|
2511
|
+
var _hoisted_51$1 = [
|
|
2175
2512
|
"id",
|
|
2176
2513
|
"onUpdate:modelValue",
|
|
2177
2514
|
"rows",
|
|
2178
2515
|
"required",
|
|
2179
2516
|
"data-testid"
|
|
2180
2517
|
];
|
|
2181
|
-
var
|
|
2182
|
-
var
|
|
2518
|
+
var _hoisted_52$1 = ["data-testid"];
|
|
2519
|
+
var _hoisted_53$1 = {
|
|
2183
2520
|
key: 0,
|
|
2184
2521
|
class: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-semibold bg-emerald-50 text-emerald-700 border border-emerald-200/40"
|
|
2185
2522
|
};
|
|
2186
|
-
var
|
|
2523
|
+
var _hoisted_54$1 = {
|
|
2187
2524
|
key: 1,
|
|
2188
2525
|
class: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-semibold bg-slate-50 text-slate-400 border border-slate-200/20"
|
|
2189
2526
|
};
|
|
2190
|
-
var
|
|
2527
|
+
var _hoisted_55$1 = {
|
|
2191
2528
|
key: 0,
|
|
2192
2529
|
class: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-semibold bg-emerald-50 text-emerald-700 border border-emerald-200/40"
|
|
2193
2530
|
};
|
|
2194
|
-
var
|
|
2531
|
+
var _hoisted_56$1 = {
|
|
2195
2532
|
key: 1,
|
|
2196
2533
|
class: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-semibold bg-slate-50 text-slate-400 border border-slate-200/20"
|
|
2197
2534
|
};
|
|
2198
|
-
var
|
|
2535
|
+
var _hoisted_57$1 = {
|
|
2199
2536
|
key: 2,
|
|
2200
2537
|
class: "text-slate-300"
|
|
2201
2538
|
};
|
|
2202
|
-
var
|
|
2539
|
+
var _hoisted_58$1 = [
|
|
2203
2540
|
"href",
|
|
2204
2541
|
"tabindex",
|
|
2205
2542
|
"data-testid",
|
|
2206
2543
|
"onClick",
|
|
2207
2544
|
"onKeydown"
|
|
2208
2545
|
];
|
|
2209
|
-
var
|
|
2546
|
+
var _hoisted_59$1 = {
|
|
2210
2547
|
key: 3,
|
|
2211
2548
|
class: "font-semibold text-slate-900 tabular-nums text-sm"
|
|
2212
2549
|
};
|
|
2213
|
-
var
|
|
2550
|
+
var _hoisted_60$1 = {
|
|
2214
2551
|
key: 4,
|
|
2215
2552
|
class: "inline-block truncate tabular-nums font-bold text-indigo-900 bg-indigo-50/50 px-2 py-0.5 rounded border border-indigo-100/50"
|
|
2216
2553
|
};
|
|
2217
|
-
var
|
|
2218
|
-
|
|
2554
|
+
var _hoisted_61$1 = ["data-testid"];
|
|
2555
|
+
var _hoisted_62$1 = {
|
|
2556
|
+
key: 6,
|
|
2219
2557
|
class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
|
|
2220
2558
|
};
|
|
2221
|
-
var
|
|
2222
|
-
var
|
|
2223
|
-
var
|
|
2224
|
-
var
|
|
2559
|
+
var _hoisted_63$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
|
|
2560
|
+
var _hoisted_64$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
|
|
2561
|
+
var _hoisted_65$1 = { class: "divide-y divide-slate-100" };
|
|
2562
|
+
var _hoisted_66$1 = {
|
|
2225
2563
|
key: 0,
|
|
2226
2564
|
class: "material-icons text-emerald-600 text-base"
|
|
2227
2565
|
};
|
|
2228
|
-
var
|
|
2566
|
+
var _hoisted_67$1 = {
|
|
2229
2567
|
key: 1,
|
|
2230
2568
|
class: "text-slate-300"
|
|
2231
2569
|
};
|
|
2232
|
-
var
|
|
2233
|
-
key:
|
|
2570
|
+
var _hoisted_68$1 = {
|
|
2571
|
+
key: 7,
|
|
2234
2572
|
class: "text-slate-400 italic"
|
|
2235
2573
|
};
|
|
2236
|
-
var
|
|
2237
|
-
key:
|
|
2574
|
+
var _hoisted_69$1 = {
|
|
2575
|
+
key: 8,
|
|
2238
2576
|
class: "bg-slate-50 rounded-xl p-4 border border-slate-200/60 text-slate-600 text-xs whitespace-pre-wrap leading-relaxed max-h-[30vh] overflow-y-auto"
|
|
2239
2577
|
};
|
|
2240
|
-
var
|
|
2578
|
+
var _hoisted_70$1 = [
|
|
2241
2579
|
"src",
|
|
2242
2580
|
"alt",
|
|
2243
2581
|
"data-testid"
|
|
2244
2582
|
];
|
|
2245
|
-
var
|
|
2246
|
-
var
|
|
2247
|
-
var
|
|
2583
|
+
var _hoisted_71$1 = ["href", "data-testid"];
|
|
2584
|
+
var _hoisted_72$1 = ["href", "data-testid"];
|
|
2585
|
+
var _hoisted_73$1 = [
|
|
2248
2586
|
"href",
|
|
2249
2587
|
"data-testid",
|
|
2250
2588
|
"onClick"
|
|
2251
2589
|
];
|
|
2252
|
-
var
|
|
2253
|
-
key:
|
|
2590
|
+
var _hoisted_74$1 = {
|
|
2591
|
+
key: 15,
|
|
2254
2592
|
class: "text-slate-800 font-semibold"
|
|
2255
2593
|
};
|
|
2256
|
-
var
|
|
2594
|
+
var _hoisted_75$1 = {
|
|
2257
2595
|
key: 0,
|
|
2258
2596
|
class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
|
|
2259
2597
|
};
|
|
2260
|
-
var
|
|
2598
|
+
var _hoisted_76$1 = {
|
|
2261
2599
|
key: 1,
|
|
2262
2600
|
class: "mt-5 pt-4 border-t border-slate-200/60",
|
|
2263
2601
|
"data-testid": "collections-detail-chat"
|
|
2264
2602
|
};
|
|
2265
|
-
var
|
|
2603
|
+
var _hoisted_77$1 = {
|
|
2266
2604
|
class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
|
|
2267
2605
|
for: "collections-detail-chat-input"
|
|
2268
2606
|
};
|
|
2269
|
-
var
|
|
2270
|
-
var
|
|
2271
|
-
var
|
|
2607
|
+
var _hoisted_78$1 = { class: "flex items-end gap-2" };
|
|
2608
|
+
var _hoisted_79$1 = ["placeholder", "onKeydown"];
|
|
2609
|
+
var _hoisted_80$1 = ["disabled"];
|
|
2272
2610
|
//#endregion
|
|
2273
2611
|
//#region src/vue/components/CollectionRecordPanel.vue
|
|
2274
2612
|
var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
@@ -2281,6 +2619,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2281
2619
|
actionError: {},
|
|
2282
2620
|
actionPending: { type: Boolean },
|
|
2283
2621
|
visibleActions: {},
|
|
2622
|
+
runningActionIds: {},
|
|
2284
2623
|
liveRecord: {},
|
|
2285
2624
|
liveDerived: {},
|
|
2286
2625
|
viewTitle: {},
|
|
@@ -2339,13 +2678,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2339
2678
|
if (!editing.value) return "collections-detail";
|
|
2340
2679
|
return editing.value.mode === "create" ? "collections-create" : "collections-edit";
|
|
2341
2680
|
});
|
|
2342
|
-
/** Whether a field gets an editable control in edit mode.
|
|
2343
|
-
*
|
|
2344
|
-
*
|
|
2345
|
-
* records) stay read-only in both modes, so the cell geometry never
|
|
2681
|
+
/** Whether a field gets an editable control in edit mode. The computed /
|
|
2682
|
+
* projected kinds (COMPUTED_TYPES: derived, embed, backlinks, rollup,
|
|
2683
|
+
* toggle) stay read-only in both modes, so the cell geometry never
|
|
2346
2684
|
* changes on the view↔edit toggle. */
|
|
2347
2685
|
function isEditableType(type) {
|
|
2348
|
-
return type
|
|
2686
|
+
return !_mulmoclaude_core_collection.COMPUTED_TYPES.has(type);
|
|
2349
2687
|
}
|
|
2350
2688
|
/** Wide field types span the full grid width in BOTH modes — keeping
|
|
2351
2689
|
* `image` full-width here (not just when viewing) is what stops a field
|
|
@@ -2434,10 +2772,10 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2434
2772
|
key: action.id,
|
|
2435
2773
|
type: "button",
|
|
2436
2774
|
class: "h-8 px-2.5 rounded border border-indigo-200 bg-indigo-50/50 text-indigo-600 hover:bg-indigo-600 hover:text-white hover:border-indigo-600 font-bold text-xs transition-all flex items-center gap-1 disabled:opacity-50",
|
|
2437
|
-
disabled: __props.actionPending,
|
|
2775
|
+
disabled: __props.actionPending || __props.runningActionIds.includes(action.id),
|
|
2438
2776
|
"data-testid": `collections-detail-action-${action.id}`,
|
|
2439
2777
|
onClick: ($event) => emit("runAction", action)
|
|
2440
|
-
}, [action.
|
|
2778
|
+
}, [__props.runningActionIds.includes(action.id) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_8$6, "progress_activity")) : action.icon ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_9$6, (0, vue.toDisplayString)(action.icon), 1)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(action.label), 1)], 8, _hoisted_7$6);
|
|
2441
2779
|
}), 128)),
|
|
2442
2780
|
(0, vue.createElementVNode)("button", {
|
|
2443
2781
|
type: "button",
|
|
@@ -2457,29 +2795,29 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2457
2795
|
"aria-label": (0, vue.unref)(t)("common.close"),
|
|
2458
2796
|
"data-testid": "collections-detail-close",
|
|
2459
2797
|
onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
|
|
2460
|
-
}, [..._cache[8] || (_cache[8] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "close", -1)])], 8,
|
|
2798
|
+
}, [..._cache[8] || (_cache[8] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_10$6)
|
|
2461
2799
|
]))]),
|
|
2462
|
-
!editing.value && __props.actionError ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p",
|
|
2463
|
-
(0, vue.createElementVNode)("div",
|
|
2800
|
+
!editing.value && __props.actionError ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_11$6, (0, vue.toDisplayString)(__props.actionError), 1)) : (0, vue.createCommentVNode)("", true),
|
|
2801
|
+
(0, vue.createElementVNode)("div", _hoisted_12$6, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.collection.schema.fields, (field, key) => {
|
|
2464
2802
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key }, [cellVisible(field, String(key)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
2465
2803
|
key: 0,
|
|
2466
2804
|
class: (0, vue.normalizeClass)(["flex flex-col gap-1.5", colSpanClass(field)])
|
|
2467
2805
|
}, [(0, vue.createElementVNode)("label", {
|
|
2468
2806
|
class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider flex items-center gap-1",
|
|
2469
2807
|
for: `collections-field-${key}`
|
|
2470
|
-
}, [(0, vue.createTextVNode)((0, vue.toDisplayString)(field.label) + " ", 1), editing.value && field.required ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span",
|
|
2808
|
+
}, [(0, vue.createTextVNode)((0, vue.toDisplayString)(field.label) + " ", 1), editing.value && field.required ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_14$5, "*")) : (0, vue.createCommentVNode)("", true)], 8, _hoisted_13$5), editing.value && field.type === "embed" && field.idField && __props.render.embedOptions(field.to ?? "").length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
2471
2809
|
key: 0,
|
|
2472
2810
|
id: `collections-field-${key}`,
|
|
2473
2811
|
"onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
|
|
2474
2812
|
required: embedPickerRequired(field),
|
|
2475
2813
|
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs bg-slate-50 hover:bg-slate-50/50 focus:bg-white focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none transition-all cursor-pointer font-medium text-slate-700",
|
|
2476
2814
|
"data-testid": `collections-input-${key}`
|
|
2477
|
-
}, [(0, vue.createElementVNode)("option",
|
|
2815
|
+
}, [(0, vue.createElementVNode)("option", _hoisted_16$5, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.embedOptions(field.to ?? ""), (opt) => {
|
|
2478
2816
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
2479
2817
|
key: opt.slug,
|
|
2480
2818
|
value: opt.slug
|
|
2481
|
-
}, (0, vue.toDisplayString)(opt.display), 9,
|
|
2482
|
-
}), 128))], 8,
|
|
2819
|
+
}, (0, vue.toDisplayString)(opt.display), 9, _hoisted_17$5);
|
|
2820
|
+
}), 128))], 8, _hoisted_15$5)), [[vue.vModelSelect, editing.value.text[field.idField]]]) : editing.value && field.type === "embed" && field.idField ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
|
|
2483
2821
|
key: 1,
|
|
2484
2822
|
id: `collections-field-${key}`,
|
|
2485
2823
|
"onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
|
|
@@ -2488,47 +2826,47 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2488
2826
|
placeholder: (0, vue.unref)(t)("collectionsView.selectPlaceholder"),
|
|
2489
2827
|
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none font-medium text-slate-700 transition-all",
|
|
2490
2828
|
"data-testid": `collections-input-${key}`
|
|
2491
|
-
}, null, 8,
|
|
2829
|
+
}, null, 8, _hoisted_18$5)), [[vue.vModelText, editing.value.text[field.idField]]]) : editing.value && isEditableType(field.type) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("label", _hoisted_19$3, [(0, vue.withDirectives)((0, vue.createElementVNode)("input", {
|
|
2492
2830
|
id: `collections-field-${key}`,
|
|
2493
2831
|
"onUpdate:modelValue": ($event) => editing.value.bool[key] = $event,
|
|
2494
2832
|
type: "checkbox",
|
|
2495
2833
|
class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
2496
2834
|
"data-testid": `collections-input-${key}`,
|
|
2497
2835
|
onChange: ($event) => markBoolTouched(String(key))
|
|
2498
|
-
}, null, 40,
|
|
2836
|
+
}, null, 40, _hoisted_20$3), [[vue.vModelCheckbox, editing.value.bool[key]]]), (0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["text-xs font-semibold", editing.value.bool[key] ? "text-indigo-600" : "text-slate-500"]) }, (0, vue.toDisplayString)(editing.value.bool[key] ? (0, vue.unref)(t)("common.yes") : (0, vue.unref)(t)("common.no")), 3)])) : field.type === "ref" && field.to && __props.render.refOptions(field.to).length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
2499
2837
|
key: 1,
|
|
2500
2838
|
id: `collections-field-${key}`,
|
|
2501
2839
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2502
2840
|
required: isFieldRequiredInUi(field),
|
|
2503
2841
|
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs bg-slate-50 hover:bg-slate-50/50 focus:bg-white focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none transition-all cursor-pointer font-medium text-slate-700",
|
|
2504
2842
|
"data-testid": `collections-input-${key}`
|
|
2505
|
-
}, [(0, vue.createElementVNode)("option",
|
|
2843
|
+
}, [(0, vue.createElementVNode)("option", _hoisted_22$3, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.refOptions(field.to), (opt) => {
|
|
2506
2844
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
2507
2845
|
key: opt.slug,
|
|
2508
2846
|
value: opt.slug
|
|
2509
|
-
}, (0, vue.toDisplayString)(opt.display), 9,
|
|
2510
|
-
}), 128))], 8,
|
|
2847
|
+
}, (0, vue.toDisplayString)(opt.display), 9, _hoisted_23$3);
|
|
2848
|
+
}), 128))], 8, _hoisted_21$3)), [[vue.vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
2511
2849
|
key: 2,
|
|
2512
2850
|
id: `collections-field-${key}`,
|
|
2513
2851
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2514
2852
|
required: isFieldRequiredInUi(field),
|
|
2515
2853
|
class: (0, vue.normalizeClass)(["w-full rounded-xl border px-3 py-2 text-xs focus:bg-white focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none transition-all cursor-pointer font-medium", enumControlClass(String(key), editing.value.text[key])]),
|
|
2516
2854
|
"data-testid": `collections-input-${key}`
|
|
2517
|
-
}, [(0, vue.createElementVNode)("option",
|
|
2855
|
+
}, [(0, vue.createElementVNode)("option", _hoisted_25$2, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.values, (value) => {
|
|
2518
2856
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
2519
2857
|
key: value,
|
|
2520
2858
|
value
|
|
2521
|
-
}, (0, vue.toDisplayString)(value), 9,
|
|
2522
|
-
}), 128))], 10,
|
|
2859
|
+
}, (0, vue.toDisplayString)(value), 9, _hoisted_26$2);
|
|
2860
|
+
}), 128))], 10, _hoisted_24$2)), [[vue.vModelSelect, editing.value.text[key]]]) : field.type === "table" && field.of ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
2523
2861
|
key: 3,
|
|
2524
2862
|
class: "border border-slate-200 bg-slate-50/30 rounded-xl p-4 space-y-3",
|
|
2525
2863
|
"data-testid": `collections-table-${key}`
|
|
2526
|
-
}, [editing.value.table[key] && editing.value.table[key].length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
2864
|
+
}, [editing.value.table[key] && editing.value.table[key].length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_28$1, [(0, vue.createElementVNode)("table", _hoisted_29$1, [(0, vue.createElementVNode)("thead", _hoisted_30$1, [(0, vue.createElementVNode)("tr", null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.of, (subField, subKey) => {
|
|
2527
2865
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("th", {
|
|
2528
2866
|
key: subKey,
|
|
2529
2867
|
class: "text-left px-3 py-2 font-bold"
|
|
2530
2868
|
}, (0, vue.toDisplayString)(subField.label), 1);
|
|
2531
|
-
}), 128)), _cache[9] || (_cache[9] = (0, vue.createElementVNode)("th", { class: "w-9" }, null, -1))])]), (0, vue.createElementVNode)("tbody",
|
|
2869
|
+
}), 128)), _cache[9] || (_cache[9] = (0, vue.createElementVNode)("th", { class: "w-9" }, null, -1))])]), (0, vue.createElementVNode)("tbody", _hoisted_31$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(editing.value.table[key], (row, rowIdx) => {
|
|
2532
2870
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("tr", {
|
|
2533
2871
|
key: rowIdx,
|
|
2534
2872
|
class: "hover:bg-slate-50/50"
|
|
@@ -2542,53 +2880,53 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2542
2880
|
type: "checkbox",
|
|
2543
2881
|
class: "h-4 w-4 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
2544
2882
|
onChange: ($event) => markRowBoolTouched(row, String(subKey))
|
|
2545
|
-
}, null, 40,
|
|
2883
|
+
}, null, 40, _hoisted_32$1)), [[vue.vModelCheckbox, row.bool[subKey]]]) : subField.type === "enum" && Array.isArray(subField.values) && subField.values.length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
2546
2884
|
key: 1,
|
|
2547
2885
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2548
2886
|
required: subField.required,
|
|
2549
2887
|
class: "w-full rounded-lg border border-slate-200 px-2 py-1 text-xs focus:border-indigo-500 focus:outline-none cursor-pointer bg-slate-50 font-medium"
|
|
2550
|
-
}, [(0, vue.createElementVNode)("option",
|
|
2888
|
+
}, [(0, vue.createElementVNode)("option", _hoisted_34$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(subField.values, (value) => {
|
|
2551
2889
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
2552
2890
|
key: value,
|
|
2553
2891
|
value
|
|
2554
|
-
}, (0, vue.toDisplayString)(value), 9,
|
|
2555
|
-
}), 128))], 8,
|
|
2892
|
+
}, (0, vue.toDisplayString)(value), 9, _hoisted_35$1);
|
|
2893
|
+
}), 128))], 8, _hoisted_33$1)), [[vue.vModelSelect, row.text[subKey]]]) : subField.type === "ref" && subField.to && __props.render.refOptions(subField.to).length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
2556
2894
|
key: 2,
|
|
2557
2895
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2558
2896
|
required: subField.required,
|
|
2559
2897
|
class: "w-full rounded-lg border border-slate-200 px-2 py-1 text-xs focus:border-indigo-500 focus:outline-none cursor-pointer bg-slate-50 font-medium"
|
|
2560
|
-
}, [(0, vue.createElementVNode)("option",
|
|
2898
|
+
}, [(0, vue.createElementVNode)("option", _hoisted_37$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.refOptions(subField.to), (opt) => {
|
|
2561
2899
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
2562
2900
|
key: opt.slug,
|
|
2563
2901
|
value: opt.slug
|
|
2564
|
-
}, (0, vue.toDisplayString)(opt.display), 9,
|
|
2565
|
-
}), 128))], 8,
|
|
2902
|
+
}, (0, vue.toDisplayString)(opt.display), 9, _hoisted_38$1);
|
|
2903
|
+
}), 128))], 8, _hoisted_36$1)), [[vue.vModelSelect, row.text[subKey]]]) : subField.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_39$1, [(0, vue.createElementVNode)("span", _hoisted_40$1, (0, vue.toDisplayString)(__props.render.currencySymbol(__props.render.resolveCurrency(subField, __props.liveRecord))), 1), (0, vue.withDirectives)((0, vue.createElementVNode)("input", {
|
|
2566
2904
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2567
2905
|
type: "number",
|
|
2568
2906
|
step: "0.01",
|
|
2569
2907
|
required: subField.required,
|
|
2570
2908
|
class: "w-full rounded-lg border border-slate-200 pl-6 pr-1.5 py-1 text-xs focus:border-indigo-500 focus:outline-none font-semibold text-slate-800"
|
|
2571
|
-
}, null, 8,
|
|
2909
|
+
}, null, 8, _hoisted_41$1), [[vue.vModelText, row.text[subKey]]])])) : (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
|
|
2572
2910
|
key: 4,
|
|
2573
2911
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2574
2912
|
type: __props.render.inputTypeFor(subField.type),
|
|
2575
2913
|
step: __props.render.stepFor(subField.type),
|
|
2576
2914
|
required: subField.required,
|
|
2577
2915
|
class: "w-full rounded-lg border border-slate-200 px-2 py-1 text-xs focus:border-indigo-500 focus:outline-none font-medium text-slate-700"
|
|
2578
|
-
}, null, 8,
|
|
2579
|
-
}), 128)), (0, vue.createElementVNode)("td",
|
|
2916
|
+
}, null, 8, _hoisted_42$1)), [[vue.vModelDynamic, row.text[subKey]]])]);
|
|
2917
|
+
}), 128)), (0, vue.createElementVNode)("td", _hoisted_43$1, [(0, vue.createElementVNode)("button", {
|
|
2580
2918
|
type: "button",
|
|
2581
2919
|
class: "h-7 w-7 flex items-center justify-center rounded-lg text-slate-400 hover:text-rose-600 hover:bg-rose-50 transition-colors",
|
|
2582
2920
|
"aria-label": (0, vue.unref)(t)("collectionsView.removeRow"),
|
|
2583
2921
|
"data-testid": `collections-table-${key}-remove-${rowIdx}`,
|
|
2584
2922
|
onClick: ($event) => removeTableRow(String(key), rowIdx)
|
|
2585
|
-
}, [..._cache[10] || (_cache[10] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8,
|
|
2586
|
-
}), 128))])])])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("p",
|
|
2923
|
+
}, [..._cache[10] || (_cache[10] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_44$1)])]);
|
|
2924
|
+
}), 128))])])])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_45$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noRows")), 1)), (0, vue.createElementVNode)("button", {
|
|
2587
2925
|
type: "button",
|
|
2588
2926
|
class: "inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-800 font-bold hover:underline",
|
|
2589
2927
|
"data-testid": `collections-table-${key}-add`,
|
|
2590
2928
|
onClick: ($event) => addTableRow(String(key), field.of)
|
|
2591
|
-
}, [_cache[11] || (_cache[11] = (0, vue.createElementVNode)("span", { class: "material-icons text-xs" }, "add", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addRow")), 1)], 8,
|
|
2929
|
+
}, [_cache[11] || (_cache[11] = (0, vue.createElementVNode)("span", { class: "material-icons text-xs" }, "add", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addRow")), 1)], 8, _hoisted_46$1)], 8, _hoisted_27$2)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_47$1, [(0, vue.createElementVNode)("div", _hoisted_48$1, (0, vue.toDisplayString)(__props.render.currencySymbol(__props.render.resolveCurrency(field, __props.liveRecord))), 1), (0, vue.withDirectives)((0, vue.createElementVNode)("input", {
|
|
2592
2930
|
id: `collections-field-${key}`,
|
|
2593
2931
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2594
2932
|
type: "number",
|
|
@@ -2596,7 +2934,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2596
2934
|
required: isFieldRequiredInUi(field),
|
|
2597
2935
|
class: "w-full rounded-xl border border-slate-200 pl-11 pr-3 py-2 text-xs focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none font-semibold text-slate-800 transition-all",
|
|
2598
2936
|
"data-testid": `collections-input-${key}`
|
|
2599
|
-
}, null, 8,
|
|
2937
|
+
}, null, 8, _hoisted_49$1), [[vue.vModelText, editing.value.text[key]]])])) : [
|
|
2600
2938
|
"string",
|
|
2601
2939
|
"email",
|
|
2602
2940
|
"number",
|
|
@@ -2615,7 +2953,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2615
2953
|
disabled: field.primary === true && (editing.value.mode === "edit" || __props.isSingleton),
|
|
2616
2954
|
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none disabled:bg-slate-100 disabled:text-slate-400 font-medium text-slate-700 transition-all",
|
|
2617
2955
|
"data-testid": `collections-input-${key}`
|
|
2618
|
-
}, null, 8,
|
|
2956
|
+
}, null, 8, _hoisted_50$1)), [[vue.vModelDynamic, editing.value.text[key]]]) : (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("textarea", {
|
|
2619
2957
|
key: 6,
|
|
2620
2958
|
id: `collections-field-${key}`,
|
|
2621
2959
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
@@ -2623,11 +2961,11 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2623
2961
|
required: isFieldRequiredInUi(field),
|
|
2624
2962
|
class: "w-full rounded-xl border border-slate-200 px-3 py-2 text-xs focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none font-medium text-slate-700 transition-all",
|
|
2625
2963
|
"data-testid": `collections-input-${key}`
|
|
2626
|
-
}, null, 8,
|
|
2964
|
+
}, null, 8, _hoisted_51$1)), [[vue.vModelText, editing.value.text[key]]])], 64)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
2627
2965
|
key: 3,
|
|
2628
2966
|
class: "text-xs font-medium text-slate-700 break-words",
|
|
2629
2967
|
"data-testid": `collections-detail-value-${key}`
|
|
2630
|
-
}, [field.type === "toggle" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span",
|
|
2968
|
+
}, [field.type === "toggle" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_53$1, [_cache[12] || (_cache[12] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_54$1, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 1))], 64)) : field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [detailRecord.value[key] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_55$1, [_cache[13] || (_cache[13] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)])) : detailRecord.value[key] === false ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_56$1, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_57$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
2631
2969
|
key: 2,
|
|
2632
2970
|
href: (0, vue.unref)(cui).recordHref?.(field.to, String(detailRecord.value[key])),
|
|
2633
2971
|
tabindex: (0, vue.unref)(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
|
|
@@ -2636,12 +2974,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2636
2974
|
"data-testid": `collections-detail-ref-${key}`,
|
|
2637
2975
|
onClick: ($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(detailRecord.value[key])),
|
|
2638
2976
|
onKeydown: [(0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(detailRecord.value[key])), ["enter"]), (0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(detailRecord.value[key])), ["space"])]
|
|
2639
|
-
}, (0, vue.toDisplayString)(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41,
|
|
2977
|
+
}, (0, vue.toDisplayString)(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_58$1)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_59$1, (0, vue.toDisplayString)(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_60$1, (0, vue.toDisplayString)(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "rollup" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
2978
|
+
key: 5,
|
|
2979
|
+
class: "inline-block truncate tabular-nums font-bold text-indigo-900 bg-indigo-50/50 px-2 py-0.5 rounded border border-indigo-100/50",
|
|
2980
|
+
"data-testid": `collections-detail-rollup-${key}`
|
|
2981
|
+
}, (0, vue.toDisplayString)(__props.render.rollupDisplay(field, detailRecord.value)), 9, _hoisted_61$1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_62$1, [(0, vue.createElementVNode)("table", _hoisted_63$1, [(0, vue.createElementVNode)("thead", _hoisted_64$1, [(0, vue.createElementVNode)("tr", null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.of, (subField, subKey) => {
|
|
2640
2982
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("th", {
|
|
2641
2983
|
key: subKey,
|
|
2642
2984
|
class: "text-left px-4 py-2 font-bold"
|
|
2643
2985
|
}, (0, vue.toDisplayString)(subField.label), 1);
|
|
2644
|
-
}), 128))])]), (0, vue.createElementVNode)("tbody",
|
|
2986
|
+
}), 128))])]), (0, vue.createElementVNode)("tbody", _hoisted_65$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
|
|
2645
2987
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("tr", {
|
|
2646
2988
|
key: rowIdx,
|
|
2647
2989
|
class: "hover:bg-slate-50/50"
|
|
@@ -2649,48 +2991,48 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2649
2991
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("td", {
|
|
2650
2992
|
key: subKey,
|
|
2651
2993
|
class: "px-4 py-2 align-middle font-medium"
|
|
2652
|
-
}, [subField.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [row[subKey] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span",
|
|
2994
|
+
}, [subField.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [row[subKey] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_66$1, "check_circle")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_67$1, "—"))], 64)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
2653
2995
|
key: 1,
|
|
2654
2996
|
class: (0, vue.normalizeClass)([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
|
|
2655
2997
|
}, (0, vue.toDisplayString)(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
|
|
2656
2998
|
}), 128))]);
|
|
2657
|
-
}), 128))])])])) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span",
|
|
2658
|
-
key:
|
|
2999
|
+
}), 128))])])])) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_68$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_69$1, (0, vue.toDisplayString)(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionEmbedView_default, {
|
|
3000
|
+
key: 9,
|
|
2659
3001
|
view: embedViews.value[key],
|
|
2660
3002
|
"field-key": String(key)
|
|
2661
3003
|
}, null, 8, ["view", "field-key"])) : field.type === "backlinks" && backlinksViews.value[key] ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionBacklinksView_default, {
|
|
2662
|
-
key:
|
|
3004
|
+
key: 10,
|
|
2663
3005
|
view: backlinksViews.value[key],
|
|
2664
3006
|
"field-key": String(key)
|
|
2665
3007
|
}, null, 8, ["view", "field-key"])) : field.type === "image" && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
|
|
2666
|
-
key:
|
|
3008
|
+
key: 11,
|
|
2667
3009
|
src: (0, vue.unref)(resolveImageSrc)(String(detailRecord.value[key])),
|
|
2668
3010
|
alt: field.label,
|
|
2669
3011
|
class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
|
|
2670
3012
|
"data-testid": `collections-detail-image-${key}`
|
|
2671
|
-
}, null, 8,
|
|
2672
|
-
key:
|
|
3013
|
+
}, null, 8, _hoisted_70$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
3014
|
+
key: 12,
|
|
2673
3015
|
href: String(detailRecord.value[key]),
|
|
2674
3016
|
target: "_blank",
|
|
2675
3017
|
rel: "noopener noreferrer",
|
|
2676
3018
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2677
3019
|
"data-testid": `collections-detail-url-${key}`
|
|
2678
|
-
}, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9,
|
|
2679
|
-
key:
|
|
3020
|
+
}, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_71$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
3021
|
+
key: 13,
|
|
2680
3022
|
href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
|
|
2681
3023
|
target: "_blank",
|
|
2682
3024
|
rel: "noopener noreferrer",
|
|
2683
3025
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2684
3026
|
"data-testid": `collections-detail-file-${key}`
|
|
2685
|
-
}, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9,
|
|
2686
|
-
key:
|
|
3027
|
+
}, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_72$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
3028
|
+
key: 14,
|
|
2687
3029
|
href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
|
|
2688
3030
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2689
3031
|
"data-testid": `collections-detail-file-${key}`,
|
|
2690
3032
|
onClick: ($event) => (0, vue.unref)(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
|
|
2691
|
-
}, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9,
|
|
2692
|
-
}), 128)), editing.value && __props.saveError ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p",
|
|
2693
|
-
!editing.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
3033
|
+
}, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_73$1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_74$1, (0, vue.toDisplayString)(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_52$1))], 2)) : (0, vue.createCommentVNode)("", true)], 64);
|
|
3034
|
+
}), 128)), editing.value && __props.saveError ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_75$1, (0, vue.toDisplayString)(__props.saveError), 1)) : (0, vue.createCommentVNode)("", true)]),
|
|
3035
|
+
!editing.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_76$1, [(0, vue.createElementVNode)("label", _hoisted_77$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.itemChatLabel")), 1), (0, vue.createElementVNode)("div", _hoisted_78$1, [(0, vue.withDirectives)((0, vue.createElementVNode)("textarea", {
|
|
2694
3036
|
id: "collections-detail-chat-input",
|
|
2695
3037
|
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
|
|
2696
3038
|
rows: "2",
|
|
@@ -2698,13 +3040,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2698
3040
|
class: "flex-1 bg-slate-50 border border-slate-200/80 rounded-xl px-3 py-2 text-xs placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 focus:bg-white transition-all resize-none",
|
|
2699
3041
|
"data-testid": "collections-detail-chat-input",
|
|
2700
3042
|
onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(submitItemChat, ["meta"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(submitItemChat, ["ctrl"]), ["enter"])]
|
|
2701
|
-
}, null, 40,
|
|
3043
|
+
}, null, 40, _hoisted_79$1), [[vue.vModelText, chatMessage.value]]), (0, vue.createElementVNode)("button", {
|
|
2702
3044
|
type: "button",
|
|
2703
3045
|
class: "h-8 px-2.5 rounded bg-indigo-600 text-white font-bold text-xs hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-sm shadow-indigo-600/10 flex items-center gap-1 shrink-0",
|
|
2704
3046
|
disabled: !chatMessage.value.trim(),
|
|
2705
3047
|
"data-testid": "collections-detail-chat-send",
|
|
2706
3048
|
onClick: submitItemChat
|
|
2707
|
-
}, [_cache[14] || (_cache[14] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)], 8,
|
|
3049
|
+
}, [_cache[14] || (_cache[14] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)], 8, _hoisted_80$1)])])) : (0, vue.createCommentVNode)("", true)
|
|
2708
3050
|
]),
|
|
2709
3051
|
_: 1
|
|
2710
3052
|
}, 40, ["data-testid"]);
|
|
@@ -3106,162 +3448,6 @@ var CollectionRemoteViewPreview_default = /*#__PURE__*/ _plugin_vue_export_helpe
|
|
|
3106
3448
|
}
|
|
3107
3449
|
}), [["__scopeId", "data-v-965ade6c"]]);
|
|
3108
3450
|
//#endregion
|
|
3109
|
-
//#region src/vue/useCollectionRendering.helpers.ts
|
|
3110
|
-
var EM_DASH = "—";
|
|
3111
|
-
var DEFAULT_CURRENCY = "USD";
|
|
3112
|
-
var MARKDOWN_CELL_PREVIEW_MAX = 80;
|
|
3113
|
-
function stepForFieldType(type) {
|
|
3114
|
-
if (type === "money") return "0.01";
|
|
3115
|
-
if (type === "number") return "any";
|
|
3116
|
-
}
|
|
3117
|
-
function inputTypeFor(type) {
|
|
3118
|
-
if (type === "email") return "email";
|
|
3119
|
-
if (type === "number") return "number";
|
|
3120
|
-
if (type === "money") return "number";
|
|
3121
|
-
if (type === "date") return "date";
|
|
3122
|
-
if (type === "datetime") return "datetime-local";
|
|
3123
|
-
return "text";
|
|
3124
|
-
}
|
|
3125
|
-
function isExternalUrl(value) {
|
|
3126
|
-
return typeof value === "string" && /^https?:\/\//i.test(value);
|
|
3127
|
-
}
|
|
3128
|
-
function detailText(value) {
|
|
3129
|
-
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
3130
|
-
return String(value);
|
|
3131
|
-
}
|
|
3132
|
-
function formatCell(value, type) {
|
|
3133
|
-
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
3134
|
-
if (type === "markdown" && typeof value === "string") return value.length > MARKDOWN_CELL_PREVIEW_MAX ? `${value.slice(0, MARKDOWN_CELL_PREVIEW_MAX)}…` : value;
|
|
3135
|
-
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
3136
|
-
return JSON.stringify(value);
|
|
3137
|
-
}
|
|
3138
|
-
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
3139
|
-
* `currencyField` (when present and non-blank) wins over the field's
|
|
3140
|
-
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
3141
|
-
* keys; any other field resolves to undefined (the formatter's USD
|
|
3142
|
-
* fallback), as before. */
|
|
3143
|
-
function resolveCurrency(field, record) {
|
|
3144
|
-
if (field.type !== "money" && field.type !== "derived") return void 0;
|
|
3145
|
-
if (field.currencyField && record) {
|
|
3146
|
-
const code = record[field.currencyField];
|
|
3147
|
-
if (typeof code === "string" && code.trim().length > 0) return code;
|
|
3148
|
-
}
|
|
3149
|
-
return field.currency;
|
|
3150
|
-
}
|
|
3151
|
-
function formatMoney(value, currency, displayLocale) {
|
|
3152
|
-
if (value === void 0 || value === "") return EM_DASH;
|
|
3153
|
-
const amount = typeof value === "number" ? value : Number(value);
|
|
3154
|
-
if (!Number.isFinite(amount)) return String(value);
|
|
3155
|
-
const currencyCode = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
3156
|
-
try {
|
|
3157
|
-
return new Intl.NumberFormat(displayLocale, {
|
|
3158
|
-
style: "currency",
|
|
3159
|
-
currency: currencyCode
|
|
3160
|
-
}).format(amount);
|
|
3161
|
-
} catch {
|
|
3162
|
-
return String(amount);
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
function currencySymbolForLocale(currency, locale) {
|
|
3166
|
-
const code = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
3167
|
-
try {
|
|
3168
|
-
return new Intl.NumberFormat(locale, {
|
|
3169
|
-
style: "currency",
|
|
3170
|
-
currency: code
|
|
3171
|
-
}).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
|
|
3172
|
-
} catch {
|
|
3173
|
-
return code;
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
function tableRows(value) {
|
|
3177
|
-
if (!Array.isArray(value)) return [];
|
|
3178
|
-
return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
|
|
3179
|
-
}
|
|
3180
|
-
function hasTableRows(value) {
|
|
3181
|
-
return tableRows(value).length > 0;
|
|
3182
|
-
}
|
|
3183
|
-
/** Pick the field used to label a referenced/embedded record: prefer a
|
|
3184
|
-
* `name` field, then `title`, else fall back to the primary key. */
|
|
3185
|
-
function displayFieldFor(fields, primaryKey) {
|
|
3186
|
-
if ("name" in fields) return "name";
|
|
3187
|
-
if ("title" in fields) return "title";
|
|
3188
|
-
return primaryKey;
|
|
3189
|
-
}
|
|
3190
|
-
function uniqueRefTargets(schema) {
|
|
3191
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3192
|
-
const walk = (fields) => {
|
|
3193
|
-
for (const field of Object.values(fields)) {
|
|
3194
|
-
if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
3195
|
-
if (field.type === "table" && field.of) walk(field.of);
|
|
3196
|
-
}
|
|
3197
|
-
};
|
|
3198
|
-
walk(schema.fields);
|
|
3199
|
-
return [...targets];
|
|
3200
|
-
}
|
|
3201
|
-
function uniqueEmbedTargets(schema) {
|
|
3202
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3203
|
-
for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
3204
|
-
return [...targets];
|
|
3205
|
-
}
|
|
3206
|
-
/** Slugs of every SOURCE collection a `backlinks` field reverses over.
|
|
3207
|
-
* Top-level only, like `embed` (the schema rejects `backlinks` inside a
|
|
3208
|
-
* table's `of`). Mirrors the server's `uniqueBacklinkSources`. */
|
|
3209
|
-
function uniqueBacklinkSources(schema) {
|
|
3210
|
-
const sources = /* @__PURE__ */ new Set();
|
|
3211
|
-
for (const field of Object.values(schema.fields)) if (field.type === "backlinks" && field.from.length > 0) sources.add(field.from);
|
|
3212
|
-
return [...sources];
|
|
3213
|
-
}
|
|
3214
|
-
function buildRefDisplayMap(detail) {
|
|
3215
|
-
const { fields, primaryKey } = detail.collection.schema;
|
|
3216
|
-
const displayField = displayFieldFor(fields, primaryKey);
|
|
3217
|
-
const map = {};
|
|
3218
|
-
for (const item of detail.items) {
|
|
3219
|
-
const slugRaw = item[primaryKey];
|
|
3220
|
-
if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
|
|
3221
|
-
const displayRaw = item[displayField];
|
|
3222
|
-
map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
|
|
3223
|
-
}
|
|
3224
|
-
return map;
|
|
3225
|
-
}
|
|
3226
|
-
/** Index DERIVED records by primary key — the client mirror of the
|
|
3227
|
-
* server's `loadTarget` indexing: string non-empty ids only, one record
|
|
3228
|
-
* per id (a duplicate keeps the LAST record in its FIRST position —
|
|
3229
|
-
* plain-object key semantics). Shared by the ref-record cache and the
|
|
3230
|
-
* backlinks view so every client consumer agrees with server enrichment
|
|
3231
|
-
* on which source records exist. */
|
|
3232
|
-
function derivedRecordsById(schema, items) {
|
|
3233
|
-
const map = {};
|
|
3234
|
-
for (const item of items) {
|
|
3235
|
-
const slugRaw = item[schema.primaryKey];
|
|
3236
|
-
if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = (0, _mulmoclaude_core_collection.deriveAll)(schema, item, {});
|
|
3237
|
-
}
|
|
3238
|
-
return map;
|
|
3239
|
-
}
|
|
3240
|
-
function buildRefRecordMap(detail) {
|
|
3241
|
-
return derivedRecordsById(detail.collection.schema, detail.items);
|
|
3242
|
-
}
|
|
3243
|
-
function sortedRefOptions(map) {
|
|
3244
|
-
return Object.entries(map).map(([slug, display]) => ({
|
|
3245
|
-
slug,
|
|
3246
|
-
display
|
|
3247
|
-
})).sort((left, right) => left.display.localeCompare(right.display));
|
|
3248
|
-
}
|
|
3249
|
-
/** Dropdown options for an `embed` field's per-record picker: every
|
|
3250
|
-
* record in the target collection, labelled by its name/title (or
|
|
3251
|
-
* primary key), skipping records without a slug and sorted by label. */
|
|
3252
|
-
function buildEmbedOptions(schema, items) {
|
|
3253
|
-
const { fields, primaryKey } = schema;
|
|
3254
|
-
const displayField = displayFieldFor(fields, primaryKey);
|
|
3255
|
-
return items.map((item) => {
|
|
3256
|
-
const slug = String(item[primaryKey] ?? "");
|
|
3257
|
-
const labelRaw = item[displayField];
|
|
3258
|
-
return {
|
|
3259
|
-
slug,
|
|
3260
|
-
display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
|
|
3261
|
-
};
|
|
3262
|
-
}).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
|
|
3263
|
-
}
|
|
3264
|
-
//#endregion
|
|
3265
3451
|
//#region src/vue/useLinkedCollectionCaches.ts
|
|
3266
3452
|
/** The de-duplicated ref + embed target slugs a schema links to. `allTargets`
|
|
3267
3453
|
* is the union (each target fetched once even when both ref'd and embedded).
|
|
@@ -3454,12 +3640,10 @@ function buildBacklinksViews(schema, embedCache, record, locale) {
|
|
|
3454
3640
|
continue;
|
|
3455
3641
|
}
|
|
3456
3642
|
for (const column of columns) column.label = data.schema.fields[column.key]?.label ?? column.key;
|
|
3457
|
-
const selfId = String(record?.[schema.primaryKey] ?? "");
|
|
3458
|
-
const sourceById = derivedRecordsById(data.schema, data.items);
|
|
3459
3643
|
out[key] = {
|
|
3460
3644
|
found: true,
|
|
3461
3645
|
columns,
|
|
3462
|
-
rows: (0, _mulmoclaude_core_collection.backlinkRows)(field,
|
|
3646
|
+
rows: (0, _mulmoclaude_core_collection.backlinkRows)(field, String(record?.[schema.primaryKey] ?? ""), derivedSourceItems(embedCache, field.from) ?? []).map((row) => ({
|
|
3463
3647
|
id: String(row[data.schema.primaryKey] ?? ""),
|
|
3464
3648
|
cells: columns.map((column) => formatBacklinkCell(data.schema.fields[column.key], row[column.key], row, locale))
|
|
3465
3649
|
})),
|
|
@@ -3468,14 +3652,63 @@ function buildBacklinksViews(schema, embedCache, record, locale) {
|
|
|
3468
3652
|
}
|
|
3469
3653
|
return out;
|
|
3470
3654
|
}
|
|
3655
|
+
var derivedSourceMemo = /* @__PURE__ */ new WeakMap();
|
|
3656
|
+
function derivedSourceItems(embedCache, from) {
|
|
3657
|
+
const data = embedCache[from];
|
|
3658
|
+
if (!data) return null;
|
|
3659
|
+
let bySlug = derivedSourceMemo.get(embedCache);
|
|
3660
|
+
if (!bySlug) {
|
|
3661
|
+
bySlug = /* @__PURE__ */ new Map();
|
|
3662
|
+
derivedSourceMemo.set(embedCache, bySlug);
|
|
3663
|
+
}
|
|
3664
|
+
let items = bySlug.get(from);
|
|
3665
|
+
if (!items) {
|
|
3666
|
+
items = Object.values(derivedRecordsById(data.schema, data.items));
|
|
3667
|
+
bySlug.set(from, items);
|
|
3668
|
+
}
|
|
3669
|
+
return items;
|
|
3670
|
+
}
|
|
3671
|
+
/** The rollup scalar for one record, from the reverse sources riding the
|
|
3672
|
+
* embed cache — the SAME index (non-empty ids, one record per id, derived
|
|
3673
|
+
* against themselves) and the SAME `rollupValue` the server enrichment
|
|
3674
|
+
* uses, so the cell and getItems can't disagree. Null (em-dash) when the
|
|
3675
|
+
* source collection isn't loadable; a real 0 for an empty match set. */
|
|
3676
|
+
function rollupValueFor(field, record, schema, embedCache) {
|
|
3677
|
+
if (field.type !== "rollup" || !schema || !record) return null;
|
|
3678
|
+
const items = derivedSourceItems(embedCache, field.from);
|
|
3679
|
+
if (items === null) return null;
|
|
3680
|
+
return (0, _mulmoclaude_core_collection.rollupValue)(field, String(record[schema.primaryKey] ?? ""), items);
|
|
3681
|
+
}
|
|
3682
|
+
/** Display string for a rollup cell: the aggregate as a plain number,
|
|
3683
|
+
* em-dash when the source collection couldn't be resolved. */
|
|
3684
|
+
function renderRollup(field, record, schema, embedCache) {
|
|
3685
|
+
const value = rollupValueFor(field, record, schema, embedCache);
|
|
3686
|
+
return value === null ? "—" : formatCell(value, "number");
|
|
3687
|
+
}
|
|
3688
|
+
/** Copy of `item` with every rollup field resolved from the reverse
|
|
3689
|
+
* sources — injected BEFORE the formula pass so a `derived` formula can
|
|
3690
|
+
* read rollup values as plain identifiers (`played = homePlayed +
|
|
3691
|
+
* awayPlayed`), in the same rollups-then-formulas order the server
|
|
3692
|
+
* enrichment runs. Returns `item` unchanged when the schema declares no
|
|
3693
|
+
* rollups (the overwhelmingly common case — no copy). */
|
|
3694
|
+
function withRollupValues(schema, item, embedCache) {
|
|
3695
|
+
if (!schema) return item;
|
|
3696
|
+
let out = item;
|
|
3697
|
+
for (const [key, field] of Object.entries(schema.fields)) {
|
|
3698
|
+
if (field.type !== "rollup") continue;
|
|
3699
|
+
if (out === item) out = { ...item };
|
|
3700
|
+
out[key] = rollupValueFor(field, item, schema, embedCache);
|
|
3701
|
+
}
|
|
3702
|
+
return out;
|
|
3703
|
+
}
|
|
3471
3704
|
function renderSubCell(subField, value, record, refCache, locale) {
|
|
3472
3705
|
if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale);
|
|
3473
3706
|
if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return lookupRefDisplay(refCache, subField.to, value);
|
|
3474
3707
|
return formatCell(value, subField.type);
|
|
3475
3708
|
}
|
|
3476
|
-
function evaluateDerived(field, fieldKey, item, schema, refRecords) {
|
|
3709
|
+
function evaluateDerived(field, fieldKey, item, schema, refRecords, embedCache = {}) {
|
|
3477
3710
|
if (field.type !== "derived" || !schema) return null;
|
|
3478
|
-
const result = (0, _mulmoclaude_core_collection.deriveAll)(schema, item, refRecords)[fieldKey];
|
|
3711
|
+
const result = (0, _mulmoclaude_core_collection.deriveAll)(schema, withRollupValues(schema, item, embedCache), refRecords)[fieldKey];
|
|
3479
3712
|
return typeof result === "number" && Number.isFinite(result) ? result : null;
|
|
3480
3713
|
}
|
|
3481
3714
|
function renderDerived(field, computedValue, record, locale) {
|
|
@@ -3509,11 +3742,17 @@ function useCollectionRendering(collection, locale) {
|
|
|
3509
3742
|
embedOptions: (targetSlug) => embedOptionsFor(embedCache.value, targetSlug),
|
|
3510
3743
|
embedViewsFor: (record) => buildEmbedViews(collection.value?.schema ?? null, embedCache.value, record, locale.value),
|
|
3511
3744
|
backlinksViewsFor: (record) => buildBacklinksViews(collection.value?.schema ?? null, embedCache.value, record, locale.value),
|
|
3745
|
+
rollupDisplay: (field, record) => renderRollup(field, record, collection.value?.schema ?? null, embedCache.value),
|
|
3512
3746
|
currencySymbol: (currency) => currencySymbolForLocale(currency, locale.value),
|
|
3513
3747
|
artifactUrl: (value) => collectionUi().fileAssetUrl(value),
|
|
3514
3748
|
fileRoutePath: (value) => collectionUi().fileRoutePath(value),
|
|
3515
3749
|
formatSubCell: (subField, value, record) => renderSubCell(subField, value, record, refCache.value, locale.value),
|
|
3516
|
-
evaluateDerivedAgainstItem: (field, fieldKey, item) => evaluateDerived(field, fieldKey, item, collection.value?.schema ?? null, refRecordCache.value),
|
|
3750
|
+
evaluateDerivedAgainstItem: (field, fieldKey, item) => evaluateDerived(field, fieldKey, item, collection.value?.schema ?? null, refRecordCache.value, embedCache.value),
|
|
3751
|
+
deriveRecord: (item) => {
|
|
3752
|
+
const schema = collection.value?.schema ?? null;
|
|
3753
|
+
if (!schema) return item;
|
|
3754
|
+
return (0, _mulmoclaude_core_collection.deriveAll)(schema, withRollupValues(schema, item, embedCache.value), refRecordCache.value);
|
|
3755
|
+
},
|
|
3517
3756
|
derivedDisplay: (field, computedValue, record) => renderDerived(field, computedValue, record, locale.value)
|
|
3518
3757
|
};
|
|
3519
3758
|
}
|
|
@@ -3630,206 +3869,211 @@ var _hoisted_11$4 = [
|
|
|
3630
3869
|
];
|
|
3631
3870
|
var _hoisted_12$4 = {
|
|
3632
3871
|
key: 0,
|
|
3872
|
+
class: "material-icons text-sm animate-spin"
|
|
3873
|
+
};
|
|
3874
|
+
var _hoisted_13$4 = {
|
|
3875
|
+
key: 1,
|
|
3633
3876
|
class: "material-icons text-sm"
|
|
3634
3877
|
};
|
|
3635
|
-
var _hoisted_13$4 = ["title", "aria-label"];
|
|
3636
3878
|
var _hoisted_14$4 = ["title", "aria-label"];
|
|
3637
|
-
var _hoisted_15$4 =
|
|
3879
|
+
var _hoisted_15$4 = ["title", "aria-label"];
|
|
3880
|
+
var _hoisted_16$4 = {
|
|
3638
3881
|
key: 1,
|
|
3639
3882
|
class: "mx-6 mt-2 rounded-lg border border-indigo-200 bg-indigo-50/60 px-4 py-2 text-sm text-indigo-800 flex items-center gap-2",
|
|
3640
3883
|
"data-testid": "collections-refresh-note"
|
|
3641
3884
|
};
|
|
3642
|
-
var
|
|
3643
|
-
var
|
|
3885
|
+
var _hoisted_17$4 = { class: "flex-1" };
|
|
3886
|
+
var _hoisted_18$4 = {
|
|
3644
3887
|
key: 2,
|
|
3645
3888
|
class: "px-6 py-3 bg-white border-b border-slate-100 flex items-center justify-between gap-4"
|
|
3646
3889
|
};
|
|
3647
|
-
var
|
|
3890
|
+
var _hoisted_19$2 = {
|
|
3648
3891
|
key: 0,
|
|
3649
3892
|
class: "relative flex-1 max-w-md"
|
|
3650
3893
|
};
|
|
3651
|
-
var
|
|
3652
|
-
var
|
|
3653
|
-
var
|
|
3654
|
-
var
|
|
3655
|
-
var _hoisted_23$2 = ["aria-pressed"];
|
|
3894
|
+
var _hoisted_20$2 = ["placeholder", "aria-label"];
|
|
3895
|
+
var _hoisted_21$2 = ["aria-label"];
|
|
3896
|
+
var _hoisted_22$2 = { class: "flex items-center gap-2" };
|
|
3897
|
+
var _hoisted_23$2 = ["aria-label"];
|
|
3656
3898
|
var _hoisted_24$1 = ["aria-pressed"];
|
|
3657
3899
|
var _hoisted_25$1 = ["aria-pressed"];
|
|
3658
|
-
var _hoisted_26$1 = [
|
|
3900
|
+
var _hoisted_26$1 = ["aria-pressed"];
|
|
3901
|
+
var _hoisted_27$1 = [
|
|
3659
3902
|
"aria-pressed",
|
|
3660
3903
|
"data-testid",
|
|
3661
3904
|
"onClick"
|
|
3662
3905
|
];
|
|
3663
|
-
var
|
|
3664
|
-
var
|
|
3906
|
+
var _hoisted_28 = { class: "material-icons text-sm" };
|
|
3907
|
+
var _hoisted_29 = [
|
|
3665
3908
|
"title",
|
|
3666
3909
|
"aria-label",
|
|
3667
3910
|
"aria-expanded"
|
|
3668
3911
|
];
|
|
3669
|
-
var
|
|
3912
|
+
var _hoisted_30 = {
|
|
3670
3913
|
key: 0,
|
|
3671
3914
|
class: "absolute left-0 top-full mt-1 z-20 min-w-max rounded border border-slate-200 bg-white shadow-lg py-1",
|
|
3672
3915
|
"data-testid": "collection-view-add-menu"
|
|
3673
3916
|
};
|
|
3674
|
-
var
|
|
3675
|
-
var
|
|
3676
|
-
var
|
|
3677
|
-
var
|
|
3678
|
-
var
|
|
3679
|
-
var
|
|
3917
|
+
var _hoisted_31 = ["title", "aria-label"];
|
|
3918
|
+
var _hoisted_32 = ["value", "aria-label"];
|
|
3919
|
+
var _hoisted_33 = ["value"];
|
|
3920
|
+
var _hoisted_34 = ["value", "aria-label"];
|
|
3921
|
+
var _hoisted_35 = ["value"];
|
|
3922
|
+
var _hoisted_36 = {
|
|
3680
3923
|
key: 3,
|
|
3681
3924
|
class: "text-[10px] text-slate-400 font-bold uppercase tracking-wider select-none"
|
|
3682
3925
|
};
|
|
3683
|
-
var
|
|
3926
|
+
var _hoisted_37 = {
|
|
3684
3927
|
key: 3,
|
|
3685
3928
|
class: "mx-6 mt-4 rounded-xl border border-amber-200 bg-amber-50/60 p-4 text-sm text-amber-900 shadow-sm flex items-center gap-3",
|
|
3686
3929
|
"data-testid": "collections-data-issues"
|
|
3687
3930
|
};
|
|
3688
|
-
var
|
|
3689
|
-
var
|
|
3690
|
-
var
|
|
3931
|
+
var _hoisted_38 = { class: "flex-1" };
|
|
3932
|
+
var _hoisted_39 = { class: "flex-1 overflow-auto" };
|
|
3933
|
+
var _hoisted_40 = {
|
|
3691
3934
|
key: 0,
|
|
3692
3935
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-500 gap-3"
|
|
3693
3936
|
};
|
|
3694
|
-
var
|
|
3937
|
+
var _hoisted_41 = {
|
|
3695
3938
|
key: 1,
|
|
3696
3939
|
class: "m-6 rounded-xl border border-red-200 bg-red-50/50 p-4 text-sm text-red-800 shadow-sm flex items-center gap-3"
|
|
3697
3940
|
};
|
|
3698
|
-
var
|
|
3699
|
-
var
|
|
3941
|
+
var _hoisted_42 = { key: 2 };
|
|
3942
|
+
var _hoisted_43 = {
|
|
3700
3943
|
key: 3,
|
|
3701
3944
|
class: "p-4"
|
|
3702
3945
|
};
|
|
3703
|
-
var
|
|
3946
|
+
var _hoisted_44 = {
|
|
3704
3947
|
key: 4,
|
|
3705
3948
|
class: "h-full flex flex-col"
|
|
3706
3949
|
};
|
|
3707
|
-
var
|
|
3950
|
+
var _hoisted_45 = {
|
|
3708
3951
|
key: 0,
|
|
3709
3952
|
class: "m-3 mb-0 rounded-xl border border-red-200 bg-red-50/50 p-4 text-sm text-red-800 shadow-sm flex items-center gap-3",
|
|
3710
3953
|
"data-testid": "collections-inline-error"
|
|
3711
3954
|
};
|
|
3712
|
-
var
|
|
3713
|
-
var
|
|
3714
|
-
var
|
|
3715
|
-
var
|
|
3955
|
+
var _hoisted_46 = { class: "flex-1" };
|
|
3956
|
+
var _hoisted_47 = ["aria-label"];
|
|
3957
|
+
var _hoisted_48 = { class: "flex-1 min-h-0 px-3 py-2" };
|
|
3958
|
+
var _hoisted_49 = {
|
|
3716
3959
|
key: 5,
|
|
3717
3960
|
class: "h-full",
|
|
3718
3961
|
"data-testid": "collection-custom-view-body"
|
|
3719
3962
|
};
|
|
3720
|
-
var
|
|
3963
|
+
var _hoisted_50 = {
|
|
3721
3964
|
key: 6,
|
|
3722
3965
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
|
|
3723
3966
|
};
|
|
3724
|
-
var
|
|
3725
|
-
var
|
|
3967
|
+
var _hoisted_51 = { class: "font-semibold text-slate-600" };
|
|
3968
|
+
var _hoisted_52 = {
|
|
3726
3969
|
key: 7,
|
|
3727
3970
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
|
|
3728
3971
|
};
|
|
3729
|
-
var
|
|
3730
|
-
var
|
|
3972
|
+
var _hoisted_53 = { class: "font-semibold text-slate-600" };
|
|
3973
|
+
var _hoisted_54 = {
|
|
3731
3974
|
key: 8,
|
|
3732
3975
|
class: "overflow-x-auto [container-type:inline-size]"
|
|
3733
3976
|
};
|
|
3734
|
-
var
|
|
3977
|
+
var _hoisted_55 = {
|
|
3735
3978
|
key: 0,
|
|
3736
3979
|
class: "m-4 rounded-xl border border-red-200 bg-red-50/50 p-4 text-sm text-red-800 shadow-sm flex items-center gap-3",
|
|
3737
3980
|
"data-testid": "collections-inline-error"
|
|
3738
3981
|
};
|
|
3739
|
-
var
|
|
3740
|
-
var
|
|
3741
|
-
var
|
|
3742
|
-
var
|
|
3743
|
-
var
|
|
3744
|
-
var
|
|
3745
|
-
var
|
|
3746
|
-
var
|
|
3982
|
+
var _hoisted_56 = { class: "flex-1" };
|
|
3983
|
+
var _hoisted_57 = ["aria-label"];
|
|
3984
|
+
var _hoisted_58 = { class: "min-w-full text-xs" };
|
|
3985
|
+
var _hoisted_59 = { class: "bg-slate-50 border-b border-slate-200" };
|
|
3986
|
+
var _hoisted_60 = ["aria-sort"];
|
|
3987
|
+
var _hoisted_61 = { class: "flex items-center gap-1" };
|
|
3988
|
+
var _hoisted_62 = ["title"];
|
|
3989
|
+
var _hoisted_63 = [
|
|
3747
3990
|
"data-testid",
|
|
3748
3991
|
"aria-label",
|
|
3749
3992
|
"onClick",
|
|
3750
3993
|
"onPointerenter"
|
|
3751
3994
|
];
|
|
3752
|
-
var
|
|
3753
|
-
var
|
|
3754
|
-
var
|
|
3995
|
+
var _hoisted_64 = { class: "material-icons text-base align-middle" };
|
|
3996
|
+
var _hoisted_65 = { class: "divide-y divide-slate-100 bg-white" };
|
|
3997
|
+
var _hoisted_66 = [
|
|
3755
3998
|
"aria-label",
|
|
3756
3999
|
"data-testid",
|
|
3757
4000
|
"onClick",
|
|
3758
4001
|
"onKeydown"
|
|
3759
4002
|
];
|
|
3760
|
-
var
|
|
4003
|
+
var _hoisted_67 = [
|
|
3761
4004
|
"checked",
|
|
3762
4005
|
"disabled",
|
|
3763
4006
|
"data-testid",
|
|
3764
4007
|
"aria-label",
|
|
3765
4008
|
"onChange"
|
|
3766
4009
|
];
|
|
3767
|
-
var
|
|
4010
|
+
var _hoisted_68 = [
|
|
3768
4011
|
"checked",
|
|
3769
4012
|
"disabled",
|
|
3770
4013
|
"data-testid",
|
|
3771
4014
|
"aria-label",
|
|
3772
4015
|
"onChange"
|
|
3773
4016
|
];
|
|
3774
|
-
var
|
|
4017
|
+
var _hoisted_69 = {
|
|
3775
4018
|
key: 2,
|
|
3776
4019
|
class: "block truncate"
|
|
3777
4020
|
};
|
|
3778
|
-
var
|
|
4021
|
+
var _hoisted_70 = [
|
|
3779
4022
|
"href",
|
|
3780
4023
|
"tabindex",
|
|
3781
4024
|
"data-testid",
|
|
3782
4025
|
"onClick",
|
|
3783
4026
|
"onKeydown"
|
|
3784
4027
|
];
|
|
3785
|
-
var
|
|
4028
|
+
var _hoisted_71 = [
|
|
3786
4029
|
"value",
|
|
3787
4030
|
"disabled",
|
|
3788
4031
|
"data-testid",
|
|
3789
4032
|
"aria-label",
|
|
3790
4033
|
"onChange"
|
|
3791
4034
|
];
|
|
3792
|
-
var
|
|
4035
|
+
var _hoisted_72 = {
|
|
3793
4036
|
key: 0,
|
|
3794
4037
|
value: ""
|
|
3795
4038
|
};
|
|
3796
|
-
var
|
|
3797
|
-
var
|
|
4039
|
+
var _hoisted_73 = ["value"];
|
|
4040
|
+
var _hoisted_74 = {
|
|
3798
4041
|
key: 4,
|
|
3799
4042
|
class: "block truncate tabular-nums font-semibold text-slate-900"
|
|
3800
4043
|
};
|
|
3801
|
-
var
|
|
4044
|
+
var _hoisted_75 = {
|
|
3802
4045
|
key: 5,
|
|
3803
4046
|
class: "inline-flex items-center gap-1 px-2 py-0.5 rounded-lg text-[10px] font-bold bg-slate-100 text-slate-600 border border-slate-200/40"
|
|
3804
4047
|
};
|
|
3805
|
-
var
|
|
4048
|
+
var _hoisted_76 = {
|
|
3806
4049
|
key: 6,
|
|
3807
4050
|
class: "inline-block truncate tabular-nums font-bold text-indigo-900 bg-indigo-50/50 px-1.5 py-0.5 rounded border border-indigo-100/50"
|
|
3808
4051
|
};
|
|
3809
|
-
var
|
|
3810
|
-
var
|
|
3811
|
-
var
|
|
4052
|
+
var _hoisted_77 = ["data-testid"];
|
|
4053
|
+
var _hoisted_78 = ["href", "data-testid"];
|
|
4054
|
+
var _hoisted_79 = ["href", "data-testid"];
|
|
4055
|
+
var _hoisted_80 = [
|
|
3812
4056
|
"href",
|
|
3813
4057
|
"data-testid",
|
|
3814
4058
|
"onClick"
|
|
3815
4059
|
];
|
|
3816
|
-
var
|
|
3817
|
-
key:
|
|
4060
|
+
var _hoisted_81 = {
|
|
4061
|
+
key: 11,
|
|
3818
4062
|
class: "block truncate text-slate-600"
|
|
3819
4063
|
};
|
|
3820
|
-
var
|
|
3821
|
-
var
|
|
3822
|
-
var
|
|
3823
|
-
var
|
|
4064
|
+
var _hoisted_82 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
|
|
4065
|
+
var _hoisted_83 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
|
|
4066
|
+
var _hoisted_84 = { class: "flex-1" };
|
|
4067
|
+
var _hoisted_85 = {
|
|
3824
4068
|
id: "collections-chat-title",
|
|
3825
4069
|
class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
|
|
3826
4070
|
};
|
|
3827
|
-
var
|
|
3828
|
-
var
|
|
3829
|
-
var
|
|
3830
|
-
var
|
|
3831
|
-
var
|
|
3832
|
-
var
|
|
4071
|
+
var _hoisted_86 = { class: "text-xs text-slate-400 font-semibold" };
|
|
4072
|
+
var _hoisted_87 = ["aria-label"];
|
|
4073
|
+
var _hoisted_88 = { class: "px-6 py-5" };
|
|
4074
|
+
var _hoisted_89 = ["placeholder", "onKeydown"];
|
|
4075
|
+
var _hoisted_90 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
|
|
4076
|
+
var _hoisted_91 = ["disabled"];
|
|
3833
4077
|
/** `slug` / `selected` are supplied only in EMBEDDED mode (the
|
|
3834
4078
|
* `presentCollection` chat card mounts this component and drives both
|
|
3835
4079
|
* from the tool result). In standalone route mode (the
|
|
@@ -3931,11 +4175,26 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
3931
4175
|
const actionPending = (0, vue.ref)(false);
|
|
3932
4176
|
const actionError = (0, vue.ref)(null);
|
|
3933
4177
|
const collectionActionPending = (0, vue.ref)(false);
|
|
4178
|
+
const runningActions = (0, vue.ref)(/* @__PURE__ */ new Set());
|
|
4179
|
+
let runningActionsGen = 0;
|
|
4180
|
+
function mutateRunningActions(mutate) {
|
|
4181
|
+
runningActionsGen += 1;
|
|
4182
|
+
const next = new Set(runningActions.value);
|
|
4183
|
+
mutate(next);
|
|
4184
|
+
runningActions.value = next;
|
|
4185
|
+
}
|
|
4186
|
+
/** Adopt a detail response's `runningActions` — only when no local
|
|
4187
|
+
* mutation happened while the response was in flight (stale snapshots
|
|
4188
|
+
* are dropped; the completion ping's refetch reconciles soon after). */
|
|
4189
|
+
function applyServerRunningActions(keys, genAtFetch) {
|
|
4190
|
+
if (runningActionsGen !== genAtFetch) return;
|
|
4191
|
+
runningActions.value = new Set(keys ?? []);
|
|
4192
|
+
}
|
|
3934
4193
|
const chatOpen = (0, vue.ref)(false);
|
|
3935
4194
|
const chatMessage = (0, vue.ref)("");
|
|
3936
4195
|
const chatInputEl = (0, vue.ref)(null);
|
|
3937
4196
|
const render = useCollectionRendering(collection, locale);
|
|
3938
|
-
const {
|
|
4197
|
+
const { refDisplay, formatMoney, resolveCurrency, derivedDisplay, evaluateDerivedAgainstItem, formatCell, isExternalUrl, artifactUrl, fileRoutePath } = render;
|
|
3939
4198
|
const searchQuery = (0, vue.ref)("");
|
|
3940
4199
|
/** Case-insensitive substring match across an item's scalar fields.
|
|
3941
4200
|
* Object-valued fields (table rows, nested records) are skipped —
|
|
@@ -4009,7 +4268,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4009
4268
|
function derivedSortValue(field, key, item) {
|
|
4010
4269
|
const display = field.type === "derived" ? field.display : void 0;
|
|
4011
4270
|
if (display === void 0 || display === "number" || display === "money") return (0, _mulmoclaude_core_collection.numericSortValue)(evaluateDerivedAgainstItem(field, key, item));
|
|
4012
|
-
const enriched =
|
|
4271
|
+
const enriched = render.deriveRecord(item);
|
|
4013
4272
|
if (display === "date") return (0, _mulmoclaude_core_collection.dateSortValue)(enriched[key]);
|
|
4014
4273
|
return (0, _mulmoclaude_core_collection.stringSortValue)(enriched[key]);
|
|
4015
4274
|
}
|
|
@@ -4097,20 +4356,33 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4097
4356
|
}
|
|
4098
4357
|
/** Collection-level header actions. No `when` predicate (no record). */
|
|
4099
4358
|
const collectionActions = (0, vue.computed)(() => collection.value?.schema.collectionActions ?? []);
|
|
4359
|
+
/** True when a `kind: "agent"` action's hidden worker is in flight —
|
|
4360
|
+
* drives the button spinner + disable. Keys mirror the server's
|
|
4361
|
+
* dispatch guard via `agentActionRunKey`. */
|
|
4362
|
+
function isActionRunning(actionId, itemId) {
|
|
4363
|
+
return runningActions.value.has((0, _mulmoclaude_core_collection.agentActionRunKey)(actionId, itemId));
|
|
4364
|
+
}
|
|
4100
4365
|
/** Run a collection-level action: ask the server to assemble the seed
|
|
4101
|
-
* prompt (a progress summary of all records + the template)
|
|
4102
|
-
*
|
|
4366
|
+
* prompt (a progress summary of all records + the template). `kind:
|
|
4367
|
+
* "chat"` gets the seed back and starts a new chat; `kind: "agent"` is
|
|
4368
|
+
* dispatched server-side as a hidden worker — mark it running and let
|
|
4369
|
+
* the completion ping's refetch reconcile. Generic — no domain knowledge. */
|
|
4103
4370
|
async function runCollectionAction(action) {
|
|
4104
4371
|
const current = collection.value;
|
|
4105
|
-
if (!current || collectionActionPending.value) return;
|
|
4372
|
+
if (!current || collectionActionPending.value || isActionRunning(action.id)) return;
|
|
4373
|
+
const runKey = action.kind === "agent" ? (0, _mulmoclaude_core_collection.agentActionRunKey)(action.id) : null;
|
|
4374
|
+
if (runKey) mutateRunningActions((next) => next.add(runKey));
|
|
4106
4375
|
collectionActionPending.value = true;
|
|
4107
4376
|
inlineError.value = null;
|
|
4108
4377
|
const result = await cui.runCollectionAction(current.slug, action.id);
|
|
4109
4378
|
collectionActionPending.value = false;
|
|
4110
4379
|
if (!result.ok) {
|
|
4380
|
+
if (runKey && result.status !== 409) mutateRunningActions((next) => next.delete(runKey));
|
|
4111
4381
|
inlineError.value = result.error;
|
|
4112
4382
|
return;
|
|
4113
4383
|
}
|
|
4384
|
+
if (result.data.dispatched) return;
|
|
4385
|
+
if (result.data.written) return;
|
|
4114
4386
|
if (props.sendTextMessage) {
|
|
4115
4387
|
props.sendTextMessage(result.data.prompt);
|
|
4116
4388
|
return;
|
|
@@ -4145,27 +4417,88 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4145
4417
|
if (!record) return [];
|
|
4146
4418
|
return (collection.value?.schema.actions ?? []).filter((action) => (0, _mulmoclaude_core_collection.actionVisible)(action, record));
|
|
4147
4419
|
});
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4420
|
+
const mutateModal = (0, vue.ref)(null);
|
|
4421
|
+
const mutatePending = (0, vue.ref)(false);
|
|
4422
|
+
const mutateError = (0, vue.ref)(null);
|
|
4423
|
+
/** POST one mutate action and, on success, adopt the written record for
|
|
4424
|
+
* the open panel (the write's change ping refreshes the table rows).
|
|
4425
|
+
* Errors land in the modal when one is open, else on the panel. */
|
|
4426
|
+
async function executeMutate(action, itemId, params) {
|
|
4427
|
+
if (!collection.value || mutatePending.value) return false;
|
|
4428
|
+
mutatePending.value = true;
|
|
4429
|
+
const result = await cui.runItemAction(collection.value.slug, itemId, action.id, params);
|
|
4430
|
+
mutatePending.value = false;
|
|
4431
|
+
if (!result.ok) {
|
|
4432
|
+
if (mutateModal.value) mutateError.value = result.error;
|
|
4433
|
+
else actionError.value = result.error;
|
|
4434
|
+
return false;
|
|
4435
|
+
}
|
|
4436
|
+
if (result.data.written && viewing.value && String(viewing.value[collection.value.schema.primaryKey] ?? "") === itemId) viewing.value = result.data.item;
|
|
4437
|
+
return true;
|
|
4438
|
+
}
|
|
4439
|
+
async function submitMutateParams(params) {
|
|
4440
|
+
const open = mutateModal.value;
|
|
4441
|
+
if (!open) return;
|
|
4442
|
+
mutateError.value = null;
|
|
4443
|
+
if (await executeMutate(open.action, open.itemId, params)) mutateModal.value = null;
|
|
4444
|
+
}
|
|
4445
|
+
/** Mutate kind: open the params mini-form when the action declares one,
|
|
4446
|
+
* else apply the declarative write immediately. */
|
|
4447
|
+
async function runMutateAction(action, itemId) {
|
|
4448
|
+
actionError.value = null;
|
|
4449
|
+
if (action.params && Object.keys(action.params).length > 0) {
|
|
4450
|
+
mutateError.value = null;
|
|
4451
|
+
mutateModal.value = {
|
|
4452
|
+
action,
|
|
4453
|
+
itemId
|
|
4454
|
+
};
|
|
4455
|
+
return;
|
|
4456
|
+
}
|
|
4457
|
+
await executeMutate(action, itemId, {});
|
|
4458
|
+
}
|
|
4459
|
+
/** Run a schema-declared action on the open record. `kind: "mutate"`
|
|
4460
|
+
* never leaves the host: with `params` it opens the mini-form, else it
|
|
4461
|
+
* applies immediately. `kind: "chat"` gets the seed back and starts a
|
|
4462
|
+
* new chat; `kind: "agent"` is dispatched server-side as a hidden
|
|
4463
|
+
* worker — mark it running and let the completion ping's refetch
|
|
4464
|
+
* reconcile. Generic — no knowledge of what the action does. */
|
|
4151
4465
|
async function runAction(action) {
|
|
4152
4466
|
if (!collection.value || !viewing.value) return;
|
|
4153
4467
|
const itemId = String(viewing.value[collection.value.schema.primaryKey] ?? "");
|
|
4154
|
-
if (!itemId) return;
|
|
4468
|
+
if (!itemId || isActionRunning(action.id, itemId)) return;
|
|
4469
|
+
if (action.kind === "mutate") {
|
|
4470
|
+
await runMutateAction(action, itemId);
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
4473
|
+
const runKey = action.kind === "agent" ? (0, _mulmoclaude_core_collection.agentActionRunKey)(action.id, itemId) : null;
|
|
4474
|
+
if (runKey) mutateRunningActions((next) => next.add(runKey));
|
|
4155
4475
|
actionPending.value = true;
|
|
4156
4476
|
actionError.value = null;
|
|
4157
4477
|
const result = await cui.runItemAction(collection.value.slug, itemId, action.id);
|
|
4158
4478
|
actionPending.value = false;
|
|
4159
4479
|
if (!result.ok) {
|
|
4480
|
+
if (runKey && result.status !== 409) mutateRunningActions((next) => next.delete(runKey));
|
|
4160
4481
|
actionError.value = result.error;
|
|
4161
4482
|
return;
|
|
4162
4483
|
}
|
|
4484
|
+
if (result.data.dispatched) return;
|
|
4485
|
+
if (result.data.written) return;
|
|
4163
4486
|
if (props.sendTextMessage) {
|
|
4164
4487
|
props.sendTextMessage(result.data.prompt);
|
|
4165
4488
|
return;
|
|
4166
4489
|
}
|
|
4167
4490
|
appApi.startNewChat(result.data.prompt, result.data.role);
|
|
4168
4491
|
}
|
|
4492
|
+
/** Ids of the open record's actions whose hidden worker is running — the
|
|
4493
|
+
* record panel renders those buttons with a spinner, disabled. */
|
|
4494
|
+
const viewingRunningActionIds = (0, vue.computed)(() => {
|
|
4495
|
+
const current = collection.value;
|
|
4496
|
+
const record = viewing.value;
|
|
4497
|
+
if (!current || !record) return [];
|
|
4498
|
+
const itemId = String(record[current.schema.primaryKey] ?? "");
|
|
4499
|
+
if (!itemId) return [];
|
|
4500
|
+
return (current.schema.actions ?? []).filter((action) => isActionRunning(action.id, itemId)).map((action) => action.id);
|
|
4501
|
+
});
|
|
4169
4502
|
/** Open the chat modal, blanking any prior draft and focusing the input. */
|
|
4170
4503
|
function openChat() {
|
|
4171
4504
|
chatMessage.value = "";
|
|
@@ -4231,10 +4564,12 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4231
4564
|
collection.value = null;
|
|
4232
4565
|
items.value = [];
|
|
4233
4566
|
dataIssues.value = [];
|
|
4567
|
+
mutateRunningActions((next) => next.clear());
|
|
4234
4568
|
searchQuery.value = "";
|
|
4235
4569
|
render.resetLinkedCaches();
|
|
4236
4570
|
viewing.value = null;
|
|
4237
4571
|
openDay.value = null;
|
|
4572
|
+
const runningGen = runningActionsGen;
|
|
4238
4573
|
const result = await cui.fetchCollectionDetail(slug);
|
|
4239
4574
|
loading.value = false;
|
|
4240
4575
|
if (!result.ok) {
|
|
@@ -4245,6 +4580,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4245
4580
|
collection.value = result.data.collection;
|
|
4246
4581
|
items.value = result.data.items;
|
|
4247
4582
|
dataIssues.value = result.data.issues ?? [];
|
|
4583
|
+
applyServerRunningActions(result.data.runningActions, runningGen);
|
|
4248
4584
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4249
4585
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4250
4586
|
if (collection.value?.slug === slug) syncViewToSelected();
|
|
@@ -4260,11 +4596,13 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4260
4596
|
* fetch is a no-op (keep the current data) — a transient blip shouldn't blank a
|
|
4261
4597
|
* view the user is reading. */
|
|
4262
4598
|
async function refreshItemsInPlace(slug) {
|
|
4599
|
+
const runningGen = runningActionsGen;
|
|
4263
4600
|
const result = await cui.fetchCollectionDetail(slug);
|
|
4264
4601
|
if (!result.ok || activeSlug.value !== slug) return;
|
|
4265
4602
|
collection.value = result.data.collection;
|
|
4266
4603
|
items.value = result.data.items;
|
|
4267
4604
|
dataIssues.value = result.data.issues ?? [];
|
|
4605
|
+
applyServerRunningActions(result.data.runningActions, runningGen);
|
|
4268
4606
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4269
4607
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4270
4608
|
if (activeSlug.value !== slug) return;
|
|
@@ -4474,7 +4812,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4474
4812
|
boolOriginallyPresent[key] = false;
|
|
4475
4813
|
boolTouched[key] = false;
|
|
4476
4814
|
} else if (field.type === "table") table[key] = [];
|
|
4477
|
-
else if (
|
|
4815
|
+
else if (!_mulmoclaude_core_collection.COMPUTED_TYPES.has(field.type)) text[key] = "";
|
|
4478
4816
|
const { singleton, primaryKey } = collection.value.schema;
|
|
4479
4817
|
if (singleton) text[primaryKey] = singleton;
|
|
4480
4818
|
else if (primaryKey in text) text[primaryKey] = generateUniqueItemId(primaryKey);
|
|
@@ -4506,7 +4844,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4506
4844
|
} else if (field.type === "table" && field.of) {
|
|
4507
4845
|
const sub = field.of;
|
|
4508
4846
|
table[key] = (Array.isArray(raw) ? raw : []).filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)).map((row) => (0, _mulmoclaude_core_collection.rowFromItem)(row, sub));
|
|
4509
|
-
} else if (
|
|
4847
|
+
} else if (!_mulmoclaude_core_collection.COMPUTED_TYPES.has(field.type)) text[key] = raw === void 0 || raw === null ? "" : String(raw);
|
|
4510
4848
|
}
|
|
4511
4849
|
const primaryRaw = item[collection.value.schema.primaryKey];
|
|
4512
4850
|
const originalId = typeof primaryRaw === "string" ? primaryRaw : String(primaryRaw ?? "");
|
|
@@ -4633,7 +4971,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4633
4971
|
* rendering composable; this binds it to the current draft. */
|
|
4634
4972
|
const liveDerived = (0, vue.computed)(() => {
|
|
4635
4973
|
if (!collection.value || !liveRecord.value) return null;
|
|
4636
|
-
return render.
|
|
4974
|
+
return render.deriveRecord(liveRecord.value);
|
|
4637
4975
|
});
|
|
4638
4976
|
/** Short summary for a `table`-typed cell in the main collection
|
|
4639
4977
|
* table. Counts rows; nothing fancier yet (per-row preview is
|
|
@@ -4954,7 +5292,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4954
5292
|
"aria-label": (0, vue.unref)(t)("collectionsView.backToIndex"),
|
|
4955
5293
|
"data-testid": "collections-back",
|
|
4956
5294
|
onClick: goBack
|
|
4957
|
-
}, [..._cache[
|
|
5295
|
+
}, [..._cache[26] || (_cache[26] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : (0, vue.createCommentVNode)("", true),
|
|
4958
5296
|
collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4$5, [(0, vue.createElementVNode)("span", _hoisted_5$5, (0, vue.toDisplayString)(collection.value.icon), 1)])) : (0, vue.createCommentVNode)("", true),
|
|
4959
5297
|
(0, vue.createElementVNode)("div", _hoisted_6$4, [(0, vue.createElementVNode)("h1", _hoisted_7$4, (0, vue.toDisplayString)(collection.value?.title ?? (0, vue.unref)(t)("collectionsView.title")), 1), collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_8$4, (0, vue.toDisplayString)(collection.value.slug), 1)) : (0, vue.createCommentVNode)("", true)]),
|
|
4960
5298
|
collection.value && !embedded.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(pinToggle)), {
|
|
@@ -4983,16 +5321,16 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
4983
5321
|
class: "h-8 px-2.5 flex items-center gap-1 rounded border border-indigo-200 bg-white hover:bg-indigo-50 text-indigo-600 font-bold text-xs transition-colors",
|
|
4984
5322
|
"data-testid": "collections-chat",
|
|
4985
5323
|
onClick: openChat
|
|
4986
|
-
}, [_cache[
|
|
5324
|
+
}, [_cache[27] || (_cache[27] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)])) : (0, vue.createCommentVNode)("", true),
|
|
4987
5325
|
((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(collectionActions.value, (action) => {
|
|
4988
5326
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
4989
5327
|
key: action.id,
|
|
4990
5328
|
type: "button",
|
|
4991
5329
|
class: "h-8 px-2.5 flex items-center gap-1 rounded border border-indigo-200 bg-white hover:bg-indigo-50 text-indigo-600 font-bold text-xs transition-colors disabled:opacity-50",
|
|
4992
|
-
disabled: collectionActionPending.value,
|
|
5330
|
+
disabled: collectionActionPending.value || isActionRunning(action.id),
|
|
4993
5331
|
"data-testid": `collections-action-${action.id}`,
|
|
4994
5332
|
onClick: ($event) => runCollectionAction(action)
|
|
4995
|
-
}, [action.
|
|
5333
|
+
}, [isActionRunning(action.id) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_12$4, "progress_activity")) : action.icon ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_13$4, (0, vue.toDisplayString)(action.icon), 1)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(action.label), 1)], 8, _hoisted_11$4);
|
|
4996
5334
|
}), 128)),
|
|
4997
5335
|
canCreate.value && !calendarActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
4998
5336
|
key: 5,
|
|
@@ -5000,7 +5338,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5000
5338
|
class: "h-8 px-2.5 flex items-center gap-1 rounded bg-indigo-600 hover:bg-indigo-700 text-white font-bold text-xs transition-colors shadow-sm",
|
|
5001
5339
|
"data-testid": "collections-add-item",
|
|
5002
5340
|
onClick: openCreate
|
|
5003
|
-
}, [_cache[
|
|
5341
|
+
}, [_cache[28] || (_cache[28] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "add", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.add")), 1)])) : (0, vue.createCommentVNode)("", true),
|
|
5004
5342
|
canDeleteCollection.value && !embedded.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5005
5343
|
key: 6,
|
|
5006
5344
|
type: "button",
|
|
@@ -5009,7 +5347,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5009
5347
|
"aria-label": (0, vue.unref)(t)("collectionsView.deleteCollection"),
|
|
5010
5348
|
"data-testid": "collections-delete",
|
|
5011
5349
|
onClick: confirmCollectionDelete
|
|
5012
|
-
}, [..._cache[
|
|
5350
|
+
}, [..._cache[29] || (_cache[29] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : (0, vue.createCommentVNode)("", true),
|
|
5013
5351
|
canDeleteFeed.value && !embedded.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5014
5352
|
key: 7,
|
|
5015
5353
|
type: "button",
|
|
@@ -5018,26 +5356,26 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5018
5356
|
"aria-label": (0, vue.unref)(t)("collectionsView.deleteFeed"),
|
|
5019
5357
|
"data-testid": "feeds-delete",
|
|
5020
5358
|
onClick: confirmFeedDelete
|
|
5021
|
-
}, [..._cache[
|
|
5359
|
+
}, [..._cache[30] || (_cache[30] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_15$4)) : (0, vue.createCommentVNode)("", true)
|
|
5022
5360
|
])) : (0, vue.createCommentVNode)("", true),
|
|
5023
|
-
refreshNote.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5024
|
-
collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5025
|
-
_cache[
|
|
5361
|
+
refreshNote.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_16$4, [_cache[31] || (_cache[31] = (0, vue.createElementVNode)("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), (0, vue.createElementVNode)("span", _hoisted_17$4, (0, vue.toDisplayString)(refreshNote.value), 1)])) : (0, vue.createCommentVNode)("", true),
|
|
5362
|
+
collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_18$4, [!__props.hideSearch && items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_19$2, [
|
|
5363
|
+
_cache[33] || (_cache[33] = (0, vue.createElementVNode)("span", { class: "absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400 pointer-events-none" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "search")], -1)),
|
|
5026
5364
|
(0, vue.withDirectives)((0, vue.createElementVNode)("input", {
|
|
5027
5365
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
|
|
5028
5366
|
type: "text",
|
|
5029
5367
|
placeholder: (0, vue.unref)(t)("collectionsView.searchPlaceholder"),
|
|
5030
5368
|
"aria-label": (0, vue.unref)(t)("collectionsView.searchPlaceholder"),
|
|
5031
5369
|
class: "w-full bg-slate-50 border border-slate-200/80 rounded-xl pl-9 pr-8 py-1.5 text-xs placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 focus:bg-white transition-all font-medium"
|
|
5032
|
-
}, null, 8,
|
|
5370
|
+
}, null, 8, _hoisted_20$2), [[vue.vModelText, searchQuery.value]]),
|
|
5033
5371
|
searchQuery.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5034
5372
|
key: 0,
|
|
5035
5373
|
type: "button",
|
|
5036
5374
|
"aria-label": (0, vue.unref)(t)("collectionsView.clearSearch"),
|
|
5037
5375
|
class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
|
|
5038
5376
|
onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
|
|
5039
|
-
}, [..._cache[
|
|
5040
|
-
])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div",
|
|
5377
|
+
}, [..._cache[32] || (_cache[32] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_21$2)) : (0, vue.createCommentVNode)("", true)
|
|
5378
|
+
])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_22$2, [
|
|
5041
5379
|
!__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
5042
5380
|
key: 0,
|
|
5043
5381
|
class: "flex gap-0.5",
|
|
@@ -5050,7 +5388,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5050
5388
|
"aria-pressed": activeView.value === "table",
|
|
5051
5389
|
"data-testid": "collection-view-toggle-table",
|
|
5052
5390
|
onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
|
|
5053
|
-
}, [_cache[
|
|
5391
|
+
}, [_cache[34] || (_cache[34] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "table_rows", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewTable")), 1)], 10, _hoisted_24$1),
|
|
5054
5392
|
hasCalendar.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5055
5393
|
key: 0,
|
|
5056
5394
|
type: "button",
|
|
@@ -5058,7 +5396,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5058
5396
|
"aria-pressed": activeView.value === "calendar",
|
|
5059
5397
|
"data-testid": "collection-view-toggle-calendar",
|
|
5060
5398
|
onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
|
|
5061
|
-
}, [_cache[
|
|
5399
|
+
}, [_cache[35] || (_cache[35] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "calendar_month", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_25$1)) : (0, vue.createCommentVNode)("", true),
|
|
5062
5400
|
hasKanban.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5063
5401
|
key: 1,
|
|
5064
5402
|
type: "button",
|
|
@@ -5066,7 +5404,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5066
5404
|
"aria-pressed": activeView.value === "kanban",
|
|
5067
5405
|
"data-testid": "collection-view-toggle-kanban",
|
|
5068
5406
|
onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
|
|
5069
|
-
}, [_cache[
|
|
5407
|
+
}, [_cache[36] || (_cache[36] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "view_kanban", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_26$1)) : (0, vue.createCommentVNode)("", true),
|
|
5070
5408
|
((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(customViews.value, (cv) => {
|
|
5071
5409
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5072
5410
|
key: cv.id,
|
|
@@ -5075,7 +5413,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5075
5413
|
"aria-pressed": activeView.value === (0, vue.unref)(customViewKey)(cv.id),
|
|
5076
5414
|
"data-testid": `collection-view-custom-${cv.id}`,
|
|
5077
5415
|
onClick: ($event) => setCustomView(cv.id)
|
|
5078
|
-
}, [(0, vue.createElementVNode)("span",
|
|
5416
|
+
}, [(0, vue.createElementVNode)("span", _hoisted_28, (0, vue.toDisplayString)(cv.icon || (cv.target === "mobile" ? "smartphone" : "dashboard_customize")), 1), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(cv.label), 1)], 10, _hoisted_27$1);
|
|
5079
5417
|
}), 128)),
|
|
5080
5418
|
canAddCustomView.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
5081
5419
|
key: 2,
|
|
@@ -5090,17 +5428,17 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5090
5428
|
"aria-expanded": addMenuOpen.value,
|
|
5091
5429
|
"data-testid": "collection-view-add",
|
|
5092
5430
|
onClick: onAddViewClick
|
|
5093
|
-
}, [..._cache[
|
|
5431
|
+
}, [..._cache[37] || (_cache[37] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_29), addMenuOpen.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_30, [(0, vue.createElementVNode)("button", {
|
|
5094
5432
|
type: "button",
|
|
5095
5433
|
class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
|
|
5096
5434
|
"data-testid": "collection-view-add-desktop",
|
|
5097
5435
|
onClick: _cache[5] || (_cache[5] = ($event) => addCustomView("desktop"))
|
|
5098
|
-
}, [_cache[
|
|
5436
|
+
}, [_cache[38] || (_cache[38] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "dashboard_customize", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addViewDesktop")), 1)]), (0, vue.createElementVNode)("button", {
|
|
5099
5437
|
type: "button",
|
|
5100
5438
|
class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
|
|
5101
5439
|
"data-testid": "collection-view-add-mobile",
|
|
5102
5440
|
onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("mobile"))
|
|
5103
|
-
}, [_cache[
|
|
5441
|
+
}, [_cache[39] || (_cache[39] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "smartphone", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addViewMobile")), 1)])])) : (0, vue.createCommentVNode)("", true)], 512)) : (0, vue.createCommentVNode)("", true),
|
|
5104
5442
|
canConfigureViews.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5105
5443
|
key: 3,
|
|
5106
5444
|
type: "button",
|
|
@@ -5109,8 +5447,8 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5109
5447
|
"aria-label": (0, vue.unref)(t)("collectionsView.config.open"),
|
|
5110
5448
|
"data-testid": "collection-config-open",
|
|
5111
5449
|
onClick: _cache[7] || (_cache[7] = ($event) => configOpen.value = true)
|
|
5112
|
-
}, [..._cache[
|
|
5113
|
-
], 8,
|
|
5450
|
+
}, [..._cache[40] || (_cache[40] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_31)) : (0, vue.createCommentVNode)("", true)
|
|
5451
|
+
], 8, _hoisted_23$2)) : (0, vue.createCommentVNode)("", true),
|
|
5114
5452
|
calendarActive.value && dateFields.value.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
5115
5453
|
key: 1,
|
|
5116
5454
|
value: calendarAnchorField.value,
|
|
@@ -5122,8 +5460,8 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5122
5460
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
5123
5461
|
key,
|
|
5124
5462
|
value: key
|
|
5125
|
-
}, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9,
|
|
5126
|
-
}), 128))], 40,
|
|
5463
|
+
}, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_33);
|
|
5464
|
+
}), 128))], 40, _hoisted_32)) : (0, vue.createCommentVNode)("", true),
|
|
5127
5465
|
kanbanActive.value && enumFields.value.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
5128
5466
|
key: 2,
|
|
5129
5467
|
value: kanbanGroupField.value,
|
|
@@ -5135,24 +5473,24 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5135
5473
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
5136
5474
|
key,
|
|
5137
5475
|
value: key
|
|
5138
|
-
}, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9,
|
|
5139
|
-
}), 128))], 40,
|
|
5140
|
-
items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5476
|
+
}, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_35);
|
|
5477
|
+
}), 128))], 40, _hoisted_34)) : (0, vue.createCommentVNode)("", true),
|
|
5478
|
+
items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_36, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.searchSummary", {
|
|
5141
5479
|
shown: filteredItems.value.length,
|
|
5142
5480
|
total: items.value.length
|
|
5143
5481
|
})), 1)) : (0, vue.createCommentVNode)("", true)
|
|
5144
5482
|
])])) : (0, vue.createCommentVNode)("", true),
|
|
5145
|
-
collection.value && dataIssues.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5146
|
-
_cache[
|
|
5147
|
-
(0, vue.createElementVNode)("span",
|
|
5483
|
+
collection.value && dataIssues.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_37, [
|
|
5484
|
+
_cache[42] || (_cache[42] = (0, vue.createElementVNode)("span", { class: "material-icons text-amber-600" }, "warning", -1)),
|
|
5485
|
+
(0, vue.createElementVNode)("span", _hoisted_38, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
|
|
5148
5486
|
(0, vue.createElementVNode)("button", {
|
|
5149
5487
|
type: "button",
|
|
5150
5488
|
class: "h-8 px-2.5 flex items-center gap-1 rounded border border-amber-300 bg-white hover:bg-amber-100 text-amber-700 font-bold text-xs transition-colors",
|
|
5151
5489
|
"data-testid": "collections-repair",
|
|
5152
5490
|
onClick: repairCollection
|
|
5153
|
-
}, [_cache[
|
|
5491
|
+
}, [_cache[41] || (_cache[41] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "build", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.repair")), 1)])
|
|
5154
5492
|
])) : (0, vue.createCommentVNode)("", true),
|
|
5155
|
-
(0, vue.createElementVNode)("div",
|
|
5493
|
+
(0, vue.createElementVNode)("div", _hoisted_39, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_40, [_cache[43] || (_cache[43] = (0, vue.createElementVNode)("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.loading")), 1)])) : loadError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_41, [_cache[44] || (_cache[44] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(loadError.value === "not-found" ? (0, vue.unref)(t)("collectionsView.notFound") : `${(0, vue.unref)(t)("collectionsView.loadFailed")}: ${loadError.value}`), 1)])) : !collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_42)) : calendarActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_43, [(0, vue.createVNode)(CollectionCalendarView_default, {
|
|
5156
5494
|
schema: collection.value.schema,
|
|
5157
5495
|
items: filteredItems.value,
|
|
5158
5496
|
"anchor-field": calendarAnchorField.value,
|
|
@@ -5196,6 +5534,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5196
5534
|
"action-error": actionError.value,
|
|
5197
5535
|
"action-pending": actionPending.value,
|
|
5198
5536
|
"visible-actions": visibleActions.value,
|
|
5537
|
+
"running-action-ids": viewingRunningActionIds.value,
|
|
5199
5538
|
"live-record": liveRecord.value,
|
|
5200
5539
|
"live-derived": liveDerived.value,
|
|
5201
5540
|
"view-title": viewTitle.value,
|
|
@@ -5218,6 +5557,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5218
5557
|
"action-error",
|
|
5219
5558
|
"action-pending",
|
|
5220
5559
|
"visible-actions",
|
|
5560
|
+
"running-action-ids",
|
|
5221
5561
|
"live-record",
|
|
5222
5562
|
"live-derived",
|
|
5223
5563
|
"view-title",
|
|
@@ -5237,16 +5577,16 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5237
5577
|
"selected",
|
|
5238
5578
|
"can-create",
|
|
5239
5579
|
"show-detail"
|
|
5240
|
-
])) : (0, vue.createCommentVNode)("", true)])) : kanbanActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5241
|
-
_cache[
|
|
5242
|
-
(0, vue.createElementVNode)("span",
|
|
5580
|
+
])) : (0, vue.createCommentVNode)("", true)])) : kanbanActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_44, [inlineError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_45, [
|
|
5581
|
+
_cache[46] || (_cache[46] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)),
|
|
5582
|
+
(0, vue.createElementVNode)("span", _hoisted_46, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
|
|
5243
5583
|
(0, vue.createElementVNode)("button", {
|
|
5244
5584
|
type: "button",
|
|
5245
5585
|
class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
|
|
5246
5586
|
"aria-label": (0, vue.unref)(t)("common.close"),
|
|
5247
5587
|
onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
|
|
5248
|
-
}, [..._cache[
|
|
5249
|
-
])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div",
|
|
5588
|
+
}, [..._cache[45] || (_cache[45] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_47)
|
|
5589
|
+
])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_48, [(0, vue.createVNode)(CollectionKanbanView_default, {
|
|
5250
5590
|
schema: collection.value.schema,
|
|
5251
5591
|
items: filteredItems.value,
|
|
5252
5592
|
"group-field": kanbanGroupField.value,
|
|
@@ -5260,7 +5600,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5260
5600
|
"group-field",
|
|
5261
5601
|
"selected",
|
|
5262
5602
|
"notified"
|
|
5263
|
-
])])])) : activeCustomView.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5603
|
+
])])])) : activeCustomView.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_49, [activeCustomView.value.target === "mobile" ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionRemoteViewPreview_default, {
|
|
5264
5604
|
key: 0,
|
|
5265
5605
|
slug: collection.value.slug,
|
|
5266
5606
|
view: activeCustomView.value,
|
|
@@ -5271,32 +5611,32 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5271
5611
|
view: activeCustomView.value,
|
|
5272
5612
|
onOpenItem: onCustomViewOpenItem,
|
|
5273
5613
|
onStartChat: onCustomViewStartChat
|
|
5274
|
-
}, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5275
|
-
_cache[
|
|
5276
|
-
(0, vue.createElementVNode)("p",
|
|
5614
|
+
}, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_50, [_cache[47] || (_cache[47] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), (0, vue.createElementVNode)("p", _hoisted_51, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_52, [
|
|
5615
|
+
_cache[48] || (_cache[48] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
|
|
5616
|
+
(0, vue.createElementVNode)("p", _hoisted_53, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noMatchingItems")), 1),
|
|
5277
5617
|
(0, vue.createElementVNode)("button", {
|
|
5278
5618
|
type: "button",
|
|
5279
5619
|
class: "text-xs text-indigo-600 font-semibold hover:underline",
|
|
5280
5620
|
onClick: _cache[13] || (_cache[13] = ($event) => searchQuery.value = "")
|
|
5281
5621
|
}, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.clearSearch")), 1)
|
|
5282
|
-
])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
5283
|
-
_cache[
|
|
5284
|
-
(0, vue.createElementVNode)("span",
|
|
5622
|
+
])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_54, [inlineError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_55, [
|
|
5623
|
+
_cache[50] || (_cache[50] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)),
|
|
5624
|
+
(0, vue.createElementVNode)("span", _hoisted_56, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
|
|
5285
5625
|
(0, vue.createElementVNode)("button", {
|
|
5286
5626
|
type: "button",
|
|
5287
5627
|
class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
|
|
5288
5628
|
"aria-label": (0, vue.unref)(t)("common.close"),
|
|
5289
5629
|
onClick: _cache[14] || (_cache[14] = ($event) => inlineError.value = null)
|
|
5290
|
-
}, [..._cache[
|
|
5291
|
-
])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("table",
|
|
5630
|
+
}, [..._cache[49] || (_cache[49] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_57)
|
|
5631
|
+
])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("table", _hoisted_58, [(0, vue.createElementVNode)("thead", null, [(0, vue.createElementVNode)("tr", _hoisted_59, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(listColumnFields.value, ([key, field]) => {
|
|
5292
5632
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("th", {
|
|
5293
5633
|
key,
|
|
5294
5634
|
"aria-sort": (0, vue.unref)(_mulmoclaude_core_collection.isSortableField)(field) ? sortAriaValue(key) : void 0,
|
|
5295
5635
|
class: "px-5 py-3 font-bold text-slate-500 text-left uppercase tracking-wider whitespace-nowrap"
|
|
5296
|
-
}, [(0, vue.createElementVNode)("div",
|
|
5636
|
+
}, [(0, vue.createElementVNode)("div", _hoisted_61, [(0, vue.createElementVNode)("span", {
|
|
5297
5637
|
class: "truncate max-w-[14rem]",
|
|
5298
5638
|
title: field.label
|
|
5299
|
-
}, (0, vue.toDisplayString)(field.label), 9,
|
|
5639
|
+
}, (0, vue.toDisplayString)(field.label), 9, _hoisted_62), (0, vue.unref)(_mulmoclaude_core_collection.isSortableField)(field) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
5300
5640
|
key: 0,
|
|
5301
5641
|
type: "button",
|
|
5302
5642
|
class: (0, vue.normalizeClass)(["inline-flex items-center justify-center rounded p-0.5 -my-1 leading-none transition-colors", sortButtonClass(key)]),
|
|
@@ -5305,8 +5645,8 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5305
5645
|
onClick: (0, vue.withModifiers)(($event) => cycleSort(key), ["stop"]),
|
|
5306
5646
|
onPointerenter: ($event) => hoveredSortKey.value = key,
|
|
5307
5647
|
onPointerleave: _cache[15] || (_cache[15] = ($event) => hoveredSortKey.value = null)
|
|
5308
|
-
}, [(0, vue.createElementVNode)("span",
|
|
5309
|
-
}), 128))])]), (0, vue.createElementVNode)("tbody",
|
|
5648
|
+
}, [(0, vue.createElementVNode)("span", _hoisted_64, (0, vue.toDisplayString)(sortIconName(key)), 1)], 42, _hoisted_63)) : (0, vue.createCommentVNode)("", true)])], 8, _hoisted_60);
|
|
5649
|
+
}), 128))])]), (0, vue.createElementVNode)("tbody", _hoisted_65, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(sortedItems.value, (item) => {
|
|
5310
5650
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("tr", {
|
|
5311
5651
|
key: String(item[collection.value.schema.primaryKey] ?? ""),
|
|
5312
5652
|
class: (0, vue.normalizeClass)(["hover:bg-slate-50/70 cursor-pointer transition-colors focus:outline-none focus:bg-indigo-50/30", isRowOpen(item) || isEditingRow(item) ? "bg-indigo-50/40" : ""]),
|
|
@@ -5330,7 +5670,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5330
5670
|
"aria-label": field.label,
|
|
5331
5671
|
onClick: _cache[16] || (_cache[16] = (0, vue.withModifiers)(() => {}, ["stop"])),
|
|
5332
5672
|
onChange: ($event) => commitToggle(item, field)
|
|
5333
|
-
}, null, 40,
|
|
5673
|
+
}, null, 40, _hoisted_67)) : field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
|
|
5334
5674
|
key: 1,
|
|
5335
5675
|
type: "checkbox",
|
|
5336
5676
|
checked: item[key] === true,
|
|
@@ -5340,7 +5680,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5340
5680
|
"aria-label": field.label,
|
|
5341
5681
|
onClick: _cache[17] || (_cache[17] = (0, vue.withModifiers)(() => {}, ["stop"])),
|
|
5342
5682
|
onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
|
|
5343
|
-
}, null, 40,
|
|
5683
|
+
}, null, 40, _hoisted_68)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_69, [(0, vue.createElementVNode)("a", {
|
|
5344
5684
|
href: (0, vue.unref)(cui).recordHref?.(field.to, String(item[key])),
|
|
5345
5685
|
tabindex: (0, vue.unref)(cui).recordHref?.(field.to, String(item[key])) ? void 0 : 0,
|
|
5346
5686
|
role: "link",
|
|
@@ -5348,7 +5688,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5348
5688
|
"data-testid": `collections-ref-link-${key}-${item[key]}`,
|
|
5349
5689
|
onClick: ($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(item[key]), true),
|
|
5350
5690
|
onKeydown: [(0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(item[key]), true), ["enter"]), (0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(item[key]), true), ["space"])]
|
|
5351
|
-
}, (0, vue.toDisplayString)((0, vue.unref)(refDisplay)(field.to, String(item[key]))), 41,
|
|
5691
|
+
}, (0, vue.toDisplayString)((0, vue.unref)(refDisplay)(field.to, String(item[key]))), 41, _hoisted_70)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
|
|
5352
5692
|
key: 3,
|
|
5353
5693
|
value: item[key] == null ? "" : String(item[key]),
|
|
5354
5694
|
disabled: isRowInlineSaving(item),
|
|
@@ -5357,35 +5697,39 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5357
5697
|
"aria-label": field.label,
|
|
5358
5698
|
onClick: _cache[18] || (_cache[18] = (0, vue.withModifiers)(() => {}, ["stop"])),
|
|
5359
5699
|
onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
|
|
5360
|
-
}, [showEnumPlaceholder(item, String(key)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("option",
|
|
5700
|
+
}, [showEnumPlaceholder(item, String(key)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("option", _hoisted_72, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1)) : (0, vue.createCommentVNode)("", true), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.values, (value) => {
|
|
5361
5701
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
5362
5702
|
key: value,
|
|
5363
5703
|
value
|
|
5364
|
-
}, (0, vue.toDisplayString)(value), 9,
|
|
5365
|
-
}), 128))], 42,
|
|
5704
|
+
}, (0, vue.toDisplayString)(value), 9, _hoisted_73);
|
|
5705
|
+
}), 128))], 42, _hoisted_71)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_74, (0, vue.toDisplayString)((0, vue.unref)(formatMoney)(item[key], (0, vue.unref)(resolveCurrency)(field, item), (0, vue.unref)(locale))), 1)) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_75, [_cache[51] || (_cache[51] = (0, vue.createElementVNode)("span", { class: "material-icons text-[11px]" }, "list", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(tableSummary(item[key])), 1)])) : field.type === "derived" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_76, (0, vue.toDisplayString)((0, vue.unref)(derivedDisplay)(field, (0, vue.unref)(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type === "rollup" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
|
|
5366
5706
|
key: 7,
|
|
5707
|
+
class: "inline-block truncate tabular-nums font-bold text-indigo-900 bg-indigo-50/50 px-1.5 py-0.5 rounded border border-indigo-100/50",
|
|
5708
|
+
"data-testid": `collections-rollup-${key}-${item[collection.value.schema.primaryKey]}`
|
|
5709
|
+
}, (0, vue.toDisplayString)((0, vue.unref)(render).rollupDisplay(field, item)), 9, _hoisted_77)) : field.type !== "file" && (0, vue.unref)(isExternalUrl)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
5710
|
+
key: 8,
|
|
5367
5711
|
href: String(item[key]),
|
|
5368
5712
|
target: "_blank",
|
|
5369
5713
|
rel: "noopener noreferrer",
|
|
5370
5714
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5371
5715
|
"data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5372
5716
|
onClick: _cache[19] || (_cache[19] = (0, vue.withModifiers)(() => {}, ["stop"]))
|
|
5373
|
-
}, (0, vue.toDisplayString)(String(item[key])), 9,
|
|
5374
|
-
key:
|
|
5717
|
+
}, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_78)) : field.type === "file" && (0, vue.unref)(artifactUrl)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
5718
|
+
key: 9,
|
|
5375
5719
|
href: (0, vue.unref)(artifactUrl)(item[key]) ?? void 0,
|
|
5376
5720
|
target: "_blank",
|
|
5377
5721
|
rel: "noopener noreferrer",
|
|
5378
5722
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5379
5723
|
"data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5380
5724
|
onClick: _cache[20] || (_cache[20] = (0, vue.withModifiers)(() => {}, ["stop"]))
|
|
5381
|
-
}, (0, vue.toDisplayString)(String(item[key])), 9,
|
|
5382
|
-
key:
|
|
5725
|
+
}, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_79)) : field.type === "file" && (0, vue.unref)(fileRoutePath)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
|
|
5726
|
+
key: 10,
|
|
5383
5727
|
href: (0, vue.unref)(fileRoutePath)(item[key]) ?? void 0,
|
|
5384
5728
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5385
5729
|
"data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5386
5730
|
onClick: ($event) => (0, vue.unref)(activatePathLink)($event, (0, vue.unref)(fileRoutePath)(item[key]) ?? "", true)
|
|
5387
|
-
}, (0, vue.toDisplayString)(String(item[key])), 9,
|
|
5388
|
-
}), 128))], 42,
|
|
5731
|
+
}, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_80)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_81, (0, vue.toDisplayString)((0, vue.unref)(formatCell)(item[key], field.type)), 1))], 64)) : (0, vue.createCommentVNode)("", true)]);
|
|
5732
|
+
}), 128))], 42, _hoisted_66);
|
|
5389
5733
|
}), 128))])])]))]),
|
|
5390
5734
|
collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionRecordModal_default, {
|
|
5391
5735
|
key: 4,
|
|
@@ -5401,6 +5745,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5401
5745
|
"action-error": actionError.value,
|
|
5402
5746
|
"action-pending": actionPending.value,
|
|
5403
5747
|
"visible-actions": visibleActions.value,
|
|
5748
|
+
"running-action-ids": viewingRunningActionIds.value,
|
|
5404
5749
|
"live-record": liveRecord.value,
|
|
5405
5750
|
"live-derived": liveDerived.value,
|
|
5406
5751
|
"view-title": viewTitle.value,
|
|
@@ -5423,6 +5768,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5423
5768
|
"action-error",
|
|
5424
5769
|
"action-pending",
|
|
5425
5770
|
"visible-actions",
|
|
5771
|
+
"running-action-ids",
|
|
5426
5772
|
"live-record",
|
|
5427
5773
|
"live-derived",
|
|
5428
5774
|
"view-title",
|
|
@@ -5432,20 +5778,32 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5432
5778
|
])]),
|
|
5433
5779
|
_: 1
|
|
5434
5780
|
})) : (0, vue.createCommentVNode)("", true),
|
|
5781
|
+
mutateModal.value ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionMutateParamsModal_default, {
|
|
5782
|
+
key: `${mutateModal.value.action.id}-${mutateModal.value.itemId}`,
|
|
5783
|
+
action: mutateModal.value.action,
|
|
5784
|
+
pending: mutatePending.value,
|
|
5785
|
+
error: mutateError.value,
|
|
5786
|
+
onClose: _cache[23] || (_cache[23] = ($event) => mutateModal.value = null),
|
|
5787
|
+
onSubmit: submitMutateParams
|
|
5788
|
+
}, null, 8, [
|
|
5789
|
+
"action",
|
|
5790
|
+
"pending",
|
|
5791
|
+
"error"
|
|
5792
|
+
])) : (0, vue.createCommentVNode)("", true),
|
|
5435
5793
|
configOpen.value && collection.value ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionViewConfigModal_default, {
|
|
5436
|
-
key:
|
|
5794
|
+
key: 6,
|
|
5437
5795
|
slug: collection.value.slug,
|
|
5438
5796
|
title: collection.value.title,
|
|
5439
5797
|
views: customViews.value,
|
|
5440
5798
|
onChanged: onViewsChanged,
|
|
5441
|
-
onClose: _cache[
|
|
5799
|
+
onClose: _cache[24] || (_cache[24] = ($event) => configOpen.value = false)
|
|
5442
5800
|
}, null, 8, [
|
|
5443
5801
|
"slug",
|
|
5444
5802
|
"title",
|
|
5445
5803
|
"views"
|
|
5446
5804
|
])) : (0, vue.createCommentVNode)("", true),
|
|
5447
5805
|
chatOpen.value && collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
5448
|
-
key:
|
|
5806
|
+
key: 7,
|
|
5449
5807
|
class: "fixed inset-0 z-30 flex items-center justify-center bg-slate-900/60 backdrop-blur-sm p-4 transition-all duration-300",
|
|
5450
5808
|
role: "dialog",
|
|
5451
5809
|
"aria-modal": "true",
|
|
@@ -5453,29 +5811,29 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5453
5811
|
"data-testid": "collections-chat-modal",
|
|
5454
5812
|
onClick: (0, vue.withModifiers)(closeChat, ["self"]),
|
|
5455
5813
|
onKeydown: (0, vue.withKeys)(closeChat, ["esc"])
|
|
5456
|
-
}, [(0, vue.createElementVNode)("div",
|
|
5457
|
-
(0, vue.createElementVNode)("header",
|
|
5458
|
-
_cache[
|
|
5459
|
-
(0, vue.createElementVNode)("div",
|
|
5814
|
+
}, [(0, vue.createElementVNode)("div", _hoisted_82, [
|
|
5815
|
+
(0, vue.createElementVNode)("header", _hoisted_83, [
|
|
5816
|
+
_cache[53] || (_cache[53] = (0, vue.createElementVNode)("div", { class: "h-9 w-9 flex items-center justify-center rounded-xl bg-indigo-50 text-indigo-600 border border-indigo-100/50" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "forum")], -1)),
|
|
5817
|
+
(0, vue.createElementVNode)("div", _hoisted_84, [(0, vue.createElementVNode)("h2", _hoisted_85, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatTitle")), 1), (0, vue.createElementVNode)("span", _hoisted_86, (0, vue.toDisplayString)(collection.value.title), 1)]),
|
|
5460
5818
|
(0, vue.createElementVNode)("button", {
|
|
5461
5819
|
type: "button",
|
|
5462
5820
|
class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-200/50 hover:text-slate-600 transition-colors",
|
|
5463
5821
|
"aria-label": (0, vue.unref)(t)("common.close"),
|
|
5464
5822
|
"data-testid": "collections-chat-close",
|
|
5465
5823
|
onClick: closeChat
|
|
5466
|
-
}, [..._cache[
|
|
5824
|
+
}, [..._cache[52] || (_cache[52] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_87)
|
|
5467
5825
|
]),
|
|
5468
|
-
(0, vue.createElementVNode)("div",
|
|
5826
|
+
(0, vue.createElementVNode)("div", _hoisted_88, [(0, vue.withDirectives)((0, vue.createElementVNode)("textarea", {
|
|
5469
5827
|
ref_key: "chatInputEl",
|
|
5470
5828
|
ref: chatInputEl,
|
|
5471
|
-
"onUpdate:modelValue": _cache[
|
|
5829
|
+
"onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => chatMessage.value = $event),
|
|
5472
5830
|
rows: "4",
|
|
5473
5831
|
placeholder: (0, vue.unref)(t)("collectionsView.chatPlaceholder"),
|
|
5474
5832
|
class: "w-full bg-slate-50 border border-slate-200/80 rounded-xl px-3 py-2.5 text-sm placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 focus:bg-white transition-all resize-none",
|
|
5475
5833
|
"data-testid": "collections-chat-input",
|
|
5476
5834
|
onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(submitChat, ["meta"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(submitChat, ["ctrl"]), ["enter"])]
|
|
5477
|
-
}, null, 40,
|
|
5478
|
-
(0, vue.createElementVNode)("footer",
|
|
5835
|
+
}, null, 40, _hoisted_89), [[vue.vModelText, chatMessage.value]])]),
|
|
5836
|
+
(0, vue.createElementVNode)("footer", _hoisted_90, [(0, vue.createElementVNode)("button", {
|
|
5479
5837
|
type: "button",
|
|
5480
5838
|
class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
|
|
5481
5839
|
"data-testid": "collections-chat-cancel",
|
|
@@ -5486,7 +5844,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
5486
5844
|
disabled: !chatMessage.value.trim(),
|
|
5487
5845
|
"data-testid": "collections-chat-send",
|
|
5488
5846
|
onClick: submitChat
|
|
5489
|
-
}, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatStart")), 9,
|
|
5847
|
+
}, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatStart")), 9, _hoisted_91)])
|
|
5490
5848
|
])], 32)) : (0, vue.createCommentVNode)("", true)
|
|
5491
5849
|
]);
|
|
5492
5850
|
};
|