@underpostnet/underpost 2.98.0 → 2.98.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.
- package/.vscode/settings.json +7 -8
- package/README.md +2 -2
- package/bin/build.js +21 -5
- package/bin/deploy.js +10 -0
- package/bin/file.js +2 -1
- package/bin/util.js +0 -17
- package/cli.md +2 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +2 -4
- package/scripts/rocky-setup.sh +12 -39
- package/src/api/document/document.service.js +1 -1
- package/src/cli/cluster.js +5 -9
- package/src/cli/repository.js +9 -9
- package/src/cli/run.js +108 -106
- package/src/client/components/core/Content.js +54 -4
- package/src/client/components/core/FullScreen.js +202 -9
- package/src/client/components/core/Panel.js +91 -22
- package/src/client/components/core/PanelForm.js +5 -2
- package/src/client/components/core/Translate.js +8 -0
- package/src/client/components/core/VanillaJs.js +80 -29
- package/src/client/services/default/default.management.js +324 -136
- package/src/index.js +58 -20
- package/src/client/components/core/ObjectLayerEngine.js +0 -1520
- package/src/client/components/core/ObjectLayerEngineModal.js +0 -1245
- package/src/client/components/core/ObjectLayerEngineViewer.js +0 -880
- package/src/server/object-layer.js +0 -335
|
@@ -52,13 +52,60 @@ const columnDefFormatter = (obj, columnDefs, customFormat) => {
|
|
|
52
52
|
|
|
53
53
|
const DefaultManagement = {
|
|
54
54
|
Tokens: {},
|
|
55
|
-
|
|
55
|
+
// Helper functions for managing serviceOptions ID filter
|
|
56
|
+
setIdFilter: function (id, itemId) {
|
|
57
|
+
if (!this.Tokens[id]) {
|
|
58
|
+
this.Tokens[id] = {};
|
|
59
|
+
}
|
|
60
|
+
if (!this.Tokens[id].serviceOptions) {
|
|
61
|
+
this.Tokens[id].serviceOptions = {};
|
|
62
|
+
}
|
|
63
|
+
if (!this.Tokens[id].serviceOptions.get) {
|
|
64
|
+
this.Tokens[id].serviceOptions.get = {};
|
|
65
|
+
}
|
|
66
|
+
this.Tokens[id].serviceOptions.get.id = itemId;
|
|
67
|
+
},
|
|
68
|
+
clearIdFilter: function (id) {
|
|
69
|
+
if (this.Tokens[id]?.serviceOptions?.get?.id) {
|
|
70
|
+
delete this.Tokens[id].serviceOptions.get.id;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
getIdFilter: function (id) {
|
|
74
|
+
return this.Tokens[id]?.serviceOptions?.get?.id ?? undefined;
|
|
75
|
+
},
|
|
76
|
+
waitGridReady: function (id) {
|
|
77
|
+
return new Promise((resolve) => {
|
|
78
|
+
if (this.Tokens[id]?.gridApi) {
|
|
79
|
+
return resolve(this.Tokens[id].gridApi);
|
|
80
|
+
}
|
|
81
|
+
if (!this.Tokens[id].readyGridEvent) this.Tokens[id].readyGridEvent = {};
|
|
82
|
+
this.Tokens[id].readyGridEvent['waitGridReady'] = (params) => {
|
|
83
|
+
delete this.Tokens[id].readyGridEvent['waitGridReady'];
|
|
84
|
+
resolve(params.api);
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
runIsolated: async function (id, callback) {
|
|
89
|
+
if (!this.Tokens[id]) return await callback();
|
|
90
|
+
this.Tokens[id].isProcessingQueryChange = true;
|
|
56
91
|
try {
|
|
92
|
+
return await callback();
|
|
93
|
+
} finally {
|
|
94
|
+
this.Tokens[id].isProcessingQueryChange = false;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
loadTable: async function (id, options = {}) {
|
|
98
|
+
options = { reload: true, force: true, createHistory: false, skipUrlUpdate: false, ...options };
|
|
99
|
+
try {
|
|
100
|
+
if (!this.Tokens[id]) {
|
|
101
|
+
logger.warn(`DefaultManagement loadTable - Token not found for id: ${id}`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
57
104
|
const { serviceId, columnDefs, customFormat, gridId } = this.Tokens[id];
|
|
58
105
|
|
|
59
106
|
let _page = this.Tokens[id].page;
|
|
60
107
|
let _limit = this.Tokens[id].limit;
|
|
61
|
-
let _id = this.
|
|
108
|
+
let _id = this.getIdFilter(id);
|
|
62
109
|
|
|
63
110
|
let filterModel = this.Tokens[id].filterModel || {};
|
|
64
111
|
let sortModel = this.Tokens[id].sortModel || [];
|
|
@@ -84,15 +131,14 @@ const DefaultManagement = {
|
|
|
84
131
|
// Use pushState (createHistory) for filter/sort changes to enable browser back/forward
|
|
85
132
|
// Skip URL update when handling browser navigation to avoid interfering with history
|
|
86
133
|
if (!options.skipUrlUpdate) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
);
|
|
134
|
+
const urlParams = {
|
|
135
|
+
page: _page,
|
|
136
|
+
limit: _limit,
|
|
137
|
+
filterModel: filterModelStr,
|
|
138
|
+
sortModel: sortModelStr,
|
|
139
|
+
id: _id ? _id : '',
|
|
140
|
+
};
|
|
141
|
+
setQueryParams(urlParams, { replace: !options.createHistory });
|
|
96
142
|
}
|
|
97
143
|
|
|
98
144
|
if (!options.force && this.Tokens[id].lastOptions) {
|
|
@@ -143,14 +189,34 @@ const DefaultManagement = {
|
|
|
143
189
|
}
|
|
144
190
|
|
|
145
191
|
logger.info(`Loading table ${serviceId}`, {
|
|
192
|
+
id,
|
|
193
|
+
idFilter: _id,
|
|
146
194
|
page: _page,
|
|
147
195
|
limit: _limit,
|
|
148
196
|
hasFilters: Object.keys(filterModel).length > 0,
|
|
149
197
|
});
|
|
150
198
|
|
|
199
|
+
if (!this.Tokens[id] || !this.Tokens[id].ServiceProvider) {
|
|
200
|
+
logger.warn(`DefaultManagement loadTable ${serviceId} - ServiceProvider not found for token ${id}`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
151
204
|
const result = await this.Tokens[id].ServiceProvider.get(queryOptions);
|
|
152
205
|
if (result.status === 'success') {
|
|
153
|
-
|
|
206
|
+
let data, total, page, totalPages;
|
|
207
|
+
|
|
208
|
+
// Handle both single object (when querying by ID) and paginated array responses
|
|
209
|
+
if (queryOptions.id && result.data && !Array.isArray(result.data.data)) {
|
|
210
|
+
// Single object response when filtering by ID
|
|
211
|
+
data = [result.data];
|
|
212
|
+
total = 1;
|
|
213
|
+
page = 1;
|
|
214
|
+
totalPages = 1;
|
|
215
|
+
} else {
|
|
216
|
+
// Paginated array response
|
|
217
|
+
({ data = [], total = 0, page = 1, totalPages = 1 } = result.data || {});
|
|
218
|
+
}
|
|
219
|
+
|
|
154
220
|
this.Tokens[id].total = total;
|
|
155
221
|
this.Tokens[id].page = page;
|
|
156
222
|
this.Tokens[id].totalPages = totalPages;
|
|
@@ -176,6 +242,8 @@ const DefaultManagement = {
|
|
|
176
242
|
for (const event of Object.keys(DefaultManagement.Tokens[id].readyRowDataEvent))
|
|
177
243
|
await DefaultManagement.Tokens[id].readyRowDataEvent[event](rowDataScope);
|
|
178
244
|
}, 1);
|
|
245
|
+
// Update clear filter button visibility
|
|
246
|
+
this.updateClearFilterButtonVisibility(id);
|
|
179
247
|
} else {
|
|
180
248
|
logger.error(`Failed to load table ${serviceId}:`, result);
|
|
181
249
|
}
|
|
@@ -184,6 +252,27 @@ const DefaultManagement = {
|
|
|
184
252
|
throw error;
|
|
185
253
|
}
|
|
186
254
|
},
|
|
255
|
+
hasActiveFilters: function (id) {
|
|
256
|
+
const gridId = this.Tokens[id]?.gridId;
|
|
257
|
+
if (!gridId) return false;
|
|
258
|
+
|
|
259
|
+
const gridApi = AgGrid.grids[gridId];
|
|
260
|
+
const filterModel = gridApi ? gridApi.getFilterModel() : {};
|
|
261
|
+
const idFilter = this.getIdFilter(id);
|
|
262
|
+
const sortModel = this.Tokens[id]?.sortModel || [];
|
|
263
|
+
|
|
264
|
+
return Object.keys(filterModel).length > 0 || !!idFilter || sortModel.length > 0;
|
|
265
|
+
},
|
|
266
|
+
updateClearFilterButtonVisibility: function (id) {
|
|
267
|
+
const clearFilterBtn = s(`.management-table-btn-clear-filter-${id}`);
|
|
268
|
+
if (!clearFilterBtn) return;
|
|
269
|
+
|
|
270
|
+
if (this.hasActiveFilters(id)) {
|
|
271
|
+
clearFilterBtn.classList.remove('hide');
|
|
272
|
+
} else {
|
|
273
|
+
clearFilterBtn.classList.add('hide');
|
|
274
|
+
}
|
|
275
|
+
},
|
|
187
276
|
refreshTable: async function (id) {
|
|
188
277
|
const gridApi = AgGrid.grids[this.Tokens[id].gridId];
|
|
189
278
|
if (gridApi) {
|
|
@@ -207,6 +296,7 @@ const DefaultManagement = {
|
|
|
207
296
|
const page = parseInt(queryParams.page) || 1;
|
|
208
297
|
const defaultLimit = paginationOptions?.limitOptions?.[0] || 10;
|
|
209
298
|
const limit = parseInt(queryParams.limit) || defaultLimit;
|
|
299
|
+
const urlId = queryParams.id || undefined;
|
|
210
300
|
|
|
211
301
|
let filterModel = {};
|
|
212
302
|
let sortModel = [];
|
|
@@ -275,10 +365,102 @@ const DefaultManagement = {
|
|
|
275
365
|
return enhancedCol;
|
|
276
366
|
});
|
|
277
367
|
|
|
368
|
+
class RemoveActionGridRenderer {
|
|
369
|
+
eGui;
|
|
370
|
+
tokens;
|
|
371
|
+
|
|
372
|
+
async init(params) {
|
|
373
|
+
this.eGui = document.createElement('div');
|
|
374
|
+
this.tokens = {};
|
|
375
|
+
const { rowIndex } = params;
|
|
376
|
+
const { createdAt, updatedAt } = params.data;
|
|
377
|
+
|
|
378
|
+
const cellRenderId = getId(this.tokens, `${serviceId}-`);
|
|
379
|
+
this.tokens[cellRenderId] = {};
|
|
380
|
+
|
|
381
|
+
this.eGui.innerHTML = html` ${await BtnIcon.Render({
|
|
382
|
+
label: html`<div class="abs center">
|
|
383
|
+
<i class="fas fa-times"></i>
|
|
384
|
+
</div> `,
|
|
385
|
+
class: `in fll section-mp management-table-btn-mini management-table-btn-remove-${id}-${cellRenderId} ${
|
|
386
|
+
!params.data._id ? 'hide' : ''
|
|
387
|
+
}`,
|
|
388
|
+
})}`;
|
|
389
|
+
setTimeout(() => {
|
|
390
|
+
EventsUI.onClick(
|
|
391
|
+
`.management-table-btn-remove-${id}-${cellRenderId}`,
|
|
392
|
+
async () => {
|
|
393
|
+
const confirmResult = await Modal.RenderConfirm({
|
|
394
|
+
html: async () => {
|
|
395
|
+
return html`
|
|
396
|
+
<div class="in section-mp" style="text-align: center">
|
|
397
|
+
${Translate.Render('confirm-delete-item')}
|
|
398
|
+
${Object.keys(params.data).length > 0
|
|
399
|
+
? html`<br />
|
|
400
|
+
"${options.defaultColKeyFocus
|
|
401
|
+
? getValueFromJoinString(params.data, options.defaultColKeyFocus)
|
|
402
|
+
: params.data[Object.keys(params.data)[0]]}"`
|
|
403
|
+
: ''}
|
|
404
|
+
</div>
|
|
405
|
+
`;
|
|
406
|
+
},
|
|
407
|
+
id: `delete-${params.data._id}`,
|
|
408
|
+
});
|
|
409
|
+
if (confirmResult.status !== 'confirm') return;
|
|
410
|
+
let result;
|
|
411
|
+
if (params.data._id) result = await ServiceProvider.delete({ id: params.data._id });
|
|
412
|
+
else result = { status: 'success' };
|
|
413
|
+
|
|
414
|
+
NotificationManager.Push({
|
|
415
|
+
html: result.status === 'error' ? result.message : Translate.Render('item-success-delete'),
|
|
416
|
+
status: result.status,
|
|
417
|
+
});
|
|
418
|
+
if (result.status === 'success') {
|
|
419
|
+
AgGrid.grids[gridId].applyTransaction({ remove: [params.data] });
|
|
420
|
+
const token = DefaultManagement.Tokens[id];
|
|
421
|
+
// if we are on the last page and we delete the last item, go to the previous page
|
|
422
|
+
const newTotal = token.total - 1;
|
|
423
|
+
const newTotalPages = Math.ceil(newTotal / token.limit);
|
|
424
|
+
if (token.page > newTotalPages && newTotalPages > 0) {
|
|
425
|
+
token.page = newTotalPages;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// reload the current page
|
|
429
|
+
await DefaultManagement.loadTable(id, { reload: false });
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
{ context: 'modal' },
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
getGui() {
|
|
438
|
+
return this.eGui;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
refresh(params) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const finalColumnDefs = (enhancedColumnDefs || []).concat(
|
|
447
|
+
permissions.remove
|
|
448
|
+
? [
|
|
449
|
+
{
|
|
450
|
+
field: 'remove-action',
|
|
451
|
+
headerName: '',
|
|
452
|
+
width: 100,
|
|
453
|
+
cellRenderer: RemoveActionGridRenderer,
|
|
454
|
+
editable: false,
|
|
455
|
+
},
|
|
456
|
+
]
|
|
457
|
+
: [],
|
|
458
|
+
);
|
|
459
|
+
|
|
278
460
|
this.Tokens[id] = {
|
|
279
461
|
...this.Tokens[id],
|
|
280
462
|
...options,
|
|
281
|
-
columnDefs:
|
|
463
|
+
columnDefs: finalColumnDefs, // Use enhanced definitions including actions
|
|
282
464
|
gridId,
|
|
283
465
|
page,
|
|
284
466
|
limit,
|
|
@@ -290,107 +472,22 @@ const DefaultManagement = {
|
|
|
290
472
|
isProcessingQueryChange: false, // Flag to prevent listener recursion
|
|
291
473
|
};
|
|
292
474
|
|
|
475
|
+
// Initialize ID filter from query params if present
|
|
476
|
+
if (urlId) {
|
|
477
|
+
this.setIdFilter(id, urlId);
|
|
478
|
+
}
|
|
479
|
+
|
|
293
480
|
setQueryParams({
|
|
294
481
|
page,
|
|
295
482
|
limit,
|
|
483
|
+
id: urlId ? urlId : '',
|
|
296
484
|
filterModel: Object.keys(filterModel).length > 0 ? JSON.stringify(filterModel) : null,
|
|
297
485
|
sortModel: sortModel.length > 0 ? JSON.stringify(sortModel) : null,
|
|
298
486
|
});
|
|
487
|
+
|
|
299
488
|
setTimeout(async () => {
|
|
300
489
|
// https://www.ag-grid.com/javascript-data-grid/data-update-transactions/
|
|
301
490
|
|
|
302
|
-
class RemoveActionGridRenderer {
|
|
303
|
-
eGui;
|
|
304
|
-
tokens;
|
|
305
|
-
|
|
306
|
-
async init(params) {
|
|
307
|
-
this.eGui = document.createElement('div');
|
|
308
|
-
this.tokens = {};
|
|
309
|
-
const { rowIndex } = params;
|
|
310
|
-
const { createdAt, updatedAt } = params.data;
|
|
311
|
-
|
|
312
|
-
const cellRenderId = getId(this.tokens, `${serviceId}-`);
|
|
313
|
-
this.tokens[cellRenderId] = {};
|
|
314
|
-
|
|
315
|
-
this.eGui.innerHTML = html` ${await BtnIcon.Render({
|
|
316
|
-
label: html`<div class="abs center">
|
|
317
|
-
<i class="fas fa-times"></i>
|
|
318
|
-
</div> `,
|
|
319
|
-
class: `in fll section-mp management-table-btn-mini management-table-btn-remove-${id}-${cellRenderId} ${!params.data._id ? 'hide' : ''}`,
|
|
320
|
-
})}`;
|
|
321
|
-
setTimeout(() => {
|
|
322
|
-
EventsUI.onClick(
|
|
323
|
-
`.management-table-btn-remove-${id}-${cellRenderId}`,
|
|
324
|
-
async () => {
|
|
325
|
-
const confirmResult = await Modal.RenderConfirm({
|
|
326
|
-
html: async () => {
|
|
327
|
-
return html`
|
|
328
|
-
<div class="in section-mp" style="text-align: center">
|
|
329
|
-
${Translate.Render('confirm-delete-item')}
|
|
330
|
-
${Object.keys(params.data).length > 0
|
|
331
|
-
? html`<br />
|
|
332
|
-
"${options.defaultColKeyFocus
|
|
333
|
-
? getValueFromJoinString(params.data, options.defaultColKeyFocus)
|
|
334
|
-
: params.data[Object.keys(params.data)[0]]}"`
|
|
335
|
-
: ''}
|
|
336
|
-
</div>
|
|
337
|
-
`;
|
|
338
|
-
},
|
|
339
|
-
id: `delete-${params.data._id}`,
|
|
340
|
-
});
|
|
341
|
-
if (confirmResult.status !== 'confirm') return;
|
|
342
|
-
let result;
|
|
343
|
-
if (params.data._id) result = await ServiceProvider.delete({ id: params.data._id });
|
|
344
|
-
else result = { status: 'success' };
|
|
345
|
-
|
|
346
|
-
NotificationManager.Push({
|
|
347
|
-
html: result.status === 'error' ? result.message : Translate.Render('item-success-delete'),
|
|
348
|
-
status: result.status,
|
|
349
|
-
});
|
|
350
|
-
if (result.status === 'success') {
|
|
351
|
-
AgGrid.grids[gridId].applyTransaction({ remove: [params.data] });
|
|
352
|
-
const token = DefaultManagement.Tokens[id];
|
|
353
|
-
// if we are on the last page and we delete the last item, go to the previous page
|
|
354
|
-
const newTotal = token.total - 1;
|
|
355
|
-
const newTotalPages = Math.ceil(newTotal / token.limit);
|
|
356
|
-
if (token.page > newTotalPages && newTotalPages > 0) {
|
|
357
|
-
token.page = newTotalPages;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// reload the current page
|
|
361
|
-
await DefaultManagement.loadTable(id, { reload: false });
|
|
362
|
-
}
|
|
363
|
-
},
|
|
364
|
-
{ context: 'modal' },
|
|
365
|
-
);
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
getGui() {
|
|
370
|
-
return this.eGui;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
refresh(params) {
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
AgGrid.grids[gridId].setGridOption(
|
|
379
|
-
'columnDefs',
|
|
380
|
-
enhancedColumnDefs.concat(
|
|
381
|
-
permissions.remove
|
|
382
|
-
? [
|
|
383
|
-
{
|
|
384
|
-
field: 'remove-action',
|
|
385
|
-
headerName: '',
|
|
386
|
-
width: 100,
|
|
387
|
-
cellRenderer: RemoveActionGridRenderer,
|
|
388
|
-
editable: false,
|
|
389
|
-
},
|
|
390
|
-
]
|
|
391
|
-
: [],
|
|
392
|
-
),
|
|
393
|
-
);
|
|
394
491
|
// Initial loadTable is now called in onGridReady after grid is fully initialized
|
|
395
492
|
// {
|
|
396
493
|
// const result = await ServiceProvider.get();
|
|
@@ -536,9 +633,21 @@ const DefaultManagement = {
|
|
|
536
633
|
const newLimit = parseInt(queryParams.limit, 10) || this.Tokens[id].limit || 10;
|
|
537
634
|
const newFilterModel = queryParams.filterModel;
|
|
538
635
|
const newSortModel = queryParams.sortModel;
|
|
636
|
+
const newId = queryParams.id || undefined;
|
|
539
637
|
|
|
540
638
|
let shouldReload = false;
|
|
541
639
|
|
|
640
|
+
// Check if id parameter changed
|
|
641
|
+
const currentId = this.getIdFilter(id);
|
|
642
|
+
if (newId !== currentId) {
|
|
643
|
+
if (newId) {
|
|
644
|
+
this.setIdFilter(id, newId);
|
|
645
|
+
} else {
|
|
646
|
+
this.clearIdFilter(id);
|
|
647
|
+
}
|
|
648
|
+
shouldReload = true;
|
|
649
|
+
}
|
|
650
|
+
|
|
542
651
|
// Check if page or limit changed
|
|
543
652
|
if (newPage !== this.Tokens[id].page || newLimit !== this.Tokens[id].limit) {
|
|
544
653
|
this.Tokens[id].page = newPage;
|
|
@@ -626,6 +735,47 @@ const DefaultManagement = {
|
|
|
626
735
|
},
|
|
627
736
|
});
|
|
628
737
|
|
|
738
|
+
EventsUI.onClick(`.management-table-btn-clear-filter-${id}`, async () => {
|
|
739
|
+
try {
|
|
740
|
+
const gridApi = AgGrid.grids[gridId];
|
|
741
|
+
|
|
742
|
+
// Clear all filters
|
|
743
|
+
DefaultManagement.clearIdFilter(id);
|
|
744
|
+
if (gridApi) {
|
|
745
|
+
gridApi.setFilterModel({});
|
|
746
|
+
gridApi.applyColumnState({ defaultState: { sort: null } });
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// Clear token state
|
|
750
|
+
if (DefaultManagement.Tokens[id]) {
|
|
751
|
+
DefaultManagement.Tokens[id].filterModel = {};
|
|
752
|
+
DefaultManagement.Tokens[id].sortModel = [];
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Update URL - keep only page and limit
|
|
756
|
+
const queryParams = getQueryParams();
|
|
757
|
+
setQueryParams({
|
|
758
|
+
page: queryParams.page || 1,
|
|
759
|
+
limit: queryParams.limit || DefaultManagement.Tokens[id]?.limit || 10,
|
|
760
|
+
filterModel: null,
|
|
761
|
+
sortModel: null,
|
|
762
|
+
id: null,
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
// Reload table
|
|
766
|
+
await DefaultManagement.loadTable(id, { force: true, reload: true });
|
|
767
|
+
|
|
768
|
+
NotificationManager.Push({
|
|
769
|
+
html: Translate.Render('success-clear-filter') || 'Filters cleared',
|
|
770
|
+
status: 'success',
|
|
771
|
+
});
|
|
772
|
+
} catch (error) {
|
|
773
|
+
NotificationManager.Push({
|
|
774
|
+
html: error.message || 'Error clearing filters',
|
|
775
|
+
status: 'error',
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
});
|
|
629
779
|
EventsUI.onClick(`.management-table-btn-reload-${id}`, async () => {
|
|
630
780
|
try {
|
|
631
781
|
// Reload data from server
|
|
@@ -663,6 +813,7 @@ const DefaultManagement = {
|
|
|
663
813
|
const queryParams = getQueryParams();
|
|
664
814
|
const page = parseInt(queryParams.page) || 1;
|
|
665
815
|
const limit = parseInt(queryParams.limit) || 10;
|
|
816
|
+
const urlId = queryParams.id || undefined;
|
|
666
817
|
let filterModel = {};
|
|
667
818
|
let sortModel = [];
|
|
668
819
|
try {
|
|
@@ -671,17 +822,27 @@ const DefaultManagement = {
|
|
|
671
822
|
} catch (e) {}
|
|
672
823
|
|
|
673
824
|
const token = DefaultManagement.Tokens[id];
|
|
825
|
+
|
|
674
826
|
if (!token) {
|
|
675
827
|
// Token doesn't exist yet, table hasn't been initialized
|
|
676
828
|
return;
|
|
677
829
|
}
|
|
678
830
|
|
|
679
831
|
// Check if state in URL is different from current state
|
|
832
|
+
const currentId = DefaultManagement.getIdFilter(id);
|
|
833
|
+
const isIdChanged = currentId !== urlId;
|
|
680
834
|
const isPaginationChanged = token.page !== page || token.limit !== limit;
|
|
681
835
|
const isFilterChanged = JSON.stringify(token.filterModel || {}) !== JSON.stringify(filterModel);
|
|
682
836
|
const isSortChanged = JSON.stringify(token.sortModel || []) !== JSON.stringify(sortModel);
|
|
683
837
|
|
|
684
|
-
if (isPaginationChanged || isFilterChanged || isSortChanged) {
|
|
838
|
+
if (isPaginationChanged || isFilterChanged || isSortChanged || isIdChanged) {
|
|
839
|
+
// Update ID filter from query params
|
|
840
|
+
if (urlId) {
|
|
841
|
+
DefaultManagement.setIdFilter(id, urlId);
|
|
842
|
+
} else {
|
|
843
|
+
DefaultManagement.clearIdFilter(id);
|
|
844
|
+
}
|
|
845
|
+
|
|
685
846
|
token.page = page;
|
|
686
847
|
token.limit = limit;
|
|
687
848
|
token.filterModel = filterModel;
|
|
@@ -709,8 +870,8 @@ const DefaultManagement = {
|
|
|
709
870
|
console.warn('Failed to apply column state:', e);
|
|
710
871
|
}
|
|
711
872
|
}
|
|
712
|
-
// If
|
|
713
|
-
if (isPaginationChanged && !isFilterChanged && !isSortChanged) {
|
|
873
|
+
// If pagination or ID changed, and no grid-level filter/sort changed, we must load manually
|
|
874
|
+
if ((isPaginationChanged || isIdChanged) && !isFilterChanged && !isSortChanged) {
|
|
714
875
|
await DefaultManagement.loadTable(id);
|
|
715
876
|
}
|
|
716
877
|
} else if (!gridApi) {
|
|
@@ -746,6 +907,15 @@ const DefaultManagement = {
|
|
|
746
907
|
label: html`<div class="abs center btn-clean-${id}-label"><i class="fas fa-broom"></i></div> `,
|
|
747
908
|
type: 'button',
|
|
748
909
|
})}
|
|
910
|
+
${await BtnIcon.Render({
|
|
911
|
+
class: `in fll section-mp management-table-btn-mini management-table-btn-clear-filter-${id} ${
|
|
912
|
+
Object.keys(filterModel).length > 0 || sortModel.length > 0 || urlId ? '' : 'hide'
|
|
913
|
+
}`,
|
|
914
|
+
label: html`<div class="abs center btn-clear-filter-${id}-label">
|
|
915
|
+
<i class="fa-solid fa-filter-circle-xmark"></i>
|
|
916
|
+
</div> `,
|
|
917
|
+
type: 'button',
|
|
918
|
+
})}
|
|
749
919
|
${await BtnIcon.Render({
|
|
750
920
|
class: `in fll section-mp management-table-btn-mini management-table-btn-reload-${id} ${
|
|
751
921
|
permissions.reload ? '' : 'hide'
|
|
@@ -760,9 +930,21 @@ const DefaultManagement = {
|
|
|
760
930
|
parentModal: options.idModal,
|
|
761
931
|
usePagination: true,
|
|
762
932
|
paginationOptions,
|
|
763
|
-
customHeightOffset:
|
|
764
|
-
|
|
933
|
+
customHeightOffset:
|
|
934
|
+
options.customHeightOffset !== undefined
|
|
935
|
+
? options.customHeightOffset
|
|
936
|
+
: !permissions.add && !permissions.remove && !permissions.reload
|
|
937
|
+
? 50
|
|
938
|
+
: 0,
|
|
939
|
+
darkTheme: typeof darkTheme !== 'undefined' ? darkTheme : false,
|
|
765
940
|
gridOptions: {
|
|
941
|
+
columnDefs: finalColumnDefs,
|
|
942
|
+
getRowClass: (params) => {
|
|
943
|
+
const idFilter = DefaultManagement.getIdFilter(id);
|
|
944
|
+
if (idFilter && params.data && params.data._id === idFilter) {
|
|
945
|
+
return 'row-new-highlight';
|
|
946
|
+
}
|
|
947
|
+
},
|
|
766
948
|
defaultColDef: {
|
|
767
949
|
flex: 1,
|
|
768
950
|
editable: true,
|
|
@@ -771,8 +953,16 @@ const DefaultManagement = {
|
|
|
771
953
|
filter: true,
|
|
772
954
|
autoHeight: true,
|
|
773
955
|
},
|
|
774
|
-
onGridReady: (params) => {
|
|
956
|
+
onGridReady: async (params) => {
|
|
775
957
|
this.Tokens[id].gridApi = params.api;
|
|
958
|
+
|
|
959
|
+
if (this.Tokens[id].readyGridEvent) {
|
|
960
|
+
for (const key of Object.keys(this.Tokens[id].readyGridEvent)) {
|
|
961
|
+
await this.Tokens[id].readyGridEvent[key](params);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
params.api.setGridOption('columnDefs', finalColumnDefs);
|
|
776
966
|
// Apply initial state from URL
|
|
777
967
|
const { filterModel, sortModel } = this.Tokens[id];
|
|
778
968
|
if (filterModel && Object.keys(filterModel).length > 0) {
|
|
@@ -798,6 +988,10 @@ const DefaultManagement = {
|
|
|
798
988
|
if (this.Tokens[id].isProcessingQueryChange) return;
|
|
799
989
|
// Reset to page 1 on filter change
|
|
800
990
|
this.Tokens[id].page = 1;
|
|
991
|
+
|
|
992
|
+
// Update clear filter button visibility
|
|
993
|
+
DefaultManagement.updateClearFilterButtonVisibility(id);
|
|
994
|
+
|
|
801
995
|
// Create history entry for filter changes
|
|
802
996
|
DefaultManagement.loadTable(id, { reload: true, force: true, createHistory: true });
|
|
803
997
|
},
|
|
@@ -806,6 +1000,8 @@ const DefaultManagement = {
|
|
|
806
1000
|
if (this.Tokens[id].isInitializing) return;
|
|
807
1001
|
// Skip if we're processing a query change from browser navigation
|
|
808
1002
|
if (this.Tokens[id].isProcessingQueryChange) return;
|
|
1003
|
+
// Update clear filter button visibility
|
|
1004
|
+
DefaultManagement.updateClearFilterButtonVisibility(id);
|
|
809
1005
|
// Create history entry for sort changes
|
|
810
1006
|
DefaultManagement.loadTable(id, { reload: true, force: true, createHistory: true });
|
|
811
1007
|
},
|
|
@@ -881,33 +1077,25 @@ const DefaultManagement = {
|
|
|
881
1077
|
status: result.status,
|
|
882
1078
|
});
|
|
883
1079
|
if (result.status === 'success') {
|
|
1080
|
+
// Filter by the newly created row's ID
|
|
1081
|
+
const newItemId = result.data._id;
|
|
1082
|
+
|
|
1083
|
+
// Update UI buttons first
|
|
1084
|
+
s(`.management-table-btn-save-${id}`).classList.add('hide');
|
|
1085
|
+
if (permissions.add) s(`.management-table-btn-add-${id}`).classList.remove('hide');
|
|
1086
|
+
if (permissions.remove) s(`.management-table-btn-clean-${id}`).classList.remove('hide');
|
|
1087
|
+
if (permissions.reload) s(`.management-table-btn-reload-${id}`).classList.remove('hide');
|
|
1088
|
+
|
|
1089
|
+
// Stop editing to avoid triggering other events
|
|
1090
|
+
AgGrid.grids[gridId].stopEditing();
|
|
1091
|
+
|
|
1092
|
+
// Set ID filter and reload
|
|
884
1093
|
this.Tokens[id].page = 1;
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
setQueryParams({ page: 1, limit: this.Tokens[id].limit });
|
|
890
|
-
|
|
891
|
-
let rowNode;
|
|
892
|
-
AgGrid.grids[gridId].forEachLeafNode((_rowNode) => {
|
|
893
|
-
if (_rowNode.data._id === result.data._id) {
|
|
894
|
-
rowNode = _rowNode;
|
|
895
|
-
}
|
|
1094
|
+
this.setIdFilter(id, newItemId);
|
|
1095
|
+
|
|
1096
|
+
setTimeout(async () => {
|
|
1097
|
+
await DefaultManagement.loadTable(id, { force: true, createHistory: true });
|
|
896
1098
|
});
|
|
897
|
-
if (rowNode) {
|
|
898
|
-
const newRow = columnDefFormatter(result.data, columnDefs, options.customFormat);
|
|
899
|
-
// Add a temporary flag to the new row data.
|
|
900
|
-
newRow._new = true;
|
|
901
|
-
// Update the row data with the data from the server, which includes the new permanent `_id`.
|
|
902
|
-
rowNode.setData(newRow);
|
|
903
|
-
// The `rowClassRules` will automatically apply the 'row-new-highlight' class.
|
|
904
|
-
// Now, remove the flag after a delay to remove the highlight.
|
|
905
|
-
// setTimeout(() => {
|
|
906
|
-
// delete newRow._new;
|
|
907
|
-
// rowNode.setData(newRow);
|
|
908
|
-
// }, 2000);
|
|
909
|
-
}
|
|
910
|
-
s(`.management-table-btn-save-${id}`).click();
|
|
911
1099
|
}
|
|
912
1100
|
} else {
|
|
913
1101
|
// Skip update here - onCellValueChanged already handles auto-save for existing rows
|