underpost 2.8.846 → 2.8.848
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/README.md +15 -2
- package/bin/build.js +7 -1
- package/bin/deploy.js +7 -1
- package/cli.md +17 -2
- package/conf.js +1 -1
- package/docker-compose.yml +1 -1
- package/manifests/deployment/dd-template-development/deployment.yaml +2 -2
- package/package.json +1 -1
- package/src/api/user/user.service.js +1 -4
- package/src/cli/cluster.js +6 -0
- package/src/cli/deploy.js +2 -1
- package/src/cli/index.js +7 -0
- package/src/cli/run.js +9 -1
- package/src/cli/ssh.js +32 -0
- package/src/client/Default.index.js +6 -2
- package/src/client/components/core/Account.js +1 -1
- package/src/client/components/core/Css.js +190 -14
- package/src/client/components/core/CssCore.js +3 -4
- package/src/client/components/core/Docs.js +4 -4
- package/src/client/components/core/LoadingAnimation.js +8 -15
- package/src/client/components/core/Modal.js +100 -7
- package/src/client/components/core/PanelForm.js +2 -3
- package/src/client/components/core/Router.js +22 -23
- package/src/client/components/core/SocketIo.js +3 -3
- package/src/client/components/core/VanillaJs.js +0 -3
- package/src/client/components/core/Worker.js +3 -1
- package/src/client/components/default/CssDefault.js +17 -3
- package/src/client/components/default/MenuDefault.js +241 -48
- package/src/client/components/default/RoutesDefault.js +6 -11
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/dark.svg +557 -0
- package/src/client/public/default/assets/logo/underpost.gif +0 -0
- package/src/index.js +9 -1
- package/src/server/client-build.js +1 -8
package/README.md
CHANGED
|
@@ -35,6 +35,12 @@ template
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
38
44
|
|
|
39
45
|
|
|
40
46
|
|
|
@@ -44,7 +50,7 @@ template
|
|
|
44
50
|
<!-- badges -->
|
|
45
51
|
|
|
46
52
|
|
|
47
|
-
[](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [](https://www.npmjs.com/package/underpost) [](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [](https://www.npmjs.com/package/underpost) [](https://socket.dev/npm/package/underpost/overview/2.8.848) [](https://coveralls.io/github/underpostnet/engine?branch=master) [](https://www.npmjs.org/package/underpost) [](https://www.npmjs.com/package/underpost)
|
|
48
54
|
|
|
49
55
|
|
|
50
56
|
<!-- end-badges -->
|
|
@@ -62,6 +68,12 @@ template
|
|
|
62
68
|
|
|
63
69
|
|
|
64
70
|
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
65
77
|
|
|
66
78
|
|
|
67
79
|
|
|
@@ -112,7 +124,7 @@ Run dev client server
|
|
|
112
124
|
npm run dev
|
|
113
125
|
```
|
|
114
126
|
<!-- -->
|
|
115
|
-
## underpost ci/cd cli v2.8.
|
|
127
|
+
## underpost ci/cd cli v2.8.848
|
|
116
128
|
|
|
117
129
|
### Usage: `underpost [options] [command]`
|
|
118
130
|
```
|
|
@@ -142,6 +154,7 @@ Commands:
|
|
|
142
154
|
fs [options] [path] Manages file storage, defaulting to file upload operations.
|
|
143
155
|
test [options] [deploy-list] Manages and runs tests, defaulting to the current Underpost default test suite.
|
|
144
156
|
monitor [options] <deploy-id> [env] Manages health server monitoring for specified deployments.
|
|
157
|
+
ssh [options] Import and start ssh server and client based on current default deployment ID.
|
|
145
158
|
run [options] <runner-id> [path] Runs a script from the specified path.
|
|
146
159
|
lxd [options] Manages LXD containers and virtual machines.
|
|
147
160
|
baremetal [options] [workflow-id] [hostname] [ip-address] Manages baremetal server operations, including installation, database setup, commissioning, and user management.
|
package/bin/build.js
CHANGED
|
@@ -53,7 +53,9 @@ if (process.argv.includes('conf')) {
|
|
|
53
53
|
fs.removeSync(toPath);
|
|
54
54
|
fs.mkdirSync(toPath, { recursive: true });
|
|
55
55
|
fs.copySync(`./engine-private/conf/${_confName}`, toPath);
|
|
56
|
-
if (fs.existsSync(
|
|
56
|
+
if (process.argv.includes('remove-replica') && fs.existsSync(`../${privateRepoName}/replica`)) {
|
|
57
|
+
fs.removeSync(`../${privateRepoName}/replica`);
|
|
58
|
+
} else if (fs.existsSync(`./engine-private/replica`)) {
|
|
57
59
|
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
58
60
|
for (const replica of replicas)
|
|
59
61
|
if (replica.match(_confName))
|
|
@@ -187,4 +189,8 @@ const { DefaultConf } = await import(`../conf.${confName}.js`);
|
|
|
187
189
|
|
|
188
190
|
fs.copyFileSync(`./.github/workflows/${repoName}.ci.yml`, `${basePath}/.github/workflows/${repoName}.ci.yml`);
|
|
189
191
|
fs.copyFileSync(`./.github/workflows/${repoName}.cd.yml`, `${basePath}/.github/workflows/${repoName}.cd.yml`);
|
|
192
|
+
|
|
193
|
+
if (fs.existsSync(`./src/ws/${confName.split('-')[1]}`)) {
|
|
194
|
+
fs.copySync(`./src/ws/${confName.split('-')[1]}`, `${basePath}/src/ws/${confName.split('-')[1]}`);
|
|
195
|
+
}
|
|
190
196
|
}
|
package/bin/deploy.js
CHANGED
|
@@ -835,6 +835,12 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
|
|
|
835
835
|
}
|
|
836
836
|
|
|
837
837
|
case 'ssh': {
|
|
838
|
+
// only import + start
|
|
839
|
+
// node bin/deploy ssh root@<host> <password> import
|
|
840
|
+
|
|
841
|
+
// generate + import + start
|
|
842
|
+
// node bin/deploy ssh root@<host> <password>
|
|
843
|
+
|
|
838
844
|
const host = process.argv[3] ?? `root@${await ip.public.ipv4()}`;
|
|
839
845
|
const domain = host.split('@')[1];
|
|
840
846
|
const user = 'root'; // host.split('@')[0];
|
|
@@ -907,7 +913,7 @@ EOF`);
|
|
|
907
913
|
// shellExec(`sudo echo "" > ~/.ssh/known_hosts`);
|
|
908
914
|
|
|
909
915
|
// ssh-copy-id -i ~/.ssh/id_rsa.pub -p <port_number> <username>@<host>
|
|
910
|
-
shellExec(`ssh-copy-id -i ~/.ssh/id_rsa.pub -p ${port} ${host}`);
|
|
916
|
+
// shellExec(`ssh-copy-id -i ~/.ssh/id_rsa.pub -p ${port} ${host}`);
|
|
911
917
|
// debug:
|
|
912
918
|
// shellExec(`ssh -vvv ${host}`);
|
|
913
919
|
|
package/cli.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v2.8.
|
|
1
|
+
## underpost ci/cd cli v2.8.848
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -28,6 +28,7 @@ Commands:
|
|
|
28
28
|
fs [options] [path] Manages file storage, defaulting to file upload operations.
|
|
29
29
|
test [options] [deploy-list] Manages and runs tests, defaulting to the current Underpost default test suite.
|
|
30
30
|
monitor [options] <deploy-id> [env] Manages health server monitoring for specified deployments.
|
|
31
|
+
ssh [options] Import and start ssh server and client based on current default deployment ID.
|
|
31
32
|
run [options] <runner-id> [path] Runs a script from the specified path.
|
|
32
33
|
lxd [options] Manages LXD containers and virtual machines.
|
|
33
34
|
baremetal [options] [workflow-id] [hostname] [ip-address] Manages baremetal server operations, including installation, database setup, commissioning, and user management.
|
|
@@ -552,6 +553,20 @@ Options:
|
|
|
552
553
|
```
|
|
553
554
|
|
|
554
555
|
|
|
556
|
+
### `ssh` :
|
|
557
|
+
```
|
|
558
|
+
Usage: underpost ssh [options]
|
|
559
|
+
|
|
560
|
+
Import and start ssh server and client based on current default deployment ID.
|
|
561
|
+
|
|
562
|
+
Options:
|
|
563
|
+
--generate Generates new ssh credential and stores it in current private
|
|
564
|
+
keys file storage.
|
|
565
|
+
-h, --help display help for command
|
|
566
|
+
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
|
|
555
570
|
### `run` :
|
|
556
571
|
```
|
|
557
572
|
Usage: underpost run [options] <runner-id> [path]
|
|
@@ -559,7 +574,7 @@ Options:
|
|
|
559
574
|
Runs a script from the specified path.
|
|
560
575
|
|
|
561
576
|
Arguments:
|
|
562
|
-
runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, gpu-env, tf-gpu-test, dev-cluster, cyberia-ide, engine-ide, ssh-deploy, ide, monitor, db-client, cluster, deploy, tf-vae-test, deploy-job.
|
|
577
|
+
runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, gpu-env, tf-gpu-test, dev-cluster, cyberia-ide, engine-ide, template-deploy, ssh-deploy, ide, monitor, db-client, cluster, deploy, tf-vae-test, deploy-job.
|
|
563
578
|
path The absolute or relative directory path where the script is located.
|
|
564
579
|
|
|
565
580
|
Options:
|
package/conf.js
CHANGED
package/docker-compose.yml
CHANGED
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-template-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.8.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.8.848
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "124Ki"
|
|
@@ -100,7 +100,7 @@ spec:
|
|
|
100
100
|
spec:
|
|
101
101
|
containers:
|
|
102
102
|
- name: dd-template-development-green
|
|
103
|
-
image: localhost/rockylinux9-underpost:v2.8.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v2.8.848
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
package/package.json
CHANGED
|
@@ -444,7 +444,7 @@ const UserService = {
|
|
|
444
444
|
_id: user._id,
|
|
445
445
|
}).select(UserDto.select.get());
|
|
446
446
|
} else throw new Error('invalid token');
|
|
447
|
-
}
|
|
447
|
+
} else delete req.body.password;
|
|
448
448
|
|
|
449
449
|
switch (req.params.id) {
|
|
450
450
|
default: {
|
|
@@ -453,9 +453,6 @@ const UserService = {
|
|
|
453
453
|
});
|
|
454
454
|
switch (user.role) {
|
|
455
455
|
case 'admin': {
|
|
456
|
-
if (req.body.password !== undefined && req.body.password !== user.password)
|
|
457
|
-
req.body.password = await hashPassword(req.body.password);
|
|
458
|
-
else delete req.body.password;
|
|
459
456
|
return await User.findByIdAndUpdate(req.params.id, req.body, {
|
|
460
457
|
runValidators: true,
|
|
461
458
|
});
|
package/src/cli/cluster.js
CHANGED
|
@@ -476,6 +476,12 @@ net.bridge.bridge-nf-call-arptables = 1
|
|
|
476
476
|
net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
477
477
|
{ silent: true },
|
|
478
478
|
);
|
|
479
|
+
|
|
480
|
+
// Increase inotify limits
|
|
481
|
+
shellExec(`sudo sysctl -w fs.inotify.max_user_watches=2099999999`);
|
|
482
|
+
shellExec(`sudo sysctl -w fs.inotify.max_user_instances=2099999999`);
|
|
483
|
+
shellExec(`sudo sysctl -w fs.inotify.max_queued_events=2099999999`);
|
|
484
|
+
|
|
479
485
|
// shellExec(`sudo sysctl --system`); // Apply sysctl changes immediately
|
|
480
486
|
// Apply NAT iptables rules.
|
|
481
487
|
shellExec(`${underpostRoot}/manifests/maas/nat-iptables.sh`, { silent: true });
|
package/src/cli/deploy.js
CHANGED
|
@@ -528,13 +528,14 @@ node bin/deploy build-full-client ${deployId}
|
|
|
528
528
|
}).trim(),
|
|
529
529
|
);
|
|
530
530
|
},
|
|
531
|
-
checkDeploymentReadyStatus(deployId, env, traffic) {
|
|
531
|
+
checkDeploymentReadyStatus(deployId, env, traffic, ignoresNames = []) {
|
|
532
532
|
const cmd = `underpost config get container-status`;
|
|
533
533
|
const pods = UnderpostDeploy.API.get(`${deployId}-${env}-${traffic}`);
|
|
534
534
|
const readyPods = [];
|
|
535
535
|
const notReadyPods = [];
|
|
536
536
|
for (const pod of pods) {
|
|
537
537
|
const { NAME } = pod;
|
|
538
|
+
if (ignoresNames && ignoresNames.find((t) => NAME.trim().toLowerCase().match(t.trim().toLowerCase()))) continue;
|
|
538
539
|
if (
|
|
539
540
|
shellExec(`sudo kubectl exec -i ${NAME} -- sh -c "${cmd}"`, { stdout: true }).match(
|
|
540
541
|
`${deployId}-${env}-running-deployment`,
|
package/src/cli/index.js
CHANGED
|
@@ -316,6 +316,13 @@ program
|
|
|
316
316
|
.description('Manages health server monitoring for specified deployments.')
|
|
317
317
|
.action(Underpost.monitor.callback);
|
|
318
318
|
|
|
319
|
+
// 'ssh' command: SSH management
|
|
320
|
+
program
|
|
321
|
+
.command('ssh')
|
|
322
|
+
.option('--generate', 'Generates new ssh credential and stores it in current private keys file storage.')
|
|
323
|
+
.description('Import and start ssh server and client based on current default deployment ID.')
|
|
324
|
+
.action(Underpost.ssh.callback);
|
|
325
|
+
|
|
319
326
|
// 'run' command: Run a script
|
|
320
327
|
program
|
|
321
328
|
.command('run')
|
package/src/cli/run.js
CHANGED
|
@@ -86,6 +86,13 @@ class UnderpostRun {
|
|
|
86
86
|
shellExec(`${baseCommand} run ide /home/dd/engine`);
|
|
87
87
|
shellExec(`${baseCommand} run ide /home/dd/engine/engine-private`);
|
|
88
88
|
},
|
|
89
|
+
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
90
|
+
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
91
|
+
shellCd('/home/dd/engine');
|
|
92
|
+
shellExec(`git reset`);
|
|
93
|
+
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
94
|
+
shellExec(`${baseCommand} push . underpostnet/engine`);
|
|
95
|
+
},
|
|
89
96
|
'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
90
97
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
91
98
|
shellCd('/home/dd/engine');
|
|
@@ -206,12 +213,13 @@ class UnderpostRun {
|
|
|
206
213
|
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
207
214
|
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
208
215
|
const env = 'production';
|
|
216
|
+
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
209
217
|
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
210
218
|
|
|
211
219
|
let secondsElapsed = 0;
|
|
212
220
|
logger.info('Deployment init', { deployId, env, targetTraffic });
|
|
213
221
|
|
|
214
|
-
while (!UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic).ready) {
|
|
222
|
+
while (!UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready) {
|
|
215
223
|
await timer(1000);
|
|
216
224
|
secondsElapsed++;
|
|
217
225
|
logger.info(`Deployment in progress, seconds elapsed: ${secondsElapsed}`);
|
package/src/cli/ssh.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getNpmRootPath } from '../server/conf.js';
|
|
2
|
+
import { shellExec } from '../server/process.js';
|
|
3
|
+
|
|
4
|
+
class UnderpostSSH {
|
|
5
|
+
static API = {
|
|
6
|
+
/**
|
|
7
|
+
* @method callback
|
|
8
|
+
* @param {object} options
|
|
9
|
+
* @param {boolean} options.generate - Generates new ssh credential and stores it in current private keys file storage.
|
|
10
|
+
* @description Import and start ssh server and client based on current default deployment ID.
|
|
11
|
+
*/
|
|
12
|
+
callback: async (
|
|
13
|
+
options = {
|
|
14
|
+
generate: false,
|
|
15
|
+
},
|
|
16
|
+
) => {
|
|
17
|
+
// only import + start
|
|
18
|
+
// node bin/deploy ssh root@<host> <password> import
|
|
19
|
+
|
|
20
|
+
// generate + import + start
|
|
21
|
+
// node bin/deploy ssh root@<host> <password>
|
|
22
|
+
|
|
23
|
+
shellExec(
|
|
24
|
+
`node bin/deploy ssh root@${process.env.DEFAULT_DEPLOY_HOST} ${process.env.DEFAULT_DEPLOY_PASSWORD ?? `''`}${
|
|
25
|
+
options.generate === true ? '' : ' import'
|
|
26
|
+
}`,
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default UnderpostSSH;
|
|
@@ -16,6 +16,7 @@ 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 { Scroll } from './components/core/Scroll.js';
|
|
19
|
+
import { CssDefaultDark, CssDefaultLight } from './components/default/CssDefault.js';
|
|
19
20
|
|
|
20
21
|
const htmlMainBody = async () => {
|
|
21
22
|
return html`<span>Hello World!!</span>`;
|
|
@@ -25,12 +26,15 @@ window.onload = () =>
|
|
|
25
26
|
Worker.instance({
|
|
26
27
|
router: RouterDefault,
|
|
27
28
|
render: async () => {
|
|
28
|
-
await Css.loadThemes();
|
|
29
|
+
await Css.loadThemes([CssDefaultLight, CssDefaultDark]);
|
|
29
30
|
await TranslateCore.Init();
|
|
30
31
|
await TranslateDefault.Init();
|
|
31
32
|
await Responsive.Init();
|
|
32
33
|
await MenuDefault.Render({ htmlMainBody });
|
|
33
|
-
await SocketIo.Init({
|
|
34
|
+
await SocketIo.Init({
|
|
35
|
+
channels: ElementsDefault.Data,
|
|
36
|
+
path: `/`,
|
|
37
|
+
});
|
|
34
38
|
await SocketIoDefault.Init();
|
|
35
39
|
await LogInDefault();
|
|
36
40
|
await LogOutDefault();
|
|
@@ -44,7 +44,7 @@ const Account = {
|
|
|
44
44
|
{ model: 'email', id: `account-email`, rules: [{ type: 'isEmpty' }, { type: 'isEmail' }] },
|
|
45
45
|
{
|
|
46
46
|
model: 'password',
|
|
47
|
-
defaultValue: '
|
|
47
|
+
defaultValue: '#Changethis123',
|
|
48
48
|
id: `account-password`,
|
|
49
49
|
rules: [{ type: 'isStrongPassword' }],
|
|
50
50
|
},
|
|
@@ -51,8 +51,8 @@ const Css = {
|
|
|
51
51
|
// if (!ThemesScope.find((t) => t.dark)) addTheme(CssCoreDark);
|
|
52
52
|
// if (!ThemesScope.find((t) => !t.dark)) addTheme(CssCoreLight);
|
|
53
53
|
if (ThemesScope.length === 0) {
|
|
54
|
-
addTheme(CssCoreDark);
|
|
55
54
|
addTheme(CssCoreLight);
|
|
55
|
+
addTheme(CssCoreDark);
|
|
56
56
|
}
|
|
57
57
|
const localStorageTheme = localStorage.getItem('_theme');
|
|
58
58
|
if (localStorageTheme && Themes[localStorageTheme]) {
|
|
@@ -199,6 +199,7 @@ const addTheme = (options) => {
|
|
|
199
199
|
if (!['core', 'css-core'].includes(options.theme))
|
|
200
200
|
render += darkTheme ? await CssCoreDark.render() : await CssCoreLight.render();
|
|
201
201
|
render += await options.render();
|
|
202
|
+
render += await subThemeManager.render();
|
|
202
203
|
htmls('.theme', render);
|
|
203
204
|
TriggerThemeEvents();
|
|
204
205
|
}
|
|
@@ -232,18 +233,29 @@ const borderChar = (px, color, selectors, hover = false) => {
|
|
|
232
233
|
${color}, ${px}px ${px}px ${px}px ${color};
|
|
233
234
|
`;
|
|
234
235
|
};
|
|
235
|
-
|
|
236
236
|
const boxShadow = ({ selector }) => html`
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
237
|
+
${darkTheme
|
|
238
|
+
? html`
|
|
239
|
+
<style>
|
|
240
|
+
${selector} {
|
|
241
|
+
box-shadow: 0 4px 8px 0 rgba(255, 255, 255, 0.1), 0 6px 20px 0 rgba(255, 255, 255, 0.08);
|
|
242
|
+
}
|
|
243
|
+
${selector}:hover {
|
|
244
|
+
box-shadow: 0 8px 16px 0 rgba(255, 255, 255, 0.15), 0 10px 30px 0 rgba(255, 255, 255, 0.1);
|
|
245
|
+
}
|
|
246
|
+
</style>
|
|
247
|
+
`
|
|
248
|
+
: html`
|
|
249
|
+
<style>
|
|
250
|
+
${selector} {
|
|
251
|
+
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
252
|
+
}
|
|
253
|
+
${selector}:hover {
|
|
254
|
+
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 10px 30px 0 rgba(0, 0, 0, 0.3);
|
|
255
|
+
}
|
|
256
|
+
</style>
|
|
257
|
+
`}
|
|
245
258
|
`;
|
|
246
|
-
|
|
247
259
|
const renderMediaQuery = (mediaData) => {
|
|
248
260
|
// first limit should be '0'
|
|
249
261
|
return html`
|
|
@@ -677,6 +689,166 @@ const scrollBarLightRender = () => {
|
|
|
677
689
|
.join('');
|
|
678
690
|
};
|
|
679
691
|
|
|
692
|
+
/**
|
|
693
|
+
* Adjust hex color brightness toward white/black ("mix") or by modifying HSL lightness ("hsl").
|
|
694
|
+
*
|
|
695
|
+
* @param {string} hex - Color as '#rrggbb', 'rrggbb', '#rgb', or 'rgb'.
|
|
696
|
+
* @param {number} factor - -1..1 or -100..100 (percent). Positive = lighten, negative = darken.
|
|
697
|
+
* @param {{mode?: 'mix'|'hsl'}} [options]
|
|
698
|
+
* @returns {string} - Adjusted color as '#rrggbb' (lowercase).
|
|
699
|
+
*/
|
|
700
|
+
function adjustHex(hex, factor = 0.1, options = {}) {
|
|
701
|
+
if (typeof hex !== 'string') throw new TypeError('hex must be a string');
|
|
702
|
+
if (typeof factor !== 'number') throw new TypeError('factor must be a number');
|
|
703
|
+
|
|
704
|
+
// normalize factor: allow -100..100 or -1..1
|
|
705
|
+
if (factor > 1 && factor <= 100) factor = factor / 100;
|
|
706
|
+
if (factor < -1 && factor >= -100) factor = factor / 100;
|
|
707
|
+
factor = Math.max(-1, Math.min(1, factor));
|
|
708
|
+
|
|
709
|
+
const mode = options.mode === 'hsl' ? 'hsl' : 'mix';
|
|
710
|
+
|
|
711
|
+
// normalize hex
|
|
712
|
+
let h = hex.replace(/^#/, '').trim();
|
|
713
|
+
if (!(h.length === 3 || h.length === 6)) throw new Error('Invalid hex format');
|
|
714
|
+
if (h.length === 3)
|
|
715
|
+
h = h
|
|
716
|
+
.split('')
|
|
717
|
+
.map((c) => c + c)
|
|
718
|
+
.join('');
|
|
719
|
+
|
|
720
|
+
const r = parseInt(h.slice(0, 2), 16);
|
|
721
|
+
const g = parseInt(h.slice(2, 4), 16);
|
|
722
|
+
const b = parseInt(h.slice(4, 6), 16);
|
|
723
|
+
|
|
724
|
+
const clamp = (v, a = 0, z = 255) => Math.max(a, Math.min(z, v));
|
|
725
|
+
|
|
726
|
+
const rgbToHex = (rr, gg, bb) =>
|
|
727
|
+
'#' +
|
|
728
|
+
[rr, gg, bb]
|
|
729
|
+
.map((v) => Math.round(v).toString(16).padStart(2, '0'))
|
|
730
|
+
.join('')
|
|
731
|
+
.toLowerCase();
|
|
732
|
+
|
|
733
|
+
if (mode === 'mix') {
|
|
734
|
+
// positive: mix toward white (255); negative: mix toward black (0)
|
|
735
|
+
const mixChannel = (c) => {
|
|
736
|
+
if (factor >= 0) {
|
|
737
|
+
return clamp(Math.round(c + (255 - c) * factor));
|
|
738
|
+
} else {
|
|
739
|
+
const a = Math.abs(factor);
|
|
740
|
+
return clamp(Math.round(c * (1 - a)));
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
return rgbToHex(mixChannel(r), mixChannel(g), mixChannel(b));
|
|
744
|
+
} else {
|
|
745
|
+
// HSL mode: convert rgb to hsl, adjust L by factor, convert back
|
|
746
|
+
const rgbToHsl = (r, g, b) => {
|
|
747
|
+
r /= 255;
|
|
748
|
+
g /= 255;
|
|
749
|
+
b /= 255;
|
|
750
|
+
const max = Math.max(r, g, b),
|
|
751
|
+
min = Math.min(r, g, b);
|
|
752
|
+
let h = 0,
|
|
753
|
+
s = 0,
|
|
754
|
+
l = (max + min) / 2;
|
|
755
|
+
if (max !== min) {
|
|
756
|
+
const d = max - min;
|
|
757
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
758
|
+
switch (max) {
|
|
759
|
+
case r:
|
|
760
|
+
h = (g - b) / d + (g < b ? 6 : 0);
|
|
761
|
+
break;
|
|
762
|
+
case g:
|
|
763
|
+
h = (b - r) / d + 2;
|
|
764
|
+
break;
|
|
765
|
+
case b:
|
|
766
|
+
h = (r - g) / d + 4;
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
h /= 6;
|
|
770
|
+
}
|
|
771
|
+
return { h, s, l };
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
const hslToRgb = (h, s, l) => {
|
|
775
|
+
let r, g, b;
|
|
776
|
+
if (s === 0) {
|
|
777
|
+
r = g = b = l;
|
|
778
|
+
} else {
|
|
779
|
+
const hue2rgb = (p, q, t) => {
|
|
780
|
+
if (t < 0) t += 1;
|
|
781
|
+
if (t > 1) t -= 1;
|
|
782
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
783
|
+
if (t < 1 / 2) return q;
|
|
784
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
785
|
+
return p;
|
|
786
|
+
};
|
|
787
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
788
|
+
const p = 2 * l - q;
|
|
789
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
790
|
+
g = hue2rgb(p, q, h);
|
|
791
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
792
|
+
}
|
|
793
|
+
return { r: r * 255, g: g * 255, b: b * 255 };
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
const { h: hh, s: ss, l: ll } = rgbToHsl(r, g, b);
|
|
797
|
+
// add factor to lightness (factor already normalized -1..1)
|
|
798
|
+
let newL = ll + factor;
|
|
799
|
+
newL = Math.max(0, Math.min(1, newL));
|
|
800
|
+
const { r: r2, g: g2, b: b2 } = hslToRgb(hh, ss, newL);
|
|
801
|
+
return rgbToHex(r2, g2, b2);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// Convenience helpers:
|
|
806
|
+
function lightenHex(hex, percentOr01 = 0.1, options = {}) {
|
|
807
|
+
return adjustHex(hex, Math.abs(percentOr01), options);
|
|
808
|
+
}
|
|
809
|
+
function darkenHex(hex, percentOr01 = 0.1, options = {}) {
|
|
810
|
+
return adjustHex(hex, -Math.abs(percentOr01), options);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const subThemeManager = {
|
|
814
|
+
render: async function () {
|
|
815
|
+
if (darkTheme && this.renderDark) {
|
|
816
|
+
return await this.renderDark();
|
|
817
|
+
} else if (!darkTheme && this.renderLight) {
|
|
818
|
+
return await this.renderLight();
|
|
819
|
+
}
|
|
820
|
+
return html``;
|
|
821
|
+
},
|
|
822
|
+
lightColor: null,
|
|
823
|
+
setLightTheme: function (color) {
|
|
824
|
+
this.lightColor = color;
|
|
825
|
+
this.renderLight = async function () {
|
|
826
|
+
return html`<style>
|
|
827
|
+
button:hover,
|
|
828
|
+
.a-btn:hover,
|
|
829
|
+
.main-btn-menu-active {
|
|
830
|
+
color: ${this.lightColor};
|
|
831
|
+
background-color: ${lightenHex(this.lightColor, 0.8)};
|
|
832
|
+
}
|
|
833
|
+
</style>`;
|
|
834
|
+
};
|
|
835
|
+
},
|
|
836
|
+
darkColor: null,
|
|
837
|
+
setDarkTheme: function (color) {
|
|
838
|
+
this.darkColor = color;
|
|
839
|
+
this.renderDark = async function () {
|
|
840
|
+
return html`<style>
|
|
841
|
+
button:hover,
|
|
842
|
+
.a-btn:hover,
|
|
843
|
+
.main-btn-menu-active {
|
|
844
|
+
color: ${lightenHex(this.darkColor, 0.8)};
|
|
845
|
+
background-color: ${darkenHex(this.darkColor, 0.75)};
|
|
846
|
+
}
|
|
847
|
+
</style>`;
|
|
848
|
+
};
|
|
849
|
+
},
|
|
850
|
+
};
|
|
851
|
+
|
|
680
852
|
const scrollBarDarkRender = () => {
|
|
681
853
|
return cssBrowserCodes
|
|
682
854
|
.map(
|
|
@@ -685,8 +857,8 @@ const scrollBarDarkRender = () => {
|
|
|
685
857
|
::-` +
|
|
686
858
|
b +
|
|
687
859
|
`-scrollbar {
|
|
688
|
-
width:
|
|
689
|
-
height:
|
|
860
|
+
width: 8px;
|
|
861
|
+
height: 8px;
|
|
690
862
|
/* line-height: 1em; */
|
|
691
863
|
}
|
|
692
864
|
|
|
@@ -702,7 +874,7 @@ const scrollBarDarkRender = () => {
|
|
|
702
874
|
b +
|
|
703
875
|
`-scrollbar-thumb {
|
|
704
876
|
background: #74747457;
|
|
705
|
-
border-radius:
|
|
877
|
+
border-radius: 4px;
|
|
706
878
|
}
|
|
707
879
|
|
|
708
880
|
/* Handle on hover */
|
|
@@ -907,4 +1079,8 @@ export {
|
|
|
907
1079
|
simpleIconsRender,
|
|
908
1080
|
extractBackgroundImageUrl,
|
|
909
1081
|
renderChessPattern,
|
|
1082
|
+
subThemeManager,
|
|
1083
|
+
lightenHex,
|
|
1084
|
+
darkenHex,
|
|
1085
|
+
adjustHex,
|
|
910
1086
|
};
|
|
@@ -17,8 +17,8 @@ const CssCommonCore = async () => {
|
|
|
17
17
|
await AgGrid.RenderStyle();
|
|
18
18
|
return html`<style>
|
|
19
19
|
.top-bar-app-icon {
|
|
20
|
-
width:
|
|
21
|
-
height:
|
|
20
|
+
width: 40px;
|
|
21
|
+
height: 40px;
|
|
22
22
|
}
|
|
23
23
|
.mini-title {
|
|
24
24
|
font-size: 15px;
|
|
@@ -33,7 +33,7 @@ const CssCommonCore = async () => {
|
|
|
33
33
|
top: 0;
|
|
34
34
|
left: 0;
|
|
35
35
|
transition: 0.3s;
|
|
36
|
-
height:
|
|
36
|
+
height: 10px;
|
|
37
37
|
width: 100%;
|
|
38
38
|
z-index: 11;
|
|
39
39
|
}
|
|
@@ -51,7 +51,6 @@ const CssCommonCore = async () => {
|
|
|
51
51
|
cursor: grabbing !important;
|
|
52
52
|
}
|
|
53
53
|
.btn-label-content {
|
|
54
|
-
height: 100%;
|
|
55
54
|
top: 15px;
|
|
56
55
|
}
|
|
57
56
|
.badge {
|
|
@@ -16,10 +16,7 @@ const Docs = {
|
|
|
16
16
|
const docData = this.Data.find((d) => d.type === type);
|
|
17
17
|
const ModalId = `modal-docs-${docData.type}`;
|
|
18
18
|
const { barConfig } = await Themes[Css.currentTheme]();
|
|
19
|
-
|
|
20
|
-
setQueryPath({ path: 'docs' });
|
|
21
|
-
Modal.removeModal(ModalId);
|
|
22
|
-
};
|
|
19
|
+
|
|
23
20
|
await Modal.Render({
|
|
24
21
|
barConfig,
|
|
25
22
|
title: renderViewTitle(docData),
|
|
@@ -53,6 +50,9 @@ const Docs = {
|
|
|
53
50
|
}
|
|
54
51
|
};
|
|
55
52
|
Modal.Data[ModalId].onObserverListener[ModalId]();
|
|
53
|
+
Modal.Data[ModalId].onCloseListener[ModalId] = () => {
|
|
54
|
+
setQueryPath({ path: 'docs', queryPath: '' });
|
|
55
|
+
};
|
|
56
56
|
},
|
|
57
57
|
Data: [
|
|
58
58
|
{
|