underpost 2.8.1 → 2.8.41
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/.dockerignore +1 -0
- package/.github/workflows/ghpkg.yml +14 -11
- package/.github/workflows/pwa-microservices-template.page.yml +10 -3
- package/.vscode/extensions.json +17 -71
- package/.vscode/settings.json +10 -4
- package/AUTHORS.md +16 -5
- package/CHANGELOG.md +63 -3
- package/Dockerfile +41 -62
- package/README.md +1 -28
- package/bin/build.js +278 -0
- package/bin/db.js +2 -24
- package/bin/deploy.js +105 -55
- package/bin/file.js +33 -4
- package/bin/index.js +33 -51
- package/bin/ssl.js +19 -11
- package/bin/util.js +9 -89
- package/bin/vs.js +25 -2
- package/conf.js +31 -138
- package/docker-compose.yml +1 -1
- package/manifests/core/kustomization.yaml +11 -0
- package/manifests/core/underpost-engine-backup-access.yaml +16 -0
- package/manifests/core/underpost-engine-backup-pv-pvc.yaml +22 -0
- package/manifests/core/underpost-engine-headless-service.yaml +10 -0
- package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +40 -0
- package/manifests/core/underpost-engine-mongodb-configmap.yaml +26 -0
- package/manifests/core/underpost-engine-pv-pvc.yaml +23 -0
- package/manifests/core/underpost-engine-statefulset.yaml +91 -0
- package/manifests/deployment/mongo-express.yaml +60 -0
- package/manifests/deployment/phpmyadmin.yaml +54 -0
- package/manifests/kind-config.yaml +12 -0
- package/manifests/letsencrypt-prod.yaml +15 -0
- package/manifests/mariadb/config.yaml +10 -0
- package/manifests/mariadb/kustomization.yaml +9 -0
- package/manifests/mariadb/pv.yaml +12 -0
- package/manifests/mariadb/pvc.yaml +10 -0
- package/manifests/mariadb/secret.yaml +8 -0
- package/manifests/mariadb/service.yaml +10 -0
- package/manifests/mariadb/statefulset.yaml +55 -0
- package/manifests/valkey/kustomization.yaml +7 -0
- package/manifests/valkey/underpost-engine-valkey-service.yaml +17 -0
- package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +39 -0
- package/package.json +115 -136
- package/src/api/user/user.model.js +16 -3
- package/src/api/user/user.service.js +1 -1
- package/src/client/components/core/CalendarCore.js +115 -49
- package/src/client/components/core/CommonJs.js +150 -19
- package/src/client/components/core/CssCore.js +6 -0
- package/src/client/components/core/DropDown.js +5 -1
- package/src/client/components/core/Input.js +17 -3
- package/src/client/components/core/Modal.js +10 -5
- package/src/client/components/core/Panel.js +84 -25
- package/src/client/components/core/PanelForm.js +4 -18
- package/src/client/components/core/Translate.js +43 -9
- package/src/client/components/core/Validator.js +9 -1
- package/src/client/services/default/default.management.js +4 -2
- package/src/db/mongo/MongooseDB.js +13 -1
- package/src/index.js +8 -1
- package/src/runtime/lampp/Lampp.js +1 -13
- package/src/runtime/xampp/Xampp.js +0 -13
- package/src/server/auth.js +3 -3
- package/src/server/client-build.js +3 -13
- package/src/server/conf.js +296 -29
- package/src/server/dns.js +2 -3
- package/src/server/logger.js +10 -5
- package/src/server/network.js +0 -36
- package/src/server/process.js +25 -2
- package/src/server/project.js +39 -0
- package/src/server/proxy.js +4 -26
- package/src/server/runtime.js +6 -7
- package/src/server/ssl.js +1 -1
- package/src/server/valkey.js +2 -0
- package/startup.cjs +12 -0
- package/src/server/prompt-optimizer.js +0 -28
- package/startup.js +0 -11
|
@@ -518,25 +518,25 @@ function getDirname(path) {
|
|
|
518
518
|
return parts.join('/'); // Adjust separator if needed for Windows ('\')
|
|
519
519
|
}
|
|
520
520
|
|
|
521
|
-
const isDayValid = (day) => {
|
|
522
|
-
const date = new Date();
|
|
523
|
-
date.setDate(day);
|
|
524
|
-
return date.getDate() === day;
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
const isMonthValid = (month) => {
|
|
528
|
-
const date = new Date();
|
|
529
|
-
date.setMonth(month - 1);
|
|
530
|
-
return date.getMonth() === month - 1;
|
|
531
|
-
};
|
|
532
|
-
|
|
533
521
|
const isValidDate = (day, month, year) => {
|
|
534
|
-
if (!
|
|
535
|
-
|
|
536
|
-
|
|
522
|
+
if (!month && !year) return !(new Date(day) == 'Invalid Date');
|
|
523
|
+
// new Date('2025-12-28')
|
|
524
|
+
// Sat Dec 27 2025 19:00:00 GMT-0500 (Eastern Standard Time)
|
|
525
|
+
// new Date('2025/12/28')
|
|
526
|
+
// Sun Dec 28 2025 00:00:00 GMT-0500 (Eastern Standard Time)
|
|
527
|
+
return !(new Date(`${year}/${month}/${day}`) == 'Invalid Date');
|
|
528
|
+
};
|
|
537
529
|
|
|
538
|
-
|
|
539
|
-
|
|
530
|
+
// console.log(req.body.timeZoneClient, Intl.DateTimeFormat().resolvedOptions().timeZone);
|
|
531
|
+
// DateTime.fromISO("2017-05-15T09:10:23", { zone: "Europe/Paris" });
|
|
532
|
+
const strToDateUTC = (date = '2025-01-30T14:32') => {
|
|
533
|
+
const year = parseInt(date.split('-')[0]);
|
|
534
|
+
const month = parseInt(date.split('-')[1]);
|
|
535
|
+
const day = parseInt(date.split('-')[2].split('T')[0]);
|
|
536
|
+
const hour = parseInt(date.split('T')[1].split(':')[0]);
|
|
537
|
+
const minute = parseInt(date.split('T')[1].split(':')[1]);
|
|
538
|
+
date = new Date(Date.UTC(year, month - 1, day, hour, minute, 0, 0));
|
|
539
|
+
return date;
|
|
540
540
|
};
|
|
541
541
|
|
|
542
542
|
const isValidFormat = (value, format) => {
|
|
@@ -662,6 +662,22 @@ function componentFromStr(numStr, percent) {
|
|
|
662
662
|
return percent ? Math.floor((255 * Math.min(100, num)) / 100) : Math.min(255, num);
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
const isChileanIdentityDocument = function (rutCompleto) {
|
|
666
|
+
const dv = function (T) {
|
|
667
|
+
let M = 0,
|
|
668
|
+
S = 1;
|
|
669
|
+
for (; T; T = Math.floor(T / 10)) S = (S + (T % 10) * (9 - (M++ % 6))) % 11;
|
|
670
|
+
return S ? S - 1 : 'k';
|
|
671
|
+
};
|
|
672
|
+
rutCompleto = rutCompleto.replace('‐', '-');
|
|
673
|
+
if (!/^[0-9]+[-|‐]{1}[0-9kK]{1}$/.test(rutCompleto)) return false;
|
|
674
|
+
var tmp = rutCompleto.split('-');
|
|
675
|
+
var digv = tmp[1];
|
|
676
|
+
var rut = tmp[0];
|
|
677
|
+
if (digv == 'K') digv = 'k';
|
|
678
|
+
return dv(rut) == digv;
|
|
679
|
+
};
|
|
680
|
+
|
|
665
681
|
function rgbToHex(rgb) {
|
|
666
682
|
const rgbRegex = /^rgb\(\s*(-?\d+)(%?)\s*,\s*(-?\d+)(%?)\s*,\s*(-?\d+)(%?)\s*\)$/;
|
|
667
683
|
let result,
|
|
@@ -685,10 +701,121 @@ const hexToNumber = (hex = 0xdc) => Number(hex) || parseFloat(hex, 16);
|
|
|
685
701
|
|
|
686
702
|
const numberToHex = (number = 0) => number.toString(16);
|
|
687
703
|
|
|
704
|
+
const generateRandomPasswordSelection = (length) => {
|
|
705
|
+
const _random = (arr) => {
|
|
706
|
+
const rand = Math.floor(Math.random() * arr.length);
|
|
707
|
+
return arr[rand];
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const uppercase = [
|
|
711
|
+
'A',
|
|
712
|
+
'B',
|
|
713
|
+
'C',
|
|
714
|
+
'D',
|
|
715
|
+
'E',
|
|
716
|
+
'F',
|
|
717
|
+
'G',
|
|
718
|
+
'H',
|
|
719
|
+
'I',
|
|
720
|
+
'J',
|
|
721
|
+
'K',
|
|
722
|
+
'L',
|
|
723
|
+
'M',
|
|
724
|
+
'N',
|
|
725
|
+
'O',
|
|
726
|
+
'P',
|
|
727
|
+
'Q',
|
|
728
|
+
'R',
|
|
729
|
+
'S',
|
|
730
|
+
'T',
|
|
731
|
+
'U',
|
|
732
|
+
'V',
|
|
733
|
+
'W',
|
|
734
|
+
'X',
|
|
735
|
+
'Y',
|
|
736
|
+
'Z',
|
|
737
|
+
];
|
|
738
|
+
const lowercase = [
|
|
739
|
+
'a',
|
|
740
|
+
'b',
|
|
741
|
+
'c',
|
|
742
|
+
'd',
|
|
743
|
+
'e',
|
|
744
|
+
'f',
|
|
745
|
+
'g',
|
|
746
|
+
'h',
|
|
747
|
+
'i',
|
|
748
|
+
'j',
|
|
749
|
+
'k',
|
|
750
|
+
'l',
|
|
751
|
+
'm',
|
|
752
|
+
'n',
|
|
753
|
+
'o',
|
|
754
|
+
'p',
|
|
755
|
+
'q',
|
|
756
|
+
'r',
|
|
757
|
+
's',
|
|
758
|
+
't',
|
|
759
|
+
'u',
|
|
760
|
+
'v',
|
|
761
|
+
'w',
|
|
762
|
+
'x',
|
|
763
|
+
'y',
|
|
764
|
+
'z',
|
|
765
|
+
];
|
|
766
|
+
const special = [
|
|
767
|
+
'~',
|
|
768
|
+
'!',
|
|
769
|
+
'@',
|
|
770
|
+
'#',
|
|
771
|
+
'$',
|
|
772
|
+
'%',
|
|
773
|
+
'^',
|
|
774
|
+
'&',
|
|
775
|
+
'*',
|
|
776
|
+
'(',
|
|
777
|
+
')',
|
|
778
|
+
'_',
|
|
779
|
+
'+',
|
|
780
|
+
'-',
|
|
781
|
+
'=',
|
|
782
|
+
'{',
|
|
783
|
+
'}',
|
|
784
|
+
'[',
|
|
785
|
+
']',
|
|
786
|
+
':',
|
|
787
|
+
';',
|
|
788
|
+
'?',
|
|
789
|
+
',',
|
|
790
|
+
'.',
|
|
791
|
+
'|',
|
|
792
|
+
'\\',
|
|
793
|
+
];
|
|
794
|
+
const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
795
|
+
|
|
796
|
+
const nonSpecial = [...uppercase, ...lowercase, ...numbers];
|
|
797
|
+
|
|
798
|
+
let password = '';
|
|
799
|
+
|
|
800
|
+
for (let i = 0; i < length; i++) {
|
|
801
|
+
// Previous character is a special character
|
|
802
|
+
if (i !== 0 && special.includes(password[i - 1])) {
|
|
803
|
+
password += _random(nonSpecial);
|
|
804
|
+
} else password += _random([...nonSpecial, ...special]);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return password;
|
|
808
|
+
};
|
|
809
|
+
|
|
688
810
|
// 0x = Hexadecimal
|
|
689
811
|
// 0b = Binary
|
|
690
812
|
// 0o = Octal
|
|
691
813
|
|
|
814
|
+
const userRoleEnum = ['admin', 'moderator', 'user', 'guest'];
|
|
815
|
+
|
|
816
|
+
const commonAdminGuard = (role) => userRoleEnum.indexOf(role) === userRoleEnum.indexOf('admin');
|
|
817
|
+
const commonModeratorGuard = (role) => userRoleEnum.indexOf(role) <= userRoleEnum.indexOf('moderator');
|
|
818
|
+
|
|
692
819
|
export {
|
|
693
820
|
s4,
|
|
694
821
|
range,
|
|
@@ -727,10 +854,9 @@ export {
|
|
|
727
854
|
getSubpaths,
|
|
728
855
|
formatBytes,
|
|
729
856
|
getDirname,
|
|
730
|
-
isDayValid,
|
|
731
|
-
isMonthValid,
|
|
732
857
|
isValidDate,
|
|
733
858
|
isValidFormat,
|
|
859
|
+
strToDateUTC,
|
|
734
860
|
getTimezoneOffset,
|
|
735
861
|
cleanString,
|
|
736
862
|
splitEveryXChar,
|
|
@@ -742,4 +868,9 @@ export {
|
|
|
742
868
|
getCapVariableName,
|
|
743
869
|
hexToNumber,
|
|
744
870
|
numberToHex,
|
|
871
|
+
generateRandomPasswordSelection,
|
|
872
|
+
userRoleEnum,
|
|
873
|
+
commonAdminGuard,
|
|
874
|
+
commonModeratorGuard,
|
|
875
|
+
isChileanIdentityDocument,
|
|
745
876
|
};
|
|
@@ -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);
|
|
@@ -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
|
-
|
|
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';
|
|
@@ -147,6 +149,10 @@ const Input = {
|
|
|
147
149
|
htmls(`.file-name-render-${inputData.id}`, `${s(`.${inputData.id}`).fileNameInputExtDefaultContent}`);
|
|
148
150
|
continue;
|
|
149
151
|
break;
|
|
152
|
+
case 'dropdown-checkbox': {
|
|
153
|
+
s(`.dropdown-option-${inputData.id}-reset`).click();
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
150
156
|
case 'md':
|
|
151
157
|
RichText.Tokens[inputData.id].easyMDE.value('');
|
|
152
158
|
continue;
|
|
@@ -196,6 +202,12 @@ const Input = {
|
|
|
196
202
|
RichText.Tokens[inputData.id].easyMDE.value(fileObj[inputData.model].mdPlain);
|
|
197
203
|
continue;
|
|
198
204
|
break;
|
|
205
|
+
|
|
206
|
+
case 'dropdown-checkbox': {
|
|
207
|
+
s(`.dropdown-option-${inputData.id}-reset`).click();
|
|
208
|
+
for (const opt of originObj[inputData.model]) s(`.dropdown-option-${inputData.id}-${opt}`).click();
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
199
211
|
case 'checkbox':
|
|
200
212
|
case 'checkbox-on-off':
|
|
201
213
|
if (
|
|
@@ -207,9 +219,11 @@ const Input = {
|
|
|
207
219
|
break;
|
|
208
220
|
case 'datetime-local':
|
|
209
221
|
{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
222
|
+
if (isValidDate(originObj[inputData.model])) {
|
|
223
|
+
const date = new Date(originObj[inputData.model]);
|
|
224
|
+
// date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
|
225
|
+
s(`.${inputData.id}`).value = date.toISOString().slice(0, 16);
|
|
226
|
+
} else s(`.${inputData.id}`).value = null;
|
|
213
227
|
}
|
|
214
228
|
continue;
|
|
215
229
|
break;
|
|
@@ -403,6 +403,11 @@ const Modal = {
|
|
|
403
403
|
})}
|
|
404
404
|
</div>
|
|
405
405
|
</div>
|
|
406
|
+
${options?.slideMenuTopBarFix
|
|
407
|
+
? html`<div class="abs modal slide-menu-top-bar-fix" style="height: ${options.heightTopBar}px">
|
|
408
|
+
${await options.slideMenuTopBarFix()}
|
|
409
|
+
</div>`
|
|
410
|
+
: ''}
|
|
406
411
|
</div>`,
|
|
407
412
|
);
|
|
408
413
|
EventsUI.onClick(`.action-btn-profile-log-in`, () => {
|
|
@@ -537,12 +542,12 @@ const Modal = {
|
|
|
537
542
|
if (routerId) {
|
|
538
543
|
if (
|
|
539
544
|
s(`.main-btn-${routerId}`) &&
|
|
540
|
-
(routerId.
|
|
545
|
+
(routerId.toLowerCase().match(s(`.${id}`).value.toLowerCase()) ||
|
|
541
546
|
(Translate.Data[routerId] &&
|
|
542
547
|
Object.keys(Translate.Data[routerId]).filter((keyLang) =>
|
|
543
548
|
Translate.Data[routerId][keyLang]
|
|
544
|
-
.
|
|
545
|
-
.match(s(`.${id}`).value.
|
|
549
|
+
.toLowerCase()
|
|
550
|
+
.match(s(`.${id}`).value.toLowerCase()),
|
|
546
551
|
).length > 0))
|
|
547
552
|
) {
|
|
548
553
|
const fontAwesomeIcon = getAllChildNodes(s(`.main-btn-${routerId}`)).find((e) => {
|
|
@@ -1691,7 +1696,7 @@ const Modal = {
|
|
|
1691
1696
|
const htmlRender = html`
|
|
1692
1697
|
<br />
|
|
1693
1698
|
<div class="in section-mp" style="font-size: 40px; text-align: center">
|
|
1694
|
-
<i class="fas fa-question-circle"></i
|
|
1699
|
+
${options.icon ? options.icon : html` <i class="fas fa-question-circle"></i>`}
|
|
1695
1700
|
</div>
|
|
1696
1701
|
${await options.html()}
|
|
1697
1702
|
<div class="in section-mp">
|
|
@@ -1702,7 +1707,7 @@ const Modal = {
|
|
|
1702
1707
|
style: `margin: auto`,
|
|
1703
1708
|
})}
|
|
1704
1709
|
</div>
|
|
1705
|
-
<div class="in section-mp">
|
|
1710
|
+
<div class="in section-mp ${options.disableBtnCancel ? 'hide' : ''}">
|
|
1706
1711
|
${await BtnIcon.Render({
|
|
1707
1712
|
class: `in section-mp form-button btn-cancel-${id}`,
|
|
1708
1713
|
label: Translate.Render('cancel'),
|
|
@@ -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';
|
|
@@ -51,8 +51,6 @@ const Panel = {
|
|
|
51
51
|
<i style="font-size: 25px" class="fa-solid fa-cloud"></i>
|
|
52
52
|
</div>`;
|
|
53
53
|
|
|
54
|
-
let editId;
|
|
55
|
-
|
|
56
54
|
const openPanelForm = () => {
|
|
57
55
|
s(`.${idPanel}-form-body`).classList.remove('hide');
|
|
58
56
|
s(`.btn-${idPanel}-add`).classList.add('hide');
|
|
@@ -72,7 +70,7 @@ const Panel = {
|
|
|
72
70
|
};
|
|
73
71
|
|
|
74
72
|
const renderPanel = async (payload) => {
|
|
75
|
-
const obj = payload;
|
|
73
|
+
const obj = newInstance(payload);
|
|
76
74
|
if ('_id' in obj) obj.id = obj._id;
|
|
77
75
|
const { id } = obj;
|
|
78
76
|
|
|
@@ -98,8 +96,8 @@ const Panel = {
|
|
|
98
96
|
});
|
|
99
97
|
EventsUI.onClick(`.${idPanel}-btn-edit-${id}`, async () => {
|
|
100
98
|
logger.warn('edit', obj);
|
|
101
|
-
if (obj._id) editId = obj._id;
|
|
102
|
-
else if (obj.id) editId = obj.id;
|
|
99
|
+
if (obj._id) Panel.Tokens[idPanel].editId = obj._id;
|
|
100
|
+
else if (obj.id) Panel.Tokens[idPanel].editId = obj.id;
|
|
103
101
|
|
|
104
102
|
s(`.btn-${idPanel}-label-edit`).classList.remove('hide');
|
|
105
103
|
s(`.btn-${idPanel}-label-add`).classList.add('hide');
|
|
@@ -171,6 +169,10 @@ const Panel = {
|
|
|
171
169
|
const valueIcon = formObjData?.panel?.icon?.value ? formObjData.panel.icon.value : '';
|
|
172
170
|
const keyIcon = formObjData?.panel?.icon?.key ? formObjData.panel.icon.key : '';
|
|
173
171
|
|
|
172
|
+
if (formObjData && ['datetime-local'].includes(formObjData.inputType) && isValidDate(obj[infoKey])) {
|
|
173
|
+
obj[infoKey] = `${obj[infoKey]}`.replace('T', ' ').replace('.000Z', '');
|
|
174
|
+
}
|
|
175
|
+
|
|
174
176
|
if (formData.find((f) => f.model === infoKey && f.panel && f.panel.type === 'tags')) {
|
|
175
177
|
setTimeout(async () => {
|
|
176
178
|
let tagRender = html``;
|
|
@@ -186,22 +188,50 @@ const Panel = {
|
|
|
186
188
|
});
|
|
187
189
|
return html``;
|
|
188
190
|
}
|
|
191
|
+
{
|
|
192
|
+
const formDataObj = formData.find((f) => f.model === infoKey && f.panel && f.panel.type === 'list');
|
|
193
|
+
if (obj[infoKey] && obj[infoKey].length > 0 && formDataObj)
|
|
194
|
+
return html`<div class="in ${idPanel}-row">
|
|
195
|
+
<span class="${idPanel}-row-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
|
|
196
|
+
${keyIcon} ${Translate.Render(infoKey)}:</span
|
|
197
|
+
>
|
|
198
|
+
<span class="${idPanel}-row-value"
|
|
199
|
+
>${valueIcon} ${obj[infoKey].map((k) => Translate.Render(k)).join(', ')}</span
|
|
200
|
+
>
|
|
201
|
+
</div> `;
|
|
202
|
+
}
|
|
189
203
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
204
|
+
{
|
|
205
|
+
const formDataObj = formData.find(
|
|
206
|
+
(f) => f.model === infoKey && f.panel && f.panel.type === 'info-row-pin',
|
|
207
|
+
);
|
|
208
|
+
if (obj[infoKey] && formDataObj)
|
|
209
|
+
return html`<div class="in ${idPanel}-row">
|
|
210
|
+
<span class="${idPanel}-row-pin-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
|
|
211
|
+
${keyIcon}
|
|
212
|
+
${formDataObj.translateCode
|
|
213
|
+
? Translate.Render(formDataObj.translateCode)
|
|
214
|
+
: Translate.Render(infoKey)}:</span
|
|
215
|
+
>
|
|
216
|
+
<span class="${idPanel}-row-pin-value">${valueIcon} ${obj[infoKey]}</span>
|
|
217
|
+
</div> `;
|
|
218
|
+
}
|
|
197
219
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
220
|
+
{
|
|
221
|
+
const formDataObj = formData.find(
|
|
222
|
+
(f) => f.model === infoKey && f.panel && f.panel.type === 'info-row',
|
|
223
|
+
);
|
|
224
|
+
if (obj[infoKey] && formDataObj)
|
|
225
|
+
return html`<div class="in ${idPanel}-row">
|
|
226
|
+
<span class="${idPanel}-row-key capitalize ${formObjData.label?.disabled ? 'hide' : ''}">
|
|
227
|
+
${keyIcon}
|
|
228
|
+
${formDataObj.translateCode
|
|
229
|
+
? Translate.Render(formDataObj.translateCode)
|
|
230
|
+
: Translate.Render(infoKey)}:</span
|
|
231
|
+
>
|
|
232
|
+
<span class="${idPanel}-row-value"> ${valueIcon} ${obj[infoKey]}</span>
|
|
233
|
+
</div> `;
|
|
234
|
+
}
|
|
205
235
|
|
|
206
236
|
return html``;
|
|
207
237
|
})
|
|
@@ -224,6 +254,30 @@ const Panel = {
|
|
|
224
254
|
for (const modelData of formData) {
|
|
225
255
|
if (modelData.disableRender) continue;
|
|
226
256
|
switch (modelData.inputType) {
|
|
257
|
+
case 'dropdown-checkbox': {
|
|
258
|
+
renderForm += html`<div class="in section-mp">
|
|
259
|
+
${await DropDown.Render({
|
|
260
|
+
id: `${modelData.id}`,
|
|
261
|
+
label: html`${Translate.Render(modelData.model)}`,
|
|
262
|
+
type: 'checkbox',
|
|
263
|
+
value: modelData.dropdown.options[0],
|
|
264
|
+
resetOption: true,
|
|
265
|
+
containerClass: `${idPanel}-dropdown-checkbox`,
|
|
266
|
+
data: modelData.dropdown.options.map((dKey) => {
|
|
267
|
+
return {
|
|
268
|
+
value: dKey,
|
|
269
|
+
data: dKey,
|
|
270
|
+
checked: false,
|
|
271
|
+
display: html`${Translate.Render(dKey)}`,
|
|
272
|
+
onClick: function () {
|
|
273
|
+
logger.info('DropDown onClick', this.checked);
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
}),
|
|
277
|
+
})}
|
|
278
|
+
</div>`;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
227
281
|
case 'dropdown':
|
|
228
282
|
renderForm += html` <div class="in section-mp">
|
|
229
283
|
${await DropDown.Render({
|
|
@@ -418,21 +472,23 @@ const Panel = {
|
|
|
418
472
|
obj.id = `${data.length}`;
|
|
419
473
|
let documents;
|
|
420
474
|
if (options && options.on && options.on.add) {
|
|
421
|
-
const { status, data } = await options.on.add({ data: obj, editId });
|
|
475
|
+
const { status, data } = await options.on.add({ data: obj, editId: Panel.Tokens[idPanel].editId });
|
|
422
476
|
if (status === 'error') return;
|
|
423
477
|
documents = data;
|
|
424
478
|
}
|
|
425
479
|
s(`.btn-${idPanel}-clean`).click();
|
|
426
|
-
if (editId && s(`.${idPanel}-${
|
|
480
|
+
if (Panel.Tokens[idPanel].editId && s(`.${idPanel}-${Panel.Tokens[idPanel].editId}`))
|
|
481
|
+
s(`.${idPanel}-${Panel.Tokens[idPanel].editId}`).remove();
|
|
427
482
|
if (Array.isArray(documents)) {
|
|
428
483
|
htmls(`.${idPanel}-render`, '');
|
|
429
484
|
for (const doc of documents) {
|
|
430
485
|
append(`.${idPanel}-render`, await renderPanel(doc));
|
|
431
486
|
}
|
|
432
|
-
} else htmls(`.${idPanel}-render`, await renderPanel(obj));
|
|
487
|
+
} else htmls(`.${idPanel}-render`, await renderPanel({ ...obj, ...documents }));
|
|
433
488
|
Input.cleanValues(formData);
|
|
434
489
|
s(`.btn-${idPanel}-close`).click();
|
|
435
490
|
s(`.${scrollClassContainer}`).scrollTop = 0;
|
|
491
|
+
if (s(`.${scrollClassContainer}`)) s(`.${scrollClassContainer}`).style.overflow = 'auto';
|
|
436
492
|
});
|
|
437
493
|
s(`.btn-${idPanel}-clean`).onclick = () => {
|
|
438
494
|
Input.cleanValues(formData);
|
|
@@ -458,13 +514,14 @@ const Panel = {
|
|
|
458
514
|
s(`.btn-${idPanel}-add`).onclick = (e) => {
|
|
459
515
|
e.preventDefault();
|
|
460
516
|
// s(`.btn-${idPanel}-clean`).click();
|
|
461
|
-
editId = undefined;
|
|
517
|
+
Panel.Tokens[idPanel].editId = undefined;
|
|
462
518
|
s(`.btn-${idPanel}-label-add`).classList.remove('hide');
|
|
463
519
|
s(`.btn-${idPanel}-label-edit`).classList.add('hide');
|
|
464
520
|
s(`.${scrollClassContainer}`).scrollTop = 0;
|
|
465
521
|
|
|
466
522
|
openPanelForm();
|
|
467
523
|
};
|
|
524
|
+
if (s(`.${scrollClassContainer}`)) s(`.${scrollClassContainer}`).style.overflow = 'auto';
|
|
468
525
|
});
|
|
469
526
|
|
|
470
527
|
if (data.length > 0) for (const obj of data) render += await renderPanel(obj);
|
|
@@ -597,7 +654,9 @@ const Panel = {
|
|
|
597
654
|
>
|
|
598
655
|
<div class="in ${idPanel}-form-header">
|
|
599
656
|
${await BtnIcon.Render({
|
|
600
|
-
class: `section-mp btn-custom btn-${idPanel}-add
|
|
657
|
+
class: `section-mp btn-custom btn-${idPanel}-add ${
|
|
658
|
+
options?.role?.add ? (!options.role.add() ? 'hide' : '') : ''
|
|
659
|
+
}`,
|
|
601
660
|
label: html`<i class="fas fa-plus"></i> ${Translate.Render('add')}`,
|
|
602
661
|
type: 'button',
|
|
603
662
|
})}
|
|
@@ -90,16 +90,7 @@ const PanelForm = {
|
|
|
90
90
|
},
|
|
91
91
|
},
|
|
92
92
|
];
|
|
93
|
-
|
|
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
|
-
>`;
|
|
93
|
+
|
|
103
94
|
const titleIcon = html`<i class="fa-solid fa-quote-left"></i>`;
|
|
104
95
|
const panelRender = async ({ data }) =>
|
|
105
96
|
await Panel.Render({
|
|
@@ -271,7 +262,7 @@ const PanelForm = {
|
|
|
271
262
|
fileId: file ? URL.createObjectURL(file) : undefined,
|
|
272
263
|
_id: documentData._id,
|
|
273
264
|
id: documentData._id,
|
|
274
|
-
createdAt:
|
|
265
|
+
createdAt: documentData.createdAt,
|
|
275
266
|
};
|
|
276
267
|
|
|
277
268
|
if (documentStatus === 'error') status = 'error';
|
|
@@ -376,7 +367,7 @@ const PanelForm = {
|
|
|
376
367
|
PanelForm.Data[idPanel].data.push({
|
|
377
368
|
id: documentObject._id,
|
|
378
369
|
title: documentObject.title,
|
|
379
|
-
createdAt:
|
|
370
|
+
createdAt: documentObject.createdAt,
|
|
380
371
|
tags: documentObject.tags.filter((t) => !prefixTags.includes(t)),
|
|
381
372
|
mdFileId: marked.parse(mdFileId),
|
|
382
373
|
userId: documentObject.userId._id,
|
|
@@ -431,14 +422,9 @@ const PanelForm = {
|
|
|
431
422
|
})),
|
|
432
423
|
});
|
|
433
424
|
|
|
434
|
-
let lastCid;
|
|
435
|
-
let lasUserId;
|
|
436
425
|
this.Data[idPanel].updatePanel = async () => {
|
|
437
426
|
const cid = getQueryParams().cid ? getQueryParams().cid : '';
|
|
438
|
-
if (lastCid === cid && lasUserId === Elements.Data.user.main.model.user._id) return;
|
|
439
427
|
if (options.route === 'home') Modal.homeCid = newInstance(cid);
|
|
440
|
-
lastCid = cid;
|
|
441
|
-
lasUserId = newInstance(Elements.Data.user.main.model.user._id);
|
|
442
428
|
htmls(`.${options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body'}`, await renderSrrPanelData());
|
|
443
429
|
await getPanelData();
|
|
444
430
|
htmls(
|
|
@@ -451,7 +437,7 @@ const PanelForm = {
|
|
|
451
437
|
id: options.parentIdModal ? 'html-' + options.parentIdModal : 'main-body',
|
|
452
438
|
routeId: options.route,
|
|
453
439
|
event: async (path) => {
|
|
454
|
-
await this.Data[idPanel].updatePanel();
|
|
440
|
+
if (!PanelForm.Data[idPanel].sessionIn) await this.Data[idPanel].updatePanel();
|
|
455
441
|
},
|
|
456
442
|
});
|
|
457
443
|
|
|
@@ -11,35 +11,49 @@ const Translate = {
|
|
|
11
11
|
Data: {},
|
|
12
12
|
Token: {},
|
|
13
13
|
Event: {},
|
|
14
|
+
Options: {},
|
|
14
15
|
Parse: function (lang) {
|
|
15
16
|
s('html').lang = lang;
|
|
16
17
|
Object.keys(this.Token).map((translateHash) => {
|
|
17
18
|
if (translateHash in this.Token && lang in this.Token[translateHash]) {
|
|
18
|
-
if (!('placeholder' in this.
|
|
19
|
-
htmls(
|
|
19
|
+
if (!('placeholder' in this.Options[translateHash]) && s(`.${translateHash}`))
|
|
20
|
+
htmls(
|
|
21
|
+
`.${translateHash}`,
|
|
22
|
+
this.Options[translateHash]?.disableTextFormat
|
|
23
|
+
? this.Token[translateHash][lang]
|
|
24
|
+
: textFormatted(this.Token[translateHash][lang]),
|
|
25
|
+
);
|
|
20
26
|
else if ('placeholder' in this.Token[translateHash] && s(this.Token[translateHash].placeholder))
|
|
21
|
-
s(this.Token[translateHash].placeholder).placeholder =
|
|
27
|
+
s(this.Token[translateHash].placeholder).placeholder = this.Options[translateHash]?.disableTextFormat
|
|
28
|
+
? this.Token[translateHash][lang]
|
|
29
|
+
: textFormatted(this.Token[translateHash][lang]);
|
|
22
30
|
}
|
|
23
31
|
});
|
|
24
32
|
for (const keyEvent of Object.keys(this.Event)) this.Event[keyEvent]();
|
|
25
33
|
},
|
|
26
|
-
Render: function (keyLang, placeholder) {
|
|
34
|
+
Render: function (keyLang, placeholder, options = { disableTextFormat: false }) {
|
|
27
35
|
if (!(keyLang in this.Data)) {
|
|
28
36
|
// TODO: add translate package or library for this case
|
|
29
37
|
logger.warn('translate key lang does not exist: ', keyLang);
|
|
30
|
-
return textFormatted(keyLang);
|
|
38
|
+
return options.disableTextFormat ? keyLang : textFormatted(keyLang);
|
|
31
39
|
}
|
|
32
40
|
if (placeholder) this.Data[keyLang].placeholder = placeholder;
|
|
33
41
|
keyLang = this.Data[keyLang];
|
|
34
42
|
const translateHash = getId(this.Token, 'trans');
|
|
43
|
+
this.Options[translateHash] = options;
|
|
35
44
|
this.Token[translateHash] = newInstance(keyLang);
|
|
36
45
|
if ('placeholder' in keyLang) {
|
|
37
|
-
if (s('html').lang in keyLang)
|
|
38
|
-
|
|
46
|
+
if (s('html').lang in keyLang)
|
|
47
|
+
return options.disableTextFormat ? keyLang[s('html').lang] : textFormatted(keyLang[s('html').lang]);
|
|
48
|
+
return options.disableTextFormat ? keyLang['en'] : textFormatted(keyLang['en']);
|
|
39
49
|
}
|
|
40
50
|
if (s('html').lang in keyLang)
|
|
41
|
-
return html`<span class="${translateHash}"
|
|
42
|
-
|
|
51
|
+
return html`<span class="${translateHash}"
|
|
52
|
+
>${options.disableTextFormat ? keyLang[s('html').lang] : textFormatted(keyLang[s('html').lang])}</span
|
|
53
|
+
>`;
|
|
54
|
+
return html`<span class="${translateHash}"
|
|
55
|
+
>${options.disableTextFormat ? keyLang['en'] : textFormatted(keyLang['en'])}</span
|
|
56
|
+
>`;
|
|
43
57
|
},
|
|
44
58
|
renderLang: function (language) {
|
|
45
59
|
localStorage.setItem('lang', language);
|
|
@@ -474,6 +488,26 @@ const TranslateCore = {
|
|
|
474
488
|
Translate.Data['friday'] = { es: 'Viernes', en: 'Friday' };
|
|
475
489
|
Translate.Data['saturday'] = { es: 'Sábado', en: 'Saturday' };
|
|
476
490
|
Translate.Data['sunday'] = { es: 'Domingo', en: 'Sunday' };
|
|
491
|
+
|
|
492
|
+
Translate.Data['description'] = { es: 'Descripción', en: 'Description' };
|
|
493
|
+
Translate.Data['daysOfWeek'] = { es: 'Días de la semana', en: 'Days of the week' };
|
|
494
|
+
Translate.Data['startTime'] = { es: 'Hora de inicio', en: 'Start time' };
|
|
495
|
+
Translate.Data['endTime'] = { es: 'Hora de finalizacion', en: 'End time' };
|
|
496
|
+
Translate.Data['appointment-scheduled'] = {
|
|
497
|
+
en: 'Your appointment has been scheduled',
|
|
498
|
+
es: 'Tu cita ha sido programada',
|
|
499
|
+
};
|
|
500
|
+
Translate.Data['info'] = { es: 'Información', en: 'Info' };
|
|
501
|
+
Translate.Data['complete-name'] = { es: 'Nombre completo', en: 'Complete name' };
|
|
502
|
+
Translate.Data['identityDocument'] = { es: 'Rut', en: 'Identity document' };
|
|
503
|
+
Translate.Data['day'] = { es: 'Día', en: 'Day' };
|
|
504
|
+
Translate.Data['month'] = { es: 'Mes', en: 'Month' };
|
|
505
|
+
Translate.Data['year'] = { es: 'Año', en: 'Year' };
|
|
506
|
+
Translate.Data['phone'] = { es: 'Teléfono', en: 'Phone' };
|
|
507
|
+
Translate.Data['invalid-identity-document'] = {
|
|
508
|
+
en: 'Invalid identity document',
|
|
509
|
+
es: 'Documento de identidad inválido',
|
|
510
|
+
};
|
|
477
511
|
},
|
|
478
512
|
};
|
|
479
513
|
|