underpost 2.8.85 → 2.8.86
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/.env.development +1 -1
- package/.env.production +1 -1
- package/.env.test +1 -1
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
- package/.github/workflows/release.cd.yml +37 -0
- package/README.md +7 -44
- package/bin/cyberia0.js +78 -0
- package/bin/db.js +1 -3
- package/bin/deploy.js +13 -350
- package/bin/file.js +11 -1
- package/cli.md +39 -19
- package/manifests/deployment/{dd-template-development → dd-default-development}/deployment.yaml +16 -16
- package/manifests/deployment/{dd-template-development → dd-default-development}/proxy.yaml +3 -3
- package/manifests/grafana/deployment.yaml +57 -0
- package/manifests/grafana/kustomization.yaml +7 -0
- package/manifests/grafana/pvc.yaml +12 -0
- package/manifests/grafana/service.yaml +14 -0
- package/manifests/maas/ssh-cluster-info.sh +14 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/package.json +1 -2
- package/src/api/user/user.service.js +8 -34
- package/src/cli/cluster.js +41 -2
- package/src/cli/cron.js +12 -45
- package/src/cli/db.js +149 -0
- package/src/cli/deploy.js +20 -81
- package/src/cli/index.js +20 -6
- package/src/cli/monitor.js +1 -4
- package/src/cli/repository.js +12 -5
- package/src/cli/run.js +77 -14
- package/src/client/Default.index.js +0 -2
- package/src/client/components/core/Account.js +6 -2
- package/src/client/components/core/Content.js +11 -7
- package/src/client/components/core/Css.js +5 -1
- package/src/client/components/core/Input.js +6 -1
- package/src/client/components/core/LogIn.js +3 -0
- package/src/client/components/core/LogOut.js +1 -1
- package/src/client/components/core/Modal.js +7 -4
- package/src/client/components/core/Recover.js +5 -2
- package/src/client/components/core/Scroll.js +65 -120
- package/src/client/components/core/SignUp.js +1 -0
- package/src/client/components/core/VanillaJs.js +48 -2
- package/src/client/components/default/MenuDefault.js +2 -2
- package/src/client/components/default/RoutesDefault.js +3 -3
- package/src/index.js +1 -1
- package/src/mailer/MailerProvider.js +37 -0
- package/src/server/client-build-live.js +1 -1
- package/src/server/client-dev-server.js +1 -1
- package/src/server/conf.js +2 -272
- package/src/server/proxy.js +1 -2
- package/src/server/start.js +3 -3
- package/docker-compose.yml +0 -67
- package/prometheus.yml +0 -36
|
@@ -1,131 +1,76 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Modal } from './Modal.js';
|
|
3
|
-
import { append, s } from './VanillaJs.js';
|
|
1
|
+
import { s } from './VanillaJs.js';
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
class Scroll {
|
|
4
|
+
/**
|
|
5
|
+
* Attach scroll listener to an element (resolved with s(selector)).
|
|
6
|
+
* @param {string} selector - selector passed to s(selector)
|
|
7
|
+
* @param {function} [callback] - callback function to be called on scroll
|
|
8
|
+
* @param {object} options
|
|
9
|
+
* @param {number} [options.threshold=1] - px margin to treat as bottom
|
|
10
|
+
* @param {number} [options.precision=3] - decimal places for percentages
|
|
11
|
+
*/
|
|
12
|
+
static setEvent(selector, callback = async () => {}, options = { threshold: 1, precision: 3 }) {
|
|
13
|
+
const el = s(selector);
|
|
14
|
+
if (!el) return;
|
|
15
|
+
|
|
16
|
+
const threshold = options.threshold ?? 1; // px tolerance for bottom detection
|
|
17
|
+
const precision = options.precision ?? 3;
|
|
18
|
+
let ticking = false;
|
|
19
|
+
|
|
20
|
+
const round = (v) => {
|
|
21
|
+
const m = Math.pow(10, precision);
|
|
22
|
+
return Math.round(v * m) / m;
|
|
11
23
|
};
|
|
12
|
-
return Scroll.data[selector];
|
|
13
|
-
},
|
|
14
|
-
getScrollPosition: function (selector) {
|
|
15
|
-
// Scroll.data[selector].element.clientHeight -
|
|
16
|
-
return Scroll.data[selector].element.scrollTop;
|
|
17
|
-
},
|
|
18
|
-
scrollHandler: async function () {
|
|
19
|
-
for (const selector in Scroll.data) await Scroll.data[selector].callback(Scroll.getScrollPosition(selector));
|
|
20
|
-
},
|
|
21
|
-
addEvent: function (selector = '', callback = (position = 0) => {}) {
|
|
22
|
-
Scroll.data[selector].callback = callback;
|
|
23
|
-
},
|
|
24
|
-
removeEvent: function (selector) {
|
|
25
|
-
delete Scroll.data[selector];
|
|
26
|
-
},
|
|
27
|
-
to: function (elector = '', options = { top: 100, left: 100, behavior: 'smooth' }) {
|
|
28
|
-
Scroll.data[selector].element.scrollTo({
|
|
29
|
-
top: options.top || Scroll.getScrollPosition(selector),
|
|
30
|
-
left: options.left || 0,
|
|
31
|
-
behavior: options.behavior || 'smooth',
|
|
32
|
-
});
|
|
33
|
-
},
|
|
34
|
-
topRefreshEvents: {},
|
|
35
|
-
addTopRefreshEvent: function (options = { id: '', callback: () => {}, condition: () => {} }) {
|
|
36
|
-
this.topRefreshEvents[options.id] = options;
|
|
37
|
-
},
|
|
38
|
-
removeTopRefreshEvent: function (id = '') {
|
|
39
|
-
delete this.topRefreshEvents[id];
|
|
40
|
-
},
|
|
41
|
-
pullTopRefresh: function () {
|
|
42
|
-
return;
|
|
43
|
-
append(
|
|
44
|
-
'body',
|
|
45
|
-
html` <style>
|
|
46
|
-
.pull-refresh-icon-container {
|
|
47
|
-
height: 60px;
|
|
48
|
-
width: 100%;
|
|
49
|
-
z-index: 10;
|
|
50
|
-
transition: 0.3s;
|
|
51
|
-
left: 0px;
|
|
52
|
-
}
|
|
53
|
-
.pull-refresh-icon {
|
|
54
|
-
width: 60px;
|
|
55
|
-
height: 60px;
|
|
56
|
-
margin: auto;
|
|
57
|
-
color: white;
|
|
58
|
-
font-size: 30px;
|
|
59
|
-
}
|
|
60
|
-
</style>
|
|
61
|
-
${borderChar(2, 'black', [' .pull-refresh-icon-container'])}
|
|
62
|
-
<div style="top: -60px" class="abs pull-refresh-icon-container">
|
|
63
|
-
<div class="in pull-refresh-icon">
|
|
64
|
-
<div class="abs center"><i class="fa-solid fa-arrows-rotate"></i></div>
|
|
65
|
-
</div>
|
|
66
|
-
</div>`,
|
|
67
|
-
);
|
|
68
24
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
25
|
+
const listener = (event) => {
|
|
26
|
+
if (ticking) return;
|
|
27
|
+
ticking = true;
|
|
28
|
+
|
|
29
|
+
requestAnimationFrame(() => {
|
|
30
|
+
const scrollHeight = el.scrollHeight;
|
|
31
|
+
const clientHeight = el.clientHeight;
|
|
32
|
+
const scrollTop = el.scrollTop;
|
|
33
|
+
|
|
34
|
+
// pixels left to scroll (clamped to >= 0)
|
|
35
|
+
const remaining = Math.max(0, scrollHeight - clientHeight - scrollTop);
|
|
73
36
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// console.warn('touchstart', touchstartY);
|
|
77
|
-
});
|
|
37
|
+
// maximum possible remaining (0 if content fits without scrolling)
|
|
38
|
+
const maxRemaining = Math.max(0, scrollHeight - clientHeight);
|
|
78
39
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
(!s(`.btn-bar-center-icon-close`).classList.contains('hide') &&
|
|
83
|
-
!s(
|
|
84
|
-
`.btn-icon-menu-mode-${Modal.Data['modal-menu'].options.mode !== 'slide-menu-right' ? 'left' : 'right'}`,
|
|
85
|
-
).classList.contains('hide'))
|
|
86
|
-
)
|
|
87
|
-
return;
|
|
40
|
+
// percentRemaining: 1 = top (all remaining), 0 = bottom (none remaining)
|
|
41
|
+
let percentRemaining = maxRemaining === 0 ? 0 : remaining / maxRemaining;
|
|
42
|
+
percentRemaining = Math.max(0, Math.min(1, percentRemaining));
|
|
88
43
|
|
|
89
|
-
|
|
90
|
-
|
|
44
|
+
// percentScrolled: complementary value (0 = top, 1 = bottom)
|
|
45
|
+
let percentScrolled = 1 - percentRemaining;
|
|
46
|
+
percentScrolled = Math.max(0, Math.min(1, percentScrolled));
|
|
91
47
|
|
|
92
|
-
|
|
48
|
+
const payload = {
|
|
49
|
+
scrollHeight,
|
|
50
|
+
clientHeight,
|
|
51
|
+
scrollTop,
|
|
52
|
+
remaining, // px left (>= 0)
|
|
53
|
+
scrollBottom: remaining <= threshold ? 0 : remaining,
|
|
54
|
+
atBottom: remaining <= threshold,
|
|
55
|
+
percentRemaining: round(percentRemaining), // 0..1
|
|
56
|
+
percentScrolled: round(percentScrolled), // 0..1
|
|
57
|
+
};
|
|
93
58
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
59
|
+
// replace this with an event dispatch or callback if you prefer
|
|
60
|
+
// console.warn('scroll', event, JSON.stringify(payload, null, 2));
|
|
61
|
+
callback(payload);
|
|
97
62
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (Scroll.topRefreshEvents[event].condition()) Scroll.topRefreshEvents[event].callback();
|
|
110
|
-
}
|
|
111
|
-
reload = false;
|
|
112
|
-
});
|
|
113
|
-
Scroll.addTopRefreshEvent({
|
|
114
|
-
id: 'main-body',
|
|
115
|
-
callback: () => {
|
|
116
|
-
location.reload();
|
|
117
|
-
},
|
|
118
|
-
condition: () => {
|
|
119
|
-
return (
|
|
120
|
-
s('.main-body') &&
|
|
121
|
-
s('.main-body').scrollTop === 0 &&
|
|
122
|
-
!Object.keys(Modal.Data).find(
|
|
123
|
-
(idModal) => !['modal-menu', 'main-body', 'bottom-bar', 'main-body-top'].includes(idModal),
|
|
124
|
-
)
|
|
125
|
-
);
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
},
|
|
129
|
-
};
|
|
63
|
+
ticking = false;
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
el.addEventListener('scroll', listener, { passive: true });
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
removeEvent: () => el.removeEventListener('scroll', listener),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
130
74
|
|
|
131
75
|
export { Scroll };
|
|
76
|
+
export default Scroll;
|
|
@@ -147,8 +147,40 @@ const pasteData = () => new Promise((resolve) => navigator.clipboard.readText().
|
|
|
147
147
|
* @memberof VanillaJS
|
|
148
148
|
*/
|
|
149
149
|
const setPath = (path = '/', stateStorage = {}, title = '') => {
|
|
150
|
-
if (
|
|
151
|
-
|
|
150
|
+
if (!path) path = '/';
|
|
151
|
+
|
|
152
|
+
const [inputPath, inputSearch] = `${path}`.split('?');
|
|
153
|
+
|
|
154
|
+
let sanitizedPath = (inputPath[0] !== '/' ? `/${inputPath}` : inputPath)
|
|
155
|
+
.trim()
|
|
156
|
+
.replaceAll('//', '/')
|
|
157
|
+
.replaceAll(`\\`, '/');
|
|
158
|
+
|
|
159
|
+
if (sanitizedPath.length > 1 && sanitizedPath[sanitizedPath.length - 1] === '/')
|
|
160
|
+
sanitizedPath = sanitizedPath.slice(0, -1);
|
|
161
|
+
|
|
162
|
+
if (window.location.pathname === sanitizedPath && (!inputSearch || inputSearch === location.search)) {
|
|
163
|
+
console.warn('Prevent overwriting same path', {
|
|
164
|
+
inputPath: inputPath,
|
|
165
|
+
inputSearch: inputSearch,
|
|
166
|
+
sanitizedPath: sanitizedPath,
|
|
167
|
+
currentLocationSearch: location.search,
|
|
168
|
+
currentLocationHash: location.hash,
|
|
169
|
+
});
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
console.warn('Set path', {
|
|
173
|
+
inputPath: inputPath,
|
|
174
|
+
inputSearch: inputSearch,
|
|
175
|
+
sanitizedPath: sanitizedPath,
|
|
176
|
+
currentLocationSearch: location.search,
|
|
177
|
+
currentLocationHash: location.hash,
|
|
178
|
+
});
|
|
179
|
+
return history.pushState(
|
|
180
|
+
stateStorage,
|
|
181
|
+
title,
|
|
182
|
+
`${sanitizedPath}${inputSearch ? `?${inputSearch}` : ''}${location.hash ?? ''}`,
|
|
183
|
+
);
|
|
152
184
|
};
|
|
153
185
|
|
|
154
186
|
/**
|
|
@@ -425,6 +457,19 @@ const getLang = () =>
|
|
|
425
457
|
.slice(0, 2)
|
|
426
458
|
.toLowerCase();
|
|
427
459
|
|
|
460
|
+
function hexToRgbA(hex) {
|
|
461
|
+
let c;
|
|
462
|
+
if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {
|
|
463
|
+
c = hex.substring(1).split('');
|
|
464
|
+
if (c.length == 3) {
|
|
465
|
+
c = [c[0], c[0], c[1], c[1], c[2], c[2]];
|
|
466
|
+
}
|
|
467
|
+
c = '0x' + c.join('');
|
|
468
|
+
return [(c >> 16) & 255, (c >> 8) & 255, c & 255];
|
|
469
|
+
}
|
|
470
|
+
throw new Error('Invalid Hex');
|
|
471
|
+
}
|
|
472
|
+
|
|
428
473
|
export {
|
|
429
474
|
s,
|
|
430
475
|
htmls,
|
|
@@ -454,4 +499,5 @@ export {
|
|
|
454
499
|
isDevInstance,
|
|
455
500
|
getDataFromInputFile,
|
|
456
501
|
getLang,
|
|
502
|
+
hexToRgbA,
|
|
457
503
|
};
|
|
@@ -35,7 +35,7 @@ const MenuDefault = {
|
|
|
35
35
|
const id = getId(this.Data, 'menu-');
|
|
36
36
|
this.Data[id] = {};
|
|
37
37
|
const RouterInstance = RouterDefault();
|
|
38
|
-
const {
|
|
38
|
+
const { BannerAppTemplate } = RouterInstance;
|
|
39
39
|
const { barConfig } = await Themes[Css.currentTheme]();
|
|
40
40
|
const heightTopBar = 50;
|
|
41
41
|
const heightBottomBar = 50;
|
|
@@ -162,7 +162,7 @@ const MenuDefault = {
|
|
|
162
162
|
</div>
|
|
163
163
|
`,
|
|
164
164
|
barConfig: newInstance(barConfig),
|
|
165
|
-
title:
|
|
165
|
+
title: BannerAppTemplate,
|
|
166
166
|
// titleClass: 'hide',
|
|
167
167
|
titleRender: () => {
|
|
168
168
|
ThemeEvents['titleRender'] = () => {
|
|
@@ -4,7 +4,7 @@ import { getProxyPath, s } from '../core/VanillaJs.js';
|
|
|
4
4
|
|
|
5
5
|
const logger = loggerFactory(import.meta);
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const BannerAppTemplate = html`<strong class="inl" style="font-family: system-ui">PWA</strong>`;
|
|
8
8
|
|
|
9
9
|
// Router
|
|
10
10
|
const RoutesDefault = () => {
|
|
@@ -39,7 +39,7 @@ const RoutesDefault = () => {
|
|
|
39
39
|
window.Routes = RoutesDefault;
|
|
40
40
|
|
|
41
41
|
const RouterDefault = () => {
|
|
42
|
-
return { Routes: RoutesDefault,
|
|
42
|
+
return { Routes: RoutesDefault, BannerAppTemplate };
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
export { RoutesDefault, RouterDefault,
|
|
45
|
+
export { RoutesDefault, RouterDefault, BannerAppTemplate };
|
package/src/index.js
CHANGED
|
@@ -48,6 +48,43 @@ const MailerProvider = {
|
|
|
48
48
|
...options,
|
|
49
49
|
transporter,
|
|
50
50
|
templates: await EmailRender.getTemplates(options),
|
|
51
|
+
translateTemplates: {
|
|
52
|
+
confirmEmail: {
|
|
53
|
+
H1: {
|
|
54
|
+
en: 'Confirm Your Email',
|
|
55
|
+
es: 'Confirma tu correo electrónico',
|
|
56
|
+
},
|
|
57
|
+
P1: {
|
|
58
|
+
en: `Email confirmed! Thanks.
|
|
59
|
+
<br />
|
|
60
|
+
<span style="font-size: 12px; color: gray">
|
|
61
|
+
If it is not automatically verified,
|
|
62
|
+
please allow the image to be seen, thank you.
|
|
63
|
+
</span>
|
|
64
|
+
`,
|
|
65
|
+
es: `Correo electrónico confirmado! Gracias.
|
|
66
|
+
<br />
|
|
67
|
+
<span style="font-size: 12px; color: gray">
|
|
68
|
+
Si no se verifica automáticamente, por favor permita que se vea la imagen, gracias.
|
|
69
|
+
</span>
|
|
70
|
+
`,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
recoverEmail: {
|
|
74
|
+
H1: {
|
|
75
|
+
en: 'Recover your account',
|
|
76
|
+
es: 'Recupera tu cuenta',
|
|
77
|
+
},
|
|
78
|
+
P1: {
|
|
79
|
+
en: 'To recover your account, please click the button below:',
|
|
80
|
+
es: 'Para recuperar tu cuenta, haz click en el botón de abajo:',
|
|
81
|
+
},
|
|
82
|
+
BTN_LABEL: {
|
|
83
|
+
en: 'Recover Password',
|
|
84
|
+
es: 'Recuperar Contraseña',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
51
88
|
};
|
|
52
89
|
|
|
53
90
|
return this.instance[id];
|
|
@@ -59,7 +59,7 @@ const clientLiveBuild = async () => {
|
|
|
59
59
|
const updates = JSON.parse(fs.readFileSync(`./tmp/client.build.json`, 'utf8'));
|
|
60
60
|
const liveClientBuildPaths = [];
|
|
61
61
|
for (let srcPath of updates) {
|
|
62
|
-
srcPath = srcPath.replaceAll('/', `\\`);
|
|
62
|
+
srcPath = srcPath.replaceAll('/', `\\`);
|
|
63
63
|
|
|
64
64
|
const srcBuildPath = `./src${srcPath.split('src')[1].replace(/\\/g, '/')}`;
|
|
65
65
|
if (
|
|
@@ -7,7 +7,7 @@ const logger = loggerFactory(import.meta);
|
|
|
7
7
|
|
|
8
8
|
const createClientDevServer = () => {
|
|
9
9
|
// process.argv.slice(2).join(' ')
|
|
10
|
-
shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')}
|
|
10
|
+
shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')}`);
|
|
11
11
|
shellExec(
|
|
12
12
|
`env-cmd -f .env.development node src/api ${process.argv[2]}${process.argv[5] ? ` ${process.argv[5]}` : ''}${
|
|
13
13
|
process.argv.includes('static') ? ' static' : ''
|