@mulmoclaude/collection-plugin 0.5.3 → 0.5.7
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/server/host.d.ts +25 -0
- package/dist/server/host.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/io.d.ts +6 -0
- package/dist/server/io.d.ts.map +1 -1
- package/dist/server.cjs +32 -8
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +31 -9
- package/dist/server.js.map +1 -1
- package/dist/style.css +19 -3
- package/dist/vue/components/CollectionCustomView.vue.d.ts +19 -1
- package/dist/vue/components/CollectionCustomView.vue.d.ts.map +1 -1
- package/dist/vue/components/CollectionRecordPanel.vue.d.ts +4 -2
- 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/lang/de.d.ts.map +1 -1
- package/dist/vue/lang/en.d.ts +2 -0
- package/dist/vue/lang/en.d.ts.map +1 -1
- package/dist/vue/lang/es.d.ts.map +1 -1
- package/dist/vue/lang/fr.d.ts.map +1 -1
- package/dist/vue/lang/index.d.ts +2 -0
- package/dist/vue/lang/index.d.ts.map +1 -1
- package/dist/vue/lang/ja.d.ts.map +1 -1
- package/dist/vue/lang/ko.d.ts.map +1 -1
- package/dist/vue/lang/ptBR.d.ts.map +1 -1
- package/dist/vue/lang/zh.d.ts.map +1 -1
- package/dist/vue/uiContext.d.ts +12 -0
- package/dist/vue/uiContext.d.ts.map +1 -1
- package/dist/vue/useCollectionRendering.d.ts +2 -0
- package/dist/vue/useCollectionRendering.d.ts.map +1 -1
- package/dist/vue.cjs +240 -19
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +241 -20
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
package/dist/vue.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as buildUpdatedRecord, C as dateSortValue, D as numericSortValue, E as nextSortDirection, F as rowFromItem, G as TOOL_DEFINITION, I as actionVisible, L as fieldVisible, M as draftToRecord, N as emptyRow, O as sortItems, P as firstMissingRequiredField, T as isSortableField, W as resolveEnumColor, _ as ymdKey, a as assignLanes, b as labelFieldFor, i as MINUTES_PER_DAY, j as coerceInlineValue, k as stringSortValue, l as dateOf, n as shortHexId, o as bucketRecords, q as executePresentCollection, r as errorMessage, s as buildMonthGrid, t as defangForPrompt, u as daySlice, v as itemIdOf, w as enumSortValue, x as boolSortValue, y as itemLabelOf } from "./promptSafety-DIQ2yDca.js";
|
|
2
2
|
import { t as deriveAll } from "./deriveAll-BHcs1erT.js";
|
|
3
|
-
import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, effectScope, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useModel, vModelCheckbox, vModelDynamic, vModelSelect, vModelText, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
3
|
+
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";
|
|
4
4
|
import { createI18n } from "vue-i18n";
|
|
5
5
|
import draggable from "vuedraggable";
|
|
6
6
|
//#region src/vue/uiContext.ts
|
|
@@ -67,6 +67,8 @@ var i18n = createI18n({
|
|
|
67
67
|
chatTitle: "Start a chat",
|
|
68
68
|
chatPlaceholder: "Describe what you want to do with this collection…",
|
|
69
69
|
chatStart: "Start chat",
|
|
70
|
+
itemChatLabel: "Chat about this record",
|
|
71
|
+
itemChatPlaceholder: "Ask or instruct about this record…",
|
|
70
72
|
viewToggle: "View",
|
|
71
73
|
viewTable: "Table",
|
|
72
74
|
viewCalendar: "Calendar",
|
|
@@ -168,6 +170,8 @@ var i18n = createI18n({
|
|
|
168
170
|
chatTitle: "チャットを開始",
|
|
169
171
|
chatPlaceholder: "このコレクションで行いたいことを入力してください…",
|
|
170
172
|
chatStart: "チャットを開始",
|
|
173
|
+
itemChatLabel: "このレコードについてチャット",
|
|
174
|
+
itemChatPlaceholder: "このレコードについて質問・指示する…",
|
|
171
175
|
viewToggle: "表示",
|
|
172
176
|
viewTable: "テーブル",
|
|
173
177
|
viewCalendar: "カレンダー",
|
|
@@ -269,6 +273,8 @@ var i18n = createI18n({
|
|
|
269
273
|
chatTitle: "开始对话",
|
|
270
274
|
chatPlaceholder: "描述你想对这个集合做什么…",
|
|
271
275
|
chatStart: "开始对话",
|
|
276
|
+
itemChatLabel: "就此记录对话",
|
|
277
|
+
itemChatPlaceholder: "询问或指示有关此记录的操作…",
|
|
272
278
|
viewToggle: "视图",
|
|
273
279
|
viewTable: "表格",
|
|
274
280
|
viewCalendar: "日历",
|
|
@@ -370,6 +376,8 @@ var i18n = createI18n({
|
|
|
370
376
|
chatTitle: "채팅 시작",
|
|
371
377
|
chatPlaceholder: "이 컬렉션으로 하고 싶은 작업을 설명하세요…",
|
|
372
378
|
chatStart: "채팅 시작",
|
|
379
|
+
itemChatLabel: "이 레코드에 대해 채팅",
|
|
380
|
+
itemChatPlaceholder: "이 레코드에 대해 질문하거나 지시하세요…",
|
|
373
381
|
viewToggle: "보기",
|
|
374
382
|
viewTable: "표",
|
|
375
383
|
viewCalendar: "캘린더",
|
|
@@ -471,6 +479,8 @@ var i18n = createI18n({
|
|
|
471
479
|
chatTitle: "Iniciar un chat",
|
|
472
480
|
chatPlaceholder: "Describe qué quieres hacer con esta colección…",
|
|
473
481
|
chatStart: "Iniciar chat",
|
|
482
|
+
itemChatLabel: "Chatear sobre este registro",
|
|
483
|
+
itemChatPlaceholder: "Pregunta o indica algo sobre este registro…",
|
|
474
484
|
viewToggle: "Vista",
|
|
475
485
|
viewTable: "Tabla",
|
|
476
486
|
viewCalendar: "Calendario",
|
|
@@ -572,6 +582,8 @@ var i18n = createI18n({
|
|
|
572
582
|
chatTitle: "Iniciar um chat",
|
|
573
583
|
chatPlaceholder: "Descreva o que você quer fazer com esta coleção…",
|
|
574
584
|
chatStart: "Iniciar chat",
|
|
585
|
+
itemChatLabel: "Conversar sobre este registro",
|
|
586
|
+
itemChatPlaceholder: "Pergunte ou instrua sobre este registro…",
|
|
575
587
|
viewToggle: "Visualização",
|
|
576
588
|
viewTable: "Tabela",
|
|
577
589
|
viewCalendar: "Calendário",
|
|
@@ -673,6 +685,8 @@ var i18n = createI18n({
|
|
|
673
685
|
chatTitle: "Démarrer une discussion",
|
|
674
686
|
chatPlaceholder: "Décrivez ce que vous voulez faire avec cette collection…",
|
|
675
687
|
chatStart: "Démarrer la discussion",
|
|
688
|
+
itemChatLabel: "Discuter de cet enregistrement",
|
|
689
|
+
itemChatPlaceholder: "Posez une question ou donnez une instruction sur cet enregistrement…",
|
|
676
690
|
viewToggle: "Affichage",
|
|
677
691
|
viewTable: "Tableau",
|
|
678
692
|
viewCalendar: "Calendrier",
|
|
@@ -774,6 +788,8 @@ var i18n = createI18n({
|
|
|
774
788
|
chatTitle: "Chat starten",
|
|
775
789
|
chatPlaceholder: "Beschreibe, was du mit dieser Sammlung tun möchtest…",
|
|
776
790
|
chatStart: "Chat starten",
|
|
791
|
+
itemChatLabel: "Über diesen Eintrag chatten",
|
|
792
|
+
itemChatPlaceholder: "Stelle eine Frage oder gib eine Anweisung zu diesem Eintrag…",
|
|
777
793
|
viewToggle: "Ansicht",
|
|
778
794
|
viewTable: "Tabelle",
|
|
779
795
|
viewCalendar: "Kalender",
|
|
@@ -1755,6 +1771,7 @@ var _hoisted_36$1 = ["onUpdate:modelValue", "required"];
|
|
|
1755
1771
|
var _hoisted_37$1 = [
|
|
1756
1772
|
"onUpdate:modelValue",
|
|
1757
1773
|
"type",
|
|
1774
|
+
"step",
|
|
1758
1775
|
"required"
|
|
1759
1776
|
];
|
|
1760
1777
|
var _hoisted_38$1 = { class: "text-center px-1" };
|
|
@@ -1783,6 +1800,7 @@ var _hoisted_45$1 = [
|
|
|
1783
1800
|
"id",
|
|
1784
1801
|
"onUpdate:modelValue",
|
|
1785
1802
|
"type",
|
|
1803
|
+
"step",
|
|
1786
1804
|
"required",
|
|
1787
1805
|
"disabled",
|
|
1788
1806
|
"data-testid"
|
|
@@ -1873,6 +1891,18 @@ var _hoisted_69$1 = {
|
|
|
1873
1891
|
key: 0,
|
|
1874
1892
|
class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
|
|
1875
1893
|
};
|
|
1894
|
+
var _hoisted_70$1 = {
|
|
1895
|
+
key: 1,
|
|
1896
|
+
class: "mt-5 pt-4 border-t border-slate-200/60",
|
|
1897
|
+
"data-testid": "collections-detail-chat"
|
|
1898
|
+
};
|
|
1899
|
+
var _hoisted_71$1 = {
|
|
1900
|
+
class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
|
|
1901
|
+
for: "collections-detail-chat-input"
|
|
1902
|
+
};
|
|
1903
|
+
var _hoisted_72$1 = { class: "flex items-end gap-2" };
|
|
1904
|
+
var _hoisted_73$1 = ["placeholder", "onKeydown"];
|
|
1905
|
+
var _hoisted_74$1 = ["disabled"];
|
|
1876
1906
|
//#endregion
|
|
1877
1907
|
//#region src/vue/components/CollectionRecordPanel.vue
|
|
1878
1908
|
var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
@@ -1901,7 +1931,8 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
1901
1931
|
"edit",
|
|
1902
1932
|
"close",
|
|
1903
1933
|
"delete",
|
|
1904
|
-
"runAction"
|
|
1934
|
+
"runAction",
|
|
1935
|
+
"itemChat"
|
|
1905
1936
|
], ["update:editing"]),
|
|
1906
1937
|
setup(__props, { emit: __emit }) {
|
|
1907
1938
|
const cui = collectionUi();
|
|
@@ -1910,6 +1941,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
1910
1941
|
const editing = useModel(__props, "editing");
|
|
1911
1942
|
const emit = __emit;
|
|
1912
1943
|
const { t } = useCollectionI18n();
|
|
1944
|
+
const chatMessage = ref("");
|
|
1945
|
+
watch(() => props.viewing, () => {
|
|
1946
|
+
chatMessage.value = "";
|
|
1947
|
+
});
|
|
1948
|
+
function submitItemChat() {
|
|
1949
|
+
const message = chatMessage.value.trim();
|
|
1950
|
+
if (!message) return;
|
|
1951
|
+
emit("itemChat", message);
|
|
1952
|
+
chatMessage.value = "";
|
|
1953
|
+
}
|
|
1913
1954
|
const embedViews = computed(() => props.render.embedViews.value);
|
|
1914
1955
|
/** The record the read-only displays render from: the live draft while
|
|
1915
1956
|
* editing (so non-editable cells like derived/embed preview the in-flight
|
|
@@ -1988,7 +2029,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
1988
2029
|
return openBlock(), createBlock(resolveDynamicComponent(editing.value ? "form" : "div"), {
|
|
1989
2030
|
class: "px-6 py-5 max-h-[60vh] overflow-y-auto",
|
|
1990
2031
|
"data-testid": rootTestid.value,
|
|
1991
|
-
onSubmit: _cache[
|
|
2032
|
+
onSubmit: _cache[5] || (_cache[5] = withModifiers(($event) => emit("submit"), ["prevent"]))
|
|
1992
2033
|
}, {
|
|
1993
2034
|
default: withCtx(() => [
|
|
1994
2035
|
createElementVNode("div", _hoisted_1$7, [createElementVNode("div", _hoisted_2$6, [createElementVNode("span", _hoisted_3$6, toDisplayString(__props.collection.title), 1), createElementVNode("h2", {
|
|
@@ -2020,20 +2061,20 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2020
2061
|
class: "h-8 px-2.5 rounded border border-slate-200 bg-white text-slate-700 hover:bg-slate-50 font-bold text-xs transition-all flex items-center gap-1",
|
|
2021
2062
|
"data-testid": "collections-detail-edit",
|
|
2022
2063
|
onClick: _cache[1] || (_cache[1] = ($event) => emit("edit"))
|
|
2023
|
-
}, [_cache[
|
|
2064
|
+
}, [_cache[6] || (_cache[6] = createElementVNode("span", { class: "material-icons text-sm" }, "edit", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.editItem")), 1)]),
|
|
2024
2065
|
createElementVNode("button", {
|
|
2025
2066
|
type: "button",
|
|
2026
2067
|
class: "h-8 px-2.5 rounded border border-rose-200 bg-white text-rose-600 hover:bg-rose-50 font-bold text-xs transition-all flex items-center gap-1",
|
|
2027
2068
|
"data-testid": "collections-detail-remove",
|
|
2028
2069
|
onClick: _cache[2] || (_cache[2] = ($event) => emit("delete"))
|
|
2029
|
-
}, [_cache[
|
|
2070
|
+
}, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "material-icons text-sm" }, "delete", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.remove")), 1)]),
|
|
2030
2071
|
createElementVNode("button", {
|
|
2031
2072
|
type: "button",
|
|
2032
2073
|
class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors",
|
|
2033
2074
|
"aria-label": unref(t)("common.close"),
|
|
2034
2075
|
"data-testid": "collections-detail-close",
|
|
2035
2076
|
onClick: _cache[3] || (_cache[3] = ($event) => emit("close"))
|
|
2036
|
-
}, [..._cache[
|
|
2077
|
+
}, [..._cache[8] || (_cache[8] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_9$4)
|
|
2037
2078
|
]))]),
|
|
2038
2079
|
!editing.value && __props.actionError ? (openBlock(), createElementBlock("p", _hoisted_10$4, toDisplayString(__props.actionError), 1)) : createCommentVNode("", true),
|
|
2039
2080
|
createElementVNode("div", _hoisted_11$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.collection.schema.fields, (field, key) => {
|
|
@@ -2083,7 +2124,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2083
2124
|
key: subKey,
|
|
2084
2125
|
class: "text-left px-3 py-2 font-bold"
|
|
2085
2126
|
}, toDisplayString(subField.label), 1);
|
|
2086
|
-
}), 128)), _cache[
|
|
2127
|
+
}), 128)), _cache[9] || (_cache[9] = createElementVNode("th", { class: "w-9" }, null, -1))])]), createElementVNode("tbody", _hoisted_26$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(editing.value.table[key], (row, rowIdx) => {
|
|
2087
2128
|
return openBlock(), createElementBlock("tr", {
|
|
2088
2129
|
key: rowIdx,
|
|
2089
2130
|
class: "hover:bg-slate-50/50"
|
|
@@ -2127,6 +2168,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2127
2168
|
key: 4,
|
|
2128
2169
|
"onUpdate:modelValue": ($event) => row.text[subKey] = $event,
|
|
2129
2170
|
type: __props.render.inputTypeFor(subField.type),
|
|
2171
|
+
step: __props.render.stepFor(subField.type),
|
|
2130
2172
|
required: subField.required,
|
|
2131
2173
|
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"
|
|
2132
2174
|
}, null, 8, _hoisted_37$1)), [[vModelDynamic, row.text[subKey]]])]);
|
|
@@ -2136,13 +2178,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2136
2178
|
"aria-label": unref(t)("collectionsView.removeRow"),
|
|
2137
2179
|
"data-testid": `collections-table-${key}-remove-${rowIdx}`,
|
|
2138
2180
|
onClick: ($event) => removeTableRow(String(key), rowIdx)
|
|
2139
|
-
}, [..._cache[
|
|
2181
|
+
}, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_39$1)])]);
|
|
2140
2182
|
}), 128))])])])) : (openBlock(), createElementBlock("p", _hoisted_40$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)), createElementVNode("button", {
|
|
2141
2183
|
type: "button",
|
|
2142
2184
|
class: "inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-800 font-bold hover:underline",
|
|
2143
2185
|
"data-testid": `collections-table-${key}-add`,
|
|
2144
2186
|
onClick: ($event) => addTableRow(String(key), field.of)
|
|
2145
|
-
}, [_cache[
|
|
2187
|
+
}, [_cache[11] || (_cache[11] = createElementVNode("span", { class: "material-icons text-xs" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addRow")), 1)], 8, _hoisted_41$1)], 8, _hoisted_22$2)) : field.type === "money" ? (openBlock(), createElementBlock("div", _hoisted_42$1, [createElementVNode("div", _hoisted_43$1, toDisplayString(__props.render.currencySymbol(__props.render.resolveCurrency(field, __props.liveRecord))), 1), withDirectives(createElementVNode("input", {
|
|
2146
2188
|
id: `collections-field-${key}`,
|
|
2147
2189
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2148
2190
|
type: "number",
|
|
@@ -2164,6 +2206,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2164
2206
|
id: `collections-field-${key}`,
|
|
2165
2207
|
"onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
|
|
2166
2208
|
type: __props.render.inputTypeFor(field.type),
|
|
2209
|
+
step: __props.render.stepFor(field.type),
|
|
2167
2210
|
required: isFieldRequiredInUi(field),
|
|
2168
2211
|
disabled: field.primary === true && (editing.value.mode === "edit" || __props.isSingleton),
|
|
2169
2212
|
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",
|
|
@@ -2180,7 +2223,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2180
2223
|
key: 1,
|
|
2181
2224
|
class: "text-xs font-medium text-slate-700 break-words",
|
|
2182
2225
|
"data-testid": `collections-detail-value-${key}`
|
|
2183
|
-
}, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span", _hoisted_48$1, [_cache[
|
|
2226
|
+
}, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span", _hoisted_48$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_49$1, toDisplayString(unref(t)("common.no")), 1))], 64)) : field.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [detailRecord.value[key] === true ? (openBlock(), createElementBlock("span", _hoisted_50$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_51$1, toDisplayString(unref(t)("common.no")), 1)) : (openBlock(), createElementBlock("span", _hoisted_52$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("a", {
|
|
2184
2227
|
key: 2,
|
|
2185
2228
|
href: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])),
|
|
2186
2229
|
tabindex: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
|
|
@@ -2238,7 +2281,22 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
|
|
|
2238
2281
|
"data-testid": `collections-detail-file-${key}`,
|
|
2239
2282
|
onClick: ($event) => unref(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
|
|
2240
2283
|
}, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_67$1)) : (openBlock(), createElementBlock("span", _hoisted_68$1, toDisplayString(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_47$1))], 2)) : createCommentVNode("", true)], 64);
|
|
2241
|
-
}), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_69$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)])
|
|
2284
|
+
}), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_69$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)]),
|
|
2285
|
+
!editing.value ? (openBlock(), createElementBlock("div", _hoisted_70$1, [createElementVNode("label", _hoisted_71$1, toDisplayString(unref(t)("collectionsView.itemChatLabel")), 1), createElementVNode("div", _hoisted_72$1, [withDirectives(createElementVNode("textarea", {
|
|
2286
|
+
id: "collections-detail-chat-input",
|
|
2287
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
|
|
2288
|
+
rows: "2",
|
|
2289
|
+
placeholder: unref(t)("collectionsView.itemChatPlaceholder"),
|
|
2290
|
+
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",
|
|
2291
|
+
"data-testid": "collections-detail-chat-input",
|
|
2292
|
+
onKeydown: [withKeys(withModifiers(submitItemChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitItemChat, ["ctrl"]), ["enter"])]
|
|
2293
|
+
}, null, 40, _hoisted_73$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
|
|
2294
|
+
type: "button",
|
|
2295
|
+
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",
|
|
2296
|
+
disabled: !chatMessage.value.trim(),
|
|
2297
|
+
"data-testid": "collections-detail-chat-send",
|
|
2298
|
+
onClick: submitItemChat
|
|
2299
|
+
}, [_cache[14] || (_cache[14] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)], 8, _hoisted_74$1)])])) : createCommentVNode("", true)
|
|
2242
2300
|
]),
|
|
2243
2301
|
_: 1
|
|
2244
2302
|
}, 40, ["data-testid"]);
|
|
@@ -2376,12 +2434,15 @@ var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /* @__PUR
|
|
|
2376
2434
|
slug: {},
|
|
2377
2435
|
view: {}
|
|
2378
2436
|
},
|
|
2379
|
-
|
|
2437
|
+
emits: ["openItem", "startChat"],
|
|
2438
|
+
setup(__props, { emit: __emit }) {
|
|
2380
2439
|
const { t } = useCollectionI18n();
|
|
2381
2440
|
const props = __props;
|
|
2441
|
+
const emit = __emit;
|
|
2382
2442
|
const loading = ref(true);
|
|
2383
2443
|
const error = ref(null);
|
|
2384
2444
|
const srcdoc = ref(null);
|
|
2445
|
+
const iframeEl = ref(null);
|
|
2385
2446
|
let refreshTimer;
|
|
2386
2447
|
function clearRefresh() {
|
|
2387
2448
|
if (refreshTimer !== void 0) {
|
|
@@ -2430,9 +2491,53 @@ var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /* @__PUR
|
|
|
2430
2491
|
}
|
|
2431
2492
|
}
|
|
2432
2493
|
watch([() => props.slug, () => props.view.id], () => void load(), { immediate: true });
|
|
2433
|
-
|
|
2494
|
+
let changeUnsub = null;
|
|
2495
|
+
function relayChange() {
|
|
2496
|
+
iframeEl.value?.contentWindow?.postMessage({
|
|
2497
|
+
type: "mc-collection-changed",
|
|
2498
|
+
slug: props.slug
|
|
2499
|
+
}, "*");
|
|
2500
|
+
}
|
|
2501
|
+
watch(() => props.slug, (slug) => {
|
|
2502
|
+
changeUnsub?.();
|
|
2503
|
+
changeUnsub = null;
|
|
2504
|
+
const subscribe = collectionUi().subscribeChanges;
|
|
2505
|
+
if (slug && subscribe) changeUnsub = subscribe(slug, relayChange);
|
|
2506
|
+
}, { immediate: true });
|
|
2507
|
+
function handleOpenItem(body) {
|
|
2508
|
+
const itemId = typeof body.id === "string" ? body.id : String(body.id ?? "");
|
|
2509
|
+
if (!itemId) return;
|
|
2510
|
+
emit("openItem", {
|
|
2511
|
+
id: itemId,
|
|
2512
|
+
mode: body.mode === "edit" ? "edit" : "view"
|
|
2513
|
+
});
|
|
2514
|
+
}
|
|
2515
|
+
function handleStartChat(body) {
|
|
2516
|
+
const prompt = typeof body.prompt === "string" ? body.prompt.trim() : "";
|
|
2517
|
+
if (!prompt) return;
|
|
2518
|
+
emit("startChat", {
|
|
2519
|
+
prompt,
|
|
2520
|
+
role: typeof body.role === "string" ? body.role : void 0
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
function onWindowMessage(event) {
|
|
2524
|
+
if (event.source !== iframeEl.value?.contentWindow) return;
|
|
2525
|
+
const msg = event.data;
|
|
2526
|
+
if (!msg || msg.slug !== props.slug) return;
|
|
2527
|
+
if (msg.type === "mc-open-item") handleOpenItem(msg);
|
|
2528
|
+
else if (msg.type === "mc-start-chat") handleStartChat(msg);
|
|
2529
|
+
}
|
|
2530
|
+
onMounted(() => window.addEventListener("message", onWindowMessage));
|
|
2531
|
+
onBeforeUnmount(() => {
|
|
2532
|
+
clearRefresh();
|
|
2533
|
+
changeUnsub?.();
|
|
2534
|
+
changeUnsub = null;
|
|
2535
|
+
window.removeEventListener("message", onWindowMessage);
|
|
2536
|
+
});
|
|
2434
2537
|
return (_ctx, _cache) => {
|
|
2435
2538
|
return openBlock(), createElementBlock("div", _hoisted_1$5, [error.value ? (openBlock(), createElementBlock("div", _hoisted_2$4, toDisplayString(unref(t)("collectionsView.customViewError", { error: error.value })), 1)) : loading.value ? (openBlock(), createElementBlock("div", _hoisted_3$4, toDisplayString(unref(t)("collectionsView.customViewLoading")), 1)) : srcdoc.value ? (openBlock(), createElementBlock("iframe", {
|
|
2539
|
+
ref_key: "iframeEl",
|
|
2540
|
+
ref: iframeEl,
|
|
2436
2541
|
key: __props.view.id,
|
|
2437
2542
|
"data-testid": "collection-custom-view-iframe",
|
|
2438
2543
|
title: __props.view.label,
|
|
@@ -2452,9 +2557,13 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
|
|
|
2452
2557
|
};
|
|
2453
2558
|
//#endregion
|
|
2454
2559
|
//#region src/vue/components/CollectionCustomView.vue
|
|
2455
|
-
var CollectionCustomView_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
2560
|
+
var CollectionCustomView_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d5fb7ca6"]]);
|
|
2456
2561
|
//#endregion
|
|
2457
2562
|
//#region src/vue/useCollectionRendering.ts
|
|
2563
|
+
function stepForFieldType(type) {
|
|
2564
|
+
if (type === "money") return "0.01";
|
|
2565
|
+
if (type === "number") return "any";
|
|
2566
|
+
}
|
|
2458
2567
|
function useCollectionRendering(collection, locale) {
|
|
2459
2568
|
const refCache = ref({});
|
|
2460
2569
|
const refRecordCache = ref({});
|
|
@@ -2669,6 +2778,7 @@ function useCollectionRendering(collection, locale) {
|
|
|
2669
2778
|
if (type === "datetime") return "datetime-local";
|
|
2670
2779
|
return "text";
|
|
2671
2780
|
}
|
|
2781
|
+
const stepFor = stepForFieldType;
|
|
2672
2782
|
function evaluateDerivedAgainstItem(field, fieldKey, item) {
|
|
2673
2783
|
if (!field.formula || !collection.value) return null;
|
|
2674
2784
|
const result = deriveAll(collection.value.schema, item, refRecordCache.value)[fieldKey];
|
|
@@ -2700,6 +2810,7 @@ function useCollectionRendering(collection, locale) {
|
|
|
2700
2810
|
hasTableRows,
|
|
2701
2811
|
formatSubCell,
|
|
2702
2812
|
inputTypeFor,
|
|
2813
|
+
stepFor,
|
|
2703
2814
|
deriveAll,
|
|
2704
2815
|
evaluateDerivedAgainstItem,
|
|
2705
2816
|
derivedDisplay
|
|
@@ -2982,6 +3093,17 @@ var _hoisted_83 = { class: "px-6 py-5" };
|
|
|
2982
3093
|
var _hoisted_84 = ["placeholder", "onKeydown"];
|
|
2983
3094
|
var _hoisted_85 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
|
|
2984
3095
|
var _hoisted_86 = ["disabled"];
|
|
3096
|
+
/** `slug` / `selected` are supplied only in EMBEDDED mode (the
|
|
3097
|
+
* `presentCollection` chat card mounts this component and drives both
|
|
3098
|
+
* from the tool result). In standalone route mode (the
|
|
3099
|
+
* `/collections/:slug` page) both are undefined and the component reads
|
|
3100
|
+
* `route.params.slug` / `route.query.selected` as before.
|
|
3101
|
+
*
|
|
3102
|
+
* `sendTextMessage` is forwarded ONLY by the chat card — its presence
|
|
3103
|
+
* is our "rendered inside a chat" signal. When set, chat-triggering
|
|
3104
|
+
* actions send into the current session instead of spawning a new
|
|
3105
|
+
* chat (see `runAction` / `submitChat`). */
|
|
3106
|
+
var LIVE_REFRESH_DEBOUNCE_MS = 150;
|
|
2985
3107
|
//#endregion
|
|
2986
3108
|
//#region src/vue/components/CollectionView.vue
|
|
2987
3109
|
var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
@@ -3304,13 +3426,13 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3304
3426
|
* nothing. Instead, point the agent at the feed's schema + records
|
|
3305
3427
|
* (`feeds/<slug>/schema.json` and `<dataPath>/`) and let it act on the
|
|
3306
3428
|
* request directly. */
|
|
3307
|
-
function buildChatSeed(slug, message) {
|
|
3429
|
+
function buildChatSeed(slug, message, itemId) {
|
|
3308
3430
|
const schema = collection.value?.schema;
|
|
3309
|
-
if (!schema?.ingest) return `/${slug} ${message}`;
|
|
3431
|
+
if (!schema?.ingest) return itemId ? `/${slug} id=${itemId} ${message}` : `/${slug} ${message}`;
|
|
3310
3432
|
return t("collectionsView.feedChatSeed", {
|
|
3311
3433
|
slug,
|
|
3312
3434
|
dataPath: schema.dataPath ?? `data/feeds/${slug}`,
|
|
3313
|
-
message
|
|
3435
|
+
message: itemId ? `(for record \`${itemId}\`) ${message}` : message
|
|
3314
3436
|
});
|
|
3315
3437
|
}
|
|
3316
3438
|
/** Start a new general-role chat seeded from the current view. */
|
|
@@ -3326,6 +3448,21 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3326
3448
|
}
|
|
3327
3449
|
appApi.startNewChat(text, cui.generalRoleId);
|
|
3328
3450
|
}
|
|
3451
|
+
/** The open record's chat box: start a chat scoped to that one record. Seeds
|
|
3452
|
+
* the collection's skill command with an `id=<itemId>` selector
|
|
3453
|
+
* (`/<slug> id=<itemId> <message>`) so the agent acts on this record. */
|
|
3454
|
+
function onItemChat(message) {
|
|
3455
|
+
if (!collection.value || !viewing.value) return;
|
|
3456
|
+
const text = message.trim();
|
|
3457
|
+
if (!text) return;
|
|
3458
|
+
const itemId = String(viewing.value[collection.value.schema.primaryKey] ?? "");
|
|
3459
|
+
const seed = buildChatSeed(collection.value.slug, text, itemId || void 0);
|
|
3460
|
+
if (props.sendTextMessage) {
|
|
3461
|
+
props.sendTextMessage(seed);
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3464
|
+
appApi.startNewChat(seed, cui.generalRoleId);
|
|
3465
|
+
}
|
|
3329
3466
|
async function loadCollection(slug) {
|
|
3330
3467
|
const requestedKind = !embedded.value && cui.isFeedRoute() ? "feed" : "collection";
|
|
3331
3468
|
loading.value = true;
|
|
@@ -3355,6 +3492,26 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3355
3492
|
}
|
|
3356
3493
|
maybeAutoRefreshFeed(slug);
|
|
3357
3494
|
}
|
|
3495
|
+
/** Refresh records + schema IN PLACE for a live (pub/sub-driven) update,
|
|
3496
|
+
* preserving the user's browsing state — unlike `loadCollection`, which is the
|
|
3497
|
+
* route-change path and resets it. Specifically: does NOT null `collection`
|
|
3498
|
+
* (so the layout and an active custom-view iframe don't remount), keeps
|
|
3499
|
+
* `searchQuery` / `openDay` / `sortState`, and shows no loading spinner; the
|
|
3500
|
+
* open detail (`viewing`) is re-resolved against the fresh records by id, so it
|
|
3501
|
+
* follows an edited record and closes only if the record was deleted. A failed
|
|
3502
|
+
* fetch is a no-op (keep the current data) — a transient blip shouldn't blank a
|
|
3503
|
+
* view the user is reading. */
|
|
3504
|
+
async function refreshItemsInPlace(slug) {
|
|
3505
|
+
const result = await cui.fetchCollectionDetail(slug);
|
|
3506
|
+
if (!result.ok || activeSlug.value !== slug) return;
|
|
3507
|
+
collection.value = result.data.collection;
|
|
3508
|
+
items.value = result.data.items;
|
|
3509
|
+
dataIssues.value = result.data.issues ?? [];
|
|
3510
|
+
enumOriginallyEmpty.value = snapshotEmptyEnums(result.data.collection.schema, result.data.items);
|
|
3511
|
+
await render.loadLinkedCollections(result.data.collection.schema, slug);
|
|
3512
|
+
if (activeSlug.value !== slug) return;
|
|
3513
|
+
if (viewing.value) viewing.value = findItemById(String(viewing.value[result.data.collection.schema.primaryKey] ?? "")) ?? null;
|
|
3514
|
+
}
|
|
3358
3515
|
function maybeAutoRefreshFeed(slug) {
|
|
3359
3516
|
if (embedded.value) return;
|
|
3360
3517
|
const current = collection.value;
|
|
@@ -3870,6 +4027,30 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3870
4027
|
showDetail(item);
|
|
3871
4028
|
writeSelectedToUrl(itemId);
|
|
3872
4029
|
}
|
|
4030
|
+
/** A custom (sandboxed) view asked to open a record in the shared modal.
|
|
4031
|
+
* `view` → read-only detail, `edit` → straight into the editor. Ungated: the
|
|
4032
|
+
* capability token governs the view's *code*, not user actions through the
|
|
4033
|
+
* host's own trusted modal (no write happens without an explicit Save). */
|
|
4034
|
+
function onCustomViewOpenItem(payload) {
|
|
4035
|
+
const item = findItemById(payload.id);
|
|
4036
|
+
if (!item) return;
|
|
4037
|
+
if (editing.value) closeEditor();
|
|
4038
|
+
if (payload.mode === "edit") {
|
|
4039
|
+
openEdit(item);
|
|
4040
|
+
return;
|
|
4041
|
+
}
|
|
4042
|
+
showDetail(item);
|
|
4043
|
+
writeSelectedToUrl(payload.id);
|
|
4044
|
+
}
|
|
4045
|
+
/** The custom view called `__MC_VIEW.startChat(prompt, role)` — open a new chat
|
|
4046
|
+
* with the prompt prefilled as an editable draft. The host validates `role`
|
|
4047
|
+
* (falls back to General). The view's code only proposes text; the user
|
|
4048
|
+
* approves / edits / sends, so no capability is required. */
|
|
4049
|
+
function onCustomViewStartChat(payload) {
|
|
4050
|
+
const prompt = payload.prompt.trim();
|
|
4051
|
+
if (!prompt) return;
|
|
4052
|
+
cui.startNewChatDraft(prompt, payload.role);
|
|
4053
|
+
}
|
|
3873
4054
|
/** A calendar day cell was activated → open its popup on a clean slate
|
|
3874
4055
|
* (clear any prior selection so the popup opens timeline-only). */
|
|
3875
4056
|
function onOpenDay(day) {
|
|
@@ -3925,6 +4106,42 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
3925
4106
|
loading.value = false;
|
|
3926
4107
|
}
|
|
3927
4108
|
}, { immediate: true });
|
|
4109
|
+
let changeUnsub = null;
|
|
4110
|
+
let liveRefreshTimer;
|
|
4111
|
+
let pendingRemoteRefresh = false;
|
|
4112
|
+
function clearLiveRefreshTimer() {
|
|
4113
|
+
if (liveRefreshTimer !== void 0) {
|
|
4114
|
+
clearTimeout(liveRefreshTimer);
|
|
4115
|
+
liveRefreshTimer = void 0;
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
function onRemoteChange(slug) {
|
|
4119
|
+
clearLiveRefreshTimer();
|
|
4120
|
+
liveRefreshTimer = setTimeout(() => {
|
|
4121
|
+
liveRefreshTimer = void 0;
|
|
4122
|
+
if (editing.value) {
|
|
4123
|
+
pendingRemoteRefresh = true;
|
|
4124
|
+
return;
|
|
4125
|
+
}
|
|
4126
|
+
if (activeSlug.value === slug) refreshItemsInPlace(slug);
|
|
4127
|
+
}, LIVE_REFRESH_DEBOUNCE_MS);
|
|
4128
|
+
}
|
|
4129
|
+
watch(editing, (current) => {
|
|
4130
|
+
if (current || !pendingRemoteRefresh) return;
|
|
4131
|
+
pendingRemoteRefresh = false;
|
|
4132
|
+
if (activeSlug.value) refreshItemsInPlace(activeSlug.value);
|
|
4133
|
+
});
|
|
4134
|
+
watch(activeSlug, (slug) => {
|
|
4135
|
+
changeUnsub?.();
|
|
4136
|
+
changeUnsub = null;
|
|
4137
|
+
clearLiveRefreshTimer();
|
|
4138
|
+
if (slug && cui.subscribeChanges) changeUnsub = cui.subscribeChanges(slug, () => onRemoteChange(slug));
|
|
4139
|
+
}, { immediate: true });
|
|
4140
|
+
onUnmounted(() => {
|
|
4141
|
+
changeUnsub?.();
|
|
4142
|
+
changeUnsub = null;
|
|
4143
|
+
clearLiveRefreshTimer();
|
|
4144
|
+
});
|
|
3928
4145
|
watch([
|
|
3929
4146
|
activeView,
|
|
3930
4147
|
calendarAnchorField,
|
|
@@ -4195,7 +4412,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4195
4412
|
onEdit: editFromView,
|
|
4196
4413
|
onClose: onDayClose,
|
|
4197
4414
|
onDelete: _cache[9] || (_cache[9] = ($event) => viewing.value && confirmDelete(viewing.value)),
|
|
4198
|
-
onRunAction: runAction
|
|
4415
|
+
onRunAction: runAction,
|
|
4416
|
+
onItemChat
|
|
4199
4417
|
}, null, 8, [
|
|
4200
4418
|
"editing",
|
|
4201
4419
|
"collection",
|
|
@@ -4249,7 +4467,9 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4249
4467
|
"notified"
|
|
4250
4468
|
])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_45, [createVNode(CollectionCustomView_default, {
|
|
4251
4469
|
slug: collection.value.slug,
|
|
4252
|
-
view: activeCustomView.value
|
|
4470
|
+
view: activeCustomView.value,
|
|
4471
|
+
onOpenItem: onCustomViewOpenItem,
|
|
4472
|
+
onStartChat: onCustomViewStartChat
|
|
4253
4473
|
}, null, 8, ["slug", "view"])])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_46, [_cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_47, toDisplayString(unref(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_48, [
|
|
4254
4474
|
_cache[42] || (_cache[42] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
|
|
4255
4475
|
createElementVNode("p", _hoisted_49, toDisplayString(unref(t)("collectionsView.noMatchingItems")), 1),
|
|
@@ -4391,7 +4611,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
|
|
|
4391
4611
|
onEdit: editFromView,
|
|
4392
4612
|
onClose: closeView,
|
|
4393
4613
|
onDelete: _cache[20] || (_cache[20] = ($event) => viewing.value && confirmDelete(viewing.value)),
|
|
4394
|
-
onRunAction: runAction
|
|
4614
|
+
onRunAction: runAction,
|
|
4615
|
+
onItemChat
|
|
4395
4616
|
}, null, 8, [
|
|
4396
4617
|
"editing",
|
|
4397
4618
|
"collection",
|