@mulmoclaude/collection-plugin 0.8.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +12 -0
- package/dist/vue/components/CollectionMutateParamsModal.vue.d.ts +19 -0
- package/dist/vue/components/CollectionMutateParamsModal.vue.d.ts.map +1 -0
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts +73 -8
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts.map +1 -1
- package/dist/vue/components/CollectionView.vue.d.ts.map +1 -1
- package/dist/vue/uiContext.d.ts +26 -5
- package/dist/vue/uiContext.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.d.ts +10 -0
- package/dist/vue/useCollectionRendering.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.helpers.d.ts +4 -3
- package/dist/vue/useCollectionRendering.helpers.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.renderers.d.ts +17 -1
- package/dist/vue/useCollectionRendering.renderers.d.ts.map +1 -1
- package/dist/vue.cjs +815 -457
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +817 -459
- package/dist/vue.js.map +1 -1
- package/package.json +3 -3
package/dist/vue.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MINUTES_PER_DAY, TOOL_DEFINITION, actionVisible, 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, 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,6 +1209,338 @@ 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
1545
|
var _hoisted_1$15 = {
|
|
1214
1546
|
class: "flex flex-col gap-3",
|
|
@@ -1514,6 +1846,7 @@ var CollectionDayView_default = /* @__PURE__ */ defineComponent({
|
|
|
1514
1846
|
"table",
|
|
1515
1847
|
"embed",
|
|
1516
1848
|
"backlinks",
|
|
1849
|
+
"rollup",
|
|
1517
1850
|
"image",
|
|
1518
1851
|
"markdown"
|
|
1519
1852
|
]);
|
|
@@ -2034,111 +2367,115 @@ var _hoisted_7$6 = [
|
|
|
2034
2367
|
];
|
|
2035
2368
|
var _hoisted_8$6 = {
|
|
2036
2369
|
key: 0,
|
|
2370
|
+
class: "material-icons text-sm animate-spin"
|
|
2371
|
+
};
|
|
2372
|
+
var _hoisted_9$6 = {
|
|
2373
|
+
key: 1,
|
|
2037
2374
|
class: "material-icons text-sm"
|
|
2038
2375
|
};
|
|
2039
|
-
var
|
|
2040
|
-
var
|
|
2376
|
+
var _hoisted_10$6 = ["aria-label"];
|
|
2377
|
+
var _hoisted_11$6 = {
|
|
2041
2378
|
key: 0,
|
|
2042
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",
|
|
2043
2380
|
"data-testid": "collections-detail-action-error"
|
|
2044
2381
|
};
|
|
2045
|
-
var
|
|
2046
|
-
var
|
|
2047
|
-
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 = {
|
|
2048
2385
|
key: 0,
|
|
2049
2386
|
class: "text-rose-500 font-bold"
|
|
2050
2387
|
};
|
|
2051
|
-
var
|
|
2388
|
+
var _hoisted_15$5 = [
|
|
2052
2389
|
"id",
|
|
2053
2390
|
"onUpdate:modelValue",
|
|
2054
2391
|
"required",
|
|
2055
2392
|
"data-testid"
|
|
2056
2393
|
];
|
|
2057
|
-
var
|
|
2058
|
-
var
|
|
2059
|
-
var
|
|
2394
|
+
var _hoisted_16$5 = { value: "" };
|
|
2395
|
+
var _hoisted_17$5 = ["value"];
|
|
2396
|
+
var _hoisted_18$5 = [
|
|
2060
2397
|
"id",
|
|
2061
2398
|
"onUpdate:modelValue",
|
|
2062
2399
|
"required",
|
|
2063
2400
|
"placeholder",
|
|
2064
2401
|
"data-testid"
|
|
2065
2402
|
];
|
|
2066
|
-
var
|
|
2403
|
+
var _hoisted_19$3 = {
|
|
2067
2404
|
key: 0,
|
|
2068
2405
|
class: "inline-flex items-center gap-2.5 text-sm text-slate-700 cursor-pointer select-none"
|
|
2069
2406
|
};
|
|
2070
|
-
var
|
|
2407
|
+
var _hoisted_20$3 = [
|
|
2071
2408
|
"id",
|
|
2072
2409
|
"onUpdate:modelValue",
|
|
2073
2410
|
"data-testid",
|
|
2074
2411
|
"onChange"
|
|
2075
2412
|
];
|
|
2076
|
-
var
|
|
2413
|
+
var _hoisted_21$3 = [
|
|
2077
2414
|
"id",
|
|
2078
2415
|
"onUpdate:modelValue",
|
|
2079
2416
|
"required",
|
|
2080
2417
|
"data-testid"
|
|
2081
2418
|
];
|
|
2082
|
-
var
|
|
2083
|
-
var
|
|
2084
|
-
var
|
|
2419
|
+
var _hoisted_22$3 = { value: "" };
|
|
2420
|
+
var _hoisted_23$3 = ["value"];
|
|
2421
|
+
var _hoisted_24$2 = [
|
|
2085
2422
|
"id",
|
|
2086
2423
|
"onUpdate:modelValue",
|
|
2087
2424
|
"required",
|
|
2088
2425
|
"data-testid"
|
|
2089
2426
|
];
|
|
2090
|
-
var
|
|
2091
|
-
var
|
|
2092
|
-
var
|
|
2093
|
-
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 = {
|
|
2094
2431
|
key: 0,
|
|
2095
2432
|
class: "overflow-hidden border border-slate-200 rounded-lg shadow-sm"
|
|
2096
2433
|
};
|
|
2097
|
-
var
|
|
2098
|
-
var
|
|
2099
|
-
var
|
|
2100
|
-
var
|
|
2101
|
-
var
|
|
2102
|
-
var
|
|
2103
|
-
var
|
|
2104
|
-
var
|
|
2105
|
-
var
|
|
2106
|
-
var
|
|
2107
|
-
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 = {
|
|
2108
2445
|
key: 3,
|
|
2109
2446
|
class: "relative flex items-center"
|
|
2110
2447
|
};
|
|
2111
|
-
var
|
|
2112
|
-
var
|
|
2113
|
-
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 = [
|
|
2114
2451
|
"onUpdate:modelValue",
|
|
2115
2452
|
"type",
|
|
2116
2453
|
"step",
|
|
2117
2454
|
"required"
|
|
2118
2455
|
];
|
|
2119
|
-
var
|
|
2120
|
-
var
|
|
2456
|
+
var _hoisted_43$1 = { class: "text-center px-1" };
|
|
2457
|
+
var _hoisted_44$1 = [
|
|
2121
2458
|
"aria-label",
|
|
2122
2459
|
"data-testid",
|
|
2123
2460
|
"onClick"
|
|
2124
2461
|
];
|
|
2125
|
-
var
|
|
2462
|
+
var _hoisted_45$1 = {
|
|
2126
2463
|
key: 1,
|
|
2127
2464
|
class: "text-xs text-slate-400 italic"
|
|
2128
2465
|
};
|
|
2129
|
-
var
|
|
2130
|
-
var
|
|
2466
|
+
var _hoisted_46$1 = ["data-testid", "onClick"];
|
|
2467
|
+
var _hoisted_47$1 = {
|
|
2131
2468
|
key: 4,
|
|
2132
2469
|
class: "relative flex items-center"
|
|
2133
2470
|
};
|
|
2134
|
-
var
|
|
2135
|
-
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 = [
|
|
2136
2473
|
"id",
|
|
2137
2474
|
"onUpdate:modelValue",
|
|
2138
2475
|
"required",
|
|
2139
2476
|
"data-testid"
|
|
2140
2477
|
];
|
|
2141
|
-
var
|
|
2478
|
+
var _hoisted_50$1 = [
|
|
2142
2479
|
"id",
|
|
2143
2480
|
"onUpdate:modelValue",
|
|
2144
2481
|
"type",
|
|
@@ -2147,104 +2484,105 @@ var _hoisted_49$1 = [
|
|
|
2147
2484
|
"disabled",
|
|
2148
2485
|
"data-testid"
|
|
2149
2486
|
];
|
|
2150
|
-
var
|
|
2487
|
+
var _hoisted_51$1 = [
|
|
2151
2488
|
"id",
|
|
2152
2489
|
"onUpdate:modelValue",
|
|
2153
2490
|
"rows",
|
|
2154
2491
|
"required",
|
|
2155
2492
|
"data-testid"
|
|
2156
2493
|
];
|
|
2157
|
-
var
|
|
2158
|
-
var
|
|
2494
|
+
var _hoisted_52$1 = ["data-testid"];
|
|
2495
|
+
var _hoisted_53$1 = {
|
|
2159
2496
|
key: 0,
|
|
2160
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"
|
|
2161
2498
|
};
|
|
2162
|
-
var
|
|
2499
|
+
var _hoisted_54$1 = {
|
|
2163
2500
|
key: 1,
|
|
2164
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"
|
|
2165
2502
|
};
|
|
2166
|
-
var
|
|
2503
|
+
var _hoisted_55$1 = {
|
|
2167
2504
|
key: 0,
|
|
2168
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"
|
|
2169
2506
|
};
|
|
2170
|
-
var
|
|
2507
|
+
var _hoisted_56$1 = {
|
|
2171
2508
|
key: 1,
|
|
2172
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"
|
|
2173
2510
|
};
|
|
2174
|
-
var
|
|
2511
|
+
var _hoisted_57$1 = {
|
|
2175
2512
|
key: 2,
|
|
2176
2513
|
class: "text-slate-300"
|
|
2177
2514
|
};
|
|
2178
|
-
var
|
|
2515
|
+
var _hoisted_58$1 = [
|
|
2179
2516
|
"href",
|
|
2180
2517
|
"tabindex",
|
|
2181
2518
|
"data-testid",
|
|
2182
2519
|
"onClick",
|
|
2183
2520
|
"onKeydown"
|
|
2184
2521
|
];
|
|
2185
|
-
var
|
|
2522
|
+
var _hoisted_59$1 = {
|
|
2186
2523
|
key: 3,
|
|
2187
2524
|
class: "font-semibold text-slate-900 tabular-nums text-sm"
|
|
2188
2525
|
};
|
|
2189
|
-
var
|
|
2526
|
+
var _hoisted_60$1 = {
|
|
2190
2527
|
key: 4,
|
|
2191
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"
|
|
2192
2529
|
};
|
|
2193
|
-
var
|
|
2194
|
-
|
|
2530
|
+
var _hoisted_61$1 = ["data-testid"];
|
|
2531
|
+
var _hoisted_62$1 = {
|
|
2532
|
+
key: 6,
|
|
2195
2533
|
class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
|
|
2196
2534
|
};
|
|
2197
|
-
var
|
|
2198
|
-
var
|
|
2199
|
-
var
|
|
2200
|
-
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 = {
|
|
2201
2539
|
key: 0,
|
|
2202
2540
|
class: "material-icons text-emerald-600 text-base"
|
|
2203
2541
|
};
|
|
2204
|
-
var
|
|
2542
|
+
var _hoisted_67$1 = {
|
|
2205
2543
|
key: 1,
|
|
2206
2544
|
class: "text-slate-300"
|
|
2207
2545
|
};
|
|
2208
|
-
var
|
|
2209
|
-
key:
|
|
2546
|
+
var _hoisted_68$1 = {
|
|
2547
|
+
key: 7,
|
|
2210
2548
|
class: "text-slate-400 italic"
|
|
2211
2549
|
};
|
|
2212
|
-
var
|
|
2213
|
-
key:
|
|
2550
|
+
var _hoisted_69$1 = {
|
|
2551
|
+
key: 8,
|
|
2214
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"
|
|
2215
2553
|
};
|
|
2216
|
-
var
|
|
2554
|
+
var _hoisted_70$1 = [
|
|
2217
2555
|
"src",
|
|
2218
2556
|
"alt",
|
|
2219
2557
|
"data-testid"
|
|
2220
2558
|
];
|
|
2221
|
-
var
|
|
2222
|
-
var
|
|
2223
|
-
var
|
|
2559
|
+
var _hoisted_71$1 = ["href", "data-testid"];
|
|
2560
|
+
var _hoisted_72$1 = ["href", "data-testid"];
|
|
2561
|
+
var _hoisted_73$1 = [
|
|
2224
2562
|
"href",
|
|
2225
2563
|
"data-testid",
|
|
2226
2564
|
"onClick"
|
|
2227
2565
|
];
|
|
2228
|
-
var
|
|
2229
|
-
key:
|
|
2566
|
+
var _hoisted_74$1 = {
|
|
2567
|
+
key: 15,
|
|
2230
2568
|
class: "text-slate-800 font-semibold"
|
|
2231
2569
|
};
|
|
2232
|
-
var
|
|
2570
|
+
var _hoisted_75$1 = {
|
|
2233
2571
|
key: 0,
|
|
2234
2572
|
class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
|
|
2235
2573
|
};
|
|
2236
|
-
var
|
|
2574
|
+
var _hoisted_76$1 = {
|
|
2237
2575
|
key: 1,
|
|
2238
2576
|
class: "mt-5 pt-4 border-t border-slate-200/60",
|
|
2239
2577
|
"data-testid": "collections-detail-chat"
|
|
2240
2578
|
};
|
|
2241
|
-
var
|
|
2579
|
+
var _hoisted_77$1 = {
|
|
2242
2580
|
class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
|
|
2243
2581
|
for: "collections-detail-chat-input"
|
|
2244
2582
|
};
|
|
2245
|
-
var
|
|
2246
|
-
var
|
|
2247
|
-
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"];
|
|
2248
2586
|
//#endregion
|
|
2249
2587
|
//#region src/vue/components/CollectionRecordPanel.vue
|
|
2250
2588
|
var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
@@ -2257,6 +2595,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2257
2595
|
actionError: {},
|
|
2258
2596
|
actionPending: { type: Boolean },
|
|
2259
2597
|
visibleActions: {},
|
|
2598
|
+
runningActionIds: {},
|
|
2260
2599
|
liveRecord: {},
|
|
2261
2600
|
liveDerived: {},
|
|
2262
2601
|
viewTitle: {},
|
|
@@ -2315,13 +2654,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2315
2654
|
if (!editing.value) return "collections-detail";
|
|
2316
2655
|
return editing.value.mode === "create" ? "collections-create" : "collections-edit";
|
|
2317
2656
|
});
|
|
2318
|
-
/** Whether a field gets an editable control in edit mode.
|
|
2319
|
-
*
|
|
2320
|
-
*
|
|
2321
|
-
* records) stay read-only in both modes, so the cell geometry never
|
|
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
|
|
2322
2660
|
* changes on the view↔edit toggle. */
|
|
2323
2661
|
function isEditableType(type) {
|
|
2324
|
-
return type
|
|
2662
|
+
return !COMPUTED_TYPES.has(type);
|
|
2325
2663
|
}
|
|
2326
2664
|
/** Wide field types span the full grid width in BOTH modes — keeping
|
|
2327
2665
|
* `image` full-width here (not just when viewing) is what stops a field
|
|
@@ -2410,10 +2748,10 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2410
2748
|
key: action.id,
|
|
2411
2749
|
type: "button",
|
|
2412
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",
|
|
2413
|
-
disabled: __props.actionPending,
|
|
2751
|
+
disabled: __props.actionPending || __props.runningActionIds.includes(action.id),
|
|
2414
2752
|
"data-testid": `collections-detail-action-${action.id}`,
|
|
2415
2753
|
onClick: ($event) => emit("runAction", action)
|
|
2416
|
-
}, [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);
|
|
2417
2755
|
}), 128)),
|
|
2418
2756
|
createElementVNode("button", {
|
|
2419
2757
|
type: "button",
|
|
@@ -2433,29 +2771,29 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2433
2771
|
"aria-label": unref(t)("common.close"),
|
|
2434
2772
|
"data-testid": "collections-detail-close",
|
|
2435
2773
|
onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
|
|
2436
|
-
}, [..._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)
|
|
2437
2775
|
]))]),
|
|
2438
|
-
!editing.value && __props.actionError ? (openBlock(), createElementBlock("p",
|
|
2439
|
-
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) => {
|
|
2440
2778
|
return openBlock(), createElementBlock(Fragment, { key }, [cellVisible(field, String(key)) ? (openBlock(), createElementBlock("div", {
|
|
2441
2779
|
key: 0,
|
|
2442
2780
|
class: normalizeClass(["flex flex-col gap-1.5", colSpanClass(field)])
|
|
2443
2781
|
}, [createElementVNode("label", {
|
|
2444
2782
|
class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider flex items-center gap-1",
|
|
2445
2783
|
for: `collections-field-${key}`
|
|
2446
|
-
}, [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", {
|
|
2447
2785
|
key: 0,
|
|
2448
2786
|
id: `collections-field-${key}`,
|
|
2449
2787
|
"onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
|
|
2450
2788
|
required: embedPickerRequired(field),
|
|
2451
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",
|
|
2452
2790
|
"data-testid": `collections-input-${key}`
|
|
2453
|
-
}, [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) => {
|
|
2454
2792
|
return openBlock(), createElementBlock("option", {
|
|
2455
2793
|
key: opt.slug,
|
|
2456
2794
|
value: opt.slug
|
|
2457
|
-
}, toDisplayString(opt.display), 9,
|
|
2458
|
-
}), 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", {
|
|
2459
2797
|
key: 1,
|
|
2460
2798
|
id: `collections-field-${key}`,
|
|
2461
2799
|
"onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
|
|
@@ -2464,47 +2802,47 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2464
2802
|
placeholder: unref(t)("collectionsView.selectPlaceholder"),
|
|
2465
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",
|
|
2466
2804
|
"data-testid": `collections-input-${key}`
|
|
2467
|
-
}, 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", {
|
|
2468
2806
|
id: `collections-field-${key}`,
|
|
2469
2807
|
"onUpdate:modelValue": ($event) => editing.value.bool[key] = $event,
|
|
2470
2808
|
type: "checkbox",
|
|
2471
2809
|
class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
2472
2810
|
"data-testid": `collections-input-${key}`,
|
|
2473
2811
|
onChange: ($event) => markBoolTouched(String(key))
|
|
2474
|
-
}, 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", {
|
|
2475
2813
|
key: 1,
|
|
2476
2814
|
id: `collections-field-${key}`,
|
|
2477
2815
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2478
2816
|
required: isFieldRequiredInUi(field),
|
|
2479
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",
|
|
2480
2818
|
"data-testid": `collections-input-${key}`
|
|
2481
|
-
}, [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) => {
|
|
2482
2820
|
return openBlock(), createElementBlock("option", {
|
|
2483
2821
|
key: opt.slug,
|
|
2484
2822
|
value: opt.slug
|
|
2485
|
-
}, toDisplayString(opt.display), 9,
|
|
2486
|
-
}), 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", {
|
|
2487
2825
|
key: 2,
|
|
2488
2826
|
id: `collections-field-${key}`,
|
|
2489
2827
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2490
2828
|
required: isFieldRequiredInUi(field),
|
|
2491
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])]),
|
|
2492
2830
|
"data-testid": `collections-input-${key}`
|
|
2493
|
-
}, [createElementVNode("option",
|
|
2831
|
+
}, [createElementVNode("option", _hoisted_25$2, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
|
|
2494
2832
|
return openBlock(), createElementBlock("option", {
|
|
2495
2833
|
key: value,
|
|
2496
2834
|
value
|
|
2497
|
-
}, toDisplayString(value), 9,
|
|
2498
|
-
}), 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", {
|
|
2499
2837
|
key: 3,
|
|
2500
2838
|
class: "border border-slate-200 bg-slate-50/30 rounded-xl p-4 space-y-3",
|
|
2501
2839
|
"data-testid": `collections-table-${key}`
|
|
2502
|
-
}, [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) => {
|
|
2503
2841
|
return openBlock(), createElementBlock("th", {
|
|
2504
2842
|
key: subKey,
|
|
2505
2843
|
class: "text-left px-3 py-2 font-bold"
|
|
2506
2844
|
}, toDisplayString(subField.label), 1);
|
|
2507
|
-
}), 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) => {
|
|
2508
2846
|
return openBlock(), createElementBlock("tr", {
|
|
2509
2847
|
key: rowIdx,
|
|
2510
2848
|
class: "hover:bg-slate-50/50"
|
|
@@ -2518,53 +2856,53 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2518
2856
|
type: "checkbox",
|
|
2519
2857
|
class: "h-4 w-4 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
|
|
2520
2858
|
onChange: ($event) => markRowBoolTouched(row, String(subKey))
|
|
2521
|
-
}, 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", {
|
|
2522
2860
|
key: 1,
|
|
2523
2861
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2524
2862
|
required: subField.required,
|
|
2525
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"
|
|
2526
|
-
}, [createElementVNode("option",
|
|
2864
|
+
}, [createElementVNode("option", _hoisted_34$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(subField.values, (value) => {
|
|
2527
2865
|
return openBlock(), createElementBlock("option", {
|
|
2528
2866
|
key: value,
|
|
2529
2867
|
value
|
|
2530
|
-
}, toDisplayString(value), 9,
|
|
2531
|
-
}), 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", {
|
|
2532
2870
|
key: 2,
|
|
2533
2871
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2534
2872
|
required: subField.required,
|
|
2535
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"
|
|
2536
|
-
}, [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) => {
|
|
2537
2875
|
return openBlock(), createElementBlock("option", {
|
|
2538
2876
|
key: opt.slug,
|
|
2539
2877
|
value: opt.slug
|
|
2540
|
-
}, toDisplayString(opt.display), 9,
|
|
2541
|
-
}), 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", {
|
|
2542
2880
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2543
2881
|
type: "number",
|
|
2544
2882
|
step: "0.01",
|
|
2545
2883
|
required: subField.required,
|
|
2546
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"
|
|
2547
|
-
}, null, 8,
|
|
2885
|
+
}, null, 8, _hoisted_41$1), [[vModelText, row.text[subKey]]])])) : withDirectives((openBlock(), createElementBlock("input", {
|
|
2548
2886
|
key: 4,
|
|
2549
2887
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2550
2888
|
type: __props.render.inputTypeFor(subField.type),
|
|
2551
2889
|
step: __props.render.stepFor(subField.type),
|
|
2552
2890
|
required: subField.required,
|
|
2553
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"
|
|
2554
|
-
}, null, 8,
|
|
2555
|
-
}), 128)), createElementVNode("td",
|
|
2892
|
+
}, null, 8, _hoisted_42$1)), [[vModelDynamic, row.text[subKey]]])]);
|
|
2893
|
+
}), 128)), createElementVNode("td", _hoisted_43$1, [createElementVNode("button", {
|
|
2556
2894
|
type: "button",
|
|
2557
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",
|
|
2558
2896
|
"aria-label": unref(t)("collectionsView.removeRow"),
|
|
2559
2897
|
"data-testid": `collections-table-${key}-remove-${rowIdx}`,
|
|
2560
2898
|
onClick: ($event) => removeTableRow(String(key), rowIdx)
|
|
2561
|
-
}, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8,
|
|
2562
|
-
}), 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", {
|
|
2563
2901
|
type: "button",
|
|
2564
2902
|
class: "inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-800 font-bold hover:underline",
|
|
2565
2903
|
"data-testid": `collections-table-${key}-add`,
|
|
2566
2904
|
onClick: ($event) => addTableRow(String(key), field.of)
|
|
2567
|
-
}, [_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", {
|
|
2568
2906
|
id: `collections-field-${key}`,
|
|
2569
2907
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2570
2908
|
type: "number",
|
|
@@ -2572,7 +2910,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2572
2910
|
required: isFieldRequiredInUi(field),
|
|
2573
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",
|
|
2574
2912
|
"data-testid": `collections-input-${key}`
|
|
2575
|
-
}, null, 8,
|
|
2913
|
+
}, null, 8, _hoisted_49$1), [[vModelText, editing.value.text[key]]])])) : [
|
|
2576
2914
|
"string",
|
|
2577
2915
|
"email",
|
|
2578
2916
|
"number",
|
|
@@ -2591,7 +2929,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2591
2929
|
disabled: field.primary === true && (editing.value.mode === "edit" || __props.isSingleton),
|
|
2592
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",
|
|
2593
2931
|
"data-testid": `collections-input-${key}`
|
|
2594
|
-
}, null, 8,
|
|
2932
|
+
}, null, 8, _hoisted_50$1)), [[vModelDynamic, editing.value.text[key]]]) : withDirectives((openBlock(), createElementBlock("textarea", {
|
|
2595
2933
|
key: 6,
|
|
2596
2934
|
id: `collections-field-${key}`,
|
|
2597
2935
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
@@ -2599,11 +2937,11 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2599
2937
|
required: isFieldRequiredInUi(field),
|
|
2600
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",
|
|
2601
2939
|
"data-testid": `collections-input-${key}`
|
|
2602
|
-
}, null, 8,
|
|
2940
|
+
}, null, 8, _hoisted_51$1)), [[vModelText, editing.value.text[key]]])], 64)) : (openBlock(), createElementBlock("div", {
|
|
2603
2941
|
key: 3,
|
|
2604
2942
|
class: "text-xs font-medium text-slate-700 break-words",
|
|
2605
2943
|
"data-testid": `collections-detail-value-${key}`
|
|
2606
|
-
}, [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", {
|
|
2607
2945
|
key: 2,
|
|
2608
2946
|
href: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])),
|
|
2609
2947
|
tabindex: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
|
|
@@ -2612,12 +2950,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2612
2950
|
"data-testid": `collections-detail-ref-${key}`,
|
|
2613
2951
|
onClick: ($event) => unref(activateRefLink)($event, field.to, String(detailRecord.value[key])),
|
|
2614
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"])]
|
|
2615
|
-
}, 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) => {
|
|
2616
2958
|
return openBlock(), createElementBlock("th", {
|
|
2617
2959
|
key: subKey,
|
|
2618
2960
|
class: "text-left px-4 py-2 font-bold"
|
|
2619
2961
|
}, toDisplayString(subField.label), 1);
|
|
2620
|
-
}), 128))])]), createElementVNode("tbody",
|
|
2962
|
+
}), 128))])]), createElementVNode("tbody", _hoisted_65$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
|
|
2621
2963
|
return openBlock(), createElementBlock("tr", {
|
|
2622
2964
|
key: rowIdx,
|
|
2623
2965
|
class: "hover:bg-slate-50/50"
|
|
@@ -2625,48 +2967,48 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2625
2967
|
return openBlock(), createElementBlock("td", {
|
|
2626
2968
|
key: subKey,
|
|
2627
2969
|
class: "px-4 py-2 align-middle font-medium"
|
|
2628
|
-
}, [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", {
|
|
2629
2971
|
key: 1,
|
|
2630
2972
|
class: normalizeClass([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
|
|
2631
2973
|
}, toDisplayString(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
|
|
2632
2974
|
}), 128))]);
|
|
2633
|
-
}), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span",
|
|
2634
|
-
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,
|
|
2635
2977
|
view: embedViews.value[key],
|
|
2636
2978
|
"field-key": String(key)
|
|
2637
2979
|
}, null, 8, ["view", "field-key"])) : field.type === "backlinks" && backlinksViews.value[key] ? (openBlock(), createBlock(CollectionBacklinksView_default, {
|
|
2638
|
-
key:
|
|
2980
|
+
key: 10,
|
|
2639
2981
|
view: backlinksViews.value[key],
|
|
2640
2982
|
"field-key": String(key)
|
|
2641
2983
|
}, null, 8, ["view", "field-key"])) : field.type === "image" && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("img", {
|
|
2642
|
-
key:
|
|
2984
|
+
key: 11,
|
|
2643
2985
|
src: unref(resolveImageSrc)(String(detailRecord.value[key])),
|
|
2644
2986
|
alt: field.label,
|
|
2645
2987
|
class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
|
|
2646
2988
|
"data-testid": `collections-detail-image-${key}`
|
|
2647
|
-
}, null, 8,
|
|
2648
|
-
key:
|
|
2989
|
+
}, null, 8, _hoisted_70$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
|
|
2990
|
+
key: 12,
|
|
2649
2991
|
href: String(detailRecord.value[key]),
|
|
2650
2992
|
target: "_blank",
|
|
2651
2993
|
rel: "noopener noreferrer",
|
|
2652
2994
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2653
2995
|
"data-testid": `collections-detail-url-${key}`
|
|
2654
|
-
}, toDisplayString(String(detailRecord.value[key])), 9,
|
|
2655
|
-
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,
|
|
2656
2998
|
href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
|
|
2657
2999
|
target: "_blank",
|
|
2658
3000
|
rel: "noopener noreferrer",
|
|
2659
3001
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2660
3002
|
"data-testid": `collections-detail-file-${key}`
|
|
2661
|
-
}, toDisplayString(String(detailRecord.value[key])), 9,
|
|
2662
|
-
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,
|
|
2663
3005
|
href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
|
|
2664
3006
|
class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
|
|
2665
3007
|
"data-testid": `collections-detail-file-${key}`,
|
|
2666
3008
|
onClick: ($event) => unref(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
|
|
2667
|
-
}, toDisplayString(String(detailRecord.value[key])), 9,
|
|
2668
|
-
}), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p",
|
|
2669
|
-
!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", {
|
|
2670
3012
|
id: "collections-detail-chat-input",
|
|
2671
3013
|
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
|
|
2672
3014
|
rows: "2",
|
|
@@ -2674,13 +3016,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2674
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",
|
|
2675
3017
|
"data-testid": "collections-detail-chat-input",
|
|
2676
3018
|
onKeydown: [withKeys(withModifiers(submitItemChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitItemChat, ["ctrl"]), ["enter"])]
|
|
2677
|
-
}, null, 40,
|
|
3019
|
+
}, null, 40, _hoisted_79$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
|
|
2678
3020
|
type: "button",
|
|
2679
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",
|
|
2680
3022
|
disabled: !chatMessage.value.trim(),
|
|
2681
3023
|
"data-testid": "collections-detail-chat-send",
|
|
2682
3024
|
onClick: submitItemChat
|
|
2683
|
-
}, [_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)
|
|
2684
3026
|
]),
|
|
2685
3027
|
_: 1
|
|
2686
3028
|
}, 40, ["data-testid"]);
|
|
@@ -3082,162 +3424,6 @@ var CollectionRemoteViewPreview_default = /*#__PURE__*/ _plugin_vue_export_helpe
|
|
|
3082
3424
|
}
|
|
3083
3425
|
}), [["__scopeId", "data-v-965ade6c"]]);
|
|
3084
3426
|
//#endregion
|
|
3085
|
-
//#region src/vue/useCollectionRendering.helpers.ts
|
|
3086
|
-
var EM_DASH = "—";
|
|
3087
|
-
var DEFAULT_CURRENCY = "USD";
|
|
3088
|
-
var MARKDOWN_CELL_PREVIEW_MAX = 80;
|
|
3089
|
-
function stepForFieldType(type) {
|
|
3090
|
-
if (type === "money") return "0.01";
|
|
3091
|
-
if (type === "number") return "any";
|
|
3092
|
-
}
|
|
3093
|
-
function inputTypeFor(type) {
|
|
3094
|
-
if (type === "email") return "email";
|
|
3095
|
-
if (type === "number") return "number";
|
|
3096
|
-
if (type === "money") return "number";
|
|
3097
|
-
if (type === "date") return "date";
|
|
3098
|
-
if (type === "datetime") return "datetime-local";
|
|
3099
|
-
return "text";
|
|
3100
|
-
}
|
|
3101
|
-
function isExternalUrl(value) {
|
|
3102
|
-
return typeof value === "string" && /^https?:\/\//i.test(value);
|
|
3103
|
-
}
|
|
3104
|
-
function detailText(value) {
|
|
3105
|
-
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
3106
|
-
return String(value);
|
|
3107
|
-
}
|
|
3108
|
-
function formatCell(value, type) {
|
|
3109
|
-
if (value === void 0 || value === null || value === "") return EM_DASH;
|
|
3110
|
-
if (type === "markdown" && typeof value === "string") return value.length > MARKDOWN_CELL_PREVIEW_MAX ? `${value.slice(0, MARKDOWN_CELL_PREVIEW_MAX)}…` : value;
|
|
3111
|
-
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
3112
|
-
return JSON.stringify(value);
|
|
3113
|
-
}
|
|
3114
|
-
/** Resolve the ISO 4217 code for a money field: a per-record
|
|
3115
|
-
* `currencyField` (when present and non-blank) wins over the field's
|
|
3116
|
-
* literal `currency`. Only `money` / `derived` variants carry currency
|
|
3117
|
-
* keys; any other field resolves to undefined (the formatter's USD
|
|
3118
|
-
* fallback), as before. */
|
|
3119
|
-
function resolveCurrency(field, record) {
|
|
3120
|
-
if (field.type !== "money" && field.type !== "derived") return void 0;
|
|
3121
|
-
if (field.currencyField && record) {
|
|
3122
|
-
const code = record[field.currencyField];
|
|
3123
|
-
if (typeof code === "string" && code.trim().length > 0) return code;
|
|
3124
|
-
}
|
|
3125
|
-
return field.currency;
|
|
3126
|
-
}
|
|
3127
|
-
function formatMoney(value, currency, displayLocale) {
|
|
3128
|
-
if (value === void 0 || value === "") return EM_DASH;
|
|
3129
|
-
const amount = typeof value === "number" ? value : Number(value);
|
|
3130
|
-
if (!Number.isFinite(amount)) return String(value);
|
|
3131
|
-
const currencyCode = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
3132
|
-
try {
|
|
3133
|
-
return new Intl.NumberFormat(displayLocale, {
|
|
3134
|
-
style: "currency",
|
|
3135
|
-
currency: currencyCode
|
|
3136
|
-
}).format(amount);
|
|
3137
|
-
} catch {
|
|
3138
|
-
return String(amount);
|
|
3139
|
-
}
|
|
3140
|
-
}
|
|
3141
|
-
function currencySymbolForLocale(currency, locale) {
|
|
3142
|
-
const code = currency && currency.length > 0 ? currency : DEFAULT_CURRENCY;
|
|
3143
|
-
try {
|
|
3144
|
-
return new Intl.NumberFormat(locale, {
|
|
3145
|
-
style: "currency",
|
|
3146
|
-
currency: code
|
|
3147
|
-
}).formatToParts(0).find((entry) => entry.type === "currency")?.value ?? code;
|
|
3148
|
-
} catch {
|
|
3149
|
-
return code;
|
|
3150
|
-
}
|
|
3151
|
-
}
|
|
3152
|
-
function tableRows(value) {
|
|
3153
|
-
if (!Array.isArray(value)) return [];
|
|
3154
|
-
return value.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
|
|
3155
|
-
}
|
|
3156
|
-
function hasTableRows(value) {
|
|
3157
|
-
return tableRows(value).length > 0;
|
|
3158
|
-
}
|
|
3159
|
-
/** Pick the field used to label a referenced/embedded record: prefer a
|
|
3160
|
-
* `name` field, then `title`, else fall back to the primary key. */
|
|
3161
|
-
function displayFieldFor(fields, primaryKey) {
|
|
3162
|
-
if ("name" in fields) return "name";
|
|
3163
|
-
if ("title" in fields) return "title";
|
|
3164
|
-
return primaryKey;
|
|
3165
|
-
}
|
|
3166
|
-
function uniqueRefTargets(schema) {
|
|
3167
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3168
|
-
const walk = (fields) => {
|
|
3169
|
-
for (const field of Object.values(fields)) {
|
|
3170
|
-
if (field.type === "ref" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
3171
|
-
if (field.type === "table" && field.of) walk(field.of);
|
|
3172
|
-
}
|
|
3173
|
-
};
|
|
3174
|
-
walk(schema.fields);
|
|
3175
|
-
return [...targets];
|
|
3176
|
-
}
|
|
3177
|
-
function uniqueEmbedTargets(schema) {
|
|
3178
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3179
|
-
for (const field of Object.values(schema.fields)) if (field.type === "embed" && typeof field.to === "string" && field.to.length > 0) targets.add(field.to);
|
|
3180
|
-
return [...targets];
|
|
3181
|
-
}
|
|
3182
|
-
/** Slugs of every SOURCE collection a `backlinks` field reverses over.
|
|
3183
|
-
* Top-level only, like `embed` (the schema rejects `backlinks` inside a
|
|
3184
|
-
* table's `of`). Mirrors the server's `uniqueBacklinkSources`. */
|
|
3185
|
-
function uniqueBacklinkSources(schema) {
|
|
3186
|
-
const sources = /* @__PURE__ */ new Set();
|
|
3187
|
-
for (const field of Object.values(schema.fields)) if (field.type === "backlinks" && field.from.length > 0) sources.add(field.from);
|
|
3188
|
-
return [...sources];
|
|
3189
|
-
}
|
|
3190
|
-
function buildRefDisplayMap(detail) {
|
|
3191
|
-
const { fields, primaryKey } = detail.collection.schema;
|
|
3192
|
-
const displayField = displayFieldFor(fields, primaryKey);
|
|
3193
|
-
const map = {};
|
|
3194
|
-
for (const item of detail.items) {
|
|
3195
|
-
const slugRaw = item[primaryKey];
|
|
3196
|
-
if (typeof slugRaw !== "string" || slugRaw.length === 0) continue;
|
|
3197
|
-
const displayRaw = item[displayField];
|
|
3198
|
-
map[slugRaw] = typeof displayRaw === "string" && displayRaw.length > 0 ? displayRaw : slugRaw;
|
|
3199
|
-
}
|
|
3200
|
-
return map;
|
|
3201
|
-
}
|
|
3202
|
-
/** Index DERIVED records by primary key — the client mirror of the
|
|
3203
|
-
* server's `loadTarget` indexing: string non-empty ids only, one record
|
|
3204
|
-
* per id (a duplicate keeps the LAST record in its FIRST position —
|
|
3205
|
-
* plain-object key semantics). Shared by the ref-record cache and the
|
|
3206
|
-
* backlinks view so every client consumer agrees with server enrichment
|
|
3207
|
-
* on which source records exist. */
|
|
3208
|
-
function derivedRecordsById(schema, items) {
|
|
3209
|
-
const map = {};
|
|
3210
|
-
for (const item of items) {
|
|
3211
|
-
const slugRaw = item[schema.primaryKey];
|
|
3212
|
-
if (typeof slugRaw === "string" && slugRaw.length > 0) map[slugRaw] = deriveAll(schema, item, {});
|
|
3213
|
-
}
|
|
3214
|
-
return map;
|
|
3215
|
-
}
|
|
3216
|
-
function buildRefRecordMap(detail) {
|
|
3217
|
-
return derivedRecordsById(detail.collection.schema, detail.items);
|
|
3218
|
-
}
|
|
3219
|
-
function sortedRefOptions(map) {
|
|
3220
|
-
return Object.entries(map).map(([slug, display]) => ({
|
|
3221
|
-
slug,
|
|
3222
|
-
display
|
|
3223
|
-
})).sort((left, right) => left.display.localeCompare(right.display));
|
|
3224
|
-
}
|
|
3225
|
-
/** Dropdown options for an `embed` field's per-record picker: every
|
|
3226
|
-
* record in the target collection, labelled by its name/title (or
|
|
3227
|
-
* primary key), skipping records without a slug and sorted by label. */
|
|
3228
|
-
function buildEmbedOptions(schema, items) {
|
|
3229
|
-
const { fields, primaryKey } = schema;
|
|
3230
|
-
const displayField = displayFieldFor(fields, primaryKey);
|
|
3231
|
-
return items.map((item) => {
|
|
3232
|
-
const slug = String(item[primaryKey] ?? "");
|
|
3233
|
-
const labelRaw = item[displayField];
|
|
3234
|
-
return {
|
|
3235
|
-
slug,
|
|
3236
|
-
display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
|
|
3237
|
-
};
|
|
3238
|
-
}).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
|
|
3239
|
-
}
|
|
3240
|
-
//#endregion
|
|
3241
3427
|
//#region src/vue/useLinkedCollectionCaches.ts
|
|
3242
3428
|
/** The de-duplicated ref + embed target slugs a schema links to. `allTargets`
|
|
3243
3429
|
* is the union (each target fetched once even when both ref'd and embedded).
|
|
@@ -3430,12 +3616,10 @@ function buildBacklinksViews(schema, embedCache, record, locale) {
|
|
|
3430
3616
|
continue;
|
|
3431
3617
|
}
|
|
3432
3618
|
for (const column of columns) column.label = data.schema.fields[column.key]?.label ?? column.key;
|
|
3433
|
-
const selfId = String(record?.[schema.primaryKey] ?? "");
|
|
3434
|
-
const sourceById = derivedRecordsById(data.schema, data.items);
|
|
3435
3619
|
out[key] = {
|
|
3436
3620
|
found: true,
|
|
3437
3621
|
columns,
|
|
3438
|
-
rows: backlinkRows(field,
|
|
3622
|
+
rows: backlinkRows(field, String(record?.[schema.primaryKey] ?? ""), derivedSourceItems(embedCache, field.from) ?? []).map((row) => ({
|
|
3439
3623
|
id: String(row[data.schema.primaryKey] ?? ""),
|
|
3440
3624
|
cells: columns.map((column) => formatBacklinkCell(data.schema.fields[column.key], row[column.key], row, locale))
|
|
3441
3625
|
})),
|
|
@@ -3444,14 +3628,63 @@ function buildBacklinksViews(schema, embedCache, record, locale) {
|
|
|
3444
3628
|
}
|
|
3445
3629
|
return out;
|
|
3446
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
|
+
}
|
|
3447
3680
|
function renderSubCell(subField, value, record, refCache, locale) {
|
|
3448
3681
|
if (subField.type === "money") return formatMoney(value, resolveCurrency(subField, record), locale);
|
|
3449
3682
|
if (subField.type === "ref" && subField.to && typeof value === "string" && value.length > 0) return lookupRefDisplay(refCache, subField.to, value);
|
|
3450
3683
|
return formatCell(value, subField.type);
|
|
3451
3684
|
}
|
|
3452
|
-
function evaluateDerived(field, fieldKey, item, schema, refRecords) {
|
|
3685
|
+
function evaluateDerived(field, fieldKey, item, schema, refRecords, embedCache = {}) {
|
|
3453
3686
|
if (field.type !== "derived" || !schema) return null;
|
|
3454
|
-
const result = deriveAll(schema, item, refRecords)[fieldKey];
|
|
3687
|
+
const result = deriveAll(schema, withRollupValues(schema, item, embedCache), refRecords)[fieldKey];
|
|
3455
3688
|
return typeof result === "number" && Number.isFinite(result) ? result : null;
|
|
3456
3689
|
}
|
|
3457
3690
|
function renderDerived(field, computedValue, record, locale) {
|
|
@@ -3485,11 +3718,17 @@ function useCollectionRendering(collection, locale) {
|
|
|
3485
3718
|
embedOptions: (targetSlug) => embedOptionsFor(embedCache.value, targetSlug),
|
|
3486
3719
|
embedViewsFor: (record) => buildEmbedViews(collection.value?.schema ?? null, embedCache.value, record, locale.value),
|
|
3487
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),
|
|
3488
3722
|
currencySymbol: (currency) => currencySymbolForLocale(currency, locale.value),
|
|
3489
3723
|
artifactUrl: (value) => collectionUi().fileAssetUrl(value),
|
|
3490
3724
|
fileRoutePath: (value) => collectionUi().fileRoutePath(value),
|
|
3491
3725
|
formatSubCell: (subField, value, record) => renderSubCell(subField, value, record, refCache.value, locale.value),
|
|
3492
|
-
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
|
+
},
|
|
3493
3732
|
derivedDisplay: (field, computedValue, record) => renderDerived(field, computedValue, record, locale.value)
|
|
3494
3733
|
};
|
|
3495
3734
|
}
|
|
@@ -3606,206 +3845,211 @@ var _hoisted_11$4 = [
|
|
|
3606
3845
|
];
|
|
3607
3846
|
var _hoisted_12$4 = {
|
|
3608
3847
|
key: 0,
|
|
3848
|
+
class: "material-icons text-sm animate-spin"
|
|
3849
|
+
};
|
|
3850
|
+
var _hoisted_13$4 = {
|
|
3851
|
+
key: 1,
|
|
3609
3852
|
class: "material-icons text-sm"
|
|
3610
3853
|
};
|
|
3611
|
-
var _hoisted_13$4 = ["title", "aria-label"];
|
|
3612
3854
|
var _hoisted_14$4 = ["title", "aria-label"];
|
|
3613
|
-
var _hoisted_15$4 =
|
|
3855
|
+
var _hoisted_15$4 = ["title", "aria-label"];
|
|
3856
|
+
var _hoisted_16$4 = {
|
|
3614
3857
|
key: 1,
|
|
3615
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",
|
|
3616
3859
|
"data-testid": "collections-refresh-note"
|
|
3617
3860
|
};
|
|
3618
|
-
var
|
|
3619
|
-
var
|
|
3861
|
+
var _hoisted_17$4 = { class: "flex-1" };
|
|
3862
|
+
var _hoisted_18$4 = {
|
|
3620
3863
|
key: 2,
|
|
3621
3864
|
class: "px-6 py-3 bg-white border-b border-slate-100 flex items-center justify-between gap-4"
|
|
3622
3865
|
};
|
|
3623
|
-
var
|
|
3866
|
+
var _hoisted_19$2 = {
|
|
3624
3867
|
key: 0,
|
|
3625
3868
|
class: "relative flex-1 max-w-md"
|
|
3626
3869
|
};
|
|
3627
|
-
var
|
|
3628
|
-
var
|
|
3629
|
-
var
|
|
3630
|
-
var
|
|
3631
|
-
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"];
|
|
3632
3874
|
var _hoisted_24$1 = ["aria-pressed"];
|
|
3633
3875
|
var _hoisted_25$1 = ["aria-pressed"];
|
|
3634
|
-
var _hoisted_26$1 = [
|
|
3876
|
+
var _hoisted_26$1 = ["aria-pressed"];
|
|
3877
|
+
var _hoisted_27$1 = [
|
|
3635
3878
|
"aria-pressed",
|
|
3636
3879
|
"data-testid",
|
|
3637
3880
|
"onClick"
|
|
3638
3881
|
];
|
|
3639
|
-
var
|
|
3640
|
-
var
|
|
3882
|
+
var _hoisted_28 = { class: "material-icons text-sm" };
|
|
3883
|
+
var _hoisted_29 = [
|
|
3641
3884
|
"title",
|
|
3642
3885
|
"aria-label",
|
|
3643
3886
|
"aria-expanded"
|
|
3644
3887
|
];
|
|
3645
|
-
var
|
|
3888
|
+
var _hoisted_30 = {
|
|
3646
3889
|
key: 0,
|
|
3647
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",
|
|
3648
3891
|
"data-testid": "collection-view-add-menu"
|
|
3649
3892
|
};
|
|
3650
|
-
var
|
|
3651
|
-
var
|
|
3652
|
-
var
|
|
3653
|
-
var
|
|
3654
|
-
var
|
|
3655
|
-
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 = {
|
|
3656
3899
|
key: 3,
|
|
3657
3900
|
class: "text-[10px] text-slate-400 font-bold uppercase tracking-wider select-none"
|
|
3658
3901
|
};
|
|
3659
|
-
var
|
|
3902
|
+
var _hoisted_37 = {
|
|
3660
3903
|
key: 3,
|
|
3661
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",
|
|
3662
3905
|
"data-testid": "collections-data-issues"
|
|
3663
3906
|
};
|
|
3664
|
-
var
|
|
3665
|
-
var
|
|
3666
|
-
var
|
|
3907
|
+
var _hoisted_38 = { class: "flex-1" };
|
|
3908
|
+
var _hoisted_39 = { class: "flex-1 overflow-auto" };
|
|
3909
|
+
var _hoisted_40 = {
|
|
3667
3910
|
key: 0,
|
|
3668
3911
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-500 gap-3"
|
|
3669
3912
|
};
|
|
3670
|
-
var
|
|
3913
|
+
var _hoisted_41 = {
|
|
3671
3914
|
key: 1,
|
|
3672
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"
|
|
3673
3916
|
};
|
|
3674
|
-
var
|
|
3675
|
-
var
|
|
3917
|
+
var _hoisted_42 = { key: 2 };
|
|
3918
|
+
var _hoisted_43 = {
|
|
3676
3919
|
key: 3,
|
|
3677
3920
|
class: "p-4"
|
|
3678
3921
|
};
|
|
3679
|
-
var
|
|
3922
|
+
var _hoisted_44 = {
|
|
3680
3923
|
key: 4,
|
|
3681
3924
|
class: "h-full flex flex-col"
|
|
3682
3925
|
};
|
|
3683
|
-
var
|
|
3926
|
+
var _hoisted_45 = {
|
|
3684
3927
|
key: 0,
|
|
3685
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",
|
|
3686
3929
|
"data-testid": "collections-inline-error"
|
|
3687
3930
|
};
|
|
3688
|
-
var
|
|
3689
|
-
var
|
|
3690
|
-
var
|
|
3691
|
-
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 = {
|
|
3692
3935
|
key: 5,
|
|
3693
3936
|
class: "h-full",
|
|
3694
3937
|
"data-testid": "collection-custom-view-body"
|
|
3695
3938
|
};
|
|
3696
|
-
var
|
|
3939
|
+
var _hoisted_50 = {
|
|
3697
3940
|
key: 6,
|
|
3698
3941
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
|
|
3699
3942
|
};
|
|
3700
|
-
var
|
|
3701
|
-
var
|
|
3943
|
+
var _hoisted_51 = { class: "font-semibold text-slate-600" };
|
|
3944
|
+
var _hoisted_52 = {
|
|
3702
3945
|
key: 7,
|
|
3703
3946
|
class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
|
|
3704
3947
|
};
|
|
3705
|
-
var
|
|
3706
|
-
var
|
|
3948
|
+
var _hoisted_53 = { class: "font-semibold text-slate-600" };
|
|
3949
|
+
var _hoisted_54 = {
|
|
3707
3950
|
key: 8,
|
|
3708
3951
|
class: "overflow-x-auto [container-type:inline-size]"
|
|
3709
3952
|
};
|
|
3710
|
-
var
|
|
3953
|
+
var _hoisted_55 = {
|
|
3711
3954
|
key: 0,
|
|
3712
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",
|
|
3713
3956
|
"data-testid": "collections-inline-error"
|
|
3714
3957
|
};
|
|
3715
|
-
var
|
|
3716
|
-
var
|
|
3717
|
-
var
|
|
3718
|
-
var
|
|
3719
|
-
var
|
|
3720
|
-
var
|
|
3721
|
-
var
|
|
3722
|
-
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 = [
|
|
3723
3966
|
"data-testid",
|
|
3724
3967
|
"aria-label",
|
|
3725
3968
|
"onClick",
|
|
3726
3969
|
"onPointerenter"
|
|
3727
3970
|
];
|
|
3728
|
-
var
|
|
3729
|
-
var
|
|
3730
|
-
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 = [
|
|
3731
3974
|
"aria-label",
|
|
3732
3975
|
"data-testid",
|
|
3733
3976
|
"onClick",
|
|
3734
3977
|
"onKeydown"
|
|
3735
3978
|
];
|
|
3736
|
-
var
|
|
3979
|
+
var _hoisted_67 = [
|
|
3737
3980
|
"checked",
|
|
3738
3981
|
"disabled",
|
|
3739
3982
|
"data-testid",
|
|
3740
3983
|
"aria-label",
|
|
3741
3984
|
"onChange"
|
|
3742
3985
|
];
|
|
3743
|
-
var
|
|
3986
|
+
var _hoisted_68 = [
|
|
3744
3987
|
"checked",
|
|
3745
3988
|
"disabled",
|
|
3746
3989
|
"data-testid",
|
|
3747
3990
|
"aria-label",
|
|
3748
3991
|
"onChange"
|
|
3749
3992
|
];
|
|
3750
|
-
var
|
|
3993
|
+
var _hoisted_69 = {
|
|
3751
3994
|
key: 2,
|
|
3752
3995
|
class: "block truncate"
|
|
3753
3996
|
};
|
|
3754
|
-
var
|
|
3997
|
+
var _hoisted_70 = [
|
|
3755
3998
|
"href",
|
|
3756
3999
|
"tabindex",
|
|
3757
4000
|
"data-testid",
|
|
3758
4001
|
"onClick",
|
|
3759
4002
|
"onKeydown"
|
|
3760
4003
|
];
|
|
3761
|
-
var
|
|
4004
|
+
var _hoisted_71 = [
|
|
3762
4005
|
"value",
|
|
3763
4006
|
"disabled",
|
|
3764
4007
|
"data-testid",
|
|
3765
4008
|
"aria-label",
|
|
3766
4009
|
"onChange"
|
|
3767
4010
|
];
|
|
3768
|
-
var
|
|
4011
|
+
var _hoisted_72 = {
|
|
3769
4012
|
key: 0,
|
|
3770
4013
|
value: ""
|
|
3771
4014
|
};
|
|
3772
|
-
var
|
|
3773
|
-
var
|
|
4015
|
+
var _hoisted_73 = ["value"];
|
|
4016
|
+
var _hoisted_74 = {
|
|
3774
4017
|
key: 4,
|
|
3775
4018
|
class: "block truncate tabular-nums font-semibold text-slate-900"
|
|
3776
4019
|
};
|
|
3777
|
-
var
|
|
4020
|
+
var _hoisted_75 = {
|
|
3778
4021
|
key: 5,
|
|
3779
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"
|
|
3780
4023
|
};
|
|
3781
|
-
var
|
|
4024
|
+
var _hoisted_76 = {
|
|
3782
4025
|
key: 6,
|
|
3783
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"
|
|
3784
4027
|
};
|
|
3785
|
-
var
|
|
3786
|
-
var
|
|
3787
|
-
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 = [
|
|
3788
4032
|
"href",
|
|
3789
4033
|
"data-testid",
|
|
3790
4034
|
"onClick"
|
|
3791
4035
|
];
|
|
3792
|
-
var
|
|
3793
|
-
key:
|
|
4036
|
+
var _hoisted_81 = {
|
|
4037
|
+
key: 11,
|
|
3794
4038
|
class: "block truncate text-slate-600"
|
|
3795
4039
|
};
|
|
3796
|
-
var
|
|
3797
|
-
var
|
|
3798
|
-
var
|
|
3799
|
-
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 = {
|
|
3800
4044
|
id: "collections-chat-title",
|
|
3801
4045
|
class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
|
|
3802
4046
|
};
|
|
3803
|
-
var
|
|
3804
|
-
var
|
|
3805
|
-
var
|
|
3806
|
-
var
|
|
3807
|
-
var
|
|
3808
|
-
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"];
|
|
3809
4053
|
/** `slug` / `selected` are supplied only in EMBEDDED mode (the
|
|
3810
4054
|
* `presentCollection` chat card mounts this component and drives both
|
|
3811
4055
|
* from the tool result). In standalone route mode (the
|
|
@@ -3907,11 +4151,26 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3907
4151
|
const actionPending = ref(false);
|
|
3908
4152
|
const actionError = ref(null);
|
|
3909
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
|
+
}
|
|
3910
4169
|
const chatOpen = ref(false);
|
|
3911
4170
|
const chatMessage = ref("");
|
|
3912
4171
|
const chatInputEl = ref(null);
|
|
3913
4172
|
const render = useCollectionRendering(collection, locale);
|
|
3914
|
-
const {
|
|
4173
|
+
const { refDisplay, formatMoney, resolveCurrency, derivedDisplay, evaluateDerivedAgainstItem, formatCell, isExternalUrl, artifactUrl, fileRoutePath } = render;
|
|
3915
4174
|
const searchQuery = ref("");
|
|
3916
4175
|
/** Case-insensitive substring match across an item's scalar fields.
|
|
3917
4176
|
* Object-valued fields (table rows, nested records) are skipped —
|
|
@@ -3985,7 +4244,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3985
4244
|
function derivedSortValue(field, key, item) {
|
|
3986
4245
|
const display = field.type === "derived" ? field.display : void 0;
|
|
3987
4246
|
if (display === void 0 || display === "number" || display === "money") return numericSortValue(evaluateDerivedAgainstItem(field, key, item));
|
|
3988
|
-
const enriched =
|
|
4247
|
+
const enriched = render.deriveRecord(item);
|
|
3989
4248
|
if (display === "date") return dateSortValue(enriched[key]);
|
|
3990
4249
|
return stringSortValue(enriched[key]);
|
|
3991
4250
|
}
|
|
@@ -4073,20 +4332,33 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4073
4332
|
}
|
|
4074
4333
|
/** Collection-level header actions. No `when` predicate (no record). */
|
|
4075
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
|
+
}
|
|
4076
4341
|
/** Run a collection-level action: ask the server to assemble the seed
|
|
4077
|
-
* prompt (a progress summary of all records + the template)
|
|
4078
|
-
*
|
|
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. */
|
|
4079
4346
|
async function runCollectionAction(action) {
|
|
4080
4347
|
const current = collection.value;
|
|
4081
|
-
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));
|
|
4082
4351
|
collectionActionPending.value = true;
|
|
4083
4352
|
inlineError.value = null;
|
|
4084
4353
|
const result = await cui.runCollectionAction(current.slug, action.id);
|
|
4085
4354
|
collectionActionPending.value = false;
|
|
4086
4355
|
if (!result.ok) {
|
|
4356
|
+
if (runKey && result.status !== 409) mutateRunningActions((next) => next.delete(runKey));
|
|
4087
4357
|
inlineError.value = result.error;
|
|
4088
4358
|
return;
|
|
4089
4359
|
}
|
|
4360
|
+
if (result.data.dispatched) return;
|
|
4361
|
+
if (result.data.written) return;
|
|
4090
4362
|
if (props.sendTextMessage) {
|
|
4091
4363
|
props.sendTextMessage(result.data.prompt);
|
|
4092
4364
|
return;
|
|
@@ -4121,27 +4393,88 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4121
4393
|
if (!record) return [];
|
|
4122
4394
|
return (collection.value?.schema.actions ?? []).filter((action) => actionVisible(action, record));
|
|
4123
4395
|
});
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
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. */
|
|
4127
4441
|
async function runAction(action) {
|
|
4128
4442
|
if (!collection.value || !viewing.value) return;
|
|
4129
4443
|
const itemId = String(viewing.value[collection.value.schema.primaryKey] ?? "");
|
|
4130
|
-
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));
|
|
4131
4451
|
actionPending.value = true;
|
|
4132
4452
|
actionError.value = null;
|
|
4133
4453
|
const result = await cui.runItemAction(collection.value.slug, itemId, action.id);
|
|
4134
4454
|
actionPending.value = false;
|
|
4135
4455
|
if (!result.ok) {
|
|
4456
|
+
if (runKey && result.status !== 409) mutateRunningActions((next) => next.delete(runKey));
|
|
4136
4457
|
actionError.value = result.error;
|
|
4137
4458
|
return;
|
|
4138
4459
|
}
|
|
4460
|
+
if (result.data.dispatched) return;
|
|
4461
|
+
if (result.data.written) return;
|
|
4139
4462
|
if (props.sendTextMessage) {
|
|
4140
4463
|
props.sendTextMessage(result.data.prompt);
|
|
4141
4464
|
return;
|
|
4142
4465
|
}
|
|
4143
4466
|
appApi.startNewChat(result.data.prompt, result.data.role);
|
|
4144
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
|
+
});
|
|
4145
4478
|
/** Open the chat modal, blanking any prior draft and focusing the input. */
|
|
4146
4479
|
function openChat() {
|
|
4147
4480
|
chatMessage.value = "";
|
|
@@ -4207,10 +4540,12 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4207
4540
|
collection.value = null;
|
|
4208
4541
|
items.value = [];
|
|
4209
4542
|
dataIssues.value = [];
|
|
4543
|
+
mutateRunningActions((next) => next.clear());
|
|
4210
4544
|
searchQuery.value = "";
|
|
4211
4545
|
render.resetLinkedCaches();
|
|
4212
4546
|
viewing.value = null;
|
|
4213
4547
|
openDay.value = null;
|
|
4548
|
+
const runningGen = runningActionsGen;
|
|
4214
4549
|
const result = await cui.fetchCollectionDetail(slug);
|
|
4215
4550
|
loading.value = false;
|
|
4216
4551
|
if (!result.ok) {
|
|
@@ -4221,6 +4556,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4221
4556
|
collection.value = result.data.collection;
|
|
4222
4557
|
items.value = result.data.items;
|
|
4223
4558
|
dataIssues.value = result.data.issues ?? [];
|
|
4559
|
+
applyServerRunningActions(result.data.runningActions, runningGen);
|
|
4224
4560
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4225
4561
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4226
4562
|
if (collection.value?.slug === slug) syncViewToSelected();
|
|
@@ -4236,11 +4572,13 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4236
4572
|
* fetch is a no-op (keep the current data) — a transient blip shouldn't blank a
|
|
4237
4573
|
* view the user is reading. */
|
|
4238
4574
|
async function refreshItemsInPlace(slug) {
|
|
4575
|
+
const runningGen = runningActionsGen;
|
|
4239
4576
|
const result = await cui.fetchCollectionDetail(slug);
|
|
4240
4577
|
if (!result.ok || activeSlug.value !== slug) return;
|
|
4241
4578
|
collection.value = result.data.collection;
|
|
4242
4579
|
items.value = result.data.items;
|
|
4243
4580
|
dataIssues.value = result.data.issues ?? [];
|
|
4581
|
+
applyServerRunningActions(result.data.runningActions, runningGen);
|
|
4244
4582
|
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
4245
4583
|
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
4246
4584
|
if (activeSlug.value !== slug) return;
|
|
@@ -4450,7 +4788,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4450
4788
|
boolOriginallyPresent[key] = false;
|
|
4451
4789
|
boolTouched[key] = false;
|
|
4452
4790
|
} else if (field.type === "table") table[key] = [];
|
|
4453
|
-
else if (
|
|
4791
|
+
else if (!COMPUTED_TYPES.has(field.type)) text[key] = "";
|
|
4454
4792
|
const { singleton, primaryKey } = collection.value.schema;
|
|
4455
4793
|
if (singleton) text[primaryKey] = singleton;
|
|
4456
4794
|
else if (primaryKey in text) text[primaryKey] = generateUniqueItemId(primaryKey);
|
|
@@ -4482,7 +4820,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4482
4820
|
} else if (field.type === "table" && field.of) {
|
|
4483
4821
|
const sub = field.of;
|
|
4484
4822
|
table[key] = (Array.isArray(raw) ? raw : []).filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)).map((row) => rowFromItem(row, sub));
|
|
4485
|
-
} else if (
|
|
4823
|
+
} else if (!COMPUTED_TYPES.has(field.type)) text[key] = raw === void 0 || raw === null ? "" : String(raw);
|
|
4486
4824
|
}
|
|
4487
4825
|
const primaryRaw = item[collection.value.schema.primaryKey];
|
|
4488
4826
|
const originalId = typeof primaryRaw === "string" ? primaryRaw : String(primaryRaw ?? "");
|
|
@@ -4609,7 +4947,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4609
4947
|
* rendering composable; this binds it to the current draft. */
|
|
4610
4948
|
const liveDerived = computed(() => {
|
|
4611
4949
|
if (!collection.value || !liveRecord.value) return null;
|
|
4612
|
-
return render.
|
|
4950
|
+
return render.deriveRecord(liveRecord.value);
|
|
4613
4951
|
});
|
|
4614
4952
|
/** Short summary for a `table`-typed cell in the main collection
|
|
4615
4953
|
* table. Counts rows; nothing fancier yet (per-row preview is
|
|
@@ -4930,7 +5268,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4930
5268
|
"aria-label": unref(t)("collectionsView.backToIndex"),
|
|
4931
5269
|
"data-testid": "collections-back",
|
|
4932
5270
|
onClick: goBack
|
|
4933
|
-
}, [..._cache[
|
|
5271
|
+
}, [..._cache[26] || (_cache[26] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : createCommentVNode("", true),
|
|
4934
5272
|
collection.value ? (openBlock(), createElementBlock("div", _hoisted_4$5, [createElementVNode("span", _hoisted_5$5, toDisplayString(collection.value.icon), 1)])) : createCommentVNode("", true),
|
|
4935
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)]),
|
|
4936
5274
|
collection.value && !embedded.value ? (openBlock(), createBlock(resolveDynamicComponent(unref(pinToggle)), {
|
|
@@ -4959,16 +5297,16 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4959
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",
|
|
4960
5298
|
"data-testid": "collections-chat",
|
|
4961
5299
|
onClick: openChat
|
|
4962
|
-
}, [_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),
|
|
4963
5301
|
(openBlock(true), createElementBlock(Fragment, null, renderList(collectionActions.value, (action) => {
|
|
4964
5302
|
return openBlock(), createElementBlock("button", {
|
|
4965
5303
|
key: action.id,
|
|
4966
5304
|
type: "button",
|
|
4967
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",
|
|
4968
|
-
disabled: collectionActionPending.value,
|
|
5306
|
+
disabled: collectionActionPending.value || isActionRunning(action.id),
|
|
4969
5307
|
"data-testid": `collections-action-${action.id}`,
|
|
4970
5308
|
onClick: ($event) => runCollectionAction(action)
|
|
4971
|
-
}, [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);
|
|
4972
5310
|
}), 128)),
|
|
4973
5311
|
canCreate.value && !calendarActive.value ? (openBlock(), createElementBlock("button", {
|
|
4974
5312
|
key: 5,
|
|
@@ -4976,7 +5314,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4976
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",
|
|
4977
5315
|
"data-testid": "collections-add-item",
|
|
4978
5316
|
onClick: openCreate
|
|
4979
|
-
}, [_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),
|
|
4980
5318
|
canDeleteCollection.value && !embedded.value ? (openBlock(), createElementBlock("button", {
|
|
4981
5319
|
key: 6,
|
|
4982
5320
|
type: "button",
|
|
@@ -4985,7 +5323,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4985
5323
|
"aria-label": unref(t)("collectionsView.deleteCollection"),
|
|
4986
5324
|
"data-testid": "collections-delete",
|
|
4987
5325
|
onClick: confirmCollectionDelete
|
|
4988
|
-
}, [..._cache[
|
|
5326
|
+
}, [..._cache[29] || (_cache[29] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : createCommentVNode("", true),
|
|
4989
5327
|
canDeleteFeed.value && !embedded.value ? (openBlock(), createElementBlock("button", {
|
|
4990
5328
|
key: 7,
|
|
4991
5329
|
type: "button",
|
|
@@ -4994,26 +5332,26 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4994
5332
|
"aria-label": unref(t)("collectionsView.deleteFeed"),
|
|
4995
5333
|
"data-testid": "feeds-delete",
|
|
4996
5334
|
onClick: confirmFeedDelete
|
|
4997
|
-
}, [..._cache[
|
|
5335
|
+
}, [..._cache[30] || (_cache[30] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_15$4)) : createCommentVNode("", true)
|
|
4998
5336
|
])) : createCommentVNode("", true),
|
|
4999
|
-
refreshNote.value ? (openBlock(), createElementBlock("div",
|
|
5000
|
-
collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? (openBlock(), createElementBlock("div",
|
|
5001
|
-
_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)),
|
|
5002
5340
|
withDirectives(createElementVNode("input", {
|
|
5003
5341
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
|
|
5004
5342
|
type: "text",
|
|
5005
5343
|
placeholder: unref(t)("collectionsView.searchPlaceholder"),
|
|
5006
5344
|
"aria-label": unref(t)("collectionsView.searchPlaceholder"),
|
|
5007
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"
|
|
5008
|
-
}, null, 8,
|
|
5346
|
+
}, null, 8, _hoisted_20$2), [[vModelText, searchQuery.value]]),
|
|
5009
5347
|
searchQuery.value ? (openBlock(), createElementBlock("button", {
|
|
5010
5348
|
key: 0,
|
|
5011
5349
|
type: "button",
|
|
5012
5350
|
"aria-label": unref(t)("collectionsView.clearSearch"),
|
|
5013
5351
|
class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
|
|
5014
5352
|
onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
|
|
5015
|
-
}, [..._cache[
|
|
5016
|
-
])) : 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, [
|
|
5017
5355
|
!__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? (openBlock(), createElementBlock("div", {
|
|
5018
5356
|
key: 0,
|
|
5019
5357
|
class: "flex gap-0.5",
|
|
@@ -5026,7 +5364,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5026
5364
|
"aria-pressed": activeView.value === "table",
|
|
5027
5365
|
"data-testid": "collection-view-toggle-table",
|
|
5028
5366
|
onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
|
|
5029
|
-
}, [_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),
|
|
5030
5368
|
hasCalendar.value ? (openBlock(), createElementBlock("button", {
|
|
5031
5369
|
key: 0,
|
|
5032
5370
|
type: "button",
|
|
@@ -5034,7 +5372,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5034
5372
|
"aria-pressed": activeView.value === "calendar",
|
|
5035
5373
|
"data-testid": "collection-view-toggle-calendar",
|
|
5036
5374
|
onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
|
|
5037
|
-
}, [_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),
|
|
5038
5376
|
hasKanban.value ? (openBlock(), createElementBlock("button", {
|
|
5039
5377
|
key: 1,
|
|
5040
5378
|
type: "button",
|
|
@@ -5042,7 +5380,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5042
5380
|
"aria-pressed": activeView.value === "kanban",
|
|
5043
5381
|
"data-testid": "collection-view-toggle-kanban",
|
|
5044
5382
|
onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
|
|
5045
|
-
}, [_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),
|
|
5046
5384
|
(openBlock(true), createElementBlock(Fragment, null, renderList(customViews.value, (cv) => {
|
|
5047
5385
|
return openBlock(), createElementBlock("button", {
|
|
5048
5386
|
key: cv.id,
|
|
@@ -5051,7 +5389,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5051
5389
|
"aria-pressed": activeView.value === unref(customViewKey)(cv.id),
|
|
5052
5390
|
"data-testid": `collection-view-custom-${cv.id}`,
|
|
5053
5391
|
onClick: ($event) => setCustomView(cv.id)
|
|
5054
|
-
}, [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);
|
|
5055
5393
|
}), 128)),
|
|
5056
5394
|
canAddCustomView.value ? (openBlock(), createElementBlock("div", {
|
|
5057
5395
|
key: 2,
|
|
@@ -5066,17 +5404,17 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5066
5404
|
"aria-expanded": addMenuOpen.value,
|
|
5067
5405
|
"data-testid": "collection-view-add",
|
|
5068
5406
|
onClick: onAddViewClick
|
|
5069
|
-
}, [..._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", {
|
|
5070
5408
|
type: "button",
|
|
5071
5409
|
class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
|
|
5072
5410
|
"data-testid": "collection-view-add-desktop",
|
|
5073
5411
|
onClick: _cache[5] || (_cache[5] = ($event) => addCustomView("desktop"))
|
|
5074
|
-
}, [_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", {
|
|
5075
5413
|
type: "button",
|
|
5076
5414
|
class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
|
|
5077
5415
|
"data-testid": "collection-view-add-mobile",
|
|
5078
5416
|
onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("mobile"))
|
|
5079
|
-
}, [_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),
|
|
5080
5418
|
canConfigureViews.value ? (openBlock(), createElementBlock("button", {
|
|
5081
5419
|
key: 3,
|
|
5082
5420
|
type: "button",
|
|
@@ -5085,8 +5423,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5085
5423
|
"aria-label": unref(t)("collectionsView.config.open"),
|
|
5086
5424
|
"data-testid": "collection-config-open",
|
|
5087
5425
|
onClick: _cache[7] || (_cache[7] = ($event) => configOpen.value = true)
|
|
5088
|
-
}, [..._cache[
|
|
5089
|
-
], 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),
|
|
5090
5428
|
calendarActive.value && dateFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
|
|
5091
5429
|
key: 1,
|
|
5092
5430
|
value: calendarAnchorField.value,
|
|
@@ -5098,8 +5436,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5098
5436
|
return openBlock(), createElementBlock("option", {
|
|
5099
5437
|
key,
|
|
5100
5438
|
value: key
|
|
5101
|
-
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9,
|
|
5102
|
-
}), 128))], 40,
|
|
5439
|
+
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_33);
|
|
5440
|
+
}), 128))], 40, _hoisted_32)) : createCommentVNode("", true),
|
|
5103
5441
|
kanbanActive.value && enumFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
|
|
5104
5442
|
key: 2,
|
|
5105
5443
|
value: kanbanGroupField.value,
|
|
@@ -5111,24 +5449,24 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5111
5449
|
return openBlock(), createElementBlock("option", {
|
|
5112
5450
|
key,
|
|
5113
5451
|
value: key
|
|
5114
|
-
}, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9,
|
|
5115
|
-
}), 128))], 40,
|
|
5116
|
-
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", {
|
|
5117
5455
|
shown: filteredItems.value.length,
|
|
5118
5456
|
total: items.value.length
|
|
5119
5457
|
})), 1)) : createCommentVNode("", true)
|
|
5120
5458
|
])])) : createCommentVNode("", true),
|
|
5121
|
-
collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div",
|
|
5122
|
-
_cache[
|
|
5123
|
-
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),
|
|
5124
5462
|
createElementVNode("button", {
|
|
5125
5463
|
type: "button",
|
|
5126
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",
|
|
5127
5465
|
"data-testid": "collections-repair",
|
|
5128
5466
|
onClick: repairCollection
|
|
5129
|
-
}, [_cache[
|
|
5467
|
+
}, [_cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
|
|
5130
5468
|
])) : createCommentVNode("", true),
|
|
5131
|
-
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, {
|
|
5132
5470
|
schema: collection.value.schema,
|
|
5133
5471
|
items: filteredItems.value,
|
|
5134
5472
|
"anchor-field": calendarAnchorField.value,
|
|
@@ -5172,6 +5510,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5172
5510
|
"action-error": actionError.value,
|
|
5173
5511
|
"action-pending": actionPending.value,
|
|
5174
5512
|
"visible-actions": visibleActions.value,
|
|
5513
|
+
"running-action-ids": viewingRunningActionIds.value,
|
|
5175
5514
|
"live-record": liveRecord.value,
|
|
5176
5515
|
"live-derived": liveDerived.value,
|
|
5177
5516
|
"view-title": viewTitle.value,
|
|
@@ -5194,6 +5533,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5194
5533
|
"action-error",
|
|
5195
5534
|
"action-pending",
|
|
5196
5535
|
"visible-actions",
|
|
5536
|
+
"running-action-ids",
|
|
5197
5537
|
"live-record",
|
|
5198
5538
|
"live-derived",
|
|
5199
5539
|
"view-title",
|
|
@@ -5213,16 +5553,16 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5213
5553
|
"selected",
|
|
5214
5554
|
"can-create",
|
|
5215
5555
|
"show-detail"
|
|
5216
|
-
])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div",
|
|
5217
|
-
_cache[
|
|
5218
|
-
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),
|
|
5219
5559
|
createElementVNode("button", {
|
|
5220
5560
|
type: "button",
|
|
5221
5561
|
class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
|
|
5222
5562
|
"aria-label": unref(t)("common.close"),
|
|
5223
5563
|
onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
|
|
5224
|
-
}, [..._cache[
|
|
5225
|
-
])) : 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, {
|
|
5226
5566
|
schema: collection.value.schema,
|
|
5227
5567
|
items: filteredItems.value,
|
|
5228
5568
|
"group-field": kanbanGroupField.value,
|
|
@@ -5236,7 +5576,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5236
5576
|
"group-field",
|
|
5237
5577
|
"selected",
|
|
5238
5578
|
"notified"
|
|
5239
|
-
])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div",
|
|
5579
|
+
])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_49, [activeCustomView.value.target === "mobile" ? (openBlock(), createBlock(CollectionRemoteViewPreview_default, {
|
|
5240
5580
|
key: 0,
|
|
5241
5581
|
slug: collection.value.slug,
|
|
5242
5582
|
view: activeCustomView.value,
|
|
@@ -5247,32 +5587,32 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5247
5587
|
view: activeCustomView.value,
|
|
5248
5588
|
onOpenItem: onCustomViewOpenItem,
|
|
5249
5589
|
onStartChat: onCustomViewStartChat
|
|
5250
|
-
}, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div",
|
|
5251
|
-
_cache[
|
|
5252
|
-
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),
|
|
5253
5593
|
createElementVNode("button", {
|
|
5254
5594
|
type: "button",
|
|
5255
5595
|
class: "text-xs text-indigo-600 font-semibold hover:underline",
|
|
5256
5596
|
onClick: _cache[13] || (_cache[13] = ($event) => searchQuery.value = "")
|
|
5257
5597
|
}, toDisplayString(unref(t)("collectionsView.clearSearch")), 1)
|
|
5258
|
-
])) : (openBlock(), createElementBlock("div",
|
|
5259
|
-
_cache[
|
|
5260
|
-
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),
|
|
5261
5601
|
createElementVNode("button", {
|
|
5262
5602
|
type: "button",
|
|
5263
5603
|
class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
|
|
5264
5604
|
"aria-label": unref(t)("common.close"),
|
|
5265
5605
|
onClick: _cache[14] || (_cache[14] = ($event) => inlineError.value = null)
|
|
5266
|
-
}, [..._cache[
|
|
5267
|
-
])) : 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]) => {
|
|
5268
5608
|
return openBlock(), createElementBlock("th", {
|
|
5269
5609
|
key,
|
|
5270
5610
|
"aria-sort": unref(isSortableField)(field) ? sortAriaValue(key) : void 0,
|
|
5271
5611
|
class: "px-5 py-3 font-bold text-slate-500 text-left uppercase tracking-wider whitespace-nowrap"
|
|
5272
|
-
}, [createElementVNode("div",
|
|
5612
|
+
}, [createElementVNode("div", _hoisted_61, [createElementVNode("span", {
|
|
5273
5613
|
class: "truncate max-w-[14rem]",
|
|
5274
5614
|
title: field.label
|
|
5275
|
-
}, toDisplayString(field.label), 9,
|
|
5615
|
+
}, toDisplayString(field.label), 9, _hoisted_62), unref(isSortableField)(field) ? (openBlock(), createElementBlock("button", {
|
|
5276
5616
|
key: 0,
|
|
5277
5617
|
type: "button",
|
|
5278
5618
|
class: normalizeClass(["inline-flex items-center justify-center rounded p-0.5 -my-1 leading-none transition-colors", sortButtonClass(key)]),
|
|
@@ -5281,8 +5621,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5281
5621
|
onClick: withModifiers(($event) => cycleSort(key), ["stop"]),
|
|
5282
5622
|
onPointerenter: ($event) => hoveredSortKey.value = key,
|
|
5283
5623
|
onPointerleave: _cache[15] || (_cache[15] = ($event) => hoveredSortKey.value = null)
|
|
5284
|
-
}, [createElementVNode("span",
|
|
5285
|
-
}), 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) => {
|
|
5286
5626
|
return openBlock(), createElementBlock("tr", {
|
|
5287
5627
|
key: String(item[collection.value.schema.primaryKey] ?? ""),
|
|
5288
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" : ""]),
|
|
@@ -5306,7 +5646,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5306
5646
|
"aria-label": field.label,
|
|
5307
5647
|
onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"])),
|
|
5308
5648
|
onChange: ($event) => commitToggle(item, field)
|
|
5309
|
-
}, null, 40,
|
|
5649
|
+
}, null, 40, _hoisted_67)) : field.type === "boolean" ? (openBlock(), createElementBlock("input", {
|
|
5310
5650
|
key: 1,
|
|
5311
5651
|
type: "checkbox",
|
|
5312
5652
|
checked: item[key] === true,
|
|
@@ -5316,7 +5656,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5316
5656
|
"aria-label": field.label,
|
|
5317
5657
|
onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"])),
|
|
5318
5658
|
onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
|
|
5319
|
-
}, 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", {
|
|
5320
5660
|
href: unref(cui).recordHref?.(field.to, String(item[key])),
|
|
5321
5661
|
tabindex: unref(cui).recordHref?.(field.to, String(item[key])) ? void 0 : 0,
|
|
5322
5662
|
role: "link",
|
|
@@ -5324,7 +5664,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5324
5664
|
"data-testid": `collections-ref-link-${key}-${item[key]}`,
|
|
5325
5665
|
onClick: ($event) => unref(activateRefLink)($event, field.to, String(item[key]), true),
|
|
5326
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"])]
|
|
5327
|
-
}, 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", {
|
|
5328
5668
|
key: 3,
|
|
5329
5669
|
value: item[key] == null ? "" : String(item[key]),
|
|
5330
5670
|
disabled: isRowInlineSaving(item),
|
|
@@ -5333,35 +5673,39 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5333
5673
|
"aria-label": field.label,
|
|
5334
5674
|
onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"])),
|
|
5335
5675
|
onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
|
|
5336
|
-
}, [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) => {
|
|
5337
5677
|
return openBlock(), createElementBlock("option", {
|
|
5338
5678
|
key: value,
|
|
5339
5679
|
value
|
|
5340
|
-
}, toDisplayString(value), 9,
|
|
5341
|
-
}), 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", {
|
|
5342
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,
|
|
5343
5687
|
href: String(item[key]),
|
|
5344
5688
|
target: "_blank",
|
|
5345
5689
|
rel: "noopener noreferrer",
|
|
5346
5690
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5347
5691
|
"data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5348
5692
|
onClick: _cache[19] || (_cache[19] = withModifiers(() => {}, ["stop"]))
|
|
5349
|
-
}, toDisplayString(String(item[key])), 9,
|
|
5350
|
-
key:
|
|
5693
|
+
}, toDisplayString(String(item[key])), 9, _hoisted_78)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
|
|
5694
|
+
key: 9,
|
|
5351
5695
|
href: unref(artifactUrl)(item[key]) ?? void 0,
|
|
5352
5696
|
target: "_blank",
|
|
5353
5697
|
rel: "noopener noreferrer",
|
|
5354
5698
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5355
5699
|
"data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5356
5700
|
onClick: _cache[20] || (_cache[20] = withModifiers(() => {}, ["stop"]))
|
|
5357
|
-
}, toDisplayString(String(item[key])), 9,
|
|
5358
|
-
key:
|
|
5701
|
+
}, toDisplayString(String(item[key])), 9, _hoisted_79)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
|
|
5702
|
+
key: 10,
|
|
5359
5703
|
href: unref(fileRoutePath)(item[key]) ?? void 0,
|
|
5360
5704
|
class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
|
|
5361
5705
|
"data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
|
|
5362
5706
|
onClick: ($event) => unref(activatePathLink)($event, unref(fileRoutePath)(item[key]) ?? "", true)
|
|
5363
|
-
}, toDisplayString(String(item[key])), 9,
|
|
5364
|
-
}), 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);
|
|
5365
5709
|
}), 128))])])]))]),
|
|
5366
5710
|
collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? (openBlock(), createBlock(CollectionRecordModal_default, {
|
|
5367
5711
|
key: 4,
|
|
@@ -5377,6 +5721,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5377
5721
|
"action-error": actionError.value,
|
|
5378
5722
|
"action-pending": actionPending.value,
|
|
5379
5723
|
"visible-actions": visibleActions.value,
|
|
5724
|
+
"running-action-ids": viewingRunningActionIds.value,
|
|
5380
5725
|
"live-record": liveRecord.value,
|
|
5381
5726
|
"live-derived": liveDerived.value,
|
|
5382
5727
|
"view-title": viewTitle.value,
|
|
@@ -5399,6 +5744,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5399
5744
|
"action-error",
|
|
5400
5745
|
"action-pending",
|
|
5401
5746
|
"visible-actions",
|
|
5747
|
+
"running-action-ids",
|
|
5402
5748
|
"live-record",
|
|
5403
5749
|
"live-derived",
|
|
5404
5750
|
"view-title",
|
|
@@ -5408,20 +5754,32 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5408
5754
|
])]),
|
|
5409
5755
|
_: 1
|
|
5410
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),
|
|
5411
5769
|
configOpen.value && collection.value ? (openBlock(), createBlock(CollectionViewConfigModal_default, {
|
|
5412
|
-
key:
|
|
5770
|
+
key: 6,
|
|
5413
5771
|
slug: collection.value.slug,
|
|
5414
5772
|
title: collection.value.title,
|
|
5415
5773
|
views: customViews.value,
|
|
5416
5774
|
onChanged: onViewsChanged,
|
|
5417
|
-
onClose: _cache[
|
|
5775
|
+
onClose: _cache[24] || (_cache[24] = ($event) => configOpen.value = false)
|
|
5418
5776
|
}, null, 8, [
|
|
5419
5777
|
"slug",
|
|
5420
5778
|
"title",
|
|
5421
5779
|
"views"
|
|
5422
5780
|
])) : createCommentVNode("", true),
|
|
5423
5781
|
chatOpen.value && collection.value ? (openBlock(), createElementBlock("div", {
|
|
5424
|
-
key:
|
|
5782
|
+
key: 7,
|
|
5425
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",
|
|
5426
5784
|
role: "dialog",
|
|
5427
5785
|
"aria-modal": "true",
|
|
@@ -5429,29 +5787,29 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5429
5787
|
"data-testid": "collections-chat-modal",
|
|
5430
5788
|
onClick: withModifiers(closeChat, ["self"]),
|
|
5431
5789
|
onKeydown: withKeys(closeChat, ["esc"])
|
|
5432
|
-
}, [createElementVNode("div",
|
|
5433
|
-
createElementVNode("header",
|
|
5434
|
-
_cache[
|
|
5435
|
-
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)]),
|
|
5436
5794
|
createElementVNode("button", {
|
|
5437
5795
|
type: "button",
|
|
5438
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",
|
|
5439
5797
|
"aria-label": unref(t)("common.close"),
|
|
5440
5798
|
"data-testid": "collections-chat-close",
|
|
5441
5799
|
onClick: closeChat
|
|
5442
|
-
}, [..._cache[
|
|
5800
|
+
}, [..._cache[52] || (_cache[52] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_87)
|
|
5443
5801
|
]),
|
|
5444
|
-
createElementVNode("div",
|
|
5802
|
+
createElementVNode("div", _hoisted_88, [withDirectives(createElementVNode("textarea", {
|
|
5445
5803
|
ref_key: "chatInputEl",
|
|
5446
5804
|
ref: chatInputEl,
|
|
5447
|
-
"onUpdate:modelValue": _cache[
|
|
5805
|
+
"onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => chatMessage.value = $event),
|
|
5448
5806
|
rows: "4",
|
|
5449
5807
|
placeholder: unref(t)("collectionsView.chatPlaceholder"),
|
|
5450
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",
|
|
5451
5809
|
"data-testid": "collections-chat-input",
|
|
5452
5810
|
onKeydown: [withKeys(withModifiers(submitChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitChat, ["ctrl"]), ["enter"])]
|
|
5453
|
-
}, null, 40,
|
|
5454
|
-
createElementVNode("footer",
|
|
5811
|
+
}, null, 40, _hoisted_89), [[vModelText, chatMessage.value]])]),
|
|
5812
|
+
createElementVNode("footer", _hoisted_90, [createElementVNode("button", {
|
|
5455
5813
|
type: "button",
|
|
5456
5814
|
class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
|
|
5457
5815
|
"data-testid": "collections-chat-cancel",
|
|
@@ -5462,7 +5820,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
5462
5820
|
disabled: !chatMessage.value.trim(),
|
|
5463
5821
|
"data-testid": "collections-chat-send",
|
|
5464
5822
|
onClick: submitChat
|
|
5465
|
-
}, toDisplayString(unref(t)("collectionsView.chatStart")), 9,
|
|
5823
|
+
}, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_91)])
|
|
5466
5824
|
])], 32)) : createCommentVNode("", true)
|
|
5467
5825
|
]);
|
|
5468
5826
|
};
|