@opengis/cms 0.0.2 → 0.0.3

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 (144) hide show
  1. package/.gitlab-ci.yml +36 -0
  2. package/config.example +21 -0
  3. package/docs/.vitepress/abbr.mjs +26 -0
  4. package/docs/.vitepress/config.mjs +119 -0
  5. package/docs/.vitepress/navigation.mjs +82 -0
  6. package/docs/.vitepress/theme/Layout.vue +17 -0
  7. package/docs/.vitepress/theme/components/NavigationLinks.vue +102 -0
  8. package/docs/.vitepress/theme/components/Panzoom.vue +169 -0
  9. package/docs/.vitepress/theme/index.mjs +15 -0
  10. package/docs/.vitepress/theme/style.scss +136 -0
  11. package/docs/abbr.json +4 -0
  12. package/docs/api/builder/cms.builder.delete.md +65 -0
  13. package/docs/api/builder/cms.builder.get.md +70 -0
  14. package/docs/api/builder/cms.builder.list.md +98 -0
  15. package/docs/api/builder/cms.builder.post.md +72 -0
  16. package/docs/api/builder/cms.builder.put.md +88 -0
  17. package/docs/api/category/cms.category.delete.md +60 -0
  18. package/docs/api/category/cms.category.get.md +61 -0
  19. package/docs/api/category/cms.category.list.md +77 -0
  20. package/docs/api/category/cms.category.post.md +62 -0
  21. package/docs/api/category/cms.category.put.md +78 -0
  22. package/docs/api/index.md +50 -0
  23. package/docs/api/manager/cms.manager.delete.md +64 -0
  24. package/docs/api/manager/cms.manager.get.md +72 -0
  25. package/docs/api/manager/cms.manager.list.md +96 -0
  26. package/docs/api/manager/cms.manager.post.md +70 -0
  27. package/docs/api/manager/cms.manager.put.md +86 -0
  28. package/docs/api/media/del.md +64 -0
  29. package/docs/api/media/edit.md +92 -0
  30. package/docs/api/media/list.md +70 -0
  31. package/docs/api/media/metadata.md +57 -0
  32. package/docs/api/media/preview.md +33 -0
  33. package/docs/api/media/upload.md +84 -0
  34. package/docs/db/erd.md +173 -0
  35. package/docs/db/index.md +7 -0
  36. package/docs/index.md +39 -0
  37. package/docs/public/logo-dark.svg +24 -0
  38. package/docs/public/logo-light.svg +24 -0
  39. package/docs/public/logo-short.svg +15 -0
  40. package/docs/public/logo.svg +19 -0
  41. package/docs/readme/index.md +6 -0
  42. package/docs/src/vs-button.vue +157 -0
  43. package/docs/vue/basic/button.md +144 -0
  44. package/docs/vue/index.md +9 -0
  45. package/index.html +14 -0
  46. package/package.json +2 -5
  47. package/server/app.js +25 -0
  48. package/server/config.js +5 -0
  49. package/server/index.js +23 -0
  50. package/server/migrations/media.sql +30 -0
  51. package/server/plugins/hook.js +91 -0
  52. package/server/plugins/vite.js +80 -0
  53. package/server/routes/builder/controllers/cms.builder.delete.js +21 -0
  54. package/server/routes/builder/controllers/cms.builder.get.js +17 -0
  55. package/server/routes/builder/controllers/cms.builder.list.js +16 -0
  56. package/server/routes/builder/controllers/cms.builder.post.js +21 -0
  57. package/server/routes/builder/controllers/cms.builder.put.js +23 -0
  58. package/server/routes/builder/index.mjs +22 -0
  59. package/server/routes/category/controllers/cms.category.delete.js +21 -0
  60. package/server/routes/category/controllers/cms.category.get.js +17 -0
  61. package/server/routes/category/controllers/cms.category.list.js +16 -0
  62. package/server/routes/category/controllers/cms.category.post.js +21 -0
  63. package/server/routes/category/controllers/cms.category.put.js +23 -0
  64. package/server/routes/category/index.mjs +22 -0
  65. package/server/routes/manager/controllers/cms.manager.delete.js +22 -0
  66. package/server/routes/manager/controllers/cms.manager.get.js +21 -0
  67. package/server/routes/manager/controllers/cms.manager.list.js +31 -0
  68. package/server/routes/manager/controllers/cms.manager.post.js +28 -0
  69. package/server/routes/manager/controllers/cms.manager.put.js +23 -0
  70. package/server/routes/manager/index.mjs +22 -0
  71. package/server/routes/media/controllers/delete.js +59 -0
  72. package/server/routes/media/controllers/edit.js +94 -0
  73. package/server/routes/media/controllers/list.js +74 -0
  74. package/server/routes/media/controllers/metadata.js +51 -0
  75. package/server/routes/media/controllers/preview.js +47 -0
  76. package/server/routes/media/controllers/upload.js +79 -0
  77. package/server/routes/media/index.mjs +16 -0
  78. package/server/routes/root.mjs +15 -0
  79. package/server/templates/cls/cms.category_type.json +10 -0
  80. package/server/templates/cls/cms.content_review_status.json +10 -0
  81. package/server/templates/cls/cms.content_status.json +10 -0
  82. package/server/templates/cls/cms.content_type.json +10 -0
  83. package/server/templates/cls/cms.lang.json +10 -0
  84. package/server/templates/page/login.html +59 -0
  85. package/server/templates/select/cms.category_id.sql +1 -0
  86. package/server/templates/select/cms.type_id.sql +1 -0
  87. package/src/App.vue +4 -0
  88. package/src/assets/tailwind/tailwind.js +62 -0
  89. package/src/assets/vue.svg +1 -0
  90. package/src/components/builder/vs-builder-content.vue +163 -0
  91. package/src/components/builder/vs-builder-menu.vue +142 -0
  92. package/src/components/formats/index.js +8 -0
  93. package/src/components/formats/vs-manager-table-date.vue +29 -0
  94. package/src/components/formats/vs-manager-table-switch.vue +16 -0
  95. package/src/components/icons/icon-actions.vue +24 -0
  96. package/src/components/icons/icon-arrow-left.vue +19 -0
  97. package/src/components/icons/icon-check.vue +23 -0
  98. package/src/components/icons/icon-chewron-right.vue +16 -0
  99. package/src/components/icons/icon-close.vue +22 -0
  100. package/src/components/icons/icon-edit.vue +22 -0
  101. package/src/components/icons/icon-folder.vue +18 -0
  102. package/src/components/icons/icon-folder2.vue +17 -0
  103. package/src/components/icons/icon-home.vue +16 -0
  104. package/src/components/icons/icon-image.vue +18 -0
  105. package/src/components/icons/icon-logo.vue +22 -0
  106. package/src/components/icons/icon-media.vue +22 -0
  107. package/src/components/icons/icon-point.vue +11 -0
  108. package/src/components/icons/icon-search.vue +22 -0
  109. package/src/components/icons/icon-table.vue +22 -0
  110. package/src/components/icons/icon-users.vue +18 -0
  111. package/src/components/icons/icon.plus.vue +18 -0
  112. package/src/components/manager/children/vs-manager-collection-content.vue +55 -0
  113. package/src/components/manager/children/vs-manager-collection-item-content.vue +116 -0
  114. package/src/components/manager/children/vs-manager-single-content.vue +112 -0
  115. package/src/components/manager/manager-table/vs-manager-colection-table-add.vue +84 -0
  116. package/src/components/manager/manager-table/vs-manager-collection-table.vue +59 -0
  117. package/src/components/manager/vs-manager-menu.vue +73 -0
  118. package/src/components/media/Breadcrumb.vue +73 -0
  119. package/src/components/shared-components/vs-not-data.vue +213 -0
  120. package/src/components/vs-main-menu.vue +53 -0
  121. package/src/helpers/debounce.js +10 -0
  122. package/src/helpers/translite.js +19 -0
  123. package/src/main.js +30 -0
  124. package/src/misc/import-file.js +32 -0
  125. package/src/pages/vs-builder.vue +22 -0
  126. package/src/pages/vs-layout.vue +17 -0
  127. package/src/pages/vs-manager.vue +30 -0
  128. package/src/pages/vs-media.vue +398 -0
  129. package/src/router/router.js +9 -0
  130. package/src/router/routes.config.js +40 -0
  131. package/src/style.css +0 -0
  132. package/src/templates/form-columns.js +70 -0
  133. package/src/templates/form-template.js +22 -0
  134. package/test/config.js +17 -0
  135. package/test/files/eye.svg +4 -0
  136. package/test/helper.js +30 -0
  137. package/test/routes/builder.test.js +99 -0
  138. package/test/routes/category.test.js +97 -0
  139. package/test/routes/manager.test.js +103 -0
  140. package/test/routes/media.test.js +252 -0
  141. package/vite.config.js +37 -0
  142. package/editor/dist/cms.js +0 -5900
  143. package/editor/dist/cms.umd.cjs +0 -19
  144. /package/{editor/dist → public}/vite.svg +0 -0
@@ -0,0 +1,398 @@
1
+ <template>
2
+ <div
3
+ class="w-full p-[20px] bg-gray-100 flex justify-center h-[calc(100vh-60px)]"
4
+ >
5
+ <div class="p-[20px] w-full max-w-[1640px]">
6
+ <div>
7
+ <div class="flex items-start justify-between">
8
+ <!-- Breadcrumb Component -->
9
+ <Breadcrumb :initialPath="currentDir" @update-path="updatePath" />
10
+
11
+ <!-- Search Input -->
12
+ <div class="flex gap-2 relative">
13
+ <div
14
+ class="flex items-center justify-between bg-white py-2 px-3 rounded-lg border border-gray-300 focus:outline-none focus:border-blue-500 text-sm w-[250px]"
15
+ >
16
+ <div class="flex items-center gap-[12px]">
17
+ <IconSearch />
18
+ <input
19
+ v-model="searchQuery"
20
+ type="text"
21
+ placeholder="Пошук за назвою..."
22
+ class="focus:outline-none"
23
+ />
24
+ </div>
25
+ <IconClose
26
+ class="w-4 h-4 cursor-pointer"
27
+ v-if="searchQuery"
28
+ @click="clearSearch"
29
+ />
30
+ </div>
31
+
32
+ <button
33
+ ref="dropdownButton"
34
+ @click="isAddDirModalOpen = true"
35
+ class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium border border-gray-300 rounded-lg text-gray-800 hover:bg-gray-100 bg-white"
36
+ >
37
+ <IconFolder2 />
38
+ Додати папку
39
+ </button>
40
+
41
+ <!-- Upload Button -->
42
+ <label
43
+ for="file-upload"
44
+ class="py-2 px-3 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 cursor-pointer"
45
+ >
46
+ Завантажити
47
+ <input
48
+ id="file-upload"
49
+ type="file"
50
+ class="hidden"
51
+ @change="handleFileChange"
52
+ />
53
+ </label>
54
+ </div>
55
+ </div>
56
+
57
+ <!-- No data -->
58
+ <div
59
+ v-if="!filteredIcons?.length"
60
+ class="flex flex-col items-center justify-center h-64 bg-gray-50 rounded-lg border text-center"
61
+ >
62
+ <VsNotData text="" class="![&>div]:min-w-[100px] !w-auto" />
63
+ </div>
64
+
65
+ <!-- Grid of Icons -->
66
+ <div v-else>
67
+ <div class="grid grid-cols-2 lg:grid-cols-5 gap-3 xl:gap-5">
68
+ <div
69
+ v-for="icon in currentIcons"
70
+ :key="icon?.id"
71
+ class="flex flex-col bg-white border rounded-xl"
72
+ @click="icon.type === 'dir' ? navigateToDir(icon.name) : null"
73
+ :class="{
74
+ 'cursor-pointer hover:border-blue-500': icon.type === 'dir',
75
+ 'cursor-default': icon.type !== 'dir',
76
+ }"
77
+ >
78
+ <div class="relative group">
79
+ <div
80
+ class="w-full h-36 sm:h-[170px] object-cover rounded-t-xl flex items-center justify-center"
81
+ >
82
+ <div class="text-[#54aeff]" v-if="icon?.type === 'dir'">
83
+ <IconFolder />
84
+ </div>
85
+ <img
86
+ v-else
87
+ class="object-contain max-h-[40px]"
88
+ :src="`/api/cms-media/${icon?.token}`"
89
+ :alt="icon?.name"
90
+ :style="
91
+ icon?.path?.includes('.svg')
92
+ ? 'width:250px;max-height:100px'
93
+ : ''
94
+ "
95
+ />
96
+ </div>
97
+ </div>
98
+
99
+ <div class="p-3 flex items-center gap-x-3 border-t">
100
+ <span
101
+ v-if="icon.type !== 'dir'"
102
+ class="flex shrink-0 justify-center items-center w-10 h-10 bg-white border border-solid text-gray-500 rounded-lg"
103
+ >
104
+ <IconImage />
105
+ </span>
106
+ <div class="grow truncate" :title="icon?.name">
107
+ <p
108
+ class="block truncate text-sm font-semibold text-gray-800"
109
+ :class="{ 'cursor-pointer': icon.type !== 'dir' }"
110
+ @click.stop="
111
+ icon.type !== 'dir' && copyToClipboard(icon?.name)
112
+ "
113
+ >
114
+ {{ icon?.name }}
115
+ </p>
116
+ <p class="block truncate text-xs text-gray-500">
117
+ {{ icon?.size }}
118
+ </p>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <!-- Pagination -->
125
+ <VsPagination
126
+ v-if="filteredIcons.length > iconsPerPage"
127
+ :defaultPage="currentPage"
128
+ class="mt-6 focus-visible:outline-blue-500 flex !justify-center"
129
+ :total="filteredIcons.length"
130
+ :pageSize="iconsPerPage"
131
+ :maxPages="3"
132
+ :goTo="false"
133
+ @pageChange="currentPage = $event"
134
+ />
135
+ </div>
136
+ </div>
137
+
138
+ <VsDialog
139
+ v-model:visible="isAddDirModalOpen"
140
+ title="Додати папку"
141
+ size="small"
142
+ :closeClickBack="true"
143
+ @onClose="handeAddFolderClose"
144
+ >
145
+ <div class="p-4">
146
+ <VsText v-model="newDirName" placeholder="Назва нової папки.." />
147
+ <div class="flex justify-end">
148
+ <button
149
+ @click="addDir"
150
+ class="mt-4 py-2 px-4 text-white bg-blue-600 hover:bg-blue-700 rounded-lg"
151
+ >
152
+ Створити
153
+ </button>
154
+ </div>
155
+ </div>
156
+ </VsDialog>
157
+ </div>
158
+ </div>
159
+ </template>
160
+
161
+ <script>
162
+ import Breadcrumb from "../components/media/Breadcrumb.vue";
163
+ import IconSearch from "../components/icons/icon-search.vue";
164
+ import IconFolder from "../components/icons/icon-folder.vue";
165
+ import IconFolder2 from "../components/icons/icon-folder2.vue";
166
+ import IconClose from "../components/icons/icon-close.vue";
167
+ import IconActions from "../components/icons/icon-actions.vue";
168
+ import axios from "axios";
169
+ import IconImage from "../components/icons/icon-image.vue";
170
+ import VsNotData from "../components/shared-components/vs-not-data.vue";
171
+
172
+ export default {
173
+ components: {
174
+ Breadcrumb,
175
+ IconSearch,
176
+ IconFolder,
177
+ IconFolder2,
178
+ IconClose,
179
+ IconImage,
180
+ IconActions,
181
+ VsNotData,
182
+ },
183
+ props: {
184
+ type: {
185
+ type: String,
186
+ default: "icon",
187
+ },
188
+ },
189
+ data() {
190
+ return {
191
+ icons: [],
192
+ currentPage: parseInt(this.$route.query.page, 10) || 1,
193
+ iconsPerPage: 15,
194
+ token: "",
195
+ searchQuery: "",
196
+ selectedFile: null,
197
+ isAddDirModalOpen: false,
198
+ newDirName: "",
199
+ };
200
+ },
201
+ watch: {
202
+ isAddDirModalOpen(n) {
203
+ if (!n) {
204
+ this.newDirName = "";
205
+ }
206
+ },
207
+ },
208
+ computed: {
209
+ currentDir() {
210
+ return this.$route.query.dir || "";
211
+ },
212
+ currentTab() {
213
+ return this.$route.query.tab || "";
214
+ },
215
+ filteredIcons() {
216
+ if (!this.searchQuery) return this.icons;
217
+ return this.icons.filter((icon) =>
218
+ icon.name.toLowerCase().includes(this.searchQuery.toLowerCase())
219
+ );
220
+ },
221
+ sortedIcons() {
222
+ return [...this.filteredIcons].sort((a, b) => {
223
+ if (a.type === "dir" && b.type !== "dir") return -1;
224
+ if (a.type !== "dir" && b.type === "dir") return 1;
225
+ return a.name.localeCompare(b.name);
226
+ });
227
+ },
228
+ currentIcons() {
229
+ const startIndex = (this.currentPage - 1) * this.iconsPerPage;
230
+ const endIndex = startIndex + this.iconsPerPage;
231
+ return this.sortedIcons.slice(startIndex, endIndex);
232
+ },
233
+ },
234
+ methods: {
235
+ async fetchIcons(dir) {
236
+ try {
237
+ const { data } = await axios.get(`/api/cms-media`, {
238
+ params: { dir },
239
+ });
240
+ this.icons = data?.data || [];
241
+ this.token = data?.token;
242
+ } catch (error) {
243
+ console.error("Error fetching icons:", error);
244
+ }
245
+ },
246
+ async addDir() {
247
+ if (!this.newDirName.trim()) {
248
+ this.$notify({
249
+ type: "error",
250
+ title: "Помилка",
251
+ message: "Назва папки не може бути порожньою.",
252
+ });
253
+ return;
254
+ }
255
+
256
+ try {
257
+ const response = await axios.post(`/api/cms-media/${this.token}`, {
258
+ name: this.newDirName,
259
+ });
260
+
261
+ this.$notify({
262
+ type: "success",
263
+ title: "Успіх!",
264
+ message: `Папку "${this.newDirName}" успішно створено.`,
265
+ });
266
+
267
+ this.fetchIcons(this.currentDir);
268
+
269
+ this.handeAddFolderClose();
270
+ this.newDirName = "";
271
+ } catch (error) {
272
+ console.error("Error creating directory:", error);
273
+ this.$notify({
274
+ type: "error",
275
+ title: "Помилка",
276
+ message:
277
+ error.response?.data?.message || "Не вдалося створити папку.",
278
+ });
279
+ }
280
+ },
281
+ handeAddFolderClose() {
282
+ this.isAddDirModalOpen = false;
283
+ },
284
+ navigateToDir(dirName) {
285
+ const newDir = `${this.currentDir}/${dirName}`.replace(/\/+/g, "/");
286
+ this.updateURL(newDir);
287
+ },
288
+ updatePath(newPath) {
289
+ this.updateURL(newPath);
290
+ },
291
+ updateURL(dir) {
292
+ this.$router.push({
293
+ query: {
294
+ ...this.$route.query,
295
+ dir,
296
+ page: this.currentPage,
297
+ },
298
+ });
299
+ },
300
+ async handleFileChange(event) {
301
+ const file = event.target.files[0];
302
+ if (!file) return;
303
+
304
+ const formData = new FormData();
305
+ formData.append("file", file);
306
+
307
+ try {
308
+ const response = await axios.post(
309
+ `/api/cms-media/${this.token}`,
310
+ formData,
311
+ {
312
+ headers: {
313
+ "Content-Type": "multipart/form-data",
314
+ },
315
+ }
316
+ );
317
+
318
+ this.$notify({
319
+ type: "success",
320
+ title: "Успіх!",
321
+ message: "Файл успішно додано!",
322
+ });
323
+
324
+ this.currentPage = 1;
325
+ } catch (error) {
326
+ console.error("Error uploading file:", error);
327
+ this.$notify({
328
+ type: "error",
329
+ title: "Помилка",
330
+ message: error.response.statustext || error.message || error,
331
+ });
332
+ } finally {
333
+ await this.fetchIcons(this.currentDir);
334
+ }
335
+ },
336
+ clearSearch() {
337
+ this.searchQuery = "";
338
+ },
339
+
340
+ copyToClipboard(textToCopy) {
341
+ try {
342
+ const tempTextArea = document.createElement("textarea");
343
+ tempTextArea.value = textToCopy;
344
+ document.body.appendChild(tempTextArea);
345
+ tempTextArea.select();
346
+ tempTextArea.setSelectionRange(0, textToCopy.length);
347
+ const successful = document.execCommand("copy");
348
+ document.body.removeChild(tempTextArea);
349
+
350
+ if (successful) {
351
+ this.$notify({
352
+ type: "success",
353
+ title: "Скопійовано!",
354
+ message: "Назву іконки успішно скопійовано.",
355
+ });
356
+ } else {
357
+ this.$notify({
358
+ type: "error",
359
+ title: "Помилка",
360
+ message: "Не вдалося скопіювати шлях.",
361
+ });
362
+ }
363
+ } catch (error) {
364
+ this.$notify({
365
+ type: "error",
366
+ title: "Помилка",
367
+ message: "Не вдалося скопіювати координати",
368
+ });
369
+ console.error("Copy failed", error);
370
+ }
371
+ },
372
+ },
373
+ watch: {
374
+ currentDir: {
375
+ immediate: true,
376
+ handler(newDir) {
377
+ this.fetchIcons(newDir);
378
+ },
379
+ },
380
+ currentTab: {
381
+ handler() {
382
+ this.currentPage = 1;
383
+ },
384
+ },
385
+ currentPage(newPage) {
386
+ this.$emit("update-url", {
387
+ query: {
388
+ ...this.$route.query,
389
+ page: newPage,
390
+ },
391
+ });
392
+ },
393
+ },
394
+ async mounted() {
395
+ await this.fetchIcons(this.currentDir);
396
+ },
397
+ };
398
+ </script>
@@ -0,0 +1,9 @@
1
+ import { createRouter, createWebHistory } from 'vue-router';
2
+ import routes from './routes.config.js';
3
+
4
+ const router = createRouter({
5
+ history: createWebHistory(),
6
+ routes,
7
+ });
8
+
9
+ export default router;
@@ -0,0 +1,40 @@
1
+ export default [
2
+ {
3
+ name: 'app',
4
+ path: '/',
5
+ redirect: '/cms/manager',
6
+ children: [
7
+ {
8
+ name: 'cms',
9
+ path: '/cms',
10
+ component: () => import('../pages/vs-layout.vue'),
11
+ children: [
12
+ {
13
+ name: 'builder',
14
+ path: 'builder',
15
+ component: () => import('../pages/vs-builder.vue'),
16
+ children: [
17
+ { path: ':id', name: 'builder-item', component: () => import('../components/builder/vs-builder-content.vue') },
18
+ ]
19
+
20
+ },
21
+ {
22
+ name: 'manager',
23
+ path: 'manager',
24
+ component: () => import('../pages/vs-manager.vue'),
25
+ children: [
26
+ { path: 'collection/:template', name: 'manager-collection-item', component: () => import('../components/manager/children/vs-manager-collection-content.vue') },
27
+ { path: 'collection/:template/:id', name: 'manager-collection-form', component: () => import('../components/manager/children/vs-manager-collection-item-content.vue') },
28
+ { path: 'single/:template', name: 'manager-single-item', component: () => import('../components/manager/children/vs-manager-single-content.vue') },
29
+ ]
30
+ },
31
+ {
32
+ name: 'media',
33
+ path: 'media',
34
+ component: () => import('../pages/vs-media.vue'),
35
+ },
36
+ ],
37
+ },
38
+ ],
39
+ },
40
+ ];
package/src/style.css ADDED
File without changes
@@ -0,0 +1,70 @@
1
+ export default [
2
+ {
3
+ key: "title",
4
+ placeholder: "Назва колонки українською",
5
+ ua: "Назва колонки українською",
6
+ type: "text",
7
+ slots: {
8
+ row: '<div class="flex items-center gap-2"><img class="block" height="24" width="30" :src="`https://cdn.softpro.ua/data/npm/admin/column-types/icon-${row?.type?.toLowerCase()}.svg`"/> <span class="text-[12px]">{{ row?.title }}</span></div>',
9
+ },
10
+ validators: ["required"],
11
+ },
12
+ {
13
+ key: "type",
14
+ type: "radio",
15
+ ua: "Тип колонки",
16
+ view: "buttons",
17
+ style: {
18
+ class: "!w-[calc(50%-5px)]",
19
+ },
20
+ slots: {
21
+ label:
22
+ '<div class="flex items-center justify-start w-full gap-4"><img class="block" height="24" width="30" :src="`https://cdn.softpro.ua/data/npm/admin/column-types/icon-${id?.toLowerCase()}.svg`"/><div class="flex flex-col items-start gap-1"><span class="text-black text-[14px]">{{text}}</span><span class="text-[12px]">{{description}}</span></div></div>',
23
+ },
24
+ options: [
25
+ {
26
+ id: "Text",
27
+ text: "Текст",
28
+ description: "Маленький або довгий текст, наприклад заголовок або опис",
29
+ },
30
+ {
31
+ id: "Number",
32
+ text: "Цифри",
33
+ description: "Числа (цілі, з плаваючою точкою, десяткові)",
34
+ },
35
+ {
36
+ id: "Email",
37
+ text: "Електронна пошта",
38
+ description: "Поле електронної пошти з фоматом перевірки",
39
+ },
40
+ {
41
+ id: "Date",
42
+ text: "Дата",
43
+ description: "Вибір дати з годинами, хвилинами та секундами",
44
+ },
45
+ {
46
+ id: "Switcher",
47
+ text: "Так/Ні",
48
+ description: "Так чи ні, 1 або 0, вірно чи хибно",
49
+ },
50
+ { id: "File", text: "Файл", description: "Різноманітні файли" },
51
+ {
52
+ id: "Select",
53
+ text: "Селект",
54
+ description: "Список значень, а потім виберіть одне",
55
+ },
56
+ {
57
+ id: "Badge",
58
+ text: "Бейдж",
59
+ description: "Стилізоване значення з переліку",
60
+ },
61
+ ],
62
+ validators: ["required"],
63
+ },
64
+ {
65
+ key: "enabled",
66
+ type: "Switcher",
67
+ ua: "Увімкнено",
68
+ col: 6,
69
+ },
70
+ ]
@@ -0,0 +1,22 @@
1
+ export default [
2
+ {
3
+ key: "name",
4
+ type: "Text",
5
+ ua: "Назва",
6
+ placeholder: "Назва",
7
+ validators: ["required"],
8
+ },
9
+ {
10
+ key: "template",
11
+ type: "Text",
12
+ ua: "Шаблон",
13
+ placeholder: "Шаблон",
14
+ validators: ["required"],
15
+ },
16
+ {
17
+ key: "description",
18
+ type: "Text",
19
+ ua: "Опис",
20
+ placeholder: "Опис",
21
+ },
22
+ ]
package/test/config.js ADDED
@@ -0,0 +1,17 @@
1
+ import config from '../server/config.js';
2
+
3
+ Object.assign(config, {
4
+ pg: config.pg || {
5
+ host: '192.168.3.160',
6
+ port: 5439,
7
+ database: 'ip_ukraine',
8
+ user: 'postgres',
9
+ password: 'postgres',
10
+ },
11
+ redis: config.redis || {
12
+ host: '192.168.3.160',
13
+ port: 6379,
14
+ family: 4,
15
+ },
16
+ });
17
+ export default config;
@@ -0,0 +1,4 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M1.3335 8C1.3335 8 3.3335 3.33333 8.00016 3.33333C12.6668 3.33333 14.6668 8 14.6668 8C14.6668 8 12.6668 12.6667 8.00016 12.6667C3.3335 12.6667 1.3335 8 1.3335 8Z" stroke="#6B7280" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" stroke="#6B7280" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
package/test/helper.js ADDED
@@ -0,0 +1,30 @@
1
+ // This file contains code that we reuse
2
+ // between our tests.
3
+ import Fastify from 'fastify';
4
+
5
+ import { redisClients, pgClients } from '@opengis/fastify-table/utils.js';
6
+
7
+ import appService from '../server/app.js';
8
+
9
+ // automatically build and tear down our instance
10
+ async function build(t) {
11
+ // you can set all the options supported by the fastify CLI command
12
+ // const argv = [AppPath]
13
+ process.env.NODE_ENV = 'production';
14
+ const app = Fastify({ logger: false });
15
+ app.register(appService);
16
+ // close the app after we are done
17
+ t.after(() => {
18
+ Object.keys(pgClients).forEach((key) => {
19
+ pgClients[key].end();
20
+ });
21
+ Object.keys(redisClients || {}).forEach((key) => {
22
+ redisClients[key].quit();
23
+ });
24
+ app.close();
25
+ });
26
+
27
+ return app;
28
+ }
29
+
30
+ export default build;