@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.cjs CHANGED
@@ -92,6 +92,13 @@ var i18n = (0, vue_i18n.createI18n)({
92
92
  deleteCollection: "Delete collection",
93
93
  confirmDeleteCollection: "Delete the entire \"{title}\" collection, including all its records? A restorable backup is archived first.",
94
94
  itemsEmpty: "No items yet. Click + to add one.",
95
+ readonlyChip: "Read-only",
96
+ itemsEmptyReadonly: "No rows in the data file yet. Add rows to the file and they appear here.",
97
+ filter: {
98
+ all: "All",
99
+ editable: "Editable",
100
+ data: "Data"
101
+ },
95
102
  notFound: "Collection not found",
96
103
  loadFailed: "Failed to load",
97
104
  requiredField: "This field is required",
@@ -107,6 +114,11 @@ var i18n = (0, vue_i18n.createI18n)({
107
114
  searchSummary: "Showing {shown} of {total}",
108
115
  noMatchingItems: "No matching items",
109
116
  clearSearch: "Clear search",
117
+ flagFilterGroup: "Flag filters",
118
+ flagFilterAll: "Filter by {label}",
119
+ flagFilterHide: "Hiding {label}",
120
+ flagFilterOnly: "Only {label}",
121
+ flagDoneChip: "Done",
110
122
  sortBy: "Sort by {field}",
111
123
  openCollection: "Open {title}",
112
124
  createTitle: "Add new",
@@ -228,6 +240,13 @@ var i18n = (0, vue_i18n.createI18n)({
228
240
  deleteCollection: "コレクションを削除",
229
241
  confirmDeleteCollection: "コレクション「{title}」とそのすべてのレコードを削除しますか?削除前に復元可能なバックアップが保存されます。",
230
242
  itemsEmpty: "まだ項目がありません。+ を押して追加してください。",
243
+ readonlyChip: "読み取り専用",
244
+ itemsEmptyReadonly: "データファイルにまだ行がありません。ファイルに行を追加するとここに表示されます。",
245
+ filter: {
246
+ all: "すべて",
247
+ editable: "編集可能",
248
+ data: "データ"
249
+ },
231
250
  notFound: "コレクションが見つかりません",
232
251
  loadFailed: "読み込みに失敗しました",
233
252
  requiredField: "この項目は必須です",
@@ -243,6 +262,11 @@ var i18n = (0, vue_i18n.createI18n)({
243
262
  searchSummary: "{total} 件中 {shown} 件を表示",
244
263
  noMatchingItems: "一致する項目がありません",
245
264
  clearSearch: "検索をクリア",
265
+ flagFilterGroup: "フラグで絞り込み",
266
+ flagFilterAll: "{label} で絞り込む",
267
+ flagFilterHide: "{label} を非表示中",
268
+ flagFilterOnly: "{label} のみ表示中",
269
+ flagDoneChip: "完了",
246
270
  sortBy: "{field}で並べ替え",
247
271
  openCollection: "{title} を開く",
248
272
  createTitle: "新規追加",
@@ -364,6 +388,13 @@ var i18n = (0, vue_i18n.createI18n)({
364
388
  deleteCollection: "删除集合",
365
389
  confirmDeleteCollection: "删除整个“{title}”集合及其所有记录?删除前会先归档一份可恢复的备份。",
366
390
  itemsEmpty: "暂无项目。点击 + 添加一个。",
391
+ readonlyChip: "只读",
392
+ itemsEmptyReadonly: "数据文件中还没有行。在文件中添加行后会显示在这里。",
393
+ filter: {
394
+ all: "全部",
395
+ editable: "可编辑",
396
+ data: "数据"
397
+ },
367
398
  notFound: "未找到集合",
368
399
  loadFailed: "加载失败",
369
400
  requiredField: "此字段为必填项",
@@ -379,6 +410,11 @@ var i18n = (0, vue_i18n.createI18n)({
379
410
  searchSummary: "显示 {total} 条中的 {shown} 条",
380
411
  noMatchingItems: "没有匹配的项目",
381
412
  clearSearch: "清除搜索",
413
+ flagFilterGroup: "标记筛选",
414
+ flagFilterAll: "按{label}筛选",
415
+ flagFilterHide: "已隐藏{label}",
416
+ flagFilterOnly: "仅显示{label}",
417
+ flagDoneChip: "已完成",
382
418
  sortBy: "按{field}排序",
383
419
  openCollection: "打开 {title}",
384
420
  createTitle: "新增",
@@ -500,6 +536,13 @@ var i18n = (0, vue_i18n.createI18n)({
500
536
  deleteCollection: "컬렉션 삭제",
501
537
  confirmDeleteCollection: "\"{title}\" 컬렉션과 모든 레코드를 삭제하시겠습니까? 삭제 전에 복원 가능한 백업이 보관됩니다.",
502
538
  itemsEmpty: "아직 항목이 없습니다. + 를 눌러 추가하세요.",
539
+ readonlyChip: "읽기 전용",
540
+ itemsEmptyReadonly: "데이터 파일에 아직 행이 없습니다. 파일에 행을 추가하면 여기에 표시됩니다.",
541
+ filter: {
542
+ all: "전체",
543
+ editable: "편집 가능",
544
+ data: "데이터"
545
+ },
503
546
  notFound: "컬렉션을 찾을 수 없습니다",
504
547
  loadFailed: "불러오기에 실패했습니다",
505
548
  requiredField: "이 필드는 필수입니다",
@@ -515,6 +558,11 @@ var i18n = (0, vue_i18n.createI18n)({
515
558
  searchSummary: "{total}개 중 {shown}개 표시",
516
559
  noMatchingItems: "일치하는 항목이 없습니다",
517
560
  clearSearch: "검색 지우기",
561
+ flagFilterGroup: "플래그 필터",
562
+ flagFilterAll: "{label}(으)로 필터",
563
+ flagFilterHide: "{label} 숨김",
564
+ flagFilterOnly: "{label}만 표시",
565
+ flagDoneChip: "완료",
518
566
  sortBy: "{field} 기준 정렬",
519
567
  openCollection: "{title} 열기",
520
568
  createTitle: "새로 추가",
@@ -636,6 +684,13 @@ var i18n = (0, vue_i18n.createI18n)({
636
684
  deleteCollection: "Eliminar colección",
637
685
  confirmDeleteCollection: "¿Eliminar toda la colección \"{title}\", incluidos todos sus registros? Antes se archiva una copia de seguridad restaurable.",
638
686
  itemsEmpty: "Aún no hay elementos. Pulsa + para añadir uno.",
687
+ readonlyChip: "Solo lectura",
688
+ itemsEmptyReadonly: "El archivo de datos aún no tiene filas. Añádelas al archivo y aparecerán aquí.",
689
+ filter: {
690
+ all: "Todas",
691
+ editable: "Editables",
692
+ data: "Datos"
693
+ },
639
694
  notFound: "Colección no encontrada",
640
695
  loadFailed: "Error al cargar",
641
696
  requiredField: "Este campo es obligatorio",
@@ -651,6 +706,11 @@ var i18n = (0, vue_i18n.createI18n)({
651
706
  searchSummary: "Mostrando {shown} de {total}",
652
707
  noMatchingItems: "No hay elementos coincidentes",
653
708
  clearSearch: "Borrar búsqueda",
709
+ flagFilterGroup: "Filtros por indicador",
710
+ flagFilterAll: "Filtrar por {label}",
711
+ flagFilterHide: "Ocultando {label}",
712
+ flagFilterOnly: "Solo {label}",
713
+ flagDoneChip: "Hecho",
654
714
  sortBy: "Ordenar por {field}",
655
715
  openCollection: "Abrir {title}",
656
716
  createTitle: "Añadir nuevo",
@@ -772,6 +832,13 @@ var i18n = (0, vue_i18n.createI18n)({
772
832
  deleteCollection: "Excluir coleção",
773
833
  confirmDeleteCollection: "Excluir toda a coleção \"{title}\", incluindo todos os seus registros? Um backup restaurável é arquivado antes.",
774
834
  itemsEmpty: "Ainda não há itens. Clique em + para adicionar um.",
835
+ readonlyChip: "Somente leitura",
836
+ itemsEmptyReadonly: "O arquivo de dados ainda não tem linhas. Adicione linhas ao arquivo e elas aparecerão aqui.",
837
+ filter: {
838
+ all: "Todas",
839
+ editable: "Editáveis",
840
+ data: "Dados"
841
+ },
775
842
  notFound: "Coleção não encontrada",
776
843
  loadFailed: "Falha ao carregar",
777
844
  requiredField: "Este campo é obrigatório",
@@ -787,6 +854,11 @@ var i18n = (0, vue_i18n.createI18n)({
787
854
  searchSummary: "Mostrando {shown} de {total}",
788
855
  noMatchingItems: "Nenhum item correspondente",
789
856
  clearSearch: "Limpar busca",
857
+ flagFilterGroup: "Filtros por marcador",
858
+ flagFilterAll: "Filtrar por {label}",
859
+ flagFilterHide: "Ocultando {label}",
860
+ flagFilterOnly: "Somente {label}",
861
+ flagDoneChip: "Concluído",
790
862
  sortBy: "Ordenar por {field}",
791
863
  openCollection: "Abrir {title}",
792
864
  createTitle: "Adicionar novo",
@@ -908,6 +980,13 @@ var i18n = (0, vue_i18n.createI18n)({
908
980
  deleteCollection: "Supprimer la collection",
909
981
  confirmDeleteCollection: "Supprimer toute la collection « {title} », y compris tous ses enregistrements ? Une sauvegarde restaurable est archivée au préalable.",
910
982
  itemsEmpty: "Aucun élément pour l'instant. Cliquez sur + pour en ajouter un.",
983
+ readonlyChip: "Lecture seule",
984
+ itemsEmptyReadonly: "Le fichier de données ne contient pas encore de lignes. Ajoutez-en au fichier et elles apparaîtront ici.",
985
+ filter: {
986
+ all: "Toutes",
987
+ editable: "Modifiables",
988
+ data: "Données"
989
+ },
911
990
  notFound: "Collection introuvable",
912
991
  loadFailed: "Échec du chargement",
913
992
  requiredField: "Ce champ est obligatoire",
@@ -923,6 +1002,11 @@ var i18n = (0, vue_i18n.createI18n)({
923
1002
  searchSummary: "Affichage de {shown} sur {total}",
924
1003
  noMatchingItems: "Aucun élément correspondant",
925
1004
  clearSearch: "Effacer la recherche",
1005
+ flagFilterGroup: "Filtres par indicateur",
1006
+ flagFilterAll: "Filtrer par {label}",
1007
+ flagFilterHide: "{label} masqué",
1008
+ flagFilterOnly: "Uniquement {label}",
1009
+ flagDoneChip: "Terminé",
926
1010
  sortBy: "Trier par {field}",
927
1011
  openCollection: "Ouvrir {title}",
928
1012
  createTitle: "Ajouter",
@@ -1044,6 +1128,13 @@ var i18n = (0, vue_i18n.createI18n)({
1044
1128
  deleteCollection: "Sammlung löschen",
1045
1129
  confirmDeleteCollection: "Die gesamte Sammlung „{title}“ einschließlich aller Datensätze löschen? Zuvor wird eine wiederherstellbare Sicherung archiviert.",
1046
1130
  itemsEmpty: "Noch keine Einträge. Klicke auf +, um einen hinzuzufügen.",
1131
+ readonlyChip: "Schreibgeschützt",
1132
+ itemsEmptyReadonly: "Noch keine Zeilen in der Datendatei. Füge der Datei Zeilen hinzu, dann erscheinen sie hier.",
1133
+ filter: {
1134
+ all: "Alle",
1135
+ editable: "Bearbeitbar",
1136
+ data: "Daten"
1137
+ },
1047
1138
  notFound: "Sammlung nicht gefunden",
1048
1139
  loadFailed: "Laden fehlgeschlagen",
1049
1140
  requiredField: "Dieses Feld ist erforderlich",
@@ -1059,6 +1150,11 @@ var i18n = (0, vue_i18n.createI18n)({
1059
1150
  searchSummary: "{shown} von {total} werden angezeigt",
1060
1151
  noMatchingItems: "Keine passenden Einträge",
1061
1152
  clearSearch: "Suche zurücksetzen",
1153
+ flagFilterGroup: "Flag-Filter",
1154
+ flagFilterAll: "Nach {label} filtern",
1155
+ flagFilterHide: "{label} ausgeblendet",
1156
+ flagFilterOnly: "Nur {label}",
1157
+ flagDoneChip: "Erledigt",
1062
1158
  sortBy: "Nach {field} sortieren",
1063
1159
  openCollection: "{title} öffnen",
1064
1160
  createTitle: "Neu hinzufügen",
@@ -2067,7 +2163,8 @@ var CollectionKanbanView_default = /* @__PURE__ */ (0, vue.defineComponent)({
2067
2163
  groupField: {},
2068
2164
  items: {},
2069
2165
  selected: {},
2070
- notified: {}
2166
+ notified: {},
2167
+ readonly: { type: Boolean }
2071
2168
  },
2072
2169
  emits: ["select", "move"],
2073
2170
  setup(__props, { emit: __emit }) {
@@ -2174,6 +2271,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ (0, vue.defineComponent)({
2174
2271
  group: "collection-kanban-cards",
2175
2272
  class: "flex-1 overflow-y-auto p-2 space-y-2 min-h-[2rem]",
2176
2273
  animation: 150,
2274
+ disabled: __props.readonly,
2177
2275
  onChange: (e) => onDragChange(column.value, e)
2178
2276
  }, {
2179
2277
  item: (0, vue.withCtx)(({ element }) => [(0, vue.createElementVNode)("div", {
@@ -2184,7 +2282,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ (0, vue.defineComponent)({
2184
2282
  class: (0, vue.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)]]),
2185
2283
  onClick: ($event) => emit("select", itemId(element)),
2186
2284
  onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)((e) => !e.repeat && emit("select", itemId(element)), ["prevent", "self"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)((e) => !e.repeat && emit("select", itemId(element)), ["prevent", "self"]), ["space"])]
2187
- }, [(0, vue.createElementVNode)("div", _hoisted_9$8, [cardToggle.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
2285
+ }, [(0, vue.createElementVNode)("div", _hoisted_9$8, [cardToggle.value && !__props.readonly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
2188
2286
  key: 0,
2189
2287
  type: "checkbox",
2190
2288
  checked: cardChecked(element),
@@ -2198,6 +2296,7 @@ var CollectionKanbanView_default = /* @__PURE__ */ (0, vue.defineComponent)({
2198
2296
  }, 8, [
2199
2297
  "model-value",
2200
2298
  "item-key",
2299
+ "disabled",
2201
2300
  "onChange"
2202
2301
  ])], 8, _hoisted_3$12);
2203
2302
  }), 128))])]);
@@ -2424,23 +2523,23 @@ var _hoisted_18$5 = [
2424
2523
  "placeholder",
2425
2524
  "data-testid"
2426
2525
  ];
2427
- var _hoisted_19$3 = {
2526
+ var _hoisted_19$4 = {
2428
2527
  key: 0,
2429
2528
  class: "inline-flex items-center gap-2.5 text-sm text-slate-700 cursor-pointer select-none"
2430
2529
  };
2431
- var _hoisted_20$3 = [
2530
+ var _hoisted_20$4 = [
2432
2531
  "id",
2433
2532
  "onUpdate:modelValue",
2434
2533
  "data-testid",
2435
2534
  "onChange"
2436
2535
  ];
2437
- var _hoisted_21$3 = [
2536
+ var _hoisted_21$4 = [
2438
2537
  "id",
2439
2538
  "onUpdate:modelValue",
2440
2539
  "required",
2441
2540
  "data-testid"
2442
2541
  ];
2443
- var _hoisted_22$3 = { value: "" };
2542
+ var _hoisted_22$4 = { value: "" };
2444
2543
  var _hoisted_23$3 = ["value"];
2445
2544
  var _hoisted_24$2 = [
2446
2545
  "id",
@@ -2536,77 +2635,79 @@ var _hoisted_57$1 = {
2536
2635
  key: 2,
2537
2636
  class: "text-slate-300"
2538
2637
  };
2539
- var _hoisted_58$1 = [
2638
+ var _hoisted_58$1 = ["data-testid"];
2639
+ var _hoisted_59$1 = ["data-testid"];
2640
+ var _hoisted_60$1 = [
2540
2641
  "href",
2541
2642
  "tabindex",
2542
2643
  "data-testid",
2543
2644
  "onClick",
2544
2645
  "onKeydown"
2545
2646
  ];
2546
- var _hoisted_59$1 = {
2547
- key: 3,
2647
+ var _hoisted_61$1 = {
2648
+ key: 4,
2548
2649
  class: "font-semibold text-slate-900 tabular-nums text-sm"
2549
2650
  };
2550
- var _hoisted_60$1 = {
2551
- key: 4,
2651
+ var _hoisted_62$1 = {
2652
+ key: 5,
2552
2653
  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"
2553
2654
  };
2554
- var _hoisted_61$1 = ["data-testid"];
2555
- var _hoisted_62$1 = {
2556
- key: 6,
2655
+ var _hoisted_63$1 = ["data-testid"];
2656
+ var _hoisted_64$1 = {
2657
+ key: 7,
2557
2658
  class: "border border-slate-200/80 rounded-xl overflow-hidden shadow-sm mt-1"
2558
2659
  };
2559
- var _hoisted_63$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
2560
- var _hoisted_64$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
2561
- var _hoisted_65$1 = { class: "divide-y divide-slate-100" };
2562
- var _hoisted_66$1 = {
2660
+ var _hoisted_65$1 = { class: "w-full text-[11px] text-slate-600 bg-white" };
2661
+ var _hoisted_66$1 = { class: "bg-slate-50 border-b border-slate-200 text-slate-500 font-bold uppercase tracking-wider" };
2662
+ var _hoisted_67$1 = { class: "divide-y divide-slate-100" };
2663
+ var _hoisted_68$1 = {
2563
2664
  key: 0,
2564
2665
  class: "material-icons text-emerald-600 text-base"
2565
2666
  };
2566
- var _hoisted_67$1 = {
2667
+ var _hoisted_69$1 = {
2567
2668
  key: 1,
2568
2669
  class: "text-slate-300"
2569
2670
  };
2570
- var _hoisted_68$1 = {
2571
- key: 7,
2671
+ var _hoisted_70$1 = {
2672
+ key: 8,
2572
2673
  class: "text-slate-400 italic"
2573
2674
  };
2574
- var _hoisted_69$1 = {
2575
- key: 8,
2675
+ var _hoisted_71$1 = {
2676
+ key: 9,
2576
2677
  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"
2577
2678
  };
2578
- var _hoisted_70$1 = [
2679
+ var _hoisted_72$1 = [
2579
2680
  "src",
2580
2681
  "alt",
2581
2682
  "data-testid"
2582
2683
  ];
2583
- var _hoisted_71$1 = ["href", "data-testid"];
2584
- var _hoisted_72$1 = ["href", "data-testid"];
2585
- var _hoisted_73$1 = [
2684
+ var _hoisted_73$1 = ["href", "data-testid"];
2685
+ var _hoisted_74$1 = ["href", "data-testid"];
2686
+ var _hoisted_75$1 = [
2586
2687
  "href",
2587
2688
  "data-testid",
2588
2689
  "onClick"
2589
2690
  ];
2590
- var _hoisted_74$1 = {
2591
- key: 15,
2691
+ var _hoisted_76$1 = {
2692
+ key: 16,
2592
2693
  class: "text-slate-800 font-semibold"
2593
2694
  };
2594
- var _hoisted_75$1 = {
2695
+ var _hoisted_77$1 = {
2595
2696
  key: 0,
2596
2697
  class: "col-span-full text-xs font-semibold text-red-600 bg-red-50 border border-red-100 p-2.5 rounded-xl"
2597
2698
  };
2598
- var _hoisted_76$1 = {
2699
+ var _hoisted_78$1 = {
2599
2700
  key: 1,
2600
2701
  class: "mt-5 pt-4 border-t border-slate-200/60",
2601
2702
  "data-testid": "collections-detail-chat"
2602
2703
  };
2603
- var _hoisted_77$1 = {
2704
+ var _hoisted_79$1 = {
2604
2705
  class: "block text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5",
2605
2706
  for: "collections-detail-chat-input"
2606
2707
  };
2607
- var _hoisted_78$1 = { class: "flex items-end gap-2" };
2608
- var _hoisted_79$1 = ["placeholder", "onKeydown"];
2609
- var _hoisted_80$1 = ["disabled"];
2708
+ var _hoisted_80$1 = { class: "flex items-end gap-2" };
2709
+ var _hoisted_81$1 = ["placeholder", "onKeydown"];
2710
+ var _hoisted_82$1 = ["disabled"];
2610
2711
  //#endregion
2611
2712
  //#region src/vue/components/CollectionRecordPanel.vue
2612
2713
  var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -2624,6 +2725,7 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
2624
2725
  liveDerived: {},
2625
2726
  viewTitle: {},
2626
2727
  isSingleton: { type: Boolean },
2728
+ readonly: { type: Boolean },
2627
2729
  render: {},
2628
2730
  locale: {}
2629
2731
  }, {
@@ -2777,18 +2879,20 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
2777
2879
  onClick: ($event) => emit("runAction", action)
2778
2880
  }, [__props.runningActionIds.includes(action.id) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_8$6, "progress_activity")) : action.icon ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_9$6, (0, vue.toDisplayString)(action.icon), 1)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(action.label), 1)], 8, _hoisted_7$6);
2779
2881
  }), 128)),
2780
- (0, vue.createElementVNode)("button", {
2882
+ !__props.readonly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
2883
+ key: 0,
2781
2884
  type: "button",
2782
2885
  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",
2783
2886
  "data-testid": "collections-detail-edit",
2784
2887
  onClick: _cache[1] || (_cache[1] = ($event) => emit("edit"))
2785
- }, [_cache[6] || (_cache[6] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "edit", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.editItem")), 1)]),
2786
- (0, vue.createElementVNode)("button", {
2888
+ }, [_cache[6] || (_cache[6] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "edit", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.editItem")), 1)])) : (0, vue.createCommentVNode)("", true),
2889
+ !__props.readonly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
2890
+ key: 1,
2787
2891
  type: "button",
2788
2892
  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",
2789
2893
  "data-testid": "collections-detail-remove",
2790
2894
  onClick: _cache[2] || (_cache[2] = ($event) => emit("delete"))
2791
- }, [_cache[7] || (_cache[7] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.remove")), 1)]),
2895
+ }, [_cache[7] || (_cache[7] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.remove")), 1)])) : (0, vue.createCommentVNode)("", true),
2792
2896
  (0, vue.createElementVNode)("button", {
2793
2897
  type: "button",
2794
2898
  class: "h-8 w-8 flex items-center justify-center rounded text-slate-400 hover:bg-slate-100 hover:text-slate-600 transition-colors",
@@ -2826,26 +2930,26 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
2826
2930
  placeholder: (0, vue.unref)(t)("collectionsView.selectPlaceholder"),
2827
2931
  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",
2828
2932
  "data-testid": `collections-input-${key}`
2829
- }, null, 8, _hoisted_18$5)), [[vue.vModelText, editing.value.text[field.idField]]]) : editing.value && isEditableType(field.type) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("label", _hoisted_19$3, [(0, vue.withDirectives)((0, vue.createElementVNode)("input", {
2933
+ }, null, 8, _hoisted_18$5)), [[vue.vModelText, editing.value.text[field.idField]]]) : editing.value && isEditableType(field.type) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("label", _hoisted_19$4, [(0, vue.withDirectives)((0, vue.createElementVNode)("input", {
2830
2934
  id: `collections-field-${key}`,
2831
2935
  "onUpdate:modelValue": ($event) => editing.value.bool[key] = $event,
2832
2936
  type: "checkbox",
2833
2937
  class: "h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500/20 cursor-pointer",
2834
2938
  "data-testid": `collections-input-${key}`,
2835
2939
  onChange: ($event) => markBoolTouched(String(key))
2836
- }, null, 40, _hoisted_20$3), [[vue.vModelCheckbox, editing.value.bool[key]]]), (0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["text-xs font-semibold", editing.value.bool[key] ? "text-indigo-600" : "text-slate-500"]) }, (0, vue.toDisplayString)(editing.value.bool[key] ? (0, vue.unref)(t)("common.yes") : (0, vue.unref)(t)("common.no")), 3)])) : field.type === "ref" && field.to && __props.render.refOptions(field.to).length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
2940
+ }, null, 40, _hoisted_20$4), [[vue.vModelCheckbox, editing.value.bool[key]]]), (0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["text-xs font-semibold", editing.value.bool[key] ? "text-indigo-600" : "text-slate-500"]) }, (0, vue.toDisplayString)(editing.value.bool[key] ? (0, vue.unref)(t)("common.yes") : (0, vue.unref)(t)("common.no")), 3)])) : field.type === "ref" && field.to && __props.render.refOptions(field.to).length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
2837
2941
  key: 1,
2838
2942
  id: `collections-field-${key}`,
2839
2943
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
2840
2944
  required: isFieldRequiredInUi(field),
2841
2945
  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",
2842
2946
  "data-testid": `collections-input-${key}`
2843
- }, [(0, vue.createElementVNode)("option", _hoisted_22$3, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.refOptions(field.to), (opt) => {
2947
+ }, [(0, vue.createElementVNode)("option", _hoisted_22$4, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.refOptions(field.to), (opt) => {
2844
2948
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
2845
2949
  key: opt.slug,
2846
2950
  value: opt.slug
2847
2951
  }, (0, vue.toDisplayString)(opt.display), 9, _hoisted_23$3);
2848
- }), 128))], 8, _hoisted_21$3)), [[vue.vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
2952
+ }), 128))], 8, _hoisted_21$4)), [[vue.vModelSelect, editing.value.text[key]]]) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? (0, vue.withDirectives)(((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
2849
2953
  key: 2,
2850
2954
  id: `collections-field-${key}`,
2851
2955
  "onUpdate:modelValue": ($event) => editing.value.text[key] = $event,
@@ -2965,8 +3069,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
2965
3069
  key: 3,
2966
3070
  class: "text-xs font-medium text-slate-700 break-words",
2967
3071
  "data-testid": `collections-detail-value-${key}`
2968
- }, [field.type === "toggle" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_53$1, [_cache[12] || (_cache[12] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_54$1, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 1))], 64)) : field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [detailRecord.value[key] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_55$1, [_cache[13] || (_cache[13] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)])) : detailRecord.value[key] === false ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_56$1, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_57$1, "—"))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
2969
- key: 2,
3072
+ }, [field.type === "toggle" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [field.field !== void 0 && String(detailRecord.value[field.field] ?? "") === field.onValue ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_53$1, [_cache[12] || (_cache[12] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_54$1, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 1))], 64)) : field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [detailRecord.value[key] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_55$1, [_cache[13] || (_cache[13] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)])) : detailRecord.value[key] === false ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_56$1, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_57$1, "—"))], 64)) : field.type === "flag" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [__props.render.deriveRecord(detailRecord.value)[key] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
3073
+ key: 0,
3074
+ 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",
3075
+ "data-testid": `collections-detail-flag-${key}`
3076
+ }, [_cache[14] || (_cache[14] = (0, vue.createElementVNode)("span", { class: "h-1.5 w-1.5 rounded-full bg-emerald-500" }, null, -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("common.yes")), 1)], 8, _hoisted_58$1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
3077
+ key: 1,
3078
+ 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",
3079
+ "data-testid": `collections-detail-flag-${key}`
3080
+ }, (0, vue.toDisplayString)((0, vue.unref)(t)("common.no")), 9, _hoisted_59$1))], 64)) : field.type === "ref" && field.to && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3081
+ key: 3,
2970
3082
  href: (0, vue.unref)(cui).recordHref?.(field.to, String(detailRecord.value[key])),
2971
3083
  tabindex: (0, vue.unref)(cui).recordHref?.(field.to, String(detailRecord.value[key])) ? void 0 : 0,
2972
3084
  role: "link",
@@ -2974,16 +3086,16 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
2974
3086
  "data-testid": `collections-detail-ref-${key}`,
2975
3087
  onClick: ($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(detailRecord.value[key])),
2976
3088
  onKeydown: [(0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(detailRecord.value[key])), ["enter"]), (0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(detailRecord.value[key])), ["space"])]
2977
- }, (0, vue.toDisplayString)(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_58$1)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_59$1, (0, vue.toDisplayString)(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_60$1, (0, vue.toDisplayString)(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "rollup" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
2978
- key: 5,
3089
+ }, (0, vue.toDisplayString)(__props.render.refDisplay(field.to, String(detailRecord.value[key]))), 41, _hoisted_60$1)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_61$1, (0, vue.toDisplayString)(__props.render.formatMoney(detailRecord.value[key], __props.render.resolveCurrency(field, detailRecord.value), __props.locale)), 1)) : field.type === "derived" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_62$1, (0, vue.toDisplayString)(__props.render.derivedDisplay(field, __props.render.evaluateDerivedAgainstItem(field, String(key), detailRecord.value), detailRecord.value)), 1)) : field.type === "rollup" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
3090
+ key: 6,
2979
3091
  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",
2980
3092
  "data-testid": `collections-detail-rollup-${key}`
2981
- }, (0, vue.toDisplayString)(__props.render.rollupDisplay(field, detailRecord.value)), 9, _hoisted_61$1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_62$1, [(0, vue.createElementVNode)("table", _hoisted_63$1, [(0, vue.createElementVNode)("thead", _hoisted_64$1, [(0, vue.createElementVNode)("tr", null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.of, (subField, subKey) => {
3093
+ }, (0, vue.toDisplayString)(__props.render.rollupDisplay(field, detailRecord.value)), 9, _hoisted_63$1)) : field.type === "table" && field.of && __props.render.hasTableRows(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_64$1, [(0, vue.createElementVNode)("table", _hoisted_65$1, [(0, vue.createElementVNode)("thead", _hoisted_66$1, [(0, vue.createElementVNode)("tr", null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.of, (subField, subKey) => {
2982
3094
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("th", {
2983
3095
  key: subKey,
2984
3096
  class: "text-left px-4 py-2 font-bold"
2985
3097
  }, (0, vue.toDisplayString)(subField.label), 1);
2986
- }), 128))])]), (0, vue.createElementVNode)("tbody", _hoisted_65$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
3098
+ }), 128))])]), (0, vue.createElementVNode)("tbody", _hoisted_67$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.render.tableRows(detailRecord.value[key]), (row, rowIdx) => {
2987
3099
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("tr", {
2988
3100
  key: rowIdx,
2989
3101
  class: "hover:bg-slate-50/50"
@@ -2991,48 +3103,48 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
2991
3103
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("td", {
2992
3104
  key: subKey,
2993
3105
  class: "px-4 py-2 align-middle font-medium"
2994
- }, [subField.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [row[subKey] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_66$1, "check_circle")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_67$1, "—"))], 64)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
3106
+ }, [subField.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [row[subKey] === true ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_68$1, "check_circle")) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_69$1, "—"))], 64)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
2995
3107
  key: 1,
2996
3108
  class: (0, vue.normalizeClass)([subField.type === "money" ? "font-bold text-slate-800 tabular-nums" : ""])
2997
3109
  }, (0, vue.toDisplayString)(__props.render.formatSubCell(subField, row[subKey], detailRecord.value)), 3))]);
2998
3110
  }), 128))]);
2999
- }), 128))])])])) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_68$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_69$1, (0, vue.toDisplayString)(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionEmbedView_default, {
3000
- key: 9,
3111
+ }), 128))])])])) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_70$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noRows")), 1)) : field.type === "markdown" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_71$1, (0, vue.toDisplayString)(__props.render.detailText(detailRecord.value[key])), 1)) : field.type === "embed" && embedViews.value[key] ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionEmbedView_default, {
3112
+ key: 10,
3001
3113
  view: embedViews.value[key],
3002
3114
  "field-key": String(key)
3003
3115
  }, null, 8, ["view", "field-key"])) : field.type === "backlinks" && backlinksViews.value[key] ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionBacklinksView_default, {
3004
- key: 10,
3116
+ key: 11,
3005
3117
  view: backlinksViews.value[key],
3006
3118
  "field-key": String(key)
3007
3119
  }, null, 8, ["view", "field-key"])) : field.type === "image" && typeof detailRecord.value[key] === "string" && detailRecord.value[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
3008
- key: 11,
3120
+ key: 12,
3009
3121
  src: (0, vue.unref)(resolveImageSrc)(String(detailRecord.value[key])),
3010
3122
  alt: field.label,
3011
3123
  class: "max-h-64 max-w-full object-contain rounded-lg border border-slate-200 bg-slate-50",
3012
3124
  "data-testid": `collections-detail-image-${key}`
3013
- }, null, 8, _hoisted_70$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3014
- key: 12,
3125
+ }, null, 8, _hoisted_72$1)) : field.type !== "file" && __props.render.isExternalUrl(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3126
+ key: 13,
3015
3127
  href: String(detailRecord.value[key]),
3016
3128
  target: "_blank",
3017
3129
  rel: "noopener noreferrer",
3018
3130
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
3019
3131
  "data-testid": `collections-detail-url-${key}`
3020
- }, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_71$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3021
- key: 13,
3132
+ }, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_73$1)) : field.type === "file" && __props.render.artifactUrl(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3133
+ key: 14,
3022
3134
  href: __props.render.artifactUrl(detailRecord.value[key]) ?? void 0,
3023
3135
  target: "_blank",
3024
3136
  rel: "noopener noreferrer",
3025
3137
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
3026
3138
  "data-testid": `collections-detail-file-${key}`
3027
- }, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_72$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3028
- key: 14,
3139
+ }, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_74$1)) : field.type === "file" && __props.render.fileRoutePath(detailRecord.value[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
3140
+ key: 15,
3029
3141
  href: __props.render.fileRoutePath(detailRecord.value[key]) ?? void 0,
3030
3142
  class: "text-blue-600 hover:text-blue-800 font-semibold hover:underline break-all",
3031
3143
  "data-testid": `collections-detail-file-${key}`,
3032
3144
  onClick: ($event) => (0, vue.unref)(activatePathLink)($event, __props.render.fileRoutePath(detailRecord.value[key]) ?? "")
3033
- }, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_73$1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_74$1, (0, vue.toDisplayString)(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_52$1))], 2)) : (0, vue.createCommentVNode)("", true)], 64);
3034
- }), 128)), editing.value && __props.saveError ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_75$1, (0, vue.toDisplayString)(__props.saveError), 1)) : (0, vue.createCommentVNode)("", true)]),
3035
- !editing.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_76$1, [(0, vue.createElementVNode)("label", _hoisted_77$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.itemChatLabel")), 1), (0, vue.createElementVNode)("div", _hoisted_78$1, [(0, vue.withDirectives)((0, vue.createElementVNode)("textarea", {
3145
+ }, (0, vue.toDisplayString)(String(detailRecord.value[key])), 9, _hoisted_75$1)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_76$1, (0, vue.toDisplayString)(__props.render.formatCell(detailRecord.value[key], field.type)), 1))], 8, _hoisted_52$1))], 2)) : (0, vue.createCommentVNode)("", true)], 64);
3146
+ }), 128)), editing.value && __props.saveError ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_77$1, (0, vue.toDisplayString)(__props.saveError), 1)) : (0, vue.createCommentVNode)("", true)]),
3147
+ !editing.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_78$1, [(0, vue.createElementVNode)("label", _hoisted_79$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.itemChatLabel")), 1), (0, vue.createElementVNode)("div", _hoisted_80$1, [(0, vue.withDirectives)((0, vue.createElementVNode)("textarea", {
3036
3148
  id: "collections-detail-chat-input",
3037
3149
  "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => chatMessage.value = $event),
3038
3150
  rows: "2",
@@ -3040,13 +3152,13 @@ var CollectionRecordPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
3040
3152
  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",
3041
3153
  "data-testid": "collections-detail-chat-input",
3042
3154
  onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(submitItemChat, ["meta"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(submitItemChat, ["ctrl"]), ["enter"])]
3043
- }, null, 40, _hoisted_79$1), [[vue.vModelText, chatMessage.value]]), (0, vue.createElementVNode)("button", {
3155
+ }, null, 40, _hoisted_81$1), [[vue.vModelText, chatMessage.value]]), (0, vue.createElementVNode)("button", {
3044
3156
  type: "button",
3045
3157
  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",
3046
3158
  disabled: !chatMessage.value.trim(),
3047
3159
  "data-testid": "collections-detail-chat-send",
3048
3160
  onClick: submitItemChat
3049
- }, [_cache[14] || (_cache[14] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)], 8, _hoisted_80$1)])])) : (0, vue.createCommentVNode)("", true)
3161
+ }, [_cache[15] || (_cache[15] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)], 8, _hoisted_82$1)])])) : (0, vue.createCommentVNode)("", true)
3050
3162
  ]),
3051
3163
  _: 1
3052
3164
  }, 40, ["data-testid"]);
@@ -3841,6 +3953,38 @@ function writeCollectionSort(slug, sort) {
3841
3953
  localStorage.setItem(SORT_STORAGE_KEY, JSON.stringify(all));
3842
3954
  } catch {}
3843
3955
  }
3956
+ var FLAG_FILTER_STORAGE_KEY = "collection_flag_filters";
3957
+ function isFlagFilterState(value) {
3958
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3959
+ return Object.values(value).every((mode) => mode === "hide" || mode === "only");
3960
+ }
3961
+ function readAllFlagFilters() {
3962
+ try {
3963
+ const raw = localStorage.getItem(FLAG_FILTER_STORAGE_KEY);
3964
+ if (!raw) return {};
3965
+ const parsed = JSON.parse(raw);
3966
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
3967
+ const out = {};
3968
+ for (const [slug, value] of Object.entries(parsed)) if (isFlagFilterState(value)) out[slug] = value;
3969
+ return out;
3970
+ } catch {
3971
+ return {};
3972
+ }
3973
+ }
3974
+ /** The slug's persisted chip states ({} when none). A key whose flag no
3975
+ * longer exists in the schema is harmless — the chip list is derived
3976
+ * from the live schema, so a stale entry just never renders/filters. */
3977
+ function readCollectionFlagFilters(slug) {
3978
+ return readAllFlagFilters()[slug] ?? {};
3979
+ }
3980
+ /** Persist the slug's chip states; an empty state clears the entry. */
3981
+ function writeCollectionFlagFilters(slug, filters) {
3982
+ try {
3983
+ const all = Object.fromEntries(Object.entries(readAllFlagFilters()).filter(([key]) => key !== slug));
3984
+ if (Object.keys(filters).length > 0) all[slug] = filters;
3985
+ localStorage.setItem(FLAG_FILTER_STORAGE_KEY, JSON.stringify(all));
3986
+ } catch {}
3987
+ }
3844
3988
  //#endregion
3845
3989
  //#region src/vue/components/CollectionView.vue?vue&type=script&setup=true&lang.ts
3846
3990
  var _hoisted_1$6 = { class: "h-full flex flex-col bg-slate-50/30" };
@@ -3858,222 +4002,240 @@ var _hoisted_6$4 = { class: "flex-1 min-w-0" };
3858
4002
  var _hoisted_7$4 = { class: "text-base font-bold text-slate-800 truncate" };
3859
4003
  var _hoisted_8$4 = {
3860
4004
  key: 0,
3861
- class: "block text-[10px] text-slate-400 font-bold uppercase tracking-wider"
4005
+ class: "block text-[10px] text-slate-400 font-bold uppercase tracking-wider truncate"
3862
4006
  };
3863
- var _hoisted_9$4 = ["disabled"];
3864
- var _hoisted_10$4 = { class: "material-icons text-sm" };
3865
- var _hoisted_11$4 = [
4007
+ var _hoisted_9$4 = {
4008
+ 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",
4009
+ "data-testid": "collections-readonly-chip"
4010
+ };
4011
+ var _hoisted_10$4 = ["href"];
4012
+ var _hoisted_11$4 = ["disabled"];
4013
+ var _hoisted_12$4 = { class: "material-icons text-sm" };
4014
+ var _hoisted_13$4 = [
3866
4015
  "disabled",
3867
4016
  "data-testid",
3868
4017
  "onClick"
3869
4018
  ];
3870
- var _hoisted_12$4 = {
4019
+ var _hoisted_14$4 = {
3871
4020
  key: 0,
3872
4021
  class: "material-icons text-sm animate-spin"
3873
4022
  };
3874
- var _hoisted_13$4 = {
4023
+ var _hoisted_15$4 = {
3875
4024
  key: 1,
3876
4025
  class: "material-icons text-sm"
3877
4026
  };
3878
- var _hoisted_14$4 = ["title", "aria-label"];
3879
- var _hoisted_15$4 = ["title", "aria-label"];
3880
- var _hoisted_16$4 = {
4027
+ var _hoisted_16$4 = ["title", "aria-label"];
4028
+ var _hoisted_17$4 = ["title", "aria-label"];
4029
+ var _hoisted_18$4 = {
3881
4030
  key: 1,
3882
4031
  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",
3883
4032
  "data-testid": "collections-refresh-note"
3884
4033
  };
3885
- var _hoisted_17$4 = { class: "flex-1" };
3886
- var _hoisted_18$4 = {
4034
+ var _hoisted_19$3 = { class: "flex-1" };
4035
+ var _hoisted_20$3 = {
3887
4036
  key: 2,
3888
4037
  class: "px-6 py-3 bg-white border-b border-slate-100 flex items-center justify-between gap-4"
3889
4038
  };
3890
- var _hoisted_19$2 = {
4039
+ var _hoisted_21$3 = {
3891
4040
  key: 0,
3892
4041
  class: "relative flex-1 max-w-md"
3893
4042
  };
3894
- var _hoisted_20$2 = ["placeholder", "aria-label"];
3895
- var _hoisted_21$2 = ["aria-label"];
3896
- var _hoisted_22$2 = { class: "flex items-center gap-2" };
4043
+ var _hoisted_22$3 = ["placeholder", "aria-label"];
3897
4044
  var _hoisted_23$2 = ["aria-label"];
3898
- var _hoisted_24$1 = ["aria-pressed"];
3899
- var _hoisted_25$1 = ["aria-pressed"];
3900
- var _hoisted_26$1 = ["aria-pressed"];
3901
- var _hoisted_27$1 = [
4045
+ var _hoisted_24$1 = { class: "flex items-center gap-2" };
4046
+ var _hoisted_25$1 = ["aria-label"];
4047
+ var _hoisted_26$1 = [
4048
+ "title",
4049
+ "aria-label",
4050
+ "aria-pressed",
4051
+ "data-testid",
4052
+ "onClick"
4053
+ ];
4054
+ var _hoisted_27$1 = {
4055
+ class: "material-icons text-sm",
4056
+ "aria-hidden": "true"
4057
+ };
4058
+ var _hoisted_28 = ["aria-label"];
4059
+ var _hoisted_29 = ["aria-pressed"];
4060
+ var _hoisted_30 = ["aria-pressed"];
4061
+ var _hoisted_31 = ["aria-pressed"];
4062
+ var _hoisted_32 = [
3902
4063
  "aria-pressed",
3903
4064
  "data-testid",
3904
4065
  "onClick"
3905
4066
  ];
3906
- var _hoisted_28 = { class: "material-icons text-sm" };
3907
- var _hoisted_29 = [
4067
+ var _hoisted_33 = { class: "material-icons text-sm" };
4068
+ var _hoisted_34 = [
3908
4069
  "title",
3909
4070
  "aria-label",
3910
4071
  "aria-expanded"
3911
4072
  ];
3912
- var _hoisted_30 = {
4073
+ var _hoisted_35 = {
3913
4074
  key: 0,
3914
4075
  class: "absolute left-0 top-full mt-1 z-20 min-w-max rounded border border-slate-200 bg-white shadow-lg py-1",
3915
4076
  "data-testid": "collection-view-add-menu"
3916
4077
  };
3917
- var _hoisted_31 = ["title", "aria-label"];
3918
- var _hoisted_32 = ["value", "aria-label"];
3919
- var _hoisted_33 = ["value"];
3920
- var _hoisted_34 = ["value", "aria-label"];
3921
- var _hoisted_35 = ["value"];
3922
- var _hoisted_36 = {
3923
- key: 3,
4078
+ var _hoisted_36 = ["title", "aria-label"];
4079
+ var _hoisted_37 = ["value", "aria-label"];
4080
+ var _hoisted_38 = ["value"];
4081
+ var _hoisted_39 = ["value", "aria-label"];
4082
+ var _hoisted_40 = ["value"];
4083
+ var _hoisted_41 = {
4084
+ key: 4,
3924
4085
  class: "text-[10px] text-slate-400 font-bold uppercase tracking-wider select-none"
3925
4086
  };
3926
- var _hoisted_37 = {
4087
+ var _hoisted_42 = {
3927
4088
  key: 3,
3928
4089
  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",
3929
4090
  "data-testid": "collections-data-issues"
3930
4091
  };
3931
- var _hoisted_38 = { class: "flex-1" };
3932
- var _hoisted_39 = { class: "flex-1 overflow-auto" };
3933
- var _hoisted_40 = {
4092
+ var _hoisted_43 = { class: "flex-1" };
4093
+ var _hoisted_44 = { class: "flex-1 overflow-auto" };
4094
+ var _hoisted_45 = {
3934
4095
  key: 0,
3935
4096
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-500 gap-3"
3936
4097
  };
3937
- var _hoisted_41 = {
4098
+ var _hoisted_46 = {
3938
4099
  key: 1,
3939
4100
  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"
3940
4101
  };
3941
- var _hoisted_42 = { key: 2 };
3942
- var _hoisted_43 = {
4102
+ var _hoisted_47 = { key: 2 };
4103
+ var _hoisted_48 = {
3943
4104
  key: 3,
3944
4105
  class: "p-4"
3945
4106
  };
3946
- var _hoisted_44 = {
4107
+ var _hoisted_49 = {
3947
4108
  key: 4,
3948
4109
  class: "h-full flex flex-col"
3949
4110
  };
3950
- var _hoisted_45 = {
4111
+ var _hoisted_50 = {
3951
4112
  key: 0,
3952
4113
  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",
3953
4114
  "data-testid": "collections-inline-error"
3954
4115
  };
3955
- var _hoisted_46 = { class: "flex-1" };
3956
- var _hoisted_47 = ["aria-label"];
3957
- var _hoisted_48 = { class: "flex-1 min-h-0 px-3 py-2" };
3958
- var _hoisted_49 = {
4116
+ var _hoisted_51 = { class: "flex-1" };
4117
+ var _hoisted_52 = ["aria-label"];
4118
+ var _hoisted_53 = { class: "flex-1 min-h-0 px-3 py-2" };
4119
+ var _hoisted_54 = {
3959
4120
  key: 5,
3960
4121
  class: "h-full",
3961
4122
  "data-testid": "collection-custom-view-body"
3962
4123
  };
3963
- var _hoisted_50 = {
4124
+ var _hoisted_55 = {
3964
4125
  key: 6,
3965
4126
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
3966
4127
  };
3967
- var _hoisted_51 = { class: "font-semibold text-slate-600" };
3968
- var _hoisted_52 = {
4128
+ var _hoisted_56 = { class: "font-semibold text-slate-600" };
4129
+ var _hoisted_57 = {
3969
4130
  key: 7,
3970
4131
  class: "flex flex-col items-center justify-center py-20 text-sm text-slate-400 gap-2"
3971
4132
  };
3972
- var _hoisted_53 = { class: "font-semibold text-slate-600" };
3973
- var _hoisted_54 = {
4133
+ var _hoisted_58 = { class: "font-semibold text-slate-600" };
4134
+ var _hoisted_59 = {
3974
4135
  key: 8,
3975
4136
  class: "overflow-x-auto [container-type:inline-size]"
3976
4137
  };
3977
- var _hoisted_55 = {
4138
+ var _hoisted_60 = {
3978
4139
  key: 0,
3979
4140
  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",
3980
4141
  "data-testid": "collections-inline-error"
3981
4142
  };
3982
- var _hoisted_56 = { class: "flex-1" };
3983
- var _hoisted_57 = ["aria-label"];
3984
- var _hoisted_58 = { class: "min-w-full text-xs" };
3985
- var _hoisted_59 = { class: "bg-slate-50 border-b border-slate-200" };
3986
- var _hoisted_60 = ["aria-sort"];
3987
- var _hoisted_61 = { class: "flex items-center gap-1" };
3988
- var _hoisted_62 = ["title"];
3989
- var _hoisted_63 = [
4143
+ var _hoisted_61 = { class: "flex-1" };
4144
+ var _hoisted_62 = ["aria-label"];
4145
+ var _hoisted_63 = { class: "min-w-full text-xs" };
4146
+ var _hoisted_64 = { class: "bg-slate-50 border-b border-slate-200" };
4147
+ var _hoisted_65 = ["aria-sort"];
4148
+ var _hoisted_66 = { class: "flex items-center gap-1" };
4149
+ var _hoisted_67 = ["title"];
4150
+ var _hoisted_68 = [
3990
4151
  "data-testid",
3991
4152
  "aria-label",
3992
4153
  "onClick",
3993
4154
  "onPointerenter"
3994
4155
  ];
3995
- var _hoisted_64 = { class: "material-icons text-base align-middle" };
3996
- var _hoisted_65 = { class: "divide-y divide-slate-100 bg-white" };
3997
- var _hoisted_66 = [
4156
+ var _hoisted_69 = { class: "material-icons text-base align-middle" };
4157
+ var _hoisted_70 = { class: "divide-y divide-slate-100 bg-white" };
4158
+ var _hoisted_71 = [
3998
4159
  "aria-label",
3999
4160
  "data-testid",
4000
4161
  "onClick",
4001
4162
  "onKeydown"
4002
4163
  ];
4003
- var _hoisted_67 = [
4164
+ var _hoisted_72 = [
4004
4165
  "checked",
4005
4166
  "disabled",
4006
4167
  "data-testid",
4007
4168
  "aria-label",
4008
4169
  "onChange"
4009
4170
  ];
4010
- var _hoisted_68 = [
4171
+ var _hoisted_73 = [
4011
4172
  "checked",
4012
4173
  "disabled",
4013
4174
  "data-testid",
4014
4175
  "aria-label",
4015
4176
  "onChange"
4016
4177
  ];
4017
- var _hoisted_69 = {
4018
- key: 2,
4178
+ var _hoisted_74 = ["data-testid", "aria-label"];
4179
+ var _hoisted_75 = {
4180
+ key: 3,
4019
4181
  class: "block truncate"
4020
4182
  };
4021
- var _hoisted_70 = [
4183
+ var _hoisted_76 = [
4022
4184
  "href",
4023
4185
  "tabindex",
4024
4186
  "data-testid",
4025
4187
  "onClick",
4026
4188
  "onKeydown"
4027
4189
  ];
4028
- var _hoisted_71 = [
4190
+ var _hoisted_77 = [
4029
4191
  "value",
4030
4192
  "disabled",
4031
4193
  "data-testid",
4032
4194
  "aria-label",
4033
4195
  "onChange"
4034
4196
  ];
4035
- var _hoisted_72 = {
4197
+ var _hoisted_78 = {
4036
4198
  key: 0,
4037
4199
  value: ""
4038
4200
  };
4039
- var _hoisted_73 = ["value"];
4040
- var _hoisted_74 = {
4041
- key: 4,
4201
+ var _hoisted_79 = ["value"];
4202
+ var _hoisted_80 = {
4203
+ key: 5,
4042
4204
  class: "block truncate tabular-nums font-semibold text-slate-900"
4043
4205
  };
4044
- var _hoisted_75 = {
4045
- key: 5,
4206
+ var _hoisted_81 = {
4207
+ key: 6,
4046
4208
  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"
4047
4209
  };
4048
- var _hoisted_76 = {
4049
- key: 6,
4210
+ var _hoisted_82 = {
4211
+ key: 7,
4050
4212
  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"
4051
4213
  };
4052
- var _hoisted_77 = ["data-testid"];
4053
- var _hoisted_78 = ["href", "data-testid"];
4054
- var _hoisted_79 = ["href", "data-testid"];
4055
- var _hoisted_80 = [
4214
+ var _hoisted_83 = ["data-testid"];
4215
+ var _hoisted_84 = ["href", "data-testid"];
4216
+ var _hoisted_85 = ["href", "data-testid"];
4217
+ var _hoisted_86 = [
4056
4218
  "href",
4057
4219
  "data-testid",
4058
4220
  "onClick"
4059
4221
  ];
4060
- var _hoisted_81 = {
4061
- key: 11,
4222
+ var _hoisted_87 = {
4223
+ key: 12,
4062
4224
  class: "block truncate text-slate-600"
4063
4225
  };
4064
- var _hoisted_82 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
4065
- var _hoisted_83 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
4066
- var _hoisted_84 = { class: "flex-1" };
4067
- var _hoisted_85 = {
4226
+ var _hoisted_88 = { class: "bg-white rounded-2xl shadow-2xl w-full max-w-xl flex flex-col border border-slate-200 overflow-hidden" };
4227
+ var _hoisted_89 = { class: "px-6 py-4 border-b border-slate-100 flex items-center gap-3 bg-slate-50/50" };
4228
+ var _hoisted_90 = { class: "flex-1" };
4229
+ var _hoisted_91 = {
4068
4230
  id: "collections-chat-title",
4069
4231
  class: "text-sm font-bold text-slate-800 uppercase tracking-wide"
4070
4232
  };
4071
- var _hoisted_86 = { class: "text-xs text-slate-400 font-semibold" };
4072
- var _hoisted_87 = ["aria-label"];
4073
- var _hoisted_88 = { class: "px-6 py-5" };
4074
- var _hoisted_89 = ["placeholder", "onKeydown"];
4075
- 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" };
4076
- var _hoisted_91 = ["disabled"];
4233
+ var _hoisted_92 = { class: "text-xs text-slate-400 font-semibold" };
4234
+ var _hoisted_93 = ["aria-label"];
4235
+ var _hoisted_94 = { class: "px-6 py-5" };
4236
+ var _hoisted_95 = ["placeholder", "onKeydown"];
4237
+ 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" };
4238
+ var _hoisted_97 = ["disabled"];
4077
4239
  /** `slug` / `selected` are supplied only in EMBEDDED mode (the
4078
4240
  * `presentCollection` chat card mounts this component and drives both
4079
4241
  * from the tool result). In standalone route mode (the
@@ -4084,6 +4246,7 @@ var _hoisted_91 = ["disabled"];
4084
4246
  * is our "rendered inside a chat" signal. When set, chat-triggering
4085
4247
  * actions send into the current session instead of spawning a new
4086
4248
  * chat (see `runAction` / `submitChat`). */
4249
+ var COMPLETION_CHIP_KEY = "__completion";
4087
4250
  var LIVE_REFRESH_DEBOUNCE_MS = 150;
4088
4251
  //#endregion
4089
4252
  //#region src/vue/components/CollectionView.vue
@@ -4210,6 +4373,84 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4210
4373
  if (!query) return items.value;
4211
4374
  return items.value.filter((item) => itemMatchesQuery(item, query));
4212
4375
  });
4376
+ /** Chip key (state/testid/localStorage) for the synthesized
4377
+ * legacy-completion chip. Field names are unrestricted strings, so a
4378
+ * schema COULD declare a field with this exact name — the chip list
4379
+ * below skips synthesizing in that case, and the predicate dispatch
4380
+ * keys off the structural `synthetic` marker, never this string. */
4381
+ function storedFlagFiltersFor(slug) {
4382
+ return slug ? readCollectionFlagFilters(slug) : {};
4383
+ }
4384
+ const flagFilters = (0, vue.ref)(storedFlagFiltersFor(activeSlug.value));
4385
+ const flagChips = (0, vue.computed)(() => {
4386
+ const schema = collection.value?.schema;
4387
+ if (!schema) return [];
4388
+ const chips = Object.entries(schema.fields).filter(([, field]) => field.type === "flag").map(([key, field]) => ({
4389
+ key,
4390
+ label: field.label ?? key
4391
+ }));
4392
+ if (schema.completionField && schema.completionDoneValues && schema.fields[schema.completionField]?.type !== "flag" && schema.fields[COMPLETION_CHIP_KEY] === void 0) chips.push({
4393
+ key: COMPLETION_CHIP_KEY,
4394
+ label: t("collectionsView.flagDoneChip"),
4395
+ synthetic: true
4396
+ });
4397
+ return chips;
4398
+ });
4399
+ /** Own-property read of a chip's active mode. Field names may shadow
4400
+ * `Object.prototype` members (`toString`, `valueOf`, …) — a plain
4401
+ * `filters[key]` on such a key reads the inherited function, which
4402
+ * renders as an "active" chip that can never cycle (Codex review on
4403
+ * PR #2176). Every chip-state read goes through here. */
4404
+ function flagFilterMode(key) {
4405
+ const filters = flagFilters.value;
4406
+ return Object.hasOwn(filters, key) ? filters[key] : void 0;
4407
+ }
4408
+ /** A flag FIELD's computed boolean for one row (list cells + sort):
4409
+ * the enriched record's value, so a flag over derived/rollup inputs
4410
+ * reads correctly. */
4411
+ function flagValueOf(key, item) {
4412
+ return render.deriveRecord(item)[key] === true;
4413
+ }
4414
+ /** The chip's boolean for one row — `itemIsDone` for the synthesized
4415
+ * completion chip, the computed flag value otherwise. */
4416
+ function chipMatches(chip, item) {
4417
+ const schema = collection.value?.schema;
4418
+ if (!schema) return false;
4419
+ return chip.synthetic ? (0, _mulmoclaude_core_collection.itemIsDone)(schema, item) : flagValueOf(chip.key, item);
4420
+ }
4421
+ /** `filteredItems` further narrowed by every ACTIVE chip (AND). Consumed
4422
+ * only by the table (sortedItems / count summary / empty state). */
4423
+ const tableFilteredItems = (0, vue.computed)(() => {
4424
+ const active = flagChips.value.filter((chip) => flagFilterMode(chip.key) !== void 0);
4425
+ if (active.length === 0) return filteredItems.value;
4426
+ return filteredItems.value.filter((item) => active.every((chip) => chipMatches(chip, item) === (flagFilterMode(chip.key) === "only")));
4427
+ });
4428
+ /** Cycle a chip all → hide → only → all. */
4429
+ function cycleFlagFilter(key) {
4430
+ const current = flagFilterMode(key);
4431
+ const next = current === void 0 ? "hide" : current === "hide" ? "only" : void 0;
4432
+ const rest = Object.fromEntries(Object.entries(flagFilters.value).filter(([entry]) => entry !== key));
4433
+ flagFilters.value = next ? {
4434
+ ...rest,
4435
+ [key]: next
4436
+ } : rest;
4437
+ }
4438
+ function flagChipIcon(key) {
4439
+ const mode = flagFilterMode(key);
4440
+ return mode === "hide" ? "visibility_off" : mode === "only" ? "filter_alt" : "visibility";
4441
+ }
4442
+ function flagChipClass(key) {
4443
+ const mode = flagFilterMode(key);
4444
+ if (mode === "hide") return "bg-slate-600 text-white";
4445
+ if (mode === "only") return "bg-indigo-600 text-white";
4446
+ return "bg-white text-slate-500 border border-slate-200 hover:bg-slate-50";
4447
+ }
4448
+ function flagChipTitle(chip) {
4449
+ const mode = flagFilterMode(chip.key);
4450
+ if (mode === "hide") return t("collectionsView.flagFilterHide", { label: chip.label });
4451
+ if (mode === "only") return t("collectionsView.flagFilterOnly", { label: chip.label });
4452
+ return t("collectionsView.flagFilterAll", { label: chip.label });
4453
+ }
4213
4454
  function storedSortFor(slug) {
4214
4455
  return slug && readCollectionSort(slug) || null;
4215
4456
  }
@@ -4256,10 +4497,11 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4256
4497
  default: return (0, _mulmoclaude_core_collection.stringSortValue)(raw);
4257
4498
  }
4258
4499
  }
4259
- /** Comparable value for one row under the active field. Toggle and derived
4260
- * need the whole record; every other type keys off the raw cell. */
4500
+ /** Comparable value for one row under the active field. Toggle, flag, and
4501
+ * derived need the whole record; every other type keys off the raw cell. */
4261
4502
  function sortValueOf(field, key, item) {
4262
4503
  if (field.type === "toggle") return (0, _mulmoclaude_core_collection.boolSortValue)(toggleChecked(item, field));
4504
+ if (field.type === "flag") return (0, _mulmoclaude_core_collection.boolSortValue)(flagValueOf(key, item));
4263
4505
  if (field.type === "derived") return derivedSortValue(field, key, item);
4264
4506
  return scalarSortValue(field, item[key]);
4265
4507
  }
@@ -4275,8 +4517,8 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4275
4517
  const sortedItems = (0, vue.computed)(() => {
4276
4518
  const state = sortState.value;
4277
4519
  const field = state ? collection.value?.schema.fields[state.field] : void 0;
4278
- if (!state || !field) return filteredItems.value;
4279
- return (0, _mulmoclaude_core_collection.sortItems)(filteredItems.value, state.direction, (item) => sortValueOf(field, state.field, item));
4520
+ if (!state || !field) return tableFilteredItems.value;
4521
+ return (0, _mulmoclaude_core_collection.sortItems)(tableFilteredItems.value, state.direction, (item) => sortValueOf(field, state.field, item));
4280
4522
  });
4281
4523
  /** Stringified primary-key value for a row (the row's stable identity). */
4282
4524
  function rowId(item) {
@@ -4627,10 +4869,22 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
4627
4869
  /** True when the current collection declares `schema.singleton` —
4628
4870
  * exactly one record, its primary key fixed to the declared value. */
4629
4871
  const isSingleton = (0, vue.computed)(() => Boolean(collection.value?.schema.singleton));
4872
+ /** True when the collection is backed by an external `dataSource` (CSV) —
4873
+ * read-only in every write surface here; the server enforces the same
4874
+ * rule with 405s, this just keeps dead controls off the screen. */
4875
+ const isReadOnly = (0, vue.computed)(() => collection.value?.schema.dataSource !== void 0);
4876
+ /** File-explorer route for the dataSource file (the one editable thing
4877
+ * about a read-only collection), or null on a router-less host. */
4878
+ const dataSourceRoute = (0, vue.computed)(() => {
4879
+ const sourcePath = collection.value?.schema.dataSource?.path;
4880
+ return sourcePath ? fileRoutePath(sourcePath) : null;
4881
+ });
4630
4882
  /** Whether the Add button should show. Always for a normal collection;
4631
- * for a singleton only until its one record exists. */
4883
+ * for a singleton only until its one record exists; never for a
4884
+ * read-only (dataSource) collection. */
4632
4885
  const canCreate = (0, vue.computed)(() => {
4633
4886
  if (!collection.value) return false;
4887
+ if (isReadOnly.value) return false;
4634
4888
  return !(isSingleton.value && items.value.length > 0);
4635
4889
  });
4636
4890
  const canDeleteCollection = (0, vue.computed)(() => {
@@ -5022,7 +5276,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5022
5276
  * race the in-flight one. On failure, roll the cell back and surface the
5023
5277
  * error. Bypasses the detail/edit panel entirely. */
5024
5278
  async function commitInlineEdit(item, key, field, raw) {
5025
- if (!collection.value) return;
5279
+ if (!collection.value || isReadOnly.value) return;
5026
5280
  const { slug } = collection.value;
5027
5281
  const itemId = rowId(item);
5028
5282
  if (!itemId || inlineSavingRows.value.has(itemId)) return;
@@ -5210,6 +5464,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5210
5464
  kanbanOverride.value = null;
5211
5465
  addMenuOpen.value = false;
5212
5466
  sortState.value = storedSortFor(slug);
5467
+ flagFilters.value = storedFlagFiltersFor(slug);
5213
5468
  }
5214
5469
  if (slug) loadCollection(slug);
5215
5470
  else {
@@ -5264,6 +5519,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5264
5519
  calendarAnchorField,
5265
5520
  kanbanGroupField,
5266
5521
  sortState,
5522
+ flagFilters,
5267
5523
  loading
5268
5524
  ], () => {
5269
5525
  if (embedded.value) emit("viewStateChange", {
@@ -5274,6 +5530,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5274
5530
  if (activeSlug.value && !loading.value && collection.value) {
5275
5531
  if (!embedded.value) writeCollectionViewMode(activeSlug.value, activeView.value);
5276
5532
  writeCollectionSort(activeSlug.value, sortState.value);
5533
+ writeCollectionFlagFilters(activeSlug.value, flagFilters.value);
5277
5534
  }
5278
5535
  });
5279
5536
  (0, vue.watch)(activeSelected, () => {
@@ -5292,9 +5549,15 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5292
5549
  "aria-label": (0, vue.unref)(t)("collectionsView.backToIndex"),
5293
5550
  "data-testid": "collections-back",
5294
5551
  onClick: goBack
5295
- }, [..._cache[26] || (_cache[26] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : (0, vue.createCommentVNode)("", true),
5552
+ }, [..._cache[27] || (_cache[27] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "arrow_back", -1)])], 8, _hoisted_3$5)) : (0, vue.createCommentVNode)("", true),
5296
5553
  collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4$5, [(0, vue.createElementVNode)("span", _hoisted_5$5, (0, vue.toDisplayString)(collection.value.icon), 1)])) : (0, vue.createCommentVNode)("", true),
5297
- (0, vue.createElementVNode)("div", _hoisted_6$4, [(0, vue.createElementVNode)("h1", _hoisted_7$4, (0, vue.toDisplayString)(collection.value?.title ?? (0, vue.unref)(t)("collectionsView.title")), 1), collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_8$4, (0, vue.toDisplayString)(collection.value.slug), 1)) : (0, vue.createCommentVNode)("", true)]),
5554
+ (0, vue.createElementVNode)("div", _hoisted_6$4, [(0, vue.createElementVNode)("h1", _hoisted_7$4, (0, vue.toDisplayString)(collection.value?.title ?? (0, vue.unref)(t)("collectionsView.title")), 1), collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_8$4, [(0, vue.createTextVNode)((0, vue.toDisplayString)(collection.value.slug) + " ", 1), isReadOnly.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [(0, vue.createElementVNode)("span", _hoisted_9$4, [_cache[28] || (_cache[28] = (0, vue.createElementVNode)("span", { class: "material-icons text-[11px]" }, "lock", -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.readonlyChip")), 1)]), dataSourceRoute.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
5555
+ key: 0,
5556
+ href: dataSourceRoute.value ?? void 0,
5557
+ class: "ml-1 normal-case tracking-normal font-mono font-normal text-slate-500 hover:text-indigo-700 hover:underline",
5558
+ "data-testid": "collections-readonly-source",
5559
+ onClick: _cache[0] || (_cache[0] = ($event) => (0, vue.unref)(activatePathLink)($event, dataSourceRoute.value ?? "", true))
5560
+ }, (0, vue.toDisplayString)(collection.value.schema.dataSource?.path), 9, _hoisted_10$4)) : (0, vue.createCommentVNode)("", true)], 64)) : (0, vue.createCommentVNode)("", true)])) : (0, vue.createCommentVNode)("", true)]),
5298
5561
  collection.value && !embedded.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(pinToggle)), {
5299
5562
  key: 2,
5300
5563
  kind: isFeedRoute.value ? "feed" : "collection",
@@ -5314,14 +5577,14 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5314
5577
  disabled: refreshing.value,
5315
5578
  "data-testid": "collections-refresh-feed",
5316
5579
  onClick: refreshFeed
5317
- }, [(0, vue.createElementVNode)("span", _hoisted_10$4, (0, vue.toDisplayString)(refreshing.value ? "hourglass_empty" : "refresh"), 1), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.refreshFeed")), 1)], 8, _hoisted_9$4)) : (0, vue.createCommentVNode)("", true),
5580
+ }, [(0, vue.createElementVNode)("span", _hoisted_12$4, (0, vue.toDisplayString)(refreshing.value ? "hourglass_empty" : "refresh"), 1), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.refreshFeed")), 1)], 8, _hoisted_11$4)) : (0, vue.createCommentVNode)("", true),
5318
5581
  collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5319
5582
  key: 4,
5320
5583
  type: "button",
5321
5584
  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",
5322
5585
  "data-testid": "collections-chat",
5323
5586
  onClick: openChat
5324
- }, [_cache[27] || (_cache[27] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)])) : (0, vue.createCommentVNode)("", true),
5587
+ }, [_cache[29] || (_cache[29] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "forum", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chat")), 1)])) : (0, vue.createCommentVNode)("", true),
5325
5588
  ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(collectionActions.value, (action) => {
5326
5589
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5327
5590
  key: action.id,
@@ -5330,7 +5593,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5330
5593
  disabled: collectionActionPending.value || isActionRunning(action.id),
5331
5594
  "data-testid": `collections-action-${action.id}`,
5332
5595
  onClick: ($event) => runCollectionAction(action)
5333
- }, [isActionRunning(action.id) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_12$4, "progress_activity")) : action.icon ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_13$4, (0, vue.toDisplayString)(action.icon), 1)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(action.label), 1)], 8, _hoisted_11$4);
5596
+ }, [isActionRunning(action.id) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_14$4, "progress_activity")) : action.icon ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_15$4, (0, vue.toDisplayString)(action.icon), 1)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(action.label), 1)], 8, _hoisted_13$4);
5334
5597
  }), 128)),
5335
5598
  canCreate.value && !calendarActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5336
5599
  key: 5,
@@ -5338,7 +5601,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5338
5601
  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",
5339
5602
  "data-testid": "collections-add-item",
5340
5603
  onClick: openCreate
5341
- }, [_cache[28] || (_cache[28] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "add", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.add")), 1)])) : (0, vue.createCommentVNode)("", true),
5604
+ }, [_cache[30] || (_cache[30] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "add", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.add")), 1)])) : (0, vue.createCommentVNode)("", true),
5342
5605
  canDeleteCollection.value && !embedded.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5343
5606
  key: 6,
5344
5607
  type: "button",
@@ -5347,7 +5610,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5347
5610
  "aria-label": (0, vue.unref)(t)("collectionsView.deleteCollection"),
5348
5611
  "data-testid": "collections-delete",
5349
5612
  onClick: confirmCollectionDelete
5350
- }, [..._cache[29] || (_cache[29] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_14$4)) : (0, vue.createCommentVNode)("", true),
5613
+ }, [..._cache[31] || (_cache[31] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_16$4)) : (0, vue.createCommentVNode)("", true),
5351
5614
  canDeleteFeed.value && !embedded.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5352
5615
  key: 7,
5353
5616
  type: "button",
@@ -5356,28 +5619,45 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5356
5619
  "aria-label": (0, vue.unref)(t)("collectionsView.deleteFeed"),
5357
5620
  "data-testid": "feeds-delete",
5358
5621
  onClick: confirmFeedDelete
5359
- }, [..._cache[30] || (_cache[30] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_15$4)) : (0, vue.createCommentVNode)("", true)
5622
+ }, [..._cache[32] || (_cache[32] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "delete_forever", -1)])], 8, _hoisted_17$4)) : (0, vue.createCommentVNode)("", true)
5360
5623
  ])) : (0, vue.createCommentVNode)("", true),
5361
- refreshNote.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_16$4, [_cache[31] || (_cache[31] = (0, vue.createElementVNode)("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), (0, vue.createElementVNode)("span", _hoisted_17$4, (0, vue.toDisplayString)(refreshNote.value), 1)])) : (0, vue.createCommentVNode)("", true),
5362
- collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_18$4, [!__props.hideSearch && items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_19$2, [
5363
- _cache[33] || (_cache[33] = (0, vue.createElementVNode)("span", { class: "absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400 pointer-events-none" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "search")], -1)),
5624
+ refreshNote.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_18$4, [_cache[33] || (_cache[33] = (0, vue.createElementVNode)("span", { class: "material-icons text-base text-indigo-600" }, "hourglass_top", -1)), (0, vue.createElementVNode)("span", _hoisted_19$3, (0, vue.toDisplayString)(refreshNote.value), 1)])) : (0, vue.createCommentVNode)("", true),
5625
+ collection.value && (!__props.hideSearch && items.value.length > 0 || !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_20$3, [!__props.hideSearch && items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_21$3, [
5626
+ _cache[35] || (_cache[35] = (0, vue.createElementVNode)("span", { class: "absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400 pointer-events-none" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "search")], -1)),
5364
5627
  (0, vue.withDirectives)((0, vue.createElementVNode)("input", {
5365
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
5628
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => searchQuery.value = $event),
5366
5629
  type: "text",
5367
5630
  placeholder: (0, vue.unref)(t)("collectionsView.searchPlaceholder"),
5368
5631
  "aria-label": (0, vue.unref)(t)("collectionsView.searchPlaceholder"),
5369
5632
  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"
5370
- }, null, 8, _hoisted_20$2), [[vue.vModelText, searchQuery.value]]),
5633
+ }, null, 8, _hoisted_22$3), [[vue.vModelText, searchQuery.value]]),
5371
5634
  searchQuery.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5372
5635
  key: 0,
5373
5636
  type: "button",
5374
5637
  "aria-label": (0, vue.unref)(t)("collectionsView.clearSearch"),
5375
5638
  class: "absolute inset-y-0 right-0 flex items-center pr-2.5 text-slate-400 hover:text-slate-600",
5376
- onClick: _cache[1] || (_cache[1] = ($event) => searchQuery.value = "")
5377
- }, [..._cache[32] || (_cache[32] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_21$2)) : (0, vue.createCommentVNode)("", true)
5378
- ])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_22$2, [
5379
- !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
5639
+ onClick: _cache[2] || (_cache[2] = ($event) => searchQuery.value = "")
5640
+ }, [..._cache[34] || (_cache[34] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "close", -1)])], 8, _hoisted_23$2)) : (0, vue.createCommentVNode)("", true)
5641
+ ])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_24$1, [
5642
+ activeView.value === "table" && flagChips.value.length > 0 && items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
5380
5643
  key: 0,
5644
+ class: "flex items-center gap-0.5",
5645
+ role: "group",
5646
+ "aria-label": (0, vue.unref)(t)("collectionsView.flagFilterGroup")
5647
+ }, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(flagChips.value, (chip) => {
5648
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5649
+ key: chip.key,
5650
+ type: "button",
5651
+ class: (0, vue.normalizeClass)(["h-8 px-2.5 flex items-center gap-1 rounded text-xs font-bold transition-colors", flagChipClass(chip.key)]),
5652
+ title: flagChipTitle(chip),
5653
+ "aria-label": flagChipTitle(chip),
5654
+ "aria-pressed": flagFilterMode(chip.key) !== void 0,
5655
+ "data-testid": `collections-flag-chip-${chip.key}`,
5656
+ onClick: ($event) => cycleFlagFilter(chip.key)
5657
+ }, [(0, vue.createElementVNode)("span", _hoisted_27$1, (0, vue.toDisplayString)(flagChipIcon(chip.key)), 1), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(chip.label), 1)], 10, _hoisted_26$1);
5658
+ }), 128))], 8, _hoisted_25$1)) : (0, vue.createCommentVNode)("", true),
5659
+ !__props.hideViewToggle && (hasCalendar.value || hasKanban.value || hasCustomViews.value || canAddCustomView.value) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
5660
+ key: 1,
5381
5661
  class: "flex gap-0.5",
5382
5662
  role: "group",
5383
5663
  "aria-label": (0, vue.unref)(t)("collectionsView.viewToggle")
@@ -5387,24 +5667,24 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5387
5667
  class: (0, vue.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"]),
5388
5668
  "aria-pressed": activeView.value === "table",
5389
5669
  "data-testid": "collection-view-toggle-table",
5390
- onClick: _cache[2] || (_cache[2] = ($event) => setView("table"))
5391
- }, [_cache[34] || (_cache[34] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "table_rows", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewTable")), 1)], 10, _hoisted_24$1),
5670
+ onClick: _cache[3] || (_cache[3] = ($event) => setView("table"))
5671
+ }, [_cache[36] || (_cache[36] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "table_rows", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewTable")), 1)], 10, _hoisted_29),
5392
5672
  hasCalendar.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5393
5673
  key: 0,
5394
5674
  type: "button",
5395
5675
  class: (0, vue.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"]),
5396
5676
  "aria-pressed": activeView.value === "calendar",
5397
5677
  "data-testid": "collection-view-toggle-calendar",
5398
- onClick: _cache[3] || (_cache[3] = ($event) => setView("calendar"))
5399
- }, [_cache[35] || (_cache[35] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "calendar_month", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_25$1)) : (0, vue.createCommentVNode)("", true),
5678
+ onClick: _cache[4] || (_cache[4] = ($event) => setView("calendar"))
5679
+ }, [_cache[37] || (_cache[37] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "calendar_month", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewCalendar")), 1)], 10, _hoisted_30)) : (0, vue.createCommentVNode)("", true),
5400
5680
  hasKanban.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5401
5681
  key: 1,
5402
5682
  type: "button",
5403
5683
  class: (0, vue.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"]),
5404
5684
  "aria-pressed": activeView.value === "kanban",
5405
5685
  "data-testid": "collection-view-toggle-kanban",
5406
- onClick: _cache[4] || (_cache[4] = ($event) => setView("kanban"))
5407
- }, [_cache[36] || (_cache[36] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "view_kanban", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_26$1)) : (0, vue.createCommentVNode)("", true),
5686
+ onClick: _cache[5] || (_cache[5] = ($event) => setView("kanban"))
5687
+ }, [_cache[38] || (_cache[38] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "view_kanban", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.viewKanban")), 1)], 10, _hoisted_31)) : (0, vue.createCommentVNode)("", true),
5408
5688
  ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(customViews.value, (cv) => {
5409
5689
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5410
5690
  key: cv.id,
@@ -5413,7 +5693,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5413
5693
  "aria-pressed": activeView.value === (0, vue.unref)(customViewKey)(cv.id),
5414
5694
  "data-testid": `collection-view-custom-${cv.id}`,
5415
5695
  onClick: ($event) => setCustomView(cv.id)
5416
- }, [(0, vue.createElementVNode)("span", _hoisted_28, (0, vue.toDisplayString)(cv.icon || (cv.target === "mobile" ? "smartphone" : "dashboard_customize")), 1), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(cv.label), 1)], 10, _hoisted_27$1);
5696
+ }, [(0, vue.createElementVNode)("span", _hoisted_33, (0, vue.toDisplayString)(cv.icon || (cv.target === "mobile" ? "smartphone" : "dashboard_customize")), 1), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(cv.label), 1)], 10, _hoisted_32);
5417
5697
  }), 128)),
5418
5698
  canAddCustomView.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
5419
5699
  key: 2,
@@ -5428,17 +5708,17 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5428
5708
  "aria-expanded": addMenuOpen.value,
5429
5709
  "data-testid": "collection-view-add",
5430
5710
  onClick: onAddViewClick
5431
- }, [..._cache[37] || (_cache[37] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_29), addMenuOpen.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_30, [(0, vue.createElementVNode)("button", {
5711
+ }, [..._cache[39] || (_cache[39] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "add", -1)])], 8, _hoisted_34), addMenuOpen.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_35, [(0, vue.createElementVNode)("button", {
5432
5712
  type: "button",
5433
5713
  class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
5434
5714
  "data-testid": "collection-view-add-desktop",
5435
- onClick: _cache[5] || (_cache[5] = ($event) => addCustomView("desktop"))
5436
- }, [_cache[38] || (_cache[38] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "dashboard_customize", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addViewDesktop")), 1)]), (0, vue.createElementVNode)("button", {
5715
+ onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("desktop"))
5716
+ }, [_cache[40] || (_cache[40] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "dashboard_customize", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addViewDesktop")), 1)]), (0, vue.createElementVNode)("button", {
5437
5717
  type: "button",
5438
5718
  class: "w-full h-8 px-3 flex items-center gap-2 text-xs font-bold text-slate-600 hover:bg-slate-50",
5439
5719
  "data-testid": "collection-view-add-mobile",
5440
- onClick: _cache[6] || (_cache[6] = ($event) => addCustomView("mobile"))
5441
- }, [_cache[39] || (_cache[39] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "smartphone", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addViewMobile")), 1)])])) : (0, vue.createCommentVNode)("", true)], 512)) : (0, vue.createCommentVNode)("", true),
5720
+ onClick: _cache[7] || (_cache[7] = ($event) => addCustomView("mobile"))
5721
+ }, [_cache[41] || (_cache[41] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "smartphone", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.addViewMobile")), 1)])])) : (0, vue.createCommentVNode)("", true)], 512)) : (0, vue.createCommentVNode)("", true),
5442
5722
  canConfigureViews.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5443
5723
  key: 3,
5444
5724
  type: "button",
@@ -5446,51 +5726,51 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5446
5726
  title: (0, vue.unref)(t)("collectionsView.config.open"),
5447
5727
  "aria-label": (0, vue.unref)(t)("collectionsView.config.open"),
5448
5728
  "data-testid": "collection-config-open",
5449
- onClick: _cache[7] || (_cache[7] = ($event) => configOpen.value = true)
5450
- }, [..._cache[40] || (_cache[40] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_31)) : (0, vue.createCommentVNode)("", true)
5451
- ], 8, _hoisted_23$2)) : (0, vue.createCommentVNode)("", true),
5729
+ onClick: _cache[8] || (_cache[8] = ($event) => configOpen.value = true)
5730
+ }, [..._cache[42] || (_cache[42] = [(0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "settings", -1)])], 8, _hoisted_36)) : (0, vue.createCommentVNode)("", true)
5731
+ ], 8, _hoisted_28)) : (0, vue.createCommentVNode)("", true),
5452
5732
  calendarActive.value && dateFields.value.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
5453
- key: 1,
5733
+ key: 2,
5454
5734
  value: calendarAnchorField.value,
5455
5735
  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",
5456
5736
  "aria-label": (0, vue.unref)(t)("collectionsView.calendarFieldLabel"),
5457
5737
  "data-testid": "collection-calendar-field",
5458
- onChange: _cache[8] || (_cache[8] = ($event) => anchorOverride.value = $event.target.value)
5738
+ onChange: _cache[9] || (_cache[9] = ($event) => anchorOverride.value = $event.target.value)
5459
5739
  }, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(dateFields.value, (key) => {
5460
5740
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
5461
5741
  key,
5462
5742
  value: key
5463
- }, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_33);
5464
- }), 128))], 40, _hoisted_32)) : (0, vue.createCommentVNode)("", true),
5743
+ }, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_38);
5744
+ }), 128))], 40, _hoisted_37)) : (0, vue.createCommentVNode)("", true),
5465
5745
  kanbanActive.value && enumFields.value.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
5466
- key: 2,
5746
+ key: 3,
5467
5747
  value: kanbanGroupField.value,
5468
5748
  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",
5469
5749
  "aria-label": (0, vue.unref)(t)("collectionsView.kanbanFieldLabel"),
5470
5750
  "data-testid": "collection-kanban-field",
5471
- onChange: _cache[9] || (_cache[9] = ($event) => kanbanOverride.value = $event.target.value)
5751
+ onChange: _cache[10] || (_cache[10] = ($event) => kanbanOverride.value = $event.target.value)
5472
5752
  }, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(enumFields.value, (key) => {
5473
5753
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
5474
5754
  key,
5475
5755
  value: key
5476
- }, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_35);
5477
- }), 128))], 40, _hoisted_34)) : (0, vue.createCommentVNode)("", true),
5478
- items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_36, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.searchSummary", {
5479
- shown: filteredItems.value.length,
5756
+ }, (0, vue.toDisplayString)(collection.value?.schema.fields[key]?.label ?? key), 9, _hoisted_40);
5757
+ }), 128))], 40, _hoisted_39)) : (0, vue.createCommentVNode)("", true),
5758
+ items.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_41, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.searchSummary", {
5759
+ shown: activeView.value === "table" ? tableFilteredItems.value.length : filteredItems.value.length,
5480
5760
  total: items.value.length
5481
5761
  })), 1)) : (0, vue.createCommentVNode)("", true)
5482
5762
  ])])) : (0, vue.createCommentVNode)("", true),
5483
- collection.value && dataIssues.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_37, [
5484
- _cache[42] || (_cache[42] = (0, vue.createElementVNode)("span", { class: "material-icons text-amber-600" }, "warning", -1)),
5485
- (0, vue.createElementVNode)("span", _hoisted_38, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
5763
+ collection.value && dataIssues.value.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_42, [
5764
+ _cache[44] || (_cache[44] = (0, vue.createElementVNode)("span", { class: "material-icons text-amber-600" }, "warning", -1)),
5765
+ (0, vue.createElementVNode)("span", _hoisted_43, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.dataIssuesDetected", { count: dataIssues.value.length })), 1),
5486
5766
  (0, vue.createElementVNode)("button", {
5487
5767
  type: "button",
5488
5768
  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",
5489
5769
  "data-testid": "collections-repair",
5490
5770
  onClick: repairCollection
5491
- }, [_cache[41] || (_cache[41] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "build", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.repair")), 1)])
5771
+ }, [_cache[43] || (_cache[43] = (0, vue.createElementVNode)("span", { class: "material-icons text-sm" }, "build", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.repair")), 1)])
5492
5772
  ])) : (0, vue.createCommentVNode)("", true),
5493
- (0, vue.createElementVNode)("div", _hoisted_39, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_40, [_cache[43] || (_cache[43] = (0, vue.createElementVNode)("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.loading")), 1)])) : loadError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_41, [_cache[44] || (_cache[44] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(loadError.value === "not-found" ? (0, vue.unref)(t)("collectionsView.notFound") : `${(0, vue.unref)(t)("collectionsView.loadFailed")}: ${loadError.value}`), 1)])) : !collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_42)) : calendarActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_43, [(0, vue.createVNode)(CollectionCalendarView_default, {
5773
+ (0, vue.createElementVNode)("div", _hoisted_44, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_45, [_cache[45] || (_cache[45] = (0, vue.createElementVNode)("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.loading")), 1)])) : loadError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_46, [_cache[46] || (_cache[46] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(loadError.value === "not-found" ? (0, vue.unref)(t)("collectionsView.notFound") : `${(0, vue.unref)(t)("collectionsView.loadFailed")}: ${loadError.value}`), 1)])) : !collection.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_47)) : calendarActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_48, [(0, vue.createVNode)(CollectionCalendarView_default, {
5494
5774
  schema: collection.value.schema,
5495
5775
  items: filteredItems.value,
5496
5776
  "anchor-field": calendarAnchorField.value,
@@ -5526,7 +5806,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5526
5806
  }, {
5527
5807
  detail: (0, vue.withCtx)(() => [(0, vue.createVNode)(CollectionRecordPanel_default, {
5528
5808
  editing: editing.value,
5529
- "onUpdate:editing": _cache[10] || (_cache[10] = ($event) => editing.value = $event),
5809
+ "onUpdate:editing": _cache[11] || (_cache[11] = ($event) => editing.value = $event),
5530
5810
  collection: collection.value,
5531
5811
  viewing: viewing.value,
5532
5812
  saving: saving.value,
@@ -5539,13 +5819,14 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5539
5819
  "live-derived": liveDerived.value,
5540
5820
  "view-title": viewTitle.value,
5541
5821
  "is-singleton": isSingleton.value,
5822
+ readonly: isReadOnly.value,
5542
5823
  render: (0, vue.unref)(render),
5543
5824
  locale: (0, vue.unref)(locale),
5544
5825
  onSubmit: saveEditor,
5545
5826
  onCancel: cancelEditor,
5546
5827
  onEdit: editFromView,
5547
5828
  onClose: onDayClose,
5548
- onDelete: _cache[11] || (_cache[11] = ($event) => viewing.value && confirmDelete(viewing.value)),
5829
+ onDelete: _cache[12] || (_cache[12] = ($event) => viewing.value && confirmDelete(viewing.value)),
5549
5830
  onRunAction: runAction,
5550
5831
  onItemChat
5551
5832
  }, null, 8, [
@@ -5562,6 +5843,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5562
5843
  "live-derived",
5563
5844
  "view-title",
5564
5845
  "is-singleton",
5846
+ "readonly",
5565
5847
  "render",
5566
5848
  "locale"
5567
5849
  ])]),
@@ -5577,21 +5859,22 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5577
5859
  "selected",
5578
5860
  "can-create",
5579
5861
  "show-detail"
5580
- ])) : (0, vue.createCommentVNode)("", true)])) : kanbanActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_44, [inlineError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_45, [
5581
- _cache[46] || (_cache[46] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)),
5582
- (0, vue.createElementVNode)("span", _hoisted_46, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5862
+ ])) : (0, vue.createCommentVNode)("", true)])) : kanbanActive.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_49, [inlineError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_50, [
5863
+ _cache[48] || (_cache[48] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)),
5864
+ (0, vue.createElementVNode)("span", _hoisted_51, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5583
5865
  (0, vue.createElementVNode)("button", {
5584
5866
  type: "button",
5585
5867
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
5586
5868
  "aria-label": (0, vue.unref)(t)("common.close"),
5587
- onClick: _cache[12] || (_cache[12] = ($event) => inlineError.value = null)
5588
- }, [..._cache[45] || (_cache[45] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_47)
5589
- ])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_48, [(0, vue.createVNode)(CollectionKanbanView_default, {
5869
+ onClick: _cache[13] || (_cache[13] = ($event) => inlineError.value = null)
5870
+ }, [..._cache[47] || (_cache[47] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_52)
5871
+ ])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_53, [(0, vue.createVNode)(CollectionKanbanView_default, {
5590
5872
  schema: collection.value.schema,
5591
5873
  items: filteredItems.value,
5592
5874
  "group-field": kanbanGroupField.value,
5593
5875
  selected: viewing.value ? String(viewing.value[collection.value.schema.primaryKey] ?? "") : void 0,
5594
5876
  notified: notifiedSeverities.value,
5877
+ readonly: isReadOnly.value,
5595
5878
  onSelect: onCalendarSelect,
5596
5879
  onMove: onKanbanMove
5597
5880
  }, null, 8, [
@@ -5599,8 +5882,9 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5599
5882
  "items",
5600
5883
  "group-field",
5601
5884
  "selected",
5602
- "notified"
5603
- ])])])) : activeCustomView.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_49, [activeCustomView.value.target === "mobile" ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionRemoteViewPreview_default, {
5885
+ "notified",
5886
+ "readonly"
5887
+ ])])])) : activeCustomView.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_54, [activeCustomView.value.target === "mobile" ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionRemoteViewPreview_default, {
5604
5888
  key: 0,
5605
5889
  slug: collection.value.slug,
5606
5890
  view: activeCustomView.value,
@@ -5611,32 +5895,32 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5611
5895
  view: activeCustomView.value,
5612
5896
  onOpenItem: onCustomViewOpenItem,
5613
5897
  onStartChat: onCustomViewStartChat
5614
- }, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_50, [_cache[47] || (_cache[47] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), (0, vue.createElementVNode)("p", _hoisted_51, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.itemsEmpty")), 1)])) : filteredItems.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_52, [
5615
- _cache[48] || (_cache[48] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
5616
- (0, vue.createElementVNode)("p", _hoisted_53, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noMatchingItems")), 1),
5898
+ }, null, 8, ["slug", "view"]))])) : items.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_55, [_cache[49] || (_cache[49] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300" }, "folder_open", -1)), (0, vue.createElementVNode)("p", _hoisted_56, (0, vue.toDisplayString)((0, vue.unref)(t)(isReadOnly.value ? "collectionsView.itemsEmptyReadonly" : "collectionsView.itemsEmpty")), 1)])) : tableFilteredItems.value.length === 0 && editing.value?.mode !== "create" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_57, [
5899
+ _cache[50] || (_cache[50] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300" }, "search_off", -1)),
5900
+ (0, vue.createElementVNode)("p", _hoisted_58, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.noMatchingItems")), 1),
5617
5901
  (0, vue.createElementVNode)("button", {
5618
5902
  type: "button",
5619
5903
  class: "text-xs text-indigo-600 font-semibold hover:underline",
5620
- onClick: _cache[13] || (_cache[13] = ($event) => searchQuery.value = "")
5904
+ onClick: _cache[14] || (_cache[14] = ($event) => (searchQuery.value = "", flagFilters.value = {}))
5621
5905
  }, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.clearSearch")), 1)
5622
- ])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_54, [inlineError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_55, [
5623
- _cache[50] || (_cache[50] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)),
5624
- (0, vue.createElementVNode)("span", _hoisted_56, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5906
+ ])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_59, [inlineError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_60, [
5907
+ _cache[52] || (_cache[52] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)),
5908
+ (0, vue.createElementVNode)("span", _hoisted_61, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.inlineSaveFailed", { error: inlineError.value })), 1),
5625
5909
  (0, vue.createElementVNode)("button", {
5626
5910
  type: "button",
5627
5911
  class: "h-8 w-8 flex items-center justify-center rounded text-red-600 hover:bg-red-100",
5628
5912
  "aria-label": (0, vue.unref)(t)("common.close"),
5629
- onClick: _cache[14] || (_cache[14] = ($event) => inlineError.value = null)
5630
- }, [..._cache[49] || (_cache[49] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_57)
5631
- ])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("table", _hoisted_58, [(0, vue.createElementVNode)("thead", null, [(0, vue.createElementVNode)("tr", _hoisted_59, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(listColumnFields.value, ([key, field]) => {
5913
+ onClick: _cache[15] || (_cache[15] = ($event) => inlineError.value = null)
5914
+ }, [..._cache[51] || (_cache[51] = [(0, vue.createElementVNode)("span", { class: "material-icons text-base" }, "close", -1)])], 8, _hoisted_62)
5915
+ ])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("table", _hoisted_63, [(0, vue.createElementVNode)("thead", null, [(0, vue.createElementVNode)("tr", _hoisted_64, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(listColumnFields.value, ([key, field]) => {
5632
5916
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("th", {
5633
5917
  key,
5634
5918
  "aria-sort": (0, vue.unref)(_mulmoclaude_core_collection.isSortableField)(field) ? sortAriaValue(key) : void 0,
5635
5919
  class: "px-5 py-3 font-bold text-slate-500 text-left uppercase tracking-wider whitespace-nowrap"
5636
- }, [(0, vue.createElementVNode)("div", _hoisted_61, [(0, vue.createElementVNode)("span", {
5920
+ }, [(0, vue.createElementVNode)("div", _hoisted_66, [(0, vue.createElementVNode)("span", {
5637
5921
  class: "truncate max-w-[14rem]",
5638
5922
  title: field.label
5639
- }, (0, vue.toDisplayString)(field.label), 9, _hoisted_62), (0, vue.unref)(_mulmoclaude_core_collection.isSortableField)(field) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5923
+ }, (0, vue.toDisplayString)(field.label), 9, _hoisted_67), (0, vue.unref)(_mulmoclaude_core_collection.isSortableField)(field) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
5640
5924
  key: 0,
5641
5925
  type: "button",
5642
5926
  class: (0, vue.normalizeClass)(["inline-flex items-center justify-center rounded p-0.5 -my-1 leading-none transition-colors", sortButtonClass(key)]),
@@ -5644,9 +5928,9 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5644
5928
  "aria-label": (0, vue.unref)(t)("collectionsView.sortBy", { field: field.label }),
5645
5929
  onClick: (0, vue.withModifiers)(($event) => cycleSort(key), ["stop"]),
5646
5930
  onPointerenter: ($event) => hoveredSortKey.value = key,
5647
- onPointerleave: _cache[15] || (_cache[15] = ($event) => hoveredSortKey.value = null)
5648
- }, [(0, vue.createElementVNode)("span", _hoisted_64, (0, vue.toDisplayString)(sortIconName(key)), 1)], 42, _hoisted_63)) : (0, vue.createCommentVNode)("", true)])], 8, _hoisted_60);
5649
- }), 128))])]), (0, vue.createElementVNode)("tbody", _hoisted_65, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(sortedItems.value, (item) => {
5931
+ onPointerleave: _cache[16] || (_cache[16] = ($event) => hoveredSortKey.value = null)
5932
+ }, [(0, vue.createElementVNode)("span", _hoisted_69, (0, vue.toDisplayString)(sortIconName(key)), 1)], 42, _hoisted_68)) : (0, vue.createCommentVNode)("", true)])], 8, _hoisted_65);
5933
+ }), 128))])]), (0, vue.createElementVNode)("tbody", _hoisted_70, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(sortedItems.value, (item) => {
5650
5934
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("tr", {
5651
5935
  key: String(item[collection.value.schema.primaryKey] ?? ""),
5652
5936
  class: (0, vue.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" : ""]),
@@ -5664,23 +5948,29 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5664
5948
  key: 0,
5665
5949
  type: "checkbox",
5666
5950
  checked: toggleChecked(item, field),
5667
- disabled: isRowInlineSaving(item),
5951
+ disabled: isReadOnly.value || isRowInlineSaving(item),
5668
5952
  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",
5669
5953
  "data-testid": `collections-inline-toggle-${key}-${item[collection.value.schema.primaryKey]}`,
5670
5954
  "aria-label": field.label,
5671
- onClick: _cache[16] || (_cache[16] = (0, vue.withModifiers)(() => {}, ["stop"])),
5955
+ onClick: _cache[17] || (_cache[17] = (0, vue.withModifiers)(() => {}, ["stop"])),
5672
5956
  onChange: ($event) => commitToggle(item, field)
5673
- }, null, 40, _hoisted_67)) : field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
5957
+ }, null, 40, _hoisted_72)) : field.type === "boolean" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
5674
5958
  key: 1,
5675
5959
  type: "checkbox",
5676
5960
  checked: item[key] === true,
5677
- disabled: isRowInlineSaving(item),
5961
+ disabled: isReadOnly.value || isRowInlineSaving(item),
5678
5962
  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",
5679
5963
  "data-testid": `collections-inline-bool-${key}-${item[collection.value.schema.primaryKey]}`,
5680
5964
  "aria-label": field.label,
5681
- onClick: _cache[17] || (_cache[17] = (0, vue.withModifiers)(() => {}, ["stop"])),
5965
+ onClick: _cache[18] || (_cache[18] = (0, vue.withModifiers)(() => {}, ["stop"])),
5682
5966
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.checked)
5683
- }, null, 40, _hoisted_68)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_69, [(0, vue.createElementVNode)("a", {
5967
+ }, null, 40, _hoisted_73)) : field.type === "flag" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
5968
+ key: 2,
5969
+ class: (0, vue.normalizeClass)(["material-icons text-lg align-middle", flagValueOf(String(key), item) ? "text-emerald-600" : "text-slate-300"]),
5970
+ "data-testid": `collections-flag-${key}-${item[collection.value.schema.primaryKey]}`,
5971
+ "aria-label": `${field.label}: ${(0, vue.unref)(t)(flagValueOf(String(key), item) ? "common.yes" : "common.no")}`,
5972
+ role: "img"
5973
+ }, (0, vue.toDisplayString)(flagValueOf(String(key), item) ? "check_circle" : "radio_button_unchecked"), 11, _hoisted_74)) : field.type === "ref" && field.to && typeof item[key] === "string" && item[key] ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_75, [(0, vue.createElementVNode)("a", {
5684
5974
  href: (0, vue.unref)(cui).recordHref?.(field.to, String(item[key])),
5685
5975
  tabindex: (0, vue.unref)(cui).recordHref?.(field.to, String(item[key])) ? void 0 : 0,
5686
5976
  role: "link",
@@ -5688,48 +5978,48 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5688
5978
  "data-testid": `collections-ref-link-${key}-${item[key]}`,
5689
5979
  onClick: ($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(item[key]), true),
5690
5980
  onKeydown: [(0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(item[key]), true), ["enter"]), (0, vue.withKeys)(($event) => (0, vue.unref)(activateRefLink)($event, field.to, String(item[key]), true), ["space"])]
5691
- }, (0, vue.toDisplayString)((0, vue.unref)(refDisplay)(field.to, String(item[key]))), 41, _hoisted_70)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
5692
- key: 3,
5981
+ }, (0, vue.toDisplayString)((0, vue.unref)(refDisplay)(field.to, String(item[key]))), 41, _hoisted_76)])) : field.type === "enum" && Array.isArray(field.values) && field.values.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("select", {
5982
+ key: 4,
5693
5983
  value: item[key] == null ? "" : String(item[key]),
5694
- disabled: isRowInlineSaving(item),
5984
+ disabled: isReadOnly.value || isRowInlineSaving(item),
5695
5985
  class: (0, vue.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])]),
5696
5986
  "data-testid": `collections-inline-enum-${key}-${item[collection.value.schema.primaryKey]}`,
5697
5987
  "aria-label": field.label,
5698
- onClick: _cache[18] || (_cache[18] = (0, vue.withModifiers)(() => {}, ["stop"])),
5988
+ onClick: _cache[19] || (_cache[19] = (0, vue.withModifiers)(() => {}, ["stop"])),
5699
5989
  onChange: ($event) => commitInlineEdit(item, String(key), field, $event.target.value)
5700
- }, [showEnumPlaceholder(item, String(key)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("option", _hoisted_72, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1)) : (0, vue.createCommentVNode)("", true), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.values, (value) => {
5990
+ }, [showEnumPlaceholder(item, String(key)) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("option", _hoisted_78, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.selectPlaceholder")), 1)) : (0, vue.createCommentVNode)("", true), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(field.values, (value) => {
5701
5991
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
5702
5992
  key: value,
5703
5993
  value
5704
- }, (0, vue.toDisplayString)(value), 9, _hoisted_73);
5705
- }), 128))], 42, _hoisted_71)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_74, (0, vue.toDisplayString)((0, vue.unref)(formatMoney)(item[key], (0, vue.unref)(resolveCurrency)(field, item), (0, vue.unref)(locale))), 1)) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_75, [_cache[51] || (_cache[51] = (0, vue.createElementVNode)("span", { class: "material-icons text-[11px]" }, "list", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(tableSummary(item[key])), 1)])) : field.type === "derived" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_76, (0, vue.toDisplayString)((0, vue.unref)(derivedDisplay)(field, (0, vue.unref)(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type === "rollup" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
5706
- key: 7,
5994
+ }, (0, vue.toDisplayString)(value), 9, _hoisted_79);
5995
+ }), 128))], 42, _hoisted_77)) : field.type === "money" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_80, (0, vue.toDisplayString)((0, vue.unref)(formatMoney)(item[key], (0, vue.unref)(resolveCurrency)(field, item), (0, vue.unref)(locale))), 1)) : field.type === "table" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_81, [_cache[53] || (_cache[53] = (0, vue.createElementVNode)("span", { class: "material-icons text-[11px]" }, "list", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(tableSummary(item[key])), 1)])) : field.type === "derived" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_82, (0, vue.toDisplayString)((0, vue.unref)(derivedDisplay)(field, (0, vue.unref)(evaluateDerivedAgainstItem)(field, String(key), item), item)), 1)) : field.type === "rollup" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
5996
+ key: 8,
5707
5997
  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",
5708
5998
  "data-testid": `collections-rollup-${key}-${item[collection.value.schema.primaryKey]}`
5709
- }, (0, vue.toDisplayString)((0, vue.unref)(render).rollupDisplay(field, item)), 9, _hoisted_77)) : field.type !== "file" && (0, vue.unref)(isExternalUrl)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
5710
- key: 8,
5999
+ }, (0, vue.toDisplayString)((0, vue.unref)(render).rollupDisplay(field, item)), 9, _hoisted_83)) : field.type !== "file" && (0, vue.unref)(isExternalUrl)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
6000
+ key: 9,
5711
6001
  href: String(item[key]),
5712
6002
  target: "_blank",
5713
6003
  rel: "noopener noreferrer",
5714
6004
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5715
6005
  "data-testid": `collections-url-link-${key}-${item[collection.value.schema.primaryKey]}`,
5716
- onClick: _cache[19] || (_cache[19] = (0, vue.withModifiers)(() => {}, ["stop"]))
5717
- }, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_78)) : field.type === "file" && (0, vue.unref)(artifactUrl)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
5718
- key: 9,
6006
+ onClick: _cache[20] || (_cache[20] = (0, vue.withModifiers)(() => {}, ["stop"]))
6007
+ }, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_84)) : field.type === "file" && (0, vue.unref)(artifactUrl)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
6008
+ key: 10,
5719
6009
  href: (0, vue.unref)(artifactUrl)(item[key]) ?? void 0,
5720
6010
  target: "_blank",
5721
6011
  rel: "noopener noreferrer",
5722
6012
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5723
6013
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
5724
- onClick: _cache[20] || (_cache[20] = (0, vue.withModifiers)(() => {}, ["stop"]))
5725
- }, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_79)) : field.type === "file" && (0, vue.unref)(fileRoutePath)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
5726
- key: 10,
6014
+ onClick: _cache[21] || (_cache[21] = (0, vue.withModifiers)(() => {}, ["stop"]))
6015
+ }, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_85)) : field.type === "file" && (0, vue.unref)(fileRoutePath)(item[key]) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
6016
+ key: 11,
5727
6017
  href: (0, vue.unref)(fileRoutePath)(item[key]) ?? void 0,
5728
6018
  class: "block truncate text-blue-600 hover:text-blue-800 hover:underline font-semibold",
5729
6019
  "data-testid": `collections-file-link-${key}-${item[collection.value.schema.primaryKey]}`,
5730
6020
  onClick: ($event) => (0, vue.unref)(activatePathLink)($event, (0, vue.unref)(fileRoutePath)(item[key]) ?? "", true)
5731
- }, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_80)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_81, (0, vue.toDisplayString)((0, vue.unref)(formatCell)(item[key], field.type)), 1))], 64)) : (0, vue.createCommentVNode)("", true)]);
5732
- }), 128))], 42, _hoisted_66);
6021
+ }, (0, vue.toDisplayString)(String(item[key])), 9, _hoisted_86)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_87, (0, vue.toDisplayString)((0, vue.unref)(formatCell)(item[key], field.type)), 1))], 64)) : (0, vue.createCommentVNode)("", true)]);
6022
+ }), 128))], 42, _hoisted_71);
5733
6023
  }), 128))])])]))]),
5734
6024
  collection.value && (viewing.value || editing.value) && !(calendarActive.value && openDay.value) ? ((0, vue.openBlock)(), (0, vue.createBlock)(CollectionRecordModal_default, {
5735
6025
  key: 4,
@@ -5737,7 +6027,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5737
6027
  }, {
5738
6028
  default: (0, vue.withCtx)(() => [(0, vue.createVNode)(CollectionRecordPanel_default, {
5739
6029
  editing: editing.value,
5740
- "onUpdate:editing": _cache[21] || (_cache[21] = ($event) => editing.value = $event),
6030
+ "onUpdate:editing": _cache[22] || (_cache[22] = ($event) => editing.value = $event),
5741
6031
  collection: collection.value,
5742
6032
  viewing: viewing.value,
5743
6033
  saving: saving.value,
@@ -5750,13 +6040,14 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5750
6040
  "live-derived": liveDerived.value,
5751
6041
  "view-title": viewTitle.value,
5752
6042
  "is-singleton": isSingleton.value,
6043
+ readonly: isReadOnly.value,
5753
6044
  render: (0, vue.unref)(render),
5754
6045
  locale: (0, vue.unref)(locale),
5755
6046
  onSubmit: saveEditor,
5756
6047
  onCancel: cancelEditor,
5757
6048
  onEdit: editFromView,
5758
6049
  onClose: closeView,
5759
- onDelete: _cache[22] || (_cache[22] = ($event) => viewing.value && confirmDelete(viewing.value)),
6050
+ onDelete: _cache[23] || (_cache[23] = ($event) => viewing.value && confirmDelete(viewing.value)),
5760
6051
  onRunAction: runAction,
5761
6052
  onItemChat
5762
6053
  }, null, 8, [
@@ -5773,6 +6064,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5773
6064
  "live-derived",
5774
6065
  "view-title",
5775
6066
  "is-singleton",
6067
+ "readonly",
5776
6068
  "render",
5777
6069
  "locale"
5778
6070
  ])]),
@@ -5783,7 +6075,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5783
6075
  action: mutateModal.value.action,
5784
6076
  pending: mutatePending.value,
5785
6077
  error: mutateError.value,
5786
- onClose: _cache[23] || (_cache[23] = ($event) => mutateModal.value = null),
6078
+ onClose: _cache[24] || (_cache[24] = ($event) => mutateModal.value = null),
5787
6079
  onSubmit: submitMutateParams
5788
6080
  }, null, 8, [
5789
6081
  "action",
@@ -5796,7 +6088,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5796
6088
  title: collection.value.title,
5797
6089
  views: customViews.value,
5798
6090
  onChanged: onViewsChanged,
5799
- onClose: _cache[24] || (_cache[24] = ($event) => configOpen.value = false)
6091
+ onClose: _cache[25] || (_cache[25] = ($event) => configOpen.value = false)
5800
6092
  }, null, 8, [
5801
6093
  "slug",
5802
6094
  "title",
@@ -5811,29 +6103,29 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5811
6103
  "data-testid": "collections-chat-modal",
5812
6104
  onClick: (0, vue.withModifiers)(closeChat, ["self"]),
5813
6105
  onKeydown: (0, vue.withKeys)(closeChat, ["esc"])
5814
- }, [(0, vue.createElementVNode)("div", _hoisted_82, [
5815
- (0, vue.createElementVNode)("header", _hoisted_83, [
5816
- _cache[53] || (_cache[53] = (0, vue.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" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "forum")], -1)),
5817
- (0, vue.createElementVNode)("div", _hoisted_84, [(0, vue.createElementVNode)("h2", _hoisted_85, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatTitle")), 1), (0, vue.createElementVNode)("span", _hoisted_86, (0, vue.toDisplayString)(collection.value.title), 1)]),
6106
+ }, [(0, vue.createElementVNode)("div", _hoisted_88, [
6107
+ (0, vue.createElementVNode)("header", _hoisted_89, [
6108
+ _cache[55] || (_cache[55] = (0, vue.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" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "forum")], -1)),
6109
+ (0, vue.createElementVNode)("div", _hoisted_90, [(0, vue.createElementVNode)("h2", _hoisted_91, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatTitle")), 1), (0, vue.createElementVNode)("span", _hoisted_92, (0, vue.toDisplayString)(collection.value.title), 1)]),
5818
6110
  (0, vue.createElementVNode)("button", {
5819
6111
  type: "button",
5820
6112
  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",
5821
6113
  "aria-label": (0, vue.unref)(t)("common.close"),
5822
6114
  "data-testid": "collections-chat-close",
5823
6115
  onClick: closeChat
5824
- }, [..._cache[52] || (_cache[52] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_87)
6116
+ }, [..._cache[54] || (_cache[54] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "close", -1)])], 8, _hoisted_93)
5825
6117
  ]),
5826
- (0, vue.createElementVNode)("div", _hoisted_88, [(0, vue.withDirectives)((0, vue.createElementVNode)("textarea", {
6118
+ (0, vue.createElementVNode)("div", _hoisted_94, [(0, vue.withDirectives)((0, vue.createElementVNode)("textarea", {
5827
6119
  ref_key: "chatInputEl",
5828
6120
  ref: chatInputEl,
5829
- "onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => chatMessage.value = $event),
6121
+ "onUpdate:modelValue": _cache[26] || (_cache[26] = ($event) => chatMessage.value = $event),
5830
6122
  rows: "4",
5831
6123
  placeholder: (0, vue.unref)(t)("collectionsView.chatPlaceholder"),
5832
6124
  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",
5833
6125
  "data-testid": "collections-chat-input",
5834
6126
  onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(submitChat, ["meta"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(submitChat, ["ctrl"]), ["enter"])]
5835
- }, null, 40, _hoisted_89), [[vue.vModelText, chatMessage.value]])]),
5836
- (0, vue.createElementVNode)("footer", _hoisted_90, [(0, vue.createElementVNode)("button", {
6127
+ }, null, 40, _hoisted_95), [[vue.vModelText, chatMessage.value]])]),
6128
+ (0, vue.createElementVNode)("footer", _hoisted_96, [(0, vue.createElementVNode)("button", {
5837
6129
  type: "button",
5838
6130
  class: "h-8 px-2.5 rounded text-xs font-bold text-slate-500 hover:bg-slate-200/50 transition-colors",
5839
6131
  "data-testid": "collections-chat-cancel",
@@ -5844,7 +6136,7 @@ var CollectionView_default = /* @__PURE__ */ (0, vue.defineComponent)({
5844
6136
  disabled: !chatMessage.value.trim(),
5845
6137
  "data-testid": "collections-chat-send",
5846
6138
  onClick: submitChat
5847
- }, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatStart")), 9, _hoisted_91)])
6139
+ }, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.chatStart")), 9, _hoisted_97)])
5848
6140
  ])], 32)) : (0, vue.createCommentVNode)("", true)
5849
6141
  ]);
5850
6142
  };
@@ -5996,10 +6288,10 @@ var _hoisted_18$3 = {
5996
6288
  key: 0,
5997
6289
  class: "text-teal-600"
5998
6290
  };
5999
- var _hoisted_19$1 = { key: 1 };
6000
- var _hoisted_20$1 = { class: "flex items-center justify-between pt-1 border-t border-slate-100" };
6001
- var _hoisted_21$1 = { class: "text-[10px] text-slate-400 font-mono" };
6002
- var _hoisted_22$1 = { class: "flex items-center gap-2" };
6291
+ var _hoisted_19$2 = { key: 1 };
6292
+ var _hoisted_20$2 = { class: "flex items-center justify-between pt-1 border-t border-slate-100" };
6293
+ var _hoisted_21$2 = { class: "text-[10px] text-slate-400 font-mono" };
6294
+ var _hoisted_22$2 = { class: "flex items-center gap-2" };
6003
6295
  var _hoisted_23$1 = ["data-testid"];
6004
6296
  var _hoisted_24 = ["data-testid", "onClick"];
6005
6297
  var _hoisted_25 = [
@@ -6100,9 +6392,9 @@ var DiscoverPanel_default = /* @__PURE__ */ (0, vue.defineComponent)({
6100
6392
  (0, vue.createElementVNode)("div", _hoisted_17$3, [
6101
6393
  (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.discover.fields", { count: entry.fieldCount })), 1),
6102
6394
  entry.views.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_18$3, "· " + (0, vue.toDisplayString)(entry.views.join(" · ")), 1)) : (0, vue.createCommentVNode)("", true),
6103
- entry.hasSeed ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_19$1, "· " + (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.discover.samples", { count: entry.seedCount })), 1)) : (0, vue.createCommentVNode)("", true)
6395
+ entry.hasSeed ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_19$2, "· " + (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.discover.samples", { count: entry.seedCount })), 1)) : (0, vue.createCommentVNode)("", true)
6104
6396
  ]),
6105
- (0, vue.createElementVNode)("div", _hoisted_20$1, [(0, vue.createElementVNode)("span", _hoisted_21$1, "v" + (0, vue.toDisplayString)(entry.version), 1), (0, vue.createElementVNode)("div", _hoisted_22$1, [stateOf(entry).status === "error" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
6397
+ (0, vue.createElementVNode)("div", _hoisted_20$2, [(0, vue.createElementVNode)("span", _hoisted_21$2, "v" + (0, vue.toDisplayString)(entry.version), 1), (0, vue.createElementVNode)("div", _hoisted_22$2, [stateOf(entry).status === "error" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
6106
6398
  key: 0,
6107
6399
  class: "text-[11px] text-red-600",
6108
6400
  "data-testid": `discover-error-${entry.slug}`
@@ -6353,22 +6645,27 @@ var _hoisted_9$1 = {
6353
6645
  class: "rounded-xl border border-slate-200 bg-white px-6 py-12 text-center text-sm text-slate-500 shadow-sm"
6354
6646
  };
6355
6647
  var _hoisted_10$1 = { class: "font-medium text-slate-700" };
6356
- var _hoisted_11$1 = {
6357
- key: 3,
6358
- class: "grid gap-4 sm:grid-cols-2"
6648
+ var _hoisted_11$1 = { key: 3 };
6649
+ var _hoisted_12$1 = {
6650
+ key: 0,
6651
+ class: "flex items-center gap-1.5 mb-4",
6652
+ "data-testid": "collections-filter-chips"
6359
6653
  };
6360
- var _hoisted_12$1 = [
6654
+ var _hoisted_13$1 = ["data-testid", "onClick"];
6655
+ var _hoisted_14$1 = { class: "grid gap-4 sm:grid-cols-2" };
6656
+ var _hoisted_15$1 = [
6361
6657
  "aria-label",
6362
6658
  "data-testid",
6363
6659
  "onClick",
6364
6660
  "onKeydown"
6365
6661
  ];
6366
- var _hoisted_13$1 = { class: "material-symbols-outlined text-2xl" };
6367
- var _hoisted_14$1 = { class: "flex-1 min-w-0" };
6368
- var _hoisted_15$1 = { class: "block font-semibold text-slate-800 text-[15px] group-hover:text-indigo-950 transition-colors truncate" };
6369
- var _hoisted_16$1 = { class: "block text-[10px] text-slate-400 mt-1 tracking-wider font-semibold uppercase flex items-center gap-1.5" };
6370
- var _hoisted_17$1 = { class: "text-[10px] bg-slate-100 px-1 rounded lowercase text-slate-500 font-mono font-normal" };
6371
- var _hoisted_18$1 = [
6662
+ var _hoisted_16$1 = { class: "material-symbols-outlined text-2xl" };
6663
+ var _hoisted_17$1 = { class: "flex-1 min-w-0" };
6664
+ var _hoisted_18$1 = { class: "block font-semibold text-slate-800 text-[15px] group-hover:text-indigo-950 transition-colors truncate" };
6665
+ var _hoisted_19$1 = { class: "block text-[10px] text-slate-400 mt-1 tracking-wider font-semibold uppercase flex items-center gap-1.5" };
6666
+ var _hoisted_20$1 = { class: "text-[10px] bg-slate-100 px-1 rounded lowercase text-slate-500 font-mono font-normal" };
6667
+ var _hoisted_21$1 = ["data-testid"];
6668
+ var _hoisted_22$1 = [
6372
6669
  "title",
6373
6670
  "aria-label",
6374
6671
  "data-testid",
@@ -6387,6 +6684,18 @@ var CollectionsIndexView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6387
6684
  const collections = (0, vue.ref)([]);
6388
6685
  const loading = (0, vue.ref)(true);
6389
6686
  const loadError = (0, vue.ref)(null);
6687
+ const FILTER_CHIPS = [
6688
+ "all",
6689
+ "editable",
6690
+ "data"
6691
+ ];
6692
+ const filter = (0, vue.ref)("all");
6693
+ const hasReadonlyCollections = (0, vue.computed)(() => collections.value.some((collection) => collection.readonly === true));
6694
+ const filteredCollections = (0, vue.computed)(() => {
6695
+ if (filter.value === "editable") return collections.value.filter((collection) => collection.readonly !== true);
6696
+ if (filter.value === "data") return collections.value.filter((collection) => collection.readonly === true);
6697
+ return collections.value;
6698
+ });
6390
6699
  async function loadCollections() {
6391
6700
  loading.value = true;
6392
6701
  loadError.value = null;
@@ -6449,7 +6758,15 @@ var CollectionsIndexView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6449
6758
  tab.value === "discover" ? ((0, vue.openBlock)(), (0, vue.createBlock)(DiscoverPanel_default, {
6450
6759
  key: 1,
6451
6760
  onImported: loadCollections
6452
- })) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7$1, [_cache[5] || (_cache[5] = (0, vue.createElementVNode)("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.loading")), 1)])) : loadError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8$1, [_cache[6] || (_cache[6] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.loadFailed")) + ": " + (0, vue.toDisplayString)(loadError.value), 1)])) : collections.value.length === 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_9$1, [_cache[7] || (_cache[7] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300 mb-2" }, "dashboard_customize", -1)), (0, vue.createElementVNode)("p", _hoisted_10$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.indexEmpty")), 1)])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_11$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(collections.value, (collection) => {
6761
+ })) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7$1, [_cache[5] || (_cache[5] = (0, vue.createElementVNode)("div", { class: "h-8 w-8 border-2 border-indigo-600/20 border-t-indigo-600 rounded-full animate-spin" }, null, -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("common.loading")), 1)])) : loadError.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8$1, [_cache[6] || (_cache[6] = (0, vue.createElementVNode)("span", { class: "material-icons text-red-600" }, "error", -1)), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.loadFailed")) + ": " + (0, vue.toDisplayString)(loadError.value), 1)])) : collections.value.length === 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_9$1, [_cache[7] || (_cache[7] = (0, vue.createElementVNode)("span", { class: "material-icons text-4xl text-slate-300 mb-2" }, "dashboard_customize", -1)), (0, vue.createElementVNode)("p", _hoisted_10$1, (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.indexEmpty")), 1)])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_11$1, [hasReadonlyCollections.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_12$1, [((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(FILTER_CHIPS, (chip) => {
6762
+ return (0, vue.createElementVNode)("button", {
6763
+ key: chip,
6764
+ type: "button",
6765
+ class: (0, vue.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"]),
6766
+ "data-testid": `collections-filter-${chip}`,
6767
+ onClick: ($event) => filter.value = chip
6768
+ }, (0, vue.toDisplayString)((0, vue.unref)(t)(`collectionsView.filter.${chip}`)), 11, _hoisted_13$1);
6769
+ }), 64))])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_14$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(filteredCollections.value, (collection) => {
6453
6770
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
6454
6771
  key: collection.slug,
6455
6772
  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",
@@ -6461,11 +6778,16 @@ var CollectionsIndexView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6461
6778
  onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(($event) => openCollection(collection.slug), ["self"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(($event) => openCollection(collection.slug), ["self", "prevent"]), ["space"])]
6462
6779
  }, [
6463
6780
  (0, vue.createElementVNode)("div", { class: (0, vue.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),
6464
- (0, vue.createElementVNode)("div", { class: (0, vue.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"]) }, [(0, vue.createElementVNode)("span", _hoisted_13$1, (0, vue.toDisplayString)(collection.icon), 1)], 2),
6465
- (0, vue.createElementVNode)("div", _hoisted_14$1, [(0, vue.createElementVNode)("span", _hoisted_15$1, (0, vue.toDisplayString)(collection.title), 1), (0, vue.createElementVNode)("span", _hoisted_16$1, [
6781
+ (0, vue.createElementVNode)("div", { class: (0, vue.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"]) }, [(0, vue.createElementVNode)("span", _hoisted_16$1, (0, vue.toDisplayString)(collection.icon), 1)], 2),
6782
+ (0, vue.createElementVNode)("div", _hoisted_17$1, [(0, vue.createElementVNode)("span", _hoisted_18$1, (0, vue.toDisplayString)(collection.title), 1), (0, vue.createElementVNode)("span", _hoisted_19$1, [
6466
6783
  (0, vue.createElementVNode)("span", { class: (0, vue.normalizeClass)(["h-1.5 w-1.5 rounded-full", collection.source === "project" ? "bg-indigo-500" : "bg-violet-500"]) }, null, 2),
6467
6784
  (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)(`collectionsView.source.${collection.source}`)) + " · ", 1),
6468
- (0, vue.createElementVNode)("code", _hoisted_17$1, (0, vue.toDisplayString)(collection.slug), 1)
6785
+ (0, vue.createElementVNode)("code", _hoisted_20$1, (0, vue.toDisplayString)(collection.slug), 1),
6786
+ collection.readonly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
6787
+ key: 0,
6788
+ 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",
6789
+ "data-testid": `collections-readonly-badge-${collection.slug}`
6790
+ }, [_cache[8] || (_cache[8] = (0, vue.createElementVNode)("span", { class: "material-icons text-[11px]" }, "lock", -1)), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)((0, vue.unref)(t)("collectionsView.readonlyChip")), 1)], 8, _hoisted_21$1)) : (0, vue.createCommentVNode)("", true)
6469
6791
  ])]),
6470
6792
  ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(pinToggle)), {
6471
6793
  kind: "collection",
@@ -6477,17 +6799,18 @@ var CollectionsIndexView_default = /* @__PURE__ */ (0, vue.defineComponent)({
6477
6799
  "title",
6478
6800
  "icon"
6479
6801
  ])),
6480
- (0, vue.createElementVNode)("button", {
6802
+ !collection.readonly ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
6803
+ key: 0,
6481
6804
  type: "button",
6482
6805
  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",
6483
6806
  title: (0, vue.unref)(t)("collectionsView.contribute"),
6484
6807
  "aria-label": (0, vue.unref)(t)("collectionsView.contribute"),
6485
6808
  "data-testid": `collections-contribute-${collection.slug}`,
6486
6809
  onClick: (0, vue.withModifiers)(($event) => startContributeChat(collection), ["stop"])
6487
- }, [..._cache[8] || (_cache[8] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "ios_share", -1)])], 8, _hoisted_18$1),
6488
- _cache[9] || (_cache[9] = (0, vue.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" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg transition-transform duration-300 group-hover:translate-x-0.5" }, "chevron_right")], -1))
6489
- ], 40, _hoisted_12$1);
6490
- }), 128))]))], 64))
6810
+ }, [..._cache[9] || (_cache[9] = [(0, vue.createElementVNode)("span", { class: "material-icons text-lg" }, "ios_share", -1)])], 8, _hoisted_22$1)) : (0, vue.createCommentVNode)("", true),
6811
+ _cache[10] || (_cache[10] = (0, vue.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" }, [(0, vue.createElementVNode)("span", { class: "material-icons text-lg transition-transform duration-300 group-hover:translate-x-0.5" }, "chevron_right")], -1))
6812
+ ], 40, _hoisted_15$1);
6813
+ }), 128))])]))], 64))
6491
6814
  ])]);
6492
6815
  };
6493
6816
  }
@@ -6717,9 +7040,11 @@ exports.collectionUi = collectionUi;
6717
7040
  exports.configureCollectionUi = configureCollectionUi;
6718
7041
  exports.customViewKey = customViewKey;
6719
7042
  exports.plugin = plugin;
7043
+ exports.readCollectionFlagFilters = readCollectionFlagFilters;
6720
7044
  exports.readCollectionSort = readCollectionSort;
6721
7045
  exports.readCollectionViewMode = readCollectionViewMode;
6722
7046
  exports.useCollectionRendering = useCollectionRendering;
7047
+ exports.writeCollectionFlagFilters = writeCollectionFlagFilters;
6723
7048
  exports.writeCollectionSort = writeCollectionSort;
6724
7049
  exports.writeCollectionViewMode = writeCollectionViewMode;
6725
7050