Skip to content

Commit 019dd07

Browse files
committed
feat: 🎸 edit project configuration
✅ Closes: 15
1 parent 7ec472b commit 019dd07

18 files changed

+301
-31
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { JSONSchema7 } from 'json-schema';
2+
3+
export class SchemaDto implements JSONSchema7 {
4+
properties: JSONSchema7['properties'];
5+
title: JSONSchema7['title'];
6+
description: JSONSchema7['title'];
7+
8+
constructor({ title, properties, description }: JSONSchema7) {
9+
this.properties = properties;
10+
this.title = title;
11+
this.description = description;
12+
}
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface ExtractValuePaths {
2+
path: string;
3+
overridePath?: string;
4+
}
5+
export const configurationsPaths: ExtractValuePaths[] = [
6+
{ path: 'definitions.project.properties.prefix', overridePath: 'prefix' },
7+
{ path: 'definitions.project.properties.root', overridePath: 'root' },
8+
{
9+
path: 'definitions.project.properties.sourceRoot',
10+
overridePath: 'sourceRoot',
11+
},
12+
];

‎apps/cli-daemon/src/app/workspace/workspace.controller.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Patch,
1010
Post,
1111
} from '@nestjs/common';
12+
import { JSONSchema7 } from 'json-schema';
1213

1314
import { ExecResult } from '../generators/dto';
1415
import { GeneratorsService } from '../generators/generators.service';
@@ -60,6 +61,11 @@ export class WorkspaceController {
6061
return this.workspaceService.readWorkspaceProjectNames();
6162
}
6263

64+
@Get('workspace-configuration')
65+
async getWorkspaceConfiguration(): Promise<JSONSchema7> {
66+
return this.workspaceService.getWorkspaceConfiguration();
67+
}
68+
6369
@Get('project/:projectName')
6470
async getProject(
6571
@Param('projectName') projectName: string

‎apps/cli-daemon/src/app/workspace/workspace.service.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ import {
1515
Logger,
1616
NotFoundException,
1717
} from '@nestjs/common';
18+
import { JSONSchema7 } from 'json-schema';
19+
import { Draft07 } from 'json-schema-library';
20+
import * as angularSchema from 'node_modules/@angular/cli/lib/config/schema.json';
1821

1922
import { SessionService } from '../session/session.service';
2023

2124
import { ProjectDto, UpdateProjectDto } from './dto';
25+
import { SchemaDto } from './dto/schema.dto';
2226
import {
2327
ANGULAR_WORKSPACE_NOT_FOUND_EXCEPTION,
2428
BAD_PATH_EXCEPTION,
@@ -157,4 +161,18 @@ export class WorkspaceService {
157161
return new InternalServerErrorException(err);
158162
}
159163
}
164+
165+
getWorkspaceConfiguration(): Partial<JSONSchema7> {
166+
const jsonSchema = new Draft07(angularSchema);
167+
168+
const { root, prefix, sourceRoot } =
169+
jsonSchema.getSchema()['definitions']['project']['properties'];
170+
const properties = new Draft07({ root, prefix, sourceRoot }).getSchema();
171+
172+
return new SchemaDto({
173+
title: 'Angular CLI Workspace Configuration',
174+
description: 'Browser target options',
175+
properties: properties,
176+
});
177+
}
160178
}

‎apps/cli-daemon/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"noImplicitOverride": true,
1919
"noPropertyAccessFromIndexSignature": true,
2020
"noImplicitReturns": true,
21-
"noFallthroughCasesInSwitch": true
21+
"noFallthroughCasesInSwitch": true,
22+
"resolveJsonModule": true
2223
}
2324
}
Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { CommonModule } from '@angular/common';
22
import { ChangeDetectionStrategy, Component } from '@angular/core';
33

4-
import { WorkspaceSettingsService } from './workspace-settings.service';
5-
64
@Component({
75
selector: 'cli-workspace-settings',
86
standalone: true,
@@ -11,10 +9,4 @@ import { WorkspaceSettingsService } from './workspace-settings.service';
119
styleUrls: ['./workspace-settings.component.scss'],
1210
changeDetection: ChangeDetectionStrategy.OnPush,
1311
})
14-
export class WorkspaceSettingsComponent {
15-
angularJson$ = this.workspaceSettingsService.readWorkspaceProjectNames();
16-
17-
constructor(
18-
private readonly workspaceSettingsService: WorkspaceSettingsService
19-
) {}
20-
}
12+
export class WorkspaceSettingsComponent {}

‎apps/cli-gui/src/app/workspace-settings/workspace-settings.service.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
<p>configuration works!</p>
1+
<h1>Edit project configuration</h1>
2+
3+
<ng-container *ngIf="formly$ | async as formly">
4+
<form [formGroup]="form" (ngSubmit)="onSubmit()">
5+
<formly-form
6+
[model]="formly.formData"
7+
[fields]="formly.formFields"
8+
[form]="form"
9+
></formly-form>
10+
<button mat-button type="submit">Submit</button>
11+
</form>
12+
</ng-container>
Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,58 @@
11
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
3+
4+
import {
5+
createWorkspaceSettingsServiceMockk,
6+
workspaceConfigurationMock,
7+
} from '../../testing';
8+
import { WorkspaceSettingsService } from '../services';
29

310
import { ConfigurationComponent } from './configuration.component';
411

512
describe('ConfigurationComponent', () => {
613
let component: ConfigurationComponent;
714
let fixture: ComponentFixture<ConfigurationComponent>;
15+
let service: WorkspaceSettingsService;
816

917
beforeEach(async () => {
1018
await TestBed.configureTestingModule({
11-
imports: [ConfigurationComponent],
19+
imports: [ConfigurationComponent, NoopAnimationsModule],
20+
providers: [
21+
{
22+
provide: WorkspaceSettingsService,
23+
useValue: createWorkspaceSettingsServiceMockk(),
24+
},
25+
],
1226
}).compileComponents();
1327

1428
fixture = TestBed.createComponent(ConfigurationComponent);
1529
component = fixture.componentInstance;
1630
fixture.detectChanges();
31+
service = TestBed.inject(WorkspaceSettingsService);
1732
});
1833

1934
it('should create', () => {
2035
expect(component).toBeTruthy();
2136
});
37+
38+
it('should formly create descriptions for fields', () => {
39+
const { root, sourceRoot, prefix } = workspaceConfigurationMock.properties;
40+
const innerHTML = fixture.debugElement.nativeElement.innerHTML;
41+
expect(innerHTML).toContain(root.description);
42+
expect(innerHTML).toContain(sourceRoot.description);
43+
expect(innerHTML).toContain(prefix.description);
44+
});
45+
46+
it('should submit form', () => {
47+
const updateWorkspaceProjectConfigurationSpy = jest.spyOn(
48+
service,
49+
'updateWorkspaceProjectConfiguration'
50+
);
51+
fixture.debugElement.nativeElement.querySelector('button').click();
52+
expect(updateWorkspaceProjectConfigurationSpy).toBeCalledWith('name', {
53+
prefix: 'prefix',
54+
root: 'root',
55+
sourceRoot: 'sourceRoot',
56+
});
57+
});
2258
});
Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,75 @@
1-
import { CommonModule } from '@angular/common';
2-
import { Component } from '@angular/core';
1+
import { AsyncPipe, NgIf } from '@angular/common';
2+
import { ChangeDetectionStrategy, Component } from '@angular/core';
3+
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
4+
import { Project } from '@angular-cli-gui/shared/data';
5+
import { FormlyFieldConfig, FormlyModule } from '@ngx-formly/core';
6+
import { FormlyJsonschema } from '@ngx-formly/core/json-schema';
7+
import { FormlyMaterialModule } from '@ngx-formly/material';
8+
import { combineLatest, map, shareReplay, switchMap } from 'rxjs';
9+
10+
import { WorkspaceSettingsService } from '../services';
311

412
@Component({
513
selector: 'cli-configuration',
614
standalone: true,
7-
imports: [CommonModule],
15+
imports: [
16+
NgIf,
17+
AsyncPipe,
18+
FormlyModule,
19+
FormlyMaterialModule,
20+
ReactiveFormsModule,
21+
],
822
templateUrl: './configuration.component.html',
923
styleUrls: ['./configuration.component.css'],
24+
changeDetection: ChangeDetectionStrategy.OnPush,
1025
})
11-
export class ConfigurationComponent {}
26+
export class ConfigurationComponent {
27+
private readonly projectConfiguration$ = this.workspaceSettingsService
28+
.readWorkspaceProjectConfiguration()
29+
.pipe(
30+
map(
31+
(configuration) =>
32+
this.schema.toFieldConfig(configuration)
33+
.fieldGroup as FormlyFieldConfig[]
34+
)
35+
);
36+
37+
private readonly projectName$ = this.workspaceSettingsService
38+
.readWorkspaceProjectNames()
39+
.pipe(
40+
map((names) => names[0]),
41+
shareReplay({ bufferSize: 1, refCount: true })
42+
);
43+
44+
private readonly workspaceProject$ = this.projectName$.pipe(
45+
switchMap((currentProjectName: string) =>
46+
this.workspaceSettingsService.readWorkspaceProject(currentProjectName)
47+
)
48+
);
49+
50+
readonly formly$ = combineLatest([
51+
this.projectConfiguration$,
52+
this.workspaceProject$,
53+
]).pipe(map(([formFields, formData]) => ({ formFields, formData })));
54+
55+
form = this.fb.group({});
56+
57+
constructor(
58+
private workspaceSettingsService: WorkspaceSettingsService,
59+
private fb: FormBuilder,
60+
private schema: FormlyJsonschema
61+
) {}
62+
63+
onSubmit(): void {
64+
this.projectName$
65+
.pipe(
66+
switchMap((projectName) => {
67+
return this.workspaceSettingsService.updateWorkspaceProjectConfiguration(
68+
projectName,
69+
this.form.value as Project
70+
);
71+
})
72+
)
73+
.subscribe();
74+
}
75+
}

0 commit comments

Comments
 (0)