@mulmoclaude/collection-plugin 0.11.4 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
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";
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, itemIsDone, itemLabelOf, labelFieldFor, nextSortDirection, numericSortValue, resolveEnumColor, rollupValue, rowFromItem, shortHexId, sortItems, stringSortValue, ymdKey } from "@mulmoclaude/core/collection";
2
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";
@@ -68,6 +68,13 @@ var i18n = createI18n({
68
68
  deleteCollection: "Delete collection",
69
69
  confirmDeleteCollection: "Delete the entire \"{title}\" collection, including all its records? A restorable backup is archived first.",
70
70
  itemsEmpty: "No items yet. Click + to add one.",
71
+ readonlyChip: "Read-only",
72
+ itemsEmptyReadonly: "No rows in the data file yet. Add rows to the file and they appear here.",
73
+ filter: {
74
+ all: "All",
75
+ editable: "Editable",
76
+ data: "Data"
77
+ },
71
78
  notFound: "Collection not found",
72
79
  loadFailed: "Failed to load",
73
80
  requiredField: "This field is required",
@@ -83,6 +90,11 @@ var i18n = createI18n({
83
90
  searchSummary: "Showing {shown} of {total}",
84
91
  noMatchingItems: "No matching items",
85
92
  clearSearch: "Clear search",
93
+ flagFilterGroup: "Flag filters",
94
+ flagFilterAll: "Filter by {label}",
95
+ flagFilterHide: "Hiding {label}",
96
+ flagFilterOnly: "Only {label}",
97
+ flagDoneChip: "Done",
86
98
  sortBy: "Sort by {field}",
87
99
  openCollection: "Open {title}",
88
100
  createTitle: "Add new",
@@ -204,6 +216,13 @@ var i18n = createI18n({
204
216
  deleteCollection: "コレクションを削除",
205
217
  confirmDeleteCollection: "コレクション「{title}」とそのすべてのレコードを削除しますか?削除前に復元可能なバックアップが保存されます。",
206
218
  itemsEmpty: "まだ項目がありません。+ を押して追加してください。",
219
+ readonlyChip: "読み取り専用",
220
+ itemsEmptyReadonly: "データファイルにまだ行がありません。ファイルに行を追加するとここに表示されます。",
221
+ filter: {
222
+ all: "すべて",
223
+ editable: "編集可能",
224
+ data: "データ"
225
+ },
207
226
  notFound: "コレクションが見つかりません",
208
227
  loadFailed: "読み込みに失敗しました",
209
228
  requiredField: "この項目は必須です",
@@ -219,6 +238,11 @@ var i18n = createI18n({
219
238
  searchSummary: "{total} 件中 {shown} 件を表示",
220
239
  noMatchingItems: "一致する項目がありません",
221
240
  clearSearch: "検索をクリア",
241
+ flagFilterGroup: "フラグで絞り込み",
242
+ flagFilterAll: "{label} で絞り込む",
243
+ flagFilterHide: "{label} を非表示中",
244
+ flagFilterOnly: "{label} のみ表示中",
245
+ flagDoneChip: "完了",
222
246
  sortBy: "{field}で並べ替え",
223
247
  openCollection: "{title} を開く",
224
248
  createTitle: "新規追加",
@@ -340,6 +364,13 @@ var i18n = createI18n({
340
364
  deleteCollection: "删除集合",
341
365
  confirmDeleteCollection: "删除整个“{title}”集合及其所有记录?删除前会先归档一份可恢复的备份。",
342
366
  itemsEmpty: "暂无项目。点击 + 添加一个。",
367
+ readonlyChip: "只读",
368
+ itemsEmptyReadonly: "数据文件中还没有行。在文件中添加行后会显示在这里。",
369
+ filter: {
370
+ all: "全部",
371
+ editable: "可编辑",
372
+ data: "数据"
373
+ },
343
374
  notFound: "未找到集合",
344
375
  loadFailed: "加载失败",
345
376
  requiredField: "此字段为必填项",
@@ -355,6 +386,11 @@ var i18n = createI18n({
355
386
  searchSummary: "显示 {total} 条中的 {shown} 条",
356
387
  noMatchingItems: "没有匹配的项目",
357
388
  clearSearch: "清除搜索",
389
+ flagFilterGroup: "标记筛选",
390
+ flagFilterAll: "按{label}筛选",
391
+ flagFilterHide: "已隐藏{label}",
392
+ flagFilterOnly: "仅显示{label}",
393
+ flagDoneChip: "已完成",
358
394
  sortBy: "按{field}排序",
359
395
  openCollection: "打开 {title}",
360
396
  createTitle: "新增",
@@ -476,6 +512,13 @@ var i18n = createI18n({
476
512
  deleteCollection: "컬렉션 삭제",
477
513
  confirmDeleteCollection: "\"{title}\" 컬렉션과 모든 레코드를 삭제하시겠습니까? 삭제 전에 복원 가능한 백업이 보관됩니다.",
478
514
  itemsEmpty: "아직 항목이 없습니다. + 를 눌러 추가하세요.",
515
+ readonlyChip: "읽기 전용",
516
+ itemsEmptyReadonly: "데이터 파일에 아직 행이 없습니다. 파일에 행을 추가하면 여기에 표시됩니다.",
517
+ filter: {
518
+ all: "전체",
519
+ editable: "편집 가능",
520
+ data: "데이터"
521
+ },
479
522
  notFound: "컬렉션을 찾을 수 없습니다",
480
523
  loadFailed: "불러오기에 실패했습니다",
481
524
  requiredField: "이 필드는 필수입니다",
@@ -491,6 +534,11 @@ var i18n = createI18n({
491
534
  searchSummary: "{total}개 중 {shown}개 표시",
492
535
  noMatchingItems: "일치하는 항목이 없습니다",
493
536
  clearSearch: "검색 지우기",
537
+ flagFilterGroup: "플래그 필터",
538
+ flagFilterAll: "{label}(으)로 필터",
539
+ flagFilterHide: "{label} 숨김",
540
+ flagFilterOnly: "{label}만 표시",
541
+ flagDoneChip: "완료",
494
542
  sortBy: "{field} 기준 정렬",
495
543
  openCollection: "{title} 열기",
496
544
  createTitle: "새로 추가",
@@ -612,6 +660,13 @@ var i18n = createI18n({
612
660
  deleteCollection: "Eliminar colección",
613
661
  confirmDeleteCollection: "¿Eliminar toda la colección \"{title}\", incluidos todos sus registros? Antes se archiva una copia de seguridad restaurable.",
614
662
  itemsEmpty: "Aún no hay elementos. Pulsa + para añadir uno.",
663
+ readonlyChip: "Solo lectura",
664
+ itemsEmptyReadonly: "El archivo de datos aún no tiene filas. Añádelas al archivo y aparecerán aquí.",
665
+ filter: {
666
+ all: "Todas",
667
+ editable: "Editables",
668
+ data: "Datos"
669
+ },
615
670
  notFound: "Colección no encontrada",
616
671
  loadFailed: "Error al cargar",
617
672
  requiredField: "Este campo es obligatorio",
@@ -627,6 +682,11 @@ var i18n = createI18n({
627
682
  searchSummary: "Mostrando {shown} de {total}",
628
683
  noMatchingItems: "No hay elementos coincidentes",
629
684
  clearSearch: "Borrar búsqueda",
685
+ flagFilterGroup: "Filtros por indicador",
686
+ flagFilterAll: "Filtrar por {label}",
687
+ flagFilterHide: "Ocultando {label}",
688
+ flagFilterOnly: "Solo {label}",
689
+ flagDoneChip: "Hecho",
630
690
  sortBy: "Ordenar por {field}",
631
691
  openCollection: "Abrir {title}",
632
692
  createTitle: "Añadir nuevo",
@@ -748,6 +808,13 @@ var i18n = createI18n({
748
808
  deleteCollection: "Excluir coleção",
749
809
  confirmDeleteCollection: "Excluir toda a coleção \"{title}\", incluindo todos os seus registros? Um backup restaurável é arquivado antes.",
750
810
  itemsEmpty: "Ainda não há itens. Clique em + para adicionar um.",
811
+ readonlyChip: "Somente leitura",
812
+ itemsEmptyReadonly: "O arquivo de dados ainda não tem linhas. Adicione linhas ao arquivo e elas aparecerão aqui.",
813
+ filter: {
814
+ all: "Todas",
815
+ editable: "Editáveis",
816
+ data: "Dados"
817
+ },
751
818
  notFound: "Coleção não encontrada",
752
819
  loadFailed: "Falha ao carregar",
753
820
  requiredField: "Este campo é obrigatório",
@@ -763,6 +830,11 @@ var i18n = createI18n({
763
830
  searchSummary: "Mostrando {shown} de {total}",
764
831
  noMatchingItems: "Nenhum item correspondente",
765
832
  clearSearch: "Limpar busca",
833
+ flagFilterGroup: "Filtros por marcador",
834
+ flagFilterAll: "Filtrar por {label}",
835
+ flagFilterHide: "Ocultando {label}",
836
+ flagFilterOnly: "Somente {label}",
837
+ flagDoneChip: "Concluído",
766
838
  sortBy: "Ordenar por {field}",
767
839
  openCollection: "Abrir {title}",
768
840
  createTitle: "Adicionar novo",
@@ -884,6 +956,13 @@ var i18n = createI18n({
884
956
  deleteCollection: "Supprimer la collection",
885
957
  confirmDeleteCollection: "Supprimer toute la collection « {title} », y compris tous ses enregistrements ? Une sauvegarde restaurable est archivée au préalable.",
886
958
  itemsEmpty: "Aucun élément pour l'instant. Cliquez sur + pour en ajouter un.",
959
+ readonlyChip: "Lecture seule",
960
+ itemsEmptyReadonly: "Le fichier de données ne contient pas encore de lignes. Ajoutez-en au fichier et elles apparaîtront ici.",
961
+ filter: {
962
+ all: "Toutes",
963
+ editable: "Modifiables",
964
+ data: "Données"
965
+ },
887
966
  notFound: "Collection introuvable",
888
967
  loadFailed: "Échec du chargement",
889
968
  requiredField: "Ce champ est obligatoire",
@@ -899,6 +978,11 @@ var i18n = createI18n({
899
978
  searchSummary: "Affichage de {shown} sur {total}",
900
979
  noMatchingItems: "Aucun élément correspondant",
901
980
  clearSearch: "Effacer la recherche",
981
+ flagFilterGroup: "Filtres par indicateur",
982
+ flagFilterAll: "Filtrer par {label}",
983
+ flagFilterHide: "{label} masqué",
984
+ flagFilterOnly: "Uniquement {label}",
985
+ flagDoneChip: "Terminé",
902
986
  sortBy: "Trier par {field}",
903
987
  openCollection: "Ouvrir {title}",
904
988
  createTitle: "Ajouter",
@@ -1020,6 +1104,13 @@ var i18n = createI18n({
1020
1104
  deleteCollection: "Sammlung löschen",
1021
1105
  confirmDeleteCollection: "Die gesamte Sammlung „{title}“ einschließlich aller Datensätze löschen? Zuvor wird eine wiederherstellbare Sicherung archiviert.",
1022
1106
  itemsEmpty: "Noch keine Einträge. Klicke auf +, um einen hinzuzufügen.",
1107
+ readonlyChip: "Schreibgeschützt",
1108
+ itemsEmptyReadonly: "Noch keine Zeilen in der Datendatei. Füge der Datei Zeilen hinzu, dann erscheinen sie hier.",
1109
+ filter: {
1110
+ all: "Alle",
1111
+ editable: "Bearbeitbar",
1112
+ data: "Daten"
1113
+ },
1023
1114
  notFound: "Sammlung nicht gefunden",
1024
1115
  loadFailed: "Laden fehlgeschlagen",
1025
1116
  requiredField: "Dieses Feld ist erforderlich",
@@ -1035,6 +1126,11 @@ var i18n = createI18n({
1035
1126
  searchSummary: "{shown} von {total} werden angezeigt",
1036
1127
  noMatchingItems: "Keine passenden Einträge",
1037
1128
  clearSearch: "Suche zurücksetzen",
1129
+ flagFilterGroup: "Flag-Filter",
1130
+ flagFilterAll: "Nach {label} filtern",
1131
+ flagFilterHide: "{label} ausgeblendet",
1132
+ flagFilterOnly: "Nur {label}",
1133
+ flagDoneChip: "Erledigt",
1038
1134
  sortBy: "Nach {field} sortieren",
1039
1135
  openCollection: "{title} öffnen",
1040
1136
  createTitle: "Neu hinzufügen",
@@ -2043,7 +2139,8 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
2043
2139
  groupField: {},
2044
2140
  items: {},
2045
2141
  selected: {},
2046
- notified: {}
2142
+ notified: {},
2143
+ readonly: { type: Boolean }
2047
2144
  },
2048
2145
  emits: ["select", "move"],
2049
2146
  setup(__props, { emit: __emit }) {
@@ -2150,6 +2247,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
2150
2247
  group: "collection-kanban-cards",
2151
2248
  class: "flex-1 overflow-y-auto p-2 space-y-2 min-h-[2rem]",
2152
2249
  animation: 150,
2250
+ disabled: __props.readonly,
2153
2251
  onChange: (e) => onDragChange(column.value, e)
2154
2252
  }, {
2155
2253
  item: withCtx(({ element }) => [createElementVNode("div", {
@@ -2160,7 +2258,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
2160
2258
  class: normalizeClass(["bg-white border border-slate-200 rounded shadow-sm p-2 cursor-grab hover:shadow active:cursor-grabbing focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400", [itemId(element) === __props.selected ? "ring-2 ring-indigo-500 border-indigo-300" : "", notifyAccentClass(element)]]),
2161
2259
  onClick: ($event) => emit("select", itemId(element)),
2162
2260
  onKeydown: [withKeys(withModifiers((e) => !e.repeat && emit("select", itemId(element)), ["prevent", "self"]), ["enter"]), withKeys(withModifiers((e) => !e.repeat && emit("select", itemId(element)), ["prevent", "self"]), ["space"])]
2163
- }, [createElementVNode("div", _hoisted_9$8, [cardToggle.value ? (openBlock(), createElementBlock("input", {
2261
+ }, [createElementVNode("div", _hoisted_9$8, [cardToggle.value && !__props.readonly ? (openBlock(), createElementBlock("input", {
2164
2262
  key: 0,
2165
2263
  type: "checkbox",
2166
2264
  checked: cardChecked(element),
@@ -2174,6 +2272,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ defineComponent({
2174
2272
  }, 8, [
2175
2273
  "model-value",
2176
2274
  "item-key",
2275
+ "disabled",
2177
2276
  "onChange"
2178
2277
  ])], 8, _hoisted_3$12);
2179
2278
  }), 128))])]);
@@ -2400,23 +2499,23 @@ var _hoisted_18$5 = [
2400
2499
  "placeholder",
2401
2500
  "data-testid"
2402
2501
  ];
2403
- var _hoisted_19$3 = {
2502
+ var _hoisted_19$4 = {
2404
2503
  key: 0,
2405
2504
  class: "inline-flex items-center gap-2.5 text-sm text-slate-700 cursor-pointer select-none"
2406
2505
  };
2407
- var _hoisted_20$3 = [
2506
+ var _hoisted_20$4 = [
2408
2507
  "id",
2409
2508
  "onUpdate:modelValue",
2410
2509
  "data-testid",
2411
2510
  "onChange"
2412
2511
  ];
2413
- var _hoisted_21$3 = [
2512
+ var _hoisted_21$4 = [
2414
2513
  "id",
2415
2514
  "onUpdate:modelValue",
2416
2515
  "required",
2417
2516
  "data-testid"
2418
2517
  ];
2419
- var _hoisted_22$3 = { value: "" };
2518
+ var _hoisted_22$4 = { value: "" };
2420
2519
  var _hoisted_23$3 = ["value"];
2421
2520
  var _hoisted_24$2 = [
2422
2521
  "id",
@@ -2512,77 +2611,79 @@ var _hoisted_57$1 = {
2512
2611
  key: 2,
2513
2612
  class: "text-slate-300"
2514
2613
  };
2515
- var _hoisted_58$1 = [
2614
+ var _hoisted_58$1 = ["data-testid"];
2615
+ var _hoisted_59$1 = ["data-testid"];
2616
+ var _hoisted_60$1 = [
2516
2617
  "href",
2517
2618
  "tabindex",
2518
2619
  "data-testid",
2519
2620
  "onClick",
2520
2621
  "onKeydown"
2521
2622
  ];
2522
- var _hoisted_59$1 = {
2523
- key: 3,
2623
+ var _hoisted_61$1 = {
2624
+ key: 4,
2524
2625
  class: "font-semibold text-slate-900 tabular-nums text-sm"
2525
2626
  };
2526
- var _hoisted_60$1 = {
2527
- key: 4,
2627
+ var _hoisted_62$1 = {
2628
+ key: 5,
2528
2629
  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"
2529
2630
  };
2530
- var _hoisted_61$1 = ["data-testid"];
2531
- var _hoisted_62$1 = {
2532
- key: 6,
2631
+ var _hoisted_63$1 = ["data-testid"];
2632
+ var _hoisted_64$1 = {
2633
+ key: 7,
2533
2634
  class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
2534
2635
  };
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 = {
2636
+ var _hoisted_65$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
2637
+ var _hoisted_66$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
2638
+ var _hoisted_67$1 = { class: "divide-y divide-slate-100" };
2639
+ var _hoisted_68$1 = {
2539
2640
  key: 0,
2540
2641
  class: "material-icons text-emerald-600 text-base"
2541
2642
  };
2542
- var _hoisted_67$1 = {
2643
+ var _hoisted_69$1 = {
2543
2644
  key: 1,
2544
2645
  class: "text-slate-300"
2545
2646
  };
2546
- var _hoisted_68$1 = {
2547
- key: 7,
2647
+ var _hoisted_70$1 = {
2648
+ key: 8,
2548
2649
  class: "text-slate-400 italic"
2549
2650
  };
2550
- var _hoisted_69$1 = {
2551
- key: 8,
2651
+ var _hoisted_71$1 = {
2652
+ key: 9,
2552
2653
  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"
2553
2654
  };
2554
- var _hoisted_70$1 = [
2655
+ var _hoisted_72$1 = [
2555
2656
  "src",
2556
2657
  "alt",
2557
2658
  "data-testid"
2558
2659
  ];
2559
- var _hoisted_71$1 = ["href", "data-testid"];
2560
- var _hoisted_72$1 = ["href", "data-testid"];
2561
- var _hoisted_73$1 = [
2660
+ var _hoisted_73$1 = ["href", "data-testid"];
2661
+ var _hoisted_74$1 = ["href", "data-testid"];
2662
+ var _hoisted_75$1 = [
2562
2663
  "href",
2563
2664
  "data-testid",
2564
2665
  "onClick"
2565
2666
  ];
2566
- var _hoisted_74$1 = {
2567
- key: 15,
2667
+ var _hoisted_76$1 = {
2668
+ key: 16,
2568
2669
  class: "text-slate-800 font-semibold"
2569
2670
  };
2570
- var _hoisted_75$1 = {
2671
+ var _hoisted_77$1 = {
2571
2672
  key: 0,
2572
2673
  class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
2573
2674
  };
2574
- var _hoisted_76$1 = {
2675
+ var _hoisted_78$1 = {
2575
2676
  key: 1,
2576
2677
  class: "mt-5 pt-4 border-t border-slate-200/60",
2577
2678
  "data-testid": "collections-detail-chat"
2578
2679
  };
2579
- var _hoisted_77$1 = {
2680
+ var _hoisted_79$1 = {
2580
2681
  class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
2581
2682
  for: "collections-detail-chat-input"
2582
2683
  };
2583
- var _hoisted_78$1 = { class: "flex items-end gap-2" };
2584
- var _hoisted_79$1 = ["placeholder", "onKeydown"];
2585
- var _hoisted_80$1 = ["disabled"];
2684
+ var _hoisted_80$1 = { class: "flex items-end gap-2" };
2685
+ var _hoisted_81$1 = ["placeholder", "onKeydown"];
2686
+ var _hoisted_82$1 = ["disabled"];
2586
2687
  //#endregion
2587
2688
  //#region src/vue/components/CollectionRecordPanel.vue
2588
2689
  var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
@@ -2600,6 +2701,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2600
2701
  liveDerived: {},
2601
2702
  viewTitle: {},
2602
2703
  isSingleton: { type: Boolean },
2704
+ readonly: { type: Boolean },
2603
2705
  render: {},
2604
2706
  locale: {}
2605
2707
  }, {
@@ -2753,18 +2855,20 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2753
2855
  onClick: ($event) => emit("runAction", action)
2754
2856
  }, [__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);
2755
2857
  }), 128)),
2756
- createElementVNode("button", {
2858
+ !__props.readonly ? (openBlock(), createElementBlock("button", {
2859
+ key: 0,
2757
2860
  type: "button",
2758
2861
  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",
2759
2862
  "data-testid": "collections-detail-edit",
2760
2863
  onClick: _cache[1] || (_cache[1] = ($event) => emit("edit"))
2761
- }, [_cache[6] || (_cache[6] = createElementVNode("span", { class: "material-icons text-sm" }, "edit", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.editItem")), 1)]),
2762
- createElementVNode("button", {
2864
+ }, [_cache[6] || (_cache[6] = createElementVNode("span", { class: "material-icons text-sm" }, "edit", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.editItem")), 1)])) : createCommentVNode("", true),
2865
+ !__props.readonly ? (openBlock(), createElementBlock("button", {
2866
+ key: 1,
2763
2867
  type: "button",
2764
2868
  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",
2765
2869
  "data-testid": "collections-detail-remove",
2766
2870
  onClick: _cache[2] || (_cache[2] = ($event) => emit("delete"))
2767
- }, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "material-icons text-sm" }, "delete", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.remove")), 1)]),
2871
+ }, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "material-icons text-sm" }, "delete", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.remove")), 1)])) : createCommentVNode("", true),
2768
2872
  createElementVNode("button", {
2769
2873
  type: "button",
2770
2874
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors",
@@ -2802,26 +2906,26 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2802
2906
  placeholder: unref(t)("collectionsView.selectPlaceholder"),
2803
2907
  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",
2804
2908
  "data-testid": `collections-input-${key}`
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", {
2909
+ }, 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$4, [withDirectives(createElementVNode("input", {
2806
2910
  id: `collections-field-${key}`,
2807
2911
  "onUpdate:modelValue": ($event) => editing.value.bool[key] = $event,
2808
2912
  type: "checkbox",
2809
2913
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
2810
2914
  "data-testid": `collections-input-${key}`,
2811
2915
  onChange: ($event) => markBoolTouched(String(key))
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", {
2916
+ }, null, 40, _hoisted_20$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", {
2813
2917
  key: 1,
2814
2918
  id: `collections-field-${key}`,
2815
2919
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
2816
2920
  required: isFieldRequiredInUi(field),
2817
2921
  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",
2818
2922
  "data-testid": `collections-input-${key}`
2819
- }, [createElementVNode("option", _hoisted_22$3, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(field.to), (opt) => {
2923
+ }, [createElementVNode("option", _hoisted_22$4, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.refOptions(field.to), (opt) => {
2820
2924
  return openBlock(), createElementBlock("option", {
2821
2925
  key: opt.slug,
2822
2926
  value: opt.slug
2823
2927
  }, 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", {
2928
+ }), 128))], 8, _hoisted_21$4)), [[vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? withDirectives((openBlock(), createElementBlock("select", {
2825
2929
  key: 2,
2826
2930
  id: `collections-field-${key}`,
2827
2931
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
@@ -2941,8 +3045,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2941
3045
  key: 3,
2942
3046
  class: "text-xs font-medium text-slate-700 break-words",
2943
3047
  "data-testid": `collections-detail-value-${key}`
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", {
2945
- key: 2,
3048
+ }, [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 === "flag" ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [__props.render.deriveRecord(detailRecord.value)[key] === true ? (openBlock(), createElementBlock("span", {
3049
+ key: 0,
3050
+ 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",
3051
+ "data-testid": `collections-detail-flag-${key}`
3052
+ }, [_cache[14] || (_cache[14] = createElementVNode("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), createTextVNode(" " + toDisplayString(unref(t)("common.yes")), 1)], 8, _hoisted_58$1)) : (openBlock(), createElementBlock("span", {
3053
+ key: 1,
3054
+ 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",
3055
+ "data-testid": `collections-detail-flag-${key}`
3056
+ }, toDisplayString(unref(t)("common.no")), 9, _hoisted_59$1))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("a", {
3057
+ key: 3,
2946
3058
  href: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])),
2947
3059
  tabindex: unref(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
2948
3060
  role: "link",
@@ -2950,16 +3062,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2950
3062
  "data-testid": `collections-detail-ref-${key}`,
2951
3063
  onClick: ($event) => unref(activateRefLink)($event, field.to, String(detailRecord.value[key])),
2952
3064
  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"])]
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,
3065
+ }, toDisplayString(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_60$1)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_61$1, toDisplayString(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_62$1, toDisplayString(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "rollup" ? (openBlock(), createElementBlock("span", {
3066
+ key: 6,
2955
3067
  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
3068
  "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) => {
3069
+ }, toDisplayString(__props.render.rollupDisplay(field, detailRecord.value)), 9, _hoisted_63$1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? (openBlock(), createElementBlock("div", _hoisted_64$1, [createElementVNode("table", _hoisted_65$1, [createElementVNode("thead", _hoisted_66$1, [createElementVNode("tr", null, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.of, (subField, subKey) => {
2958
3070
  return openBlock(), createElementBlock("th", {
2959
3071
  key: subKey,
2960
3072
  class: "text-left px-4 py-2 font-bold"
2961
3073
  }, toDisplayString(subField.label), 1);
2962
- }), 128))])]), createElementVNode("tbody", _hoisted_65$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
3074
+ }), 128))])]), createElementVNode("tbody", _hoisted_67$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
2963
3075
  return openBlock(), createElementBlock("tr", {
2964
3076
  key: rowIdx,
2965
3077
  class: "hover:bg-slate-50/50"
@@ -2967,48 +3079,48 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
2967
3079
  return openBlock(), createElementBlock("td", {
2968
3080
  key: subKey,
2969
3081
  class: "px-4 py-2 align-middle font-medium"
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", {
3082
+ }, [subField.type === "boolean" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [row[subKey] === true ? (openBlock(), createElementBlock("span", _hoisted_68$1, "check_circle")) : (openBlock(), createElementBlock("span", _hoisted_69$1, "—"))], 64)) : (openBlock(), createElementBlock("span", {
2971
3083
  key: 1,
2972
3084
  class: normalizeClass([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
2973
3085
  }, toDisplayString(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
2974
3086
  }), 128))]);
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,
3087
+ }), 128))])])])) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_70$1, toDisplayString(unref(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? (openBlock(), createElementBlock("div", _hoisted_71$1, toDisplayString(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? (openBlock(), createBlock(CollectionEmbedView_default, {
3088
+ key: 10,
2977
3089
  view: embedViews.value[key],
2978
3090
  "field-key": String(key)
2979
3091
  }, null, 8, ["view", "field-key"])) : field.type === "backlinks" && backlinksViews.value[key] ? (openBlock(), createBlock(CollectionBacklinksView_default, {
2980
- key: 10,
3092
+ key: 11,
2981
3093
  view: backlinksViews.value[key],
2982
3094
  "field-key": String(key)
2983
3095
  }, null, 8, ["view", "field-key"])) : field.type === "image" && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? (openBlock(), createElementBlock("img", {
2984
- key: 11,
3096
+ key: 12,
2985
3097
  src: unref(resolveImageSrc)(String(detailRecord.value[key])),
2986
3098
  alt: field.label,
2987
3099
  class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
2988
3100
  "data-testid": `collections-detail-image-${key}`
2989
- }, null, 8, _hoisted_70$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
2990
- key: 12,
3101
+ }, null, 8, _hoisted_72$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
3102
+ key: 13,
2991
3103
  href: String(detailRecord.value[key]),
2992
3104
  target: "_blank",
2993
3105
  rel: "noopener noreferrer",
2994
3106
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
2995
3107
  "data-testid": `collections-detail-url-${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,
3108
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_73$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
3109
+ key: 14,
2998
3110
  href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
2999
3111
  target: "_blank",
3000
3112
  rel: "noopener noreferrer",
3001
3113
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
3002
3114
  "data-testid": `collections-detail-file-${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,
3115
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_74$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? (openBlock(), createElementBlock("a", {
3116
+ key: 15,
3005
3117
  href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
3006
3118
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
3007
3119
  "data-testid": `collections-detail-file-${key}`,
3008
3120
  onClick: ($event) => unref(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
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", {
3121
+ }, toDisplayString(String(detailRecord.value[key])), 9, _hoisted_75$1)) : (openBlock(), createElementBlock("span", _hoisted_76$1, toDisplayString(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_52$1))], 2)) : createCommentVNode("", true)], 64);
3122
+ }), 128)), editing.value && __props.saveError ? (openBlock(), createElementBlock("p", _hoisted_77$1, toDisplayString(__props.saveError), 1)) : createCommentVNode("", true)]),
3123
+ !editing.value ? (openBlock(), createElementBlock("div", _hoisted_78$1, [createElementVNode("label", _hoisted_79$1, toDisplayString(unref(t)("collectionsView.itemChatLabel")), 1), createElementVNode("div", _hoisted_80$1, [withDirectives(createElementVNode("textarea", {
3012
3124
  id: "collections-detail-chat-input",
3013
3125
  "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
3014
3126
  rows: "2",
@@ -3016,13 +3128,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ defineComponent({
3016
3128
  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",
3017
3129
  "data-testid": "collections-detail-chat-input",
3018
3130
  onKeydown: [withKeys(withModifiers(submitItemChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitItemChat, ["ctrl"]), ["enter"])]
3019
- }, null, 40, _hoisted_79$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
3131
+ }, null, 40, _hoisted_81$1), [[vModelText, chatMessage.value]]), createElementVNode("button", {
3020
3132
  type: "button",
3021
3133
  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",
3022
3134
  disabled: !chatMessage.value.trim(),
3023
3135
  "data-testid": "collections-detail-chat-send",
3024
3136
  onClick: submitItemChat
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)
3137
+ }, [_cache[15] || (_cache[15] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)], 8, _hoisted_82$1)])])) : createCommentVNode("", true)
3026
3138
  ]),
3027
3139
  _: 1
3028
3140
  }, 40, ["data-testid"]);
@@ -3817,6 +3929,38 @@ function writeCollectionSort(slug, sort) {
3817
3929
  localStorage.setItem(SORT_STORAGE_KEY, JSON.stringify(all));
3818
3930
  } catch {}
3819
3931
  }
3932
+ var FLAG_FILTER_STORAGE_KEY = "collection_flag_filters";
3933
+ function isFlagFilterState(value) {
3934
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3935
+ return Object.values(value).every((mode) => mode === "hide" || mode === "only");
3936
+ }
3937
+ function readAllFlagFilters() {
3938
+ try {
3939
+ const raw = localStorage.getItem(FLAG_FILTER_STORAGE_KEY);
3940
+ if (!raw) return {};
3941
+ const parsed = JSON.parse(raw);
3942
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
3943
+ const out = {};
3944
+ for (const [slug, value] of Object.entries(parsed)) if (isFlagFilterState(value)) out[slug] = value;
3945
+ return out;
3946
+ } catch {
3947
+ return {};
3948
+ }
3949
+ }
3950
+ /** The slug's persisted chip states ({} when none). A key whose flag no
3951
+ * longer exists in the schema is harmless — the chip list is derived
3952
+ * from the live schema, so a stale entry just never renders/filters. */
3953
+ function readCollectionFlagFilters(slug) {
3954
+ return readAllFlagFilters()[slug] ?? {};
3955
+ }
3956
+ /** Persist the slug's chip states; an empty state clears the entry. */
3957
+ function writeCollectionFlagFilters(slug, filters) {
3958
+ try {
3959
+ const all = Object.fromEntries(Object.entries(readAllFlagFilters()).filter(([key]) => key !== slug));
3960
+ if (Object.keys(filters).length > 0) all[slug] = filters;
3961
+ localStorage.setItem(FLAG_FILTER_STORAGE_KEY, JSON.stringify(all));
3962
+ } catch {}
3963
+ }
3820
3964
  //#endregion
3821
3965
  //#region src/vue/components/CollectionView.vue?vue&type=script&setup=true&lang.ts
3822
3966
  var _hoisted_1$6 = { class: "h-full flex flex-col bg-slate-50/30" };
@@ -3834,222 +3978,240 @@ var _hoisted_6$4 = { class: "flex-1 min-w-0" };
3834
3978
  var _hoisted_7$4 = { class: "text-base font-bold text-slate-800 truncate" };
3835
3979
  var _hoisted_8$4 = {
3836
3980
  key: 0,
3837
- class: "block text-[10px] text-slate-400 font-bold uppercase tracking-wider"
3981
+ class: "block text-[10px] text-slate-400 font-bold uppercase tracking-wider truncate"
3838
3982
  };
3839
- var _hoisted_9$4 = ["disabled"];
3840
- var _hoisted_10$4 = { class: "material-icons text-sm" };
3841
- var _hoisted_11$4 = [
3983
+ var _hoisted_9$4 = {
3984
+ class: "inline-flex items-center gap-0.5 ml-1.5 px-1.5 py-px rounded bg-amber-50 text-amber-700 border border-amber-200 normal-case tracking-normal",
3985
+ "data-testid": "collections-readonly-chip"
3986
+ };
3987
+ var _hoisted_10$4 = ["href"];
3988
+ var _hoisted_11$4 = ["disabled"];
3989
+ var _hoisted_12$4 = { class: "material-icons text-sm" };
3990
+ var _hoisted_13$4 = [
3842
3991
  "disabled",
3843
3992
  "data-testid",
3844
3993
  "onClick"
3845
3994
  ];
3846
- var _hoisted_12$4 = {
3995
+ var _hoisted_14$4 = {
3847
3996
  key: 0,
3848
3997
  class: "material-icons text-sm animate-spin"
3849
3998
  };
3850
- var _hoisted_13$4 = {
3999
+ var _hoisted_15$4 = {
3851
4000
  key: 1,
3852
4001
  class: "material-icons text-sm"
3853
4002
  };
3854
- var _hoisted_14$4 = ["title", "aria-label"];
3855
- var _hoisted_15$4 = ["title", "aria-label"];
3856
- var _hoisted_16$4 = {
4003
+ var _hoisted_16$4 = ["title", "aria-label"];
4004
+ var _hoisted_17$4 = ["title", "aria-label"];
4005
+ var _hoisted_18$4 = {
3857
4006
  key: 1,
3858
4007
  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",
3859
4008
  "data-testid": "collections-refresh-note"
3860
4009
  };
3861
- var _hoisted_17$4 = { class: "flex-1" };
3862
- var _hoisted_18$4 = {
4010
+ var _hoisted_19$3 = { class: "flex-1" };
4011
+ var _hoisted_20$3 = {
3863
4012
  key: 2,
3864
4013
  class: "px-6 py-3 bg-white border-b border-slate-100 flex items-center justify-between gap-4"
3865
4014
  };
3866
- var _hoisted_19$2 = {
4015
+ var _hoisted_21$3 = {
3867
4016
  key: 0,
3868
4017
  class: "relative flex-1 max-w-md"
3869
4018
  };
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" };
4019
+ var _hoisted_22$3 = ["placeholder", "aria-label"];
3873
4020
  var _hoisted_23$2 = ["aria-label"];
3874
- var _hoisted_24$1 = ["aria-pressed"];
3875
- var _hoisted_25$1 = ["aria-pressed"];
3876
- var _hoisted_26$1 = ["aria-pressed"];
3877
- var _hoisted_27$1 = [
4021
+ var _hoisted_24$1 = { class: "flex items-center gap-2" };
4022
+ var _hoisted_25$1 = ["aria-label"];
4023
+ var _hoisted_26$1 = [
4024
+ "title",
4025
+ "aria-label",
4026
+ "aria-pressed",
4027
+ "data-testid",
4028
+ "onClick"
4029
+ ];
4030
+ var _hoisted_27$1 = {
4031
+ class: "material-icons text-sm",
4032
+ "aria-hidden": "true"
4033
+ };
4034
+ var _hoisted_28 = ["aria-label"];
4035
+ var _hoisted_29 = ["aria-pressed"];
4036
+ var _hoisted_30 = ["aria-pressed"];
4037
+ var _hoisted_31 = ["aria-pressed"];
4038
+ var _hoisted_32 = [
3878
4039
  "aria-pressed",
3879
4040
  "data-testid",
3880
4041
  "onClick"
3881
4042
  ];
3882
- var _hoisted_28 = { class: "material-icons text-sm" };
3883
- var _hoisted_29 = [
4043
+ var _hoisted_33 = { class: "material-icons text-sm" };
4044
+ var _hoisted_34 = [
3884
4045
  "title",
3885
4046
  "aria-label",
3886
4047
  "aria-expanded"
3887
4048
  ];
3888
- var _hoisted_30 = {
4049
+ var _hoisted_35 = {
3889
4050
  key: 0,
3890
4051
  class: "absolute left-0 top-full mt-1 z-20 min-w-max rounded border border-slate-200 bg-white shadow-lg py-1",
3891
4052
  "data-testid": "collection-view-add-menu"
3892
4053
  };
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 = {
3899
- key: 3,
4054
+ var _hoisted_36 = ["title", "aria-label"];
4055
+ var _hoisted_37 = ["value", "aria-label"];
4056
+ var _hoisted_38 = ["value"];
4057
+ var _hoisted_39 = ["value", "aria-label"];
4058
+ var _hoisted_40 = ["value"];
4059
+ var _hoisted_41 = {
4060
+ key: 4,
3900
4061
  class: "text-[10px] text-slate-400 font-bold uppercase tracking-wider select-none"
3901
4062
  };
3902
- var _hoisted_37 = {
4063
+ var _hoisted_42 = {
3903
4064
  key: 3,
3904
4065
  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",
3905
4066
  "data-testid": "collections-data-issues"
3906
4067
  };
3907
- var _hoisted_38 = { class: "flex-1" };
3908
- var _hoisted_39 = { class: "flex-1 overflow-auto" };
3909
- var _hoisted_40 = {
4068
+ var _hoisted_43 = { class: "flex-1" };
4069
+ var _hoisted_44 = { class: "flex-1 overflow-auto" };
4070
+ var _hoisted_45 = {
3910
4071
  key: 0,
3911
4072
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-500 gap-3"
3912
4073
  };
3913
- var _hoisted_41 = {
4074
+ var _hoisted_46 = {
3914
4075
  key: 1,
3915
4076
  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"
3916
4077
  };
3917
- var _hoisted_42 = { key: 2 };
3918
- var _hoisted_43 = {
4078
+ var _hoisted_47 = { key: 2 };
4079
+ var _hoisted_48 = {
3919
4080
  key: 3,
3920
4081
  class: "p-4"
3921
4082
  };
3922
- var _hoisted_44 = {
4083
+ var _hoisted_49 = {
3923
4084
  key: 4,
3924
4085
  class: "h-full flex flex-col"
3925
4086
  };
3926
- var _hoisted_45 = {
4087
+ var _hoisted_50 = {
3927
4088
  key: 0,
3928
4089
  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",
3929
4090
  "data-testid": "collections-inline-error"
3930
4091
  };
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 = {
4092
+ var _hoisted_51 = { class: "flex-1" };
4093
+ var _hoisted_52 = ["aria-label"];
4094
+ var _hoisted_53 = { class: "flex-1 min-h-0 px-3 py-2" };
4095
+ var _hoisted_54 = {
3935
4096
  key: 5,
3936
4097
  class: "h-full",
3937
4098
  "data-testid": "collection-custom-view-body"
3938
4099
  };
3939
- var _hoisted_50 = {
4100
+ var _hoisted_55 = {
3940
4101
  key: 6,
3941
4102
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
3942
4103
  };
3943
- var _hoisted_51 = { class: "font-semibold text-slate-600" };
3944
- var _hoisted_52 = {
4104
+ var _hoisted_56 = { class: "font-semibold text-slate-600" };
4105
+ var _hoisted_57 = {
3945
4106
  key: 7,
3946
4107
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
3947
4108
  };
3948
- var _hoisted_53 = { class: "font-semibold text-slate-600" };
3949
- var _hoisted_54 = {
4109
+ var _hoisted_58 = { class: "font-semibold text-slate-600" };
4110
+ var _hoisted_59 = {
3950
4111
  key: 8,
3951
4112
  class: "overflow-x-auto [container-type:inline-size]"
3952
4113
  };
3953
- var _hoisted_55 = {
4114
+ var _hoisted_60 = {
3954
4115
  key: 0,
3955
4116
  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",
3956
4117
  "data-testid": "collections-inline-error"
3957
4118
  };
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 = [
4119
+ var _hoisted_61 = { class: "flex-1" };
4120
+ var _hoisted_62 = ["aria-label"];
4121
+ var _hoisted_63 = { class: "min-w-full text-xs" };
4122
+ var _hoisted_64 = { class: "bg-slate-50 border-b border-slate-200" };
4123
+ var _hoisted_65 = ["aria-sort"];
4124
+ var _hoisted_66 = { class: "flex items-center gap-1" };
4125
+ var _hoisted_67 = ["title"];
4126
+ var _hoisted_68 = [
3966
4127
  "data-testid",
3967
4128
  "aria-label",
3968
4129
  "onClick",
3969
4130
  "onPointerenter"
3970
4131
  ];
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 = [
4132
+ var _hoisted_69 = { class: "material-icons text-base align-middle" };
4133
+ var _hoisted_70 = { class: "divide-y divide-slate-100 bg-white" };
4134
+ var _hoisted_71 = [
3974
4135
  "aria-label",
3975
4136
  "data-testid",
3976
4137
  "onClick",
3977
4138
  "onKeydown"
3978
4139
  ];
3979
- var _hoisted_67 = [
4140
+ var _hoisted_72 = [
3980
4141
  "checked",
3981
4142
  "disabled",
3982
4143
  "data-testid",
3983
4144
  "aria-label",
3984
4145
  "onChange"
3985
4146
  ];
3986
- var _hoisted_68 = [
4147
+ var _hoisted_73 = [
3987
4148
  "checked",
3988
4149
  "disabled",
3989
4150
  "data-testid",
3990
4151
  "aria-label",
3991
4152
  "onChange"
3992
4153
  ];
3993
- var _hoisted_69 = {
3994
- key: 2,
4154
+ var _hoisted_74 = ["data-testid", "aria-label"];
4155
+ var _hoisted_75 = {
4156
+ key: 3,
3995
4157
  class: "block truncate"
3996
4158
  };
3997
- var _hoisted_70 = [
4159
+ var _hoisted_76 = [
3998
4160
  "href",
3999
4161
  "tabindex",
4000
4162
  "data-testid",
4001
4163
  "onClick",
4002
4164
  "onKeydown"
4003
4165
  ];
4004
- var _hoisted_71 = [
4166
+ var _hoisted_77 = [
4005
4167
  "value",
4006
4168
  "disabled",
4007
4169
  "data-testid",
4008
4170
  "aria-label",
4009
4171
  "onChange"
4010
4172
  ];
4011
- var _hoisted_72 = {
4173
+ var _hoisted_78 = {
4012
4174
  key: 0,
4013
4175
  value: ""
4014
4176
  };
4015
- var _hoisted_73 = ["value"];
4016
- var _hoisted_74 = {
4017
- key: 4,
4177
+ var _hoisted_79 = ["value"];
4178
+ var _hoisted_80 = {
4179
+ key: 5,
4018
4180
  class: "block truncate tabular-nums font-semibold text-slate-900"
4019
4181
  };
4020
- var _hoisted_75 = {
4021
- key: 5,
4182
+ var _hoisted_81 = {
4183
+ key: 6,
4022
4184
  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"
4023
4185
  };
4024
- var _hoisted_76 = {
4025
- key: 6,
4186
+ var _hoisted_82 = {
4187
+ key: 7,
4026
4188
  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"
4027
4189
  };
4028
- var _hoisted_77 = ["data-testid"];
4029
- var _hoisted_78 = ["href", "data-testid"];
4030
- var _hoisted_79 = ["href", "data-testid"];
4031
- var _hoisted_80 = [
4190
+ var _hoisted_83 = ["data-testid"];
4191
+ var _hoisted_84 = ["href", "data-testid"];
4192
+ var _hoisted_85 = ["href", "data-testid"];
4193
+ var _hoisted_86 = [
4032
4194
  "href",
4033
4195
  "data-testid",
4034
4196
  "onClick"
4035
4197
  ];
4036
- var _hoisted_81 = {
4037
- key: 11,
4198
+ var _hoisted_87 = {
4199
+ key: 12,
4038
4200
  class: "block truncate text-slate-600"
4039
4201
  };
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 = {
4202
+ var _hoisted_88 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
4203
+ var _hoisted_89 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
4204
+ var _hoisted_90 = { class: "flex-1" };
4205
+ var _hoisted_91 = {
4044
4206
  id: "collections-chat-title",
4045
4207
  class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
4046
4208
  };
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"];
4209
+ var _hoisted_92 = { class: "text-xs text-slate-400 font-semibold" };
4210
+ var _hoisted_93 = ["aria-label"];
4211
+ var _hoisted_94 = { class: "px-6 py-5" };
4212
+ var _hoisted_95 = ["placeholder", "onKeydown"];
4213
+ var _hoisted_96 = { class: "px-6 py-3.5 border-t border-slate-100 flex items-center justify-end gap-2 bg-slate-50/50" };
4214
+ var _hoisted_97 = ["disabled"];
4053
4215
  /** `slug` / `selected` are supplied only in EMBEDDED mode (the
4054
4216
  * `presentCollection` chat card mounts this component and drives both
4055
4217
  * from the tool result). In standalone route mode (the
@@ -4060,6 +4222,7 @@ var _hoisted_91 = ["disabled"];
4060
4222
  * is our "rendered inside a chat" signal. When set, chat-triggering
4061
4223
  * actions send into the current session instead of spawning a new
4062
4224
  * chat (see `runAction` / `submitChat`). */
4225
+ var COMPLETION_CHIP_KEY = "__completion";
4063
4226
  var LIVE_REFRESH_DEBOUNCE_MS = 150;
4064
4227
  //#endregion
4065
4228
  //#region src/vue/components/CollectionView.vue
@@ -4186,6 +4349,84 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4186
4349
  if (!query) return items.value;
4187
4350
  return items.value.filter((item) => itemMatchesQuery(item, query));
4188
4351
  });
4352
+ /** Chip key (state/testid/localStorage) for the synthesized
4353
+ * legacy-completion chip. Field names are unrestricted strings, so a
4354
+ * schema COULD declare a field with this exact name — the chip list
4355
+ * below skips synthesizing in that case, and the predicate dispatch
4356
+ * keys off the structural `synthetic` marker, never this string. */
4357
+ function storedFlagFiltersFor(slug) {
4358
+ return slug ? readCollectionFlagFilters(slug) : {};
4359
+ }
4360
+ const flagFilters = ref(storedFlagFiltersFor(activeSlug.value));
4361
+ const flagChips = computed(() => {
4362
+ const schema = collection.value?.schema;
4363
+ if (!schema) return [];
4364
+ const chips = Object.entries(schema.fields).filter(([, field]) => field.type === "flag").map(([key, field]) => ({
4365
+ key,
4366
+ label: field.label ?? key
4367
+ }));
4368
+ if (schema.completionField && schema.completionDoneValues && schema.fields[schema.completionField]?.type !== "flag" && schema.fields[COMPLETION_CHIP_KEY] === void 0) chips.push({
4369
+ key: COMPLETION_CHIP_KEY,
4370
+ label: t("collectionsView.flagDoneChip"),
4371
+ synthetic: true
4372
+ });
4373
+ return chips;
4374
+ });
4375
+ /** Own-property read of a chip's active mode. Field names may shadow
4376
+ * `Object.prototype` members (`toString`, `valueOf`, …) — a plain
4377
+ * `filters[key]` on such a key reads the inherited function, which
4378
+ * renders as an "active" chip that can never cycle (Codex review on
4379
+ * PR #2176). Every chip-state read goes through here. */
4380
+ function flagFilterMode(key) {
4381
+ const filters = flagFilters.value;
4382
+ return Object.hasOwn(filters, key) ? filters[key] : void 0;
4383
+ }
4384
+ /** A flag FIELD's computed boolean for one row (list cells + sort):
4385
+ * the enriched record's value, so a flag over derived/rollup inputs
4386
+ * reads correctly. */
4387
+ function flagValueOf(key, item) {
4388
+ return render.deriveRecord(item)[key] === true;
4389
+ }
4390
+ /** The chip's boolean for one row — `itemIsDone` for the synthesized
4391
+ * completion chip, the computed flag value otherwise. */
4392
+ function chipMatches(chip, item) {
4393
+ const schema = collection.value?.schema;
4394
+ if (!schema) return false;
4395
+ return chip.synthetic ? itemIsDone(schema, item) : flagValueOf(chip.key, item);
4396
+ }
4397
+ /** `filteredItems` further narrowed by every ACTIVE chip (AND). Consumed
4398
+ * only by the table (sortedItems / count summary / empty state). */
4399
+ const tableFilteredItems = computed(() => {
4400
+ const active = flagChips.value.filter((chip) => flagFilterMode(chip.key) !== void 0);
4401
+ if (active.length === 0) return filteredItems.value;
4402
+ return filteredItems.value.filter((item) => active.every((chip) => chipMatches(chip, item) === (flagFilterMode(chip.key) === "only")));
4403
+ });
4404
+ /** Cycle a chip all → hide → only → all. */
4405
+ function cycleFlagFilter(key) {
4406
+ const current = flagFilterMode(key);
4407
+ const next = current === void 0 ? "hide" : current === "hide" ? "only" : void 0;
4408
+ const rest = Object.fromEntries(Object.entries(flagFilters.value).filter(([entry]) => entry !== key));
4409
+ flagFilters.value = next ? {
4410
+ ...rest,
4411
+ [key]: next
4412
+ } : rest;
4413
+ }
4414
+ function flagChipIcon(key) {
4415
+ const mode = flagFilterMode(key);
4416
+ return mode === "hide" ? "visibility_off" : mode === "only" ? "filter_alt" : "visibility";
4417
+ }
4418
+ function flagChipClass(key) {
4419
+ const mode = flagFilterMode(key);
4420
+ if (mode === "hide") return "bg-slate-600 text-white";
4421
+ if (mode === "only") return "bg-indigo-600 text-white";
4422
+ return "bg-white text-slate-500 border border-slate-200 hover:bg-slate-50";
4423
+ }
4424
+ function flagChipTitle(chip) {
4425
+ const mode = flagFilterMode(chip.key);
4426
+ if (mode === "hide") return t("collectionsView.flagFilterHide", { label: chip.label });
4427
+ if (mode === "only") return t("collectionsView.flagFilterOnly", { label: chip.label });
4428
+ return t("collectionsView.flagFilterAll", { label: chip.label });
4429
+ }
4189
4430
  function storedSortFor(slug) {
4190
4431
  return slug && readCollectionSort(slug) || null;
4191
4432
  }
@@ -4232,10 +4473,11 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4232
4473
  default: return stringSortValue(raw);
4233
4474
  }
4234
4475
  }
4235
- /** Comparable value for one row under the active field. Toggle and derived
4236
- * need the whole record; every other type keys off the raw cell. */
4476
+ /** Comparable value for one row under the active field. Toggle, flag, and
4477
+ * derived need the whole record; every other type keys off the raw cell. */
4237
4478
  function sortValueOf(field, key, item) {
4238
4479
  if (field.type === "toggle") return boolSortValue(toggleChecked(item, field));
4480
+ if (field.type === "flag") return boolSortValue(flagValueOf(key, item));
4239
4481
  if (field.type === "derived") return derivedSortValue(field, key, item);
4240
4482
  return scalarSortValue(field, item[key]);
4241
4483
  }
@@ -4251,8 +4493,8 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4251
4493
  const sortedItems = computed(() => {
4252
4494
  const state = sortState.value;
4253
4495
  const field = state ? collection.value?.schema.fields[state.field] : void 0;
4254
- if (!state || !field) return filteredItems.value;
4255
- return sortItems(filteredItems.value, state.direction, (item) => sortValueOf(field, state.field, item));
4496
+ if (!state || !field) return tableFilteredItems.value;
4497
+ return sortItems(tableFilteredItems.value, state.direction, (item) => sortValueOf(field, state.field, item));
4256
4498
  });
4257
4499
  /** Stringified primary-key value for a row (the row's stable identity). */
4258
4500
  function rowId(item) {
@@ -4603,10 +4845,22 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4603
4845
  /** True when the current collection declares `schema.singleton` —
4604
4846
  * exactly one record, its primary key fixed to the declared value. */
4605
4847
  const isSingleton = computed(() => Boolean(collection.value?.schema.singleton));
4848
+ /** True when the collection is backed by an external `dataSource` (CSV) —
4849
+ * read-only in every write surface here; the server enforces the same
4850
+ * rule with 405s, this just keeps dead controls off the screen. */
4851
+ const isReadOnly = computed(() => collection.value?.schema.dataSource !== void 0);
4852
+ /** File-explorer route for the dataSource file (the one editable thing
4853
+ * about a read-only collection), or null on a router-less host. */
4854
+ const dataSourceRoute = computed(() => {
4855
+ const sourcePath = collection.value?.schema.dataSource?.path;
4856
+ return sourcePath ? fileRoutePath(sourcePath) : null;
4857
+ });
4606
4858
  /** Whether the Add button should show. Always for a normal collection;
4607
- * for a singleton only until its one record exists. */
4859
+ * for a singleton only until its one record exists; never for a
4860
+ * read-only (dataSource) collection. */
4608
4861
  const canCreate = computed(() => {
4609
4862
  if (!collection.value) return false;
4863
+ if (isReadOnly.value) return false;
4610
4864
  return !(isSingleton.value && items.value.length > 0);
4611
4865
  });
4612
4866
  const canDeleteCollection = computed(() => {
@@ -4998,7 +5252,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
4998
5252
  * race the in-flight one. On failure, roll the cell back and surface the
4999
5253
  * error. Bypasses the detail/edit panel entirely. */
5000
5254
  async function commitInlineEdit(item, key, field, raw) {
5001
- if (!collection.value) return;
5255
+ if (!collection.value || isReadOnly.value) return;
5002
5256
  const { slug } = collection.value;
5003
5257
  const itemId = rowId(item);
5004
5258
  if (!itemId || inlineSavingRows.value.has(itemId)) return;
@@ -5186,6 +5440,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5186
5440
  kanbanOverride.value = null;
5187
5441
  addMenuOpen.value = false;
5188
5442
  sortState.value = storedSortFor(slug);
5443
+ flagFilters.value = storedFlagFiltersFor(slug);
5189
5444
  }
5190
5445
  if (slug) loadCollection(slug);
5191
5446
  else {
@@ -5240,6 +5495,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5240
5495
  calendarAnchorField,
5241
5496
  kanbanGroupField,
5242
5497
  sortState,
5498
+ flagFilters,
5243
5499
  loading
5244
5500
  ], () => {
5245
5501
  if (embedded.value) emit("viewStateChange", {
@@ -5250,6 +5506,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5250
5506
  if (activeSlug.value && !loading.value && collection.value) {
5251
5507
  if (!embedded.value) writeCollectionViewMode(activeSlug.value, activeView.value);
5252
5508
  writeCollectionSort(activeSlug.value, sortState.value);
5509
+ writeCollectionFlagFilters(activeSlug.value, flagFilters.value);
5253
5510
  }
5254
5511
  });
5255
5512
  watch(activeSelected, () => {
@@ -5268,9 +5525,15 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5268
5525
  "aria-label": unref(t)("collectionsView.backToIndex"),
5269
5526
  "data-testid": "collections-back",
5270
5527
  onClick: goBack
5271
- }, [..._cache[26] || (_cache[26] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : createCommentVNode("", true),
5528
+ }, [..._cache[27] || (_cache[27] = [createElementVNode("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : createCommentVNode("", true),
5272
5529
  collection.value ? (openBlock(), createElementBlock("div", _hoisted_4$5, [createElementVNode("span", _hoisted_5$5, toDisplayString(collection.value.icon), 1)])) : createCommentVNode("", true),
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)]),
5530
+ 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, [createTextVNode(toDisplayString(collection.value.slug) + " ", 1), isReadOnly.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("span", _hoisted_9$4, [_cache[28] || (_cache[28] = createElementVNode("span", { class: "material-icons text-[11px]" }, "lock", -1)), createTextVNode(" " + toDisplayString(unref(t)("collectionsView.readonlyChip")), 1)]), dataSourceRoute.value ? (openBlock(), createElementBlock("a", {
5531
+ key: 0,
5532
+ href: dataSourceRoute.value ?? void 0,
5533
+ class: "ml-1 normal-case tracking-normal font-mono font-normal text-slate-500 hover:text-indigo-700 hover:underline",
5534
+ "data-testid": "collections-readonly-source",
5535
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(activatePathLink)($event, dataSourceRoute.value ?? "", true))
5536
+ }, toDisplayString(collection.value.schema.dataSource?.path), 9, _hoisted_10$4)) : createCommentVNode("", true)], 64)) : createCommentVNode("", true)])) : createCommentVNode("", true)]),
5274
5537
  collection.value && !embedded.value ? (openBlock(), createBlock(resolveDynamicComponent(unref(pinToggle)), {
5275
5538
  key: 2,
5276
5539
  kind: isFeedRoute.value ? "feed" : "collection",
@@ -5290,14 +5553,14 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5290
5553
  disabled: refreshing.value,
5291
5554
  "data-testid": "collections-refresh-feed",
5292
5555
  onClick: refreshFeed
5293
- }, [createElementVNode("span", _hoisted_10$4, toDisplayString(refreshing.value ? "hourglass_empty" : "refresh"), 1), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.refreshFeed")), 1)], 8, _hoisted_9$4)) : createCommentVNode("", true),
5556
+ }, [createElementVNode("span", _hoisted_12$4, toDisplayString(refreshing.value ? "hourglass_empty" : "refresh"), 1), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.refreshFeed")), 1)], 8, _hoisted_11$4)) : createCommentVNode("", true),
5294
5557
  collection.value ? (openBlock(), createElementBlock("button", {
5295
5558
  key: 4,
5296
5559
  type: "button",
5297
5560
  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",
5298
5561
  "data-testid": "collections-chat",
5299
5562
  onClick: openChat
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),
5563
+ }, [_cache[29] || (_cache[29] = createElementVNode("span", { class: "material-icons text-sm" }, "forum", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.chat")), 1)])) : createCommentVNode("", true),
5301
5564
  (openBlock(true), createElementBlock(Fragment, null, renderList(collectionActions.value, (action) => {
5302
5565
  return openBlock(), createElementBlock("button", {
5303
5566
  key: action.id,
@@ -5306,7 +5569,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5306
5569
  disabled: collectionActionPending.value || isActionRunning(action.id),
5307
5570
  "data-testid": `collections-action-${action.id}`,
5308
5571
  onClick: ($event) => runCollectionAction(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);
5572
+ }, [isActionRunning(action.id) ? (openBlock(), createElementBlock("span", _hoisted_14$4, "progress_activity")) : action.icon ? (openBlock(), createElementBlock("span", _hoisted_15$4, toDisplayString(action.icon), 1)) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(action.label), 1)], 8, _hoisted_13$4);
5310
5573
  }), 128)),
5311
5574
  canCreate.value && !calendarActive.value ? (openBlock(), createElementBlock("button", {
5312
5575
  key: 5,
@@ -5314,7 +5577,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5314
5577
  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",
5315
5578
  "data-testid": "collections-add-item",
5316
5579
  onClick: openCreate
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),
5580
+ }, [_cache[30] || (_cache[30] = createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)), createElementVNode("span", null, toDisplayString(unref(t)("common.add")), 1)])) : createCommentVNode("", true),
5318
5581
  canDeleteCollection.value && !embedded.value ? (openBlock(), createElementBlock("button", {
5319
5582
  key: 6,
5320
5583
  type: "button",
@@ -5323,7 +5586,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5323
5586
  "aria-label": unref(t)("collectionsView.deleteCollection"),
5324
5587
  "data-testid": "collections-delete",
5325
5588
  onClick: confirmCollectionDelete
5326
- }, [..._cache[29] || (_cache[29] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : createCommentVNode("", true),
5589
+ }, [..._cache[31] || (_cache[31] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_16$4)) : createCommentVNode("", true),
5327
5590
  canDeleteFeed.value && !embedded.value ? (openBlock(), createElementBlock("button", {
5328
5591
  key: 7,
5329
5592
  type: "button",
@@ -5332,28 +5595,45 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5332
5595
  "aria-label": unref(t)("collectionsView.deleteFeed"),
5333
5596
  "data-testid": "feeds-delete",
5334
5597
  onClick: confirmFeedDelete
5335
- }, [..._cache[30] || (_cache[30] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_15$4)) : createCommentVNode("", true)
5598
+ }, [..._cache[32] || (_cache[32] = [createElementVNode("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_17$4)) : createCommentVNode("", true)
5336
5599
  ])) : createCommentVNode("", true),
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)),
5600
+ refreshNote.value ? (openBlock(), createElementBlock("div", _hoisted_18$4, [_cache[33] || (_cache[33] = createElementVNode("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), createElementVNode("span", _hoisted_19$3, toDisplayString(refreshNote.value), 1)])) : createCommentVNode("", true),
5601
+ collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? (openBlock(), createElementBlock("div", _hoisted_20$3, [!__props.hideSearch && items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_21$3, [
5602
+ _cache[35] || (_cache[35] = 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)),
5340
5603
  withDirectives(createElementVNode("input", {
5341
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
5604
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => searchQuery.value = $event),
5342
5605
  type: "text",
5343
5606
  placeholder: unref(t)("collectionsView.searchPlaceholder"),
5344
5607
  "aria-label": unref(t)("collectionsView.searchPlaceholder"),
5345
5608
  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"
5346
- }, null, 8, _hoisted_20$2), [[vModelText, searchQuery.value]]),
5609
+ }, null, 8, _hoisted_22$3), [[vModelText, searchQuery.value]]),
5347
5610
  searchQuery.value ? (openBlock(), createElementBlock("button", {
5348
5611
  key: 0,
5349
5612
  type: "button",
5350
5613
  "aria-label": unref(t)("collectionsView.clearSearch"),
5351
5614
  class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
5352
- onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
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, [
5355
- !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? (openBlock(), createElementBlock("div", {
5615
+ onClick: _cache[2] || (_cache[2] = ($event) => searchQuery.value = "")
5616
+ }, [..._cache[34] || (_cache[34] = [createElementVNode("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_23$2)) : createCommentVNode("", true)
5617
+ ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_24$1, [
5618
+ activeView.value === "table" && flagChips.value.length > 0 && items.value.length > 0 ? (openBlock(), createElementBlock("div", {
5356
5619
  key: 0,
5620
+ class: "flex items-center gap-0.5",
5621
+ role: "group",
5622
+ "aria-label": unref(t)("collectionsView.flagFilterGroup")
5623
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(flagChips.value, (chip) => {
5624
+ return openBlock(), createElementBlock("button", {
5625
+ key: chip.key,
5626
+ type: "button",
5627
+ class: normalizeClass(["h-8 px-2.5 flex items-center gap-1 rounded text-xs font-bold transition-colors", flagChipClass(chip.key)]),
5628
+ title: flagChipTitle(chip),
5629
+ "aria-label": flagChipTitle(chip),
5630
+ "aria-pressed": flagFilterMode(chip.key) !== void 0,
5631
+ "data-testid": `collections-flag-chip-${chip.key}`,
5632
+ onClick: ($event) => cycleFlagFilter(chip.key)
5633
+ }, [createElementVNode("span", _hoisted_27$1, toDisplayString(flagChipIcon(chip.key)), 1), createElementVNode("span", null, toDisplayString(chip.label), 1)], 10, _hoisted_26$1);
5634
+ }), 128))], 8, _hoisted_25$1)) : createCommentVNode("", true),
5635
+ !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? (openBlock(), createElementBlock("div", {
5636
+ key: 1,
5357
5637
  class: "flex gap-0.5",
5358
5638
  role: "group",
5359
5639
  "aria-label": unref(t)("collectionsView.viewToggle")
@@ -5363,24 +5643,24 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5363
5643
  class: normalizeClass(["h-8 px-2.5 flex items-center gap-1 rounded text-xs font-bold transition-colors", activeView.value === "table" ? "bg-indigo-600 text-white" : "bg-white text-slate-500 border border-slate-200 hover:bg-slate-50"]),
5364
5644
  "aria-pressed": activeView.value === "table",
5365
5645
  "data-testid": "collection-view-toggle-table",
5366
- onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
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),
5646
+ onClick: _cache[3] || (_cache[3] = ($event) => setView("table"))
5647
+ }, [_cache[36] || (_cache[36] = createElementVNode("span", { class: "material-icons text-sm" }, "table_rows", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewTable")), 1)], 10, _hoisted_29),
5368
5648
  hasCalendar.value ? (openBlock(), createElementBlock("button", {
5369
5649
  key: 0,
5370
5650
  type: "button",
5371
5651
  class: normalizeClass(["h-8 px-2.5 flex items-center gap-1 rounded text-xs font-bold transition-colors", activeView.value === "calendar" ? "bg-indigo-600 text-white" : "bg-white text-slate-500 border border-slate-200 hover:bg-slate-50"]),
5372
5652
  "aria-pressed": activeView.value === "calendar",
5373
5653
  "data-testid": "collection-view-toggle-calendar",
5374
- onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
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),
5654
+ onClick: _cache[4] || (_cache[4] = ($event) => setView("calendar"))
5655
+ }, [_cache[37] || (_cache[37] = createElementVNode("span", { class: "material-icons text-sm" }, "calendar_month", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_30)) : createCommentVNode("", true),
5376
5656
  hasKanban.value ? (openBlock(), createElementBlock("button", {
5377
5657
  key: 1,
5378
5658
  type: "button",
5379
5659
  class: normalizeClass(["h-8 px-2.5 flex items-center gap-1 rounded text-xs font-bold transition-colors", activeView.value === "kanban" ? "bg-indigo-600 text-white" : "bg-white text-slate-500 border border-slate-200 hover:bg-slate-50"]),
5380
5660
  "aria-pressed": activeView.value === "kanban",
5381
5661
  "data-testid": "collection-view-toggle-kanban",
5382
- onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
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),
5662
+ onClick: _cache[5] || (_cache[5] = ($event) => setView("kanban"))
5663
+ }, [_cache[38] || (_cache[38] = createElementVNode("span", { class: "material-icons text-sm" }, "view_kanban", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_31)) : createCommentVNode("", true),
5384
5664
  (openBlock(true), createElementBlock(Fragment, null, renderList(customViews.value, (cv) => {
5385
5665
  return openBlock(), createElementBlock("button", {
5386
5666
  key: cv.id,
@@ -5389,7 +5669,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5389
5669
  "aria-pressed": activeView.value === unref(customViewKey)(cv.id),
5390
5670
  "data-testid": `collection-view-custom-${cv.id}`,
5391
5671
  onClick: ($event) => setCustomView(cv.id)
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);
5672
+ }, [createElementVNode("span", _hoisted_33, toDisplayString(cv.icon || (cv.target === "mobile" ? "smartphone" : "dashboard_customize")), 1), createElementVNode("span", null, toDisplayString(cv.label), 1)], 10, _hoisted_32);
5393
5673
  }), 128)),
5394
5674
  canAddCustomView.value ? (openBlock(), createElementBlock("div", {
5395
5675
  key: 2,
@@ -5404,17 +5684,17 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5404
5684
  "aria-expanded": addMenuOpen.value,
5405
5685
  "data-testid": "collection-view-add",
5406
5686
  onClick: onAddViewClick
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", {
5687
+ }, [..._cache[39] || (_cache[39] = [createElementVNode("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_34), addMenuOpen.value ? (openBlock(), createElementBlock("div", _hoisted_35, [createElementVNode("button", {
5408
5688
  type: "button",
5409
5689
  class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
5410
5690
  "data-testid": "collection-view-add-desktop",
5411
- onClick: _cache[5] || (_cache[5] = ($event) => addCustomView("desktop"))
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", {
5691
+ onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("desktop"))
5692
+ }, [_cache[40] || (_cache[40] = createElementVNode("span", { class: "material-icons text-sm" }, "dashboard_customize", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addViewDesktop")), 1)]), createElementVNode("button", {
5413
5693
  type: "button",
5414
5694
  class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
5415
5695
  "data-testid": "collection-view-add-mobile",
5416
- onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("mobile"))
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),
5696
+ onClick: _cache[7] || (_cache[7] = ($event) => addCustomView("mobile"))
5697
+ }, [_cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-sm" }, "smartphone", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.addViewMobile")), 1)])])) : createCommentVNode("", true)], 512)) : createCommentVNode("", true),
5418
5698
  canConfigureViews.value ? (openBlock(), createElementBlock("button", {
5419
5699
  key: 3,
5420
5700
  type: "button",
@@ -5422,51 +5702,51 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5422
5702
  title: unref(t)("collectionsView.config.open"),
5423
5703
  "aria-label": unref(t)("collectionsView.config.open"),
5424
5704
  "data-testid": "collection-config-open",
5425
- onClick: _cache[7] || (_cache[7] = ($event) => configOpen.value = true)
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),
5705
+ onClick: _cache[8] || (_cache[8] = ($event) => configOpen.value = true)
5706
+ }, [..._cache[42] || (_cache[42] = [createElementVNode("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_36)) : createCommentVNode("", true)
5707
+ ], 8, _hoisted_28)) : createCommentVNode("", true),
5428
5708
  calendarActive.value && dateFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
5429
- key: 1,
5709
+ key: 2,
5430
5710
  value: calendarAnchorField.value,
5431
5711
  class: "h-8 px-2 rounded border border-slate-200 bg-white text-xs font-semibold text-slate-600 focus:outline-none focus:border-indigo-500 cursor-pointer",
5432
5712
  "aria-label": unref(t)("collectionsView.calendarFieldLabel"),
5433
5713
  "data-testid": "collection-calendar-field",
5434
- onChange: _cache[8] || (_cache[8] = ($event) => anchorOverride.value = $event.target.value)
5714
+ onChange: _cache[9] || (_cache[9] = ($event) => anchorOverride.value = $event.target.value)
5435
5715
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(dateFields.value, (key) => {
5436
5716
  return openBlock(), createElementBlock("option", {
5437
5717
  key,
5438
5718
  value: key
5439
- }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_33);
5440
- }), 128))], 40, _hoisted_32)) : createCommentVNode("", true),
5719
+ }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_38);
5720
+ }), 128))], 40, _hoisted_37)) : createCommentVNode("", true),
5441
5721
  kanbanActive.value && enumFields.value.length > 1 ? (openBlock(), createElementBlock("select", {
5442
- key: 2,
5722
+ key: 3,
5443
5723
  value: kanbanGroupField.value,
5444
5724
  class: "h-8 px-2 rounded border border-slate-200 bg-white text-xs font-semibold text-slate-600 focus:outline-none focus:border-indigo-500 cursor-pointer",
5445
5725
  "aria-label": unref(t)("collectionsView.kanbanFieldLabel"),
5446
5726
  "data-testid": "collection-kanban-field",
5447
- onChange: _cache[9] || (_cache[9] = ($event) => kanbanOverride.value = $event.target.value)
5727
+ onChange: _cache[10] || (_cache[10] = ($event) => kanbanOverride.value = $event.target.value)
5448
5728
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(enumFields.value, (key) => {
5449
5729
  return openBlock(), createElementBlock("option", {
5450
5730
  key,
5451
5731
  value: key
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", {
5455
- shown: filteredItems.value.length,
5732
+ }, toDisplayString(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_40);
5733
+ }), 128))], 40, _hoisted_39)) : createCommentVNode("", true),
5734
+ items.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_41, toDisplayString(unref(t)("collectionsView.searchSummary", {
5735
+ shown: activeView.value === "table" ? tableFilteredItems.value.length : filteredItems.value.length,
5456
5736
  total: items.value.length
5457
5737
  })), 1)) : createCommentVNode("", true)
5458
5738
  ])])) : createCommentVNode("", true),
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),
5739
+ collection.value && dataIssues.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_42, [
5740
+ _cache[44] || (_cache[44] = createElementVNode("span", { class: "material-icons text-amber-600" }, "warning", -1)),
5741
+ createElementVNode("span", _hoisted_43, toDisplayString(unref(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
5462
5742
  createElementVNode("button", {
5463
5743
  type: "button",
5464
5744
  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",
5465
5745
  "data-testid": "collections-repair",
5466
5746
  onClick: repairCollection
5467
- }, [_cache[41] || (_cache[41] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
5747
+ }, [_cache[43] || (_cache[43] = createElementVNode("span", { class: "material-icons text-sm" }, "build", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.repair")), 1)])
5468
5748
  ])) : createCommentVNode("", true),
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, {
5749
+ createElementVNode("div", _hoisted_44, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_45, [_cache[45] || (_cache[45] = 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_46, [_cache[46] || (_cache[46] = 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_47)) : calendarActive.value ? (openBlock(), createElementBlock("div", _hoisted_48, [createVNode(CollectionCalendarView_default, {
5470
5750
  schema: collection.value.schema,
5471
5751
  items: filteredItems.value,
5472
5752
  "anchor-field": calendarAnchorField.value,
@@ -5502,7 +5782,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5502
5782
  }, {
5503
5783
  detail: withCtx(() => [createVNode(CollectionRecordPanel_default, {
5504
5784
  editing: editing.value,
5505
- "onUpdate:editing": _cache[10] || (_cache[10] = ($event) => editing.value = $event),
5785
+ "onUpdate:editing": _cache[11] || (_cache[11] = ($event) => editing.value = $event),
5506
5786
  collection: collection.value,
5507
5787
  viewing: viewing.value,
5508
5788
  saving: saving.value,
@@ -5515,13 +5795,14 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5515
5795
  "live-derived": liveDerived.value,
5516
5796
  "view-title": viewTitle.value,
5517
5797
  "is-singleton": isSingleton.value,
5798
+ readonly: isReadOnly.value,
5518
5799
  render: unref(render),
5519
5800
  locale: unref(locale),
5520
5801
  onSubmit: saveEditor,
5521
5802
  onCancel: cancelEditor,
5522
5803
  onEdit: editFromView,
5523
5804
  onClose: onDayClose,
5524
- onDelete: _cache[11] || (_cache[11] = ($event) => viewing.value && confirmDelete(viewing.value)),
5805
+ onDelete: _cache[12] || (_cache[12] = ($event) => viewing.value && confirmDelete(viewing.value)),
5525
5806
  onRunAction: runAction,
5526
5807
  onItemChat
5527
5808
  }, null, 8, [
@@ -5538,6 +5819,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5538
5819
  "live-derived",
5539
5820
  "view-title",
5540
5821
  "is-singleton",
5822
+ "readonly",
5541
5823
  "render",
5542
5824
  "locale"
5543
5825
  ])]),
@@ -5553,21 +5835,22 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5553
5835
  "selected",
5554
5836
  "can-create",
5555
5837
  "show-detail"
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),
5838
+ ])) : createCommentVNode("", true)])) : kanbanActive.value ? (openBlock(), createElementBlock("div", _hoisted_49, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_50, [
5839
+ _cache[48] || (_cache[48] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
5840
+ createElementVNode("span", _hoisted_51, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5559
5841
  createElementVNode("button", {
5560
5842
  type: "button",
5561
5843
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
5562
5844
  "aria-label": unref(t)("common.close"),
5563
- onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
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, {
5845
+ onClick: _cache[13] || (_cache[13] = ($event) => inlineError.value = null)
5846
+ }, [..._cache[47] || (_cache[47] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_52)
5847
+ ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_53, [createVNode(CollectionKanbanView_default, {
5566
5848
  schema: collection.value.schema,
5567
5849
  items: filteredItems.value,
5568
5850
  "group-field": kanbanGroupField.value,
5569
5851
  selected: viewing.value ? String(viewing.value[collection.value.schema.primaryKey] ?? "") : void 0,
5570
5852
  notified: notifiedSeverities.value,
5853
+ readonly: isReadOnly.value,
5571
5854
  onSelect: onCalendarSelect,
5572
5855
  onMove: onKanbanMove
5573
5856
  }, null, 8, [
@@ -5575,8 +5858,9 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5575
5858
  "items",
5576
5859
  "group-field",
5577
5860
  "selected",
5578
- "notified"
5579
- ])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_49, [activeCustomView.value.target === "mobile" ? (openBlock(), createBlock(CollectionRemoteViewPreview_default, {
5861
+ "notified",
5862
+ "readonly"
5863
+ ])])])) : activeCustomView.value ? (openBlock(), createElementBlock("div", _hoisted_54, [activeCustomView.value.target === "mobile" ? (openBlock(), createBlock(CollectionRemoteViewPreview_default, {
5580
5864
  key: 0,
5581
5865
  slug: collection.value.slug,
5582
5866
  view: activeCustomView.value,
@@ -5587,32 +5871,32 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5587
5871
  view: activeCustomView.value,
5588
5872
  onOpenItem: onCustomViewOpenItem,
5589
5873
  onStartChat: onCustomViewStartChat
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),
5874
+ }, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_55, [_cache[49] || (_cache[49] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), createElementVNode("p", _hoisted_56, toDisplayString(unref(t)(isReadOnly.value ? "collectionsView.itemsEmptyReadonly" : "collectionsView.itemsEmpty")), 1)])) : tableFilteredItems.value.length === 0 && editing.value?.mode !== "create" ? (openBlock(), createElementBlock("div", _hoisted_57, [
5875
+ _cache[50] || (_cache[50] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
5876
+ createElementVNode("p", _hoisted_58, toDisplayString(unref(t)("collectionsView.noMatchingItems")), 1),
5593
5877
  createElementVNode("button", {
5594
5878
  type: "button",
5595
5879
  class: "text-xs text-indigo-600 font-semibold hover:underline",
5596
- onClick: _cache[13] || (_cache[13] = ($event) => searchQuery.value = "")
5880
+ onClick: _cache[14] || (_cache[14] = ($event) => (searchQuery.value = "", flagFilters.value = {}))
5597
5881
  }, toDisplayString(unref(t)("collectionsView.clearSearch")), 1)
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),
5882
+ ])) : (openBlock(), createElementBlock("div", _hoisted_59, [inlineError.value ? (openBlock(), createElementBlock("div", _hoisted_60, [
5883
+ _cache[52] || (_cache[52] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)),
5884
+ createElementVNode("span", _hoisted_61, toDisplayString(unref(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5601
5885
  createElementVNode("button", {
5602
5886
  type: "button",
5603
5887
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
5604
5888
  "aria-label": unref(t)("common.close"),
5605
- onClick: _cache[14] || (_cache[14] = ($event) => inlineError.value = null)
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]) => {
5889
+ onClick: _cache[15] || (_cache[15] = ($event) => inlineError.value = null)
5890
+ }, [..._cache[51] || (_cache[51] = [createElementVNode("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_62)
5891
+ ])) : createCommentVNode("", true), createElementVNode("table", _hoisted_63, [createElementVNode("thead", null, [createElementVNode("tr", _hoisted_64, [(openBlock(true), createElementBlock(Fragment, null, renderList(listColumnFields.value, ([key, field]) => {
5608
5892
  return openBlock(), createElementBlock("th", {
5609
5893
  key,
5610
5894
  "aria-sort": unref(isSortableField)(field) ? sortAriaValue(key) : void 0,
5611
5895
  class: "px-5 py-3 font-bold text-slate-500 text-left uppercase tracking-wider whitespace-nowrap"
5612
- }, [createElementVNode("div", _hoisted_61, [createElementVNode("span", {
5896
+ }, [createElementVNode("div", _hoisted_66, [createElementVNode("span", {
5613
5897
  class: "truncate max-w-[14rem]",
5614
5898
  title: field.label
5615
- }, toDisplayString(field.label), 9, _hoisted_62), unref(isSortableField)(field) ? (openBlock(), createElementBlock("button", {
5899
+ }, toDisplayString(field.label), 9, _hoisted_67), unref(isSortableField)(field) ? (openBlock(), createElementBlock("button", {
5616
5900
  key: 0,
5617
5901
  type: "button",
5618
5902
  class: normalizeClass(["inline-flex items-center justify-center rounded p-0.5 -my-1 leading-none transition-colors", sortButtonClass(key)]),
@@ -5620,9 +5904,9 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5620
5904
  "aria-label": unref(t)("collectionsView.sortBy", { field: field.label }),
5621
5905
  onClick: withModifiers(($event) => cycleSort(key), ["stop"]),
5622
5906
  onPointerenter: ($event) => hoveredSortKey.value = key,
5623
- onPointerleave: _cache[15] || (_cache[15] = ($event) => hoveredSortKey.value = null)
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) => {
5907
+ onPointerleave: _cache[16] || (_cache[16] = ($event) => hoveredSortKey.value = null)
5908
+ }, [createElementVNode("span", _hoisted_69, toDisplayString(sortIconName(key)), 1)], 42, _hoisted_68)) : createCommentVNode("", true)])], 8, _hoisted_65);
5909
+ }), 128))])]), createElementVNode("tbody", _hoisted_70, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortedItems.value, (item) => {
5626
5910
  return openBlock(), createElementBlock("tr", {
5627
5911
  key: String(item[collection.value.schema.primaryKey] ?? ""),
5628
5912
  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" : ""]),
@@ -5640,23 +5924,29 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5640
5924
  key: 0,
5641
5925
  type: "checkbox",
5642
5926
  checked: toggleChecked(item, field),
5643
- disabled: isRowInlineSaving(item),
5927
+ disabled: isReadOnly.value || isRowInlineSaving(item),
5644
5928
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer align-middle disabled:opacity-50 disabled:cursor-not-allowed",
5645
5929
  "data-testid": `collections-inline-toggle-${key}-${item[collection.value.schema.primaryKey]}`,
5646
5930
  "aria-label": field.label,
5647
- onClick: _cache[16] || (_cache[16] = withModifiers(() => {}, ["stop"])),
5931
+ onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"])),
5648
5932
  onChange: ($event) => commitToggle(item, field)
5649
- }, null, 40, _hoisted_67)) : field.type === "boolean" ? (openBlock(), createElementBlock("input", {
5933
+ }, null, 40, _hoisted_72)) : field.type === "boolean" ? (openBlock(), createElementBlock("input", {
5650
5934
  key: 1,
5651
5935
  type: "checkbox",
5652
5936
  checked: item[key] === true,
5653
- disabled: isRowInlineSaving(item),
5937
+ disabled: isReadOnly.value || isRowInlineSaving(item),
5654
5938
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer align-middle disabled:opacity-50 disabled:cursor-not-allowed",
5655
5939
  "data-testid": `collections-inline-bool-${key}-${item[collection.value.schema.primaryKey]}`,
5656
5940
  "aria-label": field.label,
5657
- onClick: _cache[17] || (_cache[17] = withModifiers(() => {}, ["stop"])),
5941
+ onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"])),
5658
5942
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
5659
- }, null, 40, _hoisted_68)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_69, [createElementVNode("a", {
5943
+ }, null, 40, _hoisted_73)) : field.type === "flag" ? (openBlock(), createElementBlock("span", {
5944
+ key: 2,
5945
+ class: normalizeClass(["material-icons text-lg align-middle", flagValueOf(String(key), item) ? "text-emerald-600" : "text-slate-300"]),
5946
+ "data-testid": `collections-flag-${key}-${item[collection.value.schema.primaryKey]}`,
5947
+ "aria-label": `${field.label}: ${unref(t)(flagValueOf(String(key), item) ? "common.yes" : "common.no")}`,
5948
+ role: "img"
5949
+ }, toDisplayString(flagValueOf(String(key), item) ? "check_circle" : "radio_button_unchecked"), 11, _hoisted_74)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? (openBlock(), createElementBlock("span", _hoisted_75, [createElementVNode("a", {
5660
5950
  href: unref(cui).recordHref?.(field.to, String(item[key])),
5661
5951
  tabindex: unref(cui).recordHref?.(field.to, String(item[key])) ? void 0 : 0,
5662
5952
  role: "link",
@@ -5664,48 +5954,48 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5664
5954
  "data-testid": `collections-ref-link-${key}-${item[key]}`,
5665
5955
  onClick: ($event) => unref(activateRefLink)($event, field.to, String(item[key]), true),
5666
5956
  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"])]
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", {
5668
- key: 3,
5957
+ }, toDisplayString(unref(refDisplay)(field.to, String(item[key]))), 41, _hoisted_76)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (openBlock(), createElementBlock("select", {
5958
+ key: 4,
5669
5959
  value: item[key] == null ? "" : String(item[key]),
5670
- disabled: isRowInlineSaving(item),
5960
+ disabled: isReadOnly.value || isRowInlineSaving(item),
5671
5961
  class: normalizeClass(["rounded-lg border px-2 py-0.5 text-[11px] font-semibold focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 focus:outline-none cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed", enumControlClass(String(key), item[key])]),
5672
5962
  "data-testid": `collections-inline-enum-${key}-${item[collection.value.schema.primaryKey]}`,
5673
5963
  "aria-label": field.label,
5674
- onClick: _cache[18] || (_cache[18] = withModifiers(() => {}, ["stop"])),
5964
+ onClick: _cache[19] || (_cache[19] = withModifiers(() => {}, ["stop"])),
5675
5965
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
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) => {
5966
+ }, [showEnumPlaceholder(item, String(key)) ? (openBlock(), createElementBlock("option", _hoisted_78, toDisplayString(unref(t)("collectionsView.selectPlaceholder")), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(field.values, (value) => {
5677
5967
  return openBlock(), createElementBlock("option", {
5678
5968
  key: value,
5679
5969
  value
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", {
5682
- key: 7,
5970
+ }, toDisplayString(value), 9, _hoisted_79);
5971
+ }), 128))], 42, _hoisted_77)) : field.type === "money" ? (openBlock(), createElementBlock("span", _hoisted_80, toDisplayString(unref(formatMoney)(item[key], unref(resolveCurrency)(field, item), unref(locale))), 1)) : field.type === "table" ? (openBlock(), createElementBlock("span", _hoisted_81, [_cache[53] || (_cache[53] = createElementVNode("span", { class: "material-icons text-[11px]" }, "list", -1)), createElementVNode("span", null, toDisplayString(tableSummary(item[key])), 1)])) : field.type === "derived" ? (openBlock(), createElementBlock("span", _hoisted_82, toDisplayString(unref(derivedDisplay)(field, unref(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type === "rollup" ? (openBlock(), createElementBlock("span", {
5972
+ key: 8,
5683
5973
  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
5974
  "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,
5975
+ }, toDisplayString(unref(render).rollupDisplay(field, item)), 9, _hoisted_83)) : field.type !== "file" && unref(isExternalUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5976
+ key: 9,
5687
5977
  href: String(item[key]),
5688
5978
  target: "_blank",
5689
5979
  rel: "noopener noreferrer",
5690
5980
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5691
5981
  "data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
5692
- onClick: _cache[19] || (_cache[19] = withModifiers(() => {}, ["stop"]))
5693
- }, toDisplayString(String(item[key])), 9, _hoisted_78)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5694
- key: 9,
5982
+ onClick: _cache[20] || (_cache[20] = withModifiers(() => {}, ["stop"]))
5983
+ }, toDisplayString(String(item[key])), 9, _hoisted_84)) : field.type === "file" && unref(artifactUrl)(item[key]) ? (openBlock(), createElementBlock("a", {
5984
+ key: 10,
5695
5985
  href: unref(artifactUrl)(item[key]) ?? void 0,
5696
5986
  target: "_blank",
5697
5987
  rel: "noopener noreferrer",
5698
5988
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5699
5989
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
5700
- onClick: _cache[20] || (_cache[20] = withModifiers(() => {}, ["stop"]))
5701
- }, toDisplayString(String(item[key])), 9, _hoisted_79)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
5702
- key: 10,
5990
+ onClick: _cache[21] || (_cache[21] = withModifiers(() => {}, ["stop"]))
5991
+ }, toDisplayString(String(item[key])), 9, _hoisted_85)) : field.type === "file" && unref(fileRoutePath)(item[key]) ? (openBlock(), createElementBlock("a", {
5992
+ key: 11,
5703
5993
  href: unref(fileRoutePath)(item[key]) ?? void 0,
5704
5994
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5705
5995
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
5706
5996
  onClick: ($event) => unref(activatePathLink)($event, unref(fileRoutePath)(item[key]) ?? "", true)
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);
5997
+ }, toDisplayString(String(item[key])), 9, _hoisted_86)) : (openBlock(), createElementBlock("span", _hoisted_87, toDisplayString(unref(formatCell)(item[key], field.type)), 1))], 64)) : createCommentVNode("", true)]);
5998
+ }), 128))], 42, _hoisted_71);
5709
5999
  }), 128))])])]))]),
5710
6000
  collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? (openBlock(), createBlock(CollectionRecordModal_default, {
5711
6001
  key: 4,
@@ -5713,7 +6003,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5713
6003
  }, {
5714
6004
  default: withCtx(() => [createVNode(CollectionRecordPanel_default, {
5715
6005
  editing: editing.value,
5716
- "onUpdate:editing": _cache[21] || (_cache[21] = ($event) => editing.value = $event),
6006
+ "onUpdate:editing": _cache[22] || (_cache[22] = ($event) => editing.value = $event),
5717
6007
  collection: collection.value,
5718
6008
  viewing: viewing.value,
5719
6009
  saving: saving.value,
@@ -5726,13 +6016,14 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5726
6016
  "live-derived": liveDerived.value,
5727
6017
  "view-title": viewTitle.value,
5728
6018
  "is-singleton": isSingleton.value,
6019
+ readonly: isReadOnly.value,
5729
6020
  render: unref(render),
5730
6021
  locale: unref(locale),
5731
6022
  onSubmit: saveEditor,
5732
6023
  onCancel: cancelEditor,
5733
6024
  onEdit: editFromView,
5734
6025
  onClose: closeView,
5735
- onDelete: _cache[22] || (_cache[22] = ($event) => viewing.value && confirmDelete(viewing.value)),
6026
+ onDelete: _cache[23] || (_cache[23] = ($event) => viewing.value && confirmDelete(viewing.value)),
5736
6027
  onRunAction: runAction,
5737
6028
  onItemChat
5738
6029
  }, null, 8, [
@@ -5749,6 +6040,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5749
6040
  "live-derived",
5750
6041
  "view-title",
5751
6042
  "is-singleton",
6043
+ "readonly",
5752
6044
  "render",
5753
6045
  "locale"
5754
6046
  ])]),
@@ -5759,7 +6051,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5759
6051
  action: mutateModal.value.action,
5760
6052
  pending: mutatePending.value,
5761
6053
  error: mutateError.value,
5762
- onClose: _cache[23] || (_cache[23] = ($event) => mutateModal.value = null),
6054
+ onClose: _cache[24] || (_cache[24] = ($event) => mutateModal.value = null),
5763
6055
  onSubmit: submitMutateParams
5764
6056
  }, null, 8, [
5765
6057
  "action",
@@ -5772,7 +6064,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5772
6064
  title: collection.value.title,
5773
6065
  views: customViews.value,
5774
6066
  onChanged: onViewsChanged,
5775
- onClose: _cache[24] || (_cache[24] = ($event) => configOpen.value = false)
6067
+ onClose: _cache[25] || (_cache[25] = ($event) => configOpen.value = false)
5776
6068
  }, null, 8, [
5777
6069
  "slug",
5778
6070
  "title",
@@ -5787,29 +6079,29 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5787
6079
  "data-testid": "collections-chat-modal",
5788
6080
  onClick: withModifiers(closeChat, ["self"]),
5789
6081
  onKeydown: withKeys(closeChat, ["esc"])
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)]),
6082
+ }, [createElementVNode("div", _hoisted_88, [
6083
+ createElementVNode("header", _hoisted_89, [
6084
+ _cache[55] || (_cache[55] = 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)),
6085
+ createElementVNode("div", _hoisted_90, [createElementVNode("h2", _hoisted_91, toDisplayString(unref(t)("collectionsView.chatTitle")), 1), createElementVNode("span", _hoisted_92, toDisplayString(collection.value.title), 1)]),
5794
6086
  createElementVNode("button", {
5795
6087
  type: "button",
5796
6088
  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",
5797
6089
  "aria-label": unref(t)("common.close"),
5798
6090
  "data-testid": "collections-chat-close",
5799
6091
  onClick: closeChat
5800
- }, [..._cache[52] || (_cache[52] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_87)
6092
+ }, [..._cache[54] || (_cache[54] = [createElementVNode("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_93)
5801
6093
  ]),
5802
- createElementVNode("div", _hoisted_88, [withDirectives(createElementVNode("textarea", {
6094
+ createElementVNode("div", _hoisted_94, [withDirectives(createElementVNode("textarea", {
5803
6095
  ref_key: "chatInputEl",
5804
6096
  ref: chatInputEl,
5805
- "onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => chatMessage.value = $event),
6097
+ "onUpdate:modelValue": _cache[26] || (_cache[26] = ($event) => chatMessage.value = $event),
5806
6098
  rows: "4",
5807
6099
  placeholder: unref(t)("collectionsView.chatPlaceholder"),
5808
6100
  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",
5809
6101
  "data-testid": "collections-chat-input",
5810
6102
  onKeydown: [withKeys(withModifiers(submitChat, ["meta"]), ["enter"]), withKeys(withModifiers(submitChat, ["ctrl"]), ["enter"])]
5811
- }, null, 40, _hoisted_89), [[vModelText, chatMessage.value]])]),
5812
- createElementVNode("footer", _hoisted_90, [createElementVNode("button", {
6103
+ }, null, 40, _hoisted_95), [[vModelText, chatMessage.value]])]),
6104
+ createElementVNode("footer", _hoisted_96, [createElementVNode("button", {
5813
6105
  type: "button",
5814
6106
  class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
5815
6107
  "data-testid": "collections-chat-cancel",
@@ -5820,7 +6112,7 @@ var CollectionView_default = /* @__PURE__ */ defineComponent({
5820
6112
  disabled: !chatMessage.value.trim(),
5821
6113
  "data-testid": "collections-chat-send",
5822
6114
  onClick: submitChat
5823
- }, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_91)])
6115
+ }, toDisplayString(unref(t)("collectionsView.chatStart")), 9, _hoisted_97)])
5824
6116
  ])], 32)) : createCommentVNode("", true)
5825
6117
  ]);
5826
6118
  };
@@ -5972,10 +6264,10 @@ var _hoisted_18$3 = {
5972
6264
  key: 0,
5973
6265
  class: "text-teal-600"
5974
6266
  };
5975
- var _hoisted_19$1 = { key: 1 };
5976
- var _hoisted_20$1 = { class: "flex items-center justify-between pt-1 border-t border-slate-100" };
5977
- var _hoisted_21$1 = { class: "text-[10px] text-slate-400 font-mono" };
5978
- var _hoisted_22$1 = { class: "flex items-center gap-2" };
6267
+ var _hoisted_19$2 = { key: 1 };
6268
+ var _hoisted_20$2 = { class: "flex items-center justify-between pt-1 border-t border-slate-100" };
6269
+ var _hoisted_21$2 = { class: "text-[10px] text-slate-400 font-mono" };
6270
+ var _hoisted_22$2 = { class: "flex items-center gap-2" };
5979
6271
  var _hoisted_23$1 = ["data-testid"];
5980
6272
  var _hoisted_24 = ["data-testid", "onClick"];
5981
6273
  var _hoisted_25 = [
@@ -6076,9 +6368,9 @@ var DiscoverPanel_default = /* @__PURE__ */ defineComponent({
6076
6368
  createElementVNode("div", _hoisted_17$3, [
6077
6369
  createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.discover.fields", { count: entry.fieldCount })), 1),
6078
6370
  entry.views.length ? (openBlock(), createElementBlock("span", _hoisted_18$3, "· " + toDisplayString(entry.views.join(" · ")), 1)) : createCommentVNode("", true),
6079
- entry.hasSeed ? (openBlock(), createElementBlock("span", _hoisted_19$1, "· " + toDisplayString(unref(t)("collectionsView.discover.samples", { count: entry.seedCount })), 1)) : createCommentVNode("", true)
6371
+ entry.hasSeed ? (openBlock(), createElementBlock("span", _hoisted_19$2, "· " + toDisplayString(unref(t)("collectionsView.discover.samples", { count: entry.seedCount })), 1)) : createCommentVNode("", true)
6080
6372
  ]),
6081
- createElementVNode("div", _hoisted_20$1, [createElementVNode("span", _hoisted_21$1, "v" + toDisplayString(entry.version), 1), createElementVNode("div", _hoisted_22$1, [stateOf(entry).status === "error" ? (openBlock(), createElementBlock("span", {
6373
+ createElementVNode("div", _hoisted_20$2, [createElementVNode("span", _hoisted_21$2, "v" + toDisplayString(entry.version), 1), createElementVNode("div", _hoisted_22$2, [stateOf(entry).status === "error" ? (openBlock(), createElementBlock("span", {
6082
6374
  key: 0,
6083
6375
  class: "text-[11px] text-red-600",
6084
6376
  "data-testid": `discover-error-${entry.slug}`
@@ -6329,22 +6621,27 @@ var _hoisted_9$1 = {
6329
6621
  class: "rounded-xl border border-slate-200 bg-white px-6 py-12 text-center text-sm text-slate-500 shadow-sm"
6330
6622
  };
6331
6623
  var _hoisted_10$1 = { class: "font-medium text-slate-700" };
6332
- var _hoisted_11$1 = {
6333
- key: 3,
6334
- class: "grid gap-4 sm:grid-cols-2"
6624
+ var _hoisted_11$1 = { key: 3 };
6625
+ var _hoisted_12$1 = {
6626
+ key: 0,
6627
+ class: "flex items-center gap-1.5 mb-4",
6628
+ "data-testid": "collections-filter-chips"
6335
6629
  };
6336
- var _hoisted_12$1 = [
6630
+ var _hoisted_13$1 = ["data-testid", "onClick"];
6631
+ var _hoisted_14$1 = { class: "grid gap-4 sm:grid-cols-2" };
6632
+ var _hoisted_15$1 = [
6337
6633
  "aria-label",
6338
6634
  "data-testid",
6339
6635
  "onClick",
6340
6636
  "onKeydown"
6341
6637
  ];
6342
- var _hoisted_13$1 = { class: "material-symbols-outlined text-2xl" };
6343
- var _hoisted_14$1 = { class: "flex-1 min-w-0" };
6344
- var _hoisted_15$1 = { class: "block font-semibold text-slate-800 text-[15px] group-hover:text-indigo-950 transition-colors truncate" };
6345
- var _hoisted_16$1 = { class: "block text-[10px] text-slate-400 mt-1 tracking-wider font-semibold uppercase flex items-center gap-1.5" };
6346
- var _hoisted_17$1 = { class: "text-[10px] bg-slate-100 px-1 rounded lowercase text-slate-500 font-mono font-normal" };
6347
- var _hoisted_18$1 = [
6638
+ var _hoisted_16$1 = { class: "material-symbols-outlined text-2xl" };
6639
+ var _hoisted_17$1 = { class: "flex-1 min-w-0" };
6640
+ var _hoisted_18$1 = { class: "block font-semibold text-slate-800 text-[15px] group-hover:text-indigo-950 transition-colors truncate" };
6641
+ var _hoisted_19$1 = { class: "block text-[10px] text-slate-400 mt-1 tracking-wider font-semibold uppercase flex items-center gap-1.5" };
6642
+ var _hoisted_20$1 = { class: "text-[10px] bg-slate-100 px-1 rounded lowercase text-slate-500 font-mono font-normal" };
6643
+ var _hoisted_21$1 = ["data-testid"];
6644
+ var _hoisted_22$1 = [
6348
6645
  "title",
6349
6646
  "aria-label",
6350
6647
  "data-testid",
@@ -6363,6 +6660,18 @@ var CollectionsIndexView_default = /* @__PURE__ */ defineComponent({
6363
6660
  const collections = ref([]);
6364
6661
  const loading = ref(true);
6365
6662
  const loadError = ref(null);
6663
+ const FILTER_CHIPS = [
6664
+ "all",
6665
+ "editable",
6666
+ "data"
6667
+ ];
6668
+ const filter = ref("all");
6669
+ const hasReadonlyCollections = computed(() => collections.value.some((collection) => collection.readonly === true));
6670
+ const filteredCollections = computed(() => {
6671
+ if (filter.value === "editable") return collections.value.filter((collection) => collection.readonly !== true);
6672
+ if (filter.value === "data") return collections.value.filter((collection) => collection.readonly === true);
6673
+ return collections.value;
6674
+ });
6366
6675
  async function loadCollections() {
6367
6676
  loading.value = true;
6368
6677
  loadError.value = null;
@@ -6425,7 +6734,15 @@ var CollectionsIndexView_default = /* @__PURE__ */ defineComponent({
6425
6734
  tab.value === "discover" ? (openBlock(), createBlock(DiscoverPanel_default, {
6426
6735
  key: 1,
6427
6736
  onImported: loadCollections
6428
- })) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_7$1, [_cache[5] || (_cache[5] = 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_8$1, [_cache[6] || (_cache[6] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.loadFailed")) + ": " + toDisplayString(loadError.value), 1)])) : collections.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_9$1, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300 mb-2" }, "dashboard_customize", -1)), createElementVNode("p", _hoisted_10$1, toDisplayString(unref(t)("collectionsView.indexEmpty")), 1)])) : (openBlock(), createElementBlock("div", _hoisted_11$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(collections.value, (collection) => {
6737
+ })) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [loading.value ? (openBlock(), createElementBlock("div", _hoisted_7$1, [_cache[5] || (_cache[5] = 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_8$1, [_cache[6] || (_cache[6] = createElementVNode("span", { class: "material-icons text-red-600" }, "error", -1)), createElementVNode("span", null, toDisplayString(unref(t)("collectionsView.loadFailed")) + ": " + toDisplayString(loadError.value), 1)])) : collections.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_9$1, [_cache[7] || (_cache[7] = createElementVNode("span", { class: "material-icons text-4xl text-slate-300 mb-2" }, "dashboard_customize", -1)), createElementVNode("p", _hoisted_10$1, toDisplayString(unref(t)("collectionsView.indexEmpty")), 1)])) : (openBlock(), createElementBlock("div", _hoisted_11$1, [hasReadonlyCollections.value ? (openBlock(), createElementBlock("div", _hoisted_12$1, [(openBlock(), createElementBlock(Fragment, null, renderList(FILTER_CHIPS, (chip) => {
6738
+ return createElementVNode("button", {
6739
+ key: chip,
6740
+ type: "button",
6741
+ class: normalizeClass(["px-3 h-7 rounded-full text-xs font-semibold border transition-colors", filter.value === chip ? "bg-indigo-600 border-indigo-600 text-white" : "bg-white border-slate-200 text-slate-500 hover:text-slate-700 hover:bg-slate-50"]),
6742
+ "data-testid": `collections-filter-${chip}`,
6743
+ onClick: ($event) => filter.value = chip
6744
+ }, toDisplayString(unref(t)(`collectionsView.filter.${chip}`)), 11, _hoisted_13$1);
6745
+ }), 64))])) : createCommentVNode("", true), createElementVNode("div", _hoisted_14$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(filteredCollections.value, (collection) => {
6429
6746
  return openBlock(), createElementBlock("div", {
6430
6747
  key: collection.slug,
6431
6748
  class: "group relative rounded-xl border border-slate-200 bg-white p-5 shadow-sm hover:shadow-md hover:border-indigo-300 transition-all duration-300 cursor-pointer flex items-center gap-4 focus:outline-none focus:ring-2 focus:ring-indigo-500/20",
@@ -6437,11 +6754,16 @@ var CollectionsIndexView_default = /* @__PURE__ */ defineComponent({
6437
6754
  onKeydown: [withKeys(withModifiers(($event) => openCollection(collection.slug), ["self"]), ["enter"]), withKeys(withModifiers(($event) => openCollection(collection.slug), ["self", "prevent"]), ["space"])]
6438
6755
  }, [
6439
6756
  createElementVNode("div", { class: normalizeClass(["absolute left-0 top-0 bottom-0 w-1 rounded-l-xl transition-all duration-300 group-hover:w-1.5", collection.source === "project" ? "bg-indigo-600" : "bg-violet-600"]) }, null, 2),
6440
- createElementVNode("div", { class: normalizeClass(["h-12 w-12 flex items-center justify-center rounded-xl transition-all duration-300 group-hover:scale-105 shadow-sm", collection.source === "project" ? "bg-indigo-50 text-indigo-600 group-hover:bg-indigo-100/80 border border-indigo-100/50" : "bg-violet-50 text-violet-600 group-hover:bg-violet-100/80 border border-violet-100/50"]) }, [createElementVNode("span", _hoisted_13$1, toDisplayString(collection.icon), 1)], 2),
6441
- createElementVNode("div", _hoisted_14$1, [createElementVNode("span", _hoisted_15$1, toDisplayString(collection.title), 1), createElementVNode("span", _hoisted_16$1, [
6757
+ createElementVNode("div", { class: normalizeClass(["h-12 w-12 flex items-center justify-center rounded-xl transition-all duration-300 group-hover:scale-105 shadow-sm", collection.source === "project" ? "bg-indigo-50 text-indigo-600 group-hover:bg-indigo-100/80 border border-indigo-100/50" : "bg-violet-50 text-violet-600 group-hover:bg-violet-100/80 border border-violet-100/50"]) }, [createElementVNode("span", _hoisted_16$1, toDisplayString(collection.icon), 1)], 2),
6758
+ createElementVNode("div", _hoisted_17$1, [createElementVNode("span", _hoisted_18$1, toDisplayString(collection.title), 1), createElementVNode("span", _hoisted_19$1, [
6442
6759
  createElementVNode("span", { class: normalizeClass(["h-1.5 w-1.5 rounded-full", collection.source === "project" ? "bg-indigo-500" : "bg-violet-500"]) }, null, 2),
6443
6760
  createTextVNode(" " + toDisplayString(unref(t)(`collectionsView.source.${collection.source}`)) + " · ", 1),
6444
- createElementVNode("code", _hoisted_17$1, toDisplayString(collection.slug), 1)
6761
+ createElementVNode("code", _hoisted_20$1, toDisplayString(collection.slug), 1),
6762
+ collection.readonly ? (openBlock(), createElementBlock("span", {
6763
+ key: 0,
6764
+ class: "inline-flex items-center gap-0.5 px-1.5 py-px rounded bg-amber-50 text-amber-700 border border-amber-200 normal-case tracking-normal",
6765
+ "data-testid": `collections-readonly-badge-${collection.slug}`
6766
+ }, [_cache[8] || (_cache[8] = createElementVNode("span", { class: "material-icons text-[11px]" }, "lock", -1)), createTextVNode(" " + toDisplayString(unref(t)("collectionsView.readonlyChip")), 1)], 8, _hoisted_21$1)) : createCommentVNode("", true)
6445
6767
  ])]),
6446
6768
  (openBlock(), createBlock(resolveDynamicComponent(unref(pinToggle)), {
6447
6769
  kind: "collection",
@@ -6453,17 +6775,18 @@ var CollectionsIndexView_default = /* @__PURE__ */ defineComponent({
6453
6775
  "title",
6454
6776
  "icon"
6455
6777
  ])),
6456
- createElementVNode("button", {
6778
+ !collection.readonly ? (openBlock(), createElementBlock("button", {
6779
+ key: 0,
6457
6780
  type: "button",
6458
6781
  class: "h-8 w-8 flex items-center justify-center rounded-lg bg-slate-50 text-slate-400 hover:bg-teal-50 hover:text-teal-600 transition-all duration-300",
6459
6782
  title: unref(t)("collectionsView.contribute"),
6460
6783
  "aria-label": unref(t)("collectionsView.contribute"),
6461
6784
  "data-testid": `collections-contribute-${collection.slug}`,
6462
6785
  onClick: withModifiers(($event) => startContributeChat(collection), ["stop"])
6463
- }, [..._cache[8] || (_cache[8] = [createElementVNode("span", { class: "material-icons text-lg" }, "ios_share", -1)])], 8, _hoisted_18$1),
6464
- _cache[9] || (_cache[9] = createElementVNode("div", { class: "h-8 w-8 flex items-center justify-center rounded-lg bg-slate-50 group-hover:bg-indigo-50 text-slate-400 group-hover:text-indigo-600 transition-all duration-300" }, [createElementVNode("span", { class: "material-icons text-lg transition-transform duration-300 group-hover:translate-x-0.5" }, "chevron_right")], -1))
6465
- ], 40, _hoisted_12$1);
6466
- }), 128))]))], 64))
6786
+ }, [..._cache[9] || (_cache[9] = [createElementVNode("span", { class: "material-icons text-lg" }, "ios_share", -1)])], 8, _hoisted_22$1)) : createCommentVNode("", true),
6787
+ _cache[10] || (_cache[10] = createElementVNode("div", { class: "h-8 w-8 flex items-center justify-center rounded-lg bg-slate-50 group-hover:bg-indigo-50 text-slate-400 group-hover:text-indigo-600 transition-all duration-300" }, [createElementVNode("span", { class: "material-icons text-lg transition-transform duration-300 group-hover:translate-x-0.5" }, "chevron_right")], -1))
6788
+ ], 40, _hoisted_15$1);
6789
+ }), 128))])]))], 64))
6467
6790
  ])]);
6468
6791
  };
6469
6792
  }
@@ -6675,6 +6998,6 @@ var plugin = {
6675
6998
  previewComponent: Preview_default
6676
6999
  };
6677
7000
  //#endregion
6678
- export { CollectionCalendarView_default as CollectionCalendarView, CollectionCustomView_default as CollectionCustomView, CollectionDayView_default as CollectionDayView, CollectionEmbedView_default as CollectionEmbedView, CollectionKanbanView_default as CollectionKanbanView, CollectionRecordModal_default as CollectionRecordModal, CollectionRecordPanel_default as CollectionRecordPanel, CollectionView_default as CollectionView, CollectionViewConfigModal_default as CollectionViewConfigModal, CollectionsIndexView_default as CollectionsIndexView, FeedsView_default as FeedsView, Preview_default as PresentCollectionPreview, View_default as PresentCollectionView, applicableViewModes, collectionUi, configureCollectionUi, customViewKey, plugin, readCollectionSort, readCollectionViewMode, useCollectionRendering, writeCollectionSort, writeCollectionViewMode };
7001
+ export { CollectionCalendarView_default as CollectionCalendarView, CollectionCustomView_default as CollectionCustomView, CollectionDayView_default as CollectionDayView, CollectionEmbedView_default as CollectionEmbedView, CollectionKanbanView_default as CollectionKanbanView, CollectionRecordModal_default as CollectionRecordModal, CollectionRecordPanel_default as CollectionRecordPanel, CollectionView_default as CollectionView, CollectionViewConfigModal_default as CollectionViewConfigModal, CollectionsIndexView_default as CollectionsIndexView, FeedsView_default as FeedsView, Preview_default as PresentCollectionPreview, View_default as PresentCollectionView, applicableViewModes, collectionUi, configureCollectionUi, customViewKey, plugin, readCollectionFlagFilters, readCollectionSort, readCollectionViewMode, useCollectionRendering, writeCollectionFlagFilters, writeCollectionSort, writeCollectionViewMode };
6679
7002
 
6680
7003
  //# sourceMappingURL=vue.js.map