@opengis/gis 0.2.151 → 0.2.154

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 (199) hide show
  1. package/README.md +181 -181
  2. package/dist/{CardIcon-COYvGn3y.js → CardIcon--lAtW-9w.js} +1 -1
  3. package/dist/{EntityTablePage-n5jN3Vg8.js → EntityTablePage-C4xpTFhX.js} +2 -2
  4. package/dist/{ExtentOutlineLayer.vue_vue_type_script_setup_true_lang-_bbOMBQM.js → ExtentOutlineLayer.vue_vue_type_script_setup_true_lang-ChIqnIJk.js} +1 -1
  5. package/dist/HeaderActions.vue_vue_type_script_setup_true_lang-ZusIbDWr.js +1099 -0
  6. package/dist/{MapSettings-DFpaiasG.js → MapSettings-DW8jEvOa.js} +2 -2
  7. package/dist/{RastersTablePage-BDPlRImd.js → RastersTablePage-BiLlnxUp.js} +2 -2
  8. package/dist/{cartocss-DAww4B8T.js → cartocss-CLomvOS2.js} +5 -5
  9. package/dist/{import-utils-BD6m47wz.js → import-utils-kb-uej6A.js} +1 -1
  10. package/dist/{index-DgSwtpZG.js → index-BlZ7asai.js} +37 -37
  11. package/dist/index.css +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/index.umd.cjs +20 -20
  14. package/dist/{raster-Dj4pagIY.js → raster-DwJbTo-Q.js} +3 -3
  15. package/dist/{register-lve1-eW0.js → register-O9oHRhKY.js} +3 -3
  16. package/dist/{service-DfMY6QRr.js → service-Bej37Mtm.js} +6 -6
  17. package/dist/{vs-datatable-CMGb14xz.js → vs-datatable-ChBQO9dx.js} +2 -2
  18. package/module/cls.json +6 -6
  19. package/module/gis/card/gis.metadata.table/index.yml +22 -22
  20. package/module/gis/card/gis.metadata.table/main_info.hbs +20 -20
  21. package/module/gis/card/gis.metadata.table/metadata_info.hbs +27 -27
  22. package/module/gis/card/gis.metadata.table/other.hbs +25 -25
  23. package/module/gis/card/gis.rasters.table/index.yml +11 -11
  24. package/module/gis/card/gis.rasters.table/main_info.hbs +27 -27
  25. package/module/gis/card/gis.registers.table/cls.hbs +36 -36
  26. package/module/gis/card/gis.registers.table/columns.hbs +89 -89
  27. package/module/gis/card/gis.registers.table/filters.hbs +80 -80
  28. package/module/gis/card/gis.registers.table/index.yml +23 -23
  29. package/module/gis/card/gis.registers.table/main_info.hbs +35 -35
  30. package/module/gis/card/gis.registers.table/source.hbs +45 -45
  31. package/module/gis/card/gis.services.table/attributes.hbs +91 -91
  32. package/module/gis/card/gis.services.table/filters.hbs +83 -83
  33. package/module/gis/card/gis.services.table/index.yml +25 -25
  34. package/module/gis/card/gis.services.table/main_info.hbs +27 -27
  35. package/module/gis/card/gis.services.table/source.hbs +25 -25
  36. package/module/gis/cls/bool.yes_no.json +12 -12
  37. package/module/gis/cls/encoding.json +14 -14
  38. package/module/gis/cls/geom_type.json +14 -14
  39. package/module/gis/cls/gis.column_type.json +34 -34
  40. package/module/gis/cls/gis.column_view_type.json +26 -26
  41. package/module/gis/cls/gis.filter_type.json +22 -22
  42. package/module/gis/cls/language.json +10 -10
  43. package/module/gis/cls/meta.service_type.json +42 -42
  44. package/module/gis/cls/ogc.service.json +21 -21
  45. package/module/gis/cls/service_type.json +42 -42
  46. package/module/gis/cls/source_type.json +10 -10
  47. package/module/gis/cls/standarts.json +6 -6
  48. package/module/gis/cls/topic_category.json +106 -106
  49. package/module/gis/cls/update_frequency.json +29 -29
  50. package/module/gis/cls/view.json +21 -21
  51. package/module/gis/form/feedback.answer.form.json +10 -10
  52. package/module/gis/form/gis.cartocss.form.json +64 -64
  53. package/module/gis/form/gis.group_list.form.json +17 -17
  54. package/module/gis/form/gis.maps.form.json +61 -61
  55. package/module/gis/form/gis.metadata.form.json +240 -240
  56. package/module/gis/form/gis.metadata_new.form.json +195 -195
  57. package/module/gis/form/gis.ogc_service.form.json +51 -51
  58. package/module/gis/form/gis.rasters.form.json +76 -76
  59. package/module/gis/form/gis.registers.form.json +124 -124
  60. package/module/gis/form/gis.registers_column.form.json +84 -84
  61. package/module/gis/form/gis.registers_filter.form.json +65 -65
  62. package/module/gis/form/gis.services.form.json +111 -111
  63. package/module/gis/form/gis.services_attributes.form.json +75 -75
  64. package/module/gis/form/gis.services_filter.form.json +65 -65
  65. package/module/gis/menu.json +43 -43
  66. package/module/gis/select/admin.cls.name.sql +9 -9
  67. package/module/gis/select/layer_list.sql +7 -7
  68. package/module/gis/select/layer_list_text.sql +7 -7
  69. package/module/gis/select/pg.column_name.geometry.sql +12 -12
  70. package/module/gis/select/pg.columns.parent.sql +6 -6
  71. package/module/gis/select/pg.table_name.sql +17 -17
  72. package/module/gis/select/service_id.sql +1 -1
  73. package/module/gis/table/gis.cartocss.table.json +74 -74
  74. package/module/gis/table/gis.group_list.table.json +58 -58
  75. package/module/gis/table/gis.maps.table.json +110 -110
  76. package/module/gis/table/gis.metadata.table.json +70 -70
  77. package/module/gis/table/gis.metadata_new.table.json +137 -137
  78. package/module/gis/table/gis.ogc_service.table.json +100 -100
  79. package/module/gis/table/gis.rasters.table.json +113 -113
  80. package/module/gis/table/gis.registers.table.json +143 -143
  81. package/module/gis/table/gis.services.table.json +120 -120
  82. package/module/gis/table/site.gis.registers.table.json +88 -88
  83. package/module/gis/table/site.gis.services.table.json +106 -106
  84. package/module/gis/templates/ISO19136_2017_gml_template.xml +330 -330
  85. package/module/gis/tokens.yml +5 -5
  86. package/module/permissions/form/permissions.users.form.json +151 -151
  87. package/module/permissions/table/gis.permissions.table.json +97 -97
  88. package/module/test/cls/bp_build_type.json +37 -37
  89. package/module/test/cls/doc_status.json +31 -31
  90. package/module/test/cls/ts.temp_status.json +18 -18
  91. package/module/test/cls/ts.temp_structure.ts_class.json +49 -49
  92. package/module/test/cls/ts.temp_type.json +9 -9
  93. package/module/test/layer/bp.json +59 -59
  94. package/module/test/layer/bp1.yml +33 -33
  95. package/module/test/layer/individual.yml +53 -53
  96. package/module/test/layer/ts.linking_passport.yml +55 -55
  97. package/module/test/layer/ts.temp_structure.yml +50 -50
  98. package/module/test/map/addr.yml +21 -21
  99. package/module/test/map/bp_myo.json +43 -43
  100. package/module/test/map/bpf.json +43 -43
  101. package/module/test/map/main.json +37 -37
  102. package/module/test/map/mbd.json +92 -92
  103. package/module/test/map/ts.json +53 -53
  104. package/module/test/select/address_id.json +2 -2
  105. package/module/test/select/address_id.sql +7 -7
  106. package/module/test/select/core.user_uid.sql +1 -1
  107. package/module/test/table/data_address.street.table.json +69 -69
  108. package/module/test/table/data_bp_myo.bp.table.json +122 -122
  109. package/package.json +6 -6
  110. package/plugin.js +55 -55
  111. package/server/migrations/array_intersect.sql +13 -13
  112. package/server/migrations/cartocss.sql +27 -27
  113. package/server/migrations/group_list.sql +74 -74
  114. package/server/migrations/maps.sql +30 -30
  115. package/server/migrations/metadata.sql +415 -415
  116. package/server/migrations/ogc.sql +106 -106
  117. package/server/migrations/rasters.sql +265 -265
  118. package/server/migrations/services.sql +247 -247
  119. package/server/migrations/services_users_rel.sql +22 -22
  120. package/server/migrations/widgets.sql +20 -20
  121. package/server/plugins/crons.js +21 -21
  122. package/server/plugins/mapnik/funcs/checkRasterFile.js +109 -109
  123. package/server/plugins/mapnik/funcs/mapnik.js +151 -151
  124. package/server/plugins/mapnik/funcs/rootFolder.mjs +8 -8
  125. package/server/plugins/mapnik/map.proto +305 -230
  126. package/server/plugins/vite.js +74 -74
  127. package/server/routes/gis/cartocss/add.cartocss.js +42 -42
  128. package/server/routes/gis/cartocss/get.cartocss.js +59 -59
  129. package/server/routes/gis/checkXML.js +117 -117
  130. package/server/routes/gis/dashboard.js +29 -29
  131. package/server/routes/gis/index.mjs +89 -87
  132. package/server/routes/gis/metadata/editMetadata.js +34 -34
  133. package/server/routes/gis/metadata/metadataXML.js +13 -13
  134. package/server/routes/gis/ogc/map.info.point.js +124 -124
  135. package/server/routes/gis/registers/add.registry.js +35 -35
  136. package/server/routes/gis/registers/del.registry.js +14 -14
  137. package/server/routes/gis/registers/funcs/classifiers.js +100 -100
  138. package/server/routes/gis/registers/funcs/columns.js +3 -3
  139. package/server/routes/gis/registers/funcs/content.type.js +9 -9
  140. package/server/routes/gis/registers/funcs/get.info.js +89 -89
  141. package/server/routes/gis/registers/funcs/handleRegistryRequest.js +146 -146
  142. package/server/routes/gis/registers/gis.export.js +153 -153
  143. package/server/routes/gis/registers/gis.registry.js +64 -64
  144. package/server/routes/gis/registers/gis.registry.list.js +59 -59
  145. package/server/routes/gis/registers/insert.columns.js +107 -107
  146. package/server/routes/gis/registers/insert.filters.js +110 -110
  147. package/server/routes/gis/registers/map.registry.js +79 -79
  148. package/server/routes/gis/services/add.service.js +64 -64
  149. package/server/routes/gis/services/del.service.js +12 -12
  150. package/server/routes/gis/services/get.layer.geom.js +27 -27
  151. package/server/routes/gis/services/get.service.users.js +74 -0
  152. package/server/routes/gis/services/get.services.col.js +33 -33
  153. package/server/routes/gis/services/get.services.js +84 -84
  154. package/server/routes/gis/services/legend.auto.js +77 -77
  155. package/server/routes/map/controllers/clearTiles.js +34 -34
  156. package/server/routes/map/controllers/geojson.js +187 -187
  157. package/server/routes/map/controllers/jsonData.js +205 -205
  158. package/server/routes/map/controllers/layerList.js +102 -102
  159. package/server/routes/map/controllers/map.js +123 -123
  160. package/server/routes/map/controllers/mapCatalog.js +72 -72
  161. package/server/routes/map/controllers/mapCatalogAttribute.js +55 -55
  162. package/server/routes/map/controllers/mapFeatures.js +128 -128
  163. package/server/routes/map/controllers/mapFormat.js +234 -234
  164. package/server/routes/map/controllers/mapTiles.js +152 -152
  165. package/server/routes/map/controllers/maps.js +15 -15
  166. package/server/routes/map/controllers/marker_icon.js +43 -43
  167. package/server/routes/map/controllers/vtile.js +172 -172
  168. package/server/routes/map/index.mjs +169 -169
  169. package/server/routes/map/maps/add.map.js +43 -43
  170. package/server/routes/map/maps/del.map.js +18 -18
  171. package/server/routes/map/maps/get.map.js +118 -118
  172. package/server/routes/map/vtile1.js +179 -179
  173. package/server/routes/map/widgets/add.widget.js +38 -38
  174. package/server/routes/map/widgets/del.widget.js +22 -22
  175. package/server/routes/map/widgets/get.widget.js +40 -40
  176. package/server/routes/mapnik/controllers/clearTiles.js +106 -106
  177. package/server/routes/mapnik/controllers/createXml.js +67 -67
  178. package/server/routes/mapnik/controllers/createXmlMulti.js +76 -76
  179. package/server/routes/mapnik/controllers/fileSearch.js +38 -38
  180. package/server/routes/mapnik/controllers/fileStat.js +28 -28
  181. package/server/routes/mapnik/controllers/mapnikLogger.js +29 -29
  182. package/server/routes/mapnik/controllers/mapnikStat.js +19 -19
  183. package/server/routes/mapnik/controllers/pretile.js +144 -144
  184. package/server/routes/mapnik/controllers/rasterInfo.js +57 -57
  185. package/server/routes/mapnik/controllers/readDir.js +22 -22
  186. package/server/routes/mapnik/controllers/rtile.js +166 -150
  187. package/server/routes/mapnik/controllers/uploadRaster.js +157 -157
  188. package/server/routes/mapnik/functions/cartoBounds.js +32 -32
  189. package/server/routes/mapnik/functions/convertBoundToTile.js +27 -27
  190. package/server/routes/mapnik/functions/uploadXML.js +113 -113
  191. package/server/routes/mapnik/index.js +40 -40
  192. package/server/routes/permissions/controllers/catalog.permissions.edit.js +22 -22
  193. package/server/routes/permissions/controllers/catalog.permissions.js +7 -7
  194. package/server/routes/permissions/controllers/gis.catalog.js +80 -80
  195. package/server/routes/permissions/controllers/utils/get.permissions.js +59 -59
  196. package/server/routes/permissions/index.mjs +18 -18
  197. package/server/routes/root.mjs +3 -3
  198. package/utils.js +13 -13
  199. package/dist/HeaderActions.vue_vue_type_script_setup_true_lang-X8W5T9FU.js +0 -847
@@ -0,0 +1,1099 @@
1
+ import { openBlock as c, createElementBlock as v, createElementVNode as l, defineComponent as Y, normalizeClass as le, createVNode as F, createBlock as ie, unref as R, ref as y, computed as g, watch as ue, withDirectives as ke, vModelText as Ce, createCommentVNode as H, Fragment as q, renderList as J, createStaticVNode as ze, toDisplayString as x, defineAsyncComponent as ae, createTextVNode as be, withCtx as re, nextTick as Ve, onMounted as Se, onUnmounted as $e, withModifiers as Ee, Teleport as Me, normalizeStyle as Le } from "vue";
2
+ import { _ as Te } from "./index-BlZ7asai.js";
3
+ import { Settings as Ie, BrushCleaning as fe, SquareCode as ye, Pencil as Be } from "lucide-vue-next";
4
+ import { notify as X } from "@opengis/core";
5
+ const Ue = {}, je = {
6
+ xmlns: "http://www.w3.org/2000/svg",
7
+ width: "24",
8
+ height: "24",
9
+ viewBox: "0 0 24 24",
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ "stroke-width": "2",
13
+ "stroke-linecap": "round",
14
+ "stroke-linejoin": "round",
15
+ class: "inline-block shrink-0"
16
+ };
17
+ function Ae(a, k) {
18
+ return c(), v("svg", je, [...k[0] || (k[0] = [
19
+ l("path", { d: "M8 3 4 7l4 4" }, null, -1),
20
+ l("path", { d: "M4 7h16" }, null, -1),
21
+ l("path", { d: "m16 21 4-4-4-4" }, null, -1),
22
+ l("path", { d: "M20 17H4" }, null, -1)
23
+ ])]);
24
+ }
25
+ const Ne = /* @__PURE__ */ Te(Ue, [["render", Ae]]), Re = ["aria-label"], Bt = /* @__PURE__ */ Y({
26
+ __name: "PanelToggleButton",
27
+ props: {
28
+ open: { type: Boolean },
29
+ topClass: { default: "top-5" }
30
+ },
31
+ emits: ["toggle"],
32
+ setup(a) {
33
+ return (k, m) => (c(), v("button", {
34
+ type: "button",
35
+ onClick: m[0] || (m[0] = (E) => k.$emit("toggle")),
36
+ class: le([
37
+ "absolute right-0 w-5 h-9 shrink-0 rounded-l-lg inline-flex items-center justify-center",
38
+ "text-gray-600 hover:bg-gray-100 hover:text-gray-800 transition border border-gray-100 shadow-md bg-white z-[21]",
39
+ a.topClass
40
+ ]),
41
+ "aria-label": a.open ? "Закрити панель" : "Відкрити панель"
42
+ }, [
43
+ F(Ne, { class: "h-3 w-3" })
44
+ ], 10, Re));
45
+ }
46
+ }), Ut = /* @__PURE__ */ Y({
47
+ __name: "SettingsIcon",
48
+ setup(a) {
49
+ return (k, m) => (c(), ie(R(Ie), {
50
+ size: 16,
51
+ class: "lucide lucide-settings"
52
+ }));
53
+ }
54
+ }), Fe = { class: "flex flex-col gap-2" }, De = { class: "relative flex items-center" }, Oe = {
55
+ key: 0,
56
+ class: "flex flex-col gap-1.5"
57
+ }, Pe = {
58
+ key: 1,
59
+ class: "flex flex-col items-center gap-1.5 py-5 text-gray-400"
60
+ }, He = { class: "text-xs" }, Ge = {
61
+ key: 2,
62
+ class: "flex flex-col gap-1 p-0"
63
+ }, Qe = { class: "flex size-[30px] shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-blue-500 to-indigo-500 text-xs font-semibold text-white" }, qe = { class: "flex min-w-0 flex-1 flex-col gap-0.5" }, Xe = { class: "truncate text-xs font-medium text-gray-900" }, We = { class: "flex flex-wrap gap-1" }, Je = {
64
+ key: 3,
65
+ class: "flex items-center justify-end gap-1.5 pt-1"
66
+ }, Ye = ["disabled"], Ze = { class: "min-w-[36px] text-center text-[11px] text-gray-500" }, Ke = ["disabled"], et = { class: "ml-1 text-[11px] text-gray-400" }, tt = /* @__PURE__ */ Y({
67
+ __name: "ServiceUsers",
68
+ props: {
69
+ serviceId: {},
70
+ limit: {}
71
+ },
72
+ setup(a) {
73
+ const k = a, m = k.limit ?? 10, E = y([]), d = y(0), U = y(!1), b = y(1), _ = y("");
74
+ let C = null;
75
+ const M = g(() => Math.max(1, Math.ceil(d.value / m))), I = g(() => {
76
+ const i = d.value % 100, n = d.value % 10;
77
+ return i >= 11 && i <= 19 ? "ів" : n === 1 ? "" : n >= 2 && n <= 4 ? "и" : "ів";
78
+ });
79
+ function e(i) {
80
+ return (i || "?").trim().charAt(0).toUpperCase();
81
+ }
82
+ function z(i) {
83
+ if (!i) return [];
84
+ if (Array.isArray(i)) return i;
85
+ if (typeof i == "string") {
86
+ try {
87
+ const n = JSON.parse(i);
88
+ if (Array.isArray(n)) return n;
89
+ } catch {
90
+ }
91
+ return i.replace(/[{}"]/g, "").split(",").filter(Boolean);
92
+ }
93
+ return [];
94
+ }
95
+ const L = {
96
+ view: "Перегляд",
97
+ edit: "Редагування",
98
+ del: "Видалення",
99
+ add: "Додавання"
100
+ };
101
+ function j(i) {
102
+ return L[i] ?? i;
103
+ }
104
+ const B = {
105
+ view: "bg-blue-50 text-blue-700 border-blue-200",
106
+ edit: "bg-green-50 text-green-700 border-green-200",
107
+ del: "bg-red-50 text-red-600 border-red-200",
108
+ add: "bg-emerald-50 text-emerald-700 border-emerald-200",
109
+ admin: "bg-purple-50 text-purple-700 border-purple-200",
110
+ export: "bg-amber-50 text-amber-700 border-amber-200",
111
+ import: "bg-teal-50 text-teal-700 border-teal-200"
112
+ };
113
+ function D(i) {
114
+ return B[i] ?? "bg-gray-50 text-gray-600 border-gray-200";
115
+ }
116
+ async function A() {
117
+ if (!k.serviceId) {
118
+ E.value = [], d.value = 0;
119
+ return;
120
+ }
121
+ U.value = !0;
122
+ try {
123
+ const i = (b.value - 1) * m, n = new URLSearchParams({
124
+ limit: String(m),
125
+ offset: String(i)
126
+ });
127
+ _.value.trim() && n.set("search", _.value.trim());
128
+ const h = await fetch(`/api/gis-service-users/${encodeURIComponent(String(k.serviceId))}?${n}`);
129
+ if (!h.ok) throw new Error(`HTTP ${h.status}`);
130
+ const $ = await h.json();
131
+ E.value = ($ == null ? void 0 : $.rows) ?? [], d.value = ($ == null ? void 0 : $.count) ?? 0;
132
+ } catch (i) {
133
+ console.error("[ServiceUsers] fetch error", i), E.value = [], d.value = 0;
134
+ } finally {
135
+ U.value = !1;
136
+ }
137
+ }
138
+ function S(i) {
139
+ b.value = i, A();
140
+ }
141
+ function T() {
142
+ C && clearTimeout(C), C = setTimeout(() => {
143
+ b.value = 1, A();
144
+ }, 350);
145
+ }
146
+ function w() {
147
+ _.value = "", b.value = 1, A();
148
+ }
149
+ return ue(
150
+ () => k.serviceId,
151
+ () => {
152
+ b.value = 1, _.value = "", A();
153
+ },
154
+ { immediate: !0 }
155
+ ), (i, n) => (c(), v("div", Fe, [
156
+ l("div", De, [
157
+ n[4] || (n[4] = l("div", { class: "pointer-events-none absolute left-2.5 flex text-gray-400" }, [
158
+ l("svg", {
159
+ xmlns: "http://www.w3.org/2000/svg",
160
+ width: "14",
161
+ height: "14",
162
+ viewBox: "0 0 24 24",
163
+ fill: "none",
164
+ stroke: "currentColor",
165
+ "stroke-width": "2",
166
+ "stroke-linecap": "round",
167
+ "stroke-linejoin": "round"
168
+ }, [
169
+ l("circle", {
170
+ cx: "11",
171
+ cy: "11",
172
+ r: "8"
173
+ }),
174
+ l("line", {
175
+ x1: "21",
176
+ y1: "21",
177
+ x2: "16.65",
178
+ y2: "16.65"
179
+ })
180
+ ])
181
+ ], -1)),
182
+ ke(l("input", {
183
+ "onUpdate:modelValue": n[0] || (n[0] = (h) => _.value = h),
184
+ type: "text",
185
+ class: "w-full rounded-md border border-gray-200 bg-gray-50 py-1.5 pl-8 pr-7 text-xs text-gray-900 outline-none transition focus:border-blue-400 focus:bg-white focus:ring-2 focus:ring-blue-400/20",
186
+ placeholder: "Пошук за іменем або логіном…",
187
+ onInput: T
188
+ }, null, 544), [
189
+ [Ce, _.value]
190
+ ]),
191
+ _.value ? (c(), v("button", {
192
+ key: 0,
193
+ class: "absolute right-2 flex items-center justify-center rounded p-0.5 text-gray-400 transition hover:text-gray-700",
194
+ onClick: w
195
+ }, [...n[3] || (n[3] = [
196
+ l("svg", {
197
+ xmlns: "http://www.w3.org/2000/svg",
198
+ width: "12",
199
+ height: "12",
200
+ viewBox: "0 0 24 24",
201
+ fill: "none",
202
+ stroke: "currentColor",
203
+ "stroke-width": "2.5",
204
+ "stroke-linecap": "round",
205
+ "stroke-linejoin": "round"
206
+ }, [
207
+ l("line", {
208
+ x1: "18",
209
+ y1: "6",
210
+ x2: "6",
211
+ y2: "18"
212
+ }),
213
+ l("line", {
214
+ x1: "6",
215
+ y1: "6",
216
+ x2: "18",
217
+ y2: "18"
218
+ })
219
+ ], -1)
220
+ ])])) : H("", !0)
221
+ ]),
222
+ U.value ? (c(), v("div", Oe, [
223
+ (c(), v(q, null, J(3, (h) => l("div", {
224
+ key: h,
225
+ class: "flex animate-pulse items-center gap-2 rounded-lg bg-gray-50 px-2 py-1.5"
226
+ }, [...n[5] || (n[5] = [
227
+ l("div", { class: "size-[30px] shrink-0 rounded-full bg-gray-200" }, null, -1),
228
+ l("div", { class: "flex flex-1 flex-col gap-1.5" }, [
229
+ l("div", { class: "h-2 w-2/3 rounded bg-gray-200" }),
230
+ l("div", { class: "h-2 w-1/3 rounded bg-gray-200" })
231
+ ], -1)
232
+ ])])), 64))
233
+ ])) : E.value.length ? (c(), v("ul", Ge, [
234
+ (c(!0), v(q, null, J(E.value, (h) => (c(), v("li", {
235
+ key: h.user_id,
236
+ class: "flex items-center gap-2 rounded-lg border border-gray-100 bg-gray-50 px-2 py-1.5 transition hover:border-sky-200 hover:bg-sky-50"
237
+ }, [
238
+ l("div", Qe, x(e(h.user_full_name)), 1),
239
+ l("div", qe, [
240
+ l("span", Xe, x(h.user_full_name), 1),
241
+ l("div", We, [
242
+ (c(!0), v(q, null, J(z(h.actions), ($) => (c(), v("span", {
243
+ key: $,
244
+ class: le(["rounded-full border px-1.5 py-px text-[10px] font-medium", D($)])
245
+ }, x(j($)), 3))), 128))
246
+ ])
247
+ ])
248
+ ]))), 128))
249
+ ])) : (c(), v("div", Pe, [
250
+ n[6] || (n[6] = ze('<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="opacity-50"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>', 1)),
251
+ l("span", He, x(_.value ? "Нічого не знайдено" : "Немає користувачів з доступом"), 1)
252
+ ])),
253
+ M.value > 1 ? (c(), v("div", Je, [
254
+ l("button", {
255
+ class: "flex size-[26px] items-center justify-center rounded-md border border-gray-200 bg-white text-gray-600 transition enabled:hover:border-blue-400 enabled:hover:bg-sky-50 enabled:hover:text-blue-600 disabled:cursor-not-allowed disabled:opacity-40",
256
+ disabled: b.value === 1,
257
+ onClick: n[1] || (n[1] = (h) => S(b.value - 1))
258
+ }, [...n[7] || (n[7] = [
259
+ l("svg", {
260
+ xmlns: "http://www.w3.org/2000/svg",
261
+ width: "14",
262
+ height: "14",
263
+ viewBox: "0 0 24 24",
264
+ fill: "none",
265
+ stroke: "currentColor",
266
+ "stroke-width": "2",
267
+ "stroke-linecap": "round",
268
+ "stroke-linejoin": "round"
269
+ }, [
270
+ l("polyline", { points: "15 18 9 12 15 6" })
271
+ ], -1)
272
+ ])], 8, Ye),
273
+ l("span", Ze, x(b.value) + " / " + x(M.value), 1),
274
+ l("button", {
275
+ class: "flex size-[26px] items-center justify-center rounded-md border border-gray-200 bg-white text-gray-600 transition enabled:hover:border-blue-400 enabled:hover:bg-sky-50 enabled:hover:text-blue-600 disabled:cursor-not-allowed disabled:opacity-40",
276
+ disabled: b.value === M.value,
277
+ onClick: n[2] || (n[2] = (h) => S(b.value + 1))
278
+ }, [...n[8] || (n[8] = [
279
+ l("svg", {
280
+ xmlns: "http://www.w3.org/2000/svg",
281
+ width: "14",
282
+ height: "14",
283
+ viewBox: "0 0 24 24",
284
+ fill: "none",
285
+ stroke: "currentColor",
286
+ "stroke-width": "2",
287
+ "stroke-linecap": "round",
288
+ "stroke-linejoin": "round"
289
+ }, [
290
+ l("polyline", { points: "9 18 15 12 9 6" })
291
+ ], -1)
292
+ ])], 8, Ke),
293
+ l("span", et, x(d.value) + " запис" + x(I.value), 1)
294
+ ])) : H("", !0)
295
+ ]));
296
+ }
297
+ });
298
+ function lt(a) {
299
+ const m = (e) => typeof e != "number" || Number.isNaN(e) ? "" : Number(e.toFixed(5)).toFixed(5), E = [
300
+ {
301
+ name: "description",
302
+ type: "textarea",
303
+ label: "Опис",
304
+ col: 12
305
+ },
306
+ {
307
+ name: "group_id",
308
+ type: "Autocomplete",
309
+ label: "Група",
310
+ data: "gis.group_list",
311
+ col: 6
312
+ },
313
+ {
314
+ name: "keywords",
315
+ type: "Tags",
316
+ label: "Ключові слова",
317
+ placeholder: "Введіть тег та натисніть Enter",
318
+ col: 12
319
+ },
320
+ {
321
+ name: "is_public",
322
+ type: "switcher",
323
+ label: "Публічність",
324
+ col: 6,
325
+ data: "yes_no"
326
+ },
327
+ {
328
+ name: "is_active",
329
+ type: "switcher",
330
+ label: "Активність",
331
+ col: 6,
332
+ data: "yes_no"
333
+ }
334
+ ], d = (e, z) => {
335
+ const L = Array.isArray(e == null ? void 0 : e.config) ? e.config[0] : null;
336
+ return a.normalizeValue(L == null ? void 0 : L[z]);
337
+ }, U = (e) => !Array.isArray(e == null ? void 0 : e.bounds) || e.bounds.length < 4 ? "" : e.bounds.map((z) => m(z)).filter(Boolean).join(", "), b = (e) => !Array.isArray(e == null ? void 0 : e.extent) || e.extent.length < 4 ? "" : e.extent.map((z) => m(z)).filter(Boolean).join(", "), _ = (e) => !Array.isArray(e == null ? void 0 : e.bands) || !e.bands.length ? "" : e.bands.join(", "), C = (e) => typeof e != "boolean" ? "" : e ? "Так" : "Ні", M = [
338
+ { label: "Група", value: (e) => a.normalizeValue((e == null ? void 0 : e.group_name) ?? a.resolvedGroupName ?? (e == null ? void 0 : e.group_id)) },
339
+ { label: "Статус", value: (e) => a.normalizeValue(a.statusLabel(e)) },
340
+ { label: "Видимість", value: (e) => a.normalizeValue(a.visibilityLabel(e)) },
341
+ { label: "Тип сервісу", value: (e) => a.normalizeValue(e == null ? void 0 : e.service_type) },
342
+ { label: "Тип джерела", value: (e) => a.normalizeValue(e == null ? void 0 : e.source_type) },
343
+ { label: "Шлях до джерела", value: (e) => a.normalizeValue(e == null ? void 0 : e.source_path) },
344
+ { label: "Тип геометрії", value: (e) => a.normalizeValue(e == null ? void 0 : e.geom_type) },
345
+ { label: "Геометрична колонка", value: (e) => a.normalizeValue(e == null ? void 0 : e.geometry_column) },
346
+ { label: "SRID", value: (e) => a.normalizeValue(e == null ? void 0 : e.srid) },
347
+ { label: "Кількість обʼєктів", value: (e) => a.normalizeValue(e == null ? void 0 : e.count) },
348
+ { label: "Створено", value: (e) => e != null && e.created_at ? a.formatDate(e.created_at) : "" },
349
+ { label: "Оновлено", value: (e) => e != null && e.updated_at ? a.formatDate(e.updated_at) : "" }
350
+ ], I = [
351
+ { label: "Ключ сервісу", value: (e) => a.normalizeValue(e == null ? void 0 : e.service_key) },
352
+ { label: "Виробник", value: (e) => a.normalizeValue((e == null ? void 0 : e.holder) ?? (e == null ? void 0 : e.producer)) },
353
+ { label: "Категорія", value: (e) => a.normalizeValue(e == null ? void 0 : e.category) },
354
+ { label: "Ліцензія", value: (e) => a.normalizeValue(e == null ? void 0 : e.license) },
355
+ { label: "Рік", value: (e) => a.normalizeValue(e == null ? void 0 : e.year) },
356
+ { label: "Ключові слова", value: (e) => a.normalizeValue(e == null ? void 0 : e.keywords) },
357
+ { label: "URL сервісу", value: (e) => a.normalizeValue(e == null ? void 0 : e.service_url) },
358
+ { label: "Metadata URL", value: (e) => a.normalizeValue(e == null ? void 0 : e.metadata_url) },
359
+ { label: "Thumbnail URL", value: (e) => a.normalizeValue(e == null ? void 0 : e.thumbnail_url) },
360
+ { label: "SQL / Query", value: (e) => a.normalizeValue(e == null ? void 0 : e.query) }
361
+ ];
362
+ return {
363
+ service: {
364
+ general: M,
365
+ meta: I,
366
+ edit: [
367
+ ...E,
368
+ { name: "service_key", type: "text", label: "Ключ сервісу", col: 6 },
369
+ { name: "producer", type: "text", label: "Виробник", col: 6 },
370
+ { name: "category", type: "text", label: "Категорія", col: 6 },
371
+ { name: "license", type: "text", label: "Ліцензія", col: 6 },
372
+ { name: "year", type: "number", label: "Рік", col: 6 },
373
+ { name: "service_url", type: "text", label: "URL сервісу", col: 12 },
374
+ { name: "metadata_url", type: "text", label: "Metadata URL", col: 12 },
375
+ { name: "thumbnail_url", type: "text", label: "Thumbnail URL", col: 12 },
376
+ { name: "query", type: "textarea", label: "SQL / Query", col: 12 }
377
+ ]
378
+ },
379
+ dataset: {
380
+ general: M,
381
+ meta: I,
382
+ edit: [
383
+ ...E,
384
+ { name: "service_key", type: "text", label: "Ключ сервісу", col: 6 },
385
+ { name: "producer", type: "text", label: "Виробник", col: 6 },
386
+ { name: "category", type: "text", label: "Категорія", col: 6 },
387
+ { name: "license", type: "text", label: "Ліцензія", col: 6 },
388
+ { name: "year", type: "number", label: "Рік", col: 6 },
389
+ { name: "service_url", type: "text", label: "URL сервісу", col: 12 },
390
+ { name: "metadata_url", type: "text", label: "Metadata URL", col: 12 },
391
+ { name: "thumbnail_url", type: "text", label: "Thumbnail URL", col: 12 },
392
+ { name: "query", type: "textarea", label: "SQL / Query", col: 12 }
393
+ ]
394
+ },
395
+ raster: {
396
+ general: [
397
+ { label: "Статус", value: (e) => a.normalizeValue(a.statusLabel(e)) },
398
+ { label: "Видимість", value: (e) => a.normalizeValue(a.visibilityLabel(e)) },
399
+ { label: "Формат", value: (e) => a.normalizeValue(e == null ? void 0 : e.extension) },
400
+ { label: "SRID", value: (e) => a.normalizeValue(e == null ? void 0 : e.srid) },
401
+ { label: "Файл джерела", value: (e) => a.normalizeValue(e == null ? void 0 : e.source_path) },
402
+ { label: "Кеш", value: (e) => C(e == null ? void 0 : e.cache) },
403
+ { label: "XML", value: (e) => C(e == null ? void 0 : e.xml) }
404
+ ],
405
+ meta: [
406
+ { label: "Bounds", value: (e) => b(e) },
407
+ { label: "Розмір", value: (e) => a.normalizeValue(e == null ? void 0 : e.total_size) },
408
+ { label: "Ширина", value: (e) => a.normalizeValue(e == null ? void 0 : e.width) },
409
+ { label: "Висота", value: (e) => a.normalizeValue(e == null ? void 0 : e.height) },
410
+ { label: "Кількість каналів", value: (e) => a.normalizeValue(e == null ? void 0 : e.bands_count) },
411
+ { label: "Канали", value: (e) => _(e) },
412
+ { label: "Роздільна здатність", value: (e) => a.normalizeValue(e == null ? void 0 : e.resolution) },
413
+ { label: "Глибина кольору", value: (e) => a.normalizeValue(e == null ? void 0 : e.color_depth) },
414
+ { label: "Стиснення", value: (e) => a.normalizeValue(e == null ? void 0 : e.compression) },
415
+ { label: "Proj4", value: (e) => a.normalizeValue(e == null ? void 0 : e.proj4) }
416
+ ],
417
+ edit: [
418
+ {
419
+ name: "description",
420
+ type: "textarea",
421
+ label: "Опис",
422
+ col: 12
423
+ },
424
+ {
425
+ name: "group_id",
426
+ type: "Autocomplete",
427
+ label: "Група",
428
+ data: "gis.group_list",
429
+ col: 6
430
+ },
431
+ {
432
+ name: "is_public",
433
+ type: "switcher",
434
+ label: "Публічність",
435
+ col: 6,
436
+ data: "yes_no"
437
+ },
438
+ {
439
+ name: "is_active",
440
+ type: "switcher",
441
+ label: "Активність",
442
+ col: 6,
443
+ data: "yes_no"
444
+ }
445
+ ]
446
+ },
447
+ css: {
448
+ general: [
449
+ { label: "Група", value: (e) => a.normalizeValue((e == null ? void 0 : e.group_name) ?? a.resolvedGroupName ?? (e == null ? void 0 : e.group_id)) },
450
+ { label: "Статус", value: (e) => a.normalizeValue(a.statusLabel(e)) },
451
+ { label: "Видимість", value: (e) => a.normalizeValue(a.visibilityLabel(e)) },
452
+ { label: "Ключ CartoCSS", value: (e) => a.normalizeValue(e == null ? void 0 : e.cartocss_key) },
453
+ { label: "Таблиця джерела", value: (e) => d(e, "table") || a.normalizeValue(e == null ? void 0 : e.source_path) },
454
+ { label: "Ключ набору", value: (e) => d(e, "key") },
455
+ { label: "Авто-картка", value: (e) => C(e == null ? void 0 : e.card_auto) },
456
+ { label: "Інфо по кліку", value: (e) => C(e == null ? void 0 : e.info) },
457
+ { label: "Статичний", value: (e) => C(e == null ? void 0 : e.is_static) }
458
+ ],
459
+ meta: [
460
+ { label: "Bounds", value: (e) => U(e) }
461
+ ],
462
+ edit: [
463
+ {
464
+ name: "description",
465
+ type: "textarea",
466
+ label: "Опис",
467
+ col: 12
468
+ },
469
+ {
470
+ name: "group_id",
471
+ type: "Autocomplete",
472
+ label: "Група",
473
+ data: "gis.group_list",
474
+ col: 6
475
+ },
476
+ {
477
+ name: "is_public",
478
+ type: "switcher",
479
+ label: "Публічність",
480
+ col: 6,
481
+ data: "yes_no"
482
+ },
483
+ {
484
+ name: "enabled",
485
+ type: "switcher",
486
+ label: "Активність",
487
+ col: 6,
488
+ data: "yes_no"
489
+ },
490
+ {
491
+ name: "is_static",
492
+ type: "switcher",
493
+ label: "Статичний",
494
+ col: 6,
495
+ data: "yes_no"
496
+ }
497
+ ]
498
+ }
499
+ };
500
+ }
501
+ const at = { class: "flex-1 overflow-y-auto p-4" }, rt = { class: "space-y-4" }, nt = { class: "border border-gray-200 rounded-lg p-4" }, ot = {
502
+ key: 0,
503
+ class: "grid grid-cols-2 gap-2"
504
+ }, st = { class: "text-xs text-gray-500 mb-1" }, it = { class: "text-sm font-semibold text-gray-900" }, ut = {
505
+ key: 1,
506
+ class: "text-sm text-gray-700 leading-relaxed"
507
+ }, ct = { class: "border border-gray-200 rounded-lg p-4" }, vt = { class: "text-sm text-gray-700 leading-relaxed" }, pt = { class: "border border-gray-200 rounded-lg p-4" }, dt = { class: "flex items-center justify-between mb-3" }, mt = { class: "text-xs text-gray-500 mb-1" }, bt = { class: "text-sm font-semibold text-gray-900" }, ft = {
508
+ key: 1,
509
+ class: "text-sm text-gray-700 leading-relaxed"
510
+ }, yt = { class: "border border-gray-200 rounded-lg p-4" }, gt = { class: "flex justify-end gap-2 px-4 py-3 border-t border-gray-100 w-full" }, ht = ["disabled"], xt = ["disabled"], P = "-", jt = /* @__PURE__ */ Y({
511
+ __name: "MetaDataTab",
512
+ props: {
513
+ data: {},
514
+ entityId: {},
515
+ entityType: {}
516
+ },
517
+ emits: ["saved", "editCssBounds"],
518
+ setup(a, { emit: k }) {
519
+ const m = ae(() => import("@opengis/core").then((t) => t.VsModal)), E = ae(() => import("@opengis/form")), d = a, U = k, b = y(null);
520
+ async function _(t) {
521
+ var r;
522
+ try {
523
+ const o = await fetch("/api/suggest/gis.group_list");
524
+ if (!o.ok) return null;
525
+ const N = (r = (await o.json()).data) == null ? void 0 : r.find((Q) => String(Q.id) === String(t));
526
+ return (N == null ? void 0 : N.text) ?? null;
527
+ } catch {
528
+ return null;
529
+ }
530
+ }
531
+ ue(
532
+ () => d.data,
533
+ async (t) => {
534
+ if (b.value = null, (t == null ? void 0 : t.group_id) != null) {
535
+ const r = await _(String(t.group_id));
536
+ b.value = r;
537
+ }
538
+ },
539
+ { immediate: !0 }
540
+ );
541
+ function C(t) {
542
+ if (!t || typeof t != "string") return P;
543
+ try {
544
+ const r = new Date(t);
545
+ return Number.isNaN(r.getTime()) ? P : r.toLocaleDateString("uk-UA", {
546
+ day: "numeric",
547
+ month: "long",
548
+ year: "numeric"
549
+ });
550
+ } catch {
551
+ return P;
552
+ }
553
+ }
554
+ function M(t) {
555
+ return typeof (t == null ? void 0 : t.is_active) == "boolean" ? t.is_active ? "Активний" : "Неактивний" : typeof (t == null ? void 0 : t.enabled) == "boolean" ? t.enabled ? "Активний" : "Неактивний" : P;
556
+ }
557
+ function I(t) {
558
+ return typeof (t == null ? void 0 : t.is_public) != "boolean" ? P : t.is_public ? "Публічний" : "Приватний";
559
+ }
560
+ function e(t) {
561
+ if (t == null) return "";
562
+ if (Array.isArray(t)) return t.filter(Boolean).join(", ");
563
+ if (typeof t == "boolean") return t ? "Так" : "Ні";
564
+ if (typeof t == "object") return "";
565
+ const r = String(t).trim();
566
+ return r === "" ? "" : r;
567
+ }
568
+ function z(t, r) {
569
+ return r.map((o) => ({ label: o.label, value: o.value(t) })).filter((o) => o.value && o.value !== P);
570
+ }
571
+ const L = g(() => z(d.data, n().general)), j = g(() => {
572
+ var r;
573
+ const t = (r = d.data) == null ? void 0 : r.description;
574
+ return t != null && t !== "" ? t : P;
575
+ }), B = g(() => z(d.data, n().meta)), D = g(() => B.value.length === 1 ? "grid-cols-1" : "grid-cols-2"), A = g(() => d.entityType === "css" || d.entityType === "raster"), S = y(!1), T = y({}), w = y(null), i = y(!1);
576
+ function n() {
577
+ const t = lt({
578
+ resolvedGroupName: b.value,
579
+ normalizeValue: e,
580
+ statusLabel: M,
581
+ visibilityLabel: I,
582
+ formatDate: C
583
+ });
584
+ return t[d.entityType || "service"] || t.service;
585
+ }
586
+ const h = g(() => n().edit);
587
+ function $() {
588
+ const t = d.data, r = {};
589
+ n().edit.forEach((o) => {
590
+ switch (o.name) {
591
+ case "group_id":
592
+ r.group_id = (t == null ? void 0 : t.group_id) != null ? String(t.group_id) : "";
593
+ break;
594
+ case "producer":
595
+ r.producer = (t == null ? void 0 : t.holder) ?? (t == null ? void 0 : t.producer) ?? "";
596
+ break;
597
+ case "keywords":
598
+ r.keywords = Array.isArray(t == null ? void 0 : t.keywords) ? [...t.keywords] : [];
599
+ break;
600
+ case "is_public":
601
+ r.is_public = (t == null ? void 0 : t.is_public) ?? !1;
602
+ break;
603
+ case "is_active":
604
+ r.is_active = typeof (t == null ? void 0 : t.is_active) == "boolean" ? t.is_active : (t == null ? void 0 : t.enabled) ?? !1;
605
+ break;
606
+ case "enabled":
607
+ r.enabled = (t == null ? void 0 : t.enabled) ?? (t == null ? void 0 : t.is_active) ?? !1;
608
+ break;
609
+ case "info":
610
+ r.info = (t == null ? void 0 : t.info) ?? !1;
611
+ break;
612
+ case "is_static":
613
+ r.is_static = (t == null ? void 0 : t.is_static) ?? !1;
614
+ break;
615
+ case "card_auto":
616
+ r.card_auto = (t == null ? void 0 : t.card_auto) ?? !1;
617
+ break;
618
+ default:
619
+ r[o.name] = (t == null ? void 0 : t[o.name]) ?? "";
620
+ break;
621
+ }
622
+ }), T.value = r, w.value = null, S.value = !0;
623
+ }
624
+ function Z() {
625
+ U("editCssBounds");
626
+ }
627
+ function K(t) {
628
+ return d.entityType === "raster" && t === "Bounds";
629
+ }
630
+ async function ee() {
631
+ var t, r;
632
+ if (!(!d.entityId || !d.entityType)) {
633
+ if (w.value) {
634
+ const o = (r = (t = w.value).validate) == null ? void 0 : r.call(t);
635
+ if (o) {
636
+ X({
637
+ type: "warning",
638
+ title: "Валідація",
639
+ message: Object.entries(o).map(([G, N]) => `${G}: ${N}`).join(`
640
+ `)
641
+ });
642
+ return;
643
+ }
644
+ }
645
+ i.value = !0;
646
+ try {
647
+ const o = new Set(h.value.map((O) => O.name)), G = Object.fromEntries(
648
+ Object.entries(T.value).filter(([O]) => o.has(O))
649
+ ), N = d.entityType === "css" ? {
650
+ url: `/api/gis-css/${encodeURIComponent(d.entityId)}`,
651
+ method: "POST"
652
+ } : {
653
+ url: `/api/gis-metadata/${encodeURIComponent(d.entityType)}/${encodeURIComponent(d.entityId)}`,
654
+ method: "POST"
655
+ }, Q = await fetch(N.url, {
656
+ method: N.method,
657
+ headers: { "Content-Type": "application/json" },
658
+ body: JSON.stringify(G)
659
+ });
660
+ if (!Q.ok) throw new Error(`Failed to save metadata: ${Q.status}`);
661
+ X({ type: "success", title: "Збережено", message: "Метадані оновлено" }), S.value = !1, U("saved");
662
+ } catch (o) {
663
+ console.error("Failed to save metadata", o), X({ type: "error", title: "Помилка", message: "Не вдалося зберегти метадані" });
664
+ } finally {
665
+ i.value = !1;
666
+ }
667
+ }
668
+ }
669
+ return (t, r) => (c(), v("div", at, [
670
+ l("div", rt, [
671
+ l("div", nt, [
672
+ l("div", { class: "flex items-center justify-between mb-3" }, [
673
+ r[5] || (r[5] = l("h2", { class: "text-xs font-semibold text-gray-500 uppercase tracking-wider" }, " Загальна інформація ", -1)),
674
+ l("button", {
675
+ type: "button",
676
+ onClick: $,
677
+ class: "inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium transition-colors bg-sky-50 text-sky-600 hover:bg-sky-100"
678
+ }, [...r[4] || (r[4] = [
679
+ l("svg", {
680
+ xmlns: "http://www.w3.org/2000/svg",
681
+ class: "h-3.5 w-3.5",
682
+ fill: "none",
683
+ viewBox: "0 0 24 24",
684
+ stroke: "currentColor",
685
+ "stroke-width": "2"
686
+ }, [
687
+ l("path", {
688
+ "stroke-linecap": "round",
689
+ "stroke-linejoin": "round",
690
+ d: "M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
691
+ })
692
+ ], -1),
693
+ be(" Редагувати ", -1)
694
+ ])])
695
+ ]),
696
+ L.value.length ? (c(), v("div", ot, [
697
+ (c(!0), v(q, null, J(L.value, (o) => (c(), v("div", {
698
+ key: o.label,
699
+ class: "bg-gray-50 rounded-md p-2 border border-gray-100"
700
+ }, [
701
+ l("p", st, x(o.label), 1),
702
+ l("p", it, x(o.value), 1)
703
+ ]))), 128))
704
+ ])) : (c(), v("p", ut, x(P)))
705
+ ]),
706
+ l("div", ct, [
707
+ r[6] || (r[6] = l("h2", { class: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3" }, " Повний опис ", -1)),
708
+ l("p", vt, x(j.value), 1)
709
+ ]),
710
+ l("div", pt, [
711
+ l("div", dt, [
712
+ r[8] || (r[8] = l("h2", { class: "text-xs font-semibold text-gray-500 uppercase tracking-wider" }, " Метадані ", -1)),
713
+ A.value ? (c(), v("button", {
714
+ key: 0,
715
+ type: "button",
716
+ class: "inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs font-medium transition-colors bg-sky-50 text-sky-600 hover:bg-sky-100",
717
+ onClick: Z
718
+ }, [...r[7] || (r[7] = [
719
+ l("svg", {
720
+ xmlns: "http://www.w3.org/2000/svg",
721
+ class: "h-3.5 w-3.5",
722
+ fill: "none",
723
+ viewBox: "0 0 24 24",
724
+ stroke: "currentColor",
725
+ "stroke-width": "2"
726
+ }, [
727
+ l("path", {
728
+ "stroke-linecap": "round",
729
+ "stroke-linejoin": "round",
730
+ d: "M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
731
+ })
732
+ ], -1),
733
+ be(" Редагувати ", -1)
734
+ ])])) : H("", !0)
735
+ ]),
736
+ B.value.length ? (c(), v("div", {
737
+ key: 0,
738
+ class: le([D.value, "grid gap-2"])
739
+ }, [
740
+ (c(!0), v(q, null, J(B.value, (o) => (c(), v("div", {
741
+ key: o.label,
742
+ class: le(["bg-gray-50 rounded-md p-2 border border-gray-100", { "col-span-2": K(o.label) }])
743
+ }, [
744
+ l("p", mt, x(o.label), 1),
745
+ l("p", bt, x(o.value), 1)
746
+ ], 2))), 128))
747
+ ], 2)) : (c(), v("p", ft, x(P)))
748
+ ]),
749
+ l("div", yt, [
750
+ r[9] || (r[9] = l("div", { class: "flex items-center justify-between mb-3" }, [
751
+ l("h2", { class: "text-xs font-semibold text-gray-500 uppercase tracking-wider" }, " Доступи ")
752
+ ], -1)),
753
+ F(tt, {
754
+ "service-id": a.entityId,
755
+ limit: 8
756
+ }, null, 8, ["service-id"])
757
+ ])
758
+ ]),
759
+ F(R(m), {
760
+ teleport: "#modal",
761
+ visible: S.value,
762
+ "onUpdate:visible": r[3] || (r[3] = (o) => S.value = o),
763
+ title: "Редагування метаданих",
764
+ size: "lg"
765
+ }, {
766
+ footer: re(() => [
767
+ l("div", gt, [
768
+ l("button", {
769
+ type: "button",
770
+ class: "px-4 py-2 rounded bg-gray-100 text-gray-700 text-sm",
771
+ disabled: i.value,
772
+ onClick: r[2] || (r[2] = (o) => S.value = !1)
773
+ }, " Скасувати ", 8, ht),
774
+ l("button", {
775
+ type: "button",
776
+ class: "px-4 py-2 rounded bg-blue-600 text-white text-sm",
777
+ disabled: i.value,
778
+ onClick: ee
779
+ }, x(i.value ? "Збереження…" : "Зберегти"), 9, xt)
780
+ ])
781
+ ]),
782
+ default: re(() => [
783
+ F(R(E), {
784
+ values: T.value,
785
+ "onUpdate:values": r[0] || (r[0] = (o) => T.value = o),
786
+ form: w.value,
787
+ "onUpdate:form": r[1] || (r[1] = (o) => w.value = o),
788
+ schema: h.value
789
+ }, null, 8, ["values", "form", "schema"])
790
+ ]),
791
+ _: 1
792
+ }, 8, ["visible"])
793
+ ]));
794
+ }
795
+ }), wt = ["href"], _t = ["href"], kt = ["href"], Ct = {
796
+ key: 0,
797
+ class: "py-6 px-4 text-sm text-gray-500"
798
+ }, zt = {
799
+ key: 1,
800
+ class: "py-6 px-4 text-sm text-red-600"
801
+ }, Vt = { class: "flex justify-end gap-2 px-4 py-3 border-t border-gray-100 w-full" }, St = ["disabled"], $t = ["disabled"], Et = 192, ge = 8, W = 8, At = /* @__PURE__ */ Y({
802
+ __name: "HeaderActions",
803
+ props: {
804
+ entityId: {},
805
+ entityInfo: {},
806
+ table: {},
807
+ formEndpoint: {},
808
+ saveEndpoint: {},
809
+ entityLabel: {},
810
+ editButtonText: {},
811
+ saveMethod: {},
812
+ showXmlItem: { type: Boolean, default: !0 },
813
+ clearTilesHandler: {}
814
+ },
815
+ emits: ["saved"],
816
+ setup(a, { emit: k }) {
817
+ const m = a, E = k, d = ae(
818
+ () => import("@opengis/core").then((s) => s.VsModal)
819
+ ), U = ae(() => import("@opengis/form")), b = y(!1), _ = y(null), C = y(null), M = y(null), I = y(null), e = g(() => I.value ? {
820
+ position: "fixed",
821
+ top: `${I.value.top}px`,
822
+ left: `${I.value.left}px`
823
+ } : {});
824
+ ue(b, (s) => {
825
+ s && Ve(ne);
826
+ });
827
+ const z = y(!1), L = y(null), j = y({}), B = y(null), D = y(""), A = y(!1), S = y(!1), T = y(null), w = g(() => m.entityId || ""), i = (s, u) => s ? typeof s == "function" ? s(u) : typeof s != "string" ? "" : s.includes(":id") ? u ? s.replace(":id", encodeURIComponent(u)) : "" : s : "", n = g(() => {
828
+ var s;
829
+ return (s = m.table) == null ? void 0 : s.trim();
830
+ }), h = g(() => {
831
+ if (m.formEndpoint) return m.formEndpoint;
832
+ if (n.value)
833
+ return (s) => `/api/form/${n.value}/${s}`;
834
+ }), $ = g(() => {
835
+ if (m.saveEndpoint) return m.saveEndpoint;
836
+ if (n.value)
837
+ return (s) => `/api/table/${s}`;
838
+ }), Z = g(
839
+ () => i(h.value, w.value)
840
+ ), K = g(() => m.saveEndpoint ? i(m.saveEndpoint, w.value) : T.value ? `/api/table/${encodeURIComponent(T.value)}` : i($.value, w.value)), ee = g(
841
+ () => i("/api/gis-clear-rtile/:id", w.value)
842
+ ), t = g(
843
+ () => i("/api/gis-xml/:id", w.value)
844
+ ), r = g(
845
+ () => i("/api/gis-pretile/:id?zoom=10&max=12", w.value)
846
+ ), o = g(() => {
847
+ var f, V, p;
848
+ const s = (V = (f = m.entityInfo) == null ? void 0 : f.name) == null ? void 0 : V.trim();
849
+ if (s) return `Редагування ${s}`;
850
+ const u = (p = m.entityLabel) == null ? void 0 : p.trim();
851
+ return u ? `Редагування ${u}` : "Редагування";
852
+ }), G = g(() => m.editButtonText || "Редагувати"), N = g(() => (m.saveMethod || "POST").toUpperCase());
853
+ function Q() {
854
+ b.value || ne(), b.value = !b.value;
855
+ }
856
+ function O() {
857
+ b.value = !1;
858
+ }
859
+ async function he() {
860
+ const s = m.clearTilesHandler;
861
+ !s || !w.value || (O(), await s(w.value));
862
+ }
863
+ function ne() {
864
+ var me;
865
+ if (typeof window > "u" || !C.value) return;
866
+ const s = C.value.getBoundingClientRect(), u = window.innerWidth, f = window.innerHeight, V = s.left, p = Math.max(
867
+ u - Et - W,
868
+ W
869
+ ), oe = Math.min(Math.max(V, W), p), se = ((me = M.value) == null ? void 0 : me.offsetHeight) ?? 0, pe = s.bottom + ge;
870
+ let de = pe;
871
+ if (se && pe + se > f - W) {
872
+ const _e = s.top - ge - se;
873
+ de = Math.max(_e, W);
874
+ }
875
+ I.value = { top: de, left: oe };
876
+ }
877
+ function ce(s) {
878
+ var f, V;
879
+ if (!_.value && !M.value) return;
880
+ const u = s.target;
881
+ u && ((f = _.value) != null && f.contains(u) || (V = M.value) != null && V.contains(u)) || (b.value = !1);
882
+ }
883
+ function te() {
884
+ b.value && ne();
885
+ }
886
+ Se(() => {
887
+ window.addEventListener("click", ce), window.addEventListener("resize", te), window.addEventListener("scroll", te, !0);
888
+ }), $e(() => {
889
+ window.removeEventListener("click", ce), window.removeEventListener("resize", te), window.removeEventListener("scroll", te, !0);
890
+ });
891
+ async function xe() {
892
+ var s, u, f;
893
+ if (!(!w.value || !Z.value)) {
894
+ O(), z.value = !0, A.value = !0, D.value = "", L.value = null, j.value = {}, T.value = null;
895
+ try {
896
+ const V = await fetch(Z.value);
897
+ if (!V.ok)
898
+ throw new Error(`Failed to load form: ${V.status}`);
899
+ const p = await V.json();
900
+ j.value = (p == null ? void 0 : p.data) || {}, L.value = (p == null ? void 0 : p.schema) || null;
901
+ const oe = typeof (p == null ? void 0 : p.token) == "string" && p.token || typeof ((s = p == null ? void 0 : p.tokens) == null ? void 0 : s.edit) == "string" && p.tokens.edit || typeof ((u = p == null ? void 0 : p.tokens) == null ? void 0 : u.edit_token) == "string" && p.tokens.edit_token || typeof ((f = p == null ? void 0 : p.data) == null ? void 0 : f.token) == "string" && p.data.token || null;
902
+ T.value = oe, B.value = null;
903
+ } catch (V) {
904
+ console.error("Failed to load edit form", V), D.value = "Не вдалося завантажити форму редагування";
905
+ } finally {
906
+ A.value = !1;
907
+ }
908
+ }
909
+ }
910
+ function ve() {
911
+ z.value = !1, L.value = null, D.value = "", T.value = null;
912
+ }
913
+ async function we() {
914
+ var s, u;
915
+ if (!(!w.value || !K.value)) {
916
+ if (B.value) {
917
+ const f = (u = (s = B.value).validate) == null ? void 0 : u.call(s);
918
+ if (f) {
919
+ X({
920
+ type: "warning",
921
+ title: "Validation",
922
+ message: Object.entries(f).map(([V, p]) => `${V}: ${p}`).join(`
923
+ `)
924
+ });
925
+ return;
926
+ }
927
+ }
928
+ S.value = !0;
929
+ try {
930
+ const f = await fetch(K.value, {
931
+ method: N.value,
932
+ headers: { "Content-Type": "application/json" },
933
+ body: JSON.stringify(j.value)
934
+ });
935
+ if (!f.ok) throw new Error(`Failed to save: ${f.status}`);
936
+ X({
937
+ type: "success",
938
+ title: "Збережено",
939
+ message: "Зміни збережено"
940
+ }), E("saved", j.value), ve();
941
+ } catch (f) {
942
+ console.error("Failed to save edit form", f), X({
943
+ type: "error",
944
+ title: "Помилка",
945
+ message: "Не вдалося зберегти зміни"
946
+ });
947
+ } finally {
948
+ S.value = !1;
949
+ }
950
+ }
951
+ }
952
+ return (s, u) => (c(), v("div", {
953
+ ref_key: "root",
954
+ ref: _,
955
+ class: "relative flex items-center"
956
+ }, [
957
+ l("button", {
958
+ ref_key: "triggerButton",
959
+ ref: C,
960
+ type: "button",
961
+ onClick: Ee(Q, ["stop"]),
962
+ class: "flex items-center justify-center w-9 h-9 hover:rounded-md hover:border hover:border-gray-200 bg-white text-gray-600 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-500",
963
+ "aria-label": "Дії"
964
+ }, [...u[3] || (u[3] = [
965
+ l("svg", {
966
+ xmlns: "http://www.w3.org/2000/svg",
967
+ class: "h-5 w-5",
968
+ fill: "none",
969
+ viewBox: "0 0 24 24",
970
+ stroke: "currentColor"
971
+ }, [
972
+ l("path", {
973
+ "stroke-linecap": "round",
974
+ "stroke-linejoin": "round",
975
+ "stroke-width": "2",
976
+ d: "M12 5.5v.01M12 12v.01M12 18.5v.01"
977
+ })
978
+ ], -1)
979
+ ])], 512),
980
+ (c(), ie(Me, { to: "body" }, [
981
+ b.value ? (c(), v("div", {
982
+ key: 0,
983
+ ref_key: "menuContainer",
984
+ ref: M,
985
+ style: Le(e.value),
986
+ class: "absolute top-0 left-0 mt-2 w-48 rounded-xl border border-gray-200 bg-white shadow-lg text-sm z-[1000]"
987
+ }, [
988
+ ee.value || a.clearTilesHandler ? (c(), v(q, { key: 0 }, [
989
+ a.clearTilesHandler ? (c(), v("button", {
990
+ key: 0,
991
+ type: "button",
992
+ class: "flex items-center gap-2 w-full px-4 py-2 text-left text-gray-700 hover:bg-slate-50 hover:rounded-t-xl",
993
+ onClick: he
994
+ }, [
995
+ F(R(fe), {
996
+ size: 16,
997
+ class: "lucide lucide-brush-cleaning text-gray-500"
998
+ }),
999
+ u[4] || (u[4] = l("span", null, "Очистити тайли", -1))
1000
+ ])) : (c(), v("a", {
1001
+ key: 1,
1002
+ href: ee.value,
1003
+ target: "_blank",
1004
+ rel: "noreferrer",
1005
+ class: "flex items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-slate-50 hover:rounded-t-xl",
1006
+ onClick: O
1007
+ }, [
1008
+ F(R(fe), {
1009
+ size: 16,
1010
+ class: "lucide lucide-brush-cleaning text-gray-500"
1011
+ }),
1012
+ u[5] || (u[5] = l("span", null, "Очистити тайли", -1))
1013
+ ], 8, wt))
1014
+ ], 64)) : H("", !0),
1015
+ a.showXmlItem ? (c(), v("a", {
1016
+ key: 1,
1017
+ href: t.value,
1018
+ target: "_blank",
1019
+ rel: "noreferrer",
1020
+ class: "flex items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-slate-50 hover:rounded-t-xl",
1021
+ onClick: O
1022
+ }, [
1023
+ F(R(ye), {
1024
+ size: 16,
1025
+ class: "lucide lucide-square-code text-gray-500"
1026
+ }),
1027
+ u[6] || (u[6] = l("span", null, "Створити XML", -1))
1028
+ ], 8, _t)) : H("", !0),
1029
+ a.showXmlItem ? (c(), v("a", {
1030
+ key: 2,
1031
+ href: r.value,
1032
+ target: "_blank",
1033
+ rel: "noreferrer",
1034
+ class: "flex items-center gap-2 px-4 py-2 text-left text-gray-700 hover:bg-slate-50 hover:rounded-t-xl",
1035
+ onClick: O
1036
+ }, [
1037
+ F(R(ye), {
1038
+ size: 16,
1039
+ class: "lucide lucide-square-code text-gray-500"
1040
+ }),
1041
+ u[7] || (u[7] = l("span", null, "Pretile", -1))
1042
+ ], 8, kt)) : H("", !0),
1043
+ l("button", {
1044
+ type: "button",
1045
+ class: "flex items-center gap-2 w-full px-4 py-2 text-left text-gray-700 hover:bg-slate-50 hover:rounded-b-xl",
1046
+ onClick: xe
1047
+ }, [
1048
+ F(R(Be), {
1049
+ size: 16,
1050
+ class: "lucide lucide-pencil text-gray-500"
1051
+ }),
1052
+ l("span", null, x(G.value), 1)
1053
+ ])
1054
+ ], 4)) : H("", !0)
1055
+ ])),
1056
+ F(R(d), {
1057
+ teleport: "#modal",
1058
+ visible: z.value,
1059
+ "onUpdate:visible": u[2] || (u[2] = (f) => z.value = f),
1060
+ title: o.value,
1061
+ size: "lg"
1062
+ }, {
1063
+ footer: re(() => [
1064
+ l("div", Vt, [
1065
+ l("button", {
1066
+ type: "button",
1067
+ class: "px-4 py-2 rounded bg-gray-100 text-gray-700",
1068
+ onClick: ve,
1069
+ disabled: S.value
1070
+ }, " Скасувати ", 8, St),
1071
+ l("button", {
1072
+ type: "button",
1073
+ class: "px-4 py-2 rounded bg-blue-600 text-white",
1074
+ onClick: we,
1075
+ disabled: S.value
1076
+ }, x(S.value ? "Зберігається…" : "Зберегти"), 9, $t)
1077
+ ])
1078
+ ]),
1079
+ default: re(() => [
1080
+ A.value ? (c(), v("div", Ct, " Завантаження форми редагування… ")) : D.value ? (c(), v("div", zt, x(D.value), 1)) : (c(), ie(R(U), {
1081
+ key: 2,
1082
+ values: j.value,
1083
+ "onUpdate:values": u[0] || (u[0] = (f) => j.value = f),
1084
+ form: B.value,
1085
+ "onUpdate:form": u[1] || (u[1] = (f) => B.value = f),
1086
+ schema: L.value
1087
+ }, null, 8, ["values", "form", "schema"]))
1088
+ ]),
1089
+ _: 1
1090
+ }, 8, ["visible", "title"])
1091
+ ], 512));
1092
+ }
1093
+ });
1094
+ export {
1095
+ At as _,
1096
+ Bt as a,
1097
+ jt as b,
1098
+ Ut as c
1099
+ };