@mulmoclaude/collection-plugin 0.5.16 → 0.5.18

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/vue.js CHANGED
@@ -1880,82 +1880,90 @@ var _hoisted_13$4 = {
1880
1880
  key: 0,
1881
1881
  class: "text-rose-500 font-bold"
1882
1882
  };
1883
- var _hoisted_14$4 = {
1883
+ var _hoisted_14$4 = [
1884
+ "id",
1885
+ "onUpdate:modelValue",
1886
+ "required",
1887
+ "data-testid"
1888
+ ];
1889
+ var _hoisted_15$4 = { value: "" };
1890
+ var _hoisted_16$4 = ["value"];
1891
+ var _hoisted_17$4 = {
1884
1892
  key: 0,
1885
1893
  class: "inline-flex items-center gap-2.5 text-sm text-slate-700 cursor-pointer select-none"
1886
1894
  };
1887
- var _hoisted_15$4 = [
1895
+ var _hoisted_18$4 = [
1888
1896
  "id",
1889
1897
  "onUpdate:modelValue",
1890
1898
  "data-testid",
1891
1899
  "onChange"
1892
1900
  ];
1893
- var _hoisted_16$4 = [
1901
+ var _hoisted_19$3 = [
1894
1902
  "id",
1895
1903
  "onUpdate:modelValue",
1896
1904
  "required",
1897
1905
  "data-testid"
1898
1906
  ];
1899
- var _hoisted_17$4 = { value: "" };
1900
- var _hoisted_18$4 = ["value"];
1901
- var _hoisted_19$3 = [
1907
+ var _hoisted_20$3 = { value: "" };
1908
+ var _hoisted_21$3 = ["value"];
1909
+ var _hoisted_22$3 = [
1902
1910
  "id",
1903
1911
  "onUpdate:modelValue",
1904
1912
  "required",
1905
1913
  "data-testid"
1906
1914
  ];
1907
- var _hoisted_20$3 = { value: "" };
1908
- var _hoisted_21$3 = ["value"];
1909
- var _hoisted_22$3 = ["data-testid"];
1910
- var _hoisted_23$3 = {
1915
+ var _hoisted_23$3 = { value: "" };
1916
+ var _hoisted_24$2 = ["value"];
1917
+ var _hoisted_25$2 = ["data-testid"];
1918
+ var _hoisted_26$2 = {
1911
1919
  key: 0,
1912
1920
  class: "overflow-hidden border border-slate-200 rounded-lg shadow-sm"
1913
1921
  };
1914
- var _hoisted_24$2 = { class: "w-full text-xs text-slate-600 bg-white" };
1915
- var _hoisted_25$2 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
1916
- var _hoisted_26$2 = { class: "divide-y divide-slate-100" };
1917
- var _hoisted_27$2 = ["onUpdate:modelValue", "onChange"];
1918
- var _hoisted_28$1 = ["onUpdate:modelValue", "required"];
1919
- var _hoisted_29$1 = { value: "" };
1920
- var _hoisted_30$1 = ["value"];
1922
+ var _hoisted_27$2 = { class: "w-full text-xs text-slate-600 bg-white" };
1923
+ var _hoisted_28$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
1924
+ var _hoisted_29$1 = { class: "divide-y divide-slate-100" };
1925
+ var _hoisted_30$1 = ["onUpdate:modelValue", "onChange"];
1921
1926
  var _hoisted_31$1 = ["onUpdate:modelValue", "required"];
1922
1927
  var _hoisted_32$1 = { value: "" };
1923
1928
  var _hoisted_33$1 = ["value"];
1924
- var _hoisted_34$1 = {
1929
+ var _hoisted_34$1 = ["onUpdate:modelValue", "required"];
1930
+ var _hoisted_35$1 = { value: "" };
1931
+ var _hoisted_36$1 = ["value"];
1932
+ var _hoisted_37$1 = {
1925
1933
  key: 3,
1926
1934
  class: "relative flex items-center"
1927
1935
  };
1928
- var _hoisted_35$1 = { class: "absolute left-1.5 text-[10px] text-slate-400 font-bold pr-1 border-r border-slate-200" };
1929
- var _hoisted_36$1 = ["onUpdate:modelValue", "required"];
1930
- var _hoisted_37$1 = [
1936
+ var _hoisted_38$1 = { class: "absolute left-1.5 text-[10px] text-slate-400 font-bold pr-1 border-r border-slate-200" };
1937
+ var _hoisted_39$1 = ["onUpdate:modelValue", "required"];
1938
+ var _hoisted_40$1 = [
1931
1939
  "onUpdate:modelValue",
1932
1940
  "type",
1933
1941
  "step",
1934
1942
  "required"
1935
1943
  ];
1936
- var _hoisted_38$1 = { class: "text-center px-1" };
1937
- var _hoisted_39$1 = [
1944
+ var _hoisted_41$1 = { class: "text-center px-1" };
1945
+ var _hoisted_42$1 = [
1938
1946
  "aria-label",
1939
1947
  "data-testid",
1940
1948
  "onClick"
1941
1949
  ];
1942
- var _hoisted_40$1 = {
1950
+ var _hoisted_43$1 = {
1943
1951
  key: 1,
1944
1952
  class: "text-xs text-slate-400 italic"
1945
1953
  };
1946
- var _hoisted_41$1 = ["data-testid", "onClick"];
1947
- var _hoisted_42$1 = {
1954
+ var _hoisted_44$1 = ["data-testid", "onClick"];
1955
+ var _hoisted_45$1 = {
1948
1956
  key: 4,
1949
1957
  class: "relative flex items-center"
1950
1958
  };
1951
- var _hoisted_43$1 = { class: "absolute left-3 text-slate-400 font-bold text-xs select-none pr-1.5 border-r border-slate-200" };
1952
- var _hoisted_44$1 = [
1959
+ var _hoisted_46$1 = { class: "absolute left-3 text-slate-400 font-bold text-xs select-none pr-1.5 border-r border-slate-200" };
1960
+ var _hoisted_47$1 = [
1953
1961
  "id",
1954
1962
  "onUpdate:modelValue",
1955
1963
  "required",
1956
1964
  "data-testid"
1957
1965
  ];
1958
- var _hoisted_45$1 = [
1966
+ var _hoisted_48$1 = [
1959
1967
  "id",
1960
1968
  "onUpdate:modelValue",
1961
1969
  "type",
@@ -1964,104 +1972,104 @@ var _hoisted_45$1 = [
1964
1972
  "disabled",
1965
1973
  "data-testid"
1966
1974
  ];
1967
- var _hoisted_46$1 = [
1975
+ var _hoisted_49$1 = [
1968
1976
  "id",
1969
1977
  "onUpdate:modelValue",
1970
1978
  "rows",
1971
1979
  "required",
1972
1980
  "data-testid"
1973
1981
  ];
1974
- var _hoisted_47$1 = ["data-testid"];
1975
- var _hoisted_48$1 = {
1982
+ var _hoisted_50$1 = ["data-testid"];
1983
+ var _hoisted_51$1 = {
1976
1984
  key: 0,
1977
1985
  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"
1978
1986
  };
1979
- var _hoisted_49$1 = {
1987
+ var _hoisted_52$1 = {
1980
1988
  key: 1,
1981
1989
  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"
1982
1990
  };
1983
- var _hoisted_50$1 = {
1991
+ var _hoisted_53$1 = {
1984
1992
  key: 0,
1985
1993
  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"
1986
1994
  };
1987
- var _hoisted_51$1 = {
1995
+ var _hoisted_54$1 = {
1988
1996
  key: 1,
1989
1997
  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"
1990
1998
  };
1991
- var _hoisted_52$1 = {
1999
+ var _hoisted_55$1 = {
1992
2000
  key: 2,
1993
2001
  class: "text-slate-300"
1994
2002
  };
1995
- var _hoisted_53$1 = [
2003
+ var _hoisted_56$1 = [
1996
2004
  "href",
1997
2005
  "tabindex",
1998
2006
  "data-testid",
1999
2007
  "onClick",
2000
2008
  "onKeydown"
2001
2009
  ];
2002
- var _hoisted_54$1 = {
2010
+ var _hoisted_57$1 = {
2003
2011
  key: 3,
2004
2012
  class: "font-semibold text-slate-900 tabular-nums text-sm"
2005
2013
  };
2006
- var _hoisted_55$1 = {
2014
+ var _hoisted_58$1 = {
2007
2015
  key: 4,
2008
2016
  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"
2009
2017
  };
2010
- var _hoisted_56$1 = {
2018
+ var _hoisted_59$1 = {
2011
2019
  key: 5,
2012
2020
  class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
2013
2021
  };
2014
- var _hoisted_57$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
2015
- var _hoisted_58$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
2016
- var _hoisted_59$1 = { class: "divide-y divide-slate-100" };
2017
- var _hoisted_60$1 = {
2022
+ var _hoisted_60$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
2023
+ var _hoisted_61$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
2024
+ var _hoisted_62$1 = { class: "divide-y divide-slate-100" };
2025
+ var _hoisted_63$1 = {
2018
2026
  key: 0,
2019
2027
  class: "material-icons text-emerald-600 text-base"
2020
2028
  };
2021
- var _hoisted_61$1 = {
2029
+ var _hoisted_64$1 = {
2022
2030
  key: 1,
2023
2031
  class: "text-slate-300"
2024
2032
  };
2025
- var _hoisted_62$1 = {
2033
+ var _hoisted_65$1 = {
2026
2034
  key: 6,
2027
2035
  class: "text-slate-400 italic"
2028
2036
  };
2029
- var _hoisted_63$1 = {
2037
+ var _hoisted_66$1 = {
2030
2038
  key: 7,
2031
2039
  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"
2032
2040
  };
2033
- var _hoisted_64$1 = [
2041
+ var _hoisted_67$1 = [
2034
2042
  "src",
2035
2043
  "alt",
2036
2044
  "data-testid"
2037
2045
  ];
2038
- var _hoisted_65$1 = ["href", "data-testid"];
2039
- var _hoisted_66$1 = ["href", "data-testid"];
2040
- var _hoisted_67$1 = [
2046
+ var _hoisted_68$1 = ["href", "data-testid"];
2047
+ var _hoisted_69$1 = ["href", "data-testid"];
2048
+ var _hoisted_70$1 = [
2041
2049
  "href",
2042
2050
  "data-testid",
2043
2051
  "onClick"
2044
2052
  ];
2045
- var _hoisted_68$1 = {
2053
+ var _hoisted_71$1 = {
2046
2054
  key: 13,
2047
2055
  class: "text-slate-800 font-semibold"
2048
2056
  };
2049
- var _hoisted_69$1 = {
2057
+ var _hoisted_72$1 = {
2050
2058
  key: 0,
2051
2059
  class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
2052
2060
  };
2053
- var _hoisted_70$1 = {
2061
+ var _hoisted_73$1 = {
2054
2062
  key: 1,
2055
2063
  class: "mt-5 pt-4 border-t border-slate-200/60",
2056
2064
  "data-testid": "collections-detail-chat"
2057
2065
  };
2058
- var _hoisted_71$1 = {
2066
+ var _hoisted_74$1 = {
2059
2067
  class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
2060
2068
  for: "collections-detail-chat-input"
2061
2069
  };
2062
- var _hoisted_72$1 = { class: "flex items-end gap-2" };
2063
- var _hoisted_73$1 = ["placeholder", "onKeydown"];
2064
- var _hoisted_74$1 = ["disabled"];
2070
+ var _hoisted_75$1 = { class: "flex items-end gap-2" };
2071
+ var _hoisted_76$1 = ["placeholder", "onKeydown"];
2072
+ var _hoisted_77$1 = ["disabled"];
2065
2073
  //#endregion
2066
2074
  //#region src/vue/components/CollectionRecordPanel.vue
2067
2075
  var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
@@ -2110,12 +2118,17 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2110
2118
  emit("itemChat", message);
2111
2119
  chatMessage.value = "";
2112
2120
  }
2113
- const embedViews = computed(() => props.render.embedViews.value);
2114
2121
  /** The record the read-only displays render from: the live draft while
2115
2122
  * editing (so non-editable cells like derived/embed preview the in-flight
2116
2123
  * values), else the open record. Always an object so `[key]` lookups are
2117
2124
  * safe in the template. */
2118
2125
  const detailRecord = computed(() => editing.value ? props.liveDerived ?? props.liveRecord ?? {} : props.viewing ?? {});
2126
+ const embedViews = computed(() => props.render.embedViewsFor(detailRecord.value));
2127
+ const embedOwnedKeys = computed(() => {
2128
+ const keys = /* @__PURE__ */ new Set();
2129
+ for (const field of Object.values(props.collection.schema.fields)) if (field.type === "embed" && field.idField) keys.add(field.idField);
2130
+ return keys;
2131
+ });
2119
2132
  /** Title for the header: the create label, the edited record's id, or the
2120
2133
  * open record's title — same h2 slot in every mode. */
2121
2134
  const headerTitle = computed(() => {
@@ -2148,8 +2161,9 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2148
2161
  * cell appears or disappears on toggle: respect the `when` predicate
2149
2162
  * (against the active record) and hide the primary key except while
2150
2163
  * creating. */
2151
- function cellVisible(field) {
2164
+ function cellVisible(field, key) {
2152
2165
  if (field.primary && editing.value?.mode !== "create") return false;
2166
+ if (embedOwnedKeys.value.has(key)) return false;
2153
2167
  return fieldVisible(field, detailRecord.value);
2154
2168
  }
2155
2169
  /** Mirror of the create-mode primary-key carve-out: drop the HTML5
@@ -2160,6 +2174,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2160
2174
  if (editing.value?.mode === "create" && field.primary === true) return false;
2161
2175
  return true;
2162
2176
  }
2177
+ /** Required flag for an embed's per-record picker — read off the storage
2178
+ * field it writes (`idField`), since the embed itself stores nothing. */
2179
+ function embedPickerRequired(field) {
2180
+ const target = field.idField ? props.collection.schema.fields[field.idField] : void 0;
2181
+ return target ? isFieldRequiredInUi(target) : false;
2182
+ }
2163
2183
  /** Tailwind fill/text/border classes tinting an enum `<select>` by its current
2164
2184
  * value's colour (palette, or notification red/amber/grey when the field is
2165
2185
  * the schema's notifyWhen target). */
@@ -2237,53 +2257,65 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2237
2257
  ]))]),
2238
2258
  !editing.value && __props.actionError ? (openBlock(), createElementBlock("p", _hoisted_10$5, toDisplayString(__props.actionError), 1)) : createCommentVNode("", true),
2239
2259
  createElementVNode("div", _hoisted_11$5, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.collection.schema.fields, (field, key) => {
2240
- return openBlock(), createElementBlock(Fragment, { key }, [cellVisible(field) ? (openBlock(), createElementBlock("div", {
2260
+ return openBlock(), createElementBlock(Fragment, { key }, [cellVisible(field, String(key)) ? (openBlock(), createElementBlock("div", {
2241
2261
  key: 0,
2242
2262
  class: normalizeClass(["flex flex-col gap-1.5", colSpanClass(field)])
2243
2263
  }, [createElementVNode("label", {
2244
2264
  class: "text-[10px] font-bold text-slate-400 uppercase tracking-wider flex items-center gap-1",
2245
2265
  for: `collections-field-${key}`
2246
- }, [createTextVNode(toDisplayString(field.label) + " ", 1), editing.value && field.required ? (openBlock(), createElementBlock("span", _hoisted_13$4, "*")) : createCommentVNode("", true)], 8, _hoisted_12$5), editing.value && isEditableType(field.type) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.type === "boolean" ? (openBlock(), createElementBlock("label", _hoisted_14$4, [withDirectives(createElementVNode("input", {
2266
+ }, [createTextVNode(toDisplayString(field.label) + " ", 1), editing.value && field.required ? (openBlock(), createElementBlock("span", _hoisted_13$4, "*")) : createCommentVNode("", true)], 8, _hoisted_12$5), editing.value && field.type === "embed" && field.idField ? withDirectives((openBlock(), createElementBlock("select", {
2267
+ key: 0,
2268
+ id: `collections-field-${key}`,
2269
+ "onUpdate:modelValue": ($event) => editing.value.text[field.idField] = $event,
2270
+ required: embedPickerRequired(field),
2271
+ 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",
2272
+ "data-testid": `collections-input-${key}`
2273
+ }, [createElementVNode("option", _hoisted_15$4, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.embedOptions(field.to ?? ""), (opt) => {
2274
+ return openBlock(), createElementBlock("option", {
2275
+ key: opt.slug,
2276
+ value: opt.slug
2277
+ }, toDisplayString(opt.display), 9, _hoisted_16$4);
2278
+ }), 128))], 8, _hoisted_14$4)), [[vModelSelect, editing.value.text[field.idField]]]) : editing.value && isEditableType(field.type) ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [field.type === "boolean" ? (openBlock(), createElementBlock("label", _hoisted_17$4, [withDirectives(createElementVNode("input", {
2247
2279
  id: `collections-field-${key}`,
2248
2280
  "onUpdate:modelValue": ($event) => editing.value.bool[key] = $event,
2249
2281
  type: "checkbox",
2250
2282
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
2251
2283
  "data-testid": `collections-input-${key}`,
2252
2284
  onChange: ($event) => markBoolTouched(String(key))
2253
- }, null, 40, _hoisted_15$4), [[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", {
2285
+ }, null, 40, _hoisted_18$4), [[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", {
2254
2286
  key: 1,
2255
2287
  id: `collections-field-${key}`,
2256
2288
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
2257
2289
  required: isFieldRequiredInUi(field),
2258
2290
  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",
2259
2291
  "data-testid": `collections-input-${key}`
2260
- }, [createElementVNode("option", _hoisted_17$4, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(field.to), (opt) => {
2292
+ }, [createElementVNode("option", _hoisted_20$3, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(field.to), (opt) => {
2261
2293
  return openBlock(), createElementBlock("option", {
2262
2294
  key: opt.slug,
2263
2295
  value: opt.slug
2264
- }, toDisplayString(opt.display), 9, _hoisted_18$4);
2265
- }), 128))], 8, _hoisted_16$4)), [[vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2296
+ }, toDisplayString(opt.display), 9, _hoisted_21$3);
2297
+ }), 128))], 8, _hoisted_19$3)), [[vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2266
2298
  key: 2,
2267
2299
  id: `collections-field-${key}`,
2268
2300
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
2269
2301
  required: isFieldRequiredInUi(field),
2270
2302
  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])]),
2271
2303
  "data-testid": `collections-input-${key}`
2272
- }, [createElementVNode("option", _hoisted_20$3, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
2304
+ }, [createElementVNode("option", _hoisted_23$3, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
2273
2305
  return openBlock(), createElementBlock("option", {
2274
2306
  key: value,
2275
2307
  value
2276
- }, toDisplayString(value), 9, _hoisted_21$3);
2277
- }), 128))], 10, _hoisted_19$3)), [[vModelSelect, editing.value.text[key]]]) : field.type === "table" && field.of ? (openBlock(), createElementBlock("div", {
2308
+ }, toDisplayString(value), 9, _hoisted_24$2);
2309
+ }), 128))], 10, _hoisted_22$3)), [[vModelSelect, editing.value.text[key]]]) : field.type === "table" && field.of ? (openBlock(), createElementBlock("div", {
2278
2310
  key: 3,
2279
2311
  class: "border border-slate-200 bg-slate-50/30 rounded-xl p-4 space-y-3",
2280
2312
  "data-testid": `collections-table-${key}`
2281
- }, [editing.value.table[key] && editing.value.table[key].length > 0 ? (openBlock(), createElementBlock("div", _hoisted_23$3, [createElementVNode("table", _hoisted_24$2, [createElementVNode("thead", _hoisted_25$2, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2313
+ }, [editing.value.table[key] && editing.value.table[key].length > 0 ? (openBlock(), createElementBlock("div", _hoisted_26$2, [createElementVNode("table", _hoisted_27$2, [createElementVNode("thead", _hoisted_28$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2282
2314
  return openBlock(), createElementBlock("th", {
2283
2315
  key: subKey,
2284
2316
  class: "text-left px-3 py-2 font-bold"
2285
2317
  }, toDisplayString(subField.label), 1);
2286
- }), 128)), _cache[9] || (_cache[9] = createElementVNode("th", { class: "w-9" }, null, -1))])]), createElementVNode("tbody", _hoisted_26$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(editing.value.table[key], (row, rowIdx) => {
2318
+ }), 128)), _cache[9] || (_cache[9] = createElementVNode("th", { class: "w-9" }, null, -1))])]), createElementVNode("tbody", _hoisted_29$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(editing.value.table[key], (row, rowIdx) => {
2287
2319
  return openBlock(), createElementBlock("tr", {
2288
2320
  key: rowIdx,
2289
2321
  class: "hover:bg-slate-50/50"
@@ -2297,53 +2329,53 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2297
2329
  type: "checkbox",
2298
2330
  class: "h-4 w-4 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
2299
2331
  onChange: ($event) => markRowBoolTouched(row, String(subKey))
2300
- }, null, 40, _hoisted_27$2)), [[vModelCheckbox, row.bool[subKey]]]) : subField.type === "enum" && Array.isArray(subField.values) && subField.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2332
+ }, null, 40, _hoisted_30$1)), [[vModelCheckbox, row.bool[subKey]]]) : subField.type === "enum" && Array.isArray(subField.values) && subField.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2301
2333
  key: 1,
2302
2334
  "onUpdate:modelValue": ($event) => row.text[subKey] = $event,
2303
2335
  required: subField.required,
2304
2336
  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"
2305
- }, [createElementVNode("option", _hoisted_29$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(subField.values, (value) => {
2337
+ }, [createElementVNode("option", _hoisted_32$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(subField.values, (value) => {
2306
2338
  return openBlock(), createElementBlock("option", {
2307
2339
  key: value,
2308
2340
  value
2309
- }, toDisplayString(value), 9, _hoisted_30$1);
2310
- }), 128))], 8, _hoisted_28$1)), [[vModelSelect, row.text[subKey]]]) : subField.type === "ref" && subField.to && __props.render.refOptions(subField.to).length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2341
+ }, toDisplayString(value), 9, _hoisted_33$1);
2342
+ }), 128))], 8, _hoisted_31$1)), [[vModelSelect, row.text[subKey]]]) : subField.type === "ref" && subField.to && __props.render.refOptions(subField.to).length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2311
2343
  key: 2,
2312
2344
  "onUpdate:modelValue": ($event) => row.text[subKey] = $event,
2313
2345
  required: subField.required,
2314
2346
  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"
2315
- }, [createElementVNode("option", _hoisted_32$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(subField.to), (opt) => {
2347
+ }, [createElementVNode("option", _hoisted_35$1, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(subField.to), (opt) => {
2316
2348
  return openBlock(), createElementBlock("option", {
2317
2349
  key: opt.slug,
2318
2350
  value: opt.slug
2319
- }, toDisplayString(opt.display), 9, _hoisted_33$1);
2320
- }), 128))], 8, _hoisted_31$1)), [[vModelSelect, row.text[subKey]]]) : subField.type === "money" ? (openBlock(), createElementBlock("div", _hoisted_34$1, [createElementVNode("span", _hoisted_35$1, toDisplayString(__props.render.currencySymbol(__props.render.resolveCurrency(subField, __props.liveRecord))), 1), withDirectives(createElementVNode("input", {
2351
+ }, toDisplayString(opt.display), 9, _hoisted_36$1);
2352
+ }), 128))], 8, _hoisted_34$1)), [[vModelSelect, row.text[subKey]]]) : subField.type === "money" ? (openBlock(), createElementBlock("div", _hoisted_37$1, [createElementVNode("span", _hoisted_38$1, toDisplayString(__props.render.currencySymbol(__props.render.resolveCurrency(subField, __props.liveRecord))), 1), withDirectives(createElementVNode("input", {
2321
2353
  "onUpdate:modelValue": ($event) => row.text[subKey] = $event,
2322
2354
  type: "number",
2323
2355
  step: "0.01",
2324
2356
  required: subField.required,
2325
2357
  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"
2326
- }, null, 8, _hoisted_36$1), [[vModelText, row.text[subKey]]])])) : withDirectives((openBlock(), createElementBlock("input", {
2358
+ }, null, 8, _hoisted_39$1), [[vModelText, row.text[subKey]]])])) : withDirectives((openBlock(), createElementBlock("input", {
2327
2359
  key: 4,
2328
2360
  "onUpdate:modelValue": ($event) => row.text[subKey] = $event,
2329
2361
  type: __props.render.inputTypeFor(subField.type),
2330
2362
  step: __props.render.stepFor(subField.type),
2331
2363
  required: subField.required,
2332
2364
  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"
2333
- }, null, 8, _hoisted_37$1)), [[vModelDynamic, row.text[subKey]]])]);
2334
- }), 128)), createElementVNode("td", _hoisted_38$1, [createElementVNode("button", {
2365
+ }, null, 8, _hoisted_40$1)), [[vModelDynamic, row.text[subKey]]])]);
2366
+ }), 128)), createElementVNode("td", _hoisted_41$1, [createElementVNode("button", {
2335
2367
  type: "button",
2336
2368
  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",
2337
2369
  "aria-label": unref(t)("collectionsView.removeRow"),
2338
2370
  "data-testid": `collections-table-${key}-remove-${rowIdx}`,
2339
2371
  onClick: ($event) => removeTableRow(String(key), rowIdx)
2340
- }, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_39$1)])]);
2341
- }), 128))])])])) : (openBlock(), createElementBlock("p", _hoisted_40$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)), createElementVNode("button", {
2372
+ }, [..._cache[10] || (_cache[10] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_42$1)])]);
2373
+ }), 128))])])])) : (openBlock(), createElementBlock("p", _hoisted_43$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)), createElementVNode("button", {
2342
2374
  type: "button",
2343
2375
  class: "inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-800 font-bold hover:underline",
2344
2376
  "data-testid": `collections-table-${key}-add`,
2345
2377
  onClick: ($event) => addTableRow(String(key), field.of)
2346
- }, [_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$3)) : 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", {
2378
+ }, [_cache[11] || (_cache[11] = createElementVNode("span", { class: "material-icons text-xs" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addRow")), 1)], 8, _hoisted_44$1)], 8, _hoisted_25$2)) : field.type === "money" ? (openBlock(), createElementBlock("div", _hoisted_45$1, [createElementVNode("div", _hoisted_46$1, toDisplayString(__props.render.currencySymbol(__props.render.resolveCurrency(field, __props.liveRecord))), 1), withDirectives(createElementVNode("input", {
2347
2379
  id: `collections-field-${key}`,
2348
2380
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
2349
2381
  type: "number",
@@ -2351,7 +2383,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2351
2383
  required: isFieldRequiredInUi(field),
2352
2384
  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",
2353
2385
  "data-testid": `collections-input-${key}`
2354
- }, null, 8, _hoisted_44$1), [[vModelText, editing.value.text[key]]])])) : [
2386
+ }, null, 8, _hoisted_47$1), [[vModelText, editing.value.text[key]]])])) : [
2355
2387
  "string",
2356
2388
  "email",
2357
2389
  "number",
@@ -2370,7 +2402,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2370
2402
  disabled: field.primary === true && (editing.value.mode === "edit" || __props.isSingleton),
2371
2403
  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",
2372
2404
  "data-testid": `collections-input-${key}`
2373
- }, null, 8, _hoisted_45$1)), [[vModelDynamic, editing.value.text[key]]]) : withDirectives((openBlock(), createElementBlock("textarea", {
2405
+ }, null, 8, _hoisted_48$1)), [[vModelDynamic, editing.value.text[key]]]) : withDirectives((openBlock(), createElementBlock("textarea", {
2374
2406
  key: 6,
2375
2407
  id: `collections-field-${key}`,
2376
2408
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
@@ -2378,11 +2410,11 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2378
2410
  required: isFieldRequiredInUi(field),
2379
2411
  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",
2380
2412
  "data-testid": `collections-input-${key}`
2381
- }, null, 8, _hoisted_46$1)), [[vModelText, editing.value.text[key]]])], 64)) : (openBlock(), createElementBlock("div", {
2382
- key: 1,
2413
+ }, null, 8, _hoisted_49$1)), [[vModelText, editing.value.text[key]]])], 64)) : (openBlock(), createElementBlock("div", {
2414
+ key: 2,
2383
2415
  class: "text-xs font-medium text-slate-700 break-words",
2384
2416
  "data-testid": `collections-detail-value-${key}`
2385
- }, [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", {
2417
+ }, [field.type === "toggle" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? (openBlock(), createElementBlock("span", _hoisted_51$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_52$1, toDisplayString(unref(t)("common.no")), 1))], 64)) : field.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [detailRecord.value[key] === true ? (openBlock(), createElementBlock("span", _hoisted_53$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_54$1, toDisplayString(unref(t)("common.no")), 1)) : (openBlock(), createElementBlock("span", _hoisted_55$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("a", {
2386
2418
  key: 2,
2387
2419
  href: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])),
2388
2420
  tabindex: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
@@ -2391,12 +2423,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2391
2423
  "data-testid": `collections-detail-ref-${key}`,
2392
2424
  onClick: ($event) => unref(activateRefLink)($event, field.to, String(detailRecord.value[key])),
2393
2425
  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"])]
2394
- }, toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_53$1)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_54$1, toDisplayString(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_55$1, toDisplayString(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? (openBlock(), createElementBlock("div", _hoisted_56$1, [createElementVNode("table", _hoisted_57$1, [createElementVNode("thead", _hoisted_58$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2426
+ }, toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_56$1)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_57$1, toDisplayString(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_58$1, toDisplayString(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? (openBlock(), createElementBlock("div", _hoisted_59$1, [createElementVNode("table", _hoisted_60$1, [createElementVNode("thead", _hoisted_61$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2395
2427
  return openBlock(), createElementBlock("th", {
2396
2428
  key: subKey,
2397
2429
  class: "text-left px-4 py-2 font-bold"
2398
2430
  }, toDisplayString(subField.label), 1);
2399
- }), 128))])]), createElementVNode("tbody", _hoisted_59$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
2431
+ }), 128))])]), createElementVNode("tbody", _hoisted_62$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
2400
2432
  return openBlock(), createElementBlock("tr", {
2401
2433
  key: rowIdx,
2402
2434
  class: "hover:bg-slate-50/50"
@@ -2404,12 +2436,12 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2404
2436
  return openBlock(), createElementBlock("td", {
2405
2437
  key: subKey,
2406
2438
  class: "px-4 py-2 align-middle font-medium"
2407
- }, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span", _hoisted_60$1, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_61$1, "—"))], 64)) : (openBlock(), createElementBlock("span", {
2439
+ }, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span", _hoisted_63$1, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_64$1, "—"))], 64)) : (openBlock(), createElementBlock("span", {
2408
2440
  key: 1,
2409
2441
  class: normalizeClass([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
2410
2442
  }, toDisplayString(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
2411
2443
  }), 128))]);
2412
- }), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_62$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? (openBlock(), createElementBlock("div", _hoisted_63$1, toDisplayString(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? (openBlock(), createBlock(CollectionEmbedView_default, {
2444
+ }), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_65$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? (openBlock(), createElementBlock("div", _hoisted_66$1, toDisplayString(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? (openBlock(), createBlock(CollectionEmbedView_default, {
2413
2445
  key: 8,
2414
2446
  view: embedViews.value[key],
2415
2447
  "field-key": String(key)
@@ -2419,29 +2451,29 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2419
2451
  alt: field.label,
2420
2452
  class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
2421
2453
  "data-testid": `collections-detail-image-${key}`
2422
- }, null, 8, _hoisted_64$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2454
+ }, null, 8, _hoisted_67$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2423
2455
  key: 10,
2424
2456
  href: String(detailRecord.value[key]),
2425
2457
  target: "_blank",
2426
2458
  rel: "noopener noreferrer",
2427
2459
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2428
2460
  "data-testid": `collections-detail-url-${key}`
2429
- }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_65$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2461
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_68$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2430
2462
  key: 11,
2431
2463
  href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
2432
2464
  target: "_blank",
2433
2465
  rel: "noopener noreferrer",
2434
2466
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2435
2467
  "data-testid": `collections-detail-file-${key}`
2436
- }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_66$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2468
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_69$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2437
2469
  key: 12,
2438
2470
  href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
2439
2471
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2440
2472
  "data-testid": `collections-detail-file-${key}`,
2441
2473
  onClick: ($event) => unref(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
2442
- }, 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);
2443
- }), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_69$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)]),
2444
- !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", {
2474
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_70$1)) : (openBlock(), createElementBlock("span", _hoisted_71$1, toDisplayString(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_50$1))], 2)) : createCommentVNode("", true)], 64);
2475
+ }), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_72$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)]),
2476
+ !editing.value ? (openBlock(), createElementBlock("div", _hoisted_73$1, [createElementVNode("label", _hoisted_74$1, toDisplayString(unref(t)("collectionsView.itemChatLabel")), 1), createElementVNode("div", _hoisted_75$1, [withDirectives(createElementVNode("textarea", {
2445
2477
  id: "collections-detail-chat-input",
2446
2478
  "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
2447
2479
  rows: "2",
@@ -2449,13 +2481,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2449
2481
  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",
2450
2482
  "data-testid": "collections-detail-chat-input",
2451
2483
  onKeydown: [withKeys(withModifiers(submitItemChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitItemChat, ["ctrl"]), ["enter"])]
2452
- }, null, 40, _hoisted_73$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
2484
+ }, null, 40, _hoisted_76$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
2453
2485
  type: "button",
2454
2486
  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",
2455
2487
  disabled: !chatMessage.value.trim(),
2456
2488
  "data-testid": "collections-detail-chat-send",
2457
2489
  onClick: submitItemChat
2458
- }, [_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)
2490
+ }, [_cache[14] || (_cache[14] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)], 8, _hoisted_77$1)])])) : createCommentVNode("", true)
2459
2491
  ]),
2460
2492
  _: 1
2461
2493
  }, 40, ["data-testid"]);
@@ -2637,11 +2669,19 @@ var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /*@__PURE
2637
2669
  error.value = `HTTP ${resp.status}`;
2638
2670
  return;
2639
2671
  }
2672
+ const i18n = await binding.fetchViewI18n(props.slug, props.view.id, binding.localeTag());
2673
+ if (stale()) return;
2674
+ const i18nBoot = i18n.ok ? i18n.data : {
2675
+ locale: "",
2676
+ dict: {}
2677
+ };
2640
2678
  srcdoc.value = binding.buildViewSrcdoc(resp.html, {
2641
2679
  slug: props.slug,
2642
2680
  token: mint.data.token,
2643
2681
  dataUrl: mint.data.dataUrl,
2644
- origin: window.location.origin
2682
+ origin: window.location.origin,
2683
+ locale: i18nBoot.locale,
2684
+ dict: i18nBoot.dict
2645
2685
  });
2646
2686
  } catch (err) {
2647
2687
  if (!stale()) error.value = errorMessage(err);
@@ -2649,7 +2689,11 @@ var CollectionCustomView_vue_vue_type_script_setup_true_lang_default = /*@__PURE
2649
2689
  if (!stale()) loading.value = false;
2650
2690
  }
2651
2691
  }
2652
- watch([() => props.slug, () => props.view.id], () => void load(), { immediate: true });
2692
+ watch([
2693
+ () => props.slug,
2694
+ () => props.view.id,
2695
+ () => collectionUi().localeTag()
2696
+ ], () => void load(), { immediate: true });
2653
2697
  let changeUnsub = null;
2654
2698
  function relayChange() {
2655
2699
  iframeEl.value?.contentWindow?.postMessage({
@@ -2716,7 +2760,7 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
2716
2760
  };
2717
2761
  //#endregion
2718
2762
  //#region src/vue/components/CollectionCustomView.vue
2719
- var CollectionCustomView_default = /*#__PURE__*/ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-aa6e6c2d"]]);
2763
+ var CollectionCustomView_default = /*#__PURE__*/ _plugin_vue_export_helper_default(CollectionCustomView_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-b22228db"]]);
2720
2764
  //#endregion
2721
2765
  //#region src/vue/useCollectionRendering.ts
2722
2766
  function stepForFieldType(type) {
@@ -2819,17 +2863,43 @@ function useCollectionRendering(collection, locale) {
2819
2863
  display
2820
2864
  })).sort((left, right) => left.display.localeCompare(right.display));
2821
2865
  }
2822
- function resolveEmbed(field) {
2823
- if (field.type !== "embed" || !field.to || !field.id) return {
2866
+ /** Dropdown options for an `embed` field's per-record picker (`idField`):
2867
+ * every record in the target collection, labelled by its name/title (or
2868
+ * primary key). Built from `embedCache` so it works for embed targets
2869
+ * that aren't also `ref` targets (the profile collection, say). */
2870
+ function embedOptions(targetSlug) {
2871
+ const data = embedCache.value[targetSlug];
2872
+ if (!data) return [];
2873
+ const { fields, primaryKey } = data.schema;
2874
+ const displayField = "name" in fields ? "name" : "title" in fields ? "title" : primaryKey;
2875
+ return data.items.map((item) => {
2876
+ const slug = String(item[primaryKey] ?? "");
2877
+ const labelRaw = item[displayField];
2878
+ return {
2879
+ slug,
2880
+ display: typeof labelRaw === "string" && labelRaw.length > 0 ? labelRaw : slug
2881
+ };
2882
+ }).filter((opt) => opt.slug.length > 0).sort((left, right) => left.display.localeCompare(right.display));
2883
+ }
2884
+ /** The target record id an embed points at: its fixed `id`, or the
2885
+ * value of the sibling `idField` on the open record (per-record). */
2886
+ function embedTargetId(field, record) {
2887
+ if (field.id) return field.id;
2888
+ if (field.idField && record) return String(record[field.idField] ?? "");
2889
+ return "";
2890
+ }
2891
+ function resolveEmbed(field, record) {
2892
+ if (field.type !== "embed" || !field.to) return {
2824
2893
  schema: null,
2825
2894
  item: null
2826
2895
  };
2827
- const data = embedCache.value[field.to];
2896
+ const targetId = embedTargetId(field, record);
2897
+ const data = targetId ? embedCache.value[field.to] : void 0;
2828
2898
  if (!data) return {
2829
2899
  schema: null,
2830
2900
  item: null
2831
2901
  };
2832
- const item = data.items.find((entry) => String(entry[data.schema.primaryKey] ?? "") === field.id) ?? null;
2902
+ const item = data.items.find((entry) => String(entry[data.schema.primaryKey] ?? "") === targetId) ?? null;
2833
2903
  return {
2834
2904
  schema: data.schema,
2835
2905
  item
@@ -2839,12 +2909,15 @@ function useCollectionRendering(collection, locale) {
2839
2909
  if (field.type === "money") return formatMoney(value, resolveCurrency(field, record), locale.value);
2840
2910
  return detailText(value);
2841
2911
  }
2842
- const embedViews = computed(() => {
2912
+ /** Build the read-only embed view-models for one record. A function of
2913
+ * the open record (not a bare computed) because a per-record `idField`
2914
+ * embed resolves a different target per row. */
2915
+ function embedViewsFor(record) {
2843
2916
  const out = {};
2844
2917
  if (!collection.value) return out;
2845
2918
  for (const [key, field] of Object.entries(collection.value.schema.fields)) {
2846
2919
  if (field.type !== "embed") continue;
2847
- const { schema, item } = resolveEmbed(field);
2920
+ const { schema, item } = resolveEmbed(field, record);
2848
2921
  const rows = [];
2849
2922
  if (schema && item) for (const [subKey, subField] of Object.entries(schema.fields)) {
2850
2923
  const value = item[subKey];
@@ -2861,11 +2934,11 @@ function useCollectionRendering(collection, locale) {
2861
2934
  found: Boolean(item),
2862
2935
  rows,
2863
2936
  targetSlug: field.to ?? "",
2864
- recordId: field.id ?? ""
2937
+ recordId: embedTargetId(field, record)
2865
2938
  };
2866
2939
  }
2867
2940
  return out;
2868
- });
2941
+ }
2869
2942
  function resolveCurrency(field, record) {
2870
2943
  if (field.currencyField && record) {
2871
2944
  const code = record[field.currencyField];
@@ -2956,7 +3029,8 @@ function useCollectionRendering(collection, locale) {
2956
3029
  loadLinkedCollections,
2957
3030
  refDisplay,
2958
3031
  refOptions,
2959
- embedViews,
3032
+ embedOptions,
3033
+ embedViewsFor,
2960
3034
  resolveCurrency,
2961
3035
  currencySymbol,
2962
3036
  formatMoney,