underpost 2.8.877 → 2.8.881
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 +40 -3
- package/.env.test +35 -3
- package/.github/workflows/release.cd.yml +3 -3
- package/README.md +48 -36
- package/bin/deploy.js +40 -0
- package/cli.md +89 -86
- package/conf.js +28 -3
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +1 -2
- 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/user/user.router.js +4 -3
- package/src/cli/deploy.js +1 -1
- package/src/cli/index.js +3 -0
- package/src/cli/repository.js +2 -2
- package/src/cli/run.js +29 -1
- package/src/client/Default.index.js +42 -1
- package/src/client/components/core/Account.js +8 -1
- package/src/client/components/core/AgGrid.js +18 -9
- package/src/client/components/core/BtnIcon.js +3 -2
- package/src/client/components/core/Content.js +13 -11
- package/src/client/components/core/CssCore.js +4 -0
- package/src/client/components/core/Docs.js +0 -3
- package/src/client/components/core/Input.js +34 -19
- package/src/client/components/core/Modal.js +29 -7
- package/src/client/components/core/ObjectLayerEngine.js +370 -0
- package/src/client/components/core/ObjectLayerEngineModal.js +1 -0
- package/src/client/components/core/Panel.js +7 -2
- package/src/client/components/core/PanelForm.js +187 -63
- package/src/client/components/core/VanillaJs.js +3 -0
- package/src/client/components/default/MenuDefault.js +94 -41
- package/src/client/components/default/RoutesDefault.js +2 -0
- package/src/client/services/default/default.management.js +1 -0
- package/src/client/services/document/document.service.js +97 -0
- package/src/client/services/file/file.service.js +2 -0
- package/src/client/services/user/user.service.js +1 -0
- package/src/client/ssr/Render.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +2 -0
- package/src/client/ssr/head/Seo.js +1 -0
- package/src/index.js +1 -1
- package/src/mailer/EmailRender.js +1 -1
- package/src/server/auth.js +4 -3
- package/src/server/client-build.js +2 -3
- package/src/server/client-formatted.js +40 -12
- package/src/server/conf.js +42 -3
- package/src/server/object-layer.js +196 -0
- package/src/server/runtime.js +18 -21
- package/src/server/ssr.js +52 -10
- package/src/server/valkey.js +89 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { loggerFactory } from '../../server/logger.js';
|
|
2
|
+
import { DocumentController } from './document.controller.js';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
const logger = loggerFactory(import.meta);
|
|
6
|
+
|
|
7
|
+
const DocumentRouter = (options) => {
|
|
8
|
+
const router = express.Router();
|
|
9
|
+
const authMiddleware = options.authMiddleware;
|
|
10
|
+
router.post(`/:id`, authMiddleware, async (req, res) => await DocumentController.post(req, res, options));
|
|
11
|
+
router.post(`/`, authMiddleware, async (req, res) => await DocumentController.post(req, res, options));
|
|
12
|
+
router.get(`/public`, async (req, res) => await DocumentController.get(req, res, options));
|
|
13
|
+
router.get(`/:id`, authMiddleware, async (req, res) => await DocumentController.get(req, res, options));
|
|
14
|
+
router.get(`/`, authMiddleware, async (req, res) => await DocumentController.get(req, res, options));
|
|
15
|
+
router.put(`/:id`, authMiddleware, async (req, res) => await DocumentController.put(req, res, options));
|
|
16
|
+
router.put(`/`, authMiddleware, async (req, res) => await DocumentController.put(req, res, options));
|
|
17
|
+
router.delete(`/:id`, authMiddleware, async (req, res) => await DocumentController.delete(req, res, options));
|
|
18
|
+
router.delete(`/`, authMiddleware, async (req, res) => await DocumentController.delete(req, res, options));
|
|
19
|
+
return router;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const ApiRouter = DocumentRouter;
|
|
23
|
+
|
|
24
|
+
export { ApiRouter, DocumentRouter };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { loggerFactory } from '../../server/logger.js';
|
|
2
|
+
import { DataBaseProvider } from '../../db/DataBaseProvider.js';
|
|
3
|
+
import { DocumentDto } from './document.model.js';
|
|
4
|
+
import { uniqueArray } from '../../client/components/core/CommonJs.js';
|
|
5
|
+
import { getBearerToken, verifyJWT } from '../../server/auth.js';
|
|
6
|
+
import { isValidObjectId } from 'mongoose';
|
|
7
|
+
|
|
8
|
+
const logger = loggerFactory(import.meta);
|
|
9
|
+
|
|
10
|
+
const DocumentService = {
|
|
11
|
+
post: async (req, res, options) => {
|
|
12
|
+
/** @type {import('./document.model.js').DocumentModel} */
|
|
13
|
+
const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
|
|
14
|
+
|
|
15
|
+
switch (req.params.id) {
|
|
16
|
+
default:
|
|
17
|
+
req.body.userId = req.auth.user._id;
|
|
18
|
+
return await new Document(req.body).save();
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
get: async (req, res, options) => {
|
|
22
|
+
/** @type {import('./document.model.js').DocumentModel} */
|
|
23
|
+
const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
|
|
24
|
+
/** @type {import('../user/user.model.js').UserModel} */
|
|
25
|
+
const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.User;
|
|
26
|
+
|
|
27
|
+
if (req.path.startsWith('/public') && req.query['tags']) {
|
|
28
|
+
const publisherUsers = await User.find({ $or: [{ role: 'admin' }, { role: 'moderator' }] });
|
|
29
|
+
|
|
30
|
+
const token = getBearerToken(req);
|
|
31
|
+
let user;
|
|
32
|
+
if (token) user = verifyJWT(token, options);
|
|
33
|
+
|
|
34
|
+
const queryPayload = {
|
|
35
|
+
userId: {
|
|
36
|
+
$in: publisherUsers.map((p) => p._id).concat(user?.role && user.role !== 'guest' ? [user._id] : []),
|
|
37
|
+
},
|
|
38
|
+
tags: {
|
|
39
|
+
// $in: uniqueArray(['public'].concat(req.query['tags'].split(','))),
|
|
40
|
+
$all: uniqueArray(['public'].concat(req.query['tags'].split(','))),
|
|
41
|
+
},
|
|
42
|
+
...(req.query.cid
|
|
43
|
+
? {
|
|
44
|
+
_id: {
|
|
45
|
+
$in: req.query.cid.split(',').filter((cid) => isValidObjectId(cid)),
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
: undefined),
|
|
49
|
+
};
|
|
50
|
+
logger.info('queryPayload', queryPayload);
|
|
51
|
+
// sort in descending (-1) order by length
|
|
52
|
+
const sort = { createdAt: -1 };
|
|
53
|
+
const limit = req.query.limit ? parseInt(req.query.limit, 10) : 6;
|
|
54
|
+
const skip = req.query.skip ? parseInt(req.query.skip, 10) : 0;
|
|
55
|
+
|
|
56
|
+
return await Document.find(queryPayload)
|
|
57
|
+
.sort(sort)
|
|
58
|
+
.limit(limit)
|
|
59
|
+
.skip(skip)
|
|
60
|
+
.populate(DocumentDto.populate.file())
|
|
61
|
+
.populate(user && user.role !== 'guest' ? DocumentDto.populate.user() : null);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
switch (req.params.id) {
|
|
65
|
+
default:
|
|
66
|
+
return await Document.find({
|
|
67
|
+
userId: req.auth.user._id,
|
|
68
|
+
...(req.params.id ? { _id: req.params.id } : undefined),
|
|
69
|
+
}).populate(DocumentDto.populate.file());
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
delete: async (req, res, options) => {
|
|
73
|
+
/** @type {import('./document.model.js').DocumentModel} */
|
|
74
|
+
const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
|
|
75
|
+
/** @type {import('../file/file.model.js').FileModel} */
|
|
76
|
+
const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
|
|
77
|
+
|
|
78
|
+
switch (req.params.id) {
|
|
79
|
+
default: {
|
|
80
|
+
const document = await Document.findOne({ _id: req.params.id });
|
|
81
|
+
if (!document) throw new Error('document not found');
|
|
82
|
+
|
|
83
|
+
if (document.userId.toString() !== req.auth.user._id) throw new Error('invalid user');
|
|
84
|
+
|
|
85
|
+
if (document.mdFileId) {
|
|
86
|
+
const file = await File.findOne({ _id: document.mdFileId });
|
|
87
|
+
if (file) await File.findByIdAndDelete(document.mdFileId);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (document.fileId) {
|
|
91
|
+
const file = await File.findOne({ _id: document.fileId });
|
|
92
|
+
if (file) await File.findByIdAndDelete(document.fileId);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return await Document.findByIdAndDelete(req.params.id);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
put: async (req, res, options) => {
|
|
100
|
+
/** @type {import('./document.model.js').DocumentModel} */
|
|
101
|
+
const Document = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Document;
|
|
102
|
+
/** @type {import('../file/file.model.js').FileModel} */
|
|
103
|
+
const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
|
|
104
|
+
|
|
105
|
+
switch (req.params.id) {
|
|
106
|
+
default: {
|
|
107
|
+
const document = await Document.findOne({ _id: req.params.id });
|
|
108
|
+
if (!document) throw new Error(`Document not found`);
|
|
109
|
+
|
|
110
|
+
if (document.mdFileId) {
|
|
111
|
+
const file = await File.findOne({ _id: document.mdFileId });
|
|
112
|
+
if (file) await File.findByIdAndDelete(document.mdFileId);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (document.fileId) {
|
|
116
|
+
const file = await File.findOne({ _id: document.fileId });
|
|
117
|
+
if (file) await File.findByIdAndDelete(document.fileId);
|
|
118
|
+
}
|
|
119
|
+
return await Document.findByIdAndUpdate(req.params.id, req.body);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export { DocumentService };
|
|
@@ -20,7 +20,21 @@ const FileController = {
|
|
|
20
20
|
get: async (req, res, options) => {
|
|
21
21
|
try {
|
|
22
22
|
const result = await FileService.get(req, res, options);
|
|
23
|
-
if (result instanceof Buffer)
|
|
23
|
+
if (result instanceof Buffer) {
|
|
24
|
+
if (
|
|
25
|
+
process.env.NODE_ENV === 'development' ||
|
|
26
|
+
req.hostname === options.host ||
|
|
27
|
+
(options.origins && options.origins.find((o) => o.match(req.hostname)))
|
|
28
|
+
) {
|
|
29
|
+
res.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
30
|
+
return res.status(200).end(result);
|
|
31
|
+
}
|
|
32
|
+
return res.status(403).json({
|
|
33
|
+
status: 'error',
|
|
34
|
+
message: 'Forbidden',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
return res.status(200).json({
|
|
25
39
|
status: 'success',
|
|
26
40
|
data: result,
|
|
@@ -48,9 +48,10 @@ const UserRouter = (options) => {
|
|
|
48
48
|
check: fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-check.png`),
|
|
49
49
|
},
|
|
50
50
|
header: (res) => {
|
|
51
|
-
res.
|
|
52
|
-
res.
|
|
53
|
-
res.
|
|
51
|
+
res.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
52
|
+
res.set('Access-Control-Allow-Origin', '*');
|
|
53
|
+
res.set('Access-Control-Allow-Headers', '*');
|
|
54
|
+
res.set('Content-Type', 'image/png');
|
|
54
55
|
},
|
|
55
56
|
};
|
|
56
57
|
|
package/src/cli/deploy.js
CHANGED
|
@@ -334,7 +334,7 @@ EOF`);
|
|
|
334
334
|
if (!options.replicas) options.replicas = 1;
|
|
335
335
|
if (options.sync) UnderpostDeploy.API.sync(deployList, options);
|
|
336
336
|
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
|
|
337
|
-
if (options.infoRouter === true) {
|
|
337
|
+
if (options.infoRouter === true || options.buildManifest === true) {
|
|
338
338
|
logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
339
339
|
return;
|
|
340
340
|
}
|
package/src/cli/index.js
CHANGED
|
@@ -24,6 +24,7 @@ program
|
|
|
24
24
|
.command('new')
|
|
25
25
|
.argument('<app-name>', 'The name or deploy-id of the application to create.')
|
|
26
26
|
.option('--deploy-id', 'Crete deploy ID conf env files')
|
|
27
|
+
.option('--cluster', 'Create deploy ID cluster files and sync to current cluster')
|
|
27
28
|
.option('--dev', 'Sets the development cli context')
|
|
28
29
|
.description('Initializes a new Underpost project with a predefined structure.')
|
|
29
30
|
.action(Underpost.repo.new);
|
|
@@ -359,6 +360,8 @@ program
|
|
|
359
360
|
.option('--image-name <image-name>', 'Optional: Specifies the image name for test execution.')
|
|
360
361
|
.option('--container-name <container-name>', 'Optional: Specifies the container name for test execution.')
|
|
361
362
|
.option('--namespace <namespace>', 'Optional: Specifies the namespace for test execution.')
|
|
363
|
+
.option('--kubeadm', 'Flag to indicate Kubeadm cluster type context')
|
|
364
|
+
.option('--k3s', 'Flag to indicate K3s cluster type context')
|
|
362
365
|
.description('Runs a script from the specified path.')
|
|
363
366
|
.action(UnderpostRun.API.callback);
|
|
364
367
|
|
package/src/cli/repository.js
CHANGED
|
@@ -90,7 +90,7 @@ class UnderpostRepository {
|
|
|
90
90
|
);
|
|
91
91
|
},
|
|
92
92
|
|
|
93
|
-
new(repositoryName, options = { dev: false, deployId: false }) {
|
|
93
|
+
new(repositoryName, options = { dev: false, deployId: false, cluster: false }) {
|
|
94
94
|
return new Promise(async (resolve, reject) => {
|
|
95
95
|
try {
|
|
96
96
|
await logger.setUpInfo();
|
|
@@ -99,7 +99,7 @@ class UnderpostRepository {
|
|
|
99
99
|
return resolve(
|
|
100
100
|
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
|
|
101
101
|
);
|
|
102
|
-
if (options.deployId === true) return Config.deployIdFactory(repositoryName);
|
|
102
|
+
if (options.deployId === true) return Config.deployIdFactory(repositoryName, options);
|
|
103
103
|
const npmRoot = getNpmRootPath();
|
|
104
104
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
105
105
|
const destFolder = `./${repositoryName}`;
|
package/src/cli/run.js
CHANGED
|
@@ -23,6 +23,8 @@ class UnderpostRun {
|
|
|
23
23
|
namespace: '',
|
|
24
24
|
build: false,
|
|
25
25
|
replicas: 1,
|
|
26
|
+
k3s: false,
|
|
27
|
+
kubeadm: false,
|
|
26
28
|
};
|
|
27
29
|
static RUNNERS = {
|
|
28
30
|
'spark-template': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
@@ -107,6 +109,8 @@ class UnderpostRun {
|
|
|
107
109
|
},
|
|
108
110
|
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
109
111
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
112
|
+
shellExec(`${baseCommand} run clean`);
|
|
113
|
+
shellExec(`${baseCommand} push ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
110
114
|
shellCd('/home/dd/engine');
|
|
111
115
|
shellExec(`git reset`);
|
|
112
116
|
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
@@ -251,7 +255,24 @@ class UnderpostRun {
|
|
|
251
255
|
},
|
|
252
256
|
'db-client': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
253
257
|
const { underpostRoot } = options;
|
|
258
|
+
|
|
259
|
+
const image = 'adminer:4.7.6-standalone';
|
|
260
|
+
|
|
261
|
+
if (!options.kubeadm && !options.k3s) {
|
|
262
|
+
// Only load if not kubeadm/k3s (Kind needs it)
|
|
263
|
+
shellExec(`docker pull ${image}`);
|
|
264
|
+
shellExec(`sudo kind load docker-image ${image}`);
|
|
265
|
+
} else if (options.kubeadm || options.k3s)
|
|
266
|
+
// For kubeadm/k3s, ensure it's available for containerd
|
|
267
|
+
shellExec(`sudo crictl pull ${image}`);
|
|
268
|
+
|
|
269
|
+
shellExec(`kubectl delete deployment adminer`);
|
|
254
270
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/.`);
|
|
271
|
+
const successInstance = await UnderpostTest.API.statusMonitor('adminer', 'Running', 'pods', 1000, 60 * 10);
|
|
272
|
+
|
|
273
|
+
if (successInstance) {
|
|
274
|
+
shellExec(`underpost deploy --expose adminer`);
|
|
275
|
+
}
|
|
255
276
|
},
|
|
256
277
|
promote: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
257
278
|
let [inputDeployId, inputEnv, inputReplicas] = path.split(',');
|
|
@@ -330,8 +351,15 @@ class UnderpostRun {
|
|
|
330
351
|
const checkStatusIterationMsDelay = 1000;
|
|
331
352
|
const iteratorTag = `[${deployId}-${env}-${targetTraffic}]`;
|
|
332
353
|
logger.info('Deployment init', { deployId, env, targetTraffic, checkStatusIterationMsDelay });
|
|
354
|
+
const minReadyOk = 3;
|
|
355
|
+
let readyOk = 0;
|
|
333
356
|
|
|
334
|
-
while (
|
|
357
|
+
while (readyOk < minReadyOk) {
|
|
358
|
+
const ready = UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready;
|
|
359
|
+
if (ready === true) {
|
|
360
|
+
readyOk++;
|
|
361
|
+
logger.info(`${iteratorTag} | Deployment ready. Verification number: ${readyOk}`);
|
|
362
|
+
}
|
|
335
363
|
await timer(checkStatusIterationMsDelay);
|
|
336
364
|
checkStatusIteration++;
|
|
337
365
|
logger.info(
|
|
@@ -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
|
});
|
|
@@ -195,7 +195,14 @@ const Account = {
|
|
|
195
195
|
await this.instanceModalUiEvents({ user });
|
|
196
196
|
});
|
|
197
197
|
return html`
|
|
198
|
-
<
|
|
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>
|
|
199
206
|
${renderWave({ id: waveAnimationId })}
|
|
200
207
|
|
|
201
208
|
<form class="in">
|
|
@@ -5,6 +5,7 @@ import { ThemeEvents, darkTheme } from './Css.js';
|
|
|
5
5
|
import { append, htmls, s } from './VanillaJs.js';
|
|
6
6
|
import { getProxyPath } from './Router.js';
|
|
7
7
|
import './Pagination.js';
|
|
8
|
+
import { Modal } from './Modal.js';
|
|
8
9
|
|
|
9
10
|
const AgGrid = {
|
|
10
11
|
grids: {},
|
|
@@ -57,18 +58,26 @@ const AgGrid = {
|
|
|
57
58
|
delete ThemeEvents[id];
|
|
58
59
|
}
|
|
59
60
|
};
|
|
61
|
+
|
|
62
|
+
if (!options.style || !options.style.height) {
|
|
63
|
+
if (options.parentModal && Modal.Data[options.parentModal].options.observer) {
|
|
64
|
+
Modal.Data[options.parentModal].onObserverListener[id + '-observer'] = ({ width, height }) => {
|
|
65
|
+
if (s(`.${id}`)) s(`.${id}`).style.height = `${height - 180}px`;
|
|
66
|
+
else delete Modal.Data[options.parentModal].onObserverListener[id + '-observer'];
|
|
67
|
+
};
|
|
68
|
+
s(`.${id}`).style.height = `${s(`.${options.parentModal}`).offsetHeight - 180}px`;
|
|
69
|
+
} else s(`.${id}`).style.height = '500px';
|
|
70
|
+
}
|
|
60
71
|
});
|
|
61
72
|
const usePagination = options?.usePagination;
|
|
62
73
|
return html`
|
|
63
|
-
<div
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
style
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
${usePagination ? `<ag-pagination id="ag-pagination-${id}"></ag-pagination>` : ''}
|
|
71
|
-
</div>
|
|
74
|
+
<div
|
|
75
|
+
class="${id} ${this.theme}${options?.darkTheme ? `-dark` : ''}"
|
|
76
|
+
style="${options?.style
|
|
77
|
+
? Object.keys(options.style).map((styleKey) => `${styleKey}: ${options.style[styleKey]}; `)
|
|
78
|
+
: ''}"
|
|
79
|
+
></div>
|
|
80
|
+
${usePagination ? `<ag-pagination id="ag-pagination-${id}"></ag-pagination>` : ''}
|
|
72
81
|
`;
|
|
73
82
|
},
|
|
74
83
|
RenderStyle: async function (
|
|
@@ -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(() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { marked } from 'marked';
|
|
2
2
|
import { FileService } from '../../services/file/file.service.js';
|
|
3
3
|
import { append, getBlobFromUint8ArrayFile, getRawContentFile, htmls, s } from './VanillaJs.js';
|
|
4
|
-
import {
|
|
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';
|
|
@@ -137,12 +137,9 @@ const Content = {
|
|
|
137
137
|
case 'svg':
|
|
138
138
|
case 'gif':
|
|
139
139
|
case 'png': {
|
|
140
|
-
const url = options
|
|
141
|
-
? options.url
|
|
142
|
-
: file._id
|
|
143
|
-
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
144
|
-
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
140
|
+
const url = Content.urlFactory(options);
|
|
145
141
|
const imgRender = html`<img
|
|
142
|
+
alt="${file.name ? file.name : `file ${s4()}`}"
|
|
146
143
|
class="in ${options.class}"
|
|
147
144
|
${styleFactory(options.style, `${renderChessPattern(50)}`)}
|
|
148
145
|
src="${url}"
|
|
@@ -151,11 +148,7 @@ const Content = {
|
|
|
151
148
|
break;
|
|
152
149
|
}
|
|
153
150
|
case 'pdf': {
|
|
154
|
-
const url = options
|
|
155
|
-
? options.url
|
|
156
|
-
: file._id
|
|
157
|
-
? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
|
|
158
|
-
: URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
|
|
151
|
+
const url = Content.urlFactory(options);
|
|
159
152
|
render += html`<iframe
|
|
160
153
|
class="in ${options.class} iframe-${options.idModal}"
|
|
161
154
|
${styleFactory(options.style)}
|
|
@@ -189,6 +182,15 @@ const Content = {
|
|
|
189
182
|
if (options.raw) return render;
|
|
190
183
|
append(container, render);
|
|
191
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
|
+
},
|
|
192
194
|
};
|
|
193
195
|
|
|
194
196
|
export { Content };
|
|
@@ -215,6 +215,10 @@ const CssCommonCore = async () => {
|
|
|
215
215
|
.bar-default-modal {
|
|
216
216
|
overflow: hidden;
|
|
217
217
|
}
|
|
218
|
+
.panel-placeholder-bottom {
|
|
219
|
+
height: 100px;
|
|
220
|
+
color: gray;
|
|
221
|
+
}
|
|
218
222
|
</style>
|
|
219
223
|
${boxShadow({ selector: '.account-profile-image' })}
|
|
220
224
|
<div class="ag-grid-style"></div>`;
|
|
@@ -129,19 +129,16 @@ const Docs = {
|
|
|
129
129
|
s(`.btn-docs-src`).onclick = async () => {
|
|
130
130
|
setQueryPath({ path: 'docs', queryPath: 'src' });
|
|
131
131
|
cleanActive();
|
|
132
|
-
s(`.btn-docs-src`).classList.add('main-btn-menu-active');
|
|
133
132
|
await this.RenderModal('src', options.modalOptions);
|
|
134
133
|
};
|
|
135
134
|
s(`.btn-docs-api`).onclick = async () => {
|
|
136
135
|
setQueryPath({ path: 'docs', queryPath: 'api' });
|
|
137
136
|
cleanActive();
|
|
138
|
-
s(`.btn-docs-api`).classList.add('main-btn-menu-active');
|
|
139
137
|
await this.RenderModal('api', options.modalOptions);
|
|
140
138
|
};
|
|
141
139
|
s(`.btn-docs-coverage`).onclick = async () => {
|
|
142
140
|
setQueryPath({ path: 'docs', queryPath: 'coverage' });
|
|
143
141
|
cleanActive();
|
|
144
|
-
s(`.btn-docs-coverage`).classList.add('main-btn-menu-active');
|
|
145
142
|
await this.RenderModal('coverage', options.modalOptions);
|
|
146
143
|
};
|
|
147
144
|
|
|
@@ -7,7 +7,7 @@ import { loggerFactory } from './Logger.js';
|
|
|
7
7
|
import { RichText } from './RichText.js';
|
|
8
8
|
import { ToggleSwitch } from './ToggleSwitch.js';
|
|
9
9
|
import { Translate } from './Translate.js';
|
|
10
|
-
import { htmls, s } from './VanillaJs.js';
|
|
10
|
+
import { htmls, htmlStrSanitize, s } from './VanillaJs.js';
|
|
11
11
|
const logger = loggerFactory(import.meta);
|
|
12
12
|
|
|
13
13
|
const fileFormDataFactory = (e, extensions) => {
|
|
@@ -61,22 +61,27 @@ const Input = {
|
|
|
61
61
|
};
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
const labelValue = htmlStrSanitize(options.label) ? htmlStrSanitize(options.label) : id;
|
|
65
|
+
|
|
66
|
+
const inputElement = html` <label for="${id}-name">
|
|
67
|
+
<span class="hide">${labelValue}</span>
|
|
68
|
+
<input
|
|
69
|
+
type="${options?.type ? options.type : 'text'}"
|
|
70
|
+
class="${options.inputClass ? options.inputClass : 'in wfa'} ${id}"
|
|
71
|
+
${options?.min !== undefined ? `min="${options.min}"` : ''}
|
|
72
|
+
${options?.max !== undefined ? `max="${options.max}"` : ''}
|
|
73
|
+
placeholder${options?.placeholder ? `="${options.placeholder}"` : ''}
|
|
74
|
+
${options?.value !== undefined ? `value="${options.value}"` : ''}
|
|
75
|
+
${options?.autocomplete ? `autocomplete="${options.autocomplete}"` : ''}
|
|
76
|
+
${options?.disabled ? `disabled` : ''}
|
|
77
|
+
${options?.name !== undefined ? `name="${options.name}"` : `name='${id}-name'`}
|
|
78
|
+
${options?.pattern !== undefined ? `pattern="${options.pattern}"` : ''}
|
|
79
|
+
${options?.pattern === undefined && options.type === 'tel' ? `pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"` : ''}
|
|
80
|
+
${options?.required ? ` required ` : ''}
|
|
81
|
+
${options?.accept ? `accept="${options.accept}"` : ''}
|
|
82
|
+
${options?.multiple ? `multiple="multiple"` : ''}
|
|
83
|
+
id="${id}-name"
|
|
84
|
+
/></label>
|
|
80
85
|
<div class="${id}-input-extension input-info input-extension ${options?.extension ? '' : 'hide'}">
|
|
81
86
|
${options?.extension ? await options.extension() : ''}
|
|
82
87
|
</div>`;
|
|
@@ -244,7 +249,12 @@ const Input = {
|
|
|
244
249
|
};
|
|
245
250
|
|
|
246
251
|
const InputFile = {
|
|
247
|
-
Render: async function (
|
|
252
|
+
Render: async function (
|
|
253
|
+
options = { id: '', multiple: false, extensionsAccept: [] },
|
|
254
|
+
on = { change: () => {}, clear: () => {} },
|
|
255
|
+
) {
|
|
256
|
+
let { id, multiple, extensionsAccept } = options;
|
|
257
|
+
if (!extensionsAccept) extensionsAccept = [];
|
|
248
258
|
// drag drop multi file
|
|
249
259
|
const gridId = `ag-grid-input-file-${id}`;
|
|
250
260
|
setTimeout(() => {
|
|
@@ -322,7 +332,12 @@ const InputFile = {
|
|
|
322
332
|
return html` <div class="fl">
|
|
323
333
|
<div class="in fll input-file-col">
|
|
324
334
|
<div class="in section-mp input-file-sub-col">
|
|
325
|
-
<input
|
|
335
|
+
<input
|
|
336
|
+
class="wfa ${id}"
|
|
337
|
+
type="file"
|
|
338
|
+
${multiple ? `multiple="multiple"` : ''}
|
|
339
|
+
${extensionsAccept.length > 0 ? `accept="${extensionsAccept.join(', ')}"` : ''}
|
|
340
|
+
/>
|
|
326
341
|
<div class="in">
|
|
327
342
|
${await BtnIcon.Render({
|
|
328
343
|
class: `wfa btn-clear-input-file-${id}`,
|