@acorex/platform-generator 19.2.12 → 19.2.15
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/generators.json +10 -0
- package/package.json +4 -1
- package/src/bin/interactive-entity-creator.js +448 -0
- package/src/bin/test-entity-creator.js +48 -0
- package/src/generators/app-module/files/src/app/app.module.ts.template +0 -3
- package/src/generators/app-module/files/src/app/modules/root/sample/sample.service.ts.template +1 -1
- package/src/generators/app-module/files/src/app/modules/root/sample/sample.types.ts.template +1 -1
- package/src/generators/create-app-module/files/__fileName__/src/index.ts__tmpl__ +9 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/__fileName__.module.ts__tmpl__ +44 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/const.ts__tmpl__ +19 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/entity.provider.ts__tmpl__ +33 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/menu.provider.ts__tmpl__ +29 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/permission.provider.ts__tmpl__ +13 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/search-command.provider.ts__tmpl__ +17 -0
- package/src/generators/create-app-module/files/__fileName__/src/lib/setting.provider.ts__tmpl__ +29 -0
- package/src/generators/create-module-entity/files/__entityFileName__.entity.ts__tmpl__ +150 -0
- package/src/generators/create-module-entity/files/__entityFileName__.service.ts__tmpl__ +16 -0
- package/src/generators/create-module-entity/files/__entityFileName__.types.ts__tmpl__ +6 -0
- package/src/generators/create-module-entity/files/index.ts__tmpl__ +3 -0
- package/src/generators/create-module-entity/generator.d.ts +11 -0
- package/src/generators/create-module-entity/generator.js +338 -20
- package/src/generators/create-module-entity/generator.js.map +1 -1
- package/src/generators/create-module-entity/schema.json +85 -2
- package/src/generators/create-tag-entity/files/index.ts__tmpl__ +3 -0
- package/src/generators/create-tag-entity/files/tag-__entityFileName__.entity.ts__tmpl__ +240 -0
- package/src/generators/create-tag-entity/files/tag-__entityFileName__.service.ts__tmpl__ +16 -0
- package/src/generators/create-tag-entity/files/tag-__entityFileName__.types.ts__tmpl__ +6 -0
- package/src/generators/create-tag-entity/generator.d.ts +7 -0
- package/src/generators/create-tag-entity/generator.js +111 -0
- package/src/generators/create-tag-entity/generator.js.map +1 -0
- package/src/generators/create-tag-entity/schema.json +16 -0
- package/src/generators/create-widget/files/__fileName__-widget-column.component.ts__tmpl__ +11 -0
- package/src/generators/create-widget/files/__fileName__-widget-edit.component.ts__tmpl__ +35 -0
- package/src/generators/create-widget/files/__fileName__-widget-filter.component.ts__tmpl__ +12 -0
- package/src/generators/create-widget/files/__fileName__-widget-print.component.ts__tmpl__ +11 -0
- package/src/generators/create-widget/files/__fileName__-widget-view.component.ts__tmpl__ +14 -0
- package/src/generators/create-widget/files/__fileName__-widget.config.ts__tmpl__ +44 -0
- package/src/generators/create-widget/files/index.ts__tmpl__ +6 -0
- package/src/generators/create-widget/generator.d.ts +8 -0
- package/src/generators/create-widget/generator.js +99 -0
- package/src/generators/create-widget/generator.js.map +1 -0
- package/src/generators/create-widget/schema.d.ts +6 -0
- package/src/generators/create-widget/schema.json +66 -0
- package/src/generators/index.d.ts +0 -0
- package/src/generators/index.js +1 -0
- package/src/generators/index.js.map +1 -0
package/generators.json
CHANGED
|
@@ -14,6 +14,16 @@
|
|
|
14
14
|
"factory": "./src/generators/create-module-entity/generator",
|
|
15
15
|
"schema": "./src/generators/create-module-entity/schema.json",
|
|
16
16
|
"description": "create-module-entity generator"
|
|
17
|
+
},
|
|
18
|
+
"create-tag-entity": {
|
|
19
|
+
"factory": "./src/generators/create-tag-entity/generator",
|
|
20
|
+
"schema": "./src/generators/create-tag-entity/schema.json",
|
|
21
|
+
"description": "create-tag-entity generator"
|
|
22
|
+
},
|
|
23
|
+
"create-widget": {
|
|
24
|
+
"factory": "./src/generators/create-widget/generator",
|
|
25
|
+
"schema": "./src/generators/create-widget/schema.json",
|
|
26
|
+
"description": "Create a new widget with all required components"
|
|
17
27
|
}
|
|
18
28
|
}
|
|
19
29
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acorex/platform-generator",
|
|
3
|
-
"version": "19.2.
|
|
3
|
+
"version": "19.2.15",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@nx/devkit": "19.2.2",
|
|
6
6
|
"tslib": "^2.3.0"
|
|
@@ -18,5 +18,8 @@
|
|
|
18
18
|
"typings": "./src/index.d.ts",
|
|
19
19
|
"private": false,
|
|
20
20
|
"generators": "./generators.json",
|
|
21
|
+
"bin": {
|
|
22
|
+
"acx-create-entity": "./src/bin/interactive-entity-creator.js"
|
|
23
|
+
},
|
|
21
24
|
"types": "./src/index.d.ts"
|
|
22
25
|
}
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
const { join, resolve } = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
// Find the root directory of the project
|
|
9
|
+
function findProjectRoot() {
|
|
10
|
+
let currentDir = __dirname;
|
|
11
|
+
while (!fs.existsSync(join(currentDir, 'nx.json'))) {
|
|
12
|
+
const parentDir = resolve(currentDir, '..');
|
|
13
|
+
if (parentDir === currentDir) {
|
|
14
|
+
// We've reached the root of the filesystem
|
|
15
|
+
return process.cwd();
|
|
16
|
+
}
|
|
17
|
+
currentDir = parentDir;
|
|
18
|
+
}
|
|
19
|
+
return currentDir;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const projectRoot = findProjectRoot();
|
|
23
|
+
|
|
24
|
+
// Function to validate module and entity names
|
|
25
|
+
function validateName(name) {
|
|
26
|
+
// Ensure name is not empty
|
|
27
|
+
if (!name || name.trim() === '') {
|
|
28
|
+
return 'Name cannot be empty.';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Ensure name is not just a number
|
|
32
|
+
if (/^\d+$/.test(name)) {
|
|
33
|
+
return 'Name cannot be just a number. Please include at least one letter.';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Less restrictive validation that allows non-Latin characters
|
|
37
|
+
// Just check for spaces, special characters, and make sure it starts with a letter or non-Latin character
|
|
38
|
+
if (/^[^a-zA-Z\p{L}]|\s|[^\w\p{L}]/u.test(name)) {
|
|
39
|
+
return 'Name must start with a letter and cannot contain spaces or special characters.';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null; // No error
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check for --dryRun flag at the beginning
|
|
46
|
+
const isDryRun = process.argv.includes('--dryRun');
|
|
47
|
+
|
|
48
|
+
// Create an interface for readline
|
|
49
|
+
const rl = readline.createInterface({
|
|
50
|
+
input: process.stdin,
|
|
51
|
+
output: process.stdout
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Define widget catalog - copied from widget-catalog.ts
|
|
55
|
+
const widgetCatalog = {
|
|
56
|
+
text: 'text-editor',
|
|
57
|
+
email: 'email-editor',
|
|
58
|
+
password: 'password-editor',
|
|
59
|
+
phone: 'phone-editor',
|
|
60
|
+
largeText: 'large-text-editor',
|
|
61
|
+
richText: 'rich-text-editor',
|
|
62
|
+
number: 'number-editor',
|
|
63
|
+
numberUnit: 'number-unit-editor',
|
|
64
|
+
select: 'select-editor',
|
|
65
|
+
checkbox: 'checkbox-editor',
|
|
66
|
+
toggle: 'toggle-editor',
|
|
67
|
+
dateTime: 'date-time-editor',
|
|
68
|
+
color: 'color-editor',
|
|
69
|
+
link: 'link-editor',
|
|
70
|
+
contact: 'contact-editor',
|
|
71
|
+
tagable: 'tagable-editor',
|
|
72
|
+
file: 'file',
|
|
73
|
+
gallery: 'gallery',
|
|
74
|
+
signature: 'signature',
|
|
75
|
+
map: 'map',
|
|
76
|
+
lookup: 'lookup-editor',
|
|
77
|
+
selectionList: 'selection-list-editor',
|
|
78
|
+
table: 'table-editor',
|
|
79
|
+
qrcode: 'qrcode',
|
|
80
|
+
singleFileBox: 'single-file-box-editor',
|
|
81
|
+
metaData: 'meta-data-editor'
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Define widget to data type mapping
|
|
85
|
+
const widgetToDataType = {
|
|
86
|
+
'text-editor': 'string',
|
|
87
|
+
'email-editor': 'string',
|
|
88
|
+
'password-editor': 'string',
|
|
89
|
+
'phone-editor': 'string',
|
|
90
|
+
'large-text-editor': 'string',
|
|
91
|
+
'rich-text-editor': 'string',
|
|
92
|
+
'number-editor': 'number',
|
|
93
|
+
'number-unit-editor': 'number',
|
|
94
|
+
'select-editor': 'object',
|
|
95
|
+
'checkbox-editor': 'boolean',
|
|
96
|
+
'toggle-editor': 'boolean',
|
|
97
|
+
'date-time-editor': 'date',
|
|
98
|
+
'color-editor': 'string',
|
|
99
|
+
'link-editor': 'string',
|
|
100
|
+
'contact-editor': 'object',
|
|
101
|
+
'tagable-editor': 'string',
|
|
102
|
+
'file': 'object',
|
|
103
|
+
'gallery': 'object',
|
|
104
|
+
'signature': 'string',
|
|
105
|
+
'map': 'object',
|
|
106
|
+
'lookup-editor': 'object',
|
|
107
|
+
'selection-list-editor': 'array',
|
|
108
|
+
'table-editor': 'array',
|
|
109
|
+
'qrcode': 'string',
|
|
110
|
+
'single-file-box-editor': 'object',
|
|
111
|
+
'meta-data-editor': 'object'
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Widget groups for better display
|
|
115
|
+
const widgetGroups = {
|
|
116
|
+
'Basic': ['text-editor', 'large-text-editor', 'rich-text-editor', 'number-editor', 'checkbox-editor', 'toggle-editor'],
|
|
117
|
+
'Input': ['email-editor', 'password-editor', 'phone-editor', 'date-time-editor', 'color-editor'],
|
|
118
|
+
'Complex': ['select-editor', 'lookup-editor', 'selection-list-editor', 'table-editor'],
|
|
119
|
+
'Media': ['file', 'gallery', 'signature', 'map', 'qrcode']
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Define default colSpan based on widget type
|
|
123
|
+
const widgetToColSpan = {
|
|
124
|
+
'text-editor': 6,
|
|
125
|
+
'email-editor': 6,
|
|
126
|
+
'password-editor': 6,
|
|
127
|
+
'phone-editor': 6,
|
|
128
|
+
'large-text-editor': 12,
|
|
129
|
+
'rich-text-editor': 12,
|
|
130
|
+
'number-editor': 4,
|
|
131
|
+
'number-unit-editor': 6,
|
|
132
|
+
'select-editor': 6,
|
|
133
|
+
'checkbox-editor': 4,
|
|
134
|
+
'toggle-editor': 4,
|
|
135
|
+
'date-time-editor': 6,
|
|
136
|
+
'color-editor': 4,
|
|
137
|
+
'link-editor': 6,
|
|
138
|
+
'contact-editor': 8,
|
|
139
|
+
'tagable-editor': 8,
|
|
140
|
+
'file': 6,
|
|
141
|
+
'gallery': 12,
|
|
142
|
+
'signature': 8,
|
|
143
|
+
'map': 12,
|
|
144
|
+
'lookup-editor': 6,
|
|
145
|
+
'selection-list-editor': 8,
|
|
146
|
+
'table-editor': 12,
|
|
147
|
+
'qrcode': 6,
|
|
148
|
+
'single-file-box-editor': 6,
|
|
149
|
+
'meta-data-editor': 8
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Create data object to store all user input
|
|
153
|
+
const data = {
|
|
154
|
+
moduleName: '',
|
|
155
|
+
name: '',
|
|
156
|
+
properties: [],
|
|
157
|
+
dataTypes: [],
|
|
158
|
+
required: [],
|
|
159
|
+
colSpans: [],
|
|
160
|
+
orders: [],
|
|
161
|
+
widgets: [], // Used locally but not passed to NX generator
|
|
162
|
+
icon: 'fa-light fa-default',
|
|
163
|
+
enableSorts: [],
|
|
164
|
+
enableFilters: [],
|
|
165
|
+
enableInlineFilters: [],
|
|
166
|
+
inColumn: [] // اضافه کردن آرایه جدید برای ذخیره وضعیت نمایش در ستون
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Run the prompts in sequence
|
|
170
|
+
async function runPrompts() {
|
|
171
|
+
console.log('\n=== AcoreX Platform Interactive Entity Generator ===\n');
|
|
172
|
+
|
|
173
|
+
// Get module name with validation
|
|
174
|
+
while (true) {
|
|
175
|
+
data.moduleName = await askQuestion('Module name: ');
|
|
176
|
+
const error = validateName(data.moduleName);
|
|
177
|
+
if (error) {
|
|
178
|
+
console.log(`Error: ${error}`);
|
|
179
|
+
} else {
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Get entity name with validation
|
|
185
|
+
while (true) {
|
|
186
|
+
data.name = await askQuestion('Entity name: ');
|
|
187
|
+
const error = validateName(data.name);
|
|
188
|
+
if (error) {
|
|
189
|
+
console.log(`Error: ${error}`);
|
|
190
|
+
} else {
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Get properties
|
|
196
|
+
console.log('\nEnter properties (type "done" when finished):');
|
|
197
|
+
let propCount = 1;
|
|
198
|
+
while (true) {
|
|
199
|
+
const prop = await askQuestion(`Property ${propCount}: `);
|
|
200
|
+
if (prop.toLowerCase() === 'done') {
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
data.properties.push(prop);
|
|
204
|
+
|
|
205
|
+
// Get widget for this property
|
|
206
|
+
const widget = await selectWidget(`Select widget for "${prop}": `);
|
|
207
|
+
data.widgets.push(widget);
|
|
208
|
+
|
|
209
|
+
// Automatically determine data type based on widget
|
|
210
|
+
const dataType = widgetToDataType[widget] || 'string';
|
|
211
|
+
data.dataTypes.push(dataType);
|
|
212
|
+
|
|
213
|
+
// Ask if this property is required
|
|
214
|
+
const isRequired = await askQuestion(`Is "${prop}" required? (y/n): `, 'n');
|
|
215
|
+
if (isRequired.toLowerCase() === 'y') {
|
|
216
|
+
data.required.push(prop);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Ask if this property should be displayed in columns
|
|
220
|
+
const showInColumn = await askQuestion(`Show "${prop}" in table columns? (y/n): `, 'y');
|
|
221
|
+
data.inColumn.push(showInColumn.toLowerCase() === 'y' ? 'true' : 'false');
|
|
222
|
+
|
|
223
|
+
// Get colSpan for this property (1-12)
|
|
224
|
+
const defaultColSpan = widgetToColSpan[widget] || 6;
|
|
225
|
+
const colSpan = await askQuestion(`Column span for "${prop}" (1-12): `, defaultColSpan.toString());
|
|
226
|
+
data.colSpans.push(parseInt(colSpan));
|
|
227
|
+
|
|
228
|
+
// Get order for this property
|
|
229
|
+
const defaultOrder = propCount; // Default order is sequential
|
|
230
|
+
const order = await askQuestion(`Display order for "${prop}" (default: ${defaultOrder}): `, defaultOrder.toString());
|
|
231
|
+
data.orders.push(parseInt(order));
|
|
232
|
+
|
|
233
|
+
// Ask about sort
|
|
234
|
+
const enableSort = await askQuestion(`Enable sorting for "${prop}"? (y/n): `, 'y');
|
|
235
|
+
data.enableSorts.push(enableSort.toLowerCase() === 'y' ? 'true' : 'false');
|
|
236
|
+
|
|
237
|
+
// Ask about filter
|
|
238
|
+
const enableFilter = await askQuestion(`Enable filtering for "${prop}"? (y/n): `, 'y');
|
|
239
|
+
data.enableFilters.push(enableFilter.toLowerCase() === 'y' ? 'true' : 'false');
|
|
240
|
+
|
|
241
|
+
// Ask about inline filter
|
|
242
|
+
const enableInlineFilter = await askQuestion(`Enable inline filtering for "${prop}"? (y/n): `, 'n');
|
|
243
|
+
data.enableInlineFilters.push(enableInlineFilter.toLowerCase() === 'y' ? 'true' : 'false');
|
|
244
|
+
|
|
245
|
+
propCount++;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Get icon
|
|
249
|
+
console.log('\nSelect an icon:');
|
|
250
|
+
console.log('1. Default icon (fa-light fa-default)');
|
|
251
|
+
console.log('2. Box (fa-solid fa-box)');
|
|
252
|
+
console.log('3. User (fa-solid fa-user)');
|
|
253
|
+
console.log('4. Shopping cart (fa-solid fa-shopping-cart)');
|
|
254
|
+
console.log('5. File (fa-solid fa-file)');
|
|
255
|
+
console.log('6. Custom icon');
|
|
256
|
+
|
|
257
|
+
const iconChoice = await askQuestion('Select option (1-6): ', '1');
|
|
258
|
+
const iconOptions = [
|
|
259
|
+
'fa-light fa-default',
|
|
260
|
+
'fa-solid fa-box',
|
|
261
|
+
'fa-solid fa-user',
|
|
262
|
+
'fa-solid fa-shopping-cart',
|
|
263
|
+
'fa-solid fa-file'
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
if (iconChoice >= 1 && iconChoice <= 5) {
|
|
267
|
+
data.icon = iconOptions[iconChoice - 1];
|
|
268
|
+
} else if (iconChoice == 6) {
|
|
269
|
+
data.icon = await askQuestion('Enter custom icon (format: fa-solid fa-xyz): ', 'fa-solid fa-star');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Show summary
|
|
273
|
+
console.log('\n=== Summary ===');
|
|
274
|
+
console.log(`Module: ${data.moduleName}`);
|
|
275
|
+
console.log(`Entity: ${data.name}`);
|
|
276
|
+
console.log('Properties:');
|
|
277
|
+
|
|
278
|
+
// Sort properties by order for display
|
|
279
|
+
const propSummary = data.properties.map((prop, i) => ({
|
|
280
|
+
name: prop,
|
|
281
|
+
widget: data.widgets[i],
|
|
282
|
+
dataType: data.dataTypes[i],
|
|
283
|
+
required: data.required.includes(prop),
|
|
284
|
+
colSpan: data.colSpans[i],
|
|
285
|
+
order: data.orders[i],
|
|
286
|
+
enableSort: data.enableSorts[i],
|
|
287
|
+
enableFilter: data.enableFilters[i],
|
|
288
|
+
enableInlineFilter: data.enableInlineFilters[i],
|
|
289
|
+
inColumn: data.inColumn[i]
|
|
290
|
+
}));
|
|
291
|
+
|
|
292
|
+
// Sort by order
|
|
293
|
+
propSummary.sort((a, b) => a.order - b.order);
|
|
294
|
+
|
|
295
|
+
propSummary.forEach(prop => {
|
|
296
|
+
console.log(` - ${prop.name} (Widget: ${prop.widget}, Type: ${prop.dataType}${prop.required ? ', Required' : ''}, ColSpan: ${prop.colSpan}, Order: ${prop.order}, Sort: ${prop.enableSort ? 'Enabled' : 'Disabled'}, Filter: ${prop.enableFilter ? 'Enabled' : 'Disabled'}, Inline Filter: ${prop.enableInlineFilter ? 'Enabled' : 'Disabled'}, In Column: ${prop.inColumn === 'true' ? 'Yes' : 'No'})`);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
console.log(`Icon: ${data.icon}`);
|
|
300
|
+
|
|
301
|
+
const confirm = await askQuestion('\nGenerate entity with these settings? (y/n): ', 'y');
|
|
302
|
+
if (confirm.toLowerCase() === 'y') {
|
|
303
|
+
runNxGenerator();
|
|
304
|
+
} else {
|
|
305
|
+
console.log('Operation cancelled');
|
|
306
|
+
rl.close();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Helper function to ask questions and get answers
|
|
311
|
+
function askQuestion(question, defaultAnswer) {
|
|
312
|
+
return new Promise(resolve => {
|
|
313
|
+
const prompt = defaultAnswer ? `${question} [${defaultAnswer}] ` : question;
|
|
314
|
+
|
|
315
|
+
rl.question(prompt, (answer) => {
|
|
316
|
+
// If answer is empty and there's a default, use the default
|
|
317
|
+
const result = answer.trim() === '' && defaultAnswer ? defaultAnswer : answer.trim();
|
|
318
|
+
resolve(result);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Helper function to select a widget with filtering capability
|
|
324
|
+
async function selectWidget(prompt) {
|
|
325
|
+
console.log(`\n${prompt}`);
|
|
326
|
+
console.log('Available widgets (you can type to filter):');
|
|
327
|
+
|
|
328
|
+
// Display widgets by groups
|
|
329
|
+
for (const [groupName, groupWidgets] of Object.entries(widgetGroups)) {
|
|
330
|
+
console.log(`\n${groupName} widgets:`);
|
|
331
|
+
groupWidgets.forEach((widget, index) => {
|
|
332
|
+
const widgetKey = Object.entries(widgetCatalog).find(([key, value]) => value === widget)?.[0] || '';
|
|
333
|
+
console.log(` ${(index + 1).toString().padStart(2)}: ${widget} (${widgetKey})`);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Handling widget selection with filtering
|
|
338
|
+
let selectedWidget = '';
|
|
339
|
+
while (!selectedWidget) {
|
|
340
|
+
const input = await askQuestion('\nEnter widget name or number (or part of name to filter): ');
|
|
341
|
+
|
|
342
|
+
// Check if input is a number
|
|
343
|
+
if (!isNaN(input) && input > 0 && input <= Object.values(widgetCatalog).length) {
|
|
344
|
+
const allWidgets = Object.values(widgetCatalog);
|
|
345
|
+
selectedWidget = allWidgets[parseInt(input) - 1];
|
|
346
|
+
}
|
|
347
|
+
// Check if input exactly matches a widget name
|
|
348
|
+
else if (Object.values(widgetCatalog).includes(input)) {
|
|
349
|
+
selectedWidget = input;
|
|
350
|
+
}
|
|
351
|
+
// Check if input matches a widget key
|
|
352
|
+
else if (widgetCatalog[input]) {
|
|
353
|
+
selectedWidget = widgetCatalog[input];
|
|
354
|
+
}
|
|
355
|
+
// Filter widgets by input
|
|
356
|
+
else {
|
|
357
|
+
const filteredWidgets = Object.entries(widgetCatalog)
|
|
358
|
+
.filter(([key, value]) =>
|
|
359
|
+
key.toLowerCase().includes(input.toLowerCase()) ||
|
|
360
|
+
value.toLowerCase().includes(input.toLowerCase())
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
if (filteredWidgets.length === 1) {
|
|
364
|
+
selectedWidget = filteredWidgets[0][1]; // Pick the only match
|
|
365
|
+
}
|
|
366
|
+
else if (filteredWidgets.length > 1) {
|
|
367
|
+
console.log('\nFiltered widgets:');
|
|
368
|
+
filteredWidgets.forEach(([key, value], index) => {
|
|
369
|
+
console.log(` ${(index + 1).toString().padStart(2)}: ${value} (${key})`);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
const selection = await askQuestion('Select number or continue typing to filter more: ');
|
|
373
|
+
if (!isNaN(selection) && selection > 0 && selection <= filteredWidgets.length) {
|
|
374
|
+
selectedWidget = filteredWidgets[parseInt(selection) - 1][1];
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
console.log('No matches found. Try again.');
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return selectedWidget;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Run the NX generator with collected data
|
|
387
|
+
function runNxGenerator() {
|
|
388
|
+
// Handle special cases and ensure proper formatting
|
|
389
|
+
|
|
390
|
+
// For empty required array, use "_none_"
|
|
391
|
+
const requiredValue = data.required.length === 0 ? "_none_" : data.required.join(',');
|
|
392
|
+
|
|
393
|
+
// Ensure single values for colSpans and orders have trailing commas
|
|
394
|
+
let colSpansStr = data.colSpans.join(',');
|
|
395
|
+
if (data.colSpans.length === 1) {
|
|
396
|
+
colSpansStr = colSpansStr + ',';
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
let ordersStr = data.orders.join(',');
|
|
400
|
+
if (data.orders.length === 1) {
|
|
401
|
+
ordersStr = ordersStr + ',';
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Prepare arguments properly
|
|
405
|
+
const command = `cd "${projectRoot}" && npx nx g @acorex-platform/generator:create-module-entity` +
|
|
406
|
+
` --moduleName=${data.moduleName}` +
|
|
407
|
+
` --name=${data.name}` +
|
|
408
|
+
` --properties=${data.properties.join(',')}` +
|
|
409
|
+
` --dataTypes=${data.dataTypes.join(',')}` +
|
|
410
|
+
` --required=${requiredValue}` +
|
|
411
|
+
` --colSpans=${colSpansStr}` +
|
|
412
|
+
` --orders=${ordersStr}` +
|
|
413
|
+
` --icon="${data.icon}"` +
|
|
414
|
+
` --enableSorts=${data.enableSorts.join(',')}` +
|
|
415
|
+
` --enableFilters=${data.enableFilters.join(',')}` +
|
|
416
|
+
` --enableInlineFilters=${data.enableInlineFilters.join(',')}` +
|
|
417
|
+
` --inColumn=${data.inColumn.join(',')}` +
|
|
418
|
+
(isDryRun ? ' --dryRun' : '');
|
|
419
|
+
|
|
420
|
+
console.log(`\nRunning: ${command}`);
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
// Execute the command as a shell command to ensure proper environment
|
|
424
|
+
const { execSync } = require('child_process');
|
|
425
|
+
const options = {
|
|
426
|
+
stdio: 'inherit',
|
|
427
|
+
shell: true
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
execSync(command, options);
|
|
431
|
+
console.log(`\nGenerator completed successfully`);
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.error(`\nGenerator failed with error: ${error.message}`);
|
|
434
|
+
|
|
435
|
+
// Show more detailed error information
|
|
436
|
+
if (error.stderr) {
|
|
437
|
+
console.error(`Error details: ${error.stderr.toString()}`);
|
|
438
|
+
}
|
|
439
|
+
} finally {
|
|
440
|
+
rl.close();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Start the prompts
|
|
445
|
+
runPrompts().catch(err => {
|
|
446
|
+
console.error('An error occurred:', err);
|
|
447
|
+
rl.close();
|
|
448
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
|
|
5
|
+
// Check for --dryRun flag at the beginning
|
|
6
|
+
const isDryRun = process.argv.includes('--dryRun');
|
|
7
|
+
|
|
8
|
+
// Store predefined data
|
|
9
|
+
const data = {
|
|
10
|
+
moduleName: 'test',
|
|
11
|
+
name: 't1',
|
|
12
|
+
properties: ['title', 'name'],
|
|
13
|
+
widgets: ['text-editor', 'text-editor'],
|
|
14
|
+
dataTypes: ['string', 'string'],
|
|
15
|
+
required: ['name'],
|
|
16
|
+
colSpans: [6, 6],
|
|
17
|
+
orders: [1, 2],
|
|
18
|
+
icon: 'fa-light fa-default'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
console.log('\n=== AcoreX Platform Interactive Entity Generator (Test Mode) ===\n');
|
|
22
|
+
console.log('Using predefined values:');
|
|
23
|
+
console.log(`Module: ${data.moduleName}`);
|
|
24
|
+
console.log(`Entity: ${data.name}`);
|
|
25
|
+
console.log(`Properties: ${data.properties.join(', ')}`);
|
|
26
|
+
console.log(`Required: ${data.required.join(', ')}`);
|
|
27
|
+
console.log(`Icon: ${data.icon}`);
|
|
28
|
+
|
|
29
|
+
// Run the NX generator with the predefined data
|
|
30
|
+
function runNxGenerator() {
|
|
31
|
+
// Format the command
|
|
32
|
+
const command = `cd ../../.. && npx nx g @acorex-platform/generator:create-module-entity --moduleName=${data.moduleName} --name=${data.name} --properties=${data.properties.join(',')} --dataTypes=${data.dataTypes.join(',')} --required=${data.required.join(',')} --colSpans=${data.colSpans.join(',')} --orders=${data.orders.join(',')} --icon="${data.icon}"${isDryRun ? ' --dryRun' : ''}`;
|
|
33
|
+
|
|
34
|
+
console.log(`\nRunning: ${command}`);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
// Execute the command
|
|
38
|
+
const output = execSync(command, { stdio: 'inherit' });
|
|
39
|
+
console.log('\nGenerator completed successfully');
|
|
40
|
+
return 0;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(`\nGenerator failed with error: ${error.message}`);
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Run the generator
|
|
48
|
+
process.exit(runNxGenerator());
|
|
@@ -7,7 +7,6 @@ import { BrowserModule } from '@angular/platform-browser';
|
|
|
7
7
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
8
8
|
import { RouterModule, provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
|
|
9
9
|
import { EffectsModule } from '@ngrx/effects';
|
|
10
|
-
import { StoreModule } from '@ngrx/store';
|
|
11
10
|
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
|
12
11
|
import { AppComponent } from './app.component';
|
|
13
12
|
import { appRoutes } from './app.routes';
|
|
@@ -41,8 +40,6 @@ import { AXMSampleEntityModule } from './modules/<%= name %>/sample/sample.modul
|
|
|
41
40
|
bindToComponentInputs: true,
|
|
42
41
|
onSameUrlNavigation: 'reload',
|
|
43
42
|
}),
|
|
44
|
-
StoreModule.forRoot([]),
|
|
45
|
-
EffectsModule.forRoot(),
|
|
46
43
|
AXFormatModule.forRoot(),
|
|
47
44
|
AXValidationModule.forRoot(),
|
|
48
45
|
//
|
package/src/generators/app-module/files/src/app/modules/root/sample/sample.service.ts.template
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AXMEntityCrudServiceImpl } from '@acorex/platform/
|
|
1
|
+
import { AXMEntityCrudServiceImpl } from '@acorex/platform/layout/entity';
|
|
2
2
|
import { Injectable } from '@angular/core';
|
|
3
3
|
import { AXMSampleModuleConst } from '../const';
|
|
4
4
|
import { AXMSampleEntityModel } from './sample.types';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './lib/<%= fileName %>.module';
|
|
2
|
+
//export * from './lib/components';
|
|
3
|
+
export * from './lib/const';
|
|
4
|
+
//export * from './lib/entities';
|
|
5
|
+
export * from './lib/entity.provider';
|
|
6
|
+
export * from './lib/menu.provider';
|
|
7
|
+
export * from './lib/search-command.provider';
|
|
8
|
+
export * from './lib/setting.provider';
|
|
9
|
+
//export * from './lib/pages';
|
package/src/generators/create-app-module/files/__fileName__/src/lib/__fileName__.module.ts__tmpl__
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { NgModule } from "@angular/core";
|
|
2
|
+
import { AXP_PERMISSION_PROVIDER } from '@acorex/platform/auth';
|
|
3
|
+
import { AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER } from '@acorex/platform/common';
|
|
4
|
+
import { AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
5
|
+
import { AXMMenuProvider } from './menu.provider';
|
|
6
|
+
import { AXMEntityProvider } from './entity.provider';
|
|
7
|
+
import { AXMPermissionProvider } from './permission.provider';
|
|
8
|
+
import { AXMSettingProvider } from './setting.provider';
|
|
9
|
+
import { AXMSearchCommandProvider } from './search-command.provider';
|
|
10
|
+
|
|
11
|
+
@NgModule({
|
|
12
|
+
imports: [],
|
|
13
|
+
exports: [],
|
|
14
|
+
declarations: [],
|
|
15
|
+
providers : [
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
provide: AXP_MENU_PROVIDER,
|
|
19
|
+
useClass: AXMMenuProvider,
|
|
20
|
+
multi: true,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
provide: AXP_ENTITY_DEFINITION_LOADER,
|
|
24
|
+
useClass: AXMEntityProvider,
|
|
25
|
+
multi: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
29
|
+
useClass: AXMSettingProvider,
|
|
30
|
+
multi: true,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
provide: AXP_SEARCH_PROVIDER,
|
|
34
|
+
useClass: AXMSearchCommandProvider,
|
|
35
|
+
multi: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
provide: AXP_PERMISSION_PROVIDER,
|
|
39
|
+
useClass: AXMPermissionProvider,
|
|
40
|
+
multi: true,
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
})
|
|
44
|
+
export class AXM<%= className %>Module {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
i18n: '<%= fileName %>',
|
|
3
|
+
};
|
|
4
|
+
export const RootConfig = {
|
|
5
|
+
config,
|
|
6
|
+
module: {
|
|
7
|
+
module: '<%= name %>',
|
|
8
|
+
name: '<%= className %>',
|
|
9
|
+
title: `t('module-name', {scope:"${config.i18n}"})`,
|
|
10
|
+
icon: 'fa-light fa-file-invoice',
|
|
11
|
+
},
|
|
12
|
+
entities: {
|
|
13
|
+
// category: {
|
|
14
|
+
// name: 'Category',
|
|
15
|
+
// title: 't("category", { scope: "common" })',
|
|
16
|
+
// icon: 'fa-light fa-list'
|
|
17
|
+
// },
|
|
18
|
+
},
|
|
19
|
+
};
|
package/src/generators/create-app-module/files/__fileName__/src/lib/entity.provider.ts__tmpl__
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AXPEntity } from '@acorex/platform/common';
|
|
2
|
+
import {
|
|
3
|
+
AXPEntityDefinitionLoader,
|
|
4
|
+
AXPEntityDefinitionPreloader,
|
|
5
|
+
AXPEntityPreloadEntity,
|
|
6
|
+
} from '@acorex/platform/layout/entity';
|
|
7
|
+
import { Injectable, Injector, inject } from '@angular/core';
|
|
8
|
+
import { RootConfig } from './const';
|
|
9
|
+
|
|
10
|
+
@Injectable()
|
|
11
|
+
export class AXMEntityProvider implements AXPEntityDefinitionLoader, AXPEntityDefinitionPreloader {
|
|
12
|
+
private injector = inject(Injector);
|
|
13
|
+
|
|
14
|
+
public preload(): AXPEntityPreloadEntity[] {
|
|
15
|
+
const module = RootConfig.module.name;
|
|
16
|
+
return Array.from(Object.values(RootConfig.entities)).map((entity: any) => ({
|
|
17
|
+
module: module,
|
|
18
|
+
entity: entity.name,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async get(moduleName: string, entityName: string): Promise<AXPEntity | null> {
|
|
23
|
+
if (moduleName == RootConfig.module.name) {
|
|
24
|
+
switch (
|
|
25
|
+
entityName
|
|
26
|
+
// case RootConfig.entities.sample.name:
|
|
27
|
+
// return (await import('./entities/sample/sample.entity')).factory(this.injector);
|
|
28
|
+
) {
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|