devextreme-schematics 1.2.18 → 1.2.22
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +2 -2
- package/src/add-app-template/index.ts +30 -0
- package/src/add-app-template/index_spec.ts +73 -0
- package/src/add-layout/files/e2e/src/app.e2e-spec.ts +14 -14
- package/src/add-layout/files/e2e/src/app.po.ts +11 -11
- package/src/add-layout/files/src/app/app-navigation.ts +1 -1
- package/src/add-layout/files/src/app/layouts/index.ts +3 -3
- package/src/add-layout/files/src/app/shared/components/change-password-form/change-password-form.component.html +8 -6
- package/src/add-layout/files/src/app/shared/components/create-account-form/create-account-form.component.html +9 -7
- package/src/add-layout/files/src/app/shared/components/footer/footer.component.ts +19 -19
- package/src/add-layout/files/src/app/shared/components/login-form/login-form.component.html +8 -6
- package/src/add-layout/files/src/app/shared/components/reset-password-form/reset-password-form.component.html +8 -6
- package/src/add-layout/index.ts +386 -0
- package/src/add-layout/index_spec.ts +340 -0
- package/src/add-sample-views/files/pages/home/home.component.ts +10 -10
- package/src/add-sample-views/files/pages/profile/profile.component.ts +33 -33
- package/src/add-sample-views/index.ts +141 -0
- package/src/add-sample-views/index_spec.ts +74 -0
- package/src/add-view/index.ts +165 -0
- package/src/add-view/index_spec.ts +155 -0
- package/src/install/index.ts +86 -0
- package/src/install/index_spec.ts +106 -0
- package/src/install/schema.json +1 -1
- package/src/utility/array.ts +3 -0
- package/src/utility/change.js +1 -1
- package/src/utility/change.ts +66 -0
- package/src/utility/latest-versions.js +2 -2
- package/src/utility/latest-versions.ts +6 -0
- package/src/utility/modify-json-file.ts +13 -0
- package/src/utility/project.ts +25 -0
- package/src/utility/routing.js +4 -4
- package/src/utility/routing.ts +44 -0
- package/src/utility/source.ts +16 -0
- package/src/utility/string.ts +5 -0
- package/src/utility/styles.ts +33 -0
@@ -0,0 +1,340 @@
|
|
1
|
+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
2
|
+
import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
|
3
|
+
import {
|
4
|
+
NodeDependencyType,
|
5
|
+
addPackageJsonDependency,
|
6
|
+
removePackageJsonDependency
|
7
|
+
} from '@schematics/angular/utility/dependencies';
|
8
|
+
import * as path from 'path';
|
9
|
+
|
10
|
+
import { modifyJSONFile } from '../utility/modify-json-file';
|
11
|
+
|
12
|
+
const collectionPath = path.join(__dirname, '../collection.json');
|
13
|
+
|
14
|
+
describe('layout', () => {
|
15
|
+
const appOptions: any = {
|
16
|
+
name: 'testApp',
|
17
|
+
projectRoot: '',
|
18
|
+
inlineStyle: false,
|
19
|
+
inlineTemplate: false,
|
20
|
+
routing: false,
|
21
|
+
style: 'scss',
|
22
|
+
skipTests: false,
|
23
|
+
skipPackageJson: false
|
24
|
+
};
|
25
|
+
|
26
|
+
const workspaceOptions: WorkspaceOptions = {
|
27
|
+
name: 'workspace',
|
28
|
+
version: '6.0.0'
|
29
|
+
};
|
30
|
+
|
31
|
+
const options: any = {
|
32
|
+
layout: 'side-nav-outer-toolbar',
|
33
|
+
resolveConflicts: 'override',
|
34
|
+
globalNgCliVersion: '^8.0.0'
|
35
|
+
};
|
36
|
+
|
37
|
+
const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
|
38
|
+
const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
|
39
|
+
let appTree: UnitTestTree;
|
40
|
+
|
41
|
+
beforeEach(async () => {
|
42
|
+
appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
|
43
|
+
appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
|
44
|
+
});
|
45
|
+
|
46
|
+
it('should add layout with override', async () => {
|
47
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
48
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
49
|
+
|
50
|
+
expect(tree.files)
|
51
|
+
.toContain('/devextreme.json');
|
52
|
+
expect(tree.files)
|
53
|
+
.toContain('/src/app/app-navigation.ts');
|
54
|
+
expect(tree.files)
|
55
|
+
.toContain('/src/app/shared/components/header/header.component.ts');
|
56
|
+
expect(tree.files)
|
57
|
+
.toContain('/src/app/shared/components/login-form/login-form.component.ts');
|
58
|
+
expect(tree.files)
|
59
|
+
.toContain('/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
|
60
|
+
expect(tree.files)
|
61
|
+
.toContain('/src/app/shared/services/app-info.service.ts');
|
62
|
+
expect(tree.files)
|
63
|
+
.toContain('/src/app/shared/services/auth.service.ts');
|
64
|
+
expect(tree.files)
|
65
|
+
.toContain('/src/app/shared/services/screen.service.ts');
|
66
|
+
expect(tree.files)
|
67
|
+
.toContain('/src/app/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.component.ts');
|
68
|
+
expect(tree.files)
|
69
|
+
.toContain('/src/app/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.component.ts');
|
70
|
+
expect(tree.files)
|
71
|
+
.toContain('/src/app/layouts/single-card/single-card.component.ts');
|
72
|
+
expect(tree.files)
|
73
|
+
.toContain('/src/themes/metadata.base.json');
|
74
|
+
expect(tree.files)
|
75
|
+
.toContain('/src/themes/metadata.additional.json');
|
76
|
+
|
77
|
+
const devextremeConfigContent = tree.readContent('/devextreme.json');
|
78
|
+
expect(devextremeConfigContent).toContain('"applicationEngine": "angular"');
|
79
|
+
expect(devextremeConfigContent).toContain('"inputFile": "src/themes/metadata.additional.json"');
|
80
|
+
expect(devextremeConfigContent).toMatch(/\n\s{2}\S/g);
|
81
|
+
|
82
|
+
const componentContent = tree.readContent('/src/app/app.component.html');
|
83
|
+
expect(componentContent).toContain('app-side-nav-outer-toolbar title="{{appInfo.title}}"');
|
84
|
+
|
85
|
+
const stylesContent = tree.readContent('/src/dx-styles.scss');
|
86
|
+
expect(stylesContent).toMatch(/html, body {/);
|
87
|
+
|
88
|
+
const indexContent = tree.readContent('/src/index.html');
|
89
|
+
expect(indexContent).toMatch(/<body class="dx-viewport">/);
|
90
|
+
|
91
|
+
const angularContent = JSON.parse(tree.readContent('/angular.json'));
|
92
|
+
const styles = angularContent.projects.testApp.architect.build.options.styles;
|
93
|
+
|
94
|
+
expect(styles[0]).toBe('node_modules/devextreme/dist/css/dx.common.css');
|
95
|
+
expect(styles[1]).toBe('src/themes/generated/theme.base.css');
|
96
|
+
expect(styles[2]).toBe('src/themes/generated/theme.additional.css');
|
97
|
+
|
98
|
+
const moduleContent = tree.readContent('/src/app/app.module.ts');
|
99
|
+
expect(moduleContent)
|
100
|
+
.toContain('import { SideNavOuterToolbarModule, SideNavInnerToolbarModule, SingleCardModule }');
|
101
|
+
expect(moduleContent)
|
102
|
+
.toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
|
103
|
+
expect(moduleContent).toContain('import { AppRoutingModule }');
|
104
|
+
expect(moduleContent)
|
105
|
+
.toContain('import { FooterModule, ' +
|
106
|
+
'ResetPasswordFormModule, ' +
|
107
|
+
'CreateAccountFormModule, ' +
|
108
|
+
'ChangePasswordFormModule, ' +
|
109
|
+
'LoginFormModule }');
|
110
|
+
|
111
|
+
const testContent = tree.readContent('/e2e/src/app.e2e-spec.ts');
|
112
|
+
expect(testContent).toMatch(/'Welcome to TestApp!'/);
|
113
|
+
|
114
|
+
const testUtilsContent = tree.readContent('/e2e/src/app.po.ts');
|
115
|
+
expect(testUtilsContent).toMatch(/'app-root .dx-drawer-content .dx-card p:nth-child\(2\)'/);
|
116
|
+
|
117
|
+
const appContent = tree.readContent('/src/app/app.component.ts');
|
118
|
+
expect(appContent).toContain('templateUrl: \'./app.component.html\',');
|
119
|
+
expect(appContent).toContain('styleUrls: [\'./app.component.scss\']');
|
120
|
+
expect(appContent).toContain('selector: \'app-root\',');
|
121
|
+
expect(appContent).toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
|
122
|
+
|
123
|
+
const navigationMenu = tree.readContent(
|
124
|
+
'/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
|
125
|
+
expect(navigationMenu).toContain('@ViewChild(DxTreeViewComponent, { static: true })');
|
126
|
+
});
|
127
|
+
|
128
|
+
it('should add npm scripts', async () => {
|
129
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
130
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
131
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
132
|
+
expect(packageConfig.scripts['build-themes']).toBe('devextreme build');
|
133
|
+
expect(packageConfig.scripts['postinstall']).toBe('npm run build-themes');
|
134
|
+
});
|
135
|
+
|
136
|
+
it('should set static flag', async () => {
|
137
|
+
removePackageJsonDependency(appTree, '@angular/core');
|
138
|
+
addPackageJsonDependency(appTree, {
|
139
|
+
type: NodeDependencyType.Default,
|
140
|
+
name: '@angular/core',
|
141
|
+
version: '7.0.0'
|
142
|
+
});
|
143
|
+
|
144
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
145
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
146
|
+
const navigationMenu = tree.readContent(
|
147
|
+
'/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
|
148
|
+
|
149
|
+
expect(navigationMenu).toContain('@ViewChild(DxTreeViewComponent, { static: true })');
|
150
|
+
});
|
151
|
+
|
152
|
+
it('should add npm scripts safely', async () => {
|
153
|
+
modifyJSONFile(appTree, './package.json', config => {
|
154
|
+
const scripts = config['scripts'];
|
155
|
+
|
156
|
+
scripts['build-themes'] = 'prev value 1';
|
157
|
+
scripts['postinstall'] = 'prev value 2';
|
158
|
+
|
159
|
+
return config;
|
160
|
+
});
|
161
|
+
|
162
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
163
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
164
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
165
|
+
expect(packageConfig.scripts['origin-build-themes']).toBe('prev value 1');
|
166
|
+
expect(packageConfig.scripts['origin-postinstall']).toBe('prev value 2');
|
167
|
+
expect(packageConfig.scripts['build-themes']).toBe('npm run origin-build-themes && devextreme build');
|
168
|
+
expect(packageConfig.scripts['postinstall']).toBe('npm run origin-postinstall && npm run build-themes');
|
169
|
+
});
|
170
|
+
|
171
|
+
it('should add angular/cdk dependency', async () => {
|
172
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
173
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
174
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
175
|
+
|
176
|
+
expect(packageConfig.dependencies['@angular/cdk']).toBeDefined();
|
177
|
+
});
|
178
|
+
|
179
|
+
it('should choose angular/cdk version such as angular/cli', async () => {
|
180
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
181
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
182
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
183
|
+
|
184
|
+
expect(packageConfig.dependencies['@angular/cdk']).toBe('^8.0.0');
|
185
|
+
});
|
186
|
+
|
187
|
+
it('should update budgets if updateBudgets option is true', async () => {
|
188
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
189
|
+
const tree = await runner.runSchematicAsync('add-layout', {
|
190
|
+
...options,
|
191
|
+
updateBudgets: true
|
192
|
+
}, appTree).toPromise();
|
193
|
+
|
194
|
+
const angularContent = JSON.parse(tree.readContent('/angular.json'));
|
195
|
+
const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
|
196
|
+
|
197
|
+
expect(budgets.length).toBe(2);
|
198
|
+
expect(budgets[0]).toEqual({
|
199
|
+
type: 'initial',
|
200
|
+
maximumWarning: '4mb',
|
201
|
+
maximumError: '7mb'
|
202
|
+
});
|
203
|
+
});
|
204
|
+
|
205
|
+
it('should not update budgets if updateBudgets option is not defined or false', async () => {
|
206
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
207
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
208
|
+
|
209
|
+
const angularContent = JSON.parse(tree.readContent('/angular.json'));
|
210
|
+
const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
|
211
|
+
const defaultBudget = {
|
212
|
+
type: 'initial',
|
213
|
+
maximumWarning: '2mb',
|
214
|
+
maximumError: '5mb'
|
215
|
+
};
|
216
|
+
|
217
|
+
expect(budgets.length).toBe(2);
|
218
|
+
expect(budgets[0]).toEqual(defaultBudget);
|
219
|
+
});
|
220
|
+
|
221
|
+
it('should add layout without override', async () => {
|
222
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
223
|
+
|
224
|
+
options.resolveConflicts = 'createNew';
|
225
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
226
|
+
|
227
|
+
expect(tree.files).toContain('/src/app/app1.component.ts');
|
228
|
+
|
229
|
+
const componentContent = tree.readContent('/src/app/app1.component.html');
|
230
|
+
expect(componentContent).toContain('app-side-nav-outer-toolbar title="{{appInfo.title}}"');
|
231
|
+
|
232
|
+
const appContent = tree.readContent('/src/app/app.component.ts');
|
233
|
+
expect(appContent).toMatch(/templateUrl: '.\/app.component.html',/);
|
234
|
+
expect(appContent).toMatch(/styleUrls: \['.\/app.component.scss'\]/);
|
235
|
+
|
236
|
+
const newAppContent = tree.readContent('/src/app/app1.component.ts');
|
237
|
+
expect(newAppContent).toMatch(/templateUrl: '.\/app1.component.html',/);
|
238
|
+
expect(newAppContent).toMatch(/styleUrls: \['.\/app1.component.scss'\]/);
|
239
|
+
expect(newAppContent).toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
|
240
|
+
|
241
|
+
const appInfo = tree.readContent('/src/app/shared/services/app-info.service.ts');
|
242
|
+
expect(appInfo).toContain(`return 'TestApp';`);
|
243
|
+
});
|
244
|
+
|
245
|
+
it('should add routing to layout', async () => {
|
246
|
+
let newAppTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
|
247
|
+
|
248
|
+
appOptions.routing = false;
|
249
|
+
newAppTree = await schematicRunner.runSchematicAsync(
|
250
|
+
'application', appOptions, newAppTree).toPromise();
|
251
|
+
|
252
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
253
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
254
|
+
|
255
|
+
expect(tree.files).toContain('/src/app/app-routing.module.ts');
|
256
|
+
const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
|
257
|
+
expect(moduleContent)
|
258
|
+
.toMatch(/imports:\s\[RouterModule\.forRoot\(routes, { useHash: true }\)\],/);
|
259
|
+
|
260
|
+
expect(moduleContent)
|
261
|
+
.toContain(`{
|
262
|
+
path: 'login-form',
|
263
|
+
component: LoginFormComponent,
|
264
|
+
canActivate: [ AuthGuardService ]
|
265
|
+
}`);
|
266
|
+
});
|
267
|
+
|
268
|
+
it('should use selected layout', async () => {
|
269
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
270
|
+
options.layout = 'side-nav-inner-toolbar';
|
271
|
+
options.resolveConflicts = 'override';
|
272
|
+
const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
273
|
+
const content = tree.readContent('/src/app/app.component.html');
|
274
|
+
|
275
|
+
expect(content).toContain('app-side-nav-inner-toolbar title="{{appInfo.title}}"');
|
276
|
+
});
|
277
|
+
|
278
|
+
it('should consider the `project` option', async () => {
|
279
|
+
appTree = await schematicRunner.runSchematicAsync('application', {
|
280
|
+
...appOptions,
|
281
|
+
name: 'testApp2',
|
282
|
+
projectRoot: 'projects/testApp2'
|
283
|
+
}, appTree).toPromise();
|
284
|
+
|
285
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
286
|
+
const tree = await runner.runSchematicAsync('add-layout', {
|
287
|
+
...options,
|
288
|
+
project: 'testApp2'
|
289
|
+
}, appTree).toPromise();
|
290
|
+
|
291
|
+
expect(tree.files)
|
292
|
+
.toContain('/devextreme.json');
|
293
|
+
expect(tree.files)
|
294
|
+
.toContain('/projects/testApp2/src/themes/metadata.base.json');
|
295
|
+
});
|
296
|
+
|
297
|
+
it('should merge build commands in devextreme.json file', async () => {
|
298
|
+
appTree = await schematicRunner.runSchematicAsync('application', {
|
299
|
+
...appOptions,
|
300
|
+
name: 'testApp2',
|
301
|
+
prefix: 'app2',
|
302
|
+
projectRoot: 'projects/testApp2'
|
303
|
+
}, appTree).toPromise();
|
304
|
+
|
305
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
306
|
+
let tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
307
|
+
tree = await runner.runSchematicAsync('add-layout', {
|
308
|
+
...options,
|
309
|
+
project: 'testApp2'
|
310
|
+
}, appTree).toPromise();
|
311
|
+
|
312
|
+
const appContent = tree.readContent('projects/testApp2/src/app/app.component.ts');
|
313
|
+
expect(appContent).toContain('selector: \'app2-root\',');
|
314
|
+
|
315
|
+
const content = tree.readContent('/devextreme.json');
|
316
|
+
expect(content).toContain('"inputFile": "src/themes/metadata.base.json",');
|
317
|
+
expect(content).toContain('"inputFile": "projects/testApp2/src/themes/metadata.base.json",');
|
318
|
+
});
|
319
|
+
|
320
|
+
it('should add e2e tests only for default project', async () => {
|
321
|
+
appTree = await schematicRunner.runSchematicAsync('application', {
|
322
|
+
...appOptions,
|
323
|
+
name: 'testApp2',
|
324
|
+
projectRoot: 'projects/testApp2'
|
325
|
+
}, appTree).toPromise();
|
326
|
+
|
327
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
328
|
+
let tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
|
329
|
+
tree = await runner.runSchematicAsync('add-layout', {
|
330
|
+
...options,
|
331
|
+
project: 'testApp2'
|
332
|
+
}, appTree).toPromise();
|
333
|
+
|
334
|
+
const testContent = tree.readContent('/e2e/src/app.e2e-spec.ts');
|
335
|
+
expect(testContent).toContain('Welcome to TestApp!');
|
336
|
+
|
337
|
+
const testUtilsContent = tree.readContent('/e2e/src/app.po.ts');
|
338
|
+
expect(testUtilsContent).toMatch(/'app-root .dx-drawer-content .dx-card p:nth-child\(2\)'/);
|
339
|
+
});
|
340
|
+
});
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import { Component } from '@angular/core';
|
2
|
-
|
3
|
-
@Component({
|
4
|
-
templateUrl: 'home.component.html',
|
5
|
-
styleUrls: [ './home.component.scss' ]
|
6
|
-
})
|
7
|
-
|
8
|
-
export class HomeComponent {
|
9
|
-
constructor() {}
|
10
|
-
}
|
1
|
+
import { Component } from '@angular/core';
|
2
|
+
|
3
|
+
@Component({
|
4
|
+
templateUrl: 'home.component.html',
|
5
|
+
styleUrls: [ './home.component.scss' ]
|
6
|
+
})
|
7
|
+
|
8
|
+
export class HomeComponent {
|
9
|
+
constructor() {}
|
10
|
+
}
|
@@ -1,33 +1,33 @@
|
|
1
|
-
import { Component } from '@angular/core';
|
2
|
-
|
3
|
-
@Component({
|
4
|
-
templateUrl: 'profile.component.html',
|
5
|
-
styleUrls: [ './profile.component.scss' ]
|
6
|
-
})
|
7
|
-
|
8
|
-
export class ProfileComponent {
|
9
|
-
employee: any;
|
10
|
-
colCountByScreen: object;
|
11
|
-
|
12
|
-
constructor() {
|
13
|
-
this.employee = {
|
14
|
-
ID: 7,
|
15
|
-
FirstName: 'Sandra',
|
16
|
-
LastName: 'Johnson',
|
17
|
-
Prefix: 'Mrs.',
|
18
|
-
Position: 'Controller',
|
19
|
-
Picture: 'images/employees/06.png',
|
20
|
-
BirthDate: new Date('1974/11/15'),
|
21
|
-
HireDate: new Date('2005/05/11'),
|
22
|
-
/* tslint:disable-next-line:max-line-length */
|
23
|
-
Notes: 'Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you`ve not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.',
|
24
|
-
Address: '4600 N Virginia Rd.'
|
25
|
-
};
|
26
|
-
this.colCountByScreen = {
|
27
|
-
xs: 1,
|
28
|
-
sm: 2,
|
29
|
-
md: 3,
|
30
|
-
lg: 4
|
31
|
-
};
|
32
|
-
}
|
33
|
-
}
|
1
|
+
import { Component } from '@angular/core';
|
2
|
+
|
3
|
+
@Component({
|
4
|
+
templateUrl: 'profile.component.html',
|
5
|
+
styleUrls: [ './profile.component.scss' ]
|
6
|
+
})
|
7
|
+
|
8
|
+
export class ProfileComponent {
|
9
|
+
employee: any;
|
10
|
+
colCountByScreen: object;
|
11
|
+
|
12
|
+
constructor() {
|
13
|
+
this.employee = {
|
14
|
+
ID: 7,
|
15
|
+
FirstName: 'Sandra',
|
16
|
+
LastName: 'Johnson',
|
17
|
+
Prefix: 'Mrs.',
|
18
|
+
Position: 'Controller',
|
19
|
+
Picture: 'images/employees/06.png',
|
20
|
+
BirthDate: new Date('1974/11/15'),
|
21
|
+
HireDate: new Date('2005/05/11'),
|
22
|
+
/* tslint:disable-next-line:max-line-length */
|
23
|
+
Notes: 'Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you`ve not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.',
|
24
|
+
Address: '4600 N Virginia Rd.'
|
25
|
+
};
|
26
|
+
this.colCountByScreen = {
|
27
|
+
xs: 1,
|
28
|
+
sm: 2,
|
29
|
+
md: 3,
|
30
|
+
lg: 4
|
31
|
+
};
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,141 @@
|
|
1
|
+
import {
|
2
|
+
Rule,
|
3
|
+
Tree,
|
4
|
+
chain,
|
5
|
+
apply,
|
6
|
+
template,
|
7
|
+
move,
|
8
|
+
url,
|
9
|
+
mergeWith
|
10
|
+
} from '@angular-devkit/schematics';
|
11
|
+
|
12
|
+
import {
|
13
|
+
addDeclarationToModule,
|
14
|
+
addImportToModule
|
15
|
+
} from '@schematics/angular/utility/ast-utils';
|
16
|
+
|
17
|
+
import { addViewToRouting } from '../add-view';
|
18
|
+
|
19
|
+
import {
|
20
|
+
getApplicationPath,
|
21
|
+
getProjectName
|
22
|
+
} from '../utility/project';
|
23
|
+
|
24
|
+
import { humanize } from '../utility/string';
|
25
|
+
|
26
|
+
import {
|
27
|
+
applyChanges,
|
28
|
+
insertItemToArray
|
29
|
+
} from '../utility/change';
|
30
|
+
|
31
|
+
import { getSourceFile } from '../utility/source';
|
32
|
+
|
33
|
+
const sampleViewOptions = [
|
34
|
+
{
|
35
|
+
name: 'home',
|
36
|
+
componentName: 'HomeComponent',
|
37
|
+
relativePath: './pages/home/home.component'
|
38
|
+
}, {
|
39
|
+
name: 'profile',
|
40
|
+
componentName: 'ProfileComponent',
|
41
|
+
relativePath: './pages/profile/profile.component'
|
42
|
+
}, {
|
43
|
+
name: 'tasks',
|
44
|
+
componentName: 'TasksComponent',
|
45
|
+
relativePath: './pages/tasks/tasks.component'
|
46
|
+
}];
|
47
|
+
|
48
|
+
const devextremeOptions = [
|
49
|
+
{
|
50
|
+
componentName: 'DxDataGridModule',
|
51
|
+
relativePath: 'devextreme-angular'
|
52
|
+
}, {
|
53
|
+
componentName: 'DxFormModule',
|
54
|
+
relativePath: 'devextreme-angular'
|
55
|
+
}];
|
56
|
+
|
57
|
+
const navigations = [
|
58
|
+
` {
|
59
|
+
text: 'Home',
|
60
|
+
path: '/home',
|
61
|
+
icon: 'home'
|
62
|
+
}`,
|
63
|
+
` {
|
64
|
+
text: 'Examples',
|
65
|
+
icon: 'folder',
|
66
|
+
items: [
|
67
|
+
{
|
68
|
+
text: 'Profile',
|
69
|
+
path: '/profile'
|
70
|
+
},
|
71
|
+
{
|
72
|
+
text: 'Tasks',
|
73
|
+
path: '/tasks'
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}`
|
77
|
+
];
|
78
|
+
|
79
|
+
function addImportsToRoutingModule(isView: boolean, routingPath: string, options: any) {
|
80
|
+
return (host: Tree) => {
|
81
|
+
const source = getSourceFile(host, routingPath);
|
82
|
+
|
83
|
+
if (!source) {
|
84
|
+
return host;
|
85
|
+
}
|
86
|
+
|
87
|
+
let changes;
|
88
|
+
|
89
|
+
if (isView) {
|
90
|
+
changes = addDeclarationToModule(source, routingPath, options.componentName, options.relativePath);
|
91
|
+
} else {
|
92
|
+
changes = addImportToModule(source, routingPath, options.componentName, options.relativePath);
|
93
|
+
}
|
94
|
+
|
95
|
+
return applyChanges(host, changes, routingPath);
|
96
|
+
};
|
97
|
+
}
|
98
|
+
|
99
|
+
function addDefaultNavigation(rootPath: string) {
|
100
|
+
return (host: Tree) => {
|
101
|
+
const navigationPath = rootPath + 'app-navigation.ts';
|
102
|
+
|
103
|
+
navigations.forEach((navigation) => {
|
104
|
+
const navigationSource = getSourceFile(host, navigationPath)!;
|
105
|
+
insertItemToArray(host, navigationPath, navigationSource, navigation, { location: 'end' });
|
106
|
+
});
|
107
|
+
|
108
|
+
return host;
|
109
|
+
};
|
110
|
+
}
|
111
|
+
|
112
|
+
export default function(options: any): Rule {
|
113
|
+
return (host: Tree) => {
|
114
|
+
const project = getProjectName(host, options.project);
|
115
|
+
const rootPath = getApplicationPath(host, project);
|
116
|
+
const routingPath = rootPath + 'app-routing.module.ts';
|
117
|
+
const rules: any[] = [];
|
118
|
+
|
119
|
+
const templateSource = apply(url('./files'), [
|
120
|
+
template({
|
121
|
+
project: humanize(project)
|
122
|
+
}),
|
123
|
+
move(rootPath)
|
124
|
+
]);
|
125
|
+
|
126
|
+
rules.push(mergeWith(templateSource));
|
127
|
+
|
128
|
+
sampleViewOptions.forEach((viewOptions) => {
|
129
|
+
rules.push(addViewToRouting({ name: viewOptions.name, project, module: 'app-routing' }));
|
130
|
+
rules.push(addImportsToRoutingModule(true, routingPath, viewOptions));
|
131
|
+
});
|
132
|
+
|
133
|
+
devextremeOptions.forEach((moduleOptions) => {
|
134
|
+
rules.push(addImportsToRoutingModule(false, routingPath, moduleOptions));
|
135
|
+
});
|
136
|
+
|
137
|
+
rules.push(addDefaultNavigation(rootPath));
|
138
|
+
|
139
|
+
return chain(rules);
|
140
|
+
};
|
141
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
2
|
+
import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
|
3
|
+
import * as path from 'path';
|
4
|
+
|
5
|
+
const collectionPath = path.join(__dirname, '../collection.json');
|
6
|
+
|
7
|
+
describe('sample views', () => {
|
8
|
+
const appOptions: any = {
|
9
|
+
name: 'testApp',
|
10
|
+
projectRoot: '',
|
11
|
+
inlineStyle: false,
|
12
|
+
inlineTemplate: false,
|
13
|
+
routing: true,
|
14
|
+
style: 'css',
|
15
|
+
skipTests: false,
|
16
|
+
skipPackageJson: false
|
17
|
+
};
|
18
|
+
|
19
|
+
const workspaceOptions: WorkspaceOptions = {
|
20
|
+
name: 'workspace',
|
21
|
+
version: '6.0.0'
|
22
|
+
};
|
23
|
+
|
24
|
+
const sampleViewsOptions: any = {
|
25
|
+
project: 'testApp'
|
26
|
+
};
|
27
|
+
|
28
|
+
const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
|
29
|
+
const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
|
30
|
+
let appTree: UnitTestTree;
|
31
|
+
|
32
|
+
beforeEach(async () => {
|
33
|
+
appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
|
34
|
+
appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
|
35
|
+
});
|
36
|
+
|
37
|
+
it('should add sample views', async () => {
|
38
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
39
|
+
let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
|
40
|
+
tree = await runner.runSchematicAsync('add-sample-views', sampleViewsOptions, tree).toPromise();
|
41
|
+
|
42
|
+
const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
|
43
|
+
|
44
|
+
expect(moduleContent).toMatch(/component: HomeComponent/);
|
45
|
+
expect(moduleContent).toMatch(/path: 'home'/);
|
46
|
+
|
47
|
+
expect(moduleContent).toMatch(/import { HomeComponent } from /);
|
48
|
+
expect(moduleContent).toMatch(/declarations: \[HomeComponent/);
|
49
|
+
|
50
|
+
const navigationContent = tree.readContent('/src/app/app-navigation.ts');
|
51
|
+
expect(navigationContent).toMatch(/text: 'Home'/);
|
52
|
+
expect(navigationContent).toContain(`export const navigation = [
|
53
|
+
{
|
54
|
+
text: 'Home',
|
55
|
+
path: '/home',
|
56
|
+
icon: 'home'
|
57
|
+
},
|
58
|
+
{
|
59
|
+
text: 'Examples',
|
60
|
+
icon: 'folder',
|
61
|
+
items: [
|
62
|
+
{
|
63
|
+
text: 'Profile',
|
64
|
+
path: '/profile'
|
65
|
+
},
|
66
|
+
{
|
67
|
+
text: 'Tasks',
|
68
|
+
path: '/tasks'
|
69
|
+
}
|
70
|
+
]
|
71
|
+
}
|
72
|
+
];`);
|
73
|
+
});
|
74
|
+
});
|