underpost 2.8.87 → 2.8.88
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 +35 -3
- package/.env.production +39 -4
- package/.env.test +35 -3
- package/.github/workflows/ghpkg.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +1 -1
- package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -5
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +3 -3
- package/README.md +56 -2
- package/bin/build.js +4 -0
- package/bin/deploy.js +62 -8
- package/bin/file.js +3 -2
- package/cli.md +8 -2
- package/conf.js +30 -4
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +174 -0
- package/manifests/deployment/dd-test-development/proxy.yaml +51 -0
- package/package.json +6 -5
- package/src/api/core/core.router.js +2 -1
- package/src/api/default/default.controller.js +6 -1
- package/src/api/default/default.router.js +6 -2
- package/src/api/default/default.service.js +10 -1
- package/src/api/document/document.controller.js +66 -0
- package/src/api/document/document.model.js +51 -0
- package/src/api/document/document.router.js +24 -0
- package/src/api/document/document.service.js +125 -0
- package/src/api/file/file.controller.js +15 -1
- package/src/api/file/file.router.js +2 -1
- package/src/api/test/test.router.js +1 -1
- package/src/api/user/postman_collection.json +216 -0
- package/src/api/user/user.controller.js +25 -60
- package/src/api/user/user.model.js +29 -7
- package/src/api/user/user.router.js +9 -3
- package/src/api/user/user.service.js +84 -32
- package/src/cli/baremetal.js +33 -3
- package/src/cli/cloud-init.js +11 -0
- package/src/cli/cron.js +0 -1
- package/src/cli/deploy.js +46 -23
- package/src/cli/index.js +5 -0
- package/src/cli/lxd.js +7 -0
- package/src/cli/repository.js +42 -6
- package/src/cli/run.js +45 -13
- package/src/cli/ssh.js +20 -6
- package/src/client/Default.index.js +42 -1
- package/src/client/components/core/Account.js +10 -2
- package/src/client/components/core/AgGrid.js +30 -8
- package/src/client/components/core/Auth.js +99 -56
- package/src/client/components/core/BtnIcon.js +3 -2
- package/src/client/components/core/CalendarCore.js +2 -3
- package/src/client/components/core/CommonJs.js +1 -2
- package/src/client/components/core/Content.js +15 -12
- package/src/client/components/core/Css.js +2 -1
- package/src/client/components/core/CssCore.js +6 -1
- package/src/client/components/core/Docs.js +5 -5
- package/src/client/components/core/FileExplorer.js +3 -3
- package/src/client/components/core/Input.js +22 -17
- package/src/client/components/core/JoyStick.js +2 -2
- package/src/client/components/core/LoadingAnimation.js +2 -2
- package/src/client/components/core/LogIn.js +16 -23
- package/src/client/components/core/LogOut.js +5 -1
- package/src/client/components/core/Logger.js +4 -1
- package/src/client/components/core/Modal.js +82 -53
- package/src/client/components/core/ObjectLayerEngineModal.js +2 -1
- package/src/client/components/core/Pagination.js +207 -0
- package/src/client/components/core/Panel.js +10 -10
- package/src/client/components/core/PanelForm.js +130 -33
- package/src/client/components/core/Recover.js +2 -2
- package/src/client/components/core/Router.js +210 -34
- package/src/client/components/core/SignUp.js +1 -2
- package/src/client/components/core/Stream.js +1 -1
- package/src/client/components/core/VanillaJs.js +3 -84
- package/src/client/components/core/Worker.js +2 -2
- package/src/client/components/default/LogInDefault.js +0 -6
- package/src/client/components/default/LogOutDefault.js +0 -16
- package/src/client/components/default/MenuDefault.js +97 -44
- package/src/client/components/default/RoutesDefault.js +5 -2
- package/src/client/services/core/core.service.js +8 -20
- package/src/client/services/default/default.management.js +115 -18
- package/src/client/services/default/default.service.js +13 -4
- package/src/client/services/document/document.service.js +97 -0
- package/src/client/services/file/file.service.js +2 -0
- package/src/client/services/test/test.service.js +3 -0
- package/src/client/services/user/user.management.js +6 -0
- package/src/client/services/user/user.service.js +15 -4
- package/src/client/ssr/Render.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +3 -0
- package/src/client/ssr/head/Seo.js +1 -0
- package/src/index.js +24 -2
- package/src/runtime/lampp/Lampp.js +89 -2
- package/src/runtime/xampp/Xampp.js +48 -1
- package/src/server/auth.js +519 -155
- package/src/server/backup.js +2 -2
- package/src/server/conf.js +66 -8
- package/src/server/process.js +2 -1
- package/src/server/runtime.js +135 -286
- package/src/server/ssl.js +1 -2
- package/src/server/ssr.js +85 -0
- package/src/server/start.js +2 -2
- package/src/server/valkey.js +2 -1
package/src/cli/run.js
CHANGED
|
@@ -7,6 +7,8 @@ import fs from 'fs-extra';
|
|
|
7
7
|
import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
8
8
|
import UnderpostDeploy from './deploy.js';
|
|
9
9
|
import UnderpostRootEnv from './env.js';
|
|
10
|
+
import UnderpostRepository from './repository.js';
|
|
11
|
+
import os from 'os';
|
|
10
12
|
|
|
11
13
|
const logger = loggerFactory(import.meta);
|
|
12
14
|
|
|
@@ -19,6 +21,8 @@ class UnderpostRun {
|
|
|
19
21
|
imageName: '',
|
|
20
22
|
containerName: '',
|
|
21
23
|
namespace: '',
|
|
24
|
+
build: false,
|
|
25
|
+
replicas: 1,
|
|
22
26
|
};
|
|
23
27
|
static RUNNERS = {
|
|
24
28
|
'spark-template': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
@@ -26,9 +30,9 @@ class UnderpostRun {
|
|
|
26
30
|
shellExec(`sudo rm -rf ${dir}`);
|
|
27
31
|
shellCd('/home/dd');
|
|
28
32
|
|
|
29
|
-
// pbcopy(`cd /home/dd && sbt new
|
|
33
|
+
// pbcopy(`cd /home/dd && sbt new ${process.env.GITHUB_USERNAME}/spark-template.g8`);
|
|
30
34
|
// await read({ prompt: 'Command copy to clipboard, press enter to continue.\n' });
|
|
31
|
-
shellExec(`cd /home/dd && sbt new
|
|
35
|
+
shellExec(`cd /home/dd && sbt new ${process.env.GITHUB_USERNAME}/spark-template.g8 '--name=spark-template'`);
|
|
32
36
|
|
|
33
37
|
shellCd(dir);
|
|
34
38
|
|
|
@@ -103,10 +107,12 @@ class UnderpostRun {
|
|
|
103
107
|
},
|
|
104
108
|
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
105
109
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
110
|
+
shellExec(`${baseCommand} run clean`);
|
|
111
|
+
shellExec(`${baseCommand} push ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
106
112
|
shellCd('/home/dd/engine');
|
|
107
113
|
shellExec(`git reset`);
|
|
108
114
|
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
109
|
-
shellExec(`${baseCommand} push .
|
|
115
|
+
shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
110
116
|
},
|
|
111
117
|
clean: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
112
118
|
shellCd(path ?? `/home/dd/engine`);
|
|
@@ -115,8 +121,8 @@ class UnderpostRun {
|
|
|
115
121
|
pull: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
116
122
|
shellCd(`/home/dd/engine`);
|
|
117
123
|
shellExec(`node bin/deploy clean-core-repo`);
|
|
118
|
-
shellExec(`underpost pull .
|
|
119
|
-
shellExec(`underpost pull engine-private
|
|
124
|
+
shellExec(`underpost pull . ${process.env.GITHUB_USERNAME}/engine`);
|
|
125
|
+
shellExec(`underpost pull ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
120
126
|
},
|
|
121
127
|
'release-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
122
128
|
actionInitLog();
|
|
@@ -128,11 +134,12 @@ class UnderpostRun {
|
|
|
128
134
|
}
|
|
129
135
|
},
|
|
130
136
|
'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
137
|
+
actionInitLog();
|
|
131
138
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
132
139
|
shellCd('/home/dd/engine');
|
|
133
140
|
shellExec(`git reset`);
|
|
134
141
|
shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
|
|
135
|
-
shellExec(`${baseCommand} push .
|
|
142
|
+
shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
136
143
|
},
|
|
137
144
|
ide: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
138
145
|
const { underpostRoot } = options;
|
|
@@ -148,13 +155,28 @@ class UnderpostRun {
|
|
|
148
155
|
let [deployId, subConf] = path.split(',');
|
|
149
156
|
shellExec(`npm run dev-api ${deployId} ${subConf}`);
|
|
150
157
|
},
|
|
151
|
-
|
|
158
|
+
sync: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
159
|
+
const env = options.dev ? 'development' : 'production';
|
|
152
160
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
deployId =
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
shellExec(`${baseCommand} run clean`);
|
|
162
|
+
const defaultPath = ['dd-default', 1, ``, ``, 'kind-control-plane'];
|
|
163
|
+
let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
|
|
164
|
+
deployId = deployId ?? defaultPath[0];
|
|
165
|
+
replicas = replicas ?? defaultPath[1];
|
|
166
|
+
versions = versions ?? defaultPath[2];
|
|
167
|
+
image = image ?? defaultPath[3];
|
|
168
|
+
node = node ?? defaultPath[4];
|
|
169
|
+
shellExec(
|
|
170
|
+
`${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
|
|
171
|
+
replicas ?? 1
|
|
172
|
+
} --node ${node}${image ? ` --image ${image}` : ''}${
|
|
173
|
+
versions ? ` --versions ${versions.replaceAll('+', ',')}` : ''
|
|
174
|
+
} dd ${env}`,
|
|
175
|
+
);
|
|
176
|
+
if (!options.build) shellExec(`${baseCommand} deploy --kubeadm ${deployId} ${env}`);
|
|
177
|
+
},
|
|
178
|
+
'ls-deployments': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
179
|
+
console.table(await UnderpostDeploy.API.get(path, 'deployments'));
|
|
158
180
|
},
|
|
159
181
|
monitor: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
160
182
|
const pid = getTerminalPid();
|
|
@@ -290,11 +312,21 @@ class UnderpostRun {
|
|
|
290
312
|
},
|
|
291
313
|
deploy: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
292
314
|
const deployId = path;
|
|
315
|
+
const { validVersion, deployVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
|
|
316
|
+
if (!validVersion) throw new Error('Version mismatch');
|
|
293
317
|
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
294
318
|
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
295
319
|
const env = 'production';
|
|
296
320
|
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
297
|
-
|
|
321
|
+
|
|
322
|
+
if (options.build === true) {
|
|
323
|
+
// deployId, replicas, versions, image, node
|
|
324
|
+
shellExec(
|
|
325
|
+
`node bin run sync ${deployId},${options.replicas ?? 1},${targetTraffic},${
|
|
326
|
+
options.imageName ?? `localhost/rockylinux9-underpost:${deployVersion}`
|
|
327
|
+
},${os.hostname()}`,
|
|
328
|
+
);
|
|
329
|
+
} else shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
298
330
|
|
|
299
331
|
let checkStatusIteration = 0;
|
|
300
332
|
const checkStatusIterationMsDelay = 1000;
|
package/src/cli/ssh.js
CHANGED
|
@@ -1,23 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* SSH module for managing SSH key generation and connection setup.
|
|
3
|
+
* @module src/cli/ssh.js
|
|
4
|
+
* @namespace UnderpostSSH
|
|
5
|
+
*/
|
|
6
|
+
|
|
2
7
|
import { shellExec } from '../server/process.js';
|
|
3
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @class UnderpostSSH
|
|
11
|
+
* @description Manages SSH key generation and connection setup.
|
|
12
|
+
* @memberof UnderpostSSH
|
|
13
|
+
*/
|
|
4
14
|
class UnderpostSSH {
|
|
5
15
|
static API = {
|
|
6
16
|
/**
|
|
7
17
|
* @method callback
|
|
8
|
-
* @
|
|
9
|
-
*
|
|
10
|
-
*
|
|
18
|
+
* @description Manages SSH key generation and connection setup based on the default deployment ID.
|
|
19
|
+
* This function will either generate a new SSH key pair or import an existing one,
|
|
20
|
+
* then initiate the SSH connection process.
|
|
21
|
+
* @param {object} [options={ generate: false }] - Options for the SSH callback.
|
|
22
|
+
* @param {boolean} [options.generate=false] - If true, generates a new SSH key pair. Otherwise, it imports the existing one.
|
|
23
|
+
* @memberof UnderpostSSH
|
|
24
|
+
* @returns {Promise<void>}
|
|
11
25
|
*/
|
|
12
26
|
callback: async (
|
|
13
27
|
options = {
|
|
14
28
|
generate: false,
|
|
15
29
|
},
|
|
16
30
|
) => {
|
|
17
|
-
//
|
|
31
|
+
// Example usage for importing an existing key:
|
|
18
32
|
// node bin/deploy ssh root@<host> <password> import
|
|
19
33
|
|
|
20
|
-
//
|
|
34
|
+
// Example usage for generating a new key:
|
|
21
35
|
// node bin/deploy ssh root@<host> <password>
|
|
22
36
|
|
|
23
37
|
shellExec(
|
|
@@ -16,9 +16,49 @@ import { SocketIo } from './components/core/SocketIo.js';
|
|
|
16
16
|
import { SocketIoDefault } from './components/default/SocketIoDefault.js';
|
|
17
17
|
import { ElementsDefault } from './components/default/ElementsDefault.js';
|
|
18
18
|
import { CssDefaultDark, CssDefaultLight } from './components/default/CssDefault.js';
|
|
19
|
+
import { EventsUI } from './components/core/EventsUI.js';
|
|
20
|
+
import { Modal } from './components/core/Modal.js';
|
|
19
21
|
|
|
20
22
|
const htmlMainBody = async () => {
|
|
21
|
-
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
EventsUI.onClick('.get-started-button', (e) => {
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
location.href = `https://www.nexodev.org/docs/?cid=src`;
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
return html`
|
|
30
|
+
<div class="landing-container">
|
|
31
|
+
<div class="content-wrapper">
|
|
32
|
+
<h1 class="animated-text">
|
|
33
|
+
<span class="greeting">Hello, World!</span>
|
|
34
|
+
<span class="subtitle">Welcome to Our Platform</span>
|
|
35
|
+
</h1>
|
|
36
|
+
|
|
37
|
+
<div class="features">
|
|
38
|
+
<div class="feature-card">
|
|
39
|
+
<i class="icon">🚀</i>
|
|
40
|
+
<h3>Fast & Reliable</h3>
|
|
41
|
+
<p>Lightning-fast performance with 99.9% uptime</p>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="feature-card">
|
|
44
|
+
<i class="icon">🎨</i>
|
|
45
|
+
<h3>Beautiful UI</h3>
|
|
46
|
+
<p>Modern and intuitive user interface</p>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="feature-card">
|
|
49
|
+
<i class="icon">⚡</i>
|
|
50
|
+
<h3>Powerful Features</h3>
|
|
51
|
+
<p>Everything you need in one place</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<button class="cta-button get-started-button">
|
|
56
|
+
Get Started
|
|
57
|
+
<span class="button-icon">→</span>
|
|
58
|
+
</button>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
`;
|
|
22
62
|
};
|
|
23
63
|
|
|
24
64
|
window.onload = () =>
|
|
@@ -39,5 +79,6 @@ window.onload = () =>
|
|
|
39
79
|
await LogOutDefault();
|
|
40
80
|
await SignUpDefault();
|
|
41
81
|
await Keyboard.Init({ callBackTime: DefaultParams.EVENT_CALLBACK_TIME });
|
|
82
|
+
await Modal.RenderSeoSanitizer();
|
|
42
83
|
},
|
|
43
84
|
});
|
|
@@ -10,7 +10,8 @@ import { Modal } from './Modal.js';
|
|
|
10
10
|
import { NotificationManager } from './NotificationManager.js';
|
|
11
11
|
import { Translate } from './Translate.js';
|
|
12
12
|
import { Validator } from './Validator.js';
|
|
13
|
-
import { append,
|
|
13
|
+
import { append, htmls, s } from './VanillaJs.js';
|
|
14
|
+
import { getProxyPath } from './Router.js';
|
|
14
15
|
|
|
15
16
|
const Account = {
|
|
16
17
|
UpdateEvent: {},
|
|
@@ -194,7 +195,14 @@ const Account = {
|
|
|
194
195
|
await this.instanceModalUiEvents({ user });
|
|
195
196
|
});
|
|
196
197
|
return html`
|
|
197
|
-
<
|
|
198
|
+
<label for="account-profile-image-input-label"
|
|
199
|
+
><span class="hide">Profile Image</span>
|
|
200
|
+
<input
|
|
201
|
+
type="file"
|
|
202
|
+
accept="${profileFileAccept.join(', ')}"
|
|
203
|
+
class="account-profile-image-input hide"
|
|
204
|
+
id="account-profile-image-input-label"
|
|
205
|
+
/></label>
|
|
198
206
|
${renderWave({ id: waveAnimationId })}
|
|
199
207
|
|
|
200
208
|
<form class="in">
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
// https://www.ag-grid.com/javascript-data-grid/themes/
|
|
3
3
|
|
|
4
4
|
import { ThemeEvents, darkTheme } from './Css.js';
|
|
5
|
-
import { append,
|
|
6
|
-
import
|
|
5
|
+
import { append, htmls, s } from './VanillaJs.js';
|
|
6
|
+
import { getProxyPath } from './Router.js';
|
|
7
|
+
import './Pagination.js';
|
|
7
8
|
|
|
8
9
|
const AgGrid = {
|
|
9
10
|
grids: {},
|
|
@@ -14,6 +15,9 @@ const AgGrid = {
|
|
|
14
15
|
// Grid Options: Contains all of the grid configurations
|
|
15
16
|
const gridOptions = {
|
|
16
17
|
// Row Data: The data to be displayed.
|
|
18
|
+
pagination: false, // Disabled by default, will be handled by the management view
|
|
19
|
+
// paginationPageSize: 100,
|
|
20
|
+
// suppressPaginationPanel: true, // We are using our own custom pagination component
|
|
17
21
|
// rowHeight: 60,
|
|
18
22
|
enableCellChangeFlash: true,
|
|
19
23
|
defaultColDef: {
|
|
@@ -23,6 +27,12 @@ const AgGrid = {
|
|
|
23
27
|
filter: true,
|
|
24
28
|
autoHeight: true,
|
|
25
29
|
},
|
|
30
|
+
rowClassRules: {
|
|
31
|
+
'row-new-highlight': (params) => {
|
|
32
|
+
// a temporary flag we can set on new rows to highlight them
|
|
33
|
+
return params.data && params.data._new;
|
|
34
|
+
},
|
|
35
|
+
},
|
|
26
36
|
// domLayout: 'autoHeight', || 'normal'
|
|
27
37
|
// Column Definitions: Defines & controls grid columns.
|
|
28
38
|
columnDefs: options?.gridOptions?.rowData?.[0]
|
|
@@ -48,13 +58,17 @@ const AgGrid = {
|
|
|
48
58
|
}
|
|
49
59
|
};
|
|
50
60
|
});
|
|
61
|
+
const usePagination = options?.usePagination;
|
|
51
62
|
return html`
|
|
52
|
-
<div
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
<div>
|
|
64
|
+
<div
|
|
65
|
+
class="${id} ${this.theme}${options?.darkTheme ? `-dark` : ''}"
|
|
66
|
+
style="${options?.style
|
|
67
|
+
? Object.keys(options.style).map((styleKey) => `${styleKey}: ${options.style[styleKey]}; `)
|
|
68
|
+
: 'height: 500px'}"
|
|
69
|
+
></div>
|
|
70
|
+
${usePagination ? `<ag-pagination id="ag-pagination-${id}"></ag-pagination>` : ''}
|
|
71
|
+
</div>
|
|
58
72
|
`;
|
|
59
73
|
},
|
|
60
74
|
RenderStyle: async function (
|
|
@@ -136,6 +150,10 @@ const AgGrid = {
|
|
|
136
150
|
${darkTheme
|
|
137
151
|
? html`
|
|
138
152
|
<style>
|
|
153
|
+
.ag-row.row-new-highlight {
|
|
154
|
+
background-color: #6d68ff !important;
|
|
155
|
+
transition: background-color 1s ease-out;
|
|
156
|
+
}
|
|
139
157
|
.ag-cell-data-changed,
|
|
140
158
|
.ag-cell-data-changed-animation {
|
|
141
159
|
background-color: #6d68ff !important;
|
|
@@ -145,6 +163,10 @@ const AgGrid = {
|
|
|
145
163
|
</style>
|
|
146
164
|
`
|
|
147
165
|
: html`<style>
|
|
166
|
+
.ag-row.row-new-highlight {
|
|
167
|
+
background-color: #d0eaf8 !important;
|
|
168
|
+
transition: background-color 1s ease-out;
|
|
169
|
+
}
|
|
148
170
|
.ag-cell-data-changed,
|
|
149
171
|
.ag-cell-data-changed-animation {
|
|
150
172
|
background-color: #d1d1d1 !important;
|
|
@@ -4,16 +4,17 @@ import { loggerFactory } from './Logger.js';
|
|
|
4
4
|
import { LogIn } from './LogIn.js';
|
|
5
5
|
import { LogOut } from './LogOut.js';
|
|
6
6
|
import { NotificationManager } from './NotificationManager.js';
|
|
7
|
-
import { SignUp } from './SignUp.js';
|
|
8
7
|
import { Translate } from './Translate.js';
|
|
9
8
|
import { s } from './VanillaJs.js';
|
|
10
9
|
|
|
11
|
-
const logger = loggerFactory(import.meta);
|
|
10
|
+
const logger = loggerFactory(import.meta, { trace: true });
|
|
12
11
|
|
|
13
12
|
const token = Symbol('token');
|
|
14
13
|
|
|
15
14
|
const guestToken = Symbol('guestToken');
|
|
16
15
|
|
|
16
|
+
const refreshTimeout = Symbol('refreshTimeout');
|
|
17
|
+
|
|
17
18
|
const Auth = {
|
|
18
19
|
[token]: '',
|
|
19
20
|
[guestToken]: '',
|
|
@@ -35,50 +36,65 @@ const Auth = {
|
|
|
35
36
|
getGuestToken: function () {
|
|
36
37
|
return this[guestToken];
|
|
37
38
|
},
|
|
38
|
-
// jwt
|
|
39
39
|
getJWT: function () {
|
|
40
|
-
return `Bearer ${
|
|
40
|
+
if (Auth.getToken()) return `Bearer ${Auth.getToken()}`;
|
|
41
|
+
if (Auth.getGuestToken()) return `Bearer ${Auth.getGuestToken()}`;
|
|
42
|
+
return '';
|
|
41
43
|
},
|
|
42
|
-
|
|
43
|
-
result = {
|
|
44
|
-
data: {
|
|
45
|
-
token: '',
|
|
46
|
-
user: null,
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
) {
|
|
44
|
+
decodeJwt: function (token) {
|
|
50
45
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
} catch (error) {
|
|
55
|
-
logger.error(error);
|
|
56
|
-
localStorage.removeItem('jwt');
|
|
46
|
+
return JSON.parse(atob(token.split('.')[1]));
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return null;
|
|
57
49
|
}
|
|
58
50
|
},
|
|
51
|
+
scheduleTokenRefresh: function () {
|
|
52
|
+
if (this[refreshTimeout]) {
|
|
53
|
+
clearTimeout(this[refreshTimeout]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const currentToken = Auth.getToken();
|
|
57
|
+
if (!currentToken) return;
|
|
58
|
+
|
|
59
|
+
const payload = Auth.decodeJwt(currentToken);
|
|
60
|
+
if (!payload || !payload.refreshExpiresAt) return;
|
|
61
|
+
|
|
62
|
+
const expiresIn = payload.refreshExpiresAt - Date.now();
|
|
63
|
+
const refreshBuffer = 2 * 60 * 1000; // 2 minutes
|
|
64
|
+
const refreshIn = expiresIn - refreshBuffer;
|
|
65
|
+
|
|
66
|
+
logger.info(`Token refresh in ${refreshIn / (1000 * 60)} minutes`);
|
|
67
|
+
|
|
68
|
+
if (refreshIn <= 0) return; // Already expired or close to it
|
|
69
|
+
|
|
70
|
+
this[refreshTimeout] = setTimeout(async () => {
|
|
71
|
+
const { data, status } = await UserService.get({ id: 'auth' });
|
|
72
|
+
if (status === 'success') {
|
|
73
|
+
logger.info('Refreshed access token.');
|
|
74
|
+
Auth.setToken(data.token);
|
|
75
|
+
localStorage.setItem('jwt', data.token);
|
|
76
|
+
Auth.scheduleTokenRefresh();
|
|
77
|
+
} else Auth.sessionOut();
|
|
78
|
+
}, refreshIn);
|
|
79
|
+
},
|
|
59
80
|
sessionIn: async function (userServicePayload) {
|
|
60
81
|
try {
|
|
61
82
|
const token = userServicePayload?.data?.token ? userServicePayload.data.token : localStorage.getItem('jwt');
|
|
62
|
-
|
|
63
83
|
if (token) {
|
|
64
|
-
|
|
84
|
+
Auth.setToken(token);
|
|
85
|
+
|
|
65
86
|
const result = userServicePayload
|
|
66
|
-
? userServicePayload
|
|
67
|
-
: await (
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
status: _result.status,
|
|
71
|
-
message: _result.message,
|
|
72
|
-
data: {
|
|
73
|
-
user: _result.data,
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
})();
|
|
87
|
+
? userServicePayload // From login/signup
|
|
88
|
+
: await UserService.get({ id: 'auth' });
|
|
89
|
+
|
|
77
90
|
const { status, data, message } = result;
|
|
78
91
|
if (status === 'success') {
|
|
92
|
+
Auth.setToken(data.token);
|
|
79
93
|
localStorage.setItem('jwt', token);
|
|
94
|
+
Auth.renderSessionUI();
|
|
80
95
|
await LogIn.Trigger({ user: data.user });
|
|
81
96
|
await Account.updateForm(data.user);
|
|
97
|
+
Auth.scheduleTokenRefresh();
|
|
82
98
|
return { user: data.user };
|
|
83
99
|
}
|
|
84
100
|
if (message && message.match('expired'))
|
|
@@ -89,41 +105,68 @@ const Auth = {
|
|
|
89
105
|
status: 'warning',
|
|
90
106
|
});
|
|
91
107
|
});
|
|
92
|
-
return await Auth.sessionOut();
|
|
93
108
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.deleteToken();
|
|
109
|
+
// Important delete session token if guest token already exists
|
|
110
|
+
Auth.deleteToken();
|
|
97
111
|
localStorage.removeItem('jwt');
|
|
98
|
-
let guestToken = localStorage.getItem('jwt.g');
|
|
99
112
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
guestToken
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
localStorage.removeItem('jwt.g');
|
|
111
|
-
return await Auth.sessionOut();
|
|
112
|
-
} else throw new Error(message);
|
|
113
|
+
// Anon guest session
|
|
114
|
+
let guestToken = localStorage.getItem('jwt.g');
|
|
115
|
+
if (guestToken) {
|
|
116
|
+
Auth.setGuestToken(guestToken);
|
|
117
|
+
let { data, status, message } = await UserService.get({ id: 'auth' });
|
|
118
|
+
if (status === 'success') {
|
|
119
|
+
await LogIn.Trigger(data);
|
|
120
|
+
await Account.updateForm(data.user);
|
|
121
|
+
return data;
|
|
122
|
+
} else logger.error(message);
|
|
113
123
|
}
|
|
114
|
-
await
|
|
115
|
-
return { user: data };
|
|
124
|
+
return await Auth.sessionOut();
|
|
116
125
|
} catch (error) {
|
|
117
126
|
logger.error(error);
|
|
118
127
|
return { user: UserMock.default };
|
|
119
128
|
}
|
|
120
129
|
},
|
|
121
130
|
sessionOut: async function () {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
{
|
|
132
|
+
const result = await UserService.delete({ id: 'logout' });
|
|
133
|
+
localStorage.removeItem('jwt');
|
|
134
|
+
Auth.deleteToken();
|
|
135
|
+
if (this[refreshTimeout]) {
|
|
136
|
+
clearTimeout(this[refreshTimeout]);
|
|
137
|
+
}
|
|
138
|
+
Auth.renderGuestUi();
|
|
139
|
+
LogIn.Scope.user.main.model.user = {};
|
|
140
|
+
await LogOut.Trigger(result);
|
|
141
|
+
}
|
|
142
|
+
{
|
|
143
|
+
localStorage.removeItem('jwt.g');
|
|
144
|
+
Auth.deleteGuestToken();
|
|
145
|
+
const result = await UserService.post({ id: 'guest' });
|
|
146
|
+
localStorage.setItem('jwt.g', result.data.token);
|
|
147
|
+
Auth.setGuestToken(result.data.token);
|
|
148
|
+
return await Auth.sessionIn();
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
renderSessionUI: function () {
|
|
152
|
+
s(`.main-btn-log-in`).style.display = 'none';
|
|
153
|
+
s(`.main-btn-sign-up`).style.display = 'none';
|
|
154
|
+
s(`.main-btn-log-out`).style.display = null;
|
|
155
|
+
s(`.main-btn-account`).style.display = null;
|
|
156
|
+
setTimeout(() => {
|
|
157
|
+
if (s(`.modal-log-in`)) s(`.btn-close-modal-log-in`).click();
|
|
158
|
+
if (s(`.modal-sign-up`)) s(`.btn-close-modal-sign-up`).click();
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
renderGuestUi: function () {
|
|
162
|
+
s(`.main-btn-log-in`).style.display = null;
|
|
163
|
+
s(`.main-btn-sign-up`).style.display = null;
|
|
164
|
+
s(`.main-btn-log-out`).style.display = 'none';
|
|
165
|
+
s(`.main-btn-account`).style.display = 'none';
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
if (s(`.modal-log-out`)) s(`.btn-close-modal-log-out`).click();
|
|
168
|
+
if (s(`.modal-account`)) s(`.btn-close-modal-account`).click();
|
|
169
|
+
});
|
|
127
170
|
},
|
|
128
171
|
};
|
|
129
172
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getId, s4 } from './CommonJs.js';
|
|
2
2
|
import { renderCssAttr } from './Css.js';
|
|
3
3
|
import { ToolTip } from './ToolTip.js';
|
|
4
|
-
import { getAllChildNodes, s } from './VanillaJs.js';
|
|
4
|
+
import { getAllChildNodes, htmlStrSanitize, s } from './VanillaJs.js';
|
|
5
5
|
|
|
6
6
|
const BtnIcon = {
|
|
7
7
|
Tokens: {},
|
|
@@ -32,7 +32,7 @@ const BtnIcon = {
|
|
|
32
32
|
: ''}`;
|
|
33
33
|
let render = html`<button
|
|
34
34
|
${options?.class ? `class="${options.class} ${tokenId}"` : ''}
|
|
35
|
-
${options?.type ? `type="${options.type}"` :
|
|
35
|
+
${options?.type ? `type="${options.type}"` : `type="button"`}
|
|
36
36
|
${options?.style ? `style="${options.style}"` : ''}
|
|
37
37
|
${options?.attrs ? `${options.attrs}` : ''}
|
|
38
38
|
>
|
|
@@ -49,6 +49,7 @@ const BtnIcon = {
|
|
|
49
49
|
>`
|
|
50
50
|
: label}
|
|
51
51
|
</div>
|
|
52
|
+
<label class="hide">${htmlStrSanitize(options.label) ? htmlStrSanitize(options.label) : tokenId}</label>
|
|
52
53
|
</button>`;
|
|
53
54
|
if (options.tooltipHtml)
|
|
54
55
|
setTimeout(() => {
|
|
@@ -7,9 +7,9 @@ import { Modal } from './Modal.js';
|
|
|
7
7
|
import { NotificationManager } from './NotificationManager.js';
|
|
8
8
|
import { Panel } from './Panel.js';
|
|
9
9
|
import { Responsive } from './Responsive.js';
|
|
10
|
-
import { listenQueryPathInstance, RouterEvents, setQueryPath } from './Router.js';
|
|
10
|
+
import { listenQueryPathInstance, RouterEvents, setQueryPath, getQueryParams } from './Router.js';
|
|
11
11
|
import { Translate } from './Translate.js';
|
|
12
|
-
import { append,
|
|
12
|
+
import { append, getTimeZone, htmls, s, sa } from './VanillaJs.js';
|
|
13
13
|
|
|
14
14
|
// https://fullcalendar.io/docs/event-object
|
|
15
15
|
|
|
@@ -363,7 +363,6 @@ const CalendarCore = {
|
|
|
363
363
|
const cid = getQueryParams().cid ? getQueryParams().cid : '';
|
|
364
364
|
if (lastCid === cid) return;
|
|
365
365
|
lastCid = cid;
|
|
366
|
-
if (options.route === 'home') Modal.homeCid = newInstance(cid);
|
|
367
366
|
if (s(`.main-body-calendar-${options.idModal}`)) {
|
|
368
367
|
// if (Auth.getToken())
|
|
369
368
|
// else getSrrData();
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { marked } from 'marked';
|
|
2
2
|
import { FileService } from '../../services/file/file.service.js';
|
|
3
|
-
import { append, getBlobFromUint8ArrayFile,
|
|
4
|
-
import {
|
|
3
|
+
import { append, getBlobFromUint8ArrayFile, getRawContentFile, htmls, s } from './VanillaJs.js';
|
|
4
|
+
import { s4 } from './CommonJs.js';
|
|
5
5
|
import { Translate } from './Translate.js';
|
|
6
6
|
import { Modal, renderViewTitle } from './Modal.js';
|
|
7
7
|
import { DocumentService } from '../../services/document/document.service.js';
|
|
8
8
|
import { CoreService, getApiBaseUrl } from '../../services/core/core.service.js';
|
|
9
9
|
import { loggerFactory } from './Logger.js';
|
|
10
10
|
import { imageShimmer, renderChessPattern, renderCssAttr, styleFactory } from './Css.js';
|
|
11
|
+
import { getQueryParams } from './Router.js';
|
|
11
12
|
|
|
12
13
|
const logger = loggerFactory(import.meta);
|
|
13
14
|
|
|
@@ -136,12 +137,9 @@ const Content = {
|
|
|
136
137
|
case 'svg':
|
|
137
138
|
case 'gif':
|
|
138
139
|
case 'png': {
|
|
139
|
-
const url = options
|
|
140
|
-
? options.url
|
|
141
|
-
: file._id
|
|
142
|
-
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
143
|
-
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
140
|
+
const url = Content.urlFactory(options);
|
|
144
141
|
const imgRender = html`<img
|
|
142
|
+
alt="${file.name ? file.name : `file ${s4()}`}"
|
|
145
143
|
class="in ${options.class}"
|
|
146
144
|
${styleFactory(options.style, `${renderChessPattern(50)}`)}
|
|
147
145
|
src="${url}"
|
|
@@ -150,11 +148,7 @@ const Content = {
|
|
|
150
148
|
break;
|
|
151
149
|
}
|
|
152
150
|
case 'pdf': {
|
|
153
|
-
const url = options
|
|
154
|
-
? options.url
|
|
155
|
-
: file._id
|
|
156
|
-
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
157
|
-
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
151
|
+
const url = Content.urlFactory(options);
|
|
158
152
|
render += html`<iframe
|
|
159
153
|
class="in ${options.class} iframe-${options.idModal}"
|
|
160
154
|
${styleFactory(options.style)}
|
|
@@ -188,6 +182,15 @@ const Content = {
|
|
|
188
182
|
if (options.raw) return render;
|
|
189
183
|
append(container, render);
|
|
190
184
|
},
|
|
185
|
+
urlFactory: function (options) {
|
|
186
|
+
return options.url
|
|
187
|
+
? options.url
|
|
188
|
+
: options.file?.data?.data
|
|
189
|
+
? URL.createObjectURL(getBlobFromUint8ArrayFile(options.file.data.data, options.file.mimetype))
|
|
190
|
+
: options.file._id
|
|
191
|
+
? getApiBaseUrl({ id: options.file._id, endpoint: 'file/blob' })
|
|
192
|
+
: null;
|
|
193
|
+
},
|
|
191
194
|
};
|
|
192
195
|
|
|
193
196
|
export { Content };
|