@opengis/cms 0.0.22 → 0.0.26

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.
Files changed (274) hide show
  1. package/dist/index-W-qQIppj-DRzFSjU1.js +2452 -0
  2. package/dist/index.html +28 -34
  3. package/dist/index.js +13915 -0
  4. package/dist/index.umd.cjs +153 -0
  5. package/package.json +4 -11
  6. package/dist/assets/AddUser-CX-McfRW.js +0 -1
  7. package/dist/assets/ApiKeys-DSv1exYv.js +0 -16
  8. package/dist/assets/Appearance-DDtOUvCV.js +0 -6
  9. package/dist/assets/ArticlesPage-D6B3cZsl.js +0 -6
  10. package/dist/assets/BuilderPage-CCeSMVWe.js +0 -1
  11. package/dist/assets/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-DVYVfYF4.js +0 -1
  12. package/dist/assets/CollectionsPage-CHk8Cn5k.js +0 -1
  13. package/dist/assets/Dashboard-Bs7sXO6h.js +0 -11
  14. package/dist/assets/EditCollectionPage-gPuLJrN8.js +0 -41
  15. package/dist/assets/EmailPage-DhlWsPxk.js +0 -1
  16. package/dist/assets/EmptyData-Ct-xQv_N.js +0 -1
  17. package/dist/assets/FeedbackPage-DtaOncVv.js +0 -1
  18. package/dist/assets/Logs-CZ5klHNK.js +0 -1
  19. package/dist/assets/MediaBreadcrumb-BpOxt5PK.js +0 -11
  20. package/dist/assets/MediaPage-DqRcZFlO.js +0 -16
  21. package/dist/assets/MenuAddPage-BLcoVgrS.js +0 -1
  22. package/dist/assets/MenuItemPage-B2otXqkz.js +0 -20
  23. package/dist/assets/MenuPage-C00m4Fc_.js +0 -1
  24. package/dist/assets/MonacoEditor.vue_vue_type_script_setup_true_lang-CjoEsC67.js +0 -3
  25. package/dist/assets/PermissionsPage-LtqcCJ14.js +0 -1
  26. package/dist/assets/Settings-BHH6RoBP.js +0 -1
  27. package/dist/assets/SettingsTable-CY5pZx1z.js +0 -1
  28. package/dist/assets/SettingsTitle-t4WJBFxZ.js +0 -1
  29. package/dist/assets/SingletonsPage-Bn2Ypjhs.js +0 -6
  30. package/dist/assets/TagsPage-DAiakEth.js +0 -1
  31. package/dist/assets/UniversalTable.vue_vue_type_script_setup_true_lang-BQ5m4aZd.js +0 -11
  32. package/dist/assets/UniversalTablePagination.vue_vue_type_script_setup_true_lang-DppVBws0.js +0 -1
  33. package/dist/assets/Users-CMH5j0db.js +0 -1
  34. package/dist/assets/UsersPage-CDGreEib.js +0 -1
  35. package/dist/assets/arrow-up-DCe0WsrM.js +0 -16
  36. package/dist/assets/calendar-o9t4MkD2.js +0 -6
  37. package/dist/assets/chevron-left-WFftVS9c.js +0 -6
  38. package/dist/assets/chevron-right-BiiSb3Be.js +0 -6
  39. package/dist/assets/contentForm-unZQhjCu.js +0 -6
  40. package/dist/assets/en-BDx3Svx8.js +0 -1
  41. package/dist/assets/eye-Dijywc6g.js +0 -6
  42. package/dist/assets/file-B_duymIT.js +0 -6
  43. package/dist/assets/general-CkN_0qIV.js +0 -1
  44. package/dist/assets/index-BIp7eSXk.js +0 -1
  45. package/dist/assets/index-DCW2e4Az.js +0 -9
  46. package/dist/assets/index-DGweaj24.js +0 -1
  47. package/dist/assets/index-W-qQIppj-BDlsxaGB.js +0 -1
  48. package/dist/assets/index-W-qQIppj-BsopI3Hz-BIZR-dhy.js +0 -1
  49. package/dist/assets/index-oQz9FOqL.css +0 -1
  50. package/dist/assets/index-yMJAVBXk.js +0 -290
  51. package/dist/assets/list-CXRbSNky.js +0 -6
  52. package/dist/assets/logo-Cct5WB26.png +0 -0
  53. package/dist/assets/pencil-CwnPP4IJ.js +0 -6
  54. package/dist/assets/plus-DLR44m6p.js +0 -6
  55. package/dist/assets/save-FeDrOUOd.js +0 -6
  56. package/dist/assets/search-C4-fHihx.js +0 -6
  57. package/dist/assets/square-pen-xVs4e8Yb.js +0 -6
  58. package/dist/assets/trash-2-BGXMNU3d.js +0 -6
  59. package/dist/assets/uk-BA7DIKEL.js +0 -1
  60. package/dist/assets/useDebounce-DFq3rxAW.js +0 -1
  61. package/dist/assets/vs-form-reletion-link-C-xrdHDl.js +0 -20
  62. package/dist/assets/vs-form-reletion-link-bk-9ZkDH.css +0 -1
  63. package/dist/assets/vue.-sixQ7xP-CUPNuJcq.js +0 -1
  64. package/dist/assets/vuedraggable.umd-W_2WTF6i.js +0 -14
  65. package/dist/assets/x-D2t-wfBe.js +0 -6
  66. package/module/cms/card/cms.content.table/index.yml +0 -17
  67. package/module/cms/card/cms.content.table/main_info.hbs +0 -26
  68. package/module/cms/card/cms.menu.table/content_info.hbs +0 -16
  69. package/module/cms/card/cms.menu.table/index.yml +0 -18
  70. package/module/cms/card/cms.menu.table/main_info.hbs +0 -22
  71. package/module/cms/card/cms.settings.table/index.yml +0 -13
  72. package/module/cms/card/cms.settings.table/main_info.hbs +0 -20
  73. package/module/cms/cls/content.status.json +0 -18
  74. package/module/cms/cls/user_type.json +0 -10
  75. package/module/cms/form/admin.users.form.json +0 -78
  76. package/module/cms/form/cms.content.form.json +0 -79
  77. package/module/cms/form/cms.menu.form.json +0 -69
  78. package/module/cms/form/cms.settings.form.json +0 -32
  79. package/module/cms/menu.json +0 -24
  80. package/module/cms/router.js +0 -169
  81. package/module/cms/select/cms.page_type.sql +0 -2
  82. package/module/cms/select/collection.sql +0 -1
  83. package/module/cms/select/locale.sql +0 -17
  84. package/module/cms/select/news_tag_id.sql +0 -12
  85. package/module/cms/select/tag_id.sql +0 -1
  86. package/module/cms/table/admin.users.table.json +0 -54
  87. package/module/cms/table/cms.content.table.json +0 -106
  88. package/module/cms/table/cms.menu.table.json +0 -73
  89. package/module/cms/table/cms.settings.table.json +0 -57
  90. package/module/cms/table/collection.default.table.json +0 -102
  91. package/module/cms/table/single.default.table.json +0 -115
  92. package/src/App.css +0 -52
  93. package/src/App.vue +0 -62
  94. package/src/assets/image.png +0 -0
  95. package/src/assets/main.css +0 -3
  96. package/src/assets/tailwind-3.4.17.js +0 -113
  97. package/src/components/LanguageSwitcher.vue +0 -73
  98. package/src/components/SettingsCard.vue +0 -40
  99. package/src/components/builder/CreateForm.vue +0 -128
  100. package/src/components/builder/formTypeSchema.js +0 -145
  101. package/src/components/builder/tabs/index.ts +0 -9
  102. package/src/components/builder/tabs/vs-builder-edit.vue +0 -133
  103. package/src/components/builder/tabs/vs-builder-monaco.vue +0 -29
  104. package/src/components/builder/tabs/vs-builder-preview.vue +0 -39
  105. package/src/components/builder/vs-builder-datatable-controls.vue +0 -138
  106. package/src/components/builder/vs-builder-datatable-form.vue +0 -80
  107. package/src/components/builder/vs-builder-datatable.vue +0 -191
  108. package/src/components/builder/vs-builder-list-item.vue +0 -110
  109. package/src/components/collections/CollectionsBreadcrumb.vue +0 -52
  110. package/src/components/collections/CollectionsGrid.vue +0 -176
  111. package/src/components/collections/ContentBlock.vue +0 -75
  112. package/src/components/collections/formWrapper.vue +0 -156
  113. package/src/components/dashboard/ContentItem.vue +0 -82
  114. package/src/components/dashboard/DashboardHeader.vue +0 -33
  115. package/src/components/dashboard/QuickActions.vue +0 -84
  116. package/src/components/dashboard/RecentContent.vue +0 -54
  117. package/src/components/dashboard/StatCard.vue +0 -63
  118. package/src/components/dashboard/StatsGrid.vue +0 -28
  119. package/src/components/form-components/MonacoEditor.vue +0 -104
  120. package/src/components/form-components/VsFormMeta.vue +0 -40
  121. package/src/components/form-components/VsFormTags.vue +0 -150
  122. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-add.vue +0 -84
  123. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-controls.vue +0 -106
  124. package/src/components/form-components/index.js +0 -23
  125. package/src/components/form-components/reference/vs-form-reference-add.vue +0 -92
  126. package/src/components/form-components/reference/vs-form-reference-controls.vue +0 -101
  127. package/src/components/form-components/reference-list/referenceOptionList.js +0 -78
  128. package/src/components/form-components/reference-list/vs-form-reference-add.vue +0 -145
  129. package/src/components/form-components/reference-list/vs-form-reference-choce.vue +0 -39
  130. package/src/components/form-components/reference-list/vs-form-reference-controls.vue +0 -110
  131. package/src/components/form-components/reference-skeleton/about-skeleton.vue +0 -37
  132. package/src/components/form-components/reference-skeleton/banner-skeleton.vue +0 -29
  133. package/src/components/form-components/reference-skeleton/body-skeleton.vue +0 -56
  134. package/src/components/form-components/reference-skeleton/cards-skeleton.vue +0 -47
  135. package/src/components/form-components/reference-skeleton/documents-skeleton.vue +0 -64
  136. package/src/components/form-components/reference-skeleton/faq-skeleton.vue +0 -64
  137. package/src/components/form-components/reference-skeleton/form-skeleton.vue +0 -41
  138. package/src/components/form-components/reference-skeleton/index.js +0 -36
  139. package/src/components/form-components/reference-skeleton/infoLine-skeleton.vue +0 -37
  140. package/src/components/form-components/reference-skeleton/news-skeleton.vue +0 -54
  141. package/src/components/form-components/reference-skeleton/slider-skeleton.vue +0 -41
  142. package/src/components/form-components/reference-skeleton/tabs-skeleton.vue +0 -40
  143. package/src/components/form-components/reference-skeleton/team-skeleton.vue +0 -103
  144. package/src/components/form-components/reference-skeleton/usefulLinks-skeleton.vue +0 -52
  145. package/src/components/form-components/reference-skeleton/video-skeleton.vue +0 -36
  146. package/src/components/form-components/testReferenceTypes.js +0 -773
  147. package/src/components/form-components/vs-form-color-picker.vue +0 -29
  148. package/src/components/form-components/vs-form-custom-datatable.vue +0 -214
  149. package/src/components/form-components/vs-form-integer.vue +0 -86
  150. package/src/components/form-components/vs-form-key-value.vue +0 -201
  151. package/src/components/form-components/vs-form-marcdown-md.vue +0 -3
  152. package/src/components/form-components/vs-form-media-select.vue +0 -780
  153. package/src/components/form-components/vs-form-reference-list.vue +0 -97
  154. package/src/components/form-components/vs-form-reference.vue +0 -59
  155. package/src/components/form-components/vs-form-relation.vue +0 -30
  156. package/src/components/form-components/vs-form-reletion-link.vue +0 -34
  157. package/src/components/form-components/vs-form-select-collection.vue +0 -0
  158. package/src/components/form-components/vs-form-slug.vue +0 -72
  159. package/src/components/form-components/vs-form-tiptap.vue +0 -7
  160. package/src/components/form-components/vs-richtext-md.vue +0 -3
  161. package/src/components/icons/BellIcon.vue +0 -17
  162. package/src/components/icons/GlobeIcon.vue +0 -18
  163. package/src/components/icons/KeyIcon.vue +0 -20
  164. package/src/components/icons/PaletteIcon.vue +0 -22
  165. package/src/components/icons/SettingsIcon.vue +0 -19
  166. package/src/components/icons/ShieldIcon.vue +0 -18
  167. package/src/components/icons/UsersIcon.vue +0 -19
  168. package/src/components/icons/icon-chevron-right.vue +0 -16
  169. package/src/components/icons/icon-drag.vue +0 -20
  170. package/src/components/icons/icon-file-text.vue +0 -21
  171. package/src/components/icons/icon-folder.vue +0 -18
  172. package/src/components/icons/icon-grid.vue +0 -17
  173. package/src/components/icons/icon-group.vue +0 -19
  174. package/src/components/icons/icon-home.vue +0 -16
  175. package/src/components/icons/icon-image.vue +0 -18
  176. package/src/components/icons/icon-list.vue +0 -20
  177. package/src/components/icons/icon-more.vue +0 -17
  178. package/src/components/icons/icon-plus.vue +0 -17
  179. package/src/components/icons-types/icon-array.vue +0 -22
  180. package/src/components/icons-types/icon-boolean.vue +0 -18
  181. package/src/components/icons-types/icon-datalist.vue +0 -22
  182. package/src/components/icons-types/icon-date.vue +0 -20
  183. package/src/components/icons-types/icon-datetime.vue +0 -20
  184. package/src/components/icons-types/icon-file.vue +0 -21
  185. package/src/components/icons-types/icon-gallery.vue +0 -18
  186. package/src/components/icons-types/icon-image.vue +0 -19
  187. package/src/components/icons-types/icon-integer.vue +0 -20
  188. package/src/components/icons-types/icon-merkdown.vue +0 -18
  189. package/src/components/icons-types/icon-multiselect.vue +0 -22
  190. package/src/components/icons-types/icon-number.vue +0 -20
  191. package/src/components/icons-types/icon-radio.vue +0 -22
  192. package/src/components/icons-types/icon-reference-list.vue +0 -22
  193. package/src/components/icons-types/icon-reference.vue +0 -20
  194. package/src/components/icons-types/icon-relation.vue +0 -22
  195. package/src/components/icons-types/icon-richtext.vue +0 -18
  196. package/src/components/icons-types/icon-select.vue +0 -22
  197. package/src/components/icons-types/icon-slug.vue +0 -19
  198. package/src/components/icons-types/icon-text.vue +0 -19
  199. package/src/components/icons-types/index.js +0 -43
  200. package/src/components/layout/Layout.vue +0 -67
  201. package/src/components/layout/Sidebar.vue +0 -128
  202. package/src/components/media/FileUploadProgress.vue +0 -29
  203. package/src/components/media/MediaBreadcrumb.vue +0 -42
  204. package/src/components/media/MediaCreateFolder.vue +0 -59
  205. package/src/components/media/MediaFileInfo.vue +0 -148
  206. package/src/components/media/MediaGrid.vue +0 -148
  207. package/src/components/media/MediaList.vue +0 -148
  208. package/src/components/media/MediaViewControls.vue +0 -38
  209. package/src/components/media/TypeTag.vue +0 -23
  210. package/src/components/menu/AddNewItemInTree.vue +0 -75
  211. package/src/components/menu/MenuBody.vue +0 -149
  212. package/src/components/menu/MenuItem.vue +0 -73
  213. package/src/components/menu/MenuList.vue +0 -101
  214. package/src/components/referencec/index.ts +0 -7
  215. package/src/components/referencec/vs-reference-faq.vue +0 -61
  216. package/src/components/referencec/vs-reference-user-card.vue +0 -40
  217. package/src/components/settings/NotificationSettings.vue +0 -32
  218. package/src/components/settings/SettingsTable.vue +0 -50
  219. package/src/components/settings/SettingsTitle.vue +0 -33
  220. package/src/components/settings/SettingsToggleItem.vue +0 -25
  221. package/src/components/sidebar/DropdownMenu.vue +0 -34
  222. package/src/components/sidebar/SettingsSidebar.vue +0 -121
  223. package/src/components/sidebar/SidebarFooter.vue +0 -52
  224. package/src/components/sidebar/SidebarHeader.vue +0 -57
  225. package/src/components/sidebar/SidebarMenu.vue +0 -78
  226. package/src/components/ui/EmptyData.vue +0 -76
  227. package/src/components/ui/UniversalTable.vue +0 -310
  228. package/src/components/ui/UniversalTableFilters.vue +0 -0
  229. package/src/components/ui/UniversalTablePagination.vue +0 -118
  230. package/src/components/ui/VsPreview.vue +0 -75
  231. package/src/composables/useCollectionView.ts +0 -21
  232. package/src/composables/useDebounce.ts +0 -26
  233. package/src/composables/useMonaco.ts +0 -28
  234. package/src/composables/useTheme.ts +0 -40
  235. package/src/content/test-slug/metadata.json +0 -1
  236. package/src/i18n.ts +0 -75
  237. package/src/index.css +0 -3
  238. package/src/index.ts +0 -122
  239. package/src/locales/en.json +0 -778
  240. package/src/locales/uk.json +0 -797
  241. package/src/main.ts +0 -41
  242. package/src/pages/Dashboard.vue +0 -168
  243. package/src/pages/EmailPage.vue +0 -183
  244. package/src/pages/FeedbackPage.vue +0 -232
  245. package/src/pages/MediaPage.vue +0 -372
  246. package/src/pages/TagsPage.vue +0 -207
  247. package/src/pages/builder/BuilderPage.vue +0 -195
  248. package/src/pages/builder/EditCollectionPage.vue +0 -163
  249. package/src/pages/collections/ArticlesPage.vue +0 -385
  250. package/src/pages/collections/CollectionsPage.vue +0 -146
  251. package/src/pages/collections/SingletonsPage.vue +0 -119
  252. package/src/pages/collections/contentForm.vue +0 -484
  253. package/src/pages/collections/schema/seo.ts +0 -27
  254. package/src/pages/menu/MenuAddPage.vue +0 -123
  255. package/src/pages/menu/MenuItemPage.vue +0 -183
  256. package/src/pages/menu/MenuPage.vue +0 -133
  257. package/src/pages/settings/ApiKeys.vue +0 -75
  258. package/src/pages/settings/Appearance.vue +0 -80
  259. package/src/pages/settings/Logs.vue +0 -260
  260. package/src/pages/settings/PermissionsPage.vue +0 -237
  261. package/src/pages/settings/Settings.vue +0 -186
  262. package/src/pages/settings/Users.vue +0 -109
  263. package/src/pages/settings/general.vue +0 -154
  264. package/src/pages/settings/generalScheme.js +0 -132
  265. package/src/pages/users/AddUser.vue +0 -106
  266. package/src/pages/users/UsersPage.vue +0 -98
  267. package/src/props/builder.ts +0 -67
  268. package/src/props/content.ts +0 -56
  269. package/src/props/media.ts +0 -63
  270. package/src/router/index.ts +0 -181
  271. package/src/types/fastify-auth.d.ts +0 -4
  272. package/src/utils/getField.js +0 -270
  273. package/src/utils/translit.js +0 -19
  274. package/src/vite-env.d.ts +0 -1
@@ -1,385 +0,0 @@
1
- <script setup lang="ts">
2
- import { ref, onMounted, watch, inject, computed, nextTick } from "vue";
3
- import { useRouter, useRoute } from "vue-router";
4
- import { Plus, FileText, Calendar, Globe, User, ChevronDown, HelpCircle } from "lucide-vue-next";
5
- import UniversalTable from "../../components/ui/UniversalTable.vue";
6
- import UniversalTablePagination from "../../components/ui/UniversalTablePagination.vue";
7
- import { VsInputCheckbox } from "@opengis/form";
8
- import { useHead } from "@vueuse/head";
9
- import VsFilter from '@opengis/filter';
10
- import { confirm } from '@opengis/core';
11
-
12
- import { useI18n } from "vue-i18n";
13
- import EmptyData from "../../components/ui/EmptyData.vue";
14
- import CollectionsBreadcrumb from "../../components/collections/CollectionsBreadcrumb.vue";
15
- interface Article {
16
- id: string;
17
- title: string;
18
- content?: string;
19
- author: string;
20
- category: string;
21
- status: "published" | "draft" | "archived";
22
- }
23
-
24
- const route = useRoute();
25
- const router = useRouter();
26
-
27
- const tableData = ref<any>(null);
28
- const searchQuery = ref("");
29
- const { t, locale } = useI18n();
30
- const articles = ref<any[]>([]);
31
- const menu = inject("menu") || <any>[];
32
- const filter = ref<string>('');
33
- const page = ref(1);
34
- const showColumns = ref(false);
35
- const baseColumns = ref(["title","slug","author","publish_at","published_at","status"])
36
- const columns = ref([]);
37
- const options = ref<any[]>([]);
38
- const scheme = ref([]);
39
- const initialFilters = ref<Record<string, any>>({});
40
- const filterKey = ref(0); // Key для примусового перерендеру VsFilter
41
- const isLoading = ref(false); // Флаг для запобігання подвійних викликів
42
-
43
- interface FilterData {
44
- data: Record<string, any>
45
- }
46
-
47
- const rewritingFilters = () => {
48
- scheme.value = tableData.value?.filters.map((filter: any) => {
49
- return {
50
- ...filter,
51
- label: filter.name,
52
- id: filter.name,
53
- inline: true,
54
- }
55
- });
56
- }
57
-
58
- const updateColumns = () => {
59
- let selectedColumns = tableData.value?.columns.filter((col: any) => baseColumns?.value?.includes(col.name));
60
-
61
- columns.value = selectedColumns.map((col: any) => {
62
- switch (col.name) {
63
- case "title":
64
- return {
65
- ...col,
66
- title: col.name ? col.name.charAt(0).toUpperCase() + col.name.slice(1) : '--',
67
- icon: FileText,
68
- };
69
- case "slug":
70
- return {
71
- ...col,
72
- title: col.name ? col.name.charAt(0).toUpperCase() + col.name.slice(1) : '-',
73
- icon: Globe,
74
- };
75
- case "author":
76
- return {
77
- ...col,
78
- title: col.name ? col.name.charAt(0).toUpperCase() + col.name.slice(1) : '-',
79
- icon: User,
80
- };
81
- case "publish_at":
82
- return {
83
- ...col,
84
- title: col.name ? col.name.charAt(0).toUpperCase() + col.name.slice(1) : '-',
85
- icon: Calendar,
86
- };
87
- case "published_at":
88
- return {
89
- ...col,
90
- title: col.name ? col.name.charAt(0).toUpperCase() + col.name.slice(1) : '-',
91
- icon: Calendar,
92
- };
93
- default:
94
- return {
95
- ...col,
96
- title: col.name ? col.name.charAt(0).toUpperCase() + col.name.slice(1) : '-',
97
- };
98
- }
99
- });
100
-
101
- showColumns.value = false;
102
- };
103
-
104
- const titleOfCollection = computed(
105
- () => {
106
- return menu.value.find((item: any) => item.id === route.params.id)?.title
107
- }
108
- );
109
-
110
- const breadcrumbItems = computed(() => {
111
- const collectionTitle = titleOfCollection.value || route.params.id;
112
- return [
113
- {
114
- label: collectionTitle,
115
- route: `collections/${route.params.id}`,
116
- },
117
- ];
118
- });
119
-
120
- const handleBreadcrumbNavigate = (routePath: string) => {
121
- if (routePath === 'collections') {
122
- router.push('/collections');
123
- } else {
124
- router.push(`/${routePath}`);
125
- }
126
- };
127
-
128
- const handleCreateArticle = () => {
129
- router.push(`/collections/${route.params.id}/create`);
130
- };
131
-
132
- const handleRemoveArticle = async (article: Article) => {
133
- console.log('handleRemoveArticle');
134
- confirm({
135
- title: t("builder.deleteTitle"),
136
- message: t("builder.deleteObject"),
137
- type:'error',
138
- onConfirm: async () => {
139
- await fetch(`/api/cms/${route.params.id}/${article.id}`, { method: 'DELETE' });
140
- fetchArticles();
141
- }
142
- });
143
- };
144
-
145
- const handleEditArticle = (article: Article) => {
146
- router.push(`/collections/${route.params.id}/${article.id}`);
147
- };
148
-
149
- const fetchArticles = async () => {
150
- if (isLoading.value) return; // Запобігаємо подвійним викликам
151
-
152
- isLoading.value = true;
153
- try {
154
- const res = await fetch(
155
- `/api/cms/${route.params.id}?page=${page.value}&filter=${filter.value}`
156
- );
157
- const data = await res.json();
158
-
159
- articles.value = data.rows || [];
160
- tableData.value = data;
161
-
162
- // Clean filter schema to only include valid IFilterItem properties
163
- const cleanFilters = (data.filters || []).map((filter: any) => {
164
- const { extra, title, ...cleanFilter } = filter;
165
- return cleanFilter;
166
- });
167
- scheme.value = cleanFilters;
168
-
169
- if(route.params.id === 'pages') {
170
- baseColumns.value.push('type');
171
- }
172
-
173
- setOptions();
174
- updateColumns();
175
- // rewritingFilters();
176
- } finally {
177
- isLoading.value = false;
178
- }
179
- };
180
-
181
- const setOptions = () => {
182
- if (!tableData.value?.columns) return;
183
-
184
- const rawOptions = tableData.value.columns.map((col, index) => ({
185
- text: col.label,
186
- id: col.name,
187
- }));
188
-
189
-
190
- options.value = [
191
- ...baseColumns.value
192
- .map(col => rawOptions.find(opt => opt.id === col))
193
- .filter(Boolean),
194
- ...rawOptions.filter(opt => !baseColumns.value.includes(opt.id))
195
- ];
196
- }
197
-
198
- const filterFn = (row: any, query: string) => {
199
- if (!query) return true;
200
- const q = query.toLowerCase();
201
- return columns.value.some((col: any) => {
202
- const val = row[col.name];
203
- return val && val.toString().toLowerCase().includes(q);
204
- });
205
- };
206
-
207
- const filterChange = (filters: FilterData) => {
208
- const filterStr = Object.entries(filters?.data)
209
- .filter(([, v]) => v != null)
210
- .map(([key, val]) => `${key}=${val}`)
211
- .join('|');
212
-
213
- filter.value = filterStr;
214
-
215
- // Оновлюємо URL з параметрами фільтрів
216
- const query = { ...route.query };
217
- if (filterStr) {
218
- query.filter = filterStr;
219
- } else {
220
- delete query.filter;
221
- }
222
-
223
- router.replace({ query });
224
- // fetchArticles() буде викликано через watch(() => route.query, ...)
225
- };
226
-
227
- // Функція для ініціалізації фільтрів з URL
228
- const initializeFiltersFromUrl = () => {
229
- if (route.query.filter) {
230
- filter.value = route.query.filter as string;
231
-
232
- // Парсимо фільтри з URL для початкових значень
233
- const filterParams = (route.query.filter as string).split('|');
234
- const parsedFilters: Record<string, any> = {};
235
-
236
- filterParams.forEach(param => {
237
- const [key, value] = param.split('=');
238
- if (key && value) {
239
- parsedFilters[key] = value;
240
- }
241
- });
242
-
243
- initialFilters.value = parsedFilters;
244
- } else {
245
- // Очищаємо фільтри, якщо в URL немає параметрів
246
- filter.value = '';
247
- initialFilters.value = {};
248
- // Примусово перерендеруємо компонент фільтрів
249
- filterKey.value++;
250
- }
251
- };
252
-
253
- onMounted(() => {
254
- initializeFiltersFromUrl();
255
- fetchArticles();
256
- });
257
-
258
- watch(() => route.params.id, () => {
259
- // Reset filters when collection changes
260
- initialFilters.value = {};
261
- filter.value = '';
262
- scheme.value = [];
263
-
264
- // Clear URL filter parameters when switching collections
265
- const query = { ...route.query };
266
- delete query.filter;
267
- router.replace({ query });
268
-
269
- // Примусово перерендеруємо компонент фільтрів
270
- filterKey.value++;
271
-
272
- initializeFiltersFromUrl();
273
- fetchArticles();
274
- });
275
-
276
- // Відстежуємо зміни в query параметрах для обробки навігації назад/вперед
277
- watch(() => route.query, async () => {
278
- initializeFiltersFromUrl();
279
- await nextTick(); // Чекаємо, поки всі зміни застосуються
280
- fetchArticles();
281
- }, { deep: true });
282
-
283
- watch(page, async () => {
284
- // При зміні сторінки перевіряємо, чи є фільтри в URL
285
- if (!route.query.filter) {
286
- filter.value = '';
287
- initialFilters.value = {};
288
- // Примусово перерендеруємо компонент фільтрів
289
- filterKey.value++;
290
- }
291
- await nextTick(); // Чекаємо, поки всі зміни застосуються
292
- fetchArticles();
293
- });
294
-
295
- // useHead({
296
- // title: () => t("articles.title") + " | CMS",
297
- // });
298
- </script>
299
-
300
- <template>
301
- <div class="space-y-6 max-w-7xl mx-auto">
302
- <CollectionsBreadcrumb
303
- :items="breadcrumbItems"
304
- @navigate="handleBreadcrumbNavigate"
305
- />
306
- <div
307
- class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"
308
- >
309
- <div class="flex items-center gap-2">
310
- <h1 class="text-3xl font-bold text-slate-800 dark:text-white mb-2">
311
- {{ titleOfCollection }}
312
- </h1>
313
- <a :href="`https://cms.opengis.info/${locale}/guides/content/`" target="_blank" :title="$t('guide.content')">
314
- <HelpCircle class="w-5 h-5" />
315
- </a>
316
- </div>
317
- <button v-if="articles.length"
318
- @click="handleCreateArticle"
319
- class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium h-9 px-4 py-2 bg-blue-600 text-white shadow-md transition-all duration-200 transform
320
- hover:bg-blue-700 hover:shadow-lg hover:scale-105
321
- focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
322
- disabled:pointer-events-none disabled:opacity-50"
323
- >
324
- <Plus class="w-4 h-4 mr-2" />
325
- {{ $t("articles.createArticle") }}
326
- </button>
327
- </div>
328
-
329
- <div v-if="articles.length || filter.length"
330
- class="text-card-foreground shadow-lg border-0 bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm"
331
- >
332
- <div v-if="true" class="p-2 border-b border-gray-200 sm:px-4 sm:py-2 dark:border-gray-700">
333
- <div class="flex flex-col gap-4 sm:flex-row">
334
- <VsFilter
335
- :key="filterKey"
336
- :schema="scheme"
337
- :history="true"
338
- :value="initialFilters"
339
- view="inline"
340
- @change="filterChange"
341
- />
342
-
343
- <div class="relative flex items-center gap-2 ml-auto">
344
- <div class="flex items-center gap-2 cursor-pointer text-sm border border-gray-300 rounded-md p-2 dark:text-white" @click="showColumns = !showColumns" v-if="options.length > 0">
345
- <p>{{ $t("articles.showColumns") }}</p>
346
- <ChevronDown class="w-4 h-4" />
347
- </div>
348
- <div class="absolute top-full right-1/2 translate-x-1/2 min-w-full p-4 z-10 bg-white border border-gray-300 rounded-md mt-2 dark:bg-slate-800 dark:border-slate-700" v-if="options.length > 0 && showColumns">
349
- <div class="max-h-60 overflow-y-auto overflow-x-hidden">
350
- <VsInputCheckbox
351
- v-if="options.length > 0 && showColumns"
352
- :options="options"
353
- v-model="baseColumns"
354
- />
355
- </div>
356
- <button class="text-sm bg-blue-600 text-white rounded-md p-2 mt-4 w-full" @click="updateColumns">
357
- {{ $t("articles.update") }}
358
- </button>
359
- </div>
360
- </div>
361
- </div>
362
- </div>
363
- <UniversalTable
364
- v-if="columns.length > 0"
365
- class="max-h-[calc(100vh-270px)] overflow-y-auto"
366
- :rows="articles"
367
- :columns="columns"
368
- :query="searchQuery"
369
- :filterFn="filterFn"
370
- @delete="handleRemoveArticle"
371
- @edit="handleEditArticle"
372
- />
373
- <UniversalTablePagination
374
- v-if="tableData?.total > 20"
375
- :total="tableData?.filtered"
376
- :count="tableData?.count"
377
- v-model:page="page"
378
- :limit="20"
379
- />
380
- </div>
381
- <div v-else>
382
- <EmptyData @action="handleCreateArticle"/>
383
- </div>
384
- </div>
385
- </template>
@@ -1,146 +0,0 @@
1
- <template>
2
- <div class="space-y-6 max-w-7xl mx-auto">
3
- <div class="flex items-center justify-between mb-8">
4
- <div class="flex gap-4">
5
- <div>
6
- <h1 class="text-3xl font-bold text-slate-800 dark:text-slate-100 mb-2">
7
- {{ $t("navigation.collections") }}
8
- </h1>
9
- <p class="text-slate-600 dark:text-slate-300">
10
- {{ $t("collections.selectCollection") }}
11
- </p>
12
- </div>
13
- <a
14
- :href="`https://cms.opengis.info/${locale}/guides/collections/`"
15
- target="_blank"
16
- :title="$t('guide.collections')"
17
- class="mt-2"
18
- >
19
- <HelpCircle class="w-5 h-5" />
20
- </a>
21
- </div>
22
-
23
- <div class="relative w-full max-w-sm">
24
- <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
25
- <Search class="w-5 h-5 text-gray-400" />
26
- </div>
27
- <input
28
- v-model="searchQuery"
29
- type="text"
30
- class="block w-full py-2 pl-10 pr-3 leading-5 text-gray-900 placeholder-gray-500 transition-colors bg-white border border-gray-300 rounded-md dark:border-gray-600 dark:bg-gray-700 dark:placeholder-gray-400 focus:outline-none focus:ring-sky-500 focus:border-sky-500 dark:text-white sm:text-sm"
31
- :placeholder="$t('collections.searchCollections')"
32
- />
33
- </div>
34
- </div>
35
-
36
- <div v-if="collections.length > 0">
37
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-6">
38
- <button v-for="collection in filteredCollections" :key="collection.id" @click="handleViewCollection(collection)" class="w-full border border-gray-200 bg-white rounded-lg p-4 text-left hover:shadow-md transition-all hover:border-gray-300">
39
- <div class="flex items-start justify-between">
40
- <div class="flex items-start gap-3">
41
- <File v-if="collection.id === 'pages'" class="shrink-0 lucide lucide-page w-5 h-5 text-blue-600" />
42
- <Layers v-else class="shrink-0 lucide lucide-layers w-5 h-5 text-blue-600" />
43
- <div>
44
- <h4 class="text-sm font-semibold text-gray-800 mb-1">{{ collection.title }}</h4>
45
- <p class="text-xs text-gray-600">{{ collection.description || 'Опис відсутній'}}</p>
46
- </div>
47
- </div>
48
- <div class="flex items-center gap-2">
49
- <span class="text-xs text-gray-500 whitespace-nowrap">{{ collection.entries }} записів</span>
50
- <ChevronRight class="w-4 h-4 text-gray-400" />
51
- </div>
52
- </div>
53
- </button>
54
- </div>
55
-
56
- </div>
57
- <div v-else class="flex items-center justify-center min-h-[400px]">
58
- <EmptyData />
59
- </div>
60
- </div>
61
- </template>
62
-
63
- <script setup lang="ts">
64
- import { ref, computed, onMounted, inject } from "vue";
65
- import { useRouter } from "vue-router";
66
- import { HelpCircle, File, Layers, ChevronRight, Search } from "lucide-vue-next";
67
- import { useI18n } from "vue-i18n";
68
- import CollectionsGrid from "../../components/collections/CollectionsGrid.vue";
69
- import EmptyData from "../../components/ui/EmptyData.vue";
70
- import type { Collection } from "../../props/builder";
71
- import { confirm } from "@opengis/core";
72
-
73
- const { t, locale } = useI18n();
74
- const router = useRouter();
75
- const fetchContentTypes = inject<any>("fetchContentTypes");
76
-
77
- const collections = ref<Collection[]>([]);
78
- const searchQuery = ref("");
79
-
80
- const filteredCollections = computed(() => {
81
- // Фільтруємо тільки колекції (не single)
82
- const onlyCollections = collections.value.filter(
83
- (c) => c.type !== "single"
84
- );
85
-
86
- const q = searchQuery.value.trim().toLowerCase();
87
- const searched = q
88
- ? onlyCollections.filter((c: any) => {
89
- const hay = [c?.title, c?.name, c?.id, c?.description]
90
- .filter(Boolean)
91
- .join(" ")
92
- .toLowerCase();
93
- return hay.includes(q);
94
- })
95
- : onlyCollections;
96
-
97
- // Сортуємо: pages завжди перші
98
- const sorted = [...searched].sort((a, b) => {
99
- if (a.id === "pages") return -1;
100
- if (b.id === "pages") return 1;
101
- return 0;
102
- });
103
- return sorted;
104
- });
105
-
106
- async function fetchCollections() {
107
- try {
108
- const res = await fetch("/api/cms-type?type=collection");
109
- if (!res.ok) throw new Error("Failed to fetch collections");
110
- const data = await res.json();
111
- collections.value = data.rows || [];
112
- } catch (e) {
113
- console.error("Error fetching collections:", e);
114
- }
115
- }
116
-
117
- const handleEditCollection = (collection: Collection) => {
118
- router.push(`/settings/collections/edit/${collection.id || collection.name}`);
119
- };
120
-
121
- const handleViewCollection = (collection: Collection) => {
122
- router.push(`/collections/${collection.id}`);
123
- };
124
-
125
- const handleDeleteCollection = async (collection: Collection) => {
126
- confirm({
127
- title: t("builder.deleteTitle"),
128
- message: t("builder.deleteObject"),
129
- type: "error",
130
- onConfirm: async () => {
131
- try {
132
- await fetch(`/api/cms-type/${collection.id}`, { method: "DELETE" });
133
- fetchCollections();
134
- if (fetchContentTypes) fetchContentTypes();
135
- } catch (error) {
136
- console.error("Error deleting collection:", error);
137
- }
138
- },
139
- });
140
- };
141
-
142
- onMounted(() => {
143
- fetchCollections();
144
- });
145
- </script>
146
-
@@ -1,119 +0,0 @@
1
- <template>
2
- <div class="space-y-6 max-w-7xl mx-auto">
3
- <div
4
- class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"
5
- >
6
- <h1 class="text-2xl font-semibold text-gray-900 dark:text-white">
7
- {{ $t("singletons.title") }}
8
- </h1>
9
- </div>
10
- <div
11
- class="overflow-hidden bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700"
12
- >
13
- <div class="p-4 border-b border-gray-200 sm:p-6 dark:border-gray-700">
14
- <div class="flex flex-col gap-4 sm:flex-row">
15
- <div class="relative flex-1">
16
- <div
17
- class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none"
18
- >
19
- <Search class="w-5 h-5 text-gray-400" />
20
- </div>
21
- <input
22
- type="text"
23
- class="block w-full py-2 pl-10 pr-3 leading-5 text-gray-900 placeholder-gray-500 transition-colors bg-white border border-gray-300 rounded-md dark:border-gray-600 dark:bg-gray-700 dark:placeholder-gray-400 focus:outline-none focus:ring-sky-500 focus:border-sky-500 dark:text-white sm:text-sm"
24
- :placeholder="$t('singletons.search')"
25
- v-model="searchQuery"
26
- />
27
- </div>
28
-
29
- <div class="flex space-x-2">
30
- <button
31
- class="inline-flex items-center px-3 py-2 text-sm font-medium leading-4 text-gray-700 transition-colors bg-white border border-gray-300 rounded-md shadow-sm dark:border-gray-600 dark:text-gray-200 dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-sky-500"
32
- >
33
- <Filter class="w-4 h-4 mr-2 text-gray-500 dark:text-gray-400" />
34
- {{ $t("common.actions.filter") }}
35
- </button>
36
- </div>
37
- </div>
38
- </div>
39
-
40
- <UniversalTable
41
- class="max-h-[calc(100vh-270px)] overflow-y-auto"
42
- :rows="singletons"
43
- :columns="columns"
44
- :query="searchQuery"
45
- :filterFn="filterFn"
46
- @edit="handleEditSingleton"
47
- />
48
- <UniversalTablePagination
49
- v-if="tableData?.total > 16"
50
- :total="tableData?.total"
51
- :count="tableData?.count || tableData?.total"
52
- v-model:page="page"
53
- />
54
- </div>
55
- </div>
56
- </template>
57
-
58
- <script setup lang="ts">
59
- import { ref, onMounted, watch } from "vue";
60
- import { useRouter } from "vue-router";
61
- import { Plus, Search, Filter } from "lucide-vue-next";
62
- import UniversalTable from "../../components/ui/UniversalTable.vue";
63
- import UniversalTablePagination from "../../components/ui/UniversalTablePagination.vue";
64
- import { useI18n } from "vue-i18n";
65
-
66
- const { t } = useI18n();
67
-
68
- interface Singleton {
69
- id: string;
70
- name: string;
71
- description: string;
72
- status: "published" | "draft";
73
- lastModified: string;
74
- }
75
-
76
- const router = useRouter();
77
- const searchQuery = ref("");
78
- const singletons = ref<any[]>([]);
79
- const page = ref(1);
80
- const tableData = ref<any>(null);
81
- const limit = ref(16);
82
-
83
- const columns = [
84
- {
85
- name: "title",
86
- title: t("common.title"),
87
- type: "text",
88
- },
89
- ];
90
-
91
- const handleCreateSingleton = () => {
92
- router.push("/singletons/create");
93
- };
94
-
95
- const handleEditSingleton = (singleton: Singleton) => {
96
- router.push(`/collections/single/${singleton.name || singleton.id}`);
97
- };
98
-
99
- const fetchSingletons = async () => {
100
- const res = await fetch(`/api/cms?page=${page.value}&limit=${limit.value}`);
101
- const data = await res.json();
102
- const rows = data.rows;
103
- singletons.value = rows?.filter((row: any) => row.type === "single");
104
- tableData.value = data;
105
- };
106
-
107
- const filterFn = (row: any, query: string) => {
108
- if (!query) return true;
109
- const q = query.toLowerCase();
110
- return columns.value.some((col: any) => {
111
- const val = row[col.name];
112
- return val && val.toString().toLowerCase().includes(q);
113
- });
114
- };
115
-
116
- watch(page, fetchSingletons);
117
-
118
- onMounted(fetchSingletons);
119
- </script>