underpost 2.8.1 → 2.8.6

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 (108) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/ghpkg.yml +19 -49
  3. package/.github/workflows/npmpkg.yml +67 -0
  4. package/.github/workflows/publish.yml +5 -5
  5. package/.github/workflows/pwa-microservices-template.page.yml +12 -4
  6. package/.github/workflows/pwa-microservices-template.test.yml +2 -2
  7. package/.vscode/extensions.json +17 -71
  8. package/.vscode/settings.json +18 -3
  9. package/AUTHORS.md +16 -5
  10. package/CHANGELOG.md +103 -3
  11. package/Dockerfile +24 -66
  12. package/README.md +1 -28
  13. package/bin/build.js +186 -0
  14. package/bin/db.js +2 -24
  15. package/bin/deploy.js +169 -144
  16. package/bin/file.js +59 -16
  17. package/bin/hwt.js +0 -10
  18. package/bin/index.js +201 -60
  19. package/bin/ssl.js +19 -11
  20. package/bin/util.js +9 -104
  21. package/bin/vs.js +26 -2
  22. package/conf.js +29 -138
  23. package/docker-compose.yml +1 -1
  24. package/manifests/deployment/mongo-express/deployment.yaml +60 -0
  25. package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
  26. package/manifests/kind-config-dev.yaml +12 -0
  27. package/manifests/kind-config.yaml +12 -0
  28. package/manifests/letsencrypt-prod.yaml +15 -0
  29. package/manifests/mariadb/config.yaml +10 -0
  30. package/manifests/mariadb/kustomization.yaml +9 -0
  31. package/manifests/mariadb/pv.yaml +12 -0
  32. package/manifests/mariadb/pvc.yaml +10 -0
  33. package/manifests/mariadb/secret.yaml +8 -0
  34. package/manifests/mariadb/service.yaml +10 -0
  35. package/manifests/mariadb/statefulset.yaml +55 -0
  36. package/manifests/mongodb/backup-access.yaml +16 -0
  37. package/manifests/mongodb/backup-cronjob.yaml +42 -0
  38. package/manifests/mongodb/backup-pv-pvc.yaml +22 -0
  39. package/manifests/mongodb/configmap.yaml +26 -0
  40. package/manifests/mongodb/headless-service.yaml +10 -0
  41. package/manifests/mongodb/kustomization.yaml +11 -0
  42. package/manifests/mongodb/pv-pvc.yaml +23 -0
  43. package/manifests/mongodb/statefulset.yaml +125 -0
  44. package/manifests/mongodb-4.4/kustomization.yaml +7 -0
  45. package/manifests/mongodb-4.4/pv-pvc.yaml +23 -0
  46. package/manifests/mongodb-4.4/service-deployment.yaml +63 -0
  47. package/manifests/valkey/kustomization.yaml +7 -0
  48. package/manifests/valkey/service.yaml +17 -0
  49. package/manifests/valkey/statefulset.yaml +39 -0
  50. package/package.json +133 -136
  51. package/src/api/core/core.service.js +1 -1
  52. package/src/api/user/user.model.js +16 -3
  53. package/src/api/user/user.service.js +1 -1
  54. package/src/cli/cluster.js +202 -0
  55. package/src/cli/cron.js +90 -0
  56. package/src/cli/db.js +212 -0
  57. package/src/cli/deploy.js +318 -0
  58. package/src/cli/env.js +52 -0
  59. package/src/cli/fs.js +149 -0
  60. package/src/cli/image.js +148 -0
  61. package/src/cli/repository.js +125 -0
  62. package/src/cli/script.js +53 -0
  63. package/src/cli/secrets.js +37 -0
  64. package/src/cli/test.js +118 -0
  65. package/src/client/components/core/Auth.js +22 -4
  66. package/src/client/components/core/CalendarCore.js +127 -50
  67. package/src/client/components/core/CommonJs.js +282 -19
  68. package/src/client/components/core/Css.js +1 -0
  69. package/src/client/components/core/CssCore.js +8 -4
  70. package/src/client/components/core/Docs.js +1 -2
  71. package/src/client/components/core/DropDown.js +5 -1
  72. package/src/client/components/core/Input.js +22 -6
  73. package/src/client/components/core/LoadingAnimation.js +8 -1
  74. package/src/client/components/core/Modal.js +40 -12
  75. package/src/client/components/core/Panel.js +92 -31
  76. package/src/client/components/core/PanelForm.js +25 -23
  77. package/src/client/components/core/Scroll.js +1 -0
  78. package/src/client/components/core/Translate.js +47 -9
  79. package/src/client/components/core/Validator.js +9 -1
  80. package/src/client/components/core/VanillaJs.js +0 -9
  81. package/src/client/components/core/Worker.js +34 -31
  82. package/src/client/services/core/core.service.js +15 -10
  83. package/src/client/services/default/default.management.js +4 -2
  84. package/src/client/ssr/Render.js +4 -1
  85. package/src/client/ssr/body/CacheControl.js +2 -3
  86. package/src/client/sw/default.sw.js +3 -3
  87. package/src/db/mongo/MongooseDB.js +29 -1
  88. package/src/index.js +85 -19
  89. package/src/runtime/lampp/Lampp.js +1 -13
  90. package/src/runtime/xampp/Xampp.js +0 -13
  91. package/src/server/auth.js +3 -3
  92. package/src/server/backup.js +49 -93
  93. package/src/server/client-build.js +36 -46
  94. package/src/server/client-formatted.js +6 -3
  95. package/src/server/conf.js +204 -54
  96. package/src/server/dns.js +30 -55
  97. package/src/server/downloader.js +0 -8
  98. package/src/server/logger.js +15 -10
  99. package/src/server/network.js +17 -43
  100. package/src/server/process.js +25 -2
  101. package/src/server/proxy.js +4 -26
  102. package/src/server/runtime.js +30 -30
  103. package/src/server/ssl.js +1 -1
  104. package/src/server/valkey.js +2 -0
  105. package/test/api.test.js +0 -8
  106. package/src/dns.js +0 -22
  107. package/src/server/prompt-optimizer.js +0 -28
  108. package/startup.js +0 -11
@@ -117,6 +117,12 @@ const CssCommonCore = async () => {
117
117
  animation: ripple 600ms linear;
118
118
  background-color: rgba(137, 137, 137, 0.503);
119
119
  }
120
+ .slide-menu-top-bar-fix {
121
+ top: 0;
122
+ left: 0;
123
+ width: 100%;
124
+ z-index: 1;
125
+ }
120
126
  @keyframes ripple {
121
127
  to {
122
128
  transform: scale(4);
@@ -390,8 +396,7 @@ const CssCoreDark = {
390
396
  text-align: center;
391
397
  background: #1a1a1a;
392
398
  font-size: 17px;
393
- padding-top: 7px;
394
- padding-bottom: 6px;
399
+ height: 35px;
395
400
  }
396
401
  ::placeholder {
397
402
  color: #c6c4c4;
@@ -695,8 +700,7 @@ const CssCoreLight = {
695
700
  text-align: center;
696
701
  background: #eaeaea;
697
702
  font-size: 17px;
698
- padding-top: 7px;
699
- padding-bottom: 6px;
703
+ height: 35px;
700
704
  }
701
705
  ::placeholder {
702
706
  color: #333;
@@ -1,4 +1,3 @@
1
- import { _VERSION, CoreService } from '../../services/core/core.service.js';
2
1
  import { Badge } from './Badge.js';
3
2
  import { BtnIcon } from './BtnIcon.js';
4
3
  import { rgbToHex } from './CommonJs.js';
@@ -80,7 +79,7 @@ const Docs = {
80
79
  icon: html`<i class="fa-brands fa-osi"></i>`,
81
80
  text: 'Source Docs',
82
81
  url: function () {
83
- return `${getProxyPath()}docs/engine/${_VERSION}`;
82
+ return `${getProxyPath()}docs/engine/${window.renderPayload.version}`;
84
83
  },
85
84
  },
86
85
  {
@@ -16,7 +16,11 @@ const DropDown = {
16
16
  onClick: () => {
17
17
  console.log('DropDown onClick', this.value);
18
18
  if (options && options.resetOnClick) options.resetOnClick();
19
- this.Tokens[id].value = undefined;
19
+ if (options && options.type === 'checkbox')
20
+ for (const opt of DropDown.Tokens[id].value) {
21
+ s(`.dropdown-option-${id}-${opt}`).click();
22
+ }
23
+ else this.Tokens[id].value = undefined;
20
24
  },
21
25
  });
22
26
 
@@ -1,6 +1,8 @@
1
1
  import { AgGrid } from './AgGrid.js';
2
2
  import { BtnIcon } from './BtnIcon.js';
3
+ import { isValidDate } from './CommonJs.js';
3
4
  import { darkTheme } from './Css.js';
5
+ import { DropDown } from './DropDown.js';
4
6
  import { loggerFactory } from './Logger.js';
5
7
  import { RichText } from './RichText.js';
6
8
  import { ToggleSwitch } from './ToggleSwitch.js';
@@ -86,8 +88,10 @@ const Input = {
86
88
  <div class="fl input-row-${id}">
87
89
  <div class="in fll" style="width: 80%;">${inputElement}</div>
88
90
  <div class="in fll btn-eye-password btn-eye-${id}" style="width: 20%;">
89
- <i class="fas fa-eye fa-eye-${id} eye-password"></i>
90
- <i class="fas fa-eye-slash fa-eye-slash-${id} eye-password" style="display: none"></i>
91
+ <div class="abs center">
92
+ <i class="fas fa-eye fa-eye-${id} eye-password"></i>
93
+ <i class="fas fa-eye-slash fa-eye-slash-${id} eye-password" style="display: none"></i>
94
+ </div>
91
95
  </div>
92
96
  </div>
93
97
  `
@@ -98,7 +102,7 @@ const Input = {
98
102
  </div>
99
103
  </div>`;
100
104
  },
101
- parseJsonEval: (selector) => {
105
+ parseJson: (selector) => {
102
106
  try {
103
107
  return JSON.parse(s(selector).value);
104
108
  } catch (error) {
@@ -147,6 +151,10 @@ const Input = {
147
151
  htmls(`.file-name-render-${inputData.id}`, `${s(`.${inputData.id}`).fileNameInputExtDefaultContent}`);
148
152
  continue;
149
153
  break;
154
+ case 'dropdown-checkbox': {
155
+ s(`.dropdown-option-${inputData.id}-reset`).click();
156
+ break;
157
+ }
150
158
  case 'md':
151
159
  RichText.Tokens[inputData.id].easyMDE.value('');
152
160
  continue;
@@ -196,6 +204,12 @@ const Input = {
196
204
  RichText.Tokens[inputData.id].easyMDE.value(fileObj[inputData.model].mdPlain);
197
205
  continue;
198
206
  break;
207
+
208
+ case 'dropdown-checkbox': {
209
+ s(`.dropdown-option-${inputData.id}-reset`).click();
210
+ for (const opt of originObj[inputData.model]) s(`.dropdown-option-${inputData.id}-${opt}`).click();
211
+ break;
212
+ }
199
213
  case 'checkbox':
200
214
  case 'checkbox-on-off':
201
215
  if (
@@ -207,9 +221,11 @@ const Input = {
207
221
  break;
208
222
  case 'datetime-local':
209
223
  {
210
- const date = new Date(originObj[inputData.model]);
211
- date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
212
- s(`.${inputData.id}`).value = date.toISOString().slice(0, 16);
224
+ if (isValidDate(originObj[inputData.model])) {
225
+ const date = new Date(originObj[inputData.model]);
226
+ // date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
227
+ s(`.${inputData.id}`).value = date.toISOString().slice(0, 16);
228
+ } else s(`.${inputData.id}`).value = null;
213
229
  }
214
230
  continue;
215
231
  break;
@@ -75,12 +75,17 @@ const LoadingAnimation = {
75
75
  const style = {
76
76
  'text-align': 'center',
77
77
  };
78
-
79
78
  if (s(container).classList) {
80
79
  const classes = Array.from(s(container).classList);
81
80
  if (classes.find((e) => e.match('management-table-btn-mini'))) {
82
81
  style.top = '-2px';
83
82
  style.left = '-2px';
83
+ } else if (classes.find((e) => e.match('-btn-tool'))) {
84
+ style.top = '-26px';
85
+ style.left = '-10px';
86
+ } else if (classes.find((e) => e.match('main-btn-')) && !classes.find((e) => e.match('main-btn-square-menu'))) {
87
+ style.top = '-8px';
88
+ style.left = '-10px';
84
89
  } else if (classes.find((e) => e.match('action-bar-box'))) {
85
90
  style.top = '-30px';
86
91
  style.left = '-12px';
@@ -145,6 +150,8 @@ const LoadingAnimation = {
145
150
  s(backgroundContainer).style.opacity = 0;
146
151
  setTimeout(async () => {
147
152
  s(backgroundContainer).style.display = 'none';
153
+ if (s(`.modal-menu`)) s(`.modal-menu`).classList.remove('hide');
154
+ if (s(`.main-body-btn-container`)) s(`.main-body-btn-container`).classList.remove('hide');
148
155
  if (callBack) callBack();
149
156
  }, 300);
150
157
  });
@@ -9,7 +9,6 @@ import {
9
9
  htmls,
10
10
  sa,
11
11
  getAllChildNodes,
12
- getCurrentTrace,
13
12
  isActiveElement,
14
13
  } from './VanillaJs.js';
15
14
  import { BtnIcon } from './BtnIcon.js';
@@ -50,6 +49,7 @@ const Modal = {
50
49
  mode: '' /* slide-menu */,
51
50
  RouterInstance: {},
52
51
  disableTools: [],
52
+ observer: false,
53
53
  },
54
54
  ) {
55
55
  if (options.heightBottomBar === undefined) options.heightBottomBar = 50;
@@ -77,6 +77,8 @@ const Modal = {
77
77
  options,
78
78
  onCloseListener: {},
79
79
  onMenuListener: {},
80
+ onCollapseMenuListener: {},
81
+ onExtendMenuListener: {},
80
82
  onDragEndListener: {},
81
83
  onObserverListener: {},
82
84
  onClickListener: {},
@@ -157,7 +159,8 @@ const Modal = {
157
159
  };
158
160
  options.mode === 'slide-menu-right' ? (options.style.right = '0px') : (options.style.left = '0px');
159
161
  const contentIconClass = 'abs center';
160
-
162
+ if (options.class) options.class += ' hide';
163
+ else options.class = 'hide';
161
164
  options.dragDisabled = true;
162
165
  options.titleClass = 'hide';
163
166
  top = '0px';
@@ -239,7 +242,7 @@ const Modal = {
239
242
  'body',
240
243
  html`
241
244
  <div
242
- class="abs main-body-btn-container"
245
+ class="abs main-body-btn-container hide"
243
246
  style="top: ${options.heightTopBar + 50}px; z-index: 9; ${true ||
244
247
  (options.mode && options.mode.match('right'))
245
248
  ? 'right'
@@ -403,6 +406,11 @@ const Modal = {
403
406
  })}
404
407
  </div>
405
408
  </div>
409
+ ${options?.slideMenuTopBarFix
410
+ ? html`<div class="abs modal slide-menu-top-bar-fix" style="height: ${options.heightTopBar}px">
411
+ ${await options.slideMenuTopBarFix()}
412
+ </div>`
413
+ : ''}
406
414
  </div>`,
407
415
  );
408
416
  EventsUI.onClick(`.action-btn-profile-log-in`, () => {
@@ -537,12 +545,12 @@ const Modal = {
537
545
  if (routerId) {
538
546
  if (
539
547
  s(`.main-btn-${routerId}`) &&
540
- (routerId.toLocaleLowerCase().match(s(`.${id}`).value.toLocaleLowerCase()) ||
548
+ (routerId.toLowerCase().match(s(`.${id}`).value.toLowerCase()) ||
541
549
  (Translate.Data[routerId] &&
542
550
  Object.keys(Translate.Data[routerId]).filter((keyLang) =>
543
551
  Translate.Data[routerId][keyLang]
544
- .toLocaleLowerCase()
545
- .match(s(`.${id}`).value.toLocaleLowerCase()),
552
+ .toLowerCase()
553
+ .match(s(`.${id}`).value.toLowerCase()),
546
554
  ).length > 0))
547
555
  ) {
548
556
  const fontAwesomeIcon = getAllChildNodes(s(`.main-btn-${routerId}`)).find((e) => {
@@ -1379,6 +1387,9 @@ const Modal = {
1379
1387
  if (options.onCollapseMenu) options.onCollapseMenu();
1380
1388
  s(`.sub-menu-title-container-${'modal-menu'}`).classList.add('hide');
1381
1389
  s(`.nav-path-container-${'modal-menu'}`).classList.add('hide');
1390
+ Object.keys(this.Data[idModal].onCollapseMenuListener).map((keyListener) =>
1391
+ this.Data[idModal].onCollapseMenuListener[keyListener](),
1392
+ );
1382
1393
  } else {
1383
1394
  slideMenuWidth = originSlideMenuWidth;
1384
1395
  setTimeout(() => {
@@ -1399,6 +1410,9 @@ const Modal = {
1399
1410
  if (options.onExtendMenu) options.onExtendMenu();
1400
1411
  s(`.sub-menu-title-container-${'modal-menu'}`).classList.remove('hide');
1401
1412
  s(`.nav-path-container-${'modal-menu'}`).classList.remove('hide');
1413
+ Object.keys(this.Data[idModal].onExtendMenuListener).map((keyListener) =>
1414
+ this.Data[idModal].onExtendMenuListener[keyListener](),
1415
+ );
1402
1416
  }
1403
1417
  // btn-bar-center-icon-menu
1404
1418
  this.actionBtnCenter();
@@ -1691,7 +1705,7 @@ const Modal = {
1691
1705
  const htmlRender = html`
1692
1706
  <br />
1693
1707
  <div class="in section-mp" style="font-size: 40px; text-align: center">
1694
- <i class="fas fa-question-circle"></i>
1708
+ ${options.icon ? options.icon : html` <i class="fas fa-question-circle"></i>`}
1695
1709
  </div>
1696
1710
  ${await options.html()}
1697
1711
  <div class="in section-mp">
@@ -1702,7 +1716,7 @@ const Modal = {
1702
1716
  style: `margin: auto`,
1703
1717
  })}
1704
1718
  </div>
1705
- <div class="in section-mp">
1719
+ <div class="in section-mp ${options.disableBtnCancel ? 'hide' : ''}">
1706
1720
  ${await BtnIcon.Render({
1707
1721
  class: `in section-mp form-button btn-cancel-${id}`,
1708
1722
  label: Translate.Render('cancel'),
@@ -1777,20 +1791,34 @@ const renderMenuLabel = ({ img, text, icon }) => {
1777
1791
  <div class="abs center main-btn-menu-text">${text}</div>`;
1778
1792
  };
1779
1793
 
1780
- const renderViewTitle = (options = { icon: '', img: '', text: '', assetFolder: '', 'ui-icons': '', dim, top }) => {
1781
- if (options.dim === undefined) options.dim = 60;
1794
+ const renderViewTitle = (
1795
+ options = { icon: '', img: '', text: '', assetFolder: '', 'ui-icons': '', dim, top, topText: '' },
1796
+ ) => {
1797
+ if (options.dim === undefined) options.dim = 30;
1782
1798
  const { img, text, icon, dim, top } = options;
1783
1799
  if (!img && !options['ui-icon']) return html`<span class="view-title-icon">${icon}</span> ${text}`;
1784
1800
  return html`<img
1785
1801
  class="abs img-btn-square-view-title"
1786
1802
  style="${renderCssAttr({
1787
- style: { width: `${dim}px`, height: `${dim}px`, top: top !== undefined ? `${top}px` : `-${dim / 2}px` },
1803
+ style: {
1804
+ width: `${dim}px`,
1805
+ height: `${dim}px`,
1806
+ top: top !== undefined ? `${top}px !important` : undefined,
1807
+ },
1788
1808
  })}"
1789
1809
  src="${options['ui-icon']
1790
1810
  ? `${getProxyPath()}assets/${options.assetFolder ? options.assetFolder : 'ui-icons'}/${options['ui-icon']}`
1791
1811
  : img}"
1792
1812
  />
1793
- <div class="in text-btn-square-view-title" style="${renderCssAttr({ style: { 'padding-left': `${dim}px` } })}">
1813
+ <div
1814
+ class="in text-btn-square-view-title"
1815
+ style="${renderCssAttr({
1816
+ style: {
1817
+ // 'padding-left': `${20 + dim}px`,
1818
+ ...(options.topText !== undefined ? { top: options.topText + 'px !important' } : {}),
1819
+ },
1820
+ })}"
1821
+ >
1794
1822
  ${text}
1795
1823
  </div>`;
1796
1824
  };
@@ -1,4 +1,4 @@
1
- import { getId } from './CommonJs.js';
1
+ import { getId, isValidDate, newInstance } from './CommonJs.js';
2
2
  import { LoadingAnimation } from '../core/LoadingAnimation.js';
3
3
  import { Validator } from '../core/Validator.js';
4
4
  import { Input } from '../core/Input.js';
@@ -26,6 +26,7 @@ const Panel = {
26
26
  idPanel: '',
27
27
  parentIdModal: '',
28
28
  scrollClassContainer: '',
29
+ htmlFormHeader: async () => '',
29
30
  formData: [],
30
31
  data: [],
31
32
  originData: () => [],
@@ -51,8 +52,6 @@ const Panel = {
51
52
  <i style="font-size: 25px" class="fa-solid fa-cloud"></i>
52
53
  </div>`;
53
54
 
54
- let editId;
55
-
56
55
  const openPanelForm = () => {
57
56
  s(`.${idPanel}-form-body`).classList.remove('hide');
58
57
  s(`.btn-${idPanel}-add`).classList.add('hide');
@@ -72,7 +71,7 @@ const Panel = {
72
71
  };
73
72
 
74
73
  const renderPanel = async (payload) => {
75
- const obj = payload;
74
+ const obj = newInstance(payload);
76
75
  if ('_id' in obj) obj.id = obj._id;
77
76
  const { id } = obj;
78
77
 
@@ -98,8 +97,8 @@ const Panel = {
98
97
  });
99
98
  EventsUI.onClick(`.${idPanel}-btn-edit-${id}`, async () => {
100
99
  logger.warn('edit', obj);
101
- if (obj._id) editId = obj._id;
102
- else if (obj.id) editId = obj.id;
100
+ if (obj._id) Panel.Tokens[idPanel].editId = obj._id;
101
+ else if (obj.id) Panel.Tokens[idPanel].editId = obj.id;
103
102
 
104
103
  s(`.btn-${idPanel}-label-edit`).classList.remove('hide');
105
104
  s(`.btn-${idPanel}-label-add`).classList.add('hide');
@@ -171,6 +170,10 @@ const Panel = {
171
170
  const valueIcon = formObjData?.panel?.icon?.value ? formObjData.panel.icon.value : '';
172
171
  const keyIcon = formObjData?.panel?.icon?.key ? formObjData.panel.icon.key : '';
173
172
 
173
+ if (formObjData && ['datetime-local'].includes(formObjData.inputType) && isValidDate(obj[infoKey])) {
174
+ obj[infoKey] = `${obj[infoKey]}`.replace('T', ' ').replace('.000Z', '');
175
+ }
176
+
174
177
  if (formData.find((f) => f.model === infoKey && f.panel && f.panel.type === 'tags')) {
175
178
  setTimeout(async () => {
176
179
  let tagRender = html``;
@@ -186,22 +189,50 @@ const Panel = {
186
189
  });
187
190
  return html``;
188
191
  }
192
+ {
193
+ const formDataObj = formData.find((f) => f.model === infoKey && f.panel && f.panel.type === 'list');
194
+ if (obj[infoKey] && obj[infoKey].length > 0 && formDataObj)
195
+ return html`<div class="in ${idPanel}-row">
196
+ <span class="${idPanel}-row-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
197
+ ${keyIcon} ${Translate.Render(infoKey)}:</span
198
+ >
199
+ <span class="${idPanel}-row-value"
200
+ >${valueIcon} ${obj[infoKey].map((k) => Translate.Render(k)).join(', ')}</span
201
+ >
202
+ </div> `;
203
+ }
189
204
 
190
- if (formData.find((f) => f.model === infoKey && f.panel && f.panel.type === 'info-row-pin'))
191
- return html`<div class="in ${idPanel}-row">
192
- <span class="${idPanel}-row-pin-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
193
- ${keyIcon} ${infoKey}:</span
194
- >
195
- <span class="${idPanel}-row-pin-value">${valueIcon} ${obj[infoKey]}</span>
196
- </div> `;
205
+ {
206
+ const formDataObj = formData.find(
207
+ (f) => f.model === infoKey && f.panel && f.panel.type === 'info-row-pin',
208
+ );
209
+ if (obj[infoKey] && formDataObj)
210
+ return html`<div class="in ${idPanel}-row">
211
+ <span class="${idPanel}-row-pin-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
212
+ ${keyIcon}
213
+ ${formDataObj.translateCode
214
+ ? Translate.Render(formDataObj.translateCode)
215
+ : Translate.Render(infoKey)}:</span
216
+ >
217
+ <span class="${idPanel}-row-pin-value">${valueIcon} ${obj[infoKey]}</span>
218
+ </div> `;
219
+ }
197
220
 
198
- if (formData.find((f) => f.model === infoKey && f.panel && f.panel.type === 'info-row'))
199
- return html`<div class="in ${idPanel}-row">
200
- <span class="${idPanel}-row-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
201
- ${keyIcon} ${infoKey}:</span
202
- >
203
- <span class="${idPanel}-row-value"> ${valueIcon} ${obj[infoKey]}</span>
204
- </div> `;
221
+ {
222
+ const formDataObj = formData.find(
223
+ (f) => f.model === infoKey && f.panel && f.panel.type === 'info-row',
224
+ );
225
+ if (obj[infoKey] && formDataObj)
226
+ return html`<div class="in ${idPanel}-row">
227
+ <span class="${idPanel}-row-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
228
+ ${keyIcon}
229
+ ${formDataObj.translateCode
230
+ ? Translate.Render(formDataObj.translateCode)
231
+ : Translate.Render(infoKey)}:</span
232
+ >
233
+ <span class="${idPanel}-row-value"> ${valueIcon} ${obj[infoKey]}</span>
234
+ </div> `;
235
+ }
205
236
 
206
237
  return html``;
207
238
  })
@@ -214,16 +245,41 @@ const Panel = {
214
245
 
215
246
  let render = '';
216
247
  let renderForm = html` <div class="in modal stq" style="top: 0px; z-index: 1; padding-bottom: 5px">
217
- ${await BtnIcon.Render({
218
- class: `section-mp btn-custom btn-${idPanel}-close`,
219
- label: html`<i class="fa-solid fa-xmark"></i> ${Translate.Render('close')}`,
220
- type: 'button',
221
- })}
222
- </div>`;
248
+ ${await BtnIcon.Render({
249
+ class: `section-mp btn-custom btn-${idPanel}-close`,
250
+ label: html`<i class="fa-solid fa-xmark"></i> ${Translate.Render('close')}`,
251
+ type: 'button',
252
+ })}
253
+ </div>
254
+ ${options?.htmlFormHeader ? await options.htmlFormHeader() : ''}`;
223
255
 
224
256
  for (const modelData of formData) {
225
257
  if (modelData.disableRender) continue;
226
258
  switch (modelData.inputType) {
259
+ case 'dropdown-checkbox': {
260
+ renderForm += html`<div class="in section-mp">
261
+ ${await DropDown.Render({
262
+ id: `${modelData.id}`,
263
+ label: html`${Translate.Render(modelData.model)}`,
264
+ type: 'checkbox',
265
+ value: modelData.dropdown.options[0],
266
+ resetOption: true,
267
+ containerClass: `${idPanel}-dropdown-checkbox`,
268
+ data: modelData.dropdown.options.map((dKey) => {
269
+ return {
270
+ value: dKey,
271
+ data: dKey,
272
+ checked: false,
273
+ display: html`${Translate.Render(dKey)}`,
274
+ onClick: function () {
275
+ logger.info('DropDown onClick', this.checked);
276
+ },
277
+ };
278
+ }),
279
+ })}
280
+ </div>`;
281
+ break;
282
+ }
227
283
  case 'dropdown':
228
284
  renderForm += html` <div class="in section-mp">
229
285
  ${await DropDown.Render({
@@ -418,21 +474,23 @@ const Panel = {
418
474
  obj.id = `${data.length}`;
419
475
  let documents;
420
476
  if (options && options.on && options.on.add) {
421
- const { status, data } = await options.on.add({ data: obj, editId });
477
+ const { status, data } = await options.on.add({ data: obj, editId: Panel.Tokens[idPanel].editId });
422
478
  if (status === 'error') return;
423
479
  documents = data;
424
480
  }
425
481
  s(`.btn-${idPanel}-clean`).click();
426
- if (editId && s(`.${idPanel}-${editId}`)) s(`.${idPanel}-${editId}`).remove();
482
+ if (Panel.Tokens[idPanel].editId && s(`.${idPanel}-${Panel.Tokens[idPanel].editId}`))
483
+ s(`.${idPanel}-${Panel.Tokens[idPanel].editId}`).remove();
427
484
  if (Array.isArray(documents)) {
428
485
  htmls(`.${idPanel}-render`, '');
429
486
  for (const doc of documents) {
430
487
  append(`.${idPanel}-render`, await renderPanel(doc));
431
488
  }
432
- } else htmls(`.${idPanel}-render`, await renderPanel(obj));
489
+ } else htmls(`.${idPanel}-render`, await renderPanel({ ...obj, ...documents }));
433
490
  Input.cleanValues(formData);
434
491
  s(`.btn-${idPanel}-close`).click();
435
492
  s(`.${scrollClassContainer}`).scrollTop = 0;
493
+ if (s(`.${scrollClassContainer}`)) s(`.${scrollClassContainer}`).style.overflow = 'auto';
436
494
  });
437
495
  s(`.btn-${idPanel}-clean`).onclick = () => {
438
496
  Input.cleanValues(formData);
@@ -458,13 +516,14 @@ const Panel = {
458
516
  s(`.btn-${idPanel}-add`).onclick = (e) => {
459
517
  e.preventDefault();
460
518
  // s(`.btn-${idPanel}-clean`).click();
461
- editId = undefined;
519
+ Panel.Tokens[idPanel].editId = undefined;
462
520
  s(`.btn-${idPanel}-label-add`).classList.remove('hide');
463
521
  s(`.btn-${idPanel}-label-edit`).classList.add('hide');
464
522
  s(`.${scrollClassContainer}`).scrollTop = 0;
465
523
 
466
524
  openPanelForm();
467
525
  };
526
+ if (s(`.${scrollClassContainer}`)) s(`.${scrollClassContainer}`).style.overflow = 'auto';
468
527
  });
469
528
 
470
529
  if (data.length > 0) for (const obj of data) render += await renderPanel(obj);
@@ -597,7 +656,9 @@ const Panel = {
597
656
  >
598
657
  <div class="in ${idPanel}-form-header">
599
658
  ${await BtnIcon.Render({
600
- class: `section-mp btn-custom btn-${idPanel}-add`,
659
+ class: `section-mp btn-custom btn-${idPanel}-add ${
660
+ options?.role?.add ? (!options.role.add() ? 'hide' : '') : ''
661
+ }`,
601
662
  label: html`<i class="fas fa-plus"></i> ${Translate.Render('add')}`,
602
663
  type: 'button',
603
664
  })}
@@ -29,6 +29,8 @@ const PanelForm = {
29
29
  Elements: {},
30
30
  parentIdModal: undefined,
31
31
  route: 'home',
32
+ htmlFormHeader: async () => '',
33
+ firsUpdateEvent: async () => {},
32
34
  },
33
35
  ) {
34
36
  const { idPanel, heightTopBar, heightBottomBar, defaultUrlImage, Elements } = options;
@@ -90,16 +92,7 @@ const PanelForm = {
90
92
  },
91
93
  },
92
94
  ];
93
- const dateFormat = (date) =>
94
- html`<span
95
- style="${renderCssAttr({
96
- style: {
97
- 'font-size': '14px',
98
- color: '#888',
99
- },
100
- })}"
101
- >${new Date(date).toLocaleString().replaceAll(',', '')}</span
102
- >`;
95
+
103
96
  const titleIcon = html`<i class="fa-solid fa-quote-left"></i>`;
104
97
  const panelRender = async ({ data }) =>
105
98
  await Panel.Render({
@@ -108,6 +101,7 @@ const PanelForm = {
108
101
  heightTopBar,
109
102
  heightBottomBar,
110
103
  data,
104
+ htmlFormHeader: options.htmlFormHeader,
111
105
  parentIdModal: options.parentIdModal,
112
106
  originData: () => PanelForm.Data[idPanel].originData,
113
107
  filesData: () => PanelForm.Data[idPanel].filesData,
@@ -271,7 +265,7 @@ const PanelForm = {
271
265
  fileId: file ? URL.createObjectURL(file) : undefined,
272
266
  _id: documentData._id,
273
267
  id: documentData._id,
274
- createdAt: dateFormat(documentData.createdAt),
268
+ createdAt: documentData.createdAt,
275
269
  };
276
270
 
277
271
  if (documentStatus === 'error') status = 'error';
@@ -376,7 +370,7 @@ const PanelForm = {
376
370
  PanelForm.Data[idPanel].data.push({
377
371
  id: documentObject._id,
378
372
  title: documentObject.title,
379
- createdAt: dateFormat(documentObject.createdAt),
373
+ createdAt: documentObject.createdAt,
380
374
  tags: documentObject.tags.filter((t) => !prefixTags.includes(t)),
381
375
  mdFileId: marked.parse(mdFileId),
382
376
  userId: documentObject.userId._id,
@@ -430,38 +424,46 @@ const PanelForm = {
430
424
  ssr: true,
431
425
  })),
432
426
  });
433
-
434
- let lastCid;
435
- let lasUserId;
427
+ let delayBlock = false;
428
+ let firsUpdateEvent = false;
436
429
  this.Data[idPanel].updatePanel = async () => {
430
+ if (delayBlock) return;
431
+ else {
432
+ delayBlock = true;
433
+ setTimeout(() => {
434
+ delayBlock = false;
435
+ }, 500);
436
+ }
437
437
  const cid = getQueryParams().cid ? getQueryParams().cid : '';
438
- if (lastCid === cid && lasUserId === Elements.Data.user.main.model.user._id) return;
439
438
  if (options.route === 'home') Modal.homeCid = newInstance(cid);
440
- lastCid = cid;
441
- lasUserId = newInstance(Elements.Data.user.main.model.user._id);
442
439
  htmls(`.${options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body'}`, await renderSrrPanelData());
443
440
  await getPanelData();
444
441
  htmls(
445
442
  `.${options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body'}`,
446
443
  await panelRender({ data: this.Data[idPanel].data }),
447
444
  );
445
+ if (!firsUpdateEvent && options.firsUpdateEvent) {
446
+ firsUpdateEvent = true;
447
+ await options.firsUpdateEvent();
448
+ }
448
449
  };
449
450
  if (options.route)
450
451
  listenQueryPathInstance({
451
452
  id: options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body',
452
453
  routeId: options.route,
453
454
  event: async (path) => {
455
+ // if (!PanelForm.Data[idPanel].sessionIn)
454
456
  await this.Data[idPanel].updatePanel();
455
457
  },
456
458
  });
457
459
 
458
460
  // if (options.route === 'home') setTimeout(this.Data[idPanel].updatePanel);
459
461
  setTimeout(() => {
460
- if (
461
- options.route !== 'home' &&
462
- (!PanelForm.Data[idPanel].originData || PanelForm.Data[idPanel].originData.length === 0)
463
- )
464
- this.Data[idPanel].updatePanel();
462
+ // if (
463
+ // options.route !== 'home' &&
464
+ // (!PanelForm.Data[idPanel].originData || PanelForm.Data[idPanel].originData.length === 0)
465
+ // )
466
+ this.Data[idPanel].updatePanel();
465
467
  });
466
468
 
467
469
  if (options.parentIdModal) {
@@ -39,6 +39,7 @@ const Scroll = {
39
39
  delete this.topRefreshEvents[id];
40
40
  },
41
41
  pullTopRefresh: function () {
42
+ return;
42
43
  append(
43
44
  'body',
44
45
  html` <style>