@mulmoclaude/collection-plugin 0.7.6 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +26 -0
- package/dist/vue/components/CollectionBacklinksView.vue.d.ts +9 -0
- package/dist/vue/components/CollectionBacklinksView.vue.d.ts.map +1 -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 +12 -1
- package/dist/vue/useCollectionRendering.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.helpers.d.ts +12 -0
- package/dist/vue/useCollectionRendering.helpers.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.renderers.d.ts +28 -2
- package/dist/vue/useCollectionRendering.renderers.d.ts.map +1 -1
- package/dist/vue/useLinkedCollectionCaches.d.ts +5 -1
- package/dist/vue/useLinkedCollectionCaches.d.ts.map +1 -1
- package/dist/vue.cjs +968 -474
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +970 -476
- package/dist/vue.js.map +1 -1
- package/package.json +3 -3
package/dist/vue.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MINUTES_PER_DAY, TOOL_DEFINITION, actionVisible, assignLanes, boolSortValue, bucketRecords, buildMonthGrid, buildUpdatedRecord, coerceInlineValue, dateOf, dateSortValue, daySlice, defangForPrompt, deriveAll, draftToRecord, embedTargetId, emptyRow, enumSortValue, errorMessage, executePresentCollection, fieldVisible, firstMissingRequiredField, isSortableField, itemIdOf, itemLabelOf, labelFieldFor, nextSortDirection, numericSortValue, resolveEnumColor, rowFromItem, shortHexId, sortItems, stringSortValue, ymdKey } from "@mulmoclaude/core/collection";
|
|
2
|
-
import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, effectScope, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onUnmounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useModel, vModelCheckbox, vModelDynamic, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
1
|
+
import { COMPUTED_TYPES, MINUTES_PER_DAY, TOOL_DEFINITION, actionVisible, agentActionRunKey, assignLanes, backlinkRows, boolSortValue, bucketRecords, buildMonthGrid, buildUpdatedRecord, coerceInlineValue, dateOf, dateSortValue, daySlice, defangForPrompt, deriveAll, draftToRecord, embedTargetId, emptyRow, enumSortValue, errorMessage, executePresentCollection, fieldVisible, firstMissingRequiredField, isSortableField, itemIdOf, itemLabelOf, labelFieldFor, nextSortDirection, numericSortValue, resolveEnumColor, rollupValue, rowFromItem, shortHexId, sortItems, stringSortValue, ymdKey } from "@mulmoclaude/core/collection";
|
|
2
|
+
import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, effectScope, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onUnmounted, openBlock, reactive, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useModel, vModelCheckbox, vModelDynamic, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
3
3
|
import { createI18n } from "vue-i18n";
|
|
4
4
|
import draggable from "vuedraggable";
|
|
5
5
|
import { REMOTE_VIEW_MAX_BYTES, handleRemoteViewMessage } from "@mulmoclaude/core/remote-view";
|
|
@@ -1209,19 +1209,351 @@ var CollectionRecordModal_default = /* @__PURE__ */ defineComponent({
|
|
|
1209
1209
|
}
|
|
1210
1210
|
});
|
|
1211
1211
|
//#endregion
|
|
1212
|
+
//#region src/vue/useCollectionRendering.helpers.ts
|
|
1213
|
+
var EM_DASH = "—";
|
|
1214
|
+
var DEFAULT_CURRENCY = "USD";
|
|
1215
|
+
var MARKDOWN_CELL_PREVIEW_MAX = 80;
|
|
1216
|
+
function stepForFieldType(type) {
|
|
1217
|
+
if (type === "money") return "0.01";
|
|
1218
|
+
if (type === "number") return "any";
|
|
1219
|
+
}
|
|
1220
|
+
function inputTypeFor(type) {
|
|
1221
|
+
if (type === "email") return "email";
|
|
1222
|
+
if (type === "number") return "number";
|
|
1223
|
+
if (type === "money") return "number";
|
|
1224
|
+
if (type === "date") return "date";
|
|
1225
|
+
if (type === "datetime") return "datetime-local";
|
|
1226
|
+
return "text";
|
|
1227
|
+
}
|
|
1228
|
+
function isExternalUrl(value) {
|
|
1229
|
+
return typeof value === "string" && /^https?:\/\//i.test(value);
|
|
1230
|
+
}
|
|
1231
|
+
function detailText(value) {
|
|
1232
|
+
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
1233
|
+
return String(value);
|
|
1234
|
+
}
|
|
1235
|
+
function formatCell(value, type) {
|
|
1236
|
+
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
1237
|
+
if (type === "markdown" && typeof value === "string") return value.length > MARKDOWN_CELL_PREVIEW_MAX ? `${value.slice(0, MARKDOWN_CELL_PREVIEW_MAX)}…` : value;
|
|
1238
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
1239
|
+
return JSON.stringify(value);
|
|
1240
|
+
}
|
|
1241
|
+
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
1242
|
+
* `currencyField` (when present and non-blank) wins over the field's
|
|
1243
|
+
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
1244
|
+
* keys; any other field resolves to undefined (the formatter's USD
|
|
1245
|
+
* fallback), as before. */
|
|
1246
|
+
function resolveCurrency(field, record) {
|
|
1247
|
+
if (field.type !== "money" && field.type !== "derived") return void 0;
|
|
1248
|
+
if (field.currencyField && record) {
|
|
1249
|
+
const code = record[field.currencyField];
|
|
1250
|
+
if (typeof code === "string" && code.trim().length > 0) return code;
|
|
1251
|
+
}
|
|
1252
|
+
return field.currency;
|
|
1253
|
+
}
|
|
1254
|
+
function formatMoney(value, currency, displayLocale) {
|
|
1255
|
+
if (value === void 0 || value === "") return EM_DASH;
|
|
1256
|
+
const amount = typeof value === "number" ? value : Number(value);
|
|
1257
|
+
if (!Number.isFinite(amount)) return String(value);
|
|
1258
|
+
const currencyCode = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
1259
|
+
try {
|
|
1260
|
+
return new Intl.NumberFormat(displayLocale, {
|
|
1261
|
+
style: "currency",
|
|
1262
|
+
currency: currencyCode
|
|
1263
|
+
}).format(amount);
|
|
1264
|
+
} catch {
|
|
1265
|
+
return String(amount);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
function currencySymbolForLocale(currency, locale) {
|
|
1269
|
+
const code = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
1270
|
+
try {
|
|
1271
|
+
return new Intl.NumberFormat(locale, {
|
|
1272
|
+
style: "currency",
|
|
1273
|
+
currency: code
|
|
1274
|
+
}).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
|
|
1275
|
+
} catch {
|
|
1276
|
+
return code;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
function tableRows(value) {
|
|
1280
|
+
if (!Array.isArray(value)) return [];
|
|
1281
|
+
return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
|
|
1282
|
+
}
|
|
1283
|
+
function hasTableRows(value) {
|
|
1284
|
+
return tableRows(value).length > 0;
|
|
1285
|
+
}
|
|
1286
|
+
/** Pick the field used to label a referenced/embedded record: prefer a
|
|
1287
|
+
* `name` field, then `title`, else fall back to the primary key. */
|
|
1288
|
+
function displayFieldFor(fields, primaryKey) {
|
|
1289
|
+
if ("name" in fields) return "name";
|
|
1290
|
+
if ("title" in fields) return "title";
|
|
1291
|
+
return primaryKey;
|
|
1292
|
+
}
|
|
1293
|
+
function uniqueRefTargets(schema) {
|
|
1294
|
+
const targets = /* @__PURE__ */ new Set();
|
|
1295
|
+
const walk = (fields) => {
|
|
1296
|
+
for (const field of Object.values(fields)) {
|
|
1297
|
+
if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
1298
|
+
if (field.type === "table" && field.of) walk(field.of);
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
walk(schema.fields);
|
|
1302
|
+
return [...targets];
|
|
1303
|
+
}
|
|
1304
|
+
function uniqueEmbedTargets(schema) {
|
|
1305
|
+
const targets = /* @__PURE__ */ new Set();
|
|
1306
|
+
for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
1307
|
+
return [...targets];
|
|
1308
|
+
}
|
|
1309
|
+
/** Slugs of every SOURCE collection a `backlinks` or `rollup` field
|
|
1310
|
+
* reverses over (the two share one load). Top-level only, like `embed`
|
|
1311
|
+
* (the schema rejects both inside a table's `of`). Mirrors the server's
|
|
1312
|
+
* `uniqueBacklinkSources`. */
|
|
1313
|
+
function uniqueBacklinkSources(schema) {
|
|
1314
|
+
const sources = /* @__PURE__ */ new Set();
|
|
1315
|
+
for (const field of Object.values(schema.fields)) if ((field.type === "backlinks" || field.type === "rollup") && field.from.length > 0) sources.add(field.from);
|
|
1316
|
+
return [...sources];
|
|
1317
|
+
}
|
|
1318
|
+
function buildRefDisplayMap(detail) {
|
|
1319
|
+
const { fields, primaryKey } = detail.collection.schema;
|
|
1320
|
+
const displayField = displayFieldFor(fields, primaryKey);
|
|
1321
|
+
const map = {};
|
|
1322
|
+
for (const item of detail.items) {
|
|
1323
|
+
const slugRaw = item[primaryKey];
|
|
1324
|
+
if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
|
|
1325
|
+
const displayRaw = item[displayField];
|
|
1326
|
+
map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
|
|
1327
|
+
}
|
|
1328
|
+
return map;
|
|
1329
|
+
}
|
|
1330
|
+
/** Index DERIVED records by primary key — the client mirror of the
|
|
1331
|
+
* server's `loadTarget` indexing: string non-empty ids only, one record
|
|
1332
|
+
* per id (a duplicate keeps the LAST record in its FIRST position —
|
|
1333
|
+
* plain-object key semantics). Shared by the ref-record cache and the
|
|
1334
|
+
* backlinks view so every client consumer agrees with server enrichment
|
|
1335
|
+
* on which source records exist. */
|
|
1336
|
+
function derivedRecordsById(schema, items) {
|
|
1337
|
+
const map = {};
|
|
1338
|
+
for (const item of items) {
|
|
1339
|
+
const slugRaw = item[schema.primaryKey];
|
|
1340
|
+
if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
|
|
1341
|
+
}
|
|
1342
|
+
return map;
|
|
1343
|
+
}
|
|
1344
|
+
function buildRefRecordMap(detail) {
|
|
1345
|
+
return derivedRecordsById(detail.collection.schema, detail.items);
|
|
1346
|
+
}
|
|
1347
|
+
function sortedRefOptions(map) {
|
|
1348
|
+
return Object.entries(map).map(([slug, display]) => ({
|
|
1349
|
+
slug,
|
|
1350
|
+
display
|
|
1351
|
+
})).sort((left, right) => left.display.localeCompare(right.display));
|
|
1352
|
+
}
|
|
1353
|
+
/** Dropdown options for an `embed` field's per-record picker: every
|
|
1354
|
+
* record in the target collection, labelled by its name/title (or
|
|
1355
|
+
* primary key), skipping records without a slug and sorted by label. */
|
|
1356
|
+
function buildEmbedOptions(schema, items) {
|
|
1357
|
+
const { fields, primaryKey } = schema;
|
|
1358
|
+
const displayField = displayFieldFor(fields, primaryKey);
|
|
1359
|
+
return items.map((item) => {
|
|
1360
|
+
const slug = String(item[primaryKey] ?? "");
|
|
1361
|
+
const labelRaw = item[displayField];
|
|
1362
|
+
return {
|
|
1363
|
+
slug,
|
|
1364
|
+
display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
|
|
1365
|
+
};
|
|
1366
|
+
}).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
|
|
1367
|
+
}
|
|
1368
|
+
//#endregion
|
|
1369
|
+
//#region src/vue/components/CollectionMutateParamsModal.vue?vue&type=script&setup=true&lang.ts
|
|
1370
|
+
var _hoisted_1$16 = { class: "flex items-center justify-between px-6 pt-5 pb-3" };
|
|
1371
|
+
var _hoisted_2$15 = { class: "text-sm font-bold text-slate-800 flex items-center gap-1.5" };
|
|
1372
|
+
var _hoisted_3$15 = {
|
|
1373
|
+
key: 0,
|
|
1374
|
+
class: "material-icons text-base text-indigo-600"
|
|
1375
|
+
};
|
|
1376
|
+
var _hoisted_4$15 = ["aria-label"];
|
|
1377
|
+
var _hoisted_5$14 = { class: "flex flex-col gap-4 px-6 pb-2" };
|
|
1378
|
+
var _hoisted_6$13 = ["for"];
|
|
1379
|
+
var _hoisted_7$11 = {
|
|
1380
|
+
key: 0,
|
|
1381
|
+
class: "text-rose-500 font-bold"
|
|
1382
|
+
};
|
|
1383
|
+
var _hoisted_8$11 = {
|
|
1384
|
+
key: 0,
|
|
1385
|
+
class: "inline-flex items-center gap-2.5 cursor-pointer select-none"
|
|
1386
|
+
};
|
|
1387
|
+
var _hoisted_9$11 = [
|
|
1388
|
+
"id",
|
|
1389
|
+
"onUpdate:modelValue",
|
|
1390
|
+
"data-testid",
|
|
1391
|
+
"onChange"
|
|
1392
|
+
];
|
|
1393
|
+
var _hoisted_10$11 = [
|
|
1394
|
+
"id",
|
|
1395
|
+
"onUpdate:modelValue",
|
|
1396
|
+
"required",
|
|
1397
|
+
"data-testid"
|
|
1398
|
+
];
|
|
1399
|
+
var _hoisted_11$11 = { value: "" };
|
|
1400
|
+
var _hoisted_12$10 = ["value"];
|
|
1401
|
+
var _hoisted_13$9 = [
|
|
1402
|
+
"id",
|
|
1403
|
+
"onUpdate:modelValue",
|
|
1404
|
+
"required",
|
|
1405
|
+
"data-testid"
|
|
1406
|
+
];
|
|
1407
|
+
var _hoisted_14$8 = [
|
|
1408
|
+
"id",
|
|
1409
|
+
"onUpdate:modelValue",
|
|
1410
|
+
"type",
|
|
1411
|
+
"step",
|
|
1412
|
+
"required",
|
|
1413
|
+
"data-testid"
|
|
1414
|
+
];
|
|
1415
|
+
var _hoisted_15$8 = {
|
|
1416
|
+
key: 0,
|
|
1417
|
+
class: "text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl",
|
|
1418
|
+
"data-testid": "collections-mutate-error"
|
|
1419
|
+
};
|
|
1420
|
+
var _hoisted_16$7 = { class: "flex items-center justify-end gap-2 px-6 py-4" };
|
|
1421
|
+
var _hoisted_17$7 = ["disabled"];
|
|
1422
|
+
var _hoisted_18$6 = {
|
|
1423
|
+
key: 0,
|
|
1424
|
+
class: "material-icons text-sm animate-spin"
|
|
1425
|
+
};
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region src/vue/components/CollectionMutateParamsModal.vue
|
|
1428
|
+
var CollectionMutateParamsModal_default = /* @__PURE__ */ defineComponent({
|
|
1429
|
+
__name: "CollectionMutateParamsModal",
|
|
1430
|
+
props: {
|
|
1431
|
+
action: {},
|
|
1432
|
+
pending: { type: Boolean },
|
|
1433
|
+
error: {}
|
|
1434
|
+
},
|
|
1435
|
+
emits: ["close", "submit"],
|
|
1436
|
+
setup(__props, { emit: __emit }) {
|
|
1437
|
+
const props = __props;
|
|
1438
|
+
const emit = __emit;
|
|
1439
|
+
const { t } = useCollectionI18n();
|
|
1440
|
+
const text = reactive({});
|
|
1441
|
+
const bool = reactive({});
|
|
1442
|
+
const boolTouched = reactive({});
|
|
1443
|
+
for (const [key, spec] of Object.entries(props.action.params ?? {})) if (spec.type === "boolean") bool[key] = false;
|
|
1444
|
+
else text[key] = "";
|
|
1445
|
+
/** Convert the draft to the submitted params: numbers parsed, booleans
|
|
1446
|
+
* included only when touched or required, empty optionals OMITTED (the
|
|
1447
|
+
* server treats an absent param as "don't write" for `$params` refs —
|
|
1448
|
+
* merge semantics). */
|
|
1449
|
+
function submit() {
|
|
1450
|
+
const params = {};
|
|
1451
|
+
for (const [key, spec] of Object.entries(props.action.params ?? {})) {
|
|
1452
|
+
if (spec.type === "boolean") {
|
|
1453
|
+
if (boolTouched[key] || spec.required) params[key] = bool[key] === true;
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
const raw = (text[key] ?? "").trim();
|
|
1457
|
+
if (raw === "") continue;
|
|
1458
|
+
if (spec.type === "number" || spec.type === "money") {
|
|
1459
|
+
const num = Number(raw);
|
|
1460
|
+
params[key] = Number.isFinite(num) ? num : raw;
|
|
1461
|
+
continue;
|
|
1462
|
+
}
|
|
1463
|
+
params[key] = raw;
|
|
1464
|
+
}
|
|
1465
|
+
emit("submit", params);
|
|
1466
|
+
}
|
|
1467
|
+
return (_ctx, _cache) => {
|
|
1468
|
+
return openBlock(), createBlock(CollectionRecordModal_default, { onClose: _cache[2] || (_cache[2] = ($event) => emit("close")) }, {
|
|
1469
|
+
default: withCtx(() => [createElementVNode("form", {
|
|
1470
|
+
class: "flex flex-col overflow-y-auto",
|
|
1471
|
+
"data-testid": "collections-mutate-modal",
|
|
1472
|
+
onSubmit: withModifiers(submit, ["prevent"])
|
|
1473
|
+
}, [
|
|
1474
|
+
createElementVNode("div", _hoisted_1$16, [createElementVNode("h2", _hoisted_2$15, [__props.action.icon ? (openBlock(), createElementBlock("span", _hoisted_3$15, toDisplayString(__props.action.icon), 1)) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(__props.action.label), 1)]), createElementVNode("button", {
|
|
1475
|
+
type: "button",
|
|
1476
|
+
class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors",
|
|
1477
|
+
"aria-label": unref(t)("common.close"),
|
|
1478
|
+
"data-testid": "collections-mutate-close",
|
|
1479
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
|
|
1480
|
+
}, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_4$15)]),
|
|
1481
|
+
createElementVNode("div", _hoisted_5$14, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.action.params, (spec, key) => {
|
|
1482
|
+
return openBlock(), createElementBlock("div", {
|
|
1483
|
+
key,
|
|
1484
|
+
class: "flex flex-col gap-1.5"
|
|
1485
|
+
}, [createElementVNode("label", {
|
|
1486
|
+
class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider",
|
|
1487
|
+
for: `collections-mutate-${key}`
|
|
1488
|
+
}, [createTextVNode(toDisplayString(spec.label) + " ", 1), spec.required ? (openBlock(), createElementBlock("span", _hoisted_7$11, "*")) : createCommentVNode("", true)], 8, _hoisted_6$13), spec.type === "boolean" ? (openBlock(), createElementBlock("label", _hoisted_8$11, [withDirectives(createElementVNode("input", {
|
|
1489
|
+
id: `collections-mutate-${key}`,
|
|
1490
|
+
"onUpdate:modelValue": ($event) => bool[key] = $event,
|
|
1491
|
+
type: "checkbox",
|
|
1492
|
+
class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
1493
|
+
"data-testid": `collections-mutate-input-${key}`,
|
|
1494
|
+
onChange: ($event) => boolTouched[String(key)] = true
|
|
1495
|
+
}, null, 40, _hoisted_9$11), [[vModelCheckbox, bool[key]]]), createElementVNode("span", { class: normalizeClass(["text-xs font-semibold", bool[key] ? "text-indigo-600" : "text-slate-500"]) }, toDisplayString(bool[key] ? unref(t)("common.yes") : unref(t)("common.no")), 3)])) : spec.type === "enum" ? withDirectives((openBlock(), createElementBlock("select", {
|
|
1496
|
+
key: 1,
|
|
1497
|
+
id: `collections-mutate-${key}`,
|
|
1498
|
+
"onUpdate:modelValue": ($event) => text[key] = $event,
|
|
1499
|
+
required: spec.required,
|
|
1500
|
+
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",
|
|
1501
|
+
"data-testid": `collections-mutate-input-${key}`
|
|
1502
|
+
}, [createElementVNode("option", _hoisted_11$11, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(spec.values, (value) => {
|
|
1503
|
+
return openBlock(), createElementBlock("option", {
|
|
1504
|
+
key: value,
|
|
1505
|
+
value
|
|
1506
|
+
}, toDisplayString(value), 9, _hoisted_12$10);
|
|
1507
|
+
}), 128))], 8, _hoisted_10$11)), [[vModelSelect, text[key]]]) : spec.type === "text" || spec.type === "markdown" ? withDirectives((openBlock(), createElementBlock("textarea", {
|
|
1508
|
+
key: 2,
|
|
1509
|
+
id: `collections-mutate-${key}`,
|
|
1510
|
+
"onUpdate:modelValue": ($event) => text[key] = $event,
|
|
1511
|
+
required: spec.required,
|
|
1512
|
+
rows: "3",
|
|
1513
|
+
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",
|
|
1514
|
+
"data-testid": `collections-mutate-input-${key}`
|
|
1515
|
+
}, null, 8, _hoisted_13$9)), [[vModelText, text[key]]]) : withDirectives((openBlock(), createElementBlock("input", {
|
|
1516
|
+
key: 3,
|
|
1517
|
+
id: `collections-mutate-${key}`,
|
|
1518
|
+
"onUpdate:modelValue": ($event) => text[key] = $event,
|
|
1519
|
+
type: unref(inputTypeFor)(spec.type),
|
|
1520
|
+
step: unref(stepForFieldType)(spec.type),
|
|
1521
|
+
required: spec.required,
|
|
1522
|
+
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",
|
|
1523
|
+
"data-testid": `collections-mutate-input-${key}`
|
|
1524
|
+
}, null, 8, _hoisted_14$8)), [[vModelDynamic, text[key]]])]);
|
|
1525
|
+
}), 128)), __props.error ? (openBlock(), createElementBlock("p", _hoisted_15$8, toDisplayString(__props.error), 1)) : createCommentVNode("", true)]),
|
|
1526
|
+
createElementVNode("div", _hoisted_16$7, [createElementVNode("button", {
|
|
1527
|
+
type: "button",
|
|
1528
|
+
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",
|
|
1529
|
+
"data-testid": "collections-mutate-cancel",
|
|
1530
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
|
|
1531
|
+
}, toDisplayString(unref(t)("common.cancel")), 1), createElementVNode("button", {
|
|
1532
|
+
type: "submit",
|
|
1533
|
+
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",
|
|
1534
|
+
disabled: __props.pending,
|
|
1535
|
+
"data-testid": "collections-mutate-submit"
|
|
1536
|
+
}, [__props.pending ? (openBlock(), createElementBlock("span", _hoisted_18$6, "progress_activity")) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(__props.action.label), 1)], 8, _hoisted_17$7)])
|
|
1537
|
+
], 32)]),
|
|
1538
|
+
_: 1
|
|
1539
|
+
});
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
//#endregion
|
|
1212
1544
|
//#region src/vue/components/CollectionCalendarView.vue?vue&type=script&setup=true&lang.ts
|
|
1213
|
-
var _hoisted_1$
|
|
1545
|
+
var _hoisted_1$15 = {
|
|
1214
1546
|
class: "flex flex-col gap-3",
|
|
1215
1547
|
"data-testid": "collection-calendar"
|
|
1216
1548
|
};
|
|
1217
|
-
var _hoisted_2$
|
|
1218
|
-
var _hoisted_3$
|
|
1219
|
-
var _hoisted_4$
|
|
1220
|
-
var _hoisted_5$
|
|
1549
|
+
var _hoisted_2$14 = { class: "flex items-center gap-2" };
|
|
1550
|
+
var _hoisted_3$14 = ["aria-label"];
|
|
1551
|
+
var _hoisted_4$14 = ["aria-label"];
|
|
1552
|
+
var _hoisted_5$13 = {
|
|
1221
1553
|
class: "text-sm font-bold text-slate-800 flex-1",
|
|
1222
1554
|
"data-testid": "collection-calendar-month"
|
|
1223
1555
|
};
|
|
1224
|
-
var _hoisted_6$
|
|
1556
|
+
var _hoisted_6$12 = { class: "grid grid-cols-7 gap-1 text-[10px] font-bold text-slate-400 uppercase tracking-wider select-none" };
|
|
1225
1557
|
var _hoisted_7$10 = { class: "grid grid-cols-7 gap-1" };
|
|
1226
1558
|
var _hoisted_8$10 = [
|
|
1227
1559
|
"aria-label",
|
|
@@ -1351,23 +1683,23 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
|
|
|
1351
1683
|
viewMonth.value = now.getMonth() + 1;
|
|
1352
1684
|
}
|
|
1353
1685
|
return (_ctx, _cache) => {
|
|
1354
|
-
return openBlock(), createElementBlock("div", _hoisted_1$
|
|
1355
|
-
createElementVNode("div", _hoisted_2$
|
|
1686
|
+
return openBlock(), createElementBlock("div", _hoisted_1$15, [
|
|
1687
|
+
createElementVNode("div", _hoisted_2$14, [
|
|
1356
1688
|
createElementVNode("button", {
|
|
1357
1689
|
type: "button",
|
|
1358
1690
|
class: "h-8 w-8 flex items-center justify-center rounded text-slate-500 hover:bg-slate-100 transition-colors",
|
|
1359
1691
|
"aria-label": unref(t)("collectionsView.calendarPrevMonth"),
|
|
1360
1692
|
"data-testid": "collection-calendar-prev",
|
|
1361
1693
|
onClick: _cache[0] || (_cache[0] = ($event) => stepMonth(-1))
|
|
1362
|
-
}, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_left", -1)])], 8, _hoisted_3$
|
|
1694
|
+
}, [..._cache[2] || (_cache[2] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_left", -1)])], 8, _hoisted_3$14),
|
|
1363
1695
|
createElementVNode("button", {
|
|
1364
1696
|
type: "button",
|
|
1365
1697
|
class: "h-8 w-8 flex items-center justify-center rounded text-slate-500 hover:bg-slate-100 transition-colors",
|
|
1366
1698
|
"aria-label": unref(t)("collectionsView.calendarNextMonth"),
|
|
1367
1699
|
"data-testid": "collection-calendar-next",
|
|
1368
1700
|
onClick: _cache[1] || (_cache[1] = ($event) => stepMonth(1))
|
|
1369
|
-
}, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_right", -1)])], 8, _hoisted_4$
|
|
1370
|
-
createElementVNode("h3", _hoisted_5$
|
|
1701
|
+
}, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "chevron_right", -1)])], 8, _hoisted_4$14),
|
|
1702
|
+
createElementVNode("h3", _hoisted_5$13, toDisplayString(monthLabel.value), 1),
|
|
1371
1703
|
createElementVNode("button", {
|
|
1372
1704
|
type: "button",
|
|
1373
1705
|
class: "h-8 px-2.5 flex items-center gap-1 rounded border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 text-xs font-bold transition-colors",
|
|
@@ -1375,7 +1707,7 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
|
|
|
1375
1707
|
onClick: goToday
|
|
1376
1708
|
}, toDisplayString(unref(t)("collectionsView.calendarToday")), 1)
|
|
1377
1709
|
]),
|
|
1378
|
-
createElementVNode("div", _hoisted_6$
|
|
1710
|
+
createElementVNode("div", _hoisted_6$12, [(openBlock(true), createElementBlock(Fragment, null, renderList(weekdayLabels.value, (label, idx) => {
|
|
1379
1711
|
return openBlock(), createElementBlock("div", {
|
|
1380
1712
|
key: idx,
|
|
1381
1713
|
class: "px-1 py-1 text-center"
|
|
@@ -1416,18 +1748,18 @@ var CollectionCalendarView_default = /* @__PURE__ */ defineComponent({
|
|
|
1416
1748
|
});
|
|
1417
1749
|
//#endregion
|
|
1418
1750
|
//#region src/vue/components/CollectionDayView.vue?vue&type=script&setup=true&lang.ts
|
|
1419
|
-
var _hoisted_1$
|
|
1420
|
-
var _hoisted_2$
|
|
1751
|
+
var _hoisted_1$14 = { class: "flex items-center gap-2 border-b border-slate-200 px-4 py-3" };
|
|
1752
|
+
var _hoisted_2$13 = {
|
|
1421
1753
|
class: "flex-1 text-sm font-bold text-slate-800",
|
|
1422
1754
|
"data-testid": "collection-day-view-title"
|
|
1423
1755
|
};
|
|
1424
|
-
var _hoisted_3$
|
|
1425
|
-
var _hoisted_4$
|
|
1426
|
-
var _hoisted_5$
|
|
1756
|
+
var _hoisted_3$13 = ["aria-label"];
|
|
1757
|
+
var _hoisted_4$13 = ["aria-label"];
|
|
1758
|
+
var _hoisted_5$12 = {
|
|
1427
1759
|
key: 0,
|
|
1428
1760
|
class: "px-4 py-10 text-center text-sm text-slate-400"
|
|
1429
1761
|
};
|
|
1430
|
-
var _hoisted_6$
|
|
1762
|
+
var _hoisted_6$11 = { class: "absolute -top-2 left-0 w-10 pr-1 text-right text-[10px] tabular-nums text-slate-400" };
|
|
1431
1763
|
var _hoisted_7$9 = {
|
|
1432
1764
|
class: "absolute inset-y-0 right-0",
|
|
1433
1765
|
style: { "left": "2.75rem" }
|
|
@@ -1513,6 +1845,8 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
|
|
|
1513
1845
|
"datetime",
|
|
1514
1846
|
"table",
|
|
1515
1847
|
"embed",
|
|
1848
|
+
"backlinks",
|
|
1849
|
+
"rollup",
|
|
1516
1850
|
"image",
|
|
1517
1851
|
"markdown"
|
|
1518
1852
|
]);
|
|
@@ -1608,8 +1942,8 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
|
|
|
1608
1942
|
role: "dialog",
|
|
1609
1943
|
"aria-modal": "true"
|
|
1610
1944
|
}, [createElementVNode("div", { class: normalizeClass(["flex min-h-0 flex-col", __props.showDetail ? "w-80 shrink-0 border-r border-slate-200" : "w-full"]) }, [
|
|
1611
|
-
createElementVNode("div", _hoisted_1$
|
|
1612
|
-
createElementVNode("h3", _hoisted_2$
|
|
1945
|
+
createElementVNode("div", _hoisted_1$14, [
|
|
1946
|
+
createElementVNode("h3", _hoisted_2$13, toDisplayString(dayLabel.value), 1),
|
|
1613
1947
|
__props.canCreate ? (openBlock(), createElementBlock("button", {
|
|
1614
1948
|
key: 0,
|
|
1615
1949
|
type: "button",
|
|
@@ -1617,16 +1951,16 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
|
|
|
1617
1951
|
"aria-label": unref(t)("collectionsView.calendarCreateOn", { date: dayKey.value }),
|
|
1618
1952
|
"data-testid": "collection-day-view-create",
|
|
1619
1953
|
onClick: onCreate
|
|
1620
|
-
}, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "add", -1)])], 8, _hoisted_3$
|
|
1954
|
+
}, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "material-icons text-lg" }, "add", -1)])], 8, _hoisted_3$13)) : createCommentVNode("", true),
|
|
1621
1955
|
createElementVNode("button", {
|
|
1622
1956
|
type: "button",
|
|
1623
1957
|
class: "h-8 w-8 flex items-center justify-center rounded text-slate-500 hover:bg-slate-100 transition-colors",
|
|
1624
1958
|
"aria-label": unref(t)("collectionsView.dayViewClose"),
|
|
1625
1959
|
"data-testid": "collection-day-view-close",
|
|
1626
1960
|
onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
|
|
1627
|
-
}, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_4$
|
|
1961
|
+
}, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_4$13)
|
|
1628
1962
|
]),
|
|
1629
|
-
timedEntries.value.length === 0 && allDayEntries.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_5$
|
|
1963
|
+
timedEntries.value.length === 0 && allDayEntries.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_5$12, toDisplayString(unref(t)("collectionsView.dayViewEmpty")), 1)) : (openBlock(), createElementBlock("div", {
|
|
1630
1964
|
key: 1,
|
|
1631
1965
|
ref_key: "scrollEl",
|
|
1632
1966
|
ref: scrollEl,
|
|
@@ -1640,7 +1974,7 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
|
|
|
1640
1974
|
key: hour,
|
|
1641
1975
|
class: "absolute left-0 right-0 border-t border-slate-100",
|
|
1642
1976
|
style: normalizeStyle({ top: `${(hour - 1) * HOUR_PX}px` })
|
|
1643
|
-
}, [createElementVNode("span", _hoisted_6$
|
|
1977
|
+
}, [createElementVNode("span", _hoisted_6$11, toDisplayString(hourLabel(hour - 1)), 1)], 4);
|
|
1644
1978
|
}), 64)), createElementVNode("div", _hoisted_7$9, [(openBlock(true), createElementBlock(Fragment, null, renderList(timedEntries.value, (entry) => {
|
|
1645
1979
|
return openBlock(), createElementBlock("button", {
|
|
1646
1980
|
key: entry.id,
|
|
@@ -1675,15 +2009,15 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
|
|
|
1675
2009
|
});
|
|
1676
2010
|
//#endregion
|
|
1677
2011
|
//#region src/vue/components/CollectionKanbanView.vue?vue&type=script&setup=true&lang.ts
|
|
1678
|
-
var _hoisted_1$
|
|
2012
|
+
var _hoisted_1$13 = {
|
|
1679
2013
|
class: "h-full overflow-x-auto overflow-y-hidden",
|
|
1680
2014
|
"data-testid": "collection-kanban"
|
|
1681
2015
|
};
|
|
1682
|
-
var _hoisted_2$
|
|
1683
|
-
var _hoisted_3$
|
|
1684
|
-
var _hoisted_4$
|
|
1685
|
-
var _hoisted_5$
|
|
1686
|
-
var _hoisted_6$
|
|
2016
|
+
var _hoisted_2$12 = { class: "flex gap-3 h-full p-1 min-w-max" };
|
|
2017
|
+
var _hoisted_3$12 = ["data-testid"];
|
|
2018
|
+
var _hoisted_4$12 = { class: "flex items-center justify-between px-3 py-2 border-b border-slate-200" };
|
|
2019
|
+
var _hoisted_5$11 = { class: "flex items-center gap-2 min-w-0" };
|
|
2020
|
+
var _hoisted_6$10 = ["title"];
|
|
1687
2021
|
var _hoisted_7$8 = { class: "text-[11px] text-slate-400 shrink-0" };
|
|
1688
2022
|
var _hoisted_8$8 = [
|
|
1689
2023
|
"data-testid",
|
|
@@ -1802,15 +2136,15 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
|
|
|
1802
2136
|
emit("move", itemId(item), next);
|
|
1803
2137
|
}
|
|
1804
2138
|
return (_ctx, _cache) => {
|
|
1805
|
-
return openBlock(), createElementBlock("div", _hoisted_1$
|
|
2139
|
+
return openBlock(), createElementBlock("div", _hoisted_1$13, [createElementVNode("div", _hoisted_2$12, [(openBlock(true), createElementBlock(Fragment, null, renderList(columns.value, (column) => {
|
|
1806
2140
|
return openBlock(), createElementBlock("div", {
|
|
1807
2141
|
key: column.value,
|
|
1808
2142
|
"data-testid": `collection-kanban-column-${column.value || "uncategorized"}`,
|
|
1809
2143
|
class: "w-72 shrink-0 flex flex-col bg-slate-100 rounded-lg"
|
|
1810
|
-
}, [createElementVNode("div", _hoisted_4$
|
|
2144
|
+
}, [createElementVNode("div", _hoisted_4$12, [createElementVNode("div", _hoisted_5$11, [createElementVNode("span", { class: normalizeClass(["w-2 h-2 rounded-full shrink-0", unref(resolveEnumColor)(__props.schema, __props.groupField, column.value).dot]) }, null, 2), createElementVNode("span", {
|
|
1811
2145
|
class: "font-semibold text-xs text-slate-600 truncate",
|
|
1812
2146
|
title: column.label
|
|
1813
|
-
}, toDisplayString(column.label), 9, _hoisted_6$
|
|
2147
|
+
}, toDisplayString(column.label), 9, _hoisted_6$10)]), createElementVNode("span", _hoisted_7$8, toDisplayString(itemsByColumn(column.value).length), 1)]), createVNode(unref(draggable), {
|
|
1814
2148
|
"model-value": itemsByColumn(column.value),
|
|
1815
2149
|
"item-key": __props.schema.primaryKey,
|
|
1816
2150
|
group: "collection-kanban-cards",
|
|
@@ -1841,7 +2175,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
|
|
|
1841
2175
|
"model-value",
|
|
1842
2176
|
"item-key",
|
|
1843
2177
|
"onChange"
|
|
1844
|
-
])], 8, _hoisted_3$
|
|
2178
|
+
])], 8, _hoisted_3$12);
|
|
1845
2179
|
}), 128))])]);
|
|
1846
2180
|
};
|
|
1847
2181
|
}
|
|
@@ -1870,6 +2204,61 @@ function activatePathLink(event, path, stop = false) {
|
|
|
1870
2204
|
nav(path);
|
|
1871
2205
|
}
|
|
1872
2206
|
//#endregion
|
|
2207
|
+
//#region src/vue/components/CollectionBacklinksView.vue?vue&type=script&setup=true&lang.ts
|
|
2208
|
+
var _hoisted_1$12 = ["data-testid"];
|
|
2209
|
+
var _hoisted_2$11 = { class: "w-full text-[11px] text-slate-600 bg-white" };
|
|
2210
|
+
var _hoisted_3$11 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
|
|
2211
|
+
var _hoisted_4$11 = { class: "divide-y divide-slate-100" };
|
|
2212
|
+
var _hoisted_5$10 = [
|
|
2213
|
+
"data-testid",
|
|
2214
|
+
"onClick",
|
|
2215
|
+
"onKeydown"
|
|
2216
|
+
];
|
|
2217
|
+
var _hoisted_6$9 = ["data-testid"];
|
|
2218
|
+
//#endregion
|
|
2219
|
+
//#region src/vue/components/CollectionBacklinksView.vue
|
|
2220
|
+
var CollectionBacklinksView_default = /* @__PURE__ */ defineComponent({
|
|
2221
|
+
__name: "CollectionBacklinksView",
|
|
2222
|
+
props: {
|
|
2223
|
+
view: {},
|
|
2224
|
+
fieldKey: {}
|
|
2225
|
+
},
|
|
2226
|
+
setup(__props) {
|
|
2227
|
+
const { t } = useCollectionI18n();
|
|
2228
|
+
return (_ctx, _cache) => {
|
|
2229
|
+
return __props.view.rows.length > 0 ? (openBlock(), createElementBlock("div", {
|
|
2230
|
+
key: 0,
|
|
2231
|
+
class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1",
|
|
2232
|
+
"data-testid": `collections-backlinks-${__props.fieldKey}`
|
|
2233
|
+
}, [createElementVNode("table", _hoisted_2$11, [createElementVNode("thead", _hoisted_3$11, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.view.columns, (column) => {
|
|
2234
|
+
return openBlock(), createElementBlock("th", {
|
|
2235
|
+
key: column.key,
|
|
2236
|
+
class: "text-left px-4 py-2 font-bold"
|
|
2237
|
+
}, toDisplayString(column.label), 1);
|
|
2238
|
+
}), 128))])]), createElementVNode("tbody", _hoisted_4$11, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.view.rows, (row) => {
|
|
2239
|
+
return openBlock(), createElementBlock("tr", {
|
|
2240
|
+
key: row.id,
|
|
2241
|
+
class: "group hover:bg-indigo-50/30 cursor-pointer transition-colors",
|
|
2242
|
+
role: "link",
|
|
2243
|
+
tabindex: "0",
|
|
2244
|
+
"data-testid": `collections-backlinks-${__props.fieldKey}-${row.id}`,
|
|
2245
|
+
onClick: ($event) => unref(activateRefLink)($event, __props.view.fromSlug, row.id),
|
|
2246
|
+
onKeydown: [withKeys(($event) => unref(activateRefLink)($event, __props.view.fromSlug, row.id), ["enter"]), withKeys(($event) => unref(activateRefLink)($event, __props.view.fromSlug, row.id), ["space"])]
|
|
2247
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(row.cells, (cell, cellIdx) => {
|
|
2248
|
+
return openBlock(), createElementBlock("td", {
|
|
2249
|
+
key: __props.view.columns[cellIdx]?.key ?? cellIdx,
|
|
2250
|
+
class: "px-4 py-2 align-middle font-medium"
|
|
2251
|
+
}, [createElementVNode("span", { class: normalizeClass(cellIdx === 0 ? "text-indigo-600 group-hover:text-indigo-800 font-bold" : "") }, toDisplayString(cell), 3)]);
|
|
2252
|
+
}), 128))], 40, _hoisted_5$10);
|
|
2253
|
+
}), 128))])])], 8, _hoisted_1$12)) : (openBlock(), createElementBlock("span", {
|
|
2254
|
+
key: 1,
|
|
2255
|
+
class: "text-slate-400 italic",
|
|
2256
|
+
"data-testid": `collections-backlinks-${__props.fieldKey}`
|
|
2257
|
+
}, toDisplayString(unref(t)("collectionsView.noRows")), 9, _hoisted_6$9));
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
});
|
|
2261
|
+
//#endregion
|
|
1873
2262
|
//#region src/vue/components/CollectionEmbedView.vue?vue&type=script&setup=true&lang.ts
|
|
1874
2263
|
var _hoisted_1$11 = [
|
|
1875
2264
|
"href",
|
|
@@ -1978,111 +2367,115 @@ var _hoisted_7$6 = [
|
|
|
1978
2367
|
];
|
|
1979
2368
|
var _hoisted_8$6 = {
|
|
1980
2369
|
key: 0,
|
|
2370
|
+
class: "material-icons text-sm animate-spin"
|
|
2371
|
+
};
|
|
2372
|
+
var _hoisted_9$6 = {
|
|
2373
|
+
key: 1,
|
|
1981
2374
|
class: "material-icons text-sm"
|
|
1982
2375
|
};
|
|
1983
|
-
var
|
|
1984
|
-
var
|
|
2376
|
+
var _hoisted_10$6 = ["aria-label"];
|
|
2377
|
+
var _hoisted_11$6 = {
|
|
1985
2378
|
key: 0,
|
|
1986
2379
|
class: "mb-3 text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl shadow-sm",
|
|
1987
2380
|
"data-testid": "collections-detail-action-error"
|
|
1988
2381
|
};
|
|
1989
|
-
var
|
|
1990
|
-
var
|
|
1991
|
-
var
|
|
2382
|
+
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" };
|
|
2383
|
+
var _hoisted_13$5 = ["for"];
|
|
2384
|
+
var _hoisted_14$5 = {
|
|
1992
2385
|
key: 0,
|
|
1993
2386
|
class: "text-rose-500 font-bold"
|
|
1994
2387
|
};
|
|
1995
|
-
var
|
|
2388
|
+
var _hoisted_15$5 = [
|
|
1996
2389
|
"id",
|
|
1997
2390
|
"onUpdate:modelValue",
|
|
1998
2391
|
"required",
|
|
1999
2392
|
"data-testid"
|
|
2000
2393
|
];
|
|
2001
|
-
var
|
|
2002
|
-
var
|
|
2003
|
-
var
|
|
2394
|
+
var _hoisted_16$5 = { value: "" };
|
|
2395
|
+
var _hoisted_17$5 = ["value"];
|
|
2396
|
+
var _hoisted_18$5 = [
|
|
2004
2397
|
"id",
|
|
2005
2398
|
"onUpdate:modelValue",
|
|
2006
2399
|
"required",
|
|
2007
2400
|
"placeholder",
|
|
2008
2401
|
"data-testid"
|
|
2009
2402
|
];
|
|
2010
|
-
var
|
|
2403
|
+
var _hoisted_19$3 = {
|
|
2011
2404
|
key: 0,
|
|
2012
2405
|
class: "inline-flex items-center gap-2.5 text-sm text-slate-700 cursor-pointer select-none"
|
|
2013
2406
|
};
|
|
2014
|
-
var
|
|
2407
|
+
var _hoisted_20$3 = [
|
|
2015
2408
|
"id",
|
|
2016
2409
|
"onUpdate:modelValue",
|
|
2017
2410
|
"data-testid",
|
|
2018
2411
|
"onChange"
|
|
2019
2412
|
];
|
|
2020
|
-
var
|
|
2413
|
+
var _hoisted_21$3 = [
|
|
2021
2414
|
"id",
|
|
2022
2415
|
"onUpdate:modelValue",
|
|
2023
2416
|
"required",
|
|
2024
2417
|
"data-testid"
|
|
2025
2418
|
];
|
|
2026
|
-
var
|
|
2027
|
-
var
|
|
2028
|
-
var
|
|
2419
|
+
var _hoisted_22$3 = { value: "" };
|
|
2420
|
+
var _hoisted_23$3 = ["value"];
|
|
2421
|
+
var _hoisted_24$2 = [
|
|
2029
2422
|
"id",
|
|
2030
2423
|
"onUpdate:modelValue",
|
|
2031
2424
|
"required",
|
|
2032
2425
|
"data-testid"
|
|
2033
2426
|
];
|
|
2034
|
-
var
|
|
2035
|
-
var
|
|
2036
|
-
var
|
|
2037
|
-
var
|
|
2427
|
+
var _hoisted_25$2 = { value: "" };
|
|
2428
|
+
var _hoisted_26$2 = ["value"];
|
|
2429
|
+
var _hoisted_27$2 = ["data-testid"];
|
|
2430
|
+
var _hoisted_28$1 = {
|
|
2038
2431
|
key: 0,
|
|
2039
2432
|
class: "overflow-hidden border border-slate-200 rounded-lg shadow-sm"
|
|
2040
2433
|
};
|
|
2041
|
-
var
|
|
2042
|
-
var
|
|
2043
|
-
var
|
|
2044
|
-
var
|
|
2045
|
-
var
|
|
2046
|
-
var
|
|
2047
|
-
var
|
|
2048
|
-
var
|
|
2049
|
-
var
|
|
2050
|
-
var
|
|
2051
|
-
var
|
|
2434
|
+
var _hoisted_29$1 = { class: "w-full text-xs text-slate-600 bg-white" };
|
|
2435
|
+
var _hoisted_30$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
|
|
2436
|
+
var _hoisted_31$1 = { class: "divide-y divide-slate-100" };
|
|
2437
|
+
var _hoisted_32$1 = ["onUpdate:modelValue", "onChange"];
|
|
2438
|
+
var _hoisted_33$1 = ["onUpdate:modelValue", "required"];
|
|
2439
|
+
var _hoisted_34$1 = { value: "" };
|
|
2440
|
+
var _hoisted_35$1 = ["value"];
|
|
2441
|
+
var _hoisted_36$1 = ["onUpdate:modelValue", "required"];
|
|
2442
|
+
var _hoisted_37$1 = { value: "" };
|
|
2443
|
+
var _hoisted_38$1 = ["value"];
|
|
2444
|
+
var _hoisted_39$1 = {
|
|
2052
2445
|
key: 3,
|
|
2053
2446
|
class: "relative flex items-center"
|
|
2054
2447
|
};
|
|
2055
|
-
var
|
|
2056
|
-
var
|
|
2057
|
-
var
|
|
2448
|
+
var _hoisted_40$1 = { class: "absolute left-1.5 text-[10px] text-slate-400 font-bold pr-1 border-r border-slate-200" };
|
|
2449
|
+
var _hoisted_41$1 = ["onUpdate:modelValue", "required"];
|
|
2450
|
+
var _hoisted_42$1 = [
|
|
2058
2451
|
"onUpdate:modelValue",
|
|
2059
2452
|
"type",
|
|
2060
2453
|
"step",
|
|
2061
2454
|
"required"
|
|
2062
2455
|
];
|
|
2063
|
-
var
|
|
2064
|
-
var
|
|
2456
|
+
var _hoisted_43$1 = { class: "text-center px-1" };
|
|
2457
|
+
var _hoisted_44$1 = [
|
|
2065
2458
|
"aria-label",
|
|
2066
2459
|
"data-testid",
|
|
2067
2460
|
"onClick"
|
|
2068
2461
|
];
|
|
2069
|
-
var
|
|
2462
|
+
var _hoisted_45$1 = {
|
|
2070
2463
|
key: 1,
|
|
2071
2464
|
class: "text-xs text-slate-400 italic"
|
|
2072
2465
|
};
|
|
2073
|
-
var
|
|
2074
|
-
var
|
|
2466
|
+
var _hoisted_46$1 = ["data-testid", "onClick"];
|
|
2467
|
+
var _hoisted_47$1 = {
|
|
2075
2468
|
key: 4,
|
|
2076
2469
|
class: "relative flex items-center"
|
|
2077
2470
|
};
|
|
2078
|
-
var
|
|
2079
|
-
var
|
|
2471
|
+
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" };
|
|
2472
|
+
var _hoisted_49$1 = [
|
|
2080
2473
|
"id",
|
|
2081
2474
|
"onUpdate:modelValue",
|
|
2082
2475
|
"required",
|
|
2083
2476
|
"data-testid"
|
|
2084
2477
|
];
|
|
2085
|
-
var
|
|
2478
|
+
var _hoisted_50$1 = [
|
|
2086
2479
|
"id",
|
|
2087
2480
|
"onUpdate:modelValue",
|
|
2088
2481
|
"type",
|
|
@@ -2091,104 +2484,105 @@ var _hoisted_49$1 = [
|
|
|
2091
2484
|
"disabled",
|
|
2092
2485
|
"data-testid"
|
|
2093
2486
|
];
|
|
2094
|
-
var
|
|
2487
|
+
var _hoisted_51$1 = [
|
|
2095
2488
|
"id",
|
|
2096
2489
|
"onUpdate:modelValue",
|
|
2097
2490
|
"rows",
|
|
2098
2491
|
"required",
|
|
2099
2492
|
"data-testid"
|
|
2100
2493
|
];
|
|
2101
|
-
var
|
|
2102
|
-
var
|
|
2494
|
+
var _hoisted_52$1 = ["data-testid"];
|
|
2495
|
+
var _hoisted_53$1 = {
|
|
2103
2496
|
key: 0,
|
|
2104
2497
|
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"
|
|
2105
2498
|
};
|
|
2106
|
-
var
|
|
2499
|
+
var _hoisted_54$1 = {
|
|
2107
2500
|
key: 1,
|
|
2108
2501
|
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"
|
|
2109
2502
|
};
|
|
2110
|
-
var
|
|
2503
|
+
var _hoisted_55$1 = {
|
|
2111
2504
|
key: 0,
|
|
2112
2505
|
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"
|
|
2113
2506
|
};
|
|
2114
|
-
var
|
|
2507
|
+
var _hoisted_56$1 = {
|
|
2115
2508
|
key: 1,
|
|
2116
2509
|
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"
|
|
2117
2510
|
};
|
|
2118
|
-
var
|
|
2511
|
+
var _hoisted_57$1 = {
|
|
2119
2512
|
key: 2,
|
|
2120
2513
|
class: "text-slate-300"
|
|
2121
2514
|
};
|
|
2122
|
-
var
|
|
2515
|
+
var _hoisted_58$1 = [
|
|
2123
2516
|
"href",
|
|
2124
2517
|
"tabindex",
|
|
2125
2518
|
"data-testid",
|
|
2126
2519
|
"onClick",
|
|
2127
2520
|
"onKeydown"
|
|
2128
2521
|
];
|
|
2129
|
-
var
|
|
2522
|
+
var _hoisted_59$1 = {
|
|
2130
2523
|
key: 3,
|
|
2131
2524
|
class: "font-semibold text-slate-900 tabular-nums text-sm"
|
|
2132
2525
|
};
|
|
2133
|
-
var
|
|
2526
|
+
var _hoisted_60$1 = {
|
|
2134
2527
|
key: 4,
|
|
2135
2528
|
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"
|
|
2136
2529
|
};
|
|
2137
|
-
var
|
|
2138
|
-
|
|
2530
|
+
var _hoisted_61$1 = ["data-testid"];
|
|
2531
|
+
var _hoisted_62$1 = {
|
|
2532
|
+
key: 6,
|
|
2139
2533
|
class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
|
|
2140
2534
|
};
|
|
2141
|
-
var
|
|
2142
|
-
var
|
|
2143
|
-
var
|
|
2144
|
-
var
|
|
2535
|
+
var _hoisted_63$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
|
|
2536
|
+
var _hoisted_64$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
|
|
2537
|
+
var _hoisted_65$1 = { class: "divide-y divide-slate-100" };
|
|
2538
|
+
var _hoisted_66$1 = {
|
|
2145
2539
|
key: 0,
|
|
2146
2540
|
class: "material-icons text-emerald-600 text-base"
|
|
2147
2541
|
};
|
|
2148
|
-
var
|
|
2542
|
+
var _hoisted_67$1 = {
|
|
2149
2543
|
key: 1,
|
|
2150
2544
|
class: "text-slate-300"
|
|
2151
2545
|
};
|
|
2152
|
-
var
|
|
2153
|
-
key:
|
|
2546
|
+
var _hoisted_68$1 = {
|
|
2547
|
+
key: 7,
|
|
2154
2548
|
class: "text-slate-400 italic"
|
|
2155
2549
|
};
|
|
2156
|
-
var
|
|
2157
|
-
key:
|
|
2550
|
+
var _hoisted_69$1 = {
|
|
2551
|
+
key: 8,
|
|
2158
2552
|
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"
|
|
2159
2553
|
};
|
|
2160
|
-
var
|
|
2554
|
+
var _hoisted_70$1 = [
|
|
2161
2555
|
"src",
|
|
2162
2556
|
"alt",
|
|
2163
2557
|
"data-testid"
|
|
2164
2558
|
];
|
|
2165
|
-
var
|
|
2166
|
-
var
|
|
2167
|
-
var
|
|
2559
|
+
var _hoisted_71$1 = ["href", "data-testid"];
|
|
2560
|
+
var _hoisted_72$1 = ["href", "data-testid"];
|
|
2561
|
+
var _hoisted_73$1 = [
|
|
2168
2562
|
"href",
|
|
2169
2563
|
"data-testid",
|
|
2170
2564
|
"onClick"
|
|
2171
2565
|
];
|
|
2172
|
-
var
|
|
2173
|
-
key:
|
|
2566
|
+
var _hoisted_74$1 = {
|
|
2567
|
+
key: 15,
|
|
2174
2568
|
class: "text-slate-800 font-semibold"
|
|
2175
2569
|
};
|
|
2176
|
-
var
|
|
2570
|
+
var _hoisted_75$1 = {
|
|
2177
2571
|
key: 0,
|
|
2178
2572
|
class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
|
|
2179
2573
|
};
|
|
2180
|
-
var
|
|
2574
|
+
var _hoisted_76$1 = {
|
|
2181
2575
|
key: 1,
|
|
2182
2576
|
class: "mt-5 pt-4 border-t border-slate-200/60",
|
|
2183
2577
|
"data-testid": "collections-detail-chat"
|
|
2184
2578
|
};
|
|
2185
|
-
var
|
|
2579
|
+
var _hoisted_77$1 = {
|
|
2186
2580
|
class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
|
|
2187
2581
|
for: "collections-detail-chat-input"
|
|
2188
2582
|
};
|
|
2189
|
-
var
|
|
2190
|
-
var
|
|
2191
|
-
var
|
|
2583
|
+
var _hoisted_78$1 = { class: "flex items-end gap-2" };
|
|
2584
|
+
var _hoisted_79$1 = ["placeholder", "onKeydown"];
|
|
2585
|
+
var _hoisted_80$1 = ["disabled"];
|
|
2192
2586
|
//#endregion
|
|
2193
2587
|
//#region src/vue/components/CollectionRecordPanel.vue
|
|
2194
2588
|
var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
@@ -2201,6 +2595,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2201
2595
|
actionError: {},
|
|
2202
2596
|
actionPending: { type: Boolean },
|
|
2203
2597
|
visibleActions: {},
|
|
2598
|
+
runningActionIds: {},
|
|
2204
2599
|
liveRecord: {},
|
|
2205
2600
|
liveDerived: {},
|
|
2206
2601
|
viewTitle: {},
|
|
@@ -2243,6 +2638,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2243
2638
|
* safe in the template. */
|
|
2244
2639
|
const detailRecord = computed(() => editing.value ? props.liveDerived ?? props.liveRecord ?? {} : props.viewing ?? {});
|
|
2245
2640
|
const embedViews = computed(() => props.render.embedViewsFor(detailRecord.value));
|
|
2641
|
+
const backlinksViews = computed(() => props.render.backlinksViewsFor(detailRecord.value));
|
|
2246
2642
|
const embedOwnerByKey = computed(() => {
|
|
2247
2643
|
const map = /* @__PURE__ */ new Map();
|
|
2248
2644
|
for (const field of Object.values(props.collection.schema.fields)) if (field.type === "embed" && field.idField) map.set(field.idField, field);
|
|
@@ -2258,12 +2654,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2258
2654
|
if (!editing.value) return "collections-detail";
|
|
2259
2655
|
return editing.value.mode === "create" ? "collections-create" : "collections-edit";
|
|
2260
2656
|
});
|
|
2261
|
-
/** Whether a field gets an editable control in edit mode.
|
|
2262
|
-
*
|
|
2263
|
-
*
|
|
2264
|
-
*
|
|
2657
|
+
/** Whether a field gets an editable control in edit mode. The computed /
|
|
2658
|
+
* projected kinds (COMPUTED_TYPES: derived, embed, backlinks, rollup,
|
|
2659
|
+
* toggle) stay read-only in both modes, so the cell geometry never
|
|
2660
|
+
* changes on the view↔edit toggle. */
|
|
2265
2661
|
function isEditableType(type) {
|
|
2266
|
-
return type
|
|
2662
|
+
return !COMPUTED_TYPES.has(type);
|
|
2267
2663
|
}
|
|
2268
2664
|
/** Wide field types span the full grid width in BOTH modes — keeping
|
|
2269
2665
|
* `image` full-width here (not just when viewing) is what stops a field
|
|
@@ -2273,6 +2669,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2273
2669
|
"table",
|
|
2274
2670
|
"markdown",
|
|
2275
2671
|
"embed",
|
|
2672
|
+
"backlinks",
|
|
2276
2673
|
"image"
|
|
2277
2674
|
].includes(field.type) ? "col-span-full" : "col-span-1";
|
|
2278
2675
|
}
|
|
@@ -2351,10 +2748,10 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2351
2748
|
key: action.id,
|
|
2352
2749
|
type: "button",
|
|
2353
2750
|
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",
|
|
2354
|
-
disabled: __props.actionPending,
|
|
2751
|
+
disabled: __props.actionPending || __props.runningActionIds.includes(action.id),
|
|
2355
2752
|
"data-testid": `collections-detail-action-${action.id}`,
|
|
2356
2753
|
onClick: ($event) => emit("runAction", action)
|
|
2357
|
-
}, [action.
|
|
2754
|
+
}, [__props.runningActionIds.includes(action.id) ? (openBlock(), createElementBlock("span", _hoisted_8$6, "progress_activity")) : action.icon ? (openBlock(), createElementBlock("span", _hoisted_9$6, toDisplayString(action.icon), 1)) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(action.label), 1)], 8, _hoisted_7$6);
|
|
2358
2755
|
}), 128)),
|
|
2359
2756
|
createElementVNode("button", {
|
|
2360
2757
|
type: "button",
|
|
@@ -2374,29 +2771,29 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2374
2771
|
"aria-label": unref(t)("common.close"),
|
|
2375
2772
|
"data-testid": "collections-detail-close",
|
|
2376
2773
|
onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
|
|
2377
|
-
}, [..._cache[8] || (_cache[8] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8,
|
|
2774
|
+
}, [..._cache[8] || (_cache[8] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_10$6)
|
|
2378
2775
|
]))]),
|
|
2379
|
-
!editing.value && __props.actionError ? (openBlock(), createElementBlock("p",
|
|
2380
|
-
createElementVNode("div",
|
|
2776
|
+
!editing.value && __props.actionError ? (openBlock(), createElementBlock("p", _hoisted_11$6, toDisplayString(__props.actionError), 1)) : createCommentVNode("", true),
|
|
2777
|
+
createElementVNode("div", _hoisted_12$6, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.collection.schema.fields, (field, key) => {
|
|
2381
2778
|
return openBlock(), createElementBlock(Fragment, { key }, [cellVisible(field, String(key)) ? (openBlock(), createElementBlock("div", {
|
|
2382
2779
|
key: 0,
|
|
2383
2780
|
class: normalizeClass(["flex flex-col gap-1.5", colSpanClass(field)])
|
|
2384
2781
|
}, [createElementVNode("label", {
|
|
2385
2782
|
class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider flex items-center gap-1",
|
|
2386
2783
|
for: `collections-field-${key}`
|
|
2387
|
-
}, [createTextVNode(toDisplayString(field.label) + " ", 1), editing.value && field.required ? (openBlock(), createElementBlock("span",
|
|
2784
|
+
}, [createTextVNode(toDisplayString(field.label) + " ", 1), editing.value && field.required ? (openBlock(), createElementBlock("span", _hoisted_14$5, "*")) : createCommentVNode("", true)], 8, _hoisted_13$5), editing.value && field.type === "embed" && field.idField && __props.render.embedOptions(field.to ?? "").length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
|
|
2388
2785
|
key: 0,
|
|
2389
2786
|
id: `collections-field-${key}`,
|
|
2390
2787
|
"onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
|
|
2391
2788
|
required: embedPickerRequired(field),
|
|
2392
2789
|
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",
|
|
2393
2790
|
"data-testid": `collections-input-${key}`
|
|
2394
|
-
}, [createElementVNode("option",
|
|
2791
|
+
}, [createElementVNode("option", _hoisted_16$5, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.embedOptions(field.to ?? ""), (opt) => {
|
|
2395
2792
|
return openBlock(), createElementBlock("option", {
|
|
2396
2793
|
key: opt.slug,
|
|
2397
2794
|
value: opt.slug
|
|
2398
|
-
}, toDisplayString(opt.display), 9,
|
|
2399
|
-
}), 128))], 8,
|
|
2795
|
+
}, toDisplayString(opt.display), 9, _hoisted_17$5);
|
|
2796
|
+
}), 128))], 8, _hoisted_15$5)), [[vModelSelect, editing.value.text[field.idField]]]) : editing.value && field.type === "embed" && field.idField ? withDirectives((openBlock(), createElementBlock("input", {
|
|
2400
2797
|
key: 1,
|
|
2401
2798
|
id: `collections-field-${key}`,
|
|
2402
2799
|
"onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
|
|
@@ -2405,47 +2802,47 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2405
2802
|
placeholder: unref(t)("collectionsView.selectPlaceholder"),
|
|
2406
2803
|
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",
|
|
2407
2804
|
"data-testid": `collections-input-${key}`
|
|
2408
|
-
}, null, 8,
|
|
2805
|
+
}, null, 8, _hoisted_18$5)), [[vModelText, editing.value.text[field.idField]]]) : editing.value && isEditableType(field.type) ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [field.type === "boolean" ? (openBlock(), createElementBlock("label", _hoisted_19$3, [withDirectives(createElementVNode("input", {
|
|
2409
2806
|
id: `collections-field-${key}`,
|
|
2410
2807
|
"onUpdate:modelValue": ($event) => editing.value.bool[key] = $event,
|
|
2411
2808
|
type: "checkbox",
|
|
2412
2809
|
class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
2413
2810
|
"data-testid": `collections-input-${key}`,
|
|
2414
2811
|
onChange: ($event) => markBoolTouched(String(key))
|
|
2415
|
-
}, null, 40,
|
|
2812
|
+
}, null, 40, _hoisted_20$3), [[vModelCheckbox, editing.value.bool[key]]]), createElementVNode("span", { class: normalizeClass(["text-xs font-semibold", editing.value.bool[key] ? "text-indigo-600" : "text-slate-500"]) }, toDisplayString(editing.value.bool[key] ? unref(t)("common.yes") : unref(t)("common.no")), 3)])) : field.type === "ref" && field.to && __props.render.refOptions(field.to).length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
|
|
2416
2813
|
key: 1,
|
|
2417
2814
|
id: `collections-field-${key}`,
|
|
2418
2815
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2419
2816
|
required: isFieldRequiredInUi(field),
|
|
2420
2817
|
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",
|
|
2421
2818
|
"data-testid": `collections-input-${key}`
|
|
2422
|
-
}, [createElementVNode("option",
|
|
2819
|
+
}, [createElementVNode("option", _hoisted_22$3, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(field.to), (opt) => {
|
|
2423
2820
|
return openBlock(), createElementBlock("option", {
|
|
2424
2821
|
key: opt.slug,
|
|
2425
2822
|
value: opt.slug
|
|
2426
|
-
}, toDisplayString(opt.display), 9,
|
|
2427
|
-
}), 128))], 8,
|
|
2823
|
+
}, toDisplayString(opt.display), 9, _hoisted_23$3);
|
|
2824
|
+
}), 128))], 8, _hoisted_21$3)), [[vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
|
|
2428
2825
|
key: 2,
|
|
2429
2826
|
id: `collections-field-${key}`,
|
|
2430
2827
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2431
2828
|
required: isFieldRequiredInUi(field),
|
|
2432
2829
|
class: 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])]),
|
|
2433
2830
|
"data-testid": `collections-input-${key}`
|
|
2434
|
-
}, [createElementVNode("option",
|
|
2831
|
+
}, [createElementVNode("option", _hoisted_25$2, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
|
|
2435
2832
|
return openBlock(), createElementBlock("option", {
|
|
2436
2833
|
key: value,
|
|
2437
2834
|
value
|
|
2438
|
-
}, toDisplayString(value), 9,
|
|
2439
|
-
}), 128))], 10,
|
|
2835
|
+
}, toDisplayString(value), 9, _hoisted_26$2);
|
|
2836
|
+
}), 128))], 10, _hoisted_24$2)), [[vModelSelect, editing.value.text[key]]]) : field.type === "table" && field.of ? (openBlock(), createElementBlock("div", {
|
|
2440
2837
|
key: 3,
|
|
2441
2838
|
class: "border border-slate-200 bg-slate-50/30 rounded-xl p-4 space-y-3",
|
|
2442
2839
|
"data-testid": `collections-table-${key}`
|
|
2443
|
-
}, [editing.value.table[key] && editing.value.table[key].length > 0 ? (openBlock(), createElementBlock("div",
|
|
2840
|
+
}, [editing.value.table[key] && editing.value.table[key].length > 0 ? (openBlock(), createElementBlock("div", _hoisted_28$1, [createElementVNode("table", _hoisted_29$1, [createElementVNode("thead", _hoisted_30$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
|
|
2444
2841
|
return openBlock(), createElementBlock("th", {
|
|
2445
2842
|
key: subKey,
|
|
2446
2843
|
class: "text-left px-3 py-2 font-bold"
|
|
2447
2844
|
}, toDisplayString(subField.label), 1);
|
|
2448
|
-
}), 128)), _cache[9] || (_cache[9] = createElementVNode("th", { class: "w-9" }, null, -1))])]), createElementVNode("tbody",
|
|
2845
|
+
}), 128)), _cache[9] || (_cache[9] = createElementVNode("th", { class: "w-9" }, null, -1))])]), createElementVNode("tbody", _hoisted_31$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(editing.value.table[key], (row, rowIdx) => {
|
|
2449
2846
|
return openBlock(), createElementBlock("tr", {
|
|
2450
2847
|
key: rowIdx,
|
|
2451
2848
|
class: "hover:bg-slate-50/50"
|
|
@@ -2459,53 +2856,53 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2459
2856
|
type: "checkbox",
|
|
2460
2857
|
class: "h-4 w-4 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
2461
2858
|
onChange: ($event) => markRowBoolTouched(row, String(subKey))
|
|
2462
|
-
}, null, 40,
|
|
2859
|
+
}, null, 40, _hoisted_32$1)), [[vModelCheckbox, row.bool[subKey]]]) : subField.type === "enum" && Array.isArray(subField.values) && subField.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
|
|
2463
2860
|
key: 1,
|
|
2464
2861
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2465
2862
|
required: subField.required,
|
|
2466
2863
|
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"
|
|
2467
|
-
}, [createElementVNode("option",
|
|
2864
|
+
}, [createElementVNode("option", _hoisted_34$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(subField.values, (value) => {
|
|
2468
2865
|
return openBlock(), createElementBlock("option", {
|
|
2469
2866
|
key: value,
|
|
2470
2867
|
value
|
|
2471
|
-
}, toDisplayString(value), 9,
|
|
2472
|
-
}), 128))], 8,
|
|
2868
|
+
}, toDisplayString(value), 9, _hoisted_35$1);
|
|
2869
|
+
}), 128))], 8, _hoisted_33$1)), [[vModelSelect, row.text[subKey]]]) : subField.type === "ref" && subField.to && __props.render.refOptions(subField.to).length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
|
|
2473
2870
|
key: 2,
|
|
2474
2871
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2475
2872
|
required: subField.required,
|
|
2476
2873
|
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"
|
|
2477
|
-
}, [createElementVNode("option",
|
|
2874
|
+
}, [createElementVNode("option", _hoisted_37$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(subField.to), (opt) => {
|
|
2478
2875
|
return openBlock(), createElementBlock("option", {
|
|
2479
2876
|
key: opt.slug,
|
|
2480
2877
|
value: opt.slug
|
|
2481
|
-
}, toDisplayString(opt.display), 9,
|
|
2482
|
-
}), 128))], 8,
|
|
2878
|
+
}, toDisplayString(opt.display), 9, _hoisted_38$1);
|
|
2879
|
+
}), 128))], 8, _hoisted_36$1)), [[vModelSelect, row.text[subKey]]]) : subField.type === "money" ? (openBlock(), createElementBlock("div", _hoisted_39$1, [createElementVNode("span", _hoisted_40$1, toDisplayString(__props.render.currencySymbol(__props.render.resolveCurrency(subField, __props.liveRecord))), 1), withDirectives(createElementVNode("input", {
|
|
2483
2880
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2484
2881
|
type: "number",
|
|
2485
2882
|
step: "0.01",
|
|
2486
2883
|
required: subField.required,
|
|
2487
2884
|
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"
|
|
2488
|
-
}, null, 8,
|
|
2885
|
+
}, null, 8, _hoisted_41$1), [[vModelText, row.text[subKey]]])])) : withDirectives((openBlock(), createElementBlock("input", {
|
|
2489
2886
|
key: 4,
|
|
2490
2887
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2491
2888
|
type: __props.render.inputTypeFor(subField.type),
|
|
2492
2889
|
step: __props.render.stepFor(subField.type),
|
|
2493
2890
|
required: subField.required,
|
|
2494
2891
|
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"
|
|
2495
|
-
}, null, 8,
|
|
2496
|
-
}), 128)), createElementVNode("td",
|
|
2892
|
+
}, null, 8, _hoisted_42$1)), [[vModelDynamic, row.text[subKey]]])]);
|
|
2893
|
+
}), 128)), createElementVNode("td", _hoisted_43$1, [createElementVNode("button", {
|
|
2497
2894
|
type: "button",
|
|
2498
2895
|
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",
|
|
2499
2896
|
"aria-label": unref(t)("collectionsView.removeRow"),
|
|
2500
2897
|
"data-testid": `collections-table-${key}-remove-${rowIdx}`,
|
|
2501
2898
|
onClick: ($event) => removeTableRow(String(key), rowIdx)
|
|
2502
|
-
}, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8,
|
|
2503
|
-
}), 128))])])])) : (openBlock(), createElementBlock("p",
|
|
2899
|
+
}, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_44$1)])]);
|
|
2900
|
+
}), 128))])])])) : (openBlock(), createElementBlock("p", _hoisted_45$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)), createElementVNode("button", {
|
|
2504
2901
|
type: "button",
|
|
2505
2902
|
class: "inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-800 font-bold hover:underline",
|
|
2506
2903
|
"data-testid": `collections-table-${key}-add`,
|
|
2507
2904
|
onClick: ($event) => addTableRow(String(key), field.of)
|
|
2508
|
-
}, [_cache[11] || (_cache[11] = createElementVNode("span", { class: "material-icons text-xs" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addRow")), 1)], 8,
|
|
2905
|
+
}, [_cache[11] || (_cache[11] = createElementVNode("span", { class: "material-icons text-xs" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addRow")), 1)], 8, _hoisted_46$1)], 8, _hoisted_27$2)) : field.type === "money" ? (openBlock(), createElementBlock("div", _hoisted_47$1, [createElementVNode("div", _hoisted_48$1, toDisplayString(__props.render.currencySymbol(__props.render.resolveCurrency(field, __props.liveRecord))), 1), withDirectives(createElementVNode("input", {
|
|
2509
2906
|
id: `collections-field-${key}`,
|
|
2510
2907
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2511
2908
|
type: "number",
|
|
@@ -2513,7 +2910,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2513
2910
|
required: isFieldRequiredInUi(field),
|
|
2514
2911
|
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",
|
|
2515
2912
|
"data-testid": `collections-input-${key}`
|
|
2516
|
-
}, null, 8,
|
|
2913
|
+
}, null, 8, _hoisted_49$1), [[vModelText, editing.value.text[key]]])])) : [
|
|
2517
2914
|
"string",
|
|
2518
2915
|
"email",
|
|
2519
2916
|
"number",
|
|
@@ -2532,7 +2929,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2532
2929
|
disabled: field.primary === true && (editing.value.mode === "edit" || __props.isSingleton),
|
|
2533
2930
|
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",
|
|
2534
2931
|
"data-testid": `collections-input-${key}`
|
|
2535
|
-
}, null, 8,
|
|
2932
|
+
}, null, 8, _hoisted_50$1)), [[vModelDynamic, editing.value.text[key]]]) : withDirectives((openBlock(), createElementBlock("textarea", {
|
|
2536
2933
|
key: 6,
|
|
2537
2934
|
id: `collections-field-${key}`,
|
|
2538
2935
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
@@ -2540,11 +2937,11 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2540
2937
|
required: isFieldRequiredInUi(field),
|
|
2541
2938
|
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",
|
|
2542
2939
|
"data-testid": `collections-input-${key}`
|
|
2543
|
-
}, null, 8,
|
|
2940
|
+
}, null, 8, _hoisted_51$1)), [[vModelText, editing.value.text[key]]])], 64)) : (openBlock(), createElementBlock("div", {
|
|
2544
2941
|
key: 3,
|
|
2545
2942
|
class: "text-xs font-medium text-slate-700 break-words",
|
|
2546
2943
|
"data-testid": `collections-detail-value-${key}`
|
|
2547
|
-
}, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span",
|
|
2944
|
+
}, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span", _hoisted_53$1, [_cache[12] || (_cache[12] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)])) : (openBlock(), createElementBlock("span", _hoisted_54$1, toDisplayString(unref(t)("common.no")), 1))], 64)) : field.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [detailRecord.value[key] === true ? (openBlock(), createElementBlock("span", _hoisted_55$1, [_cache[13] || (_cache[13] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)])) : detailRecord.value[key] === false ? (openBlock(), createElementBlock("span", _hoisted_56$1, toDisplayString(unref(t)("common.no")), 1)) : (openBlock(), createElementBlock("span", _hoisted_57$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("a", {
|
|
2548
2945
|
key: 2,
|
|
2549
2946
|
href: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])),
|
|
2550
2947
|
tabindex: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
|
|
@@ -2553,12 +2950,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2553
2950
|
"data-testid": `collections-detail-ref-${key}`,
|
|
2554
2951
|
onClick: ($event) => unref(activateRefLink)($event, field.to, String(detailRecord.value[key])),
|
|
2555
2952
|
onKeydown: [withKeys(($event) => unref(activateRefLink)($event, field.to, String(detailRecord.value[key])), ["enter"]), withKeys(($event) => unref(activateRefLink)($event, field.to, String(detailRecord.value[key])), ["space"])]
|
|
2556
|
-
}, toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41,
|
|
2953
|
+
}, toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_58$1)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_59$1, toDisplayString(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_60$1, toDisplayString(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "rollup" ? (openBlock(), createElementBlock("span", {
|
|
2954
|
+
key: 5,
|
|
2955
|
+
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",
|
|
2956
|
+
"data-testid": `collections-detail-rollup-${key}`
|
|
2957
|
+
}, toDisplayString(__props.render.rollupDisplay(field, detailRecord.value)), 9, _hoisted_61$1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? (openBlock(), createElementBlock("div", _hoisted_62$1, [createElementVNode("table", _hoisted_63$1, [createElementVNode("thead", _hoisted_64$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
|
|
2557
2958
|
return openBlock(), createElementBlock("th", {
|
|
2558
2959
|
key: subKey,
|
|
2559
2960
|
class: "text-left px-4 py-2 font-bold"
|
|
2560
2961
|
}, toDisplayString(subField.label), 1);
|
|
2561
|
-
}), 128))])]), createElementVNode("tbody",
|
|
2962
|
+
}), 128))])]), createElementVNode("tbody", _hoisted_65$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
|
|
2562
2963
|
return openBlock(), createElementBlock("tr", {
|
|
2563
2964
|
key: rowIdx,
|
|
2564
2965
|
class: "hover:bg-slate-50/50"
|
|
@@ -2566,44 +2967,48 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2566
2967
|
return openBlock(), createElementBlock("td", {
|
|
2567
2968
|
key: subKey,
|
|
2568
2969
|
class: "px-4 py-2 align-middle font-medium"
|
|
2569
|
-
}, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span",
|
|
2970
|
+
}, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span", _hoisted_66$1, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_67$1, "—"))], 64)) : (openBlock(), createElementBlock("span", {
|
|
2570
2971
|
key: 1,
|
|
2571
2972
|
class: normalizeClass([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
|
|
2572
2973
|
}, toDisplayString(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
|
|
2573
2974
|
}), 128))]);
|
|
2574
|
-
}), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span",
|
|
2575
|
-
key:
|
|
2975
|
+
}), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_68$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? (openBlock(), createElementBlock("div", _hoisted_69$1, toDisplayString(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? (openBlock(), createBlock(CollectionEmbedView_default, {
|
|
2976
|
+
key: 9,
|
|
2576
2977
|
view: embedViews.value[key],
|
|
2577
2978
|
"field-key": String(key)
|
|
2979
|
+
}, null, 8, ["view", "field-key"])) : field.type === "backlinks" && backlinksViews.value[key] ? (openBlock(), createBlock(CollectionBacklinksView_default, {
|
|
2980
|
+
key: 10,
|
|
2981
|
+
view: backlinksViews.value[key],
|
|
2982
|
+
"field-key": String(key)
|
|
2578
2983
|
}, null, 8, ["view", "field-key"])) : field.type === "image" && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("img", {
|
|
2579
|
-
key:
|
|
2984
|
+
key: 11,
|
|
2580
2985
|
src: unref(resolveImageSrc)(String(detailRecord.value[key])),
|
|
2581
2986
|
alt: field.label,
|
|
2582
2987
|
class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
|
|
2583
2988
|
"data-testid": `collections-detail-image-${key}`
|
|
2584
|
-
}, null, 8,
|
|
2585
|
-
key:
|
|
2989
|
+
}, null, 8, _hoisted_70$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
|
|
2990
|
+
key: 12,
|
|
2586
2991
|
href: String(detailRecord.value[key]),
|
|
2587
2992
|
target: "_blank",
|
|
2588
2993
|
rel: "noopener noreferrer",
|
|
2589
2994
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2590
2995
|
"data-testid": `collections-detail-url-${key}`
|
|
2591
|
-
}, toDisplayString(String(detailRecord.value[key])), 9,
|
|
2592
|
-
key:
|
|
2996
|
+
}, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_71$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
|
|
2997
|
+
key: 13,
|
|
2593
2998
|
href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
|
|
2594
2999
|
target: "_blank",
|
|
2595
3000
|
rel: "noopener noreferrer",
|
|
2596
3001
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2597
3002
|
"data-testid": `collections-detail-file-${key}`
|
|
2598
|
-
}, toDisplayString(String(detailRecord.value[key])), 9,
|
|
2599
|
-
key:
|
|
3003
|
+
}, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_72$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
|
|
3004
|
+
key: 14,
|
|
2600
3005
|
href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
|
|
2601
3006
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2602
3007
|
"data-testid": `collections-detail-file-${key}`,
|
|
2603
3008
|
onClick: ($event) => unref(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
|
|
2604
|
-
}, toDisplayString(String(detailRecord.value[key])), 9,
|
|
2605
|
-
}), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p",
|
|
2606
|
-
!editing.value ? (openBlock(), createElementBlock("div",
|
|
3009
|
+
}, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_73$1)) : (openBlock(), createElementBlock("span", _hoisted_74$1, toDisplayString(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_52$1))], 2)) : createCommentVNode("", true)], 64);
|
|
3010
|
+
}), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_75$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)]),
|
|
3011
|
+
!editing.value ? (openBlock(), createElementBlock("div", _hoisted_76$1, [createElementVNode("label", _hoisted_77$1, toDisplayString(unref(t)("collectionsView.itemChatLabel")), 1), createElementVNode("div", _hoisted_78$1, [withDirectives(createElementVNode("textarea", {
|
|
2607
3012
|
id: "collections-detail-chat-input",
|
|
2608
3013
|
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
|
|
2609
3014
|
rows: "2",
|
|
@@ -2611,13 +3016,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2611
3016
|
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",
|
|
2612
3017
|
"data-testid": "collections-detail-chat-input",
|
|
2613
3018
|
onKeydown: [withKeys(withModifiers(submitItemChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitItemChat, ["ctrl"]), ["enter"])]
|
|
2614
|
-
}, null, 40,
|
|
3019
|
+
}, null, 40, _hoisted_79$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
|
|
2615
3020
|
type: "button",
|
|
2616
3021
|
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",
|
|
2617
3022
|
disabled: !chatMessage.value.trim(),
|
|
2618
3023
|
"data-testid": "collections-detail-chat-send",
|
|
2619
3024
|
onClick: submitItemChat
|
|
2620
|
-
}, [_cache[14] || (_cache[14] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)], 8,
|
|
3025
|
+
}, [_cache[14] || (_cache[14] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)], 8, _hoisted_80$1)])])) : createCommentVNode("", true)
|
|
2621
3026
|
]),
|
|
2622
3027
|
_: 1
|
|
2623
3028
|
}, 40, ["data-testid"]);
|
|
@@ -3019,152 +3424,16 @@ var CollectionRemoteViewPreview_default = /*#__PURE__*/ _plugin_vue_export_helpe
|
|
|
3019
3424
|
}
|
|
3020
3425
|
}), [["__scopeId", "data-v-965ade6c"]]);
|
|
3021
3426
|
//#endregion
|
|
3022
|
-
//#region src/vue/useCollectionRendering.helpers.ts
|
|
3023
|
-
var EM_DASH = "—";
|
|
3024
|
-
var DEFAULT_CURRENCY = "USD";
|
|
3025
|
-
var MARKDOWN_CELL_PREVIEW_MAX = 80;
|
|
3026
|
-
function stepForFieldType(type) {
|
|
3027
|
-
if (type === "money") return "0.01";
|
|
3028
|
-
if (type === "number") return "any";
|
|
3029
|
-
}
|
|
3030
|
-
function inputTypeFor(type) {
|
|
3031
|
-
if (type === "email") return "email";
|
|
3032
|
-
if (type === "number") return "number";
|
|
3033
|
-
if (type === "money") return "number";
|
|
3034
|
-
if (type === "date") return "date";
|
|
3035
|
-
if (type === "datetime") return "datetime-local";
|
|
3036
|
-
return "text";
|
|
3037
|
-
}
|
|
3038
|
-
function isExternalUrl(value) {
|
|
3039
|
-
return typeof value === "string" && /^https?:\/\//i.test(value);
|
|
3040
|
-
}
|
|
3041
|
-
function detailText(value) {
|
|
3042
|
-
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
3043
|
-
return String(value);
|
|
3044
|
-
}
|
|
3045
|
-
function formatCell(value, type) {
|
|
3046
|
-
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
3047
|
-
if (type === "markdown" && typeof value === "string") return value.length > MARKDOWN_CELL_PREVIEW_MAX ? `${value.slice(0, MARKDOWN_CELL_PREVIEW_MAX)}…` : value;
|
|
3048
|
-
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
3049
|
-
return JSON.stringify(value);
|
|
3050
|
-
}
|
|
3051
|
-
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
3052
|
-
* `currencyField` (when present and non-blank) wins over the field's
|
|
3053
|
-
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
3054
|
-
* keys; any other field resolves to undefined (the formatter's USD
|
|
3055
|
-
* fallback), as before. */
|
|
3056
|
-
function resolveCurrency(field, record) {
|
|
3057
|
-
if (field.type !== "money" && field.type !== "derived") return void 0;
|
|
3058
|
-
if (field.currencyField && record) {
|
|
3059
|
-
const code = record[field.currencyField];
|
|
3060
|
-
if (typeof code === "string" && code.trim().length > 0) return code;
|
|
3061
|
-
}
|
|
3062
|
-
return field.currency;
|
|
3063
|
-
}
|
|
3064
|
-
function formatMoney(value, currency, displayLocale) {
|
|
3065
|
-
if (value === void 0 || value === "") return EM_DASH;
|
|
3066
|
-
const amount = typeof value === "number" ? value : Number(value);
|
|
3067
|
-
if (!Number.isFinite(amount)) return String(value);
|
|
3068
|
-
const currencyCode = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
3069
|
-
try {
|
|
3070
|
-
return new Intl.NumberFormat(displayLocale, {
|
|
3071
|
-
style: "currency",
|
|
3072
|
-
currency: currencyCode
|
|
3073
|
-
}).format(amount);
|
|
3074
|
-
} catch {
|
|
3075
|
-
return String(amount);
|
|
3076
|
-
}
|
|
3077
|
-
}
|
|
3078
|
-
function currencySymbolForLocale(currency, locale) {
|
|
3079
|
-
const code = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
3080
|
-
try {
|
|
3081
|
-
return new Intl.NumberFormat(locale, {
|
|
3082
|
-
style: "currency",
|
|
3083
|
-
currency: code
|
|
3084
|
-
}).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
|
|
3085
|
-
} catch {
|
|
3086
|
-
return code;
|
|
3087
|
-
}
|
|
3088
|
-
}
|
|
3089
|
-
function tableRows(value) {
|
|
3090
|
-
if (!Array.isArray(value)) return [];
|
|
3091
|
-
return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
|
|
3092
|
-
}
|
|
3093
|
-
function hasTableRows(value) {
|
|
3094
|
-
return tableRows(value).length > 0;
|
|
3095
|
-
}
|
|
3096
|
-
/** Pick the field used to label a referenced/embedded record: prefer a
|
|
3097
|
-
* `name` field, then `title`, else fall back to the primary key. */
|
|
3098
|
-
function displayFieldFor(fields, primaryKey) {
|
|
3099
|
-
if ("name" in fields) return "name";
|
|
3100
|
-
if ("title" in fields) return "title";
|
|
3101
|
-
return primaryKey;
|
|
3102
|
-
}
|
|
3103
|
-
function uniqueRefTargets(schema) {
|
|
3104
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3105
|
-
const walk = (fields) => {
|
|
3106
|
-
for (const field of Object.values(fields)) {
|
|
3107
|
-
if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
3108
|
-
if (field.type === "table" && field.of) walk(field.of);
|
|
3109
|
-
}
|
|
3110
|
-
};
|
|
3111
|
-
walk(schema.fields);
|
|
3112
|
-
return [...targets];
|
|
3113
|
-
}
|
|
3114
|
-
function uniqueEmbedTargets(schema) {
|
|
3115
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3116
|
-
for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
3117
|
-
return [...targets];
|
|
3118
|
-
}
|
|
3119
|
-
function buildRefDisplayMap(detail) {
|
|
3120
|
-
const { fields, primaryKey } = detail.collection.schema;
|
|
3121
|
-
const displayField = displayFieldFor(fields, primaryKey);
|
|
3122
|
-
const map = {};
|
|
3123
|
-
for (const item of detail.items) {
|
|
3124
|
-
const slugRaw = item[primaryKey];
|
|
3125
|
-
if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
|
|
3126
|
-
const displayRaw = item[displayField];
|
|
3127
|
-
map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
|
|
3128
|
-
}
|
|
3129
|
-
return map;
|
|
3130
|
-
}
|
|
3131
|
-
function buildRefRecordMap(detail) {
|
|
3132
|
-
const { schema } = detail.collection;
|
|
3133
|
-
const map = {};
|
|
3134
|
-
for (const item of detail.items) {
|
|
3135
|
-
const slugRaw = item[schema.primaryKey];
|
|
3136
|
-
if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
|
|
3137
|
-
}
|
|
3138
|
-
return map;
|
|
3139
|
-
}
|
|
3140
|
-
function sortedRefOptions(map) {
|
|
3141
|
-
return Object.entries(map).map(([slug, display]) => ({
|
|
3142
|
-
slug,
|
|
3143
|
-
display
|
|
3144
|
-
})).sort((left, right) => left.display.localeCompare(right.display));
|
|
3145
|
-
}
|
|
3146
|
-
/** Dropdown options for an `embed` field's per-record picker: every
|
|
3147
|
-
* record in the target collection, labelled by its name/title (or
|
|
3148
|
-
* primary key), skipping records without a slug and sorted by label. */
|
|
3149
|
-
function buildEmbedOptions(schema, items) {
|
|
3150
|
-
const { fields, primaryKey } = schema;
|
|
3151
|
-
const displayField = displayFieldFor(fields, primaryKey);
|
|
3152
|
-
return items.map((item) => {
|
|
3153
|
-
const slug = String(item[primaryKey] ?? "");
|
|
3154
|
-
const labelRaw = item[displayField];
|
|
3155
|
-
return {
|
|
3156
|
-
slug,
|
|
3157
|
-
display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
|
|
3158
|
-
};
|
|
3159
|
-
}).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
|
|
3160
|
-
}
|
|
3161
|
-
//#endregion
|
|
3162
3427
|
//#region src/vue/useLinkedCollectionCaches.ts
|
|
3163
3428
|
/** The de-duplicated ref + embed target slugs a schema links to. `allTargets`
|
|
3164
|
-
* is the union (each target fetched once even when both ref'd and embedded).
|
|
3429
|
+
* is the union (each target fetched once even when both ref'd and embedded).
|
|
3430
|
+
* `backlinks` SOURCE collections ride in `embedTargets`: a backlink needs
|
|
3431
|
+
* exactly what an embed target caches (the source's schema + items in
|
|
3432
|
+
* `embedCache`), so reverse sources reuse that cache rather than adding a
|
|
3433
|
+
* parallel one. */
|
|
3165
3434
|
function linkedTargets(schema) {
|
|
3166
3435
|
const refTargets = new Set(uniqueRefTargets(schema));
|
|
3167
|
-
const embedTargets = new Set(uniqueEmbedTargets(schema));
|
|
3436
|
+
const embedTargets = /* @__PURE__ */ new Set([...uniqueEmbedTargets(schema), ...uniqueBacklinkSources(schema)]);
|
|
3168
3437
|
return {
|
|
3169
3438
|
refTargets,
|
|
3170
3439
|
embedTargets,
|
|
@@ -3309,14 +3578,113 @@ function buildEmbedViews(schema, embedCache, record, locale) {
|
|
|
3309
3578
|
}
|
|
3310
3579
|
return out;
|
|
3311
3580
|
}
|
|
3581
|
+
/** One backlinks table CELL: money formatted with its currency, anything
|
|
3582
|
+
* else through the same `formatCell` list tables use — so a markdown
|
|
3583
|
+
* source column (a worklog `notes`) shows the one-line 80-char preview,
|
|
3584
|
+
* not the whole text. Unknown `display` key ⇒ plain text (fail-soft). */
|
|
3585
|
+
function formatBacklinkCell(sourceField, value, row, locale) {
|
|
3586
|
+
if (!sourceField) return detailText(value);
|
|
3587
|
+
if (sourceField.type === "money") return formatMoney(value, resolveCurrency(sourceField, row), locale);
|
|
3588
|
+
return formatCell(value, sourceField.type);
|
|
3589
|
+
}
|
|
3590
|
+
/** Build the read-only backlinks view-models for one record: for each
|
|
3591
|
+
* `backlinks` field, the rows of `from` whose `via` points at the open
|
|
3592
|
+
* record (matched via the SHARED `backlinkRows`, on source records
|
|
3593
|
+
* derived exactly like the server's enrichment — so a `display`/`filter`
|
|
3594
|
+
* on a derived column such as an invoice `total` agrees on both sides).
|
|
3595
|
+
* Source data comes out of `embedCache` (reverse sources ride the embed
|
|
3596
|
+
* fan-out — see `linkedTargets`). Fail-soft: an unloadable source or an
|
|
3597
|
+
* unknown `display` key degrades to `found: false` / a raw-key column,
|
|
3598
|
+
* never a throw. */
|
|
3599
|
+
function buildBacklinksViews(schema, embedCache, record, locale) {
|
|
3600
|
+
const out = {};
|
|
3601
|
+
if (!schema) return out;
|
|
3602
|
+
for (const [key, field] of Object.entries(schema.fields)) {
|
|
3603
|
+
if (field.type !== "backlinks") continue;
|
|
3604
|
+
const columns = field.display.map((col) => ({
|
|
3605
|
+
key: col,
|
|
3606
|
+
label: col
|
|
3607
|
+
}));
|
|
3608
|
+
const data = embedCache[field.from];
|
|
3609
|
+
if (!data) {
|
|
3610
|
+
out[key] = {
|
|
3611
|
+
found: false,
|
|
3612
|
+
columns,
|
|
3613
|
+
rows: [],
|
|
3614
|
+
fromSlug: field.from
|
|
3615
|
+
};
|
|
3616
|
+
continue;
|
|
3617
|
+
}
|
|
3618
|
+
for (const column of columns) column.label = data.schema.fields[column.key]?.label ?? column.key;
|
|
3619
|
+
out[key] = {
|
|
3620
|
+
found: true,
|
|
3621
|
+
columns,
|
|
3622
|
+
rows: backlinkRows(field, String(record?.[schema.primaryKey] ?? ""), derivedSourceItems(embedCache, field.from) ?? []).map((row) => ({
|
|
3623
|
+
id: String(row[data.schema.primaryKey] ?? ""),
|
|
3624
|
+
cells: columns.map((column) => formatBacklinkCell(data.schema.fields[column.key], row[column.key], row, locale))
|
|
3625
|
+
})),
|
|
3626
|
+
fromSlug: field.from
|
|
3627
|
+
};
|
|
3628
|
+
}
|
|
3629
|
+
return out;
|
|
3630
|
+
}
|
|
3631
|
+
var derivedSourceMemo = /* @__PURE__ */ new WeakMap();
|
|
3632
|
+
function derivedSourceItems(embedCache, from) {
|
|
3633
|
+
const data = embedCache[from];
|
|
3634
|
+
if (!data) return null;
|
|
3635
|
+
let bySlug = derivedSourceMemo.get(embedCache);
|
|
3636
|
+
if (!bySlug) {
|
|
3637
|
+
bySlug = /* @__PURE__ */ new Map();
|
|
3638
|
+
derivedSourceMemo.set(embedCache, bySlug);
|
|
3639
|
+
}
|
|
3640
|
+
let items = bySlug.get(from);
|
|
3641
|
+
if (!items) {
|
|
3642
|
+
items = Object.values(derivedRecordsById(data.schema, data.items));
|
|
3643
|
+
bySlug.set(from, items);
|
|
3644
|
+
}
|
|
3645
|
+
return items;
|
|
3646
|
+
}
|
|
3647
|
+
/** The rollup scalar for one record, from the reverse sources riding the
|
|
3648
|
+
* embed cache — the SAME index (non-empty ids, one record per id, derived
|
|
3649
|
+
* against themselves) and the SAME `rollupValue` the server enrichment
|
|
3650
|
+
* uses, so the cell and getItems can't disagree. Null (em-dash) when the
|
|
3651
|
+
* source collection isn't loadable; a real 0 for an empty match set. */
|
|
3652
|
+
function rollupValueFor(field, record, schema, embedCache) {
|
|
3653
|
+
if (field.type !== "rollup" || !schema || !record) return null;
|
|
3654
|
+
const items = derivedSourceItems(embedCache, field.from);
|
|
3655
|
+
if (items === null) return null;
|
|
3656
|
+
return rollupValue(field, String(record[schema.primaryKey] ?? ""), items);
|
|
3657
|
+
}
|
|
3658
|
+
/** Display string for a rollup cell: the aggregate as a plain number,
|
|
3659
|
+
* em-dash when the source collection couldn't be resolved. */
|
|
3660
|
+
function renderRollup(field, record, schema, embedCache) {
|
|
3661
|
+
const value = rollupValueFor(field, record, schema, embedCache);
|
|
3662
|
+
return value === null ? "—" : formatCell(value, "number");
|
|
3663
|
+
}
|
|
3664
|
+
/** Copy of `item` with every rollup field resolved from the reverse
|
|
3665
|
+
* sources — injected BEFORE the formula pass so a `derived` formula can
|
|
3666
|
+
* read rollup values as plain identifiers (`played = homePlayed +
|
|
3667
|
+
* awayPlayed`), in the same rollups-then-formulas order the server
|
|
3668
|
+
* enrichment runs. Returns `item` unchanged when the schema declares no
|
|
3669
|
+
* rollups (the overwhelmingly common case — no copy). */
|
|
3670
|
+
function withRollupValues(schema, item, embedCache) {
|
|
3671
|
+
if (!schema) return item;
|
|
3672
|
+
let out = item;
|
|
3673
|
+
for (const [key, field] of Object.entries(schema.fields)) {
|
|
3674
|
+
if (field.type !== "rollup") continue;
|
|
3675
|
+
if (out === item) out = { ...item };
|
|
3676
|
+
out[key] = rollupValueFor(field, item, schema, embedCache);
|
|
3677
|
+
}
|
|
3678
|
+
return out;
|
|
3679
|
+
}
|
|
3312
3680
|
function renderSubCell(subField, value, record, refCache, locale) {
|
|
3313
3681
|
if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale);
|
|
3314
3682
|
if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return lookupRefDisplay(refCache, subField.to, value);
|
|
3315
3683
|
return formatCell(value, subField.type);
|
|
3316
3684
|
}
|
|
3317
|
-
function evaluateDerived(field, fieldKey, item, schema, refRecords) {
|
|
3685
|
+
function evaluateDerived(field, fieldKey, item, schema, refRecords, embedCache = {}) {
|
|
3318
3686
|
if (field.type !== "derived" || !schema) return null;
|
|
3319
|
-
const result = deriveAll(schema, item, refRecords)[fieldKey];
|
|
3687
|
+
const result = deriveAll(schema, withRollupValues(schema, item, embedCache), refRecords)[fieldKey];
|
|
3320
3688
|
return typeof result === "number" && Number.isFinite(result) ? result : null;
|
|
3321
3689
|
}
|
|
3322
3690
|
function renderDerived(field, computedValue, record, locale) {
|
|
@@ -3349,11 +3717,18 @@ function useCollectionRendering(collection, locale) {
|
|
|
3349
3717
|
refOptions: (targetSlug) => refOptionsFor(refCache.value, targetSlug),
|
|
3350
3718
|
embedOptions: (targetSlug) => embedOptionsFor(embedCache.value, targetSlug),
|
|
3351
3719
|
embedViewsFor: (record) => buildEmbedViews(collection.value?.schema ?? null, embedCache.value, record, locale.value),
|
|
3720
|
+
backlinksViewsFor: (record) => buildBacklinksViews(collection.value?.schema ?? null, embedCache.value, record, locale.value),
|
|
3721
|
+
rollupDisplay: (field, record) => renderRollup(field, record, collection.value?.schema ?? null, embedCache.value),
|
|
3352
3722
|
currencySymbol: (currency) => currencySymbolForLocale(currency, locale.value),
|
|
3353
3723
|
artifactUrl: (value) => collectionUi().fileAssetUrl(value),
|
|
3354
3724
|
fileRoutePath: (value) => collectionUi().fileRoutePath(value),
|
|
3355
3725
|
formatSubCell: (subField, value, record) => renderSubCell(subField, value, record, refCache.value, locale.value),
|
|
3356
|
-
evaluateDerivedAgainstItem: (field, fieldKey, item) => evaluateDerived(field, fieldKey, item, collection.value?.schema ?? null, refRecordCache.value),
|
|
3726
|
+
evaluateDerivedAgainstItem: (field, fieldKey, item) => evaluateDerived(field, fieldKey, item, collection.value?.schema ?? null, refRecordCache.value, embedCache.value),
|
|
3727
|
+
deriveRecord: (item) => {
|
|
3728
|
+
const schema = collection.value?.schema ?? null;
|
|
3729
|
+
if (!schema) return item;
|
|
3730
|
+
return deriveAll(schema, withRollupValues(schema, item, embedCache.value), refRecordCache.value);
|
|
3731
|
+
},
|
|
3357
3732
|
derivedDisplay: (field, computedValue, record) => renderDerived(field, computedValue, record, locale.value)
|
|
3358
3733
|
};
|
|
3359
3734
|
}
|
|
@@ -3470,206 +3845,211 @@ var _hoisted_11$4 = [
|
|
|
3470
3845
|
];
|
|
3471
3846
|
var _hoisted_12$4 = {
|
|
3472
3847
|
key: 0,
|
|
3848
|
+
class: "material-icons text-sm animate-spin"
|
|
3849
|
+
};
|
|
3850
|
+
var _hoisted_13$4 = {
|
|
3851
|
+
key: 1,
|
|
3473
3852
|
class: "material-icons text-sm"
|
|
3474
3853
|
};
|
|
3475
|
-
var _hoisted_13$4 = ["title", "aria-label"];
|
|
3476
3854
|
var _hoisted_14$4 = ["title", "aria-label"];
|
|
3477
|
-
var _hoisted_15$4 =
|
|
3855
|
+
var _hoisted_15$4 = ["title", "aria-label"];
|
|
3856
|
+
var _hoisted_16$4 = {
|
|
3478
3857
|
key: 1,
|
|
3479
3858
|
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",
|
|
3480
3859
|
"data-testid": "collections-refresh-note"
|
|
3481
3860
|
};
|
|
3482
|
-
var
|
|
3483
|
-
var
|
|
3861
|
+
var _hoisted_17$4 = { class: "flex-1" };
|
|
3862
|
+
var _hoisted_18$4 = {
|
|
3484
3863
|
key: 2,
|
|
3485
3864
|
class: "px-6 py-3 bg-white border-b border-slate-100 flex items-center justify-between gap-4"
|
|
3486
3865
|
};
|
|
3487
|
-
var
|
|
3866
|
+
var _hoisted_19$2 = {
|
|
3488
3867
|
key: 0,
|
|
3489
3868
|
class: "relative flex-1 max-w-md"
|
|
3490
3869
|
};
|
|
3491
|
-
var
|
|
3492
|
-
var
|
|
3493
|
-
var
|
|
3494
|
-
var
|
|
3495
|
-
var _hoisted_23$2 = ["aria-pressed"];
|
|
3870
|
+
var _hoisted_20$2 = ["placeholder", "aria-label"];
|
|
3871
|
+
var _hoisted_21$2 = ["aria-label"];
|
|
3872
|
+
var _hoisted_22$2 = { class: "flex items-center gap-2" };
|
|
3873
|
+
var _hoisted_23$2 = ["aria-label"];
|
|
3496
3874
|
var _hoisted_24$1 = ["aria-pressed"];
|
|
3497
3875
|
var _hoisted_25$1 = ["aria-pressed"];
|
|
3498
|
-
var _hoisted_26$1 = [
|
|
3876
|
+
var _hoisted_26$1 = ["aria-pressed"];
|
|
3877
|
+
var _hoisted_27$1 = [
|
|
3499
3878
|
"aria-pressed",
|
|
3500
3879
|
"data-testid",
|
|
3501
3880
|
"onClick"
|
|
3502
3881
|
];
|
|
3503
|
-
var
|
|
3504
|
-
var
|
|
3882
|
+
var _hoisted_28 = { class: "material-icons text-sm" };
|
|
3883
|
+
var _hoisted_29 = [
|
|
3505
3884
|
"title",
|
|
3506
3885
|
"aria-label",
|
|
3507
3886
|
"aria-expanded"
|
|
3508
3887
|
];
|
|
3509
|
-
var
|
|
3888
|
+
var _hoisted_30 = {
|
|
3510
3889
|
key: 0,
|
|
3511
3890
|
class: "absolute left-0 top-full mt-1 z-20 min-w-max rounded border border-slate-200 bg-white shadow-lg py-1",
|
|
3512
3891
|
"data-testid": "collection-view-add-menu"
|
|
3513
3892
|
};
|
|
3514
|
-
var
|
|
3515
|
-
var
|
|
3516
|
-
var
|
|
3517
|
-
var
|
|
3518
|
-
var
|
|
3519
|
-
var
|
|
3893
|
+
var _hoisted_31 = ["title", "aria-label"];
|
|
3894
|
+
var _hoisted_32 = ["value", "aria-label"];
|
|
3895
|
+
var _hoisted_33 = ["value"];
|
|
3896
|
+
var _hoisted_34 = ["value", "aria-label"];
|
|
3897
|
+
var _hoisted_35 = ["value"];
|
|
3898
|
+
var _hoisted_36 = {
|
|
3520
3899
|
key: 3,
|
|
3521
3900
|
class: "text-[10px] text-slate-400 font-bold uppercase tracking-wider select-none"
|
|
3522
3901
|
};
|
|
3523
|
-
var
|
|
3902
|
+
var _hoisted_37 = {
|
|
3524
3903
|
key: 3,
|
|
3525
3904
|
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",
|
|
3526
3905
|
"data-testid": "collections-data-issues"
|
|
3527
3906
|
};
|
|
3528
|
-
var
|
|
3529
|
-
var
|
|
3530
|
-
var
|
|
3907
|
+
var _hoisted_38 = { class: "flex-1" };
|
|
3908
|
+
var _hoisted_39 = { class: "flex-1 overflow-auto" };
|
|
3909
|
+
var _hoisted_40 = {
|
|
3531
3910
|
key: 0,
|
|
3532
3911
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-500 gap-3"
|
|
3533
3912
|
};
|
|
3534
|
-
var
|
|
3913
|
+
var _hoisted_41 = {
|
|
3535
3914
|
key: 1,
|
|
3536
3915
|
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"
|
|
3537
3916
|
};
|
|
3538
|
-
var
|
|
3539
|
-
var
|
|
3917
|
+
var _hoisted_42 = { key: 2 };
|
|
3918
|
+
var _hoisted_43 = {
|
|
3540
3919
|
key: 3,
|
|
3541
3920
|
class: "p-4"
|
|
3542
3921
|
};
|
|
3543
|
-
var
|
|
3922
|
+
var _hoisted_44 = {
|
|
3544
3923
|
key: 4,
|
|
3545
3924
|
class: "h-full flex flex-col"
|
|
3546
3925
|
};
|
|
3547
|
-
var
|
|
3926
|
+
var _hoisted_45 = {
|
|
3548
3927
|
key: 0,
|
|
3549
3928
|
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",
|
|
3550
3929
|
"data-testid": "collections-inline-error"
|
|
3551
3930
|
};
|
|
3552
|
-
var
|
|
3553
|
-
var
|
|
3554
|
-
var
|
|
3555
|
-
var
|
|
3931
|
+
var _hoisted_46 = { class: "flex-1" };
|
|
3932
|
+
var _hoisted_47 = ["aria-label"];
|
|
3933
|
+
var _hoisted_48 = { class: "flex-1 min-h-0 px-3 py-2" };
|
|
3934
|
+
var _hoisted_49 = {
|
|
3556
3935
|
key: 5,
|
|
3557
3936
|
class: "h-full",
|
|
3558
3937
|
"data-testid": "collection-custom-view-body"
|
|
3559
3938
|
};
|
|
3560
|
-
var
|
|
3939
|
+
var _hoisted_50 = {
|
|
3561
3940
|
key: 6,
|
|
3562
3941
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
|
|
3563
3942
|
};
|
|
3564
|
-
var
|
|
3565
|
-
var
|
|
3943
|
+
var _hoisted_51 = { class: "font-semibold text-slate-600" };
|
|
3944
|
+
var _hoisted_52 = {
|
|
3566
3945
|
key: 7,
|
|
3567
3946
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
|
|
3568
3947
|
};
|
|
3569
|
-
var
|
|
3570
|
-
var
|
|
3948
|
+
var _hoisted_53 = { class: "font-semibold text-slate-600" };
|
|
3949
|
+
var _hoisted_54 = {
|
|
3571
3950
|
key: 8,
|
|
3572
3951
|
class: "overflow-x-auto [container-type:inline-size]"
|
|
3573
3952
|
};
|
|
3574
|
-
var
|
|
3953
|
+
var _hoisted_55 = {
|
|
3575
3954
|
key: 0,
|
|
3576
3955
|
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",
|
|
3577
3956
|
"data-testid": "collections-inline-error"
|
|
3578
3957
|
};
|
|
3579
|
-
var
|
|
3580
|
-
var
|
|
3581
|
-
var
|
|
3582
|
-
var
|
|
3583
|
-
var
|
|
3584
|
-
var
|
|
3585
|
-
var
|
|
3586
|
-
var
|
|
3958
|
+
var _hoisted_56 = { class: "flex-1" };
|
|
3959
|
+
var _hoisted_57 = ["aria-label"];
|
|
3960
|
+
var _hoisted_58 = { class: "min-w-full text-xs" };
|
|
3961
|
+
var _hoisted_59 = { class: "bg-slate-50 border-b border-slate-200" };
|
|
3962
|
+
var _hoisted_60 = ["aria-sort"];
|
|
3963
|
+
var _hoisted_61 = { class: "flex items-center gap-1" };
|
|
3964
|
+
var _hoisted_62 = ["title"];
|
|
3965
|
+
var _hoisted_63 = [
|
|
3587
3966
|
"data-testid",
|
|
3588
3967
|
"aria-label",
|
|
3589
3968
|
"onClick",
|
|
3590
3969
|
"onPointerenter"
|
|
3591
3970
|
];
|
|
3592
|
-
var
|
|
3593
|
-
var
|
|
3594
|
-
var
|
|
3971
|
+
var _hoisted_64 = { class: "material-icons text-base align-middle" };
|
|
3972
|
+
var _hoisted_65 = { class: "divide-y divide-slate-100 bg-white" };
|
|
3973
|
+
var _hoisted_66 = [
|
|
3595
3974
|
"aria-label",
|
|
3596
3975
|
"data-testid",
|
|
3597
3976
|
"onClick",
|
|
3598
3977
|
"onKeydown"
|
|
3599
3978
|
];
|
|
3600
|
-
var
|
|
3979
|
+
var _hoisted_67 = [
|
|
3601
3980
|
"checked",
|
|
3602
3981
|
"disabled",
|
|
3603
3982
|
"data-testid",
|
|
3604
3983
|
"aria-label",
|
|
3605
3984
|
"onChange"
|
|
3606
3985
|
];
|
|
3607
|
-
var
|
|
3986
|
+
var _hoisted_68 = [
|
|
3608
3987
|
"checked",
|
|
3609
3988
|
"disabled",
|
|
3610
3989
|
"data-testid",
|
|
3611
3990
|
"aria-label",
|
|
3612
3991
|
"onChange"
|
|
3613
3992
|
];
|
|
3614
|
-
var
|
|
3993
|
+
var _hoisted_69 = {
|
|
3615
3994
|
key: 2,
|
|
3616
3995
|
class: "block truncate"
|
|
3617
3996
|
};
|
|
3618
|
-
var
|
|
3997
|
+
var _hoisted_70 = [
|
|
3619
3998
|
"href",
|
|
3620
3999
|
"tabindex",
|
|
3621
4000
|
"data-testid",
|
|
3622
4001
|
"onClick",
|
|
3623
4002
|
"onKeydown"
|
|
3624
4003
|
];
|
|
3625
|
-
var
|
|
4004
|
+
var _hoisted_71 = [
|
|
3626
4005
|
"value",
|
|
3627
4006
|
"disabled",
|
|
3628
4007
|
"data-testid",
|
|
3629
4008
|
"aria-label",
|
|
3630
4009
|
"onChange"
|
|
3631
4010
|
];
|
|
3632
|
-
var
|
|
4011
|
+
var _hoisted_72 = {
|
|
3633
4012
|
key: 0,
|
|
3634
4013
|
value: ""
|
|
3635
4014
|
};
|
|
3636
|
-
var
|
|
3637
|
-
var
|
|
4015
|
+
var _hoisted_73 = ["value"];
|
|
4016
|
+
var _hoisted_74 = {
|
|
3638
4017
|
key: 4,
|
|
3639
4018
|
class: "block truncate tabular-nums font-semibold text-slate-900"
|
|
3640
4019
|
};
|
|
3641
|
-
var
|
|
4020
|
+
var _hoisted_75 = {
|
|
3642
4021
|
key: 5,
|
|
3643
4022
|
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"
|
|
3644
4023
|
};
|
|
3645
|
-
var
|
|
4024
|
+
var _hoisted_76 = {
|
|
3646
4025
|
key: 6,
|
|
3647
4026
|
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"
|
|
3648
4027
|
};
|
|
3649
|
-
var
|
|
3650
|
-
var
|
|
3651
|
-
var
|
|
4028
|
+
var _hoisted_77 = ["data-testid"];
|
|
4029
|
+
var _hoisted_78 = ["href", "data-testid"];
|
|
4030
|
+
var _hoisted_79 = ["href", "data-testid"];
|
|
4031
|
+
var _hoisted_80 = [
|
|
3652
4032
|
"href",
|
|
3653
4033
|
"data-testid",
|
|
3654
4034
|
"onClick"
|
|
3655
4035
|
];
|
|
3656
|
-
var
|
|
3657
|
-
key:
|
|
4036
|
+
var _hoisted_81 = {
|
|
4037
|
+
key: 11,
|
|
3658
4038
|
class: "block truncate text-slate-600"
|
|
3659
4039
|
};
|
|
3660
|
-
var
|
|
3661
|
-
var
|
|
3662
|
-
var
|
|
3663
|
-
var
|
|
4040
|
+
var _hoisted_82 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
|
|
4041
|
+
var _hoisted_83 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
|
|
4042
|
+
var _hoisted_84 = { class: "flex-1" };
|
|
4043
|
+
var _hoisted_85 = {
|
|
3664
4044
|
id: "collections-chat-title",
|
|
3665
4045
|
class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
|
|
3666
4046
|
};
|
|
3667
|
-
var
|
|
3668
|
-
var
|
|
3669
|
-
var
|
|
3670
|
-
var
|
|
3671
|
-
var
|
|
3672
|
-
var
|
|
4047
|
+
var _hoisted_86 = { class: "text-xs text-slate-400 font-semibold" };
|
|
4048
|
+
var _hoisted_87 = ["aria-label"];
|
|
4049
|
+
var _hoisted_88 = { class: "px-6 py-5" };
|
|
4050
|
+
var _hoisted_89 = ["placeholder", "onKeydown"];
|
|
4051
|
+
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" };
|
|
4052
|
+
var _hoisted_91 = ["disabled"];
|
|
3673
4053
|
/** `slug` / `selected` are supplied only in EMBEDDED mode (the
|
|
3674
4054
|
* `presentCollection` chat card mounts this component and drives both
|
|
3675
4055
|
* from the tool result). In standalone route mode (the
|
|
@@ -3771,11 +4151,26 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3771
4151
|
const actionPending = ref(false);
|
|
3772
4152
|
const actionError = ref(null);
|
|
3773
4153
|
const collectionActionPending = ref(false);
|
|
4154
|
+
const runningActions = ref(/* @__PURE__ */ new Set());
|
|
4155
|
+
let runningActionsGen = 0;
|
|
4156
|
+
function mutateRunningActions(mutate) {
|
|
4157
|
+
runningActionsGen += 1;
|
|
4158
|
+
const next = new Set(runningActions.value);
|
|
4159
|
+
mutate(next);
|
|
4160
|
+
runningActions.value = next;
|
|
4161
|
+
}
|
|
4162
|
+
/** Adopt a detail response's `runningActions` — only when no local
|
|
4163
|
+
* mutation happened while the response was in flight (stale snapshots
|
|
4164
|
+
* are dropped; the completion ping's refetch reconciles soon after). */
|
|
4165
|
+
function applyServerRunningActions(keys, genAtFetch) {
|
|
4166
|
+
if (runningActionsGen !== genAtFetch) return;
|
|
4167
|
+
runningActions.value = new Set(keys ?? []);
|
|
4168
|
+
}
|
|
3774
4169
|
const chatOpen = ref(false);
|
|
3775
4170
|
const chatMessage = ref("");
|
|
3776
4171
|
const chatInputEl = ref(null);
|
|
3777
4172
|
const render = useCollectionRendering(collection, locale);
|
|
3778
|
-
const {
|
|
4173
|
+
const { refDisplay, formatMoney, resolveCurrency, derivedDisplay, evaluateDerivedAgainstItem, formatCell, isExternalUrl, artifactUrl, fileRoutePath } = render;
|
|
3779
4174
|
const searchQuery = ref("");
|
|
3780
4175
|
/** Case-insensitive substring match across an item's scalar fields.
|
|
3781
4176
|
* Object-valued fields (table rows, nested records) are skipped —
|
|
@@ -3849,7 +4244,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3849
4244
|
function derivedSortValue(field, key, item) {
|
|
3850
4245
|
const display = field.type === "derived" ? field.display : void 0;
|
|
3851
4246
|
if (display === void 0 || display === "number" || display === "money") return numericSortValue(evaluateDerivedAgainstItem(field, key, item));
|
|
3852
|
-
const enriched =
|
|
4247
|
+
const enriched = render.deriveRecord(item);
|
|
3853
4248
|
if (display === "date") return dateSortValue(enriched[key]);
|
|
3854
4249
|
return stringSortValue(enriched[key]);
|
|
3855
4250
|
}
|
|
@@ -3937,20 +4332,33 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3937
4332
|
}
|
|
3938
4333
|
/** Collection-level header actions. No `when` predicate (no record). */
|
|
3939
4334
|
const collectionActions = computed(() => collection.value?.schema.collectionActions ?? []);
|
|
4335
|
+
/** True when a `kind: "agent"` action's hidden worker is in flight —
|
|
4336
|
+
* drives the button spinner + disable. Keys mirror the server's
|
|
4337
|
+
* dispatch guard via `agentActionRunKey`. */
|
|
4338
|
+
function isActionRunning(actionId, itemId) {
|
|
4339
|
+
return runningActions.value.has(agentActionRunKey(actionId, itemId));
|
|
4340
|
+
}
|
|
3940
4341
|
/** Run a collection-level action: ask the server to assemble the seed
|
|
3941
|
-
* prompt (a progress summary of all records + the template)
|
|
3942
|
-
*
|
|
4342
|
+
* prompt (a progress summary of all records + the template). `kind:
|
|
4343
|
+
* "chat"` gets the seed back and starts a new chat; `kind: "agent"` is
|
|
4344
|
+
* dispatched server-side as a hidden worker — mark it running and let
|
|
4345
|
+
* the completion ping's refetch reconcile. Generic — no domain knowledge. */
|
|
3943
4346
|
async function runCollectionAction(action) {
|
|
3944
4347
|
const current = collection.value;
|
|
3945
|
-
if (!current || collectionActionPending.value) return;
|
|
4348
|
+
if (!current || collectionActionPending.value || isActionRunning(action.id)) return;
|
|
4349
|
+
const runKey = action.kind === "agent" ? agentActionRunKey(action.id) : null;
|
|
4350
|
+
if (runKey) mutateRunningActions((next) => next.add(runKey));
|
|
3946
4351
|
collectionActionPending.value = true;
|
|
3947
4352
|
inlineError.value = null;
|
|
3948
4353
|
const result = await cui.runCollectionAction(current.slug, action.id);
|
|
3949
4354
|
collectionActionPending.value = false;
|
|
3950
4355
|
if (!result.ok) {
|
|
4356
|
+
if (runKey && result.status !== 409) mutateRunningActions((next) => next.delete(runKey));
|
|
3951
4357
|
inlineError.value = result.error;
|
|
3952
4358
|
return;
|
|
3953
4359
|
}
|
|
4360
|
+
if (result.data.dispatched) return;
|
|
4361
|
+
if (result.data.written) return;
|
|
3954
4362
|
if (props.sendTextMessage) {
|
|
3955
4363
|
props.sendTextMessage(result.data.prompt);
|
|
3956
4364
|
return;
|
|
@@ -3985,27 +4393,88 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3985
4393
|
if (!record) return [];
|
|
3986
4394
|
return (collection.value?.schema.actions ?? []).filter((action) => actionVisible(action, record));
|
|
3987
4395
|
});
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
4396
|
+
const mutateModal = ref(null);
|
|
4397
|
+
const mutatePending = ref(false);
|
|
4398
|
+
const mutateError = ref(null);
|
|
4399
|
+
/** POST one mutate action and, on success, adopt the written record for
|
|
4400
|
+
* the open panel (the write's change ping refreshes the table rows).
|
|
4401
|
+
* Errors land in the modal when one is open, else on the panel. */
|
|
4402
|
+
async function executeMutate(action, itemId, params) {
|
|
4403
|
+
if (!collection.value || mutatePending.value) return false;
|
|
4404
|
+
mutatePending.value = true;
|
|
4405
|
+
const result = await cui.runItemAction(collection.value.slug, itemId, action.id, params);
|
|
4406
|
+
mutatePending.value = false;
|
|
4407
|
+
if (!result.ok) {
|
|
4408
|
+
if (mutateModal.value) mutateError.value = result.error;
|
|
4409
|
+
else actionError.value = result.error;
|
|
4410
|
+
return false;
|
|
4411
|
+
}
|
|
4412
|
+
if (result.data.written && viewing.value && String(viewing.value[collection.value.schema.primaryKey] ?? "") === itemId) viewing.value = result.data.item;
|
|
4413
|
+
return true;
|
|
4414
|
+
}
|
|
4415
|
+
async function submitMutateParams(params) {
|
|
4416
|
+
const open = mutateModal.value;
|
|
4417
|
+
if (!open) return;
|
|
4418
|
+
mutateError.value = null;
|
|
4419
|
+
if (await executeMutate(open.action, open.itemId, params)) mutateModal.value = null;
|
|
4420
|
+
}
|
|
4421
|
+
/** Mutate kind: open the params mini-form when the action declares one,
|
|
4422
|
+
* else apply the declarative write immediately. */
|
|
4423
|
+
async function runMutateAction(action, itemId) {
|
|
4424
|
+
actionError.value = null;
|
|
4425
|
+
if (action.params && Object.keys(action.params).length > 0) {
|
|
4426
|
+
mutateError.value = null;
|
|
4427
|
+
mutateModal.value = {
|
|
4428
|
+
action,
|
|
4429
|
+
itemId
|
|
4430
|
+
};
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4433
|
+
await executeMutate(action, itemId, {});
|
|
4434
|
+
}
|
|
4435
|
+
/** Run a schema-declared action on the open record. `kind: "mutate"`
|
|
4436
|
+
* never leaves the host: with `params` it opens the mini-form, else it
|
|
4437
|
+
* applies immediately. `kind: "chat"` gets the seed back and starts a
|
|
4438
|
+
* new chat; `kind: "agent"` is dispatched server-side as a hidden
|
|
4439
|
+
* worker — mark it running and let the completion ping's refetch
|
|
4440
|
+
* reconcile. Generic — no knowledge of what the action does. */
|
|
3991
4441
|
async function runAction(action) {
|
|
3992
4442
|
if (!collection.value || !viewing.value) return;
|
|
3993
4443
|
const itemId = String(viewing.value[collection.value.schema.primaryKey] ?? "");
|
|
3994
|
-
if (!itemId) return;
|
|
4444
|
+
if (!itemId || isActionRunning(action.id, itemId)) return;
|
|
4445
|
+
if (action.kind === "mutate") {
|
|
4446
|
+
await runMutateAction(action, itemId);
|
|
4447
|
+
return;
|
|
4448
|
+
}
|
|
4449
|
+
const runKey = action.kind === "agent" ? agentActionRunKey(action.id, itemId) : null;
|
|
4450
|
+
if (runKey) mutateRunningActions((next) => next.add(runKey));
|
|
3995
4451
|
actionPending.value = true;
|
|
3996
4452
|
actionError.value = null;
|
|
3997
4453
|
const result = await cui.runItemAction(collection.value.slug, itemId, action.id);
|
|
3998
4454
|
actionPending.value = false;
|
|
3999
4455
|
if (!result.ok) {
|
|
4456
|
+
if (runKey && result.status !== 409) mutateRunningActions((next) => next.delete(runKey));
|
|
4000
4457
|
actionError.value = result.error;
|
|
4001
4458
|
return;
|
|
4002
4459
|
}
|
|
4460
|
+
if (result.data.dispatched) return;
|
|
4461
|
+
if (result.data.written) return;
|
|
4003
4462
|
if (props.sendTextMessage) {
|
|
4004
4463
|
props.sendTextMessage(result.data.prompt);
|
|
4005
4464
|
return;
|
|
4006
4465
|
}
|
|
4007
4466
|
appApi.startNewChat(result.data.prompt, result.data.role);
|
|
4008
4467
|
}
|
|
4468
|
+
/** Ids of the open record's actions whose hidden worker is running — the
|
|
4469
|
+
* record panel renders those buttons with a spinner, disabled. */
|
|
4470
|
+
const viewingRunningActionIds = computed(() => {
|
|
4471
|
+
const current = collection.value;
|
|
4472
|
+
const record = viewing.value;
|
|
4473
|
+
if (!current || !record) return [];
|
|
4474
|
+
const itemId = String(record[current.schema.primaryKey] ?? "");
|
|
4475
|
+
if (!itemId) return [];
|
|
4476
|
+
return (current.schema.actions ?? []).filter((action) => isActionRunning(action.id, itemId)).map((action) => action.id);
|
|
4477
|
+
});
|
|
4009
4478
|
/** Open the chat modal, blanking any prior draft and focusing the input. */
|
|
4010
4479
|
function openChat() {
|
|
4011
4480
|
chatMessage.value = "";
|
|
@@ -4071,10 +4540,12 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4071
4540
|
collection.value = null;
|
|
4072
4541
|
items.value = [];
|
|
4073
4542
|
dataIssues.value = [];
|
|
4543
|
+
mutateRunningActions((next) => next.clear());
|
|
4074
4544
|
searchQuery.value = "";
|
|
4075
4545
|
render.resetLinkedCaches();
|
|
4076
4546
|
viewing.value = null;
|
|
4077
4547
|
openDay.value = null;
|
|
4548
|
+
const runningGen = runningActionsGen;
|
|
4078
4549
|
const result = await cui.fetchCollectionDetail(slug);
|
|
4079
4550
|
loading.value = false;
|
|
4080
4551
|
if (!result.ok) {
|
|
@@ -4085,6 +4556,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4085
4556
|
collection.value = result.data.collection;
|
|
4086
4557
|
items.value = result.data.items;
|
|
4087
4558
|
dataIssues.value = result.data.issues ?? [];
|
|
4559
|
+
applyServerRunningActions(result.data.runningActions, runningGen);
|
|
4088
4560
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4089
4561
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4090
4562
|
if (collection.value?.slug === slug) syncViewToSelected();
|
|
@@ -4100,11 +4572,13 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4100
4572
|
* fetch is a no-op (keep the current data) — a transient blip shouldn't blank a
|
|
4101
4573
|
* view the user is reading. */
|
|
4102
4574
|
async function refreshItemsInPlace(slug) {
|
|
4575
|
+
const runningGen = runningActionsGen;
|
|
4103
4576
|
const result = await cui.fetchCollectionDetail(slug);
|
|
4104
4577
|
if (!result.ok || activeSlug.value !== slug) return;
|
|
4105
4578
|
collection.value = result.data.collection;
|
|
4106
4579
|
items.value = result.data.items;
|
|
4107
4580
|
dataIssues.value = result.data.issues ?? [];
|
|
4581
|
+
applyServerRunningActions(result.data.runningActions, runningGen);
|
|
4108
4582
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4109
4583
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4110
4584
|
if (activeSlug.value !== slug) return;
|
|
@@ -4125,7 +4599,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4125
4599
|
* list table only (a whole embedded record doesn't fit a table cell,
|
|
4126
4600
|
* and it'd be identical in every row). The detail modal and the edit
|
|
4127
4601
|
* form iterate the full `schema.fields` so embeds render there too. */
|
|
4128
|
-
const listColumnFields = computed(() => collection.value ? Object.entries(collection.value.schema.fields).filter(([key, field]) => field.type !== "embed" && field.type !== "image" && key !== collection.value?.schema.primaryKey) : []);
|
|
4602
|
+
const listColumnFields = computed(() => collection.value ? Object.entries(collection.value.schema.fields).filter(([key, field]) => field.type !== "embed" && field.type !== "backlinks" && field.type !== "image" && key !== collection.value?.schema.primaryKey) : []);
|
|
4129
4603
|
/** True when the current collection declares `schema.singleton` —
|
|
4130
4604
|
* exactly one record, its primary key fixed to the declared value. */
|
|
4131
4605
|
const isSingleton = computed(() => Boolean(collection.value?.schema.singleton));
|
|
@@ -4314,7 +4788,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4314
4788
|
boolOriginallyPresent[key] = false;
|
|
4315
4789
|
boolTouched[key] = false;
|
|
4316
4790
|
} else if (field.type === "table") table[key] = [];
|
|
4317
|
-
else if (
|
|
4791
|
+
else if (!COMPUTED_TYPES.has(field.type)) text[key] = "";
|
|
4318
4792
|
const { singleton, primaryKey } = collection.value.schema;
|
|
4319
4793
|
if (singleton) text[primaryKey] = singleton;
|
|
4320
4794
|
else if (primaryKey in text) text[primaryKey] = generateUniqueItemId(primaryKey);
|
|
@@ -4346,7 +4820,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4346
4820
|
} else if (field.type === "table" && field.of) {
|
|
4347
4821
|
const sub = field.of;
|
|
4348
4822
|
table[key] = (Array.isArray(raw) ? raw : []).filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)).map((row) => rowFromItem(row, sub));
|
|
4349
|
-
} else if (
|
|
4823
|
+
} else if (!COMPUTED_TYPES.has(field.type)) text[key] = raw === void 0 || raw === null ? "" : String(raw);
|
|
4350
4824
|
}
|
|
4351
4825
|
const primaryRaw = item[collection.value.schema.primaryKey];
|
|
4352
4826
|
const originalId = typeof primaryRaw === "string" ? primaryRaw : String(primaryRaw ?? "");
|
|
@@ -4473,7 +4947,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4473
4947
|
* rendering composable; this binds it to the current draft. */
|
|
4474
4948
|
const liveDerived = computed(() => {
|
|
4475
4949
|
if (!collection.value || !liveRecord.value) return null;
|
|
4476
|
-
return render.
|
|
4950
|
+
return render.deriveRecord(liveRecord.value);
|
|
4477
4951
|
});
|
|
4478
4952
|
/** Short summary for a `table`-typed cell in the main collection
|
|
4479
4953
|
* table. Counts rows; nothing fancier yet (per-row preview is
|
|
@@ -4794,7 +5268,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4794
5268
|
"aria-label": unref(t)("collectionsView.backToIndex"),
|
|
4795
5269
|
"data-testid": "collections-back",
|
|
4796
5270
|
onClick: goBack
|
|
4797
|
-
}, [..._cache[
|
|
5271
|
+
}, [..._cache[26] || (_cache[26] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : createCommentVNode("", true),
|
|
4798
5272
|
collection.value ? (openBlock(), createElementBlock("div", _hoisted_4$5, [createElementVNode("span", _hoisted_5$5, toDisplayString(collection.value.icon), 1)])) : createCommentVNode("", true),
|
|
4799
5273
|
createElementVNode("div", _hoisted_6$4, [createElementVNode("h1", _hoisted_7$4, toDisplayString(collection.value?.title ?? unref(t)("collectionsView.title")), 1), collection.value ? (openBlock(), createElementBlock("span", _hoisted_8$4, toDisplayString(collection.value.slug), 1)) : createCommentVNode("", true)]),
|
|
4800
5274
|
collection.value && !embedded.value ? (openBlock(), createBlock(resolveDynamicComponent(unref(pinToggle)), {
|
|
@@ -4823,16 +5297,16 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4823
5297
|
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",
|
|
4824
5298
|
"data-testid": "collections-chat",
|
|
4825
5299
|
onClick: openChat
|
|
4826
|
-
}, [_cache[
|
|
5300
|
+
}, [_cache[27] || (_cache[27] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)])) : createCommentVNode("", true),
|
|
4827
5301
|
(openBlock(true), createElementBlock(Fragment, null, renderList(collectionActions.value, (action) => {
|
|
4828
5302
|
return openBlock(), createElementBlock("button", {
|
|
4829
5303
|
key: action.id,
|
|
4830
5304
|
type: "button",
|
|
4831
5305
|
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",
|
|
4832
|
-
disabled: collectionActionPending.value,
|
|
5306
|
+
disabled: collectionActionPending.value || isActionRunning(action.id),
|
|
4833
5307
|
"data-testid": `collections-action-${action.id}`,
|
|
4834
5308
|
onClick: ($event) => runCollectionAction(action)
|
|
4835
|
-
}, [action.
|
|
5309
|
+
}, [isActionRunning(action.id) ? (openBlock(), createElementBlock("span", _hoisted_12$4, "progress_activity")) : action.icon ? (openBlock(), createElementBlock("span", _hoisted_13$4, toDisplayString(action.icon), 1)) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(action.label), 1)], 8, _hoisted_11$4);
|
|
4836
5310
|
}), 128)),
|
|
4837
5311
|
canCreate.value && !calendarActive.value ? (openBlock(), createElementBlock("button", {
|
|
4838
5312
|
key: 5,
|
|
@@ -4840,7 +5314,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4840
5314
|
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",
|
|
4841
5315
|
"data-testid": "collections-add-item",
|
|
4842
5316
|
onClick: openCreate
|
|
4843
|
-
}, [_cache[
|
|
5317
|
+
}, [_cache[28] || (_cache[28] = createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.add")), 1)])) : createCommentVNode("", true),
|
|
4844
5318
|
canDeleteCollection.value && !embedded.value ? (openBlock(), createElementBlock("button", {
|
|
4845
5319
|
key: 6,
|
|
4846
5320
|
type: "button",
|
|
@@ -4849,7 +5323,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4849
5323
|
"aria-label": unref(t)("collectionsView.deleteCollection"),
|
|
4850
5324
|
"data-testid": "collections-delete",
|
|
4851
5325
|
onClick: confirmCollectionDelete
|
|
4852
|
-
}, [..._cache[
|
|
5326
|
+
}, [..._cache[29] || (_cache[29] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : createCommentVNode("", true),
|
|
4853
5327
|
canDeleteFeed.value && !embedded.value ? (openBlock(), createElementBlock("button", {
|
|
4854
5328
|
key: 7,
|
|
4855
5329
|
type: "button",
|
|
@@ -4858,26 +5332,26 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4858
5332
|
"aria-label": unref(t)("collectionsView.deleteFeed"),
|
|
4859
5333
|
"data-testid": "feeds-delete",
|
|
4860
5334
|
onClick: confirmFeedDelete
|
|
4861
|
-
}, [..._cache[
|
|
5335
|
+
}, [..._cache[30] || (_cache[30] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_15$4)) : createCommentVNode("", true)
|
|
4862
5336
|
])) : createCommentVNode("", true),
|
|
4863
|
-
refreshNote.value ? (openBlock(), createElementBlock("div",
|
|
4864
|
-
collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? (openBlock(), createElementBlock("div",
|
|
4865
|
-
_cache[
|
|
5337
|
+
refreshNote.value ? (openBlock(), createElementBlock("div", _hoisted_16$4, [_cache[31] || (_cache[31] = createElementVNode("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), createElementVNode("span", _hoisted_17$4, toDisplayString(refreshNote.value), 1)])) : createCommentVNode("", true),
|
|
5338
|
+
collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? (openBlock(), createElementBlock("div", _hoisted_18$4, [!__props.hideSearch && items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_19$2, [
|
|
5339
|
+
_cache[33] || (_cache[33] = createElementVNode("span", { class: "absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400 pointer-events-none" }, [createElementVNode("span", { class: "material-icons text-lg" }, "search")], -1)),
|
|
4866
5340
|
withDirectives(createElementVNode("input", {
|
|
4867
5341
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
|
|
4868
5342
|
type: "text",
|
|
4869
5343
|
placeholder: unref(t)("collectionsView.searchPlaceholder"),
|
|
4870
5344
|
"aria-label": unref(t)("collectionsView.searchPlaceholder"),
|
|
4871
5345
|
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"
|
|
4872
|
-
}, null, 8,
|
|
5346
|
+
}, null, 8, _hoisted_20$2), [[vModelText, searchQuery.value]]),
|
|
4873
5347
|
searchQuery.value ? (openBlock(), createElementBlock("button", {
|
|
4874
5348
|
key: 0,
|
|
4875
5349
|
type: "button",
|
|
4876
5350
|
"aria-label": unref(t)("collectionsView.clearSearch"),
|
|
4877
5351
|
class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
|
|
4878
5352
|
onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
|
|
4879
|
-
}, [..._cache[
|
|
4880
|
-
])) : createCommentVNode("", true), createElementVNode("div",
|
|
5353
|
+
}, [..._cache[32] || (_cache[32] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_21$2)) : createCommentVNode("", true)
|
|
5354
|
+
])) : createCommentVNode("", true), createElementVNode("div", _hoisted_22$2, [
|
|
4881
5355
|
!__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? (openBlock(), createElementBlock("div", {
|
|
4882
5356
|
key: 0,
|
|
4883
5357
|
class: "flex gap-0.5",
|
|
@@ -4890,7 +5364,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4890
5364
|
"aria-pressed": activeView.value === "table",
|
|
4891
5365
|
"data-testid": "collection-view-toggle-table",
|
|
4892
5366
|
onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
|
|
4893
|
-
}, [_cache[
|
|
5367
|
+
}, [_cache[34] || (_cache[34] = createElementVNode("span", { class: "material-icons text-sm" }, "table_rows", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewTable")), 1)], 10, _hoisted_24$1),
|
|
4894
5368
|
hasCalendar.value ? (openBlock(), createElementBlock("button", {
|
|
4895
5369
|
key: 0,
|
|
4896
5370
|
type: "button",
|
|
@@ -4898,7 +5372,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4898
5372
|
"aria-pressed": activeView.value === "calendar",
|
|
4899
5373
|
"data-testid": "collection-view-toggle-calendar",
|
|
4900
5374
|
onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
|
|
4901
|
-
}, [_cache[
|
|
5375
|
+
}, [_cache[35] || (_cache[35] = createElementVNode("span", { class: "material-icons text-sm" }, "calendar_month", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_25$1)) : createCommentVNode("", true),
|
|
4902
5376
|
hasKanban.value ? (openBlock(), createElementBlock("button", {
|
|
4903
5377
|
key: 1,
|
|
4904
5378
|
type: "button",
|
|
@@ -4906,7 +5380,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4906
5380
|
"aria-pressed": activeView.value === "kanban",
|
|
4907
5381
|
"data-testid": "collection-view-toggle-kanban",
|
|
4908
5382
|
onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
|
|
4909
|
-
}, [_cache[
|
|
5383
|
+
}, [_cache[36] || (_cache[36] = createElementVNode("span", { class: "material-icons text-sm" }, "view_kanban", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_26$1)) : createCommentVNode("", true),
|
|
4910
5384
|
(openBlock(true), createElementBlock(Fragment, null, renderList(customViews.value, (cv) => {
|
|
4911
5385
|
return openBlock(), createElementBlock("button", {
|
|
4912
5386
|
key: cv.id,
|
|
@@ -4915,7 +5389,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4915
5389
|
"aria-pressed": activeView.value === unref(customViewKey)(cv.id),
|
|
4916
5390
|
"data-testid": `collection-view-custom-${cv.id}`,
|
|
4917
5391
|
onClick: ($event) => setCustomView(cv.id)
|
|
4918
|
-
}, [createElementVNode("span",
|
|
5392
|
+
}, [createElementVNode("span", _hoisted_28, toDisplayString(cv.icon || (cv.target === "mobile" ? "smartphone" : "dashboard_customize")), 1), createElementVNode("span", null, toDisplayString(cv.label), 1)], 10, _hoisted_27$1);
|
|
4919
5393
|
}), 128)),
|
|
4920
5394
|
canAddCustomView.value ? (openBlock(), createElementBlock("div", {
|
|
4921
5395
|
key: 2,
|
|
@@ -4930,17 +5404,17 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4930
5404
|
"aria-expanded": addMenuOpen.value,
|
|
4931
5405
|
"data-testid": "collection-view-add",
|
|
4932
5406
|
onClick: onAddViewClick
|
|
4933
|
-
}, [..._cache[
|
|
5407
|
+
}, [..._cache[37] || (_cache[37] = [createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_29), addMenuOpen.value ? (openBlock(), createElementBlock("div", _hoisted_30, [createElementVNode("button", {
|
|
4934
5408
|
type: "button",
|
|
4935
5409
|
class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
|
|
4936
5410
|
"data-testid": "collection-view-add-desktop",
|
|
4937
5411
|
onClick: _cache[5] || (_cache[5] = ($event) => addCustomView("desktop"))
|
|
4938
|
-
}, [_cache[
|
|
5412
|
+
}, [_cache[38] || (_cache[38] = createElementVNode("span", { class: "material-icons text-sm" }, "dashboard_customize", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addViewDesktop")), 1)]), createElementVNode("button", {
|
|
4939
5413
|
type: "button",
|
|
4940
5414
|
class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
|
|
4941
5415
|
"data-testid": "collection-view-add-mobile",
|
|
4942
5416
|
onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("mobile"))
|
|
4943
|
-
}, [_cache[
|
|
5417
|
+
}, [_cache[39] || (_cache[39] = createElementVNode("span", { class: "material-icons text-sm" }, "smartphone", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addViewMobile")), 1)])])) : createCommentVNode("", true)], 512)) : createCommentVNode("", true),
|
|
4944
5418
|
canConfigureViews.value ? (openBlock(), createElementBlock("button", {
|
|
4945
5419
|
key: 3,
|
|
4946
5420
|
type: "button",
|
|
@@ -4949,8 +5423,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4949
5423
|
"aria-label": unref(t)("collectionsView.config.open"),
|
|
4950
5424
|
"data-testid": "collection-config-open",
|
|
4951
5425
|
onClick: _cache[7] || (_cache[7] = ($event) => configOpen.value = true)
|
|
4952
|
-
}, [..._cache[
|
|
4953
|
-
], 8,
|
|
5426
|
+
}, [..._cache[40] || (_cache[40] = [createElementVNode("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_31)) : createCommentVNode("", true)
|
|
5427
|
+
], 8, _hoisted_23$2)) : createCommentVNode("", true),
|
|
4954
5428
|
calendarActive.value && dateFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
|
|
4955
5429
|
key: 1,
|
|
4956
5430
|
value: calendarAnchorField.value,
|
|
@@ -4962,8 +5436,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4962
5436
|
return openBlock(), createElementBlock("option", {
|
|
4963
5437
|
key,
|
|
4964
5438
|
value: key
|
|
4965
|
-
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9,
|
|
4966
|
-
}), 128))], 40,
|
|
5439
|
+
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_33);
|
|
5440
|
+
}), 128))], 40, _hoisted_32)) : createCommentVNode("", true),
|
|
4967
5441
|
kanbanActive.value && enumFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
|
|
4968
5442
|
key: 2,
|
|
4969
5443
|
value: kanbanGroupField.value,
|
|
@@ -4975,24 +5449,24 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4975
5449
|
return openBlock(), createElementBlock("option", {
|
|
4976
5450
|
key,
|
|
4977
5451
|
value: key
|
|
4978
|
-
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9,
|
|
4979
|
-
}), 128))], 40,
|
|
4980
|
-
items.value.length > 0 ? (openBlock(), createElementBlock("div",
|
|
5452
|
+
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_35);
|
|
5453
|
+
}), 128))], 40, _hoisted_34)) : createCommentVNode("", true),
|
|
5454
|
+
items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_36, toDisplayString(unref(t)("collectionsView.searchSummary", {
|
|
4981
5455
|
shown: filteredItems.value.length,
|
|
4982
5456
|
total: items.value.length
|
|
4983
5457
|
})), 1)) : createCommentVNode("", true)
|
|
4984
5458
|
])])) : createCommentVNode("", true),
|
|
4985
|
-
collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div",
|
|
4986
|
-
_cache[
|
|
4987
|
-
createElementVNode("span",
|
|
5459
|
+
collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_37, [
|
|
5460
|
+
_cache[42] || (_cache[42] = createElementVNode("span", { class: "material-icons text-amber-600" }, "warning", -1)),
|
|
5461
|
+
createElementVNode("span", _hoisted_38, toDisplayString(unref(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
|
|
4988
5462
|
createElementVNode("button", {
|
|
4989
5463
|
type: "button",
|
|
4990
5464
|
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",
|
|
4991
5465
|
"data-testid": "collections-repair",
|
|
4992
5466
|
onClick: repairCollection
|
|
4993
|
-
}, [_cache[
|
|
5467
|
+
}, [_cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
|
|
4994
5468
|
])) : createCommentVNode("", true),
|
|
4995
|
-
createElementVNode("div",
|
|
5469
|
+
createElementVNode("div", _hoisted_39, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_40, [_cache[43] || (_cache[43] = createElementVNode("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.loading")), 1)])) : loadError.value ? (openBlock(), createElementBlock("div", _hoisted_41, [_cache[44] || (_cache[44] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)), createElementVNode("span", null, toDisplayString(loadError.value === "not-found" ? unref(t)("collectionsView.notFound") : `${unref(t)("collectionsView.loadFailed")}: ${loadError.value}`), 1)])) : !collection.value ? (openBlock(), createElementBlock("div", _hoisted_42)) : calendarActive.value ? (openBlock(), createElementBlock("div", _hoisted_43, [createVNode(CollectionCalendarView_default, {
|
|
4996
5470
|
schema: collection.value.schema,
|
|
4997
5471
|
items: filteredItems.value,
|
|
4998
5472
|
"anchor-field": calendarAnchorField.value,
|
|
@@ -5036,6 +5510,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5036
5510
|
"action-error": actionError.value,
|
|
5037
5511
|
"action-pending": actionPending.value,
|
|
5038
5512
|
"visible-actions": visibleActions.value,
|
|
5513
|
+
"running-action-ids": viewingRunningActionIds.value,
|
|
5039
5514
|
"live-record": liveRecord.value,
|
|
5040
5515
|
"live-derived": liveDerived.value,
|
|
5041
5516
|
"view-title": viewTitle.value,
|
|
@@ -5058,6 +5533,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5058
5533
|
"action-error",
|
|
5059
5534
|
"action-pending",
|
|
5060
5535
|
"visible-actions",
|
|
5536
|
+
"running-action-ids",
|
|
5061
5537
|
"live-record",
|
|
5062
5538
|
"live-derived",
|
|
5063
5539
|
"view-title",
|
|
@@ -5077,16 +5553,16 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5077
5553
|
"selected",
|
|
5078
5554
|
"can-create",
|
|
5079
5555
|
"show-detail"
|
|
5080
|
-
])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div",
|
|
5081
|
-
_cache[
|
|
5082
|
-
createElementVNode("span",
|
|
5556
|
+
])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div", _hoisted_44, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_45, [
|
|
5557
|
+
_cache[46] || (_cache[46] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
|
|
5558
|
+
createElementVNode("span", _hoisted_46, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
|
|
5083
5559
|
createElementVNode("button", {
|
|
5084
5560
|
type: "button",
|
|
5085
5561
|
class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
|
|
5086
5562
|
"aria-label": unref(t)("common.close"),
|
|
5087
5563
|
onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
|
|
5088
|
-
}, [..._cache[
|
|
5089
|
-
])) : createCommentVNode("", true), createElementVNode("div",
|
|
5564
|
+
}, [..._cache[45] || (_cache[45] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_47)
|
|
5565
|
+
])) : createCommentVNode("", true), createElementVNode("div", _hoisted_48, [createVNode(CollectionKanbanView_default, {
|
|
5090
5566
|
schema: collection.value.schema,
|
|
5091
5567
|
items: filteredItems.value,
|
|
5092
5568
|
"group-field": kanbanGroupField.value,
|
|
@@ -5100,7 +5576,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5100
5576
|
"group-field",
|
|
5101
5577
|
"selected",
|
|
5102
5578
|
"notified"
|
|
5103
|
-
])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div",
|
|
5579
|
+
])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_49, [activeCustomView.value.target === "mobile" ? (openBlock(), createBlock(CollectionRemoteViewPreview_default, {
|
|
5104
5580
|
key: 0,
|
|
5105
5581
|
slug: collection.value.slug,
|
|
5106
5582
|
view: activeCustomView.value,
|
|
@@ -5111,32 +5587,32 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5111
5587
|
view: activeCustomView.value,
|
|
5112
5588
|
onOpenItem: onCustomViewOpenItem,
|
|
5113
5589
|
onStartChat: onCustomViewStartChat
|
|
5114
|
-
}, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div",
|
|
5115
|
-
_cache[
|
|
5116
|
-
createElementVNode("p",
|
|
5590
|
+
}, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_50, [_cache[47] || (_cache[47] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_51, toDisplayString(unref(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_52, [
|
|
5591
|
+
_cache[48] || (_cache[48] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
|
|
5592
|
+
createElementVNode("p", _hoisted_53, toDisplayString(unref(t)("collectionsView.noMatchingItems")), 1),
|
|
5117
5593
|
createElementVNode("button", {
|
|
5118
5594
|
type: "button",
|
|
5119
5595
|
class: "text-xs text-indigo-600 font-semibold hover:underline",
|
|
5120
5596
|
onClick: _cache[13] || (_cache[13] = ($event) => searchQuery.value = "")
|
|
5121
5597
|
}, toDisplayString(unref(t)("collectionsView.clearSearch")), 1)
|
|
5122
|
-
])) : (openBlock(), createElementBlock("div",
|
|
5123
|
-
_cache[
|
|
5124
|
-
createElementVNode("span",
|
|
5598
|
+
])) : (openBlock(), createElementBlock("div", _hoisted_54, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_55, [
|
|
5599
|
+
_cache[50] || (_cache[50] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
|
|
5600
|
+
createElementVNode("span", _hoisted_56, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
|
|
5125
5601
|
createElementVNode("button", {
|
|
5126
5602
|
type: "button",
|
|
5127
5603
|
class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
|
|
5128
5604
|
"aria-label": unref(t)("common.close"),
|
|
5129
5605
|
onClick: _cache[14] || (_cache[14] = ($event) => inlineError.value = null)
|
|
5130
|
-
}, [..._cache[
|
|
5131
|
-
])) : createCommentVNode("", true), createElementVNode("table",
|
|
5606
|
+
}, [..._cache[49] || (_cache[49] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_57)
|
|
5607
|
+
])) : createCommentVNode("", true), createElementVNode("table", _hoisted_58, [createElementVNode("thead", null, [createElementVNode("tr", _hoisted_59, [(openBlock(true), createElementBlock(Fragment, null, renderList(listColumnFields.value, ([key, field]) => {
|
|
5132
5608
|
return openBlock(), createElementBlock("th", {
|
|
5133
5609
|
key,
|
|
5134
5610
|
"aria-sort": unref(isSortableField)(field) ? sortAriaValue(key) : void 0,
|
|
5135
5611
|
class: "px-5 py-3 font-bold text-slate-500 text-left uppercase tracking-wider whitespace-nowrap"
|
|
5136
|
-
}, [createElementVNode("div",
|
|
5612
|
+
}, [createElementVNode("div", _hoisted_61, [createElementVNode("span", {
|
|
5137
5613
|
class: "truncate max-w-[14rem]",
|
|
5138
5614
|
title: field.label
|
|
5139
|
-
}, toDisplayString(field.label), 9,
|
|
5615
|
+
}, toDisplayString(field.label), 9, _hoisted_62), unref(isSortableField)(field) ? (openBlock(), createElementBlock("button", {
|
|
5140
5616
|
key: 0,
|
|
5141
5617
|
type: "button",
|
|
5142
5618
|
class: normalizeClass(["inline-flex items-center justify-center rounded p-0.5 -my-1 leading-none transition-colors", sortButtonClass(key)]),
|
|
@@ -5145,8 +5621,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5145
5621
|
onClick: withModifiers(($event) => cycleSort(key), ["stop"]),
|
|
5146
5622
|
onPointerenter: ($event) => hoveredSortKey.value = key,
|
|
5147
5623
|
onPointerleave: _cache[15] || (_cache[15] = ($event) => hoveredSortKey.value = null)
|
|
5148
|
-
}, [createElementVNode("span",
|
|
5149
|
-
}), 128))])]), createElementVNode("tbody",
|
|
5624
|
+
}, [createElementVNode("span", _hoisted_64, toDisplayString(sortIconName(key)), 1)], 42, _hoisted_63)) : createCommentVNode("", true)])], 8, _hoisted_60);
|
|
5625
|
+
}), 128))])]), createElementVNode("tbody", _hoisted_65, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortedItems.value, (item) => {
|
|
5150
5626
|
return openBlock(), createElementBlock("tr", {
|
|
5151
5627
|
key: String(item[collection.value.schema.primaryKey] ?? ""),
|
|
5152
5628
|
class: 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" : ""]),
|
|
@@ -5170,7 +5646,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5170
5646
|
"aria-label": field.label,
|
|
5171
5647
|
onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"])),
|
|
5172
5648
|
onChange: ($event) => commitToggle(item, field)
|
|
5173
|
-
}, null, 40,
|
|
5649
|
+
}, null, 40, _hoisted_67)) : field.type === "boolean" ? (openBlock(), createElementBlock("input", {
|
|
5174
5650
|
key: 1,
|
|
5175
5651
|
type: "checkbox",
|
|
5176
5652
|
checked: item[key] === true,
|
|
@@ -5180,7 +5656,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5180
5656
|
"aria-label": field.label,
|
|
5181
5657
|
onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"])),
|
|
5182
5658
|
onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
|
|
5183
|
-
}, null, 40,
|
|
5659
|
+
}, null, 40, _hoisted_68)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_69, [createElementVNode("a", {
|
|
5184
5660
|
href: unref(cui).recordHref?.(field.to, String(item[key])),
|
|
5185
5661
|
tabindex: unref(cui).recordHref?.(field.to, String(item[key])) ? void 0 : 0,
|
|
5186
5662
|
role: "link",
|
|
@@ -5188,7 +5664,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5188
5664
|
"data-testid": `collections-ref-link-${key}-${item[key]}`,
|
|
5189
5665
|
onClick: ($event) => unref(activateRefLink)($event, field.to, String(item[key]), true),
|
|
5190
5666
|
onKeydown: [withKeys(($event) => unref(activateRefLink)($event, field.to, String(item[key]), true), ["enter"]), withKeys(($event) => unref(activateRefLink)($event, field.to, String(item[key]), true), ["space"])]
|
|
5191
|
-
}, toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 41,
|
|
5667
|
+
}, toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 41, _hoisted_70)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (openBlock(), createElementBlock("select", {
|
|
5192
5668
|
key: 3,
|
|
5193
5669
|
value: item[key] == null ? "" : String(item[key]),
|
|
5194
5670
|
disabled: isRowInlineSaving(item),
|
|
@@ -5197,35 +5673,39 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5197
5673
|
"aria-label": field.label,
|
|
5198
5674
|
onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"])),
|
|
5199
5675
|
onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
|
|
5200
|
-
}, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option",
|
|
5676
|
+
}, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option", _hoisted_72, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
|
|
5201
5677
|
return openBlock(), createElementBlock("option", {
|
|
5202
5678
|
key: value,
|
|
5203
5679
|
value
|
|
5204
|
-
}, toDisplayString(value), 9,
|
|
5205
|
-
}), 128))], 42,
|
|
5680
|
+
}, toDisplayString(value), 9, _hoisted_73);
|
|
5681
|
+
}), 128))], 42, _hoisted_71)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_74, toDisplayString(unref(formatMoney)(item[key], unref(resolveCurrency)(field, item), unref(locale))), 1)) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_75, [_cache[51] || (_cache[51] = createElementVNode("span", { class: "material-icons text-[11px]" }, "list", -1)), createElementVNode("span", null, toDisplayString(tableSummary(item[key])), 1)])) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_76, toDisplayString(unref(derivedDisplay)(field, unref(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type === "rollup" ? (openBlock(), createElementBlock("span", {
|
|
5206
5682
|
key: 7,
|
|
5683
|
+
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",
|
|
5684
|
+
"data-testid": `collections-rollup-${key}-${item[collection.value.schema.primaryKey]}`
|
|
5685
|
+
}, toDisplayString(unref(render).rollupDisplay(field, item)), 9, _hoisted_77)) : field.type !== "file" && unref(isExternalUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
|
|
5686
|
+
key: 8,
|
|
5207
5687
|
href: String(item[key]),
|
|
5208
5688
|
target: "_blank",
|
|
5209
5689
|
rel: "noopener noreferrer",
|
|
5210
5690
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5211
5691
|
"data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5212
5692
|
onClick: _cache[19] || (_cache[19] = withModifiers(() => {}, ["stop"]))
|
|
5213
|
-
}, toDisplayString(String(item[key])), 9,
|
|
5214
|
-
key:
|
|
5693
|
+
}, toDisplayString(String(item[key])), 9, _hoisted_78)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
|
|
5694
|
+
key: 9,
|
|
5215
5695
|
href: unref(artifactUrl)(item[key]) ?? void 0,
|
|
5216
5696
|
target: "_blank",
|
|
5217
5697
|
rel: "noopener noreferrer",
|
|
5218
5698
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5219
5699
|
"data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5220
5700
|
onClick: _cache[20] || (_cache[20] = withModifiers(() => {}, ["stop"]))
|
|
5221
|
-
}, toDisplayString(String(item[key])), 9,
|
|
5222
|
-
key:
|
|
5701
|
+
}, toDisplayString(String(item[key])), 9, _hoisted_79)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
|
|
5702
|
+
key: 10,
|
|
5223
5703
|
href: unref(fileRoutePath)(item[key]) ?? void 0,
|
|
5224
5704
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5225
5705
|
"data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5226
5706
|
onClick: ($event) => unref(activatePathLink)($event, unref(fileRoutePath)(item[key]) ?? "", true)
|
|
5227
|
-
}, toDisplayString(String(item[key])), 9,
|
|
5228
|
-
}), 128))], 42,
|
|
5707
|
+
}, toDisplayString(String(item[key])), 9, _hoisted_80)) : (openBlock(), createElementBlock("span", _hoisted_81, toDisplayString(unref(formatCell)(item[key], field.type)), 1))], 64)) : createCommentVNode("", true)]);
|
|
5708
|
+
}), 128))], 42, _hoisted_66);
|
|
5229
5709
|
}), 128))])])]))]),
|
|
5230
5710
|
collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? (openBlock(), createBlock(CollectionRecordModal_default, {
|
|
5231
5711
|
key: 4,
|
|
@@ -5241,6 +5721,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5241
5721
|
"action-error": actionError.value,
|
|
5242
5722
|
"action-pending": actionPending.value,
|
|
5243
5723
|
"visible-actions": visibleActions.value,
|
|
5724
|
+
"running-action-ids": viewingRunningActionIds.value,
|
|
5244
5725
|
"live-record": liveRecord.value,
|
|
5245
5726
|
"live-derived": liveDerived.value,
|
|
5246
5727
|
"view-title": viewTitle.value,
|
|
@@ -5263,6 +5744,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5263
5744
|
"action-error",
|
|
5264
5745
|
"action-pending",
|
|
5265
5746
|
"visible-actions",
|
|
5747
|
+
"running-action-ids",
|
|
5266
5748
|
"live-record",
|
|
5267
5749
|
"live-derived",
|
|
5268
5750
|
"view-title",
|
|
@@ -5272,20 +5754,32 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5272
5754
|
])]),
|
|
5273
5755
|
_: 1
|
|
5274
5756
|
})) : createCommentVNode("", true),
|
|
5757
|
+
mutateModal.value ? (openBlock(), createBlock(CollectionMutateParamsModal_default, {
|
|
5758
|
+
key: `${mutateModal.value.action.id}-${mutateModal.value.itemId}`,
|
|
5759
|
+
action: mutateModal.value.action,
|
|
5760
|
+
pending: mutatePending.value,
|
|
5761
|
+
error: mutateError.value,
|
|
5762
|
+
onClose: _cache[23] || (_cache[23] = ($event) => mutateModal.value = null),
|
|
5763
|
+
onSubmit: submitMutateParams
|
|
5764
|
+
}, null, 8, [
|
|
5765
|
+
"action",
|
|
5766
|
+
"pending",
|
|
5767
|
+
"error"
|
|
5768
|
+
])) : createCommentVNode("", true),
|
|
5275
5769
|
configOpen.value && collection.value ? (openBlock(), createBlock(CollectionViewConfigModal_default, {
|
|
5276
|
-
key:
|
|
5770
|
+
key: 6,
|
|
5277
5771
|
slug: collection.value.slug,
|
|
5278
5772
|
title: collection.value.title,
|
|
5279
5773
|
views: customViews.value,
|
|
5280
5774
|
onChanged: onViewsChanged,
|
|
5281
|
-
onClose: _cache[
|
|
5775
|
+
onClose: _cache[24] || (_cache[24] = ($event) => configOpen.value = false)
|
|
5282
5776
|
}, null, 8, [
|
|
5283
5777
|
"slug",
|
|
5284
5778
|
"title",
|
|
5285
5779
|
"views"
|
|
5286
5780
|
])) : createCommentVNode("", true),
|
|
5287
5781
|
chatOpen.value && collection.value ? (openBlock(), createElementBlock("div", {
|
|
5288
|
-
key:
|
|
5782
|
+
key: 7,
|
|
5289
5783
|
class: "fixed inset-0 z-30 flex items-center justify-center bg-slate-900/60 backdrop-blur-sm p-4 transition-all duration-300",
|
|
5290
5784
|
role: "dialog",
|
|
5291
5785
|
"aria-modal": "true",
|
|
@@ -5293,29 +5787,29 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5293
5787
|
"data-testid": "collections-chat-modal",
|
|
5294
5788
|
onClick: withModifiers(closeChat, ["self"]),
|
|
5295
5789
|
onKeydown: withKeys(closeChat, ["esc"])
|
|
5296
|
-
}, [createElementVNode("div",
|
|
5297
|
-
createElementVNode("header",
|
|
5298
|
-
_cache[
|
|
5299
|
-
createElementVNode("div",
|
|
5790
|
+
}, [createElementVNode("div", _hoisted_82, [
|
|
5791
|
+
createElementVNode("header", _hoisted_83, [
|
|
5792
|
+
_cache[53] || (_cache[53] = 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" }, [createElementVNode("span", { class: "material-icons text-lg" }, "forum")], -1)),
|
|
5793
|
+
createElementVNode("div", _hoisted_84, [createElementVNode("h2", _hoisted_85, toDisplayString(unref(t)("collectionsView.chatTitle")), 1), createElementVNode("span", _hoisted_86, toDisplayString(collection.value.title), 1)]),
|
|
5300
5794
|
createElementVNode("button", {
|
|
5301
5795
|
type: "button",
|
|
5302
5796
|
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",
|
|
5303
5797
|
"aria-label": unref(t)("common.close"),
|
|
5304
5798
|
"data-testid": "collections-chat-close",
|
|
5305
5799
|
onClick: closeChat
|
|
5306
|
-
}, [..._cache[
|
|
5800
|
+
}, [..._cache[52] || (_cache[52] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_87)
|
|
5307
5801
|
]),
|
|
5308
|
-
createElementVNode("div",
|
|
5802
|
+
createElementVNode("div", _hoisted_88, [withDirectives(createElementVNode("textarea", {
|
|
5309
5803
|
ref_key: "chatInputEl",
|
|
5310
5804
|
ref: chatInputEl,
|
|
5311
|
-
"onUpdate:modelValue": _cache[
|
|
5805
|
+
"onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => chatMessage.value = $event),
|
|
5312
5806
|
rows: "4",
|
|
5313
5807
|
placeholder: unref(t)("collectionsView.chatPlaceholder"),
|
|
5314
5808
|
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",
|
|
5315
5809
|
"data-testid": "collections-chat-input",
|
|
5316
5810
|
onKeydown: [withKeys(withModifiers(submitChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitChat, ["ctrl"]), ["enter"])]
|
|
5317
|
-
}, null, 40,
|
|
5318
|
-
createElementVNode("footer",
|
|
5811
|
+
}, null, 40, _hoisted_89), [[vModelText, chatMessage.value]])]),
|
|
5812
|
+
createElementVNode("footer", _hoisted_90, [createElementVNode("button", {
|
|
5319
5813
|
type: "button",
|
|
5320
5814
|
class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
|
|
5321
5815
|
"data-testid": "collections-chat-cancel",
|
|
@@ -5326,7 +5820,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5326
5820
|
disabled: !chatMessage.value.trim(),
|
|
5327
5821
|
"data-testid": "collections-chat-send",
|
|
5328
5822
|
onClick: submitChat
|
|
5329
|
-
}, toDisplayString(unref(t)("collectionsView.chatStart")), 9,
|
|
5823
|
+
}, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_91)])
|
|
5330
5824
|
])], 32)) : createCommentVNode("", true)
|
|
5331
5825
|
]);
|
|
5332
5826
|
};
|