adminforth 1.4.3-next.2 β 1.4.3-next.21
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/commands/bundle.js +29 -0
- package/commands/generateModels.js +63 -0
- package/commands/utils.js +93 -0
- package/dist/adminforth/auth.d.ts +31 -0
- package/dist/adminforth/auth.d.ts.map +1 -0
- package/dist/adminforth/auth.js +119 -0
- package/dist/adminforth/auth.js.map +1 -0
- package/dist/adminforth/basePlugin.d.ts +23 -0
- package/dist/adminforth/basePlugin.d.ts.map +1 -0
- package/dist/adminforth/basePlugin.js +51 -0
- package/dist/adminforth/basePlugin.js.map +1 -0
- package/dist/adminforth/dataConnectors/baseConnector.d.ts +95 -0
- package/dist/adminforth/dataConnectors/baseConnector.d.ts.map +1 -0
- package/dist/adminforth/dataConnectors/baseConnector.js +178 -0
- package/dist/adminforth/dataConnectors/baseConnector.js.map +1 -0
- package/dist/adminforth/dataConnectors/clickhouse.d.ts +93 -0
- package/dist/adminforth/dataConnectors/clickhouse.d.ts.map +1 -0
- package/dist/adminforth/dataConnectors/clickhouse.js +297 -0
- package/dist/adminforth/dataConnectors/clickhouse.js.map +1 -0
- package/dist/adminforth/dataConnectors/mongo.d.ts +94 -0
- package/dist/adminforth/dataConnectors/mongo.d.ts.map +1 -0
- package/dist/adminforth/dataConnectors/mongo.js +168 -0
- package/dist/adminforth/dataConnectors/mongo.js.map +1 -0
- package/dist/adminforth/dataConnectors/postgres.d.ts +72 -0
- package/dist/adminforth/dataConnectors/postgres.d.ts.map +1 -0
- package/dist/adminforth/dataConnectors/postgres.js +298 -0
- package/dist/adminforth/dataConnectors/postgres.js.map +1 -0
- package/dist/adminforth/dataConnectors/sqlite.d.ts +67 -0
- package/dist/adminforth/dataConnectors/sqlite.d.ts.map +1 -0
- package/dist/adminforth/dataConnectors/sqlite.js +251 -0
- package/dist/adminforth/dataConnectors/sqlite.js.map +1 -0
- package/dist/adminforth/index.d.ts +94 -0
- package/dist/adminforth/index.d.ts.map +1 -0
- package/dist/adminforth/index.js +357 -0
- package/dist/adminforth/index.js.map +1 -0
- package/dist/adminforth/modules/codeInjector.d.ts +38 -0
- package/dist/adminforth/modules/codeInjector.d.ts.map +1 -0
- package/dist/adminforth/modules/codeInjector.js +673 -0
- package/dist/adminforth/modules/codeInjector.js.map +1 -0
- package/dist/adminforth/modules/configValidator.d.ts +13 -0
- package/dist/adminforth/modules/configValidator.d.ts.map +1 -0
- package/dist/adminforth/modules/configValidator.js +511 -0
- package/dist/adminforth/modules/configValidator.js.map +1 -0
- package/dist/adminforth/modules/operationalResource.d.ts +17 -0
- package/dist/adminforth/modules/operationalResource.d.ts.map +1 -0
- package/dist/adminforth/modules/operationalResource.js +75 -0
- package/dist/adminforth/modules/operationalResource.js.map +1 -0
- package/dist/adminforth/modules/restApi.d.ts +11 -0
- package/dist/adminforth/modules/restApi.d.ts.map +1 -0
- package/dist/adminforth/modules/restApi.js +657 -0
- package/dist/adminforth/modules/restApi.js.map +1 -0
- package/dist/adminforth/modules/styleGenerator.d.ts +9 -0
- package/dist/adminforth/modules/styleGenerator.d.ts.map +1 -0
- package/dist/adminforth/modules/styleGenerator.js +47 -0
- package/dist/adminforth/modules/styleGenerator.js.map +1 -0
- package/dist/adminforth/modules/styles.d.ts +96 -0
- package/dist/adminforth/modules/styles.d.ts.map +1 -0
- package/dist/adminforth/modules/styles.js +105 -0
- package/dist/adminforth/modules/styles.js.map +1 -0
- package/dist/adminforth/modules/utils.d.ts +39 -0
- package/dist/adminforth/modules/utils.d.ts.map +1 -0
- package/dist/adminforth/modules/utils.js +421 -0
- package/dist/adminforth/modules/utils.js.map +1 -0
- package/dist/adminforth/plugins/audit-log/index.d.ts +25 -0
- package/dist/adminforth/plugins/audit-log/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/audit-log/index.js +129 -0
- package/dist/adminforth/plugins/audit-log/index.js.map +1 -0
- package/dist/adminforth/plugins/audit-log/types.d.ts +35 -0
- package/dist/adminforth/plugins/audit-log/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/audit-log/types.js +2 -0
- package/dist/adminforth/plugins/audit-log/types.js.map +1 -0
- package/dist/adminforth/plugins/chat-gpt/index.d.ts +14 -0
- package/dist/adminforth/plugins/chat-gpt/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/chat-gpt/index.js +147 -0
- package/dist/adminforth/plugins/chat-gpt/index.js.map +1 -0
- package/dist/adminforth/plugins/chat-gpt/types.d.ts +82 -0
- package/dist/adminforth/plugins/chat-gpt/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/chat-gpt/types.js +2 -0
- package/dist/adminforth/plugins/chat-gpt/types.js.map +1 -0
- package/dist/adminforth/plugins/email-password-reset/index.d.ts +15 -0
- package/dist/adminforth/plugins/email-password-reset/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/email-password-reset/index.js +176 -0
- package/dist/adminforth/plugins/email-password-reset/index.js.map +1 -0
- package/dist/adminforth/plugins/email-password-reset/types.d.ts +28 -0
- package/dist/adminforth/plugins/email-password-reset/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/email-password-reset/types.js +2 -0
- package/dist/adminforth/plugins/email-password-reset/types.js.map +1 -0
- package/dist/adminforth/plugins/foreign-inline-list/index.d.ts +13 -0
- package/dist/adminforth/plugins/foreign-inline-list/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/foreign-inline-list/index.js +56 -0
- package/dist/adminforth/plugins/foreign-inline-list/index.js.map +1 -0
- package/dist/adminforth/plugins/foreign-inline-list/types.d.ts +19 -0
- package/dist/adminforth/plugins/foreign-inline-list/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/foreign-inline-list/types.js +2 -0
- package/dist/adminforth/plugins/foreign-inline-list/types.js.map +1 -0
- package/dist/adminforth/plugins/import-export/index.d.ts +15 -0
- package/dist/adminforth/plugins/import-export/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/import-export/index.js +127 -0
- package/dist/adminforth/plugins/import-export/index.js.map +1 -0
- package/dist/adminforth/plugins/import-export/types.d.ts +3 -0
- package/dist/adminforth/plugins/import-export/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/import-export/types.js +2 -0
- package/dist/adminforth/plugins/import-export/types.js.map +1 -0
- package/dist/adminforth/plugins/rich-editor/index.d.ts +17 -0
- package/dist/adminforth/plugins/rich-editor/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/rich-editor/index.js +262 -0
- package/dist/adminforth/plugins/rich-editor/index.js.map +1 -0
- package/dist/adminforth/plugins/rich-editor/types.d.ts +153 -0
- package/dist/adminforth/plugins/rich-editor/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/rich-editor/types.js +16 -0
- package/dist/adminforth/plugins/rich-editor/types.js.map +1 -0
- package/dist/adminforth/plugins/two-factors-auth/index.d.ts +16 -0
- package/dist/adminforth/plugins/two-factors-auth/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/two-factors-auth/index.js +134 -0
- package/dist/adminforth/plugins/two-factors-auth/index.js.map +1 -0
- package/dist/adminforth/plugins/two-factors-auth/types.d.ts +18 -0
- package/dist/adminforth/plugins/two-factors-auth/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/two-factors-auth/types.js +2 -0
- package/dist/adminforth/plugins/two-factors-auth/types.js.map +1 -0
- package/dist/adminforth/plugins/upload/index.d.ts +14 -0
- package/dist/adminforth/plugins/upload/index.d.ts.map +1 -0
- package/dist/adminforth/plugins/upload/index.js +450 -0
- package/dist/adminforth/plugins/upload/index.js.map +1 -0
- package/dist/adminforth/plugins/upload/types.d.ts +132 -0
- package/dist/adminforth/plugins/upload/types.d.ts.map +1 -0
- package/dist/adminforth/plugins/upload/types.js +2 -0
- package/dist/adminforth/plugins/upload/types.js.map +1 -0
- package/dist/adminforth/servers/express.d.ts +18 -0
- package/dist/adminforth/servers/express.d.ts.map +1 -0
- package/dist/adminforth/servers/express.js +238 -0
- package/dist/adminforth/servers/express.js.map +1 -0
- package/dist/adminforth/types/Back.d.ts +1103 -0
- package/dist/adminforth/types/Back.d.ts.map +1 -0
- package/dist/adminforth/types/Back.js +86 -0
- package/dist/adminforth/types/Back.js.map +1 -0
- package/dist/adminforth/types/Common.d.ts +616 -0
- package/dist/adminforth/types/Common.d.ts.map +1 -0
- package/dist/adminforth/types/Common.js +65 -0
- package/dist/adminforth/types/Common.js.map +1 -0
- package/dist/adminforth/types/FrontendAPI.d.ts +134 -0
- package/dist/adminforth/types/FrontendAPI.d.ts.map +1 -0
- package/dist/adminforth/types/FrontendAPI.js +8 -0
- package/dist/adminforth/types/FrontendAPI.js.map +1 -0
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +7 -2
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/postgres.js +3 -3
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dev-demo/index.d.ts +3 -0
- package/dist/dev-demo/index.d.ts.map +1 -0
- package/dist/dev-demo/index.js +1052 -0
- package/dist/dev-demo/index.js.map +1 -0
- package/dist/modules/codeInjector.d.ts +4 -2
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +93 -69
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +33 -19
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +0 -1
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +4 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/package-lock.json +64 -4
- package/dist/spa/package.json +1 -0
- package/dist/spa/src/App.vue +15 -25
- package/dist/spa/src/acl/Button.vue +21 -0
- package/dist/spa/src/acl/Link.vue +9 -0
- package/dist/spa/src/afcl/Button.vue +27 -0
- package/dist/spa/src/afcl/Input.vue +41 -0
- package/dist/spa/src/afcl/Link.vue +9 -0
- package/dist/spa/src/afcl/Select.vue +206 -0
- package/dist/spa/src/afcl/index.ts +6 -0
- package/dist/spa/src/components/Filters.vue +11 -5
- package/dist/spa/src/components/GroupsTable.vue +23 -23
- package/dist/spa/src/components/ValueRenderer.vue +3 -1
- package/dist/spa/src/renderers/CompactField.vue +1 -1
- package/dist/spa/src/renderers/CompactUUID.vue +1 -1
- package/dist/spa/src/renderers/CountryFlag.vue +3 -4
- package/dist/spa/src/renderers/HumanNumber.vue +3 -2
- package/dist/spa/src/renderers/RelativeTime.vue +3 -2
- package/dist/spa/src/router/index.ts +1 -1
- package/dist/spa/src/types/Back.ts +47 -13
- package/dist/spa/src/views/LoginView.vue +4 -15
- package/dist/spa/vite.config.ts +16 -34
- package/dist/types/Back.d.ts +21 -6
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
import { exec, spawn } from 'child_process';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import filewatcher from 'filewatcher';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import fsExtra from 'fs-extra';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
import { ADMIN_FORTH_ABSOLUTE_PATH, getComponentNameFromPath } from './utils.js';
|
|
10
|
+
import { StylesGenerator } from './styleGenerator.js';
|
|
11
|
+
let TMP_DIR;
|
|
12
|
+
try {
|
|
13
|
+
TMP_DIR = os.tmpdir();
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
TMP_DIR = '/tmp'; //maybe we can consider to use node_modules/.cache/adminforth here instead of tmp
|
|
17
|
+
}
|
|
18
|
+
function stripAnsiCodes(str) {
|
|
19
|
+
// Regular expression to match ANSI escape codes
|
|
20
|
+
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
21
|
+
}
|
|
22
|
+
function findHomePage(menuItem) {
|
|
23
|
+
for (const item of menuItem) {
|
|
24
|
+
if (item.homepage) {
|
|
25
|
+
return item;
|
|
26
|
+
}
|
|
27
|
+
if (item.children) {
|
|
28
|
+
const found = findHomePage(item.children);
|
|
29
|
+
if (found) {
|
|
30
|
+
return found;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
async function findFirstMenuItemWithResource(menuItem) {
|
|
37
|
+
for (const item of menuItem) {
|
|
38
|
+
if (item.path || item.resourceId) {
|
|
39
|
+
return item;
|
|
40
|
+
}
|
|
41
|
+
if (item.children) {
|
|
42
|
+
const found = await findFirstMenuItemWithResource(item.children);
|
|
43
|
+
if (found) {
|
|
44
|
+
return found;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const execAsync = promisify(exec);
|
|
51
|
+
function hashify(obj) {
|
|
52
|
+
return crypto.createHash('sha256').update(JSON.stringify(obj)).digest('hex');
|
|
53
|
+
}
|
|
54
|
+
function notifyWatcherIssue(limit) {
|
|
55
|
+
console.log('Ran out of file handles after watching %s files.', limit);
|
|
56
|
+
console.log('Falling back to polling which uses more CPU.');
|
|
57
|
+
console.log('Run ulimit -n 10000 to increase the limit for open files.');
|
|
58
|
+
}
|
|
59
|
+
class CodeInjector {
|
|
60
|
+
spaTmpPath() {
|
|
61
|
+
const brandSlug = this.adminforth.config.customization._brandNameSlug;
|
|
62
|
+
if (!brandSlug) {
|
|
63
|
+
throw new Error('brandSlug is empty, but it should be populated at least by config Validator ');
|
|
64
|
+
}
|
|
65
|
+
return path.join(TMP_DIR, 'adminforth', brandSlug, 'spa_tmp');
|
|
66
|
+
}
|
|
67
|
+
cleanup() {
|
|
68
|
+
console.log('Cleaning up...');
|
|
69
|
+
this.allWatchers.forEach((watcher) => {
|
|
70
|
+
watcher.removeAll();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
constructor(adminforth) {
|
|
74
|
+
this.allWatchers = [];
|
|
75
|
+
this.allComponentNames = {};
|
|
76
|
+
this.srcFoldersToSync = {};
|
|
77
|
+
this.devServerPort = null;
|
|
78
|
+
this.adminforth = adminforth;
|
|
79
|
+
['SIGINT', 'SIGTERM', 'SIGQUIT']
|
|
80
|
+
.forEach(signal => process.on(signal, () => {
|
|
81
|
+
this.cleanup();
|
|
82
|
+
process.exit();
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
// async runShell({ command }) {
|
|
86
|
+
// console.log(`βοΈ Running shell ${command}...`);
|
|
87
|
+
// console.time(`${command} done in`);
|
|
88
|
+
// const { stdout: out, stderr: err } = await execAsync(command);
|
|
89
|
+
// console.timeEnd(`${command} done in`);
|
|
90
|
+
// console.log(`Command ${command} output:`, out, err);
|
|
91
|
+
// }
|
|
92
|
+
async runNpmShell({ command, cwd }) {
|
|
93
|
+
const nodeBinary = process.execPath; // Path to the Node.js binary running this script
|
|
94
|
+
const npmPath = path.join(path.dirname(nodeBinary), 'npm'); // Path to the npm executable
|
|
95
|
+
const env = Object.assign({ VITE_ADMINFORTH_PUBLIC_PATH: this.adminforth.config.baseUrl, FORCE_COLOR: '1' }, process.env);
|
|
96
|
+
console.log(`βοΈ exec: npm ${command}`);
|
|
97
|
+
console.time(`npm ${command} done in`);
|
|
98
|
+
const { stdout: out, stderr: err } = await execAsync(`${nodeBinary} ${npmPath} ${command}`, {
|
|
99
|
+
cwd,
|
|
100
|
+
env,
|
|
101
|
+
});
|
|
102
|
+
console.timeEnd(`npm ${command} done in`);
|
|
103
|
+
process.env.HEAVY_DEBUG && console.log(`πͺ² npm ${command} output:`, out);
|
|
104
|
+
if (err) {
|
|
105
|
+
process.env.HEAVY_DEBUG && console.error(`πͺ²npm ${command} errors/warnings:`, err);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async rmTmpDir() {
|
|
109
|
+
// remove spa_tmp folder if it is exists
|
|
110
|
+
try {
|
|
111
|
+
await fs.promises.rm(this.spaTmpPath(), { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
// ignore
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
getServeDir() {
|
|
118
|
+
return path.join(this.getSpaDir(), 'dist');
|
|
119
|
+
}
|
|
120
|
+
async packagesFromNpm(dir) {
|
|
121
|
+
const usersPackagePath = path.join(dir, 'package.json');
|
|
122
|
+
let packageContent = null;
|
|
123
|
+
let lockHash = '';
|
|
124
|
+
let packages = [];
|
|
125
|
+
try {
|
|
126
|
+
packageContent = JSON.parse(await fs.promises.readFile(usersPackagePath, 'utf-8'));
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
// user package.json does not exist, user does not have custom components
|
|
130
|
+
}
|
|
131
|
+
if (packageContent) {
|
|
132
|
+
const lockPath = path.join(dir, 'package-lock.json');
|
|
133
|
+
let lock = null;
|
|
134
|
+
try {
|
|
135
|
+
lock = JSON.parse(await fs.promises.readFile(lockPath, 'utf-8'));
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
throw new Error(`Custom package-lock.json does not exist in ${dir}, but package.json does.
|
|
139
|
+
We can't determine version of packages without package-lock.json. Please run npm install in ${dir}`);
|
|
140
|
+
}
|
|
141
|
+
lockHash = hashify(lock);
|
|
142
|
+
packages = [
|
|
143
|
+
...Object.keys(packageContent.dependencies || []),
|
|
144
|
+
...Object.keys(packageContent.devDependencies || [])
|
|
145
|
+
].reduce((acc, packageName) => {
|
|
146
|
+
const pack = lock.packages[`node_modules/${packageName}`];
|
|
147
|
+
if (!pack) {
|
|
148
|
+
throw new Error(`Package ${packageName} is not in package-lock.json but is in package.json. Please run 'npm install' in ${dir}`);
|
|
149
|
+
}
|
|
150
|
+
const version = pack.version;
|
|
151
|
+
acc.push(`${packageName}@${version}`);
|
|
152
|
+
return acc;
|
|
153
|
+
}, []);
|
|
154
|
+
}
|
|
155
|
+
return [lockHash, packages];
|
|
156
|
+
}
|
|
157
|
+
getSpaDir() {
|
|
158
|
+
let spaDir = path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'spa');
|
|
159
|
+
if (!fs.existsSync(spaDir)) {
|
|
160
|
+
spaDir = path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'dist', 'spa');
|
|
161
|
+
}
|
|
162
|
+
return spaDir;
|
|
163
|
+
}
|
|
164
|
+
async updatePartials({ filesUpdated }) {
|
|
165
|
+
const spaDir = this.getSpaDir();
|
|
166
|
+
// copy only updated files
|
|
167
|
+
await Promise.all(filesUpdated.map(async (file) => {
|
|
168
|
+
const src = path.join(spaDir, file);
|
|
169
|
+
const dest = path.join(this.spaTmpPath(), file);
|
|
170
|
+
// overwrite:true can't be used to not destroy cache
|
|
171
|
+
await fsExtra.copy(src, dest, {
|
|
172
|
+
dereference: true, // needed to dereference types
|
|
173
|
+
// preserveTimestamps: true, // needed to not invalidate any caches
|
|
174
|
+
});
|
|
175
|
+
if (process.env.HEAVY_DEBUG) {
|
|
176
|
+
console.log('πͺ²βοΈ fsExtra.copy copy single file', src, dest);
|
|
177
|
+
}
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
async prepareSources() {
|
|
181
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
182
|
+
// check spa tmp folder exists and create if not
|
|
183
|
+
try {
|
|
184
|
+
await fs.promises.access(this.spaTmpPath(), fs.constants.F_OK);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
await fs.promises.mkdir(this.spaTmpPath(), { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
const icons = [];
|
|
190
|
+
let routes = '';
|
|
191
|
+
let routerComponents = '';
|
|
192
|
+
const collectAssetsFromMenu = (menu) => {
|
|
193
|
+
menu.forEach((item) => {
|
|
194
|
+
var _a, _b, _c, _d;
|
|
195
|
+
if (item.icon) {
|
|
196
|
+
icons.push(item.icon);
|
|
197
|
+
}
|
|
198
|
+
if (item.component) {
|
|
199
|
+
if (Object.keys(item).includes('isStaticRoute')) {
|
|
200
|
+
if (!item.isStaticRoute) {
|
|
201
|
+
routes += `{
|
|
202
|
+
path: '${item.path}',
|
|
203
|
+
name: '${item.path}',
|
|
204
|
+
component: () => import('${item.component}'),
|
|
205
|
+
meta: { title: '${((_a = item === null || item === void 0 ? void 0 : item.meta) === null || _a === void 0 ? void 0 : _a.title) || item.path.replace('/', '')}'}
|
|
206
|
+
},\n`;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
routes += `{
|
|
210
|
+
path: '${item.path}',
|
|
211
|
+
name: '${item.path}',
|
|
212
|
+
component: ${getComponentNameFromPath(item.component)},
|
|
213
|
+
meta: { title: '${((_b = item === null || item === void 0 ? void 0 : item.meta) === null || _b === void 0 ? void 0 : _b.title) || item.path.replace('/', '')}'}
|
|
214
|
+
},\n`;
|
|
215
|
+
const componentName = `${getComponentNameFromPath(item.component)}`;
|
|
216
|
+
routerComponents += `import ${componentName} from '${item.component}';\n`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
if (item.homepage) {
|
|
221
|
+
routes += `{
|
|
222
|
+
path: '${item.path}',
|
|
223
|
+
name: '${item.path}',
|
|
224
|
+
component: ${getComponentNameFromPath(item.component)},
|
|
225
|
+
meta: { title: '${((_c = item === null || item === void 0 ? void 0 : item.meta) === null || _c === void 0 ? void 0 : _c.title) || item.path.replace('/', '')}'}
|
|
226
|
+
},\n`;
|
|
227
|
+
const componentName = `${getComponentNameFromPath(item.component)}`;
|
|
228
|
+
routerComponents += `import ${componentName} from '${item.component}';\n`;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
routes += `{
|
|
232
|
+
path: '${item.path}',
|
|
233
|
+
name: '${item.path}',
|
|
234
|
+
component: () => import('${item.component}'),
|
|
235
|
+
meta: { title: '${((_d = item === null || item === void 0 ? void 0 : item.meta) === null || _d === void 0 ? void 0 : _d.title) || item.path.replace('/', '')}'}
|
|
236
|
+
},\n`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (item.children) {
|
|
241
|
+
collectAssetsFromMenu(item.children);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
const registerCustomPages = (config) => {
|
|
246
|
+
if (config.customization.customPages) {
|
|
247
|
+
config.customization.customPages.forEach((page) => {
|
|
248
|
+
var _a, _b, _c;
|
|
249
|
+
routes += `{
|
|
250
|
+
path: '${page.path}',
|
|
251
|
+
name: '${page.path}',
|
|
252
|
+
component: () => import('${((_a = page === null || page === void 0 ? void 0 : page.component) === null || _a === void 0 ? void 0 : _a.file) || page.component}'),
|
|
253
|
+
meta: ${JSON.stringify(Object.assign(Object.assign({}, (((_b = page === null || page === void 0 ? void 0 : page.component) === null || _b === void 0 ? void 0 : _b.meta) || {})), { title: ((_c = page.meta) === null || _c === void 0 ? void 0 : _c.title) || page.path.replace('/', '') }))}
|
|
254
|
+
},`;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
registerCustomPages(this.adminforth.config);
|
|
259
|
+
collectAssetsFromMenu(this.adminforth.config.menu);
|
|
260
|
+
const spaDir = this.getSpaDir();
|
|
261
|
+
if (process.env.HEAVY_DEBUG) {
|
|
262
|
+
console.log(`πͺ²βοΈ fsExtra.copy from ${spaDir} -> ${this.spaTmpPath()}`);
|
|
263
|
+
}
|
|
264
|
+
// try to rm <spa tmp path>/src/types directory
|
|
265
|
+
try {
|
|
266
|
+
await fs.promises.rm(path.join(this.spaTmpPath(), 'src', 'types'), { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
// ignore
|
|
270
|
+
}
|
|
271
|
+
// overwrite can't be used to not destroy cache
|
|
272
|
+
await fsExtra.copy(spaDir, this.spaTmpPath(), {
|
|
273
|
+
filter: (src) => {
|
|
274
|
+
const filterPasses = !src.includes('/adminforth/spa/node_modules') && !src.includes('/adminforth/spa/dist');
|
|
275
|
+
if (process.env.HEAVY_DEBUG && !filterPasses) {
|
|
276
|
+
console.log('πͺ²βοΈ fsExtra.copy filtered out', src);
|
|
277
|
+
}
|
|
278
|
+
return filterPasses;
|
|
279
|
+
},
|
|
280
|
+
dereference: true, // needed to dereference types
|
|
281
|
+
});
|
|
282
|
+
// copy whole custom directory
|
|
283
|
+
if ((_a = this.adminforth.config.customization) === null || _a === void 0 ? void 0 : _a.customComponentsDir) {
|
|
284
|
+
// resolve customComponentsDir to absolute path, so ./aa will be resolved to /path/to/current/dir/aa
|
|
285
|
+
const customCompAbsPath = path.resolve(this.adminforth.config.customization.customComponentsDir);
|
|
286
|
+
this.srcFoldersToSync[customCompAbsPath] = './';
|
|
287
|
+
}
|
|
288
|
+
// if this.adminforth.config.customization.favicon is set, copy it to assets
|
|
289
|
+
const customFav = (_b = this.adminforth.config.customization) === null || _b === void 0 ? void 0 : _b.favicon;
|
|
290
|
+
if (customFav) {
|
|
291
|
+
const faviconPath = path.join((_c = this.adminforth.config.customization) === null || _c === void 0 ? void 0 : _c.customComponentsDir, customFav.replace('@@/', ''));
|
|
292
|
+
const dest = path.join(this.spaTmpPath(), 'public', 'assets', customFav.replace('@@/', ''));
|
|
293
|
+
// make sure all folders in dest exist
|
|
294
|
+
await fsExtra.ensureDir(path.dirname(dest));
|
|
295
|
+
await fsExtra.copy(faviconPath, dest);
|
|
296
|
+
}
|
|
297
|
+
for (const [src, dest] of Object.entries(this.srcFoldersToSync)) {
|
|
298
|
+
const to = path.join(this.spaTmpPath(), 'src', 'custom', dest);
|
|
299
|
+
if (process.env.HEAVY_DEBUG) {
|
|
300
|
+
console.log(`πͺ²βοΈ srcFoldersToSync: fsExtra.copy from ${src}, ${to}`);
|
|
301
|
+
}
|
|
302
|
+
await fsExtra.copy(src, to, {
|
|
303
|
+
recursive: true,
|
|
304
|
+
dereference: true,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
//collect all 'icon' fields from resources bulkActions
|
|
308
|
+
this.adminforth.config.resources.forEach((resource) => {
|
|
309
|
+
var _a;
|
|
310
|
+
if ((_a = resource.options) === null || _a === void 0 ? void 0 : _a.bulkActions) {
|
|
311
|
+
resource.options.bulkActions.forEach((action) => {
|
|
312
|
+
if (action.icon) {
|
|
313
|
+
icons.push(action.icon);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
const uniqueIcons = Array.from(new Set(icons));
|
|
319
|
+
// icons are collectionName:iconName. Get list of all unique collection names:
|
|
320
|
+
const collections = new Set(icons.map((icon) => icon.split(':')[0]));
|
|
321
|
+
// package names @iconify-prerendered/vue-<collection name>
|
|
322
|
+
const iconPackageNames = Array.from(collections).map((collection) => `@iconify-prerendered/vue-${collection}`);
|
|
323
|
+
// for each icon generate import statement
|
|
324
|
+
const iconImports = uniqueIcons.map((icon) => {
|
|
325
|
+
const [collection, iconName] = icon.split(':');
|
|
326
|
+
const PascalIconName = 'Icon' + iconName.split('-').map((part, index) => {
|
|
327
|
+
return part[0].toUpperCase() + part.slice(1);
|
|
328
|
+
}).join('');
|
|
329
|
+
return `import { ${PascalIconName} } from '@iconify-prerendered/vue-${collection}';`;
|
|
330
|
+
}).join('\n');
|
|
331
|
+
// for each custom component generate import statement
|
|
332
|
+
const customResourceComponents = [];
|
|
333
|
+
function checkInjections(filePathes) {
|
|
334
|
+
filePathes.forEach(({ file }) => {
|
|
335
|
+
if (!customResourceComponents.includes(file)) {
|
|
336
|
+
if (file === undefined) {
|
|
337
|
+
throw new Error('file is undefined');
|
|
338
|
+
}
|
|
339
|
+
customResourceComponents.push(file);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
this.adminforth.config.resources.forEach((resource) => {
|
|
344
|
+
var _a;
|
|
345
|
+
resource.columns.forEach((column) => {
|
|
346
|
+
if (column.components) {
|
|
347
|
+
Object.values(column.components).forEach(({ file }) => {
|
|
348
|
+
if (!customResourceComponents.includes(file)) {
|
|
349
|
+
if (file === undefined) {
|
|
350
|
+
throw new Error('file is undefined from field.components, field:' + JSON.stringify(column));
|
|
351
|
+
}
|
|
352
|
+
customResourceComponents.push(file);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
(Object.values(((_a = resource.options) === null || _a === void 0 ? void 0 : _a.pageInjections) || {})).forEach((injection) => {
|
|
358
|
+
Object.values(injection).forEach((filePathes) => {
|
|
359
|
+
checkInjections(filePathes);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
if ((_d = this.adminforth.config.customization) === null || _d === void 0 ? void 0 : _d.globalInjections) {
|
|
364
|
+
Object.values(this.adminforth.config.customization.globalInjections).forEach((injection) => {
|
|
365
|
+
checkInjections(injection);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
customResourceComponents.forEach((filePath) => {
|
|
369
|
+
const componentName = getComponentNameFromPath(filePath);
|
|
370
|
+
this.allComponentNames[filePath] = componentName;
|
|
371
|
+
});
|
|
372
|
+
// console.log('π§ Injecting code into Vue sources...', this.allComponentNames);
|
|
373
|
+
let customComponentsImports = '';
|
|
374
|
+
for (const [targetPath, component] of Object.entries(this.allComponentNames)) {
|
|
375
|
+
customComponentsImports += `import ${component} from '${targetPath}';\n`;
|
|
376
|
+
}
|
|
377
|
+
// Generate Vue.component statements for each icon
|
|
378
|
+
const iconComponents = uniqueIcons.map((icon) => {
|
|
379
|
+
const [collection, iconName] = icon.split(':');
|
|
380
|
+
const PascalIconName = 'Icon' + iconName.split('-').map((part, index) => {
|
|
381
|
+
return part[0].toUpperCase() + part.slice(1);
|
|
382
|
+
}).join('');
|
|
383
|
+
return `app.component('${PascalIconName}', ${PascalIconName});`;
|
|
384
|
+
}).join('\n');
|
|
385
|
+
// Generate Vue.component statements for each custom component
|
|
386
|
+
let customComponentsComponents = '';
|
|
387
|
+
for (const name of Object.values(this.allComponentNames)) {
|
|
388
|
+
customComponentsComponents += `app.component('${name}', ${name});\n`;
|
|
389
|
+
}
|
|
390
|
+
let imports = iconImports + '\n';
|
|
391
|
+
imports += customComponentsImports + '\n';
|
|
392
|
+
if ((_e = this.adminforth.config.customization) === null || _e === void 0 ? void 0 : _e.vueUsesFile) {
|
|
393
|
+
imports += `import addCustomUses from '${this.adminforth.config.customization.vueUsesFile}';\n`;
|
|
394
|
+
}
|
|
395
|
+
// inject that code into spa_tmp/src/App.vue
|
|
396
|
+
const appVuePath = path.join(this.spaTmpPath(), 'src', 'main.ts');
|
|
397
|
+
let appVueContent = await fs.promises.readFile(appVuePath, 'utf-8');
|
|
398
|
+
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH IMPORTS */', imports);
|
|
399
|
+
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH COMPONENT REGISTRATIONS */', iconComponents + '\n' + customComponentsComponents + '\n');
|
|
400
|
+
if ((_f = this.adminforth.config.customization) === null || _f === void 0 ? void 0 : _f.vueUsesFile) {
|
|
401
|
+
appVueContent = appVueContent.replace('/* IMPORTANT:ADMINFORTH CUSTOM USES */', 'addCustomUses(app);');
|
|
402
|
+
}
|
|
403
|
+
await fs.promises.writeFile(appVuePath, appVueContent);
|
|
404
|
+
// generate tailwind extend styles
|
|
405
|
+
const stylesGenerator = new StylesGenerator((_g = this.adminforth.config.customization) === null || _g === void 0 ? void 0 : _g.styles);
|
|
406
|
+
const stylesText = JSON.stringify(stylesGenerator.mergeStyles(), null, 2).slice(1, -1);
|
|
407
|
+
let tailwindConfigPath = path.join(this.spaTmpPath(), 'tailwind.config.js');
|
|
408
|
+
let tailwindConfigContent = await fs.promises.readFile(tailwindConfigPath, 'utf-8');
|
|
409
|
+
tailwindConfigContent = tailwindConfigContent.replace('/* IMPORTANT:ADMINFORTH TAILWIND STYLES */', stylesText);
|
|
410
|
+
await fs.promises.writeFile(tailwindConfigPath, tailwindConfigContent);
|
|
411
|
+
const routerVuePath = path.join(this.spaTmpPath(), 'src', 'router', 'index.ts');
|
|
412
|
+
let routerVueContent = await fs.promises.readFile(routerVuePath, 'utf-8');
|
|
413
|
+
routerVueContent = routerVueContent.replace('/* IMPORTANT:ADMINFORTH ROUTES IMPORTS */', routerComponents);
|
|
414
|
+
// inject title to index.html
|
|
415
|
+
const indexHtmlPath = path.join(this.spaTmpPath(), 'index.html');
|
|
416
|
+
let indexHtmlContent = await fs.promises.readFile(indexHtmlPath, 'utf-8');
|
|
417
|
+
indexHtmlContent = indexHtmlContent.replace('/* IMPORTANT:ADMINFORTH TITLE */', `${this.adminforth.config.customization.title || 'AdminForth'}`);
|
|
418
|
+
indexHtmlContent = indexHtmlContent.replace('/* IMPORTANT:ADMINFORTH FAVICON */', ((_h = this.adminforth.config.customization.favicon) === null || _h === void 0 ? void 0 : _h.replace('@@/', `${this.adminforth.baseUrlSlashed}assets/`))
|
|
419
|
+
||
|
|
420
|
+
`${this.adminforth.baseUrlSlashed}assets/favicon.png`);
|
|
421
|
+
await fs.promises.writeFile(indexHtmlPath, indexHtmlContent);
|
|
422
|
+
/* generate custom routes */
|
|
423
|
+
let homepageMenuItem = findHomePage(this.adminforth.config.menu);
|
|
424
|
+
if (!homepageMenuItem) {
|
|
425
|
+
// find first item with path or resourceId. If we face a menu item with children earlier then path/resourceId, we should search in children
|
|
426
|
+
homepageMenuItem = await findFirstMenuItemWithResource(this.adminforth.config.menu);
|
|
427
|
+
}
|
|
428
|
+
if (!homepageMenuItem) {
|
|
429
|
+
throw new Error('No homepage found in menu and no menu item with path/resourceId found. AdminForth can not generate routes');
|
|
430
|
+
}
|
|
431
|
+
let homePagePath = homepageMenuItem.path || `/resource/${homepageMenuItem.resourceId}`;
|
|
432
|
+
if (!homePagePath) {
|
|
433
|
+
homePagePath = ((_j = this.adminforth.config.menu.filter((mi) => mi.path)[0]) === null || _j === void 0 ? void 0 : _j.path) || `/resource/${(_k = this.adminforth.config.menu.filter((mi) => mi.children)[0]) === null || _k === void 0 ? void 0 : _k.resourceId}`;
|
|
434
|
+
}
|
|
435
|
+
routes += `{
|
|
436
|
+
path: '/',
|
|
437
|
+
name: 'home',
|
|
438
|
+
//redirect to login
|
|
439
|
+
redirect: '${homePagePath}'
|
|
440
|
+
},\n`;
|
|
441
|
+
routerVueContent = routerVueContent.replace('/* IMPORTANT:ADMINFORTH ROUTES */', routes);
|
|
442
|
+
await fs.promises.writeFile(routerVuePath, routerVueContent);
|
|
443
|
+
/* hash checking */
|
|
444
|
+
const spaPackageLockPath = path.join(this.spaTmpPath(), 'package-lock.json');
|
|
445
|
+
const spaPackageLock = JSON.parse(await fs.promises.readFile(spaPackageLockPath, 'utf-8'));
|
|
446
|
+
const spaLockHash = hashify(spaPackageLock);
|
|
447
|
+
/* customPackageLock */
|
|
448
|
+
let usersLockHash = '';
|
|
449
|
+
let usersPackages = [];
|
|
450
|
+
if ((_l = this.adminforth.config.customization) === null || _l === void 0 ? void 0 : _l.customComponentsDir) {
|
|
451
|
+
[usersLockHash, usersPackages] = await this.packagesFromNpm(this.adminforth.config.customization.customComponentsDir);
|
|
452
|
+
}
|
|
453
|
+
const pluginPackages = [];
|
|
454
|
+
// for every installed plugin generate packages
|
|
455
|
+
for (const plugin of this.adminforth.activatedPlugins) {
|
|
456
|
+
process.env.HEAVY_DEBUG && console.log('π§ Checking packages for plugin', plugin.constructor.name, plugin.customFolderPath);
|
|
457
|
+
const [lockHash, packages] = await this.packagesFromNpm(plugin.customFolderPath);
|
|
458
|
+
if (packages.length) {
|
|
459
|
+
pluginPackages.push({
|
|
460
|
+
pluginName: plugin.constructor.name,
|
|
461
|
+
lockHash,
|
|
462
|
+
packages,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// form string "pluginName:lockHash::pLugin2Name:lockHash"
|
|
467
|
+
const pluginsLockHash = pluginPackages.map(({ pluginName, lockHash }) => `${pluginName}>${lockHash}`).join('::');
|
|
468
|
+
const iconPackagesNamesHash = hashify(iconPackageNames);
|
|
469
|
+
const fullHash = `spa>${spaLockHash}::icons>${iconPackagesNamesHash}::user/custom>${usersLockHash}::${pluginsLockHash}`;
|
|
470
|
+
const hashPath = path.join(this.spaTmpPath(), 'node_modules', '.adminforth_hash');
|
|
471
|
+
try {
|
|
472
|
+
const existingHash = await fs.promises.readFile(hashPath, 'utf-8');
|
|
473
|
+
if (existingHash === fullHash) {
|
|
474
|
+
process.env.HEAVY_DEBUG && console.log(`πͺ²Hashes match, skipping npm ci/install, from file: ${existingHash}, actual: ${fullHash}`);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
process.env.HEAVY_DEBUG && console.log(`πͺ² Hashes do not match: from file: ${existingHash} actual: ${fullHash}, proceeding with npm ci/install`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
catch (e) {
|
|
482
|
+
// ignore
|
|
483
|
+
process.env.HEAVY_DEBUG && console.log('πͺ²Hash file does not exist, proceeding with npm ci/install');
|
|
484
|
+
}
|
|
485
|
+
await this.runNpmShell({ command: 'ci', cwd: this.spaTmpPath() });
|
|
486
|
+
const allPacks = [
|
|
487
|
+
...iconPackageNames,
|
|
488
|
+
...usersPackages,
|
|
489
|
+
...pluginPackages.reduce((acc, { packages }) => {
|
|
490
|
+
acc.push(...packages);
|
|
491
|
+
return acc;
|
|
492
|
+
}, []),
|
|
493
|
+
];
|
|
494
|
+
const EXCLUDE_PACKS = ['@iconify-prerendered/vue-flowbite'];
|
|
495
|
+
const allPacksFiltered = allPacks.filter((pack) => {
|
|
496
|
+
return !EXCLUDE_PACKS.some((exclude) => pack.startsWith(exclude));
|
|
497
|
+
});
|
|
498
|
+
const allPacksUnique = Array.from(new Set(allPacksFiltered));
|
|
499
|
+
if (allPacks.length) {
|
|
500
|
+
const npmInstallCommand = `install ${allPacksUnique.join(' ')}`;
|
|
501
|
+
await this.runNpmShell({ command: npmInstallCommand, cwd: this.spaTmpPath() });
|
|
502
|
+
}
|
|
503
|
+
await fs.promises.writeFile(hashPath, fullHash);
|
|
504
|
+
}
|
|
505
|
+
async watchForReprepare({}) {
|
|
506
|
+
const spaPath = this.getSpaDir();
|
|
507
|
+
// get list of all subdirectories in spa recursively (for SPA development)
|
|
508
|
+
const directories = [];
|
|
509
|
+
const collectDirectories = async (dir) => {
|
|
510
|
+
const files = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
511
|
+
for (const file of files) {
|
|
512
|
+
if (['node_modules', 'dist'].includes(file.name)) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (file.isDirectory()) {
|
|
516
|
+
directories.push(path.join(dir, file.name));
|
|
517
|
+
await collectDirectories(path.join(dir, file.name));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
await collectDirectories(spaPath);
|
|
522
|
+
if (process.env.HEAVY_DEBUG) {
|
|
523
|
+
console.log('πͺ²π Watch for:', directories.join(','));
|
|
524
|
+
}
|
|
525
|
+
const watcher = filewatcher({ debounce: 30 });
|
|
526
|
+
directories.forEach((dir) => {
|
|
527
|
+
// read directory files and add to watcher, only files not directories
|
|
528
|
+
const files = fs.readdirSync(dir);
|
|
529
|
+
files.forEach((file) => {
|
|
530
|
+
const fullPath = path.join(dir, file);
|
|
531
|
+
if (fs.lstatSync(fullPath).isFile()) {
|
|
532
|
+
process.env.HEAVY_DEBUG && console.log(`πͺ²π Watch for file ${fullPath}`);
|
|
533
|
+
watcher.add(fullPath);
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
watcher.on('change', async (file) => {
|
|
538
|
+
process.env.HEAVY_DEBUG && console.log(`π File ${file} changed (SPA), preparing sources...`);
|
|
539
|
+
await this.updatePartials({ filesUpdated: [file.replace(spaPath + '/', '')] });
|
|
540
|
+
});
|
|
541
|
+
watcher.on('fallback', notifyWatcherIssue);
|
|
542
|
+
this.allWatchers.push(watcher);
|
|
543
|
+
}
|
|
544
|
+
async watchCustomComponentsForCopy({ customComponentsDir, destination }) {
|
|
545
|
+
if (!customComponentsDir) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
// check if folder exists
|
|
549
|
+
try {
|
|
550
|
+
await fs.promises.access(customComponentsDir, fs.constants.F_OK);
|
|
551
|
+
}
|
|
552
|
+
catch (e) {
|
|
553
|
+
process.env.HEAVY_DEBUG && console.log(`πͺ²Custom components dir ${customComponentsDir} does not exist, skipping watching`);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
// get all subdirs
|
|
557
|
+
const directories = [];
|
|
558
|
+
const files = [];
|
|
559
|
+
const collectDirectories = async (dir) => {
|
|
560
|
+
if (['node_modules', 'dist'].includes(path.basename(dir))) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
directories.push(dir);
|
|
564
|
+
const filesAndDirs = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
565
|
+
await Promise.all(filesAndDirs.map(async (file) => {
|
|
566
|
+
const isDir = fs.lstatSync(path.join(dir, file.name)).isDirectory();
|
|
567
|
+
if (isDir) {
|
|
568
|
+
await collectDirectories(path.join(dir, file.name));
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
files.push(path.join(dir, file.name));
|
|
572
|
+
}
|
|
573
|
+
}));
|
|
574
|
+
};
|
|
575
|
+
await collectDirectories(customComponentsDir);
|
|
576
|
+
const watcher = filewatcher({ debounce: 30 });
|
|
577
|
+
files.forEach((file) => {
|
|
578
|
+
process.env.HEAVY_DEBUG && console.log(`πͺ²π Watch for file ${file}`);
|
|
579
|
+
watcher.add(file);
|
|
580
|
+
});
|
|
581
|
+
if (process.env.HEAVY_DEBUG) {
|
|
582
|
+
console.log('πͺ²π Watch for:', directories.join(','));
|
|
583
|
+
}
|
|
584
|
+
watcher.on('change', async (fileOrDir) => {
|
|
585
|
+
// copy one file
|
|
586
|
+
const relativeFilename = fileOrDir.replace(customComponentsDir + '/', '');
|
|
587
|
+
if (process.env.HEAVY_DEBUG) {
|
|
588
|
+
console.log(`π fileOrDir ${fileOrDir} changed`);
|
|
589
|
+
console.log(`π relativeFilename ${relativeFilename}`);
|
|
590
|
+
console.log(`π customComponentsDir ${customComponentsDir}`);
|
|
591
|
+
console.log(`π destination ${destination}`);
|
|
592
|
+
}
|
|
593
|
+
const isFile = fs.lstatSync(fileOrDir).isFile();
|
|
594
|
+
if (isFile) {
|
|
595
|
+
const destPath = path.join(this.spaTmpPath(), 'src', 'custom', destination, relativeFilename);
|
|
596
|
+
process.env.HEAVY_DEBUG && console.log(`π Copying file ${fileOrDir} to ${destPath}`);
|
|
597
|
+
await fsExtra.copy(fileOrDir, destPath);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
// for now do nothing
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
watcher.on('fallback', notifyWatcherIssue);
|
|
605
|
+
this.allWatchers.push(watcher);
|
|
606
|
+
}
|
|
607
|
+
async bundleNow({ hotReload = false }) {
|
|
608
|
+
console.log(`AdminForth bundling ${hotReload ? ' and listening for changes (π₯ Hotreload)' : ' (no hot reload)'}`);
|
|
609
|
+
this.adminforth.runningHotReload = hotReload;
|
|
610
|
+
await this.prepareSources();
|
|
611
|
+
if (hotReload) {
|
|
612
|
+
await Promise.all([
|
|
613
|
+
this.watchForReprepare({}),
|
|
614
|
+
...Object.entries(this.srcFoldersToSync).map(async ([src, dest]) => {
|
|
615
|
+
await this.watchCustomComponentsForCopy({
|
|
616
|
+
customComponentsDir: src,
|
|
617
|
+
destination: dest,
|
|
618
|
+
});
|
|
619
|
+
}),
|
|
620
|
+
]);
|
|
621
|
+
}
|
|
622
|
+
console.log('AdminForth bundling');
|
|
623
|
+
const cwd = this.spaTmpPath();
|
|
624
|
+
if (!hotReload) {
|
|
625
|
+
// probably add option to build with tsh check (plain 'build')
|
|
626
|
+
const serveDir = this.getServeDir();
|
|
627
|
+
await this.runNpmShell({ command: 'run build-only', cwd });
|
|
628
|
+
// remove serveDir if exists
|
|
629
|
+
try {
|
|
630
|
+
await fs.promises.rm(serveDir, { recursive: true });
|
|
631
|
+
}
|
|
632
|
+
catch (e) {
|
|
633
|
+
// ignore
|
|
634
|
+
}
|
|
635
|
+
await fs.promises.mkdir(serveDir, { recursive: true });
|
|
636
|
+
// coy dist to serveDir
|
|
637
|
+
await fsExtra.copy(path.join(cwd, 'dist'), serveDir, { recursive: true });
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
const command = 'run dev';
|
|
641
|
+
console.log(`πͺ²βοΈ spawn: npm ${command}...`);
|
|
642
|
+
const nodeBinary = process.execPath;
|
|
643
|
+
const npmPath = path.join(path.dirname(nodeBinary), 'npm');
|
|
644
|
+
const env = Object.assign({ VITE_ADMINFORTH_PUBLIC_PATH: this.adminforth.config.baseUrl, FORCE_COLOR: '1' }, process.env);
|
|
645
|
+
const devServer = spawn(`${nodeBinary}`, [`${npmPath}`, ...command.split(' ')], {
|
|
646
|
+
cwd,
|
|
647
|
+
env,
|
|
648
|
+
});
|
|
649
|
+
devServer.stdout.on('data', (data) => {
|
|
650
|
+
if (data.includes('β')) {
|
|
651
|
+
// TODO: maybe be tter use our string "App port: 5174. HMR port: 5274", it is more reliable because vue might change their output
|
|
652
|
+
// parse port from message " β Local: http://localhost:xyz/"
|
|
653
|
+
const s = stripAnsiCodes(data.toString());
|
|
654
|
+
process.env.HEAVY_DEBUG && console.log('πͺ² devServer stdout β (port detect):', s);
|
|
655
|
+
const portMatch = s.match(/.+?http:\/\/.+?:(\d+).+?/m);
|
|
656
|
+
if (portMatch) {
|
|
657
|
+
this.devServerPort = parseInt(portMatch[1]);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
console.log(`[AdminForth SPA]:`);
|
|
662
|
+
process.stdout.write(data);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
devServer.stderr.on('data', (data) => {
|
|
666
|
+
console.error(`[AdminForth SPA ERR]:`);
|
|
667
|
+
process.stdout.write(data);
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
export default CodeInjector;
|
|
673
|
+
//# sourceMappingURL=codeInjector.js.map
|