@igea/oac_frontend 1.0.105 → 1.0.107

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@igea/oac_frontend",
3
- "version": "1.0.105",
3
+ "version": "1.0.107",
4
4
  "description": "Frontend service for the OAC project",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -43,7 +43,7 @@ module.exports = function(serviceName) {
43
43
  activeSidebarItem: null
44
44
  });
45
45
 
46
- res.render('investigation/view.twig', data.toJson());
46
+ res.render('v2/investigation/view.twig', data.toJson());
47
47
  });
48
48
 
49
49
  return router
@@ -389,6 +389,87 @@ document.addEventListener('DOMContentLoaded', () => {
389
389
  var intervalId = setInterval(() => {
390
390
  if(_this.form.shadowRoot){
391
391
  clearInterval(intervalId);
392
+ // 🔥 Fix alignment for add-property blocks
393
+ const shadow = _this.form.shadowRoot;
394
+
395
+ if (!shadow.querySelector('#oac-final-layout')) {
396
+ const style = document.createElement('style');
397
+ style.id = 'oac-final-layout';
398
+ style.textContent = `
399
+
400
+ /* ============================= */
401
+ /* Layout moderno a 3 elementi */
402
+ /* ============================= */
403
+
404
+ .property-instance {
405
+ display: flex !important;
406
+ align-items: center !important;
407
+ gap: 10px !important;
408
+ }
409
+
410
+ /* Label senza width fissa */
411
+ .property-instance label {
412
+ width: auto !important;
413
+ min-width: 220px !important;
414
+ white-space: nowrap !important;
415
+ flex-shrink: 0 !important;
416
+ }
417
+
418
+ /* Editor cresce */
419
+ .property-instance .editor {
420
+ flex: 1 1 auto !important;
421
+ }
422
+
423
+ /* 🔥 SPUNTA NON PIÙ ASSOLUTA */
424
+ .property-instance.valid::before {
425
+ position: static !important;
426
+ margin-right: 6px !important;
427
+ }
428
+
429
+ `;
430
+ shadow.appendChild(style);
431
+ }
432
+
433
+ if (!shadow.querySelector('#oac-fix-add-buttons')) {
434
+ const style = document.createElement('style');
435
+ style.id = 'oac-fix-add-buttons';
436
+ style.textContent = `
437
+
438
+ /* Sposta i blocchi add a sinistra */
439
+ shacl-property:not(:has(>.collapsible)),
440
+ shacl-property > .collapsible::part(content) {
441
+ align-items: flex-start !important;
442
+ }
443
+
444
+ /* Assicura che il + sia inline */
445
+ shacl-property .add-button {
446
+ align-self: flex-start !important;
447
+ margin-right: 0 !important;
448
+ }
449
+
450
+ `;
451
+ shadow.appendChild(style);
452
+ }
453
+
454
+
455
+ if (!shadow.querySelector('#oac-limit-editor-width')) {
456
+ const style = document.createElement('style');
457
+ style.id = 'oac-limit-editor-width';
458
+ style.textContent = `
459
+
460
+ .property-instance .editor {
461
+ flex-grow: 0 !important;
462
+ max-width: 500px !important;
463
+ width: 100% !important;
464
+ }
465
+
466
+ `;
467
+ shadow.appendChild(style);
468
+ }
469
+
470
+
471
+
472
+
392
473
  if(_this.inEditing)
393
474
  _this.inputIdentifizier();
394
475
  else
@@ -248,7 +248,7 @@ sparnatural.addEventListener("queryUpdated", (event) => {
248
248
  const queryString = sparnatural.expandSparql(event.detail.queryString);
249
249
 
250
250
  const q = event.detail.queryJson;
251
- lastLiteralPredicate = extractLiteralPredicate(q);
251
+ // lastLiteralPredicate = extractLiteralPredicate(q);
252
252
 
253
253
  yasqe.setValue(queryString);
254
254
  console.log("Sparnatural JSON query:");
@@ -112,8 +112,8 @@
112
112
  {% endif %}
113
113
 
114
114
  <div id="shacl-container"
115
- style="margin-top:10px; border:dashed 2px gray; padding:10px; border-radius:5px;">
116
- <shacl-form id="shacl-form" data-collapse="open"
115
+ style="border:dashed 2px gray; padding:10px; border-radius:5px; max-width: 60%; margin: 0 auto; margin-top:20px;">
116
+ <shacl-form shadow="false" id="shacl-form" data-collapse="open"
117
117
  data-values-namespace="indagine:"
118
118
  data-shapes-url="/backend/ontology/schema/editing"
119
119
  data-generate-node-shape-reference=""
@@ -1,52 +1,248 @@
1
1
  {% extends "/v2/layout.twig" %}
2
2
 
3
+ {# --------------------------------------------------
4
+ Forziamo modalità viewer:
5
+ - niente sidebar
6
+ - header minimale
7
+ -------------------------------------------------- #}
8
+ {% set activeMenu = null %}
9
+ {% set activeSidebar = null %}
10
+ {% set activeSidebarItem = null %}
11
+
12
+ {% block extendHead %}
13
+
14
+ {# SHACL FORM web component #}
15
+ <script src="/frontend/js/lib/shacl-form.bundle-2.0.7-11.js" type="module"></script>
16
+
17
+ {# Vue investigation (stessa usata per editing) #}
18
+ <script src="/frontend/js/app/vue-investigation.js"></script>
19
+
20
+ <style>
21
+ .viewer-container {
22
+ max-width: 1100px;
23
+ margin: 20px auto;
24
+ }
25
+
26
+ .viewer-header {
27
+ display: flex;
28
+ justify-content: space-between;
29
+ align-items: center;
30
+ margin-bottom: 10px;
31
+ }
32
+
33
+ .viewer-header h2 {
34
+ margin: 0;
35
+ }
36
+
37
+ .viewer-actions {
38
+ text-align: center;
39
+ margin-top: 20px;
40
+ }
41
+ </style>
42
+
43
+ {% endblock %}
44
+
3
45
  {% block content %}
4
46
 
5
- <div class="container my-4">
6
-
7
- <h2>Indagine</h2>
8
-
9
- <h2 class="d-flex justify-content-between align-items-center">
10
- <span>Indagine</span>
11
-
12
- <button id="btn-edit"
13
- class="btn btn-primary btn-sm">
14
- <i class="fa-solid fa-pen"></i> Modifica
15
- </button>
16
- </h2>
17
-
18
- <div id="shacl-container"
19
- style="margin-top:10px;
20
- border: solid 1px #ccc;
21
- padding:15px;
22
- border-radius:6px;">
23
-
24
- <shacl-form
25
- id="shacl-form"
26
- data-collapse="open"
27
- data-readonly="true"
28
- data-values-namespace="indagine:"
29
- data-node-iri="indagine:{{ uuid }}"
30
- data-shapes-url="/backend/ontology/schema/view"
31
- ></shacl-form>
47
+ <div class="viewer-container">
48
+
49
+
50
+
51
+ {# --------------------------------------------------
52
+ Vue root (SENZA search)
53
+ UUID passato dal controller
54
+ -------------------------------------------------- #}
55
+ <div v-cloak
56
+ id="investigation-app"
57
+ data-cur_role="{{ user.role }}"
58
+ data-uuid="{{ uuid }}"
59
+ data-form-id="{{ form_id }}"
60
+ data-editing="false"
61
+ data-show-form="true"
62
+ data-label_save_ok="{{ t('investigation.save_ok') }}"
63
+ data-label_save_err="{{ t('investigation.save_err') }}"
64
+ >
65
+
66
+ <div class="viewer-header">
67
+ {% if user.role != 3 %}
68
+ <!-- MODIFICA -->
69
+ <button v-if="!inEditingViewer"
70
+ title="{{ t('investigation.edit_item') }}"
71
+ @click="startEdit"
72
+ type="button"
73
+ class="btn btn-info">
74
+ <i class="fa-solid fa-pen-to-square"></i>
75
+ </button>
76
+
77
+ <!-- STOP EDITING -->
78
+ <button v-if="inEditingViewer"
79
+ title="{{ t('investigation.stop_edit') }}"
80
+ @click="stopEdit"
81
+ type="button"
82
+ class="btn btn-success">
83
+ <i class="fa-solid fa-circle-stop" style="color:red;"></i>
84
+ </button>
85
+
86
+ {% endif %}
87
+
88
+
89
+
90
+ </div>
91
+
92
+
93
+ <template v-if="isVisible">
94
+
95
+ {# ---------------- BUTTONS ---------------- #}
96
+ {% if user.role != 3 %}
97
+ <div class="col-12 text-center mt-4">
98
+
99
+ <button class="btn btn-secondary mx-2"
100
+ @click="download('xml')">
101
+ RDF/XML
102
+ </button>
103
+
104
+ <button class="btn btn-secondary mx-2"
105
+ @click="download('ttl')">
106
+ TURTLE
107
+ </button>
108
+
109
+ <button v-if="inEditingViewer && validForm"
110
+ :disabled="saving"
111
+ class="btn btn-primary mx-2"
112
+ @click="save(false)">
113
+ <i v-if="saving" class="fa-solid fa-spinner"></i>
114
+ <i v-else class="fa-solid fa-save"></i>
115
+ </button>
32
116
 
117
+
118
+
119
+ </div>
120
+ {% endif %}
121
+
122
+ {# ---------------- SHACL FORM ---------------- #}
123
+ <div id="shacl-container"
124
+ style="margin-top:15px;
125
+ border:dashed 2px gray;
126
+ padding:15px;
127
+ border-radius:6px;">
128
+
129
+ <shacl-form id="shacl-form"
130
+ data-collapse="open"
131
+ data-values-namespace="indagine:"
132
+ data-shapes-url="/backend/ontology/schema/editing"
133
+ data-generate-node-shape-reference=""
134
+ ></shacl-form>
135
+
136
+ </div>
137
+
138
+ {# ---------------- DEBUG OUTPUT (admin) ---------------- #}
139
+ {% if user.role in [0,1] %}
140
+ <fieldset v-if="inEditingViewer"
141
+ style="margin-top:15px;
142
+ border: solid 1px gray;
143
+ border-radius: 6px;
144
+ padding: 10px;">
145
+ <legend>
146
+ Output SHACL
147
+ [{@ validForm ? 'valido' : 'non valido' @}]
148
+ </legend>
149
+ <pre :style="outputStyle">{@ serializedForm @}</pre>
150
+ </fieldset>
151
+ {% endif %}
152
+
153
+ </template>
154
+
155
+ </div>
156
+
157
+ {# ---------------- CLOSE TAB ---------------- #}
158
+ <div class="viewer-actions">
159
+ <button class="btn btn-outline-secondary"
160
+ onclick="tryCloseViewer()">
161
+ Chiudi
162
+ </button>
163
+
164
+ <div id="close-hint"
165
+ style="display:none; margin-top:6px; color:#666; font-size:0.9em;">
166
+ Puoi chiudere questa scheda dal browser.
167
+ </div>
33
168
  </div>
34
169
 
35
170
  </div>
36
171
 
37
172
  <script>
38
- document.getElementById('btn-edit')?.addEventListener('click', function () {
39
- const form = document.getElementById('shacl-form');
40
- if (!form) return;
173
+ function tryCloseViewer() {
174
+ window.close();
175
+ setTimeout(() => {
176
+ const hint = document.getElementById('close-hint');
177
+ if (hint) hint.style.display = 'block';
178
+ }, 200);
179
+ }
41
180
 
42
- // rimuove readonly → entra in editing
43
- form.removeAttribute('data-readonly');
44
181
 
45
- // feedback UI
46
- this.disabled = true;
47
- this.innerHTML = '<i class="fa-solid fa-lock-open"></i> Modifica attiva';
48
- });
49
- </script>
182
+ async function startEditFromViewer(btn) {
183
+ if (btn) {
184
+ btn.disabled = true;
185
+ btn.classList.add('disabled');
186
+ }
50
187
 
188
+ const appEl = document.getElementById('investigation-app');
189
+ if (!appEl) return;
51
190
 
52
- {% endblock %}
191
+ const uuid = appEl.dataset.uuid;
192
+ if (!uuid) {
193
+ alert("UUID non disponibile");
194
+ if (btn) btn.disabled = false;
195
+ return;
196
+ }
197
+
198
+ try {
199
+ // 🔍 riuso search
200
+ const res = await fetch('/backend/ontology/form/search', {
201
+ method: 'POST',
202
+ headers: { 'Content-Type': 'application/json' },
203
+ body: JSON.stringify({ query: uuid, limit: 1 })
204
+ });
205
+
206
+ const response = await res.json();
207
+
208
+ if (!response.success || !response.data?.length) {
209
+ alert("Indagine non trovata");
210
+ if (btn) btn.disabled = false;
211
+ return;
212
+ }
213
+
214
+ const item = response.data[0];
215
+
216
+ // 🔐 lock
217
+ const lockResp = await fetch(
218
+ `/backend/ontology/form/lock/${item.id}/${window.CLIENT_UUID}`
219
+ ).then(r => r.json());
220
+
221
+ if (!lockResp.success) {
222
+ alert("Indagine in modifica da un altro UTENTES");
223
+ if (btn) btn.disabled = false;
224
+ return;
225
+ }
226
+
227
+ // 🔥 entra in editing
228
+ window.dispatchEvent(
229
+ new CustomEvent('edit-item', {
230
+ detail: {
231
+ id: item.id,
232
+ uuid: item.uuid
233
+ }
234
+ })
235
+ );
236
+
237
+ } catch (e) {
238
+ console.error(e);
239
+ alert("Errore durante l'attivazione della modifica");
240
+ if (btn) btn.disabled = false;
241
+ }
242
+ }
243
+
244
+
245
+
246
+ </script>
247
+
248
+ {% endblock %}
@@ -11,6 +11,7 @@
11
11
 
12
12
  <link rel="stylesheet" href="/frontend/v2/css/v2.css">
13
13
 
14
+
14
15
  <script src="/frontend/js/lib/axios.min.js"></script>
15
16
  <script src="/frontend/js/lib/vue.global.js"></script>
16
17
  <script src="/frontend/js/lib/bootstrap.bundle.min.js"></script>