underpost 3.2.4 → 3.2.8

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 (141) hide show
  1. package/.github/workflows/release.cd.yml +1 -2
  2. package/CHANGELOG.md +268 -1
  3. package/CLI-HELP.md +26 -13
  4. package/Dockerfile +0 -4
  5. package/README.md +3 -3
  6. package/bin/build.js +13 -3
  7. package/bin/deploy.js +570 -1
  8. package/bin/file.js +5 -0
  9. package/conf.js +11 -2
  10. package/jsconfig.json +1 -1
  11. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -3
  12. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -3
  13. package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
  14. package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
  15. package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
  16. package/package.json +20 -11
  17. package/src/api/core/core.controller.js +10 -10
  18. package/src/api/core/core.service.js +10 -10
  19. package/src/api/default/default.controller.js +10 -10
  20. package/src/api/default/default.service.js +10 -10
  21. package/src/api/document/document.controller.js +12 -12
  22. package/src/api/document/document.model.js +10 -16
  23. package/src/api/file/file.controller.js +8 -8
  24. package/src/api/file/file.model.js +10 -10
  25. package/src/api/file/file.service.js +36 -36
  26. package/src/api/test/test.controller.js +8 -8
  27. package/src/api/test/test.service.js +8 -8
  28. package/src/api/user/guest.service.js +99 -0
  29. package/src/api/user/user.controller.js +6 -6
  30. package/src/api/user/user.model.js +8 -13
  31. package/src/api/user/user.service.js +3 -20
  32. package/src/cli/deploy.js +33 -30
  33. package/src/cli/fs.js +62 -5
  34. package/src/cli/image.js +43 -1
  35. package/src/cli/index.js +5 -1
  36. package/src/cli/release.js +58 -2
  37. package/src/cli/repository.js +35 -3
  38. package/src/cli/run.js +304 -38
  39. package/src/cli/ssh.js +1 -1
  40. package/src/cli/static.js +43 -115
  41. package/src/client/Default.index.js +21 -33
  42. package/src/client/components/core/404.js +4 -4
  43. package/src/client/components/core/500.js +4 -4
  44. package/src/client/components/core/Account.js +73 -60
  45. package/src/client/components/core/AgGrid.js +23 -33
  46. package/src/client/components/core/Alert.js +12 -13
  47. package/src/client/components/core/AppStore.js +1 -1
  48. package/src/client/components/core/Auth.js +20 -32
  49. package/src/client/components/core/Badge.js +7 -13
  50. package/src/client/components/core/BtnIcon.js +15 -17
  51. package/src/client/components/core/CalendarCore.js +42 -63
  52. package/src/client/components/core/Chat.js +13 -15
  53. package/src/client/components/core/ClientEvents.js +87 -0
  54. package/src/client/components/core/ColorPaletteElement.js +309 -0
  55. package/src/client/components/core/Content.js +17 -14
  56. package/src/client/components/core/Css.js +15 -71
  57. package/src/client/components/core/CssCore.js +12 -16
  58. package/src/client/components/core/D3Chart.js +4 -4
  59. package/src/client/components/core/Docs.js +60 -59
  60. package/src/client/components/core/DropDown.js +69 -91
  61. package/src/client/components/core/EventBus.js +92 -0
  62. package/src/client/components/core/EventsUI.js +14 -17
  63. package/src/client/components/core/FileExplorer.js +102 -234
  64. package/src/client/components/core/FullScreen.js +47 -75
  65. package/src/client/components/core/Input.js +24 -69
  66. package/src/client/components/core/Keyboard.js +25 -18
  67. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  68. package/src/client/components/core/LoadingAnimation.js +25 -31
  69. package/src/client/components/core/LogIn.js +41 -41
  70. package/src/client/components/core/LogOut.js +23 -14
  71. package/src/client/components/core/Modal.js +397 -176
  72. package/src/client/components/core/NotificationManager.js +14 -18
  73. package/src/client/components/core/Panel.js +54 -50
  74. package/src/client/components/core/PanelForm.js +25 -125
  75. package/src/client/components/core/Polyhedron.js +110 -214
  76. package/src/client/components/core/PublicProfile.js +39 -32
  77. package/src/client/components/core/Recover.js +52 -48
  78. package/src/client/components/core/Responsive.js +88 -32
  79. package/src/client/components/core/RichText.js +9 -18
  80. package/src/client/components/core/Router.js +24 -3
  81. package/src/client/components/core/SearchBox.js +37 -37
  82. package/src/client/components/core/SignUp.js +39 -30
  83. package/src/client/components/core/SocketIo.js +31 -2
  84. package/src/client/components/core/SocketIoHandler.js +6 -6
  85. package/src/client/components/core/ToggleSwitch.js +8 -20
  86. package/src/client/components/core/ToolTip.js +5 -17
  87. package/src/client/components/core/Translate.js +56 -59
  88. package/src/client/components/core/Validator.js +26 -16
  89. package/src/client/components/core/Wallet.js +15 -26
  90. package/src/client/components/core/Worker.js +140 -25
  91. package/src/client/components/core/windowGetDimensions.js +7 -7
  92. package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
  93. package/src/client/components/default/CssDefault.js +12 -12
  94. package/src/client/components/default/LogInDefault.js +6 -4
  95. package/src/client/components/default/LogOutDefault.js +6 -4
  96. package/src/client/components/default/RouterDefault.js +47 -0
  97. package/src/client/components/default/SettingsDefault.js +4 -4
  98. package/src/client/components/default/SignUpDefault.js +6 -4
  99. package/src/client/components/default/TranslateDefault.js +3 -3
  100. package/src/client/services/core/core.service.js +17 -49
  101. package/src/client/services/default/default.management.js +139 -242
  102. package/src/client/services/default/default.service.js +10 -16
  103. package/src/client/services/document/document.service.js +14 -19
  104. package/src/client/services/file/file.service.js +8 -13
  105. package/src/client/services/test/test.service.js +8 -13
  106. package/src/client/services/user/guest.service.js +79 -0
  107. package/src/client/services/user/user.management.js +5 -5
  108. package/src/client/services/user/user.service.js +14 -20
  109. package/src/client/ssr/body/404.js +3 -3
  110. package/src/client/ssr/body/500.js +3 -3
  111. package/src/client/ssr/body/CacheControl.js +5 -2
  112. package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
  113. package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
  114. package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
  115. package/src/client/ssr/offline/Maintenance.js +12 -11
  116. package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
  117. package/src/client/ssr/pages/Test.js +2 -2
  118. package/src/client/sw/core.sw.js +212 -0
  119. package/src/index.js +1 -1
  120. package/src/runtime/express/Dockerfile +4 -4
  121. package/src/runtime/lampp/Dockerfile +8 -7
  122. package/src/runtime/wp/Dockerfile +11 -17
  123. package/src/server/backup.js +1 -2
  124. package/src/server/client-build-docs.js +45 -46
  125. package/src/server/client-build.js +334 -60
  126. package/src/server/client-formatted.js +47 -16
  127. package/src/server/conf.js +29 -13
  128. package/src/server/cron.js +6 -8
  129. package/src/server/dns.js +2 -1
  130. package/src/server/ipfs-client.js +232 -91
  131. package/src/server/process.js +13 -27
  132. package/src/server/start.js +6 -3
  133. package/src/server/valkey.js +134 -235
  134. package/tsconfig.docs.json +15 -0
  135. package/typedoc.json +20 -0
  136. package/jsdoc.json +0 -52
  137. package/src/client/components/core/ColorPalette.js +0 -5267
  138. package/src/client/components/core/JoyStick.js +0 -80
  139. package/src/client/components/default/RoutesDefault.js +0 -49
  140. package/src/client/sw/default.sw.js +0 -127
  141. package/src/client/sw/template.sw.js +0 -84
@@ -15,13 +15,25 @@ import { Validator } from './Validator.js';
15
15
  import { append, htmls, s } from './VanillaJs.js';
16
16
  import { getProxyPath } from './Router.js';
17
17
  import { getApiBaseUrl } from '../../services/core/core.service.js';
18
+ import { AccountEventType, accountEvents } from './ClientEvents.js';
18
19
  import { loggerFactory } from './Logger.js';
19
20
 
20
21
  const logger = loggerFactory(import.meta);
21
22
 
22
- const Account = {
23
- UpdateEvent: {},
24
- Render: async function (options = { user: {}, bottomRender: async () => '', idModal: '' }) {
23
+ class Account {
24
+ static UpdateEvent = {};
25
+ static onUpdated(listener, options = {}) {
26
+ if (options.key) Account.UpdateEvent[options.key] = listener;
27
+ return accountEvents.on(AccountEventType.updated, listener, options);
28
+ }
29
+ static offUpdated(key) {
30
+ delete Account.UpdateEvent[key];
31
+ return accountEvents.off(key);
32
+ }
33
+ static hasUpdatedListener(key) {
34
+ return accountEvents.has(key);
35
+ }
36
+ static async instance(options = { user: {}, bottomRender: async () => '', idModal: '' }) {
25
37
  // app profile page design example
26
38
  // CSS animated backgrounds
27
39
  let { user, idModal } = options;
@@ -82,7 +94,7 @@ const Account = {
82
94
  const currentUser = LogIn.Scope.user.main.model.user;
83
95
  if (!currentUser || !currentUser._id) {
84
96
  NotificationManager.Push({
85
- html: Translate.Render('error-user-not-authenticated'),
97
+ html: Translate.instance('error-user-not-authenticated'),
86
98
  status: 'error',
87
99
  });
88
100
  return;
@@ -90,7 +102,7 @@ const Account = {
90
102
  // Guest users cannot submit form
91
103
  if (currentUser.role === 'guest') {
92
104
  NotificationManager.Push({
93
- html: Translate.Render('error-user-not-authenticated'),
105
+ html: Translate.instance('error-user-not-authenticated'),
94
106
  status: 'error',
95
107
  });
96
108
  return;
@@ -99,7 +111,7 @@ const Account = {
99
111
  const { successKeys, errorKeys, errorMessage } = await validators();
100
112
  if (errorMessage) {
101
113
  NotificationManager.Push({
102
- html: `${errorKeys.map((e) => Translate.Render(e.replace('account-', '')))} ${errorMessage}`,
114
+ html: `${errorKeys.map((e) => Translate.instance(e.replace('account-', '')))} ${errorMessage}`,
103
115
  });
104
116
  return;
105
117
  }
@@ -117,7 +129,7 @@ const Account = {
117
129
  html:
118
130
  result.status === 'error' && result.message
119
131
  ? result.message
120
- : Translate.Render(`${result.status}-update-user`),
132
+ : Translate.instance(`${result.status}-update-user`),
121
133
  status: result.status,
122
134
  });
123
135
  if (result.status === 'success') {
@@ -151,7 +163,7 @@ const Account = {
151
163
  const currentUser = LogIn.Scope.user.main.model.user;
152
164
  if (!currentUser || !currentUser._id) {
153
165
  NotificationManager.Push({
154
- html: Translate.Render('error-user-not-authenticated'),
166
+ html: Translate.instance('error-user-not-authenticated'),
155
167
  status: 'error',
156
168
  });
157
169
  return;
@@ -159,7 +171,7 @@ const Account = {
159
171
  // Guest users cannot verify email
160
172
  if (currentUser.role === 'guest') {
161
173
  NotificationManager.Push({
162
- html: Translate.Render('error-user-not-authenticated'),
174
+ html: Translate.instance('error-user-not-authenticated'),
163
175
  status: 'error',
164
176
  });
165
177
  return;
@@ -173,7 +185,7 @@ const Account = {
173
185
  },
174
186
  });
175
187
  NotificationManager.Push({
176
- html: result.status === 'error' ? result.message : Translate.Render(`email send`),
188
+ html: result.status === 'error' ? result.message : Translate.instance(`email send`),
177
189
  status: result.status,
178
190
  });
179
191
  });
@@ -196,7 +208,7 @@ const Account = {
196
208
  const currentUser = LogIn.Scope.user.main.model.user;
197
209
  if (!currentUser || !currentUser._id) {
198
210
  NotificationManager.Push({
199
- html: Translate.Render('error-user-not-authenticated'),
211
+ html: Translate.instance('error-user-not-authenticated'),
200
212
  status: 'error',
201
213
  });
202
214
  s(`.account-profile-image`).style.opacity = 1;
@@ -205,7 +217,7 @@ const Account = {
205
217
  // Guest users cannot upload profile images
206
218
  if (currentUser.role === 'guest') {
207
219
  NotificationManager.Push({
208
- html: Translate.Render('error-user-not-authenticated'),
220
+ html: Translate.instance('error-user-not-authenticated'),
209
221
  status: 'error',
210
222
  });
211
223
  s(`.account-profile-image`).style.opacity = 1;
@@ -259,12 +271,12 @@ const Account = {
259
271
  if (topbarImg) topbarImg.src = newImageSrc;
260
272
 
261
273
  NotificationManager.Push({
262
- html: Translate.Render('success-update-user'),
274
+ html: Translate.instance('success-update-user'),
263
275
  status: 'success',
264
276
  });
265
277
  } else {
266
278
  NotificationManager.Push({
267
- html: data?.message || Translate.Render('file-upload-failed'),
279
+ html: data?.message || Translate.instance('file-upload-failed'),
268
280
  status: 'error',
269
281
  });
270
282
  }
@@ -286,7 +298,7 @@ const Account = {
286
298
  html: async () => {
287
299
  return html`
288
300
  <div class="in section-mp" style="text-align: center">
289
- ${Translate.Render('confirm-delete-account')}
301
+ ${Translate.instance('confirm-delete-account')}
290
302
  </div>
291
303
  `;
292
304
  },
@@ -304,7 +316,7 @@ const Account = {
304
316
  const descriptionValue = s(`.account-brief-description`).value;
305
317
  if (!descriptionValue || descriptionValue === 'undefined' || descriptionValue.trim() === '') {
306
318
  NotificationManager.Push({
307
- html: Translate.Render('brief-description-cannot-be-empty'),
319
+ html: Translate.instance('brief-description-cannot-be-empty'),
308
320
  status: 'error',
309
321
  });
310
322
  return;
@@ -313,7 +325,7 @@ const Account = {
313
325
  const currentUser = LogIn.Scope.user.main.model.user;
314
326
  if (!currentUser || !currentUser._id) {
315
327
  NotificationManager.Push({
316
- html: Translate.Render('error-user-not-authenticated'),
328
+ html: Translate.instance('error-user-not-authenticated'),
317
329
  status: 'error',
318
330
  });
319
331
  return;
@@ -321,7 +333,7 @@ const Account = {
321
333
  // Guest users cannot update brief description
322
334
  if (currentUser.role === 'guest') {
323
335
  NotificationManager.Push({
324
- html: Translate.Render('error-user-not-authenticated'),
336
+ html: Translate.instance('error-user-not-authenticated'),
325
337
  status: 'error',
326
338
  });
327
339
  return;
@@ -331,7 +343,7 @@ const Account = {
331
343
  html:
332
344
  result.status === 'error' && result.message
333
345
  ? result.message
334
- : Translate.Render(`${result.status}-update-user`),
346
+ : Translate.instance(`${result.status}-update-user`),
335
347
  status: result.status,
336
348
  });
337
349
  if (result.status === 'success') {
@@ -357,7 +369,7 @@ const Account = {
357
369
  const currentUser = LogIn.Scope.user.main.model.user;
358
370
  if (!currentUser || !currentUser._id) {
359
371
  NotificationManager.Push({
360
- html: Translate.Render('error-user-not-authenticated'),
372
+ html: Translate.instance('error-user-not-authenticated'),
361
373
  status: 'error',
362
374
  });
363
375
  return;
@@ -365,7 +377,7 @@ const Account = {
365
377
  // Guest users cannot toggle public profile
366
378
  if (currentUser.role === 'guest') {
367
379
  NotificationManager.Push({
368
- html: Translate.Render('error-user-not-authenticated'),
380
+ html: Translate.instance('error-user-not-authenticated'),
369
381
  status: 'error',
370
382
  });
371
383
  return;
@@ -375,7 +387,7 @@ const Account = {
375
387
  html:
376
388
  result.status === 'error' && result.message
377
389
  ? result.message
378
- : Translate.Render(`${result.status}-update-user`),
390
+ : Translate.instance(`${result.status}-update-user`),
379
391
  status: result.status,
380
392
  });
381
393
  if (result.status === 'success') {
@@ -403,14 +415,14 @@ const Account = {
403
415
  const currentUser = LogIn.Scope.user.main.model.user;
404
416
  if (!currentUser || !currentUser._id) {
405
417
  NotificationManager.Push({
406
- html: Translate.Render('error-user-not-authenticated'),
418
+ html: Translate.instance('error-user-not-authenticated'),
407
419
  status: 'error',
408
420
  });
409
421
  return;
410
422
  }
411
423
  const result = await UserService.delete({ id: currentUser._id });
412
424
  NotificationManager.Push({
413
- html: result.status === 'error' ? result.message : Translate.Render(`success-delete-account`),
425
+ html: result.status === 'error' ? result.message : Translate.instance(`success-delete-account`),
414
426
  status: result.status,
415
427
  });
416
428
  s(`.btn-account-delete-confirm`).classList.remove('hide');
@@ -436,27 +448,27 @@ const Account = {
436
448
 
437
449
  <form class="in">
438
450
  <div class="in">
439
- ${await Input.Render({
451
+ ${await Input.instance({
440
452
  id: `account-username`,
441
453
  type: 'text',
442
- label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.Render('username')}`,
454
+ label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.instance('username')}`,
443
455
  containerClass: 'inl section-mp width-mini-box input-container',
444
456
  placeholder: true,
445
457
  disabled: false,
446
458
  extension: async () =>
447
- html`${await BtnIcon.Render({
459
+ html`${await BtnIcon.instance({
448
460
  class: `in wfa btn-input-extension btn-account-update-username`,
449
461
  type: 'button',
450
462
  style: 'text-align: left',
451
- label: html`${Translate.Render(`update`)}`,
463
+ label: html`${Translate.instance(`update`)}`,
452
464
  })}`,
453
465
  })}
454
466
  </div>
455
467
  <div class="in">
456
- ${await Input.Render({
468
+ ${await Input.instance({
457
469
  id: `account-email`,
458
470
  type: 'email',
459
- label: html`<i class="fa-solid fa-envelope"></i> ${Translate.Render('email')}`,
471
+ label: html`<i class="fa-solid fa-envelope"></i> ${Translate.instance('email')}`,
460
472
  containerClass: 'inl section-mp width-mini-box input-container',
461
473
  placeholder: true,
462
474
  autocomplete: 'email',
@@ -464,57 +476,57 @@ const Account = {
464
476
  extension: !(options && options.disabled && options.disabled.includes('emailConfirm'))
465
477
  ? async () =>
466
478
  html`<div class="in verify-email-status"></div>
467
- ${await BtnIcon.Render({
479
+ ${await BtnIcon.instance({
468
480
  class: `in wfa btn-input-extension btn-confirm-email`,
469
481
  type: 'button',
470
482
  style: 'text-align: left',
471
483
  label: html`<div class="in">
472
- <i class="fa-solid fa-paper-plane"></i> ${Translate.Render('send')}
473
- ${Translate.Render('verify-email')}
484
+ <i class="fa-solid fa-paper-plane"></i> ${Translate.instance('send')}
485
+ ${Translate.instance('verify-email')}
474
486
  </div> `,
475
487
  })}`
476
488
  : undefined,
477
489
  })}
478
490
  </div>
479
491
  <div class="in">
480
- ${await Input.Render({
492
+ ${await Input.instance({
481
493
  id: `account-password`,
482
494
  type: 'password',
483
495
  autocomplete: 'new-password',
484
- label: html`<i class="fa-solid fa-lock"></i> ${Translate.Render('password')}`,
496
+ label: html`<i class="fa-solid fa-lock"></i> ${Translate.instance('password')}`,
485
497
  containerClass: 'inl section-mp width-mini-box input-container',
486
498
  placeholder: true,
487
499
  disabled: true,
488
500
  disabledEye: true,
489
501
  extension: async () =>
490
- html`${await BtnIcon.Render({
502
+ html`${await BtnIcon.instance({
491
503
  class: `in wfa btn-input-extension btn-account-change-password`,
492
504
  type: 'button',
493
505
  style: 'text-align: left',
494
- label: html`${Translate.Render(`change-password`)}`,
506
+ label: html`${Translate.instance(`change-password`)}`,
495
507
  })}`,
496
508
  })}
497
509
  </div>
498
510
  <div class="in">
499
- ${await Input.Render({
511
+ ${await Input.instance({
500
512
  id: `account-brief-description`,
501
- label: html`<i class="fa-solid fa-pen-fancy"></i> ${Translate.Render('brief-description')}`,
513
+ label: html`<i class="fa-solid fa-pen-fancy"></i> ${Translate.instance('brief-description')}`,
502
514
  containerClass: 'inl section-mp width-mini-box input-container',
503
515
  placeholder: true,
504
516
  rows: 4,
505
517
  extension: async () =>
506
- html`${await BtnIcon.Render({
518
+ html`${await BtnIcon.instance({
507
519
  class: `in wfa btn-input-extension btn-brief-description-update`,
508
520
  type: 'button',
509
521
  style: 'text-align: left',
510
- label: html`${Translate.Render(`update`)}`,
522
+ label: html`${Translate.instance(`update`)}`,
511
523
  })}`,
512
524
  })}
513
525
  </div>
514
526
  <div class="in section-mp">
515
- ${await ToggleSwitch.Render({
527
+ ${await ToggleSwitch.instance({
516
528
  wrapper: true,
517
- wrapperLabel: html`<i class="fa-solid fa-globe"></i> ${Translate.Render('public-profile')}`,
529
+ wrapperLabel: html`<i class="fa-solid fa-globe"></i> ${Translate.instance('public-profile')}`,
518
530
  id: 'account-public-profile',
519
531
  disabledOnClick: true,
520
532
  checked: user.publicProfile ? true : false,
@@ -522,35 +534,36 @@ const Account = {
522
534
  </div>
523
535
  ${options?.bottomRender ? await options.bottomRender() : ``}
524
536
  <div class="in hide">
525
- ${await BtnIcon.Render({
537
+ ${await BtnIcon.instance({
526
538
  class: 'in section-mp form-button btn-account',
527
- label: Translate.Render('update'),
539
+ label: Translate.instance('update'),
528
540
  type: 'submit',
529
541
  })}
530
542
  </div>
531
543
  </form>
532
544
  <div class="in">
533
- ${await BtnIcon.Render({
545
+ ${await BtnIcon.instance({
534
546
  class: 'in section-mp form-button btn-account-delete hide',
535
- label: html` ${Translate.Render(`delete-account`)}`,
547
+ label: html` ${Translate.instance(`delete-account`)}`,
536
548
  type: 'button',
537
549
  style: 'color: #5f5f5f',
538
550
  })}
539
- ${await BtnIcon.Render({
551
+ ${await BtnIcon.instance({
540
552
  class: 'in section-mp form-button btn-account-delete-confirm',
541
- label: html` ${Translate.Render(`delete-account`)}`,
553
+ label: html` ${Translate.instance(`delete-account`)}`,
542
554
  type: 'button',
543
555
  style: 'color: #5f5f5f',
544
556
  })}
545
557
  </div>
546
558
  `;
547
- },
548
- triggerUpdateEvent: async function (options = { user: {} }) {
559
+ }
560
+ static async triggerUpdateEvent(options = { user: {} }) {
561
+ await accountEvents.emit(AccountEventType.updated, options);
549
562
  for (const updateEvent of Object.keys(this.UpdateEvent)) {
550
563
  await this.UpdateEvent[updateEvent](options);
551
564
  }
552
- },
553
- renderVerifyEmailStatus: function (user) {
565
+ }
566
+ static renderVerifyEmailStatus(user) {
554
567
  if (s('.verify-email-status')) {
555
568
  if (s(`.btn-confirm-email`)) {
556
569
  if (user.emailConfirmed) s(`.btn-confirm-email`).classList.add('hide');
@@ -558,14 +571,14 @@ const Account = {
558
571
  }
559
572
  htmls(
560
573
  '.verify-email-status',
561
- html`${renderStatus(user.emailConfirmed ? 'success' : 'error', { class: 'inl' })} ${Translate.Render('email')}
562
- ${Translate.Render(user.emailConfirmed ? 'confirmed' : 'unconfirmed')}`,
574
+ html`${renderStatus(user.emailConfirmed ? 'success' : 'error', { class: 'inl' })} ${Translate.instance('email')}
575
+ ${Translate.instance(user.emailConfirmed ? 'confirmed' : 'unconfirmed')}`,
563
576
  );
564
577
  if (user.emailConfirmed === true) s(`.account-email`).setAttribute('disabled', '');
565
578
  }
566
- },
567
- instanceModalUiEvents: async (user) => null,
568
- updateForm: async function (user) {
579
+ }
580
+ static instanceModalUiEvents = async (user) => null;
581
+ static async updateForm(user) {
569
582
  if (!s(`.modal-account`)) return;
570
583
 
571
584
  // Always sync the current user data into LogIn.Scope, preserving profileImage if it exists
@@ -611,7 +624,7 @@ const Account = {
611
624
  ToggleSwitch.Tokens['account-public-profile'].click();
612
625
  }
613
626
  }
614
- },
615
- };
627
+ }
628
+ }
616
629
 
617
630
  export { Account };
@@ -1,16 +1,14 @@
1
1
  // https://www.ag-grid.com/javascript-data-grid/getting-started/
2
2
  // https://www.ag-grid.com/javascript-data-grid/themes/
3
-
4
3
  import { ThemeEvents, darkTheme } from './Css.js';
5
4
  import { append, htmls, s } from './VanillaJs.js';
6
5
  import { getProxyPath } from './Router.js';
7
6
  import './Pagination.js';
8
7
  import { Modal } from './Modal.js';
9
-
10
- const AgGrid = {
11
- grids: {},
12
- theme: `ag-theme-alpine`, // quartz
13
- Render: async function (options) {
8
+ class AgGrid {
9
+ static grids = {};
10
+ static theme = `ag-theme-alpine`;
11
+ static async instance(options) {
14
12
  let { id, paginationOptions } = options;
15
13
  setTimeout(() => {
16
14
  // Normalize rowSelection from deprecated string form to object form (AG Grid v32.2.1+)
@@ -21,7 +19,6 @@ const AgGrid = {
21
19
  mode: mode === 'multiple' ? 'multiRow' : 'singleRow',
22
20
  };
23
21
  }
24
-
25
22
  // Grid Options: Contains all of the grid configurations
26
23
  const gridOptions = {
27
24
  // Use legacy CSS theme mode to avoid conflict with Theming API (AG Grid v33+)
@@ -63,24 +60,20 @@ const AgGrid = {
63
60
  onSortChanged: options?.onSortChanged,
64
61
  // set background colour on every row, this is probably bad, should be using CSS classes
65
62
  // rowStyle: { background: 'black' },
66
-
67
63
  // set background colour on even rows again, this looks bad, should be using CSS classes
68
64
  // getRowStyle: (params) => {
69
65
  // if (params.node.rowIndex % 2 === 0) {
70
66
  // return { background: 'red' };
71
67
  // }
72
68
  // },
73
-
74
69
  // all rows assigned CSS class 'my-green-class'
75
70
  // rowClass: 'my-green-class',
76
-
77
71
  // all even rows assigned 'my-shaded-effect'
78
72
  // getRowClass: (params) => {
79
73
  // if (params.node.rowIndex % 2 === 0) {
80
74
  // return 'my-shaded-effect';
81
75
  // }
82
76
  // },
83
-
84
77
  // domLayout: 'autoHeight', || 'normal'
85
78
  // Column Definitions: Defines & controls grid columns.
86
79
  columnDefs: options?.gridOptions?.rowData?.[0]
@@ -90,25 +83,23 @@ const AgGrid = {
90
83
  : [],
91
84
  ...gridOptionsOverrides,
92
85
  };
93
-
94
86
  // Your Javascript code to create the grid
95
87
  const myGridElement = s(`.${id}`);
96
- if (this.grids[id]) this.grids[id].destroy();
97
- this.grids[id] = agGrid.createGrid(myGridElement, gridOptions);
88
+ if (AgGrid.grids[id]) AgGrid.grids[id].destroy();
89
+ AgGrid.grids[id] = agGrid.createGrid(myGridElement, gridOptions);
98
90
  // myGridElement.style.setProperty('width', '100%');
99
91
  ThemeEvents[id] = () => {
100
92
  if (s(`.${id}`)) {
101
93
  // darkTheme has already been updated by Css.js when this event fires
102
94
  // If darkTheme is true: remove light class, add dark class
103
95
  // If darkTheme is false: remove dark class, add light class
104
- s(`.${id}`).classList.remove(this.theme, this.theme + '-dark');
105
- s(`.${id}`).classList.add(darkTheme ? this.theme + '-dark' : this.theme);
96
+ s(`.${id}`).classList.remove(AgGrid.theme, AgGrid.theme + '-dark');
97
+ s(`.${id}`).classList.add(darkTheme ? AgGrid.theme + '-dark' : AgGrid.theme);
106
98
  } else {
107
99
  // console.warn('change theme: grid not found');
108
100
  delete ThemeEvents[id];
109
101
  }
110
102
  };
111
-
112
103
  if (!options.style || !options.style.height) {
113
104
  if (options.parentModal && Modal.Data[options.parentModal].options.observer) {
114
105
  Modal.Data[options.parentModal].onObserverListener[id + '-observer'] = ({ width, height }) => {
@@ -127,15 +118,15 @@ const AgGrid = {
127
118
  : '';
128
119
  return html`
129
120
  <div
130
- class="${id} ${darkTheme ? this.theme + '-dark' : this.theme}"
121
+ class="${id} ${darkTheme ? AgGrid.theme + '-dark' : AgGrid.theme}"
131
122
  style="${options?.style
132
123
  ? Object.keys(options.style).map((styleKey) => `${styleKey}: ${options.style[styleKey]}; `)
133
124
  : ''}"
134
125
  ></div>
135
126
  ${usePagination ? `<ag-pagination id="ag-pagination-${id}" ${limitOptionsAttr}></ag-pagination>` : ''}
136
127
  `;
137
- },
138
- RenderStyle: async function (
128
+ }
129
+ static async RenderStyle(
139
130
  options = {
140
131
  eventThemeId: 'AgGrid',
141
132
  style: {
@@ -147,15 +138,15 @@ const AgGrid = {
147
138
  },
148
139
  ) {
149
140
  /*
150
- --ag-foreground-color: rgb(126, 46, 132);
151
- --ag-background-color: rgb(249, 245, 227);
152
- --ag-header-foreground-color: rgb(204, 245, 172);
153
- --ag-header-background-color: rgb(209, 64, 129);
154
- --ag-odd-row-background-color: rgb(0, 0, 0, 0.03);
155
- --ag-header-column-resize-handle-color: rgb(126, 46, 132);
156
-
157
- --ag-font-size: 17px;
158
- */
141
+ --ag-foreground-color: rgb(126, 46, 132);
142
+ --ag-background-color: rgb(249, 245, 227);
143
+ --ag-header-foreground-color: rgb(204, 245, 172);
144
+ --ag-header-background-color: rgb(209, 64, 129);
145
+ --ag-odd-row-background-color: rgb(0, 0, 0, 0.03);
146
+ --ag-header-column-resize-handle-color: rgb(126, 46, 132);
147
+
148
+ --ag-font-size: 17px;
149
+ */
159
150
  if (!s(`.ag-grid-base-style`))
160
151
  append(
161
152
  'head',
@@ -167,7 +158,7 @@ const AgGrid = {
167
158
  /><link
168
159
  rel="stylesheet"
169
160
  type="text/css"
170
- href="${getProxyPath()}styles/ag-grid-community/${this.theme}.min.css"
161
+ href="${getProxyPath()}styles/ag-grid-community/${AgGrid.theme}.min.css"
171
162
  />`,
172
163
  );
173
164
  ThemeEvents[options.eventThemeId] = () => {
@@ -242,7 +233,6 @@ const AgGrid = {
242
233
  </style>`}`,
243
234
  );
244
235
  };
245
- },
246
- };
247
-
236
+ }
237
+ }
248
238
  export { AgGrid };
@@ -1,5 +1,4 @@
1
1
  import { Translate } from './Translate.js';
2
-
3
2
  const maintenance = async () => {
4
3
  const icon = html`<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 24 24">
5
4
  <path
@@ -14,10 +13,9 @@ const maintenance = async () => {
14
13
  return html` <div class="abs center" style="top: 45%">
15
14
  ${icon}
16
15
  <br />
17
- <br />${Translate.Render('server-maintenance')}
16
+ <br />${Translate.instance('server-maintenance')}
18
17
  </div>`;
19
18
  };
20
-
21
19
  const noInternet = async () => {
22
20
  const icon = html`<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 20 20">
23
21
  <path
@@ -28,10 +26,9 @@ const noInternet = async () => {
28
26
  return html` <div class="abs center" style="top: 45%">
29
27
  ${icon}
30
28
  <br />
31
- <br />${Translate.Render('no-internet-connection')}
29
+ <br />${Translate.instance('no-internet-connection')}
32
30
  </div>`;
33
31
  };
34
-
35
32
  const e404 = async () => {
36
33
  const icon = html`
37
34
  <svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 24 24">
@@ -47,12 +44,11 @@ const e404 = async () => {
47
44
  <br />
48
45
  <span class="bold">404</span>
49
46
  <br />
50
- <br />${Translate.Render('page-not-found')} <br />
47
+ <br />${Translate.instance('page-not-found')} <br />
51
48
  <br />
52
- <a target="_top" href="${location.origin}">${Translate.Render('back')}</a>
49
+ <a target="_top" href="${location.origin}">${Translate.instance('back')}</a>
53
50
  </div>`;
54
51
  };
55
-
56
52
  const e500 = async () => {
57
53
  const icon = html`<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 20 20">
58
54
  <path
@@ -66,12 +62,15 @@ const e500 = async () => {
66
62
  <br />
67
63
  <span class="bold">500</span>
68
64
  <br />
69
- <br />${Translate.Render('page-broken')} <br />
65
+ <br />${Translate.instance('page-broken')} <br />
70
66
  <br />
71
- <a target="_top" href="${location.origin}">${Translate.Render('back')}</a>
67
+ <a target="_top" href="${location.origin}">${Translate.instance('back')}</a>
72
68
  </div>`;
73
69
  };
74
-
75
- const Alert = { maintenance, noInternet, e404, e500 };
76
-
70
+ class Alert {
71
+ static maintenance = maintenance;
72
+ static noInternet = noInternet;
73
+ static e404 = e404;
74
+ static e500 = e500;
75
+ }
77
76
  export { Alert };
@@ -10,7 +10,7 @@
10
10
  * @classdesc Per-app singleton state store for WebSocket channel data and authenticated user state.
11
11
  *
12
12
  * Usage: `AppStoreX.Data.user.main.model.user` — the authenticated user object.
13
- * `AppStoreX.Data` keys (`chat`, `mailer`, `stream`, etc.) — channel definitions for `SocketIo.Init`.
13
+ * `AppStoreX.Data` keys (`chat`, `mailer`, `stream`, etc.) — channel definitions for `SocketIo.instance`.
14
14
  * @memberof AppStore
15
15
  */
16
16
  class AppStore {