underpost 2.85.1 → 2.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.env.development +2 -1
  2. package/.env.production +2 -1
  3. package/.env.test +2 -1
  4. package/.github/workflows/release.cd.yml +3 -3
  5. package/.vscode/zed.keymap.json +22 -0
  6. package/README.md +3 -3
  7. package/bin/build.js +8 -10
  8. package/bin/deploy.js +4 -2
  9. package/bin/file.js +4 -0
  10. package/bin/vs.js +4 -4
  11. package/cli.md +16 -11
  12. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  13. package/manifests/deployment/dd-test-development/deployment.yaml +50 -50
  14. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  15. package/package.json +2 -2
  16. package/src/api/file/file.service.js +29 -3
  17. package/src/cli/baremetal.js +4 -5
  18. package/src/cli/deploy.js +26 -4
  19. package/src/cli/index.js +8 -3
  20. package/src/cli/repository.js +42 -45
  21. package/src/cli/run.js +217 -48
  22. package/src/client/components/core/AgGrid.js +42 -3
  23. package/src/client/components/core/CommonJs.js +5 -0
  24. package/src/client/components/core/Css.js +95 -48
  25. package/src/client/components/core/CssCore.js +0 -1
  26. package/src/client/components/core/LoadingAnimation.js +2 -2
  27. package/src/client/components/core/Logger.js +2 -9
  28. package/src/client/components/core/Modal.js +22 -14
  29. package/src/client/components/core/ObjectLayerEngine.js +300 -9
  30. package/src/client/components/core/ObjectLayerEngineModal.js +686 -148
  31. package/src/client/components/core/ObjectLayerEngineViewer.js +1061 -0
  32. package/src/client/components/core/Pagination.js +15 -5
  33. package/src/client/components/core/Router.js +5 -1
  34. package/src/client/components/core/SocketIo.js +5 -1
  35. package/src/client/components/core/Translate.js +4 -0
  36. package/src/client/components/core/Worker.js +8 -1
  37. package/src/client/services/default/default.management.js +86 -16
  38. package/src/client/sw/default.sw.js +193 -97
  39. package/src/client.dev.js +1 -1
  40. package/src/db/mariadb/MariaDB.js +2 -2
  41. package/src/index.js +1 -1
  42. package/src/proxy.js +1 -1
  43. package/src/runtime/express/Express.js +4 -1
  44. package/src/server/auth.js +2 -1
  45. package/src/server/client-build.js +57 -2
  46. package/src/server/conf.js +132 -15
  47. package/src/server/object-layer.js +44 -0
  48. package/src/server/proxy.js +53 -26
  49. package/src/server/start.js +25 -3
  50. package/src/server/tls.js +1 -1
  51. package/src/ws/IoInterface.js +2 -3
  52. package/AUTHORS.md +0 -21
  53. package/src/server/network.js +0 -72
@@ -140,13 +140,20 @@ class UnderpostRepository {
140
140
  .join('');
141
141
  if (history[0]) {
142
142
  for (const commit of history) {
143
+ console.log(
144
+ shellExec(`git show -s --format=%ci ${commit.hash}`, {
145
+ stdout: true,
146
+ silent: true,
147
+ disableLog: true,
148
+ }).trim().green,
149
+ );
143
150
  console.log(commit.hash.yellow, commit.message);
144
151
  console.log(
145
152
  shellExec(`git show --name-status --pretty="" ${commit.hash}`, {
146
153
  stdout: true,
147
154
  silent: true,
148
155
  disableLog: true,
149
- }).red,
156
+ }).trim().red,
150
157
  );
151
158
  }
152
159
  if (options.copy) pbcopy(chainCmd);
@@ -213,60 +220,50 @@ class UnderpostRepository {
213
220
  },
214
221
 
215
222
  /**
216
- * Creates a new Underpost project, service, or configuration.
217
- * @param {string} repositoryName - The name of the new project or service, or a deployId.
218
- * @param {object} [options={ dev: false, deployId: false, cluster: false, subConf: '' }] - Creation options.
219
- * @param {boolean} [options.dev=false] - If true, sets up a development project.
220
- * @param {boolean} [options.deployId=false] - If true, creates deploy ID configuration files.
221
- * @param {boolean} [options.cluster=false] - If true, creates cluster configuration files.
222
- * @param {string} [options.subConf=''] - If provided, creates a sub-configuration for a deployId.
223
- * @returns {Promise<void>} A promise that resolves when the operation is complete.
223
+ * Initializes a new Underpost repository, optionally setting up a deploy ID or sub-configuration.
224
+ * @param {string} [projectName=''] - The name of the project to create.
225
+ * @param {object} [options={ deployId: '', subConf: '', cluster: false, dev: false }] - Initialization options.
226
+ * @param {string} [options.deployId=''] - The deployment ID to set up.
227
+ * @param {string} [options.subConf=''] - The sub-configuration to create.
228
+ * @param {boolean} [options.cluster=false] - If true, sets up a clustered configuration.
229
+ * @param {boolean} [options.dev=false] - If true, uses development settings.
230
+ * @returns {Promise<boolean>} A promise that resolves when the initialization is complete.
224
231
  * @memberof UnderpostRepository
225
232
  */
226
- new(repositoryName, options = { dev: false, deployId: false, cluster: false, subConf: '' }) {
233
+ new(projectName, options = { deployId: '', subConf: '', cluster: false, dev: false }) {
227
234
  return new Promise(async (resolve, reject) => {
228
235
  try {
229
236
  await logger.setUpInfo();
230
237
  actionInitLog();
231
- if (options.subConf && typeof options.subConf === 'string') {
232
- const deployId = repositoryName;
233
- logger.info('Creating sub conf', {
234
- deployId,
235
- subConf: options.subConf,
236
- });
237
- fs.copySync(
238
- `./engine-private/conf/${deployId}/conf.server.json`,
239
- `./engine-private/conf/${deployId}/conf.server.dev.${options.subConf}.json`,
240
- );
241
- return resolve();
238
+ if (options.deployId) {
239
+ Config.deployIdFactory(options.deployId, options);
240
+ return resolve(true);
242
241
  }
243
- if (repositoryName === 'service')
244
- return resolve(
245
- await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
246
- );
247
- if (options.deployId === true) return Config.deployIdFactory(repositoryName, options);
248
- const npmRoot = getNpmRootPath();
249
- const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
250
- const destFolder = `./${repositoryName}`;
251
- logger.info('Note: This process may take several minutes to complete');
252
- logger.info('build app', { destFolder });
253
- if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
254
- fs.mkdirSync(destFolder, { recursive: true });
255
- if (!options.dev) {
256
- fs.copySync(underpostRoot, destFolder);
257
- fs.writeFileSync(
258
- `${destFolder}/.gitignore`,
259
- fs.readFileSync(`${underpostRoot}/.dockerignore`, 'utf8'),
260
- 'utf8',
261
- );
262
- shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
242
+ if (projectName) {
243
+ const npmRoot = getNpmRootPath();
244
+ const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
245
+ const destFolder = `./${projectName}`;
246
+ logger.info('Note: This process may take several minutes to complete');
247
+ logger.info('build app', { destFolder });
248
+ if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
249
+ fs.mkdirSync(destFolder, { recursive: true });
250
+ if (!options.dev) {
251
+ fs.copySync(underpostRoot, destFolder);
252
+ fs.writeFileSync(
253
+ `${destFolder}/.gitignore`,
254
+ fs.readFileSync(`${underpostRoot}/.dockerignore`, 'utf8'),
255
+ 'utf8',
256
+ );
257
+ shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
258
+ }
259
+ shellExec(`cd ${destFolder} && npm run build`);
260
+ shellExec(`cd ${destFolder} && npm run dev`);
263
261
  }
264
- shellExec(`cd ${destFolder} && npm run build`);
265
- shellExec(`cd ${destFolder} && npm run dev`);
266
- return resolve();
262
+ return resolve(true);
267
263
  } catch (error) {
264
+ console.log(error);
268
265
  logger.error(error, error.stack);
269
- return reject(error.message);
266
+ return reject(false);
270
267
  }
271
268
  });
272
269
  },
package/src/cli/run.js CHANGED
@@ -5,7 +5,14 @@
5
5
  */
6
6
 
7
7
  import { daemonProcess, getTerminalPid, openTerminal, pbcopy, shellCd, shellExec } from '../server/process.js';
8
- import { getNpmRootPath, getUnderpostRootPath, isDeployRunnerContext } from '../server/conf.js';
8
+ import {
9
+ awaitDeployMonitor,
10
+ Config,
11
+ getNpmRootPath,
12
+ getUnderpostRootPath,
13
+ isDeployRunnerContext,
14
+ writeEnv,
15
+ } from '../server/conf.js';
9
16
  import { actionInitLog, loggerFactory } from '../server/logger.js';
10
17
  import UnderpostTest from './test.js';
11
18
  import fs from 'fs-extra';
@@ -15,6 +22,7 @@ import UnderpostRootEnv from './env.js';
15
22
  import UnderpostRepository from './repository.js';
16
23
  import os from 'os';
17
24
  import Underpost from '../index.js';
25
+ import dotenv from 'dotenv';
18
26
 
19
27
  const logger = loggerFactory(import.meta);
20
28
 
@@ -44,6 +52,14 @@ class UnderpostRun {
44
52
  * @property {boolean} k3s - Whether to run in k3s mode.
45
53
  * @property {boolean} kubeadm - Whether to run in kubeadm mode.
46
54
  * @property {boolean} force - Whether to force the operation.
55
+ * @property {boolean} reset - Whether to reset the operation.
56
+ * @property {boolean} tls - Whether to use TLS.
57
+ * @property {string} tty - The TTY option for the container.
58
+ * @property {string} stdin - The stdin option for the container.
59
+ * @property {string} restartPolicy - The restart policy for the container.
60
+ * @property {boolean} terminal - Whether to open a terminal.
61
+ * @property {number} devProxyPortOffset - The port offset for the development proxy.
62
+ * @property {string} confServerPath - The configuration server path.
47
63
  * @memberof UnderpostRun
48
64
  */
49
65
  static DEFAULT_OPTION = {
@@ -59,6 +75,14 @@ class UnderpostRun {
59
75
  k3s: false,
60
76
  kubeadm: false,
61
77
  force: false,
78
+ reset: false,
79
+ tls: false,
80
+ tty: '',
81
+ stdin: '',
82
+ restartPolicy: '',
83
+ terminal: false,
84
+ devProxyPortOffset: 0,
85
+ confServerPath: '',
62
86
  };
63
87
  /**
64
88
  * @static
@@ -106,13 +130,21 @@ class UnderpostRun {
106
130
  },
107
131
  /**
108
132
  * @method kill
109
- * @description Kills the process running on the specified port by finding its PID using `lsof -t -i:${path}`.
133
+ * @description Kills processes listening on the specified port(s). If the `path` contains a `+`, it treats it as a range of ports to kill.
110
134
  * @param {string} path - The input value, identifier, or path for the operation (used as the port number).
111
135
  * @param {Object} options - The default underpost runner options for customizing workflow
112
136
  * @memberof UnderpostRun
113
137
  */
114
- kill: (path, options = UnderpostRun.DEFAULT_OPTION) => {
115
- shellExec(`sudo kill -9 $(lsof -t -i:${path})`);
138
+ kill: (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
139
+ for (const _path of path.split(',')) {
140
+ if (_path.split('+')[1]) {
141
+ let [port, sumPortOffSet] = _path.split('+');
142
+ port = parseInt(port);
143
+ sumPortOffSet = parseInt(sumPortOffSet);
144
+ for (const sumPort of range(0, sumPortOffSet))
145
+ shellExec(`sudo kill -9 $(lsof -t -i:${parseInt(port) + parseInt(sumPort)})`);
146
+ } else shellExec(`sudo kill -9 $(lsof -t -i:${_path})`);
147
+ }
116
148
  },
117
149
  /**
118
150
  * @method secret
@@ -228,30 +260,6 @@ class UnderpostRun {
228
260
  shellExec(`node bin deploy --restore-hosts`);
229
261
  },
230
262
 
231
- /**
232
- * @method cyberia-ide
233
- * @description Starts the development environment (IDE) for both `cyberia-server` and `cyberia-client` repositories.
234
- * @param {string} path - The input value, identifier, or path for the operation.
235
- * @param {Object} options - The default underpost runner options for customizing workflow
236
- * @memberof UnderpostRun
237
- */
238
- 'cyberia-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
239
- const baseCommand = options.dev ? 'node bin' : 'underpost';
240
- shellExec(`${baseCommand} run ide /home/dd/cyberia-server`);
241
- shellExec(`${baseCommand} run ide /home/dd/cyberia-client`);
242
- },
243
- /**
244
- * @method engine-ide
245
- * @description Starts the development environment (IDE) for the `engine` and `engine-private` repositories.
246
- * @param {string} path - The input value, identifier, or path for the operation.
247
- * @param {Object} options - The default underpost runner options for customizing workflow
248
- * @memberof UnderpostRun
249
- */
250
- 'engine-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
251
- const baseCommand = options.dev ? 'node bin' : 'underpost';
252
- shellExec(`${baseCommand} run ide /home/dd/engine`);
253
- shellExec(`${baseCommand} run ide /home/dd/engine/engine-private`);
254
- },
255
263
  /**
256
264
  * @method cluster-build
257
265
  * @description Build configuration for cluster deployment.
@@ -264,8 +272,12 @@ class UnderpostRun {
264
272
  shellExec(`node bin run --dev sync-replica template-deploy`);
265
273
  shellExec(`node bin run sync-replica template-deploy`);
266
274
  shellExec(`node bin env clean`);
267
- shellExec(`git add . && underpost cmt . build cluster-build`);
268
- shellExec(`cd engine-private && git add . && underpost cmt . build cluster-build`);
275
+ for (const deployId of fs.readFileSync('./engine-private/deploy/dd.router', 'utf8').split(','))
276
+ shellExec(`node bin/deploy update-default-conf ${deployId.trim()}`);
277
+ if (path === 'cmt') {
278
+ shellExec(`git add . && underpost cmt . build cluster-build`);
279
+ shellExec(`cd engine-private && git add . && underpost cmt . build cluster-build`);
280
+ }
269
281
  },
270
282
  /**
271
283
  * @method template-deploy
@@ -330,7 +342,9 @@ class UnderpostRun {
330
342
  if (!fs.existsSync(`/home/dd/engine/engine-private`))
331
343
  shellExec(`cd /home/dd/engine && underpost clone ${process.env.GITHUB_USERNAME}/engine-private`);
332
344
  else
333
- shellExec(`cd /home/dd/engine/engine-private underpost pull . ${process.env.GITHUB_USERNAME}/engine-private`);
345
+ shellExec(
346
+ `cd /home/dd/engine/engine-private && underpost pull . ${process.env.GITHUB_USERNAME}/engine-private`,
347
+ );
334
348
  },
335
349
  /**
336
350
  * @method release-deploy
@@ -392,6 +406,7 @@ class UnderpostRun {
392
406
  // Dev usage: node bin run --dev --build sync dd-default
393
407
  const env = options.dev ? 'development' : 'production';
394
408
  const baseCommand = options.dev ? 'node bin' : 'underpost';
409
+ const baseClusterCommand = options.dev ? ' --dev' : '';
395
410
  const defaultPath = [
396
411
  'dd-default',
397
412
  1,
@@ -409,6 +424,8 @@ class UnderpostRun {
409
424
  if (isDeployRunnerContext(path, options)) {
410
425
  const { validVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
411
426
  if (!validVersion) throw new Error('Version mismatch');
427
+ shellExec(`${baseCommand} run${baseClusterCommand} tz`);
428
+ shellExec(`${baseCommand} run${baseClusterCommand} cron`);
412
429
  }
413
430
 
414
431
  const currentTraffic = isDeployRunnerContext(path, options)
@@ -430,6 +447,39 @@ class UnderpostRun {
430
447
  UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
431
448
  } else logger.info('current traffic', UnderpostDeploy.API.getCurrentTraffic(deployId));
432
449
  },
450
+
451
+ /**
452
+ * @method tz
453
+ * @description Sets the system timezone using `timedatectl set-timezone` command.
454
+ * @param {string} path - The input value, identifier, or path for the operation (used as the timezone string).
455
+ * @param {Object} options - The default underpost runner options for customizing workflow
456
+ * @memberof UnderpostRun
457
+ */
458
+ tz: (path, options = UnderpostRun.DEFAULT_OPTION) => {
459
+ const tz = path
460
+ ? path
461
+ : UnderpostRootEnv.API.get('TIME_ZONE', undefined, { disableLog: true })
462
+ ? UnderpostRootEnv.API.get('TIME_ZONE')
463
+ : process.env.TIME_ZONE
464
+ ? process.env.TIME_ZONE
465
+ : 'America/New_York';
466
+ shellExec(`sudo timedatectl set-timezone ${tz}`);
467
+ },
468
+
469
+ /**
470
+ * @method cron
471
+ * @description Sets up and starts the `dd-cron` environment by writing environment variables, starting the cron service, and cleaning up.
472
+ * @param {string} path - The input value, identifier, or path for the operation.
473
+ * @param {Object} options - The default underpost runner options for customizing workflow
474
+ * @memberof UnderpostRun
475
+ */
476
+ cron: (path, options = UnderpostRun.DEFAULT_OPTION) => {
477
+ const env = options.dev ? 'development' : 'production';
478
+ shellExec(`node bin env ${path ? path : 'dd-cron'} ${env}`);
479
+ shellExec(`npm start`);
480
+ shellExec(`node bin env clean`);
481
+ },
482
+
433
483
  /**
434
484
  * @method ls-deployments
435
485
  * @description Retrieves and logs a table of Kubernetes deployments using `UnderpostDeploy.API.get`.
@@ -440,6 +490,16 @@ class UnderpostRun {
440
490
  'ls-deployments': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
441
491
  console.table(await UnderpostDeploy.API.get(path, 'deployments'));
442
492
  },
493
+ /**
494
+ * @method ls-images
495
+ * @description Retrieves and logs a table of currently loaded Docker images in the 'kind-worker' node using `UnderpostDeploy.API.getCurrentLoadedImages`.
496
+ * @param {string} path - The input value, identifier, or path for the operation.
497
+ * @param {Object} options - The default underpost runner options for customizing workflow
498
+ * @memberof UnderpostRun
499
+ */
500
+ 'ls-images': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
501
+ console.table(UnderpostDeploy.API.getCurrentLoadedImages('kind-worker', false));
502
+ },
443
503
 
444
504
  /**
445
505
  * @method host-update
@@ -608,10 +668,16 @@ class UnderpostRun {
608
668
  * @memberof UnderpostRun
609
669
  */
610
670
  'git-conf': (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
611
- const defaultUsername = UnderpostRootEnv.API.get('GITHUB_USERNAME', '', { disableLog: true });
612
- const defaultEmail = UnderpostRootEnv.API.get('GITHUB_EMAIL', '', { disableLog: true });
613
- const [username, email] = path && path.split(',').length > 0 ? path.split(',') : [defaultUsername, defaultEmail];
614
-
671
+ const defaultUsername = UnderpostRootEnv.API.get('GITHUB_USERNAME');
672
+ const defaultEmail = UnderpostRootEnv.API.get('GITHUB_EMAIL');
673
+ const validPath = path && path.split(',').length;
674
+ const [username, email] = validPath ? path.split(',') : [defaultUsername, defaultEmail];
675
+ if (validPath) {
676
+ UnderpostRootEnv.API.set('GITHUB_USERNAME', username);
677
+ UnderpostRootEnv.API.set('GITHUB_EMAIL', email);
678
+ UnderpostRootEnv.API.get('GITHUB_USERNAME');
679
+ UnderpostRootEnv.API.get('GITHUB_EMAIL');
680
+ }
615
681
  shellExec(
616
682
  `git config --global credential.helper "" && ` +
617
683
  `git config credential.helper "" && ` +
@@ -750,6 +816,63 @@ class UnderpostRun {
750
816
  UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
751
817
  },
752
818
 
819
+ /**
820
+ * @method dev
821
+ * @description Starts development servers for client, API, and proxy based on provided parameters (deployId, host, path, clientHostPort).
822
+ * @param {string} path - The input value, identifier, or path for the operation (formatted as `deployId,subConf,host,path,clientHostPort`).
823
+ * @param {Object} options - The default underpost runner options for customizing workflow
824
+ * @memberof UnderpostRun
825
+ */
826
+ dev: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
827
+ let [deployId, subConf, host, _path, clientHostPort] = path.split(',');
828
+ if (options.confServerPath) {
829
+ const confServer = JSON.parse(fs.readFileSync(options.confServerPath, 'utf8'));
830
+ fs.writeFileSync(
831
+ `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`,
832
+ JSON.stringify(
833
+ {
834
+ [host]: {
835
+ [_path]: confServer[host][_path],
836
+ },
837
+ },
838
+ null,
839
+ 4,
840
+ ),
841
+ 'utf8',
842
+ );
843
+ }
844
+ if (!deployId) deployId = 'dd-default';
845
+ if (!host) host = 'default.net';
846
+ if (!_path) _path = '/';
847
+ if (!clientHostPort) clientHostPort = 'localhost:4004';
848
+ if (!subConf) subConf = 'local';
849
+ if (options.reset && fs.existsSync(`./engine-private/conf/${deployId}`))
850
+ fs.removeSync(`./engine-private/conf/${deployId}`);
851
+ if (!fs.existsSync(`./engine-private/conf/${deployId}`)) Config.deployIdFactory(deployId, { subConf });
852
+ if (options.devProxyPortOffset) {
853
+ const envPath = `./engine-private/conf/${deployId}/.env.development`;
854
+ const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
855
+ envObj.DEV_PROXY_PORT_OFFSET = options.devProxyPortOffset;
856
+ writeEnv(envPath, envObj);
857
+ }
858
+ shellExec(`node bin run dev-cluster expose`, { async: true });
859
+ {
860
+ const cmd = `npm run dev-api ${deployId} ${subConf} ${host} ${_path} ${clientHostPort}${options.tls ? ' tls' : ''}`;
861
+ options.terminal ? openTerminal(cmd) : shellExec(cmd, { async: true });
862
+ }
863
+ await awaitDeployMonitor(true);
864
+ {
865
+ const cmd = `npm run dev-client ${deployId} ${subConf} ${host} ${_path} proxy${options.tls ? ' tls' : ''}`;
866
+ options.terminal
867
+ ? openTerminal(cmd)
868
+ : shellExec(cmd, {
869
+ async: true,
870
+ });
871
+ }
872
+ await awaitDeployMonitor(true);
873
+ shellExec(`npm run dev-proxy ${deployId} ${subConf} ${host} ${_path}${options.tls ? ' tls' : ''}`);
874
+ },
875
+
753
876
  /**
754
877
  * @method service
755
878
  * @description Deploys and exposes specific services (like `mongo-express-service`) on the cluster, updating deployment configurations and monitoring status.
@@ -808,6 +931,49 @@ class UnderpostRun {
808
931
  }
809
932
  },
810
933
 
934
+ /**
935
+ * @method sh
936
+ * @description Enables remote control for the Kitty terminal emulator.
937
+ * @param {string} path - The input value, identifier, or path for the operation.
938
+ * @param {Object} options - The default underpost runner options for customizing workflow
939
+ * @memberof UnderpostRun
940
+ */
941
+ sh: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
942
+ shellExec(`kitty -o allow_remote_control=yes`);
943
+ },
944
+
945
+ /**
946
+ * @method log
947
+ * @description Searches and highlights keywords in a specified log file, optionally showing surrounding lines.
948
+ * @param {string} path - The input value, identifier, or path for the operation (formatted as `filePath,keywords,lines`).
949
+ * @param {Object} options - The default underpost runner options for customizing workflow
950
+ * @memberof UnderpostRun
951
+ */
952
+ log: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
953
+ const [filePath, keywords, lines] = path.split(',');
954
+ let result = shellExec(`grep -i -E ${lines ? `-C ${lines} ` : ''}'${keywords}' ${filePath}`, {
955
+ stdout: true,
956
+ silent: true,
957
+ }).replaceAll(`--`, `==============================`.green.bold);
958
+ for (const keyword of keywords.split('|')) result = result.replaceAll(keyword, keyword.bgYellow.black.bold);
959
+ console.log(result);
960
+ },
961
+
962
+ /**
963
+ * @method release-cmt
964
+ * @description Commits and pushes a new release for the `engine` repository with a message indicating the new version.
965
+ * @param {string} path - The input value, identifier, or path for the operation.
966
+ * @param {Object} options - The default underpost runner options for customizing workflow
967
+ * @memberof UnderpostRun
968
+ */
969
+ 'release-cmt': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
970
+ shellExec(`underpost run pull`);
971
+ shellExec(`underpost run secret`);
972
+ shellCd(`/home/dd/engine`);
973
+ shellExec(`underpost cmt --empty . ci engine ' New engine release $(underpost --version)'`);
974
+ shellExec(`underpost push . ${process.env.GITHUB_USERNAME}/engine`);
975
+ },
976
+
811
977
  /**
812
978
  * @method sync-replica
813
979
  * @description Syncs a replica for the dd.router
@@ -824,15 +990,13 @@ class UnderpostRun {
824
990
  const _path = '/single-replica';
825
991
  const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
826
992
  shellExec(`${baseCommand} env ${deployId} ${env}`);
827
- for (const host of Object.keys(confServer)) {
828
- if (!(_path in confServer[host])) continue;
829
- shellExec(`node bin/deploy build-single-replica ${deployId} ${host} ${_path}`);
830
- shellExec(`node bin/deploy build-full-client ${deployId}`);
831
- const node = options.dev || !isDeployRunnerContext(path, options) ? 'kind-control-plane' : os.hostname();
832
- // deployId, replicas, versions, image, node
833
- let defaultPath = [deployId, 1, ``, ``, node];
834
- shellExec(`${baseCommand} run${options.dev === true ? ' --dev' : ''} --build sync ${defaultPath}`);
835
- }
993
+ for (const host of Object.keys(confServer))
994
+ if (_path in confServer[host]) shellExec(`node bin/deploy build-single-replica ${deployId} ${host} ${_path}`);
995
+ const node = options.dev || !isDeployRunnerContext(path, options) ? 'kind-control-plane' : os.hostname();
996
+ // deployId, replicas, versions, image, node
997
+ let defaultPath = [deployId, 1, ``, ``, node];
998
+ shellExec(`${baseCommand} run${options.dev === true ? ' --dev' : ''} --build sync ${defaultPath}`);
999
+ shellExec(`node bin/deploy build-full-client ${deployId}`);
836
1000
  }
837
1001
  if (isDeployRunnerContext(path, options)) shellExec(`${baseCommand} run promote ${path} production`);
838
1002
  },
@@ -896,6 +1060,9 @@ class UnderpostRun {
896
1060
  const volumeMountPath = options.volumeMountPath || path;
897
1061
  const volumeHostPath = options.volumeHostPath || path;
898
1062
  const enableVolumeMount = volumeHostPath && volumeMountPath;
1063
+ const tty = options.tty ? 'true' : 'false';
1064
+ const stdin = options.stdin ? 'true' : 'false';
1065
+ const restartPolicy = options.restartPolicy || 'Never';
899
1066
 
900
1067
  if (options.volumeType === 'dev') options.volumeType = 'FileOrCreate';
901
1068
  const volumeType =
@@ -909,15 +1076,17 @@ kind: Pod
909
1076
  metadata:
910
1077
  name: ${podName}
911
1078
  namespace: ${namespace}
1079
+ labels:
1080
+ app: ${podName}
912
1081
  spec:
913
- restartPolicy: Never
1082
+ restartPolicy: ${restartPolicy}
914
1083
  ${runtimeClassName ? ` runtimeClassName: ${runtimeClassName}` : ''}
915
1084
  containers:
916
1085
  - name: ${containerName}
917
1086
  image: ${imageName}
918
1087
  imagePullPolicy: IfNotPresent
919
- tty: true
920
- stdin: true
1088
+ tty: ${tty}
1089
+ stdin: ${stdin}
921
1090
  command: ${JSON.stringify(options.command ? options.command : ['/bin/bash', '-c'])}
922
1091
  ${
923
1092
  args.length > 0
@@ -953,7 +1122,7 @@ ${
953
1122
  : ''
954
1123
  }
955
1124
  EOF`;
956
- shellExec(`kubectl delete pod ${podName}`);
1125
+ shellExec(`kubectl delete pod ${podName} --ignore-not-found`);
957
1126
  console.log(cmd);
958
1127
  shellExec(cmd, { disableLog: true });
959
1128
  const successInstance = await UnderpostTest.API.statusMonitor(podName);
@@ -11,7 +11,7 @@ const AgGrid = {
11
11
  grids: {},
12
12
  theme: `ag-theme-alpine`, // quartz
13
13
  Render: async function (options) {
14
- let { id } = options;
14
+ let { id, paginationOptions } = options;
15
15
  setTimeout(() => {
16
16
  // Grid Options: Contains all of the grid configurations
17
17
  const gridOptions = {
@@ -34,6 +34,38 @@ const AgGrid = {
34
34
  return params.data && params.data._new;
35
35
  },
36
36
  },
37
+ // Cell rendering events
38
+ onFirstDataRendered: options?.onFirstDataRendered,
39
+ onViewportChanged: options?.onViewportChanged,
40
+ onModelUpdated: options?.onModelUpdated,
41
+ onVirtualRowRemoved: options?.onVirtualRowRemoved,
42
+ // Cell interaction events
43
+ onCellClicked: options?.onCellClicked,
44
+ onCellDoubleClicked: options?.onCellDoubleClicked,
45
+ onCellFocused: options?.onCellFocused,
46
+ onCellMouseOver: options?.onCellMouseOver,
47
+ onCellMouseOut: options?.onCellMouseOut,
48
+ onCellValueChanged: options?.onCellValueChanged,
49
+ // set background colour on every row, this is probably bad, should be using CSS classes
50
+ // rowStyle: { background: 'black' },
51
+
52
+ // set background colour on even rows again, this looks bad, should be using CSS classes
53
+ // getRowStyle: (params) => {
54
+ // if (params.node.rowIndex % 2 === 0) {
55
+ // return { background: 'red' };
56
+ // }
57
+ // },
58
+
59
+ // all rows assigned CSS class 'my-green-class'
60
+ // rowClass: 'my-green-class',
61
+
62
+ // all even rows assigned 'my-shaded-effect'
63
+ // getRowClass: (params) => {
64
+ // if (params.node.rowIndex % 2 === 0) {
65
+ // return 'my-shaded-effect';
66
+ // }
67
+ // },
68
+
37
69
  // domLayout: 'autoHeight', || 'normal'
38
70
  // Column Definitions: Defines & controls grid columns.
39
71
  columnDefs: options?.gridOptions?.rowData?.[0]
@@ -62,7 +94,9 @@ const AgGrid = {
62
94
  if (!options.style || !options.style.height) {
63
95
  if (options.parentModal && Modal.Data[options.parentModal].options.observer) {
64
96
  Modal.Data[options.parentModal].onObserverListener[id + '-observer'] = ({ width, height }) => {
65
- if (s(`.${id}`)) s(`.${id}`).style.height = `${height - 180}px`;
97
+ if (s(`.${id}`))
98
+ s(`.${id}`).style.height =
99
+ `${height - 180 + (options.customHeightOffset ? options.customHeightOffset : 0)}px`;
66
100
  else delete Modal.Data[options.parentModal].onObserverListener[id + '-observer'];
67
101
  };
68
102
  s(`.${id}`).style.height = `${s(`.${options.parentModal}`).offsetHeight - 180}px`;
@@ -70,6 +104,9 @@ const AgGrid = {
70
104
  }
71
105
  });
72
106
  const usePagination = options?.usePagination;
107
+ const limitOptionsAttr = paginationOptions?.limitOptions
108
+ ? `limit-options='${JSON.stringify(paginationOptions.limitOptions)}'`
109
+ : '';
73
110
  return html`
74
111
  <div
75
112
  class="${id} ${this.theme}${options?.darkTheme ? `-dark` : ''}"
@@ -77,7 +114,7 @@ const AgGrid = {
77
114
  ? Object.keys(options.style).map((styleKey) => `${styleKey}: ${options.style[styleKey]}; `)
78
115
  : ''}"
79
116
  ></div>
80
- ${usePagination ? `<ag-pagination id="ag-pagination-${id}"></ag-pagination>` : ''}
117
+ ${usePagination ? `<ag-pagination id="ag-pagination-${id}" ${limitOptionsAttr}></ag-pagination>` : ''}
81
118
  `;
82
119
  },
83
120
  RenderStyle: async function (
@@ -159,6 +196,7 @@ const AgGrid = {
159
196
  ${darkTheme
160
197
  ? html`
161
198
  <style>
199
+ .row-new-highlight,
162
200
  .ag-row.row-new-highlight {
163
201
  background-color: #6d68ff !important;
164
202
  transition: background-color 1s ease-out;
@@ -172,6 +210,7 @@ const AgGrid = {
172
210
  </style>
173
211
  `
174
212
  : html`<style>
213
+ .row-new-highlight,
175
214
  .ag-row.row-new-highlight {
176
215
  background-color: #d0eaf8 !important;
177
216
  transition: background-color 1s ease-out;
@@ -101,6 +101,7 @@ const cap = (str) =>
101
101
 
102
102
  const capFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
103
103
 
104
+ // Other option: Array.from(new Set(arr))
104
105
  const uniqueArray = (arr) => arr.filter((item, pos) => arr.indexOf(item) == pos);
105
106
 
106
107
  const orderArrayFromAttrInt = (arr, attr, type) =>
@@ -946,6 +947,8 @@ const emotionsData = [
946
947
  const userRoleEnum = ['admin', 'moderator', 'user', 'guest'];
947
948
  const commonAdminGuard = (role) => userRoleEnum.indexOf(role) === userRoleEnum.indexOf('admin');
948
949
  const commonModeratorGuard = (role) => userRoleEnum.indexOf(role) <= userRoleEnum.indexOf('moderator');
950
+ const commonUserGuard = (role) => userRoleEnum.indexOf(role) <= userRoleEnum.indexOf('user');
951
+ const commonGuestGuard = (role) => userRoleEnum.indexOf(role) <= userRoleEnum.indexOf('guest');
949
952
 
950
953
  export {
951
954
  s4,
@@ -1002,6 +1005,8 @@ export {
1002
1005
  generateRandomPasswordSelection,
1003
1006
  commonAdminGuard,
1004
1007
  commonModeratorGuard,
1008
+ commonUserGuard,
1009
+ commonGuestGuard,
1005
1010
  isChileanIdentityDocument,
1006
1011
  getCurrentTrace,
1007
1012
  userRoleEnum,