Skip to content

Commit 1766fc9

Browse files
kbrownomniKatherine BrownKatherine Brown
authored
Arc admin attribute form (#227)
* updated arc admin attributes html and added a reactive form for the data * binding fixes * updated tests * moved form def to constructor, populated form with config, on cancel form re-populates with config * replaced the frozen default config with a hardcoded mock in showcase --------- Co-authored-by: Katherine Brown <[email protected]> Co-authored-by: Katherine Brown <[email protected]>
1 parent d945ed2 commit 1766fc9

File tree

10 files changed

+425
-272
lines changed

10 files changed

+425
-272
lines changed

plugins/arcgis/web-app/projects/main/src/lib/arc-admin/arc-admin.component.html

Lines changed: 184 additions & 193 deletions
Large diffs are not rendered by default.

plugins/arcgis/web-app/projects/main/src/lib/arc-admin/arc-admin.component.scss

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
section {
1111
>* {
12-
margin-inline-start: 1em;
12+
margin-inline-start: 0em;
1313
}
1414

1515
header {
@@ -50,20 +50,6 @@ section {
5050
}
5151
}
5252

53-
.attributes-table {
54-
tr {
55-
th {
56-
font-weight: normal;
57-
}
58-
59-
td {
60-
padding-left: 20px;
61-
opacity: 0.5;
62-
font-size: 0.9em;
63-
}
64-
}
65-
}
66-
6753
.fieldOverrides {
6854
margin-top: 20px;
6955
}
@@ -193,3 +179,18 @@ section {
193179
line-height: inherit;
194180
width: inherit;
195181
}
182+
183+
184+
.mat-form-field {
185+
width: 100%;
186+
margin-bottom: 32px;
187+
}
188+
189+
mat-card {
190+
margin-bottom: 8px;
191+
}
192+
193+
.hint {
194+
font-size: 75%;
195+
padding: 0 1em;
196+
}

plugins/arcgis/web-app/projects/main/src/lib/arc-admin/arc-admin.component.ts

Lines changed: 105 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { MatDialog } from '@angular/material/dialog'
33
import { AttributeConfig, AttributeConcatenationConfig, AttributeDefaultConfig, AttributeValueConfig } from '../ArcGISConfig';
44
import { ArcGISPluginConfig, defaultArcGISPluginConfig } from '../ArcGISPluginConfig'
55
import { ArcService, Form, MageEvent } from '../arc.service'
6-
import { Subject } from 'rxjs';
6+
import { Subject, first } from 'rxjs';
7+
import { FormGroup, FormBuilder } from '@angular/forms';
78

89
@Component({
910
selector: 'arc-admin',
@@ -52,10 +53,27 @@ export class ArcAdminComponent implements OnInit {
5253
@ViewChild('editAttributeConfigDialog', { static: true })
5354
private editAttributeConfigTemplate: TemplateRef<unknown>
5455

55-
constructor(private arcService: ArcService, private dialog: MatDialog) {
56+
attributesForm: FormGroup;
57+
58+
constructor(private arcService: ArcService, private dialog: MatDialog, private fb: FormBuilder) {
5659
this.config = defaultArcGISPluginConfig;
5760
this.editConfig = defaultArcGISPluginConfig;
5861
this.editFieldMappings = false;
62+
this.attributesForm = this.fb.group({
63+
observationIdField: [''],
64+
idSeparator: [''],
65+
eventIdField: [''],
66+
lastEditedDateField: [''],
67+
eventNameField: [''],
68+
userIdField: [''],
69+
usernameField: [''],
70+
userDisplayNameField: [''],
71+
deviceIdField: [''],
72+
createdAtField: [''],
73+
lastModifiedField: [''],
74+
geometryType: ['']
75+
});
76+
5977
arcService.fetchArcConfig().subscribe(x => {
6078
this.config = x;
6179
if (!this.config.baseUrl) {
@@ -71,12 +89,95 @@ export class ArcAdminComponent implements OnInit {
7189
}
7290

7391
ngOnInit(): void {
92+
this.arcService.fetchArcConfig().pipe(first()).subscribe({
93+
next: config => {
94+
if (config) {
95+
// Populate form with values from config
96+
this.attributesForm.patchValue({
97+
observationIdField: config.observationIdField || '',
98+
idSeparator: config.idSeparator || '',
99+
eventIdField: config.eventIdField || '',
100+
lastEditedDateField: config.lastEditedDateField || '',
101+
eventNameField: config.eventNameField || '',
102+
userIdField: config.userIdField || '',
103+
usernameField: config.usernameField || '',
104+
userDisplayNameField: config.userDisplayNameField || '',
105+
deviceIdField: config.deviceIdField || '',
106+
createdAtField: config.createdAtField || '',
107+
lastModifiedField: config.lastModifiedField || '',
108+
geometryType: config.geometryType || ''
109+
});
110+
console.log('Form initialized with server config:', config);
111+
}
112+
},
113+
error: error => {
114+
console.error('Failed to fetch config:', error);
115+
}
116+
});
117+
}
118+
119+
//Save attributes form. If left blank, assign default value
120+
onSubmit(): void {
121+
console.log('submitting form...');
122+
123+
if (this.attributesForm.valid) {
124+
const formValue = this.attributesForm.value;
125+
this.editConfig = {
126+
...this.editConfig,
127+
observationIdField: formValue.observationIdField || this.editConfig.observationIdField,
128+
idSeparator: formValue.idSeparator || this.editConfig.idSeparator,
129+
eventIdField: formValue.eventIdField || this.editConfig.eventIdField,
130+
lastEditedDateField: formValue.lastEditedDateField || this.editConfig.lastEditedDateField,
131+
eventNameField: formValue.eventNameField || this.editConfig.eventNameField,
132+
userIdField: formValue.userIdField || this.editConfig.userIdField,
133+
usernameField: formValue.usernameField || this.editConfig.usernameField,
134+
userDisplayNameField: formValue.userDisplayNameField || this.editConfig.userDisplayNameField,
135+
deviceIdField: formValue.deviceIdField || this.editConfig.deviceIdField,
136+
createdAtField: formValue.createdAtField || this.editConfig.createdAtField,
137+
lastModifiedField: formValue.lastModifiedField || this.editConfig.lastModifiedField,
138+
geometryType: formValue.geometryType || this.editConfig.geometryType
139+
};
140+
141+
console.log('Form Submitted:', this.editConfig);
142+
console.log('formValue: ', formValue);
143+
144+
this.editConfig = this.copyConfig();
145+
}
146+
else{
147+
console.log('Form is invalid, please correct the errors.')
148+
}
149+
}
150+
151+
onCancel(): void {
152+
console.log('Cancel selected');
153+
this.arcService.fetchArcConfig().pipe(first()).subscribe({
154+
next: config => {
155+
if (config) {
156+
this.attributesForm.patchValue({
157+
observationIdField: config.observationIdField || '',
158+
idSeparator: config.idSeparator || '',
159+
eventIdField: config.eventIdField || '',
160+
lastEditedDateField: config.lastEditedDateField || '',
161+
eventNameField: config.eventNameField || '',
162+
userIdField: config.userIdField || '',
163+
usernameField: config.usernameField || '',
164+
userDisplayNameField: config.userDisplayNameField || '',
165+
deviceIdField: config.deviceIdField || '',
166+
createdAtField: config.createdAtField || '',
167+
lastModifiedField: config.lastModifiedField || '',
168+
geometryType: config.geometryType || ''
169+
});
170+
console.log('Form reloaded with server config:', config);
171+
}
172+
},
173+
error: error => {
174+
console.error('Failed to reload config from server:', error);
175+
}
176+
});
74177
}
75-
76178
handleEventResults(x: MageEvent[]) {
77179
this.events = x
78180
}
79-
80181
onDeleteLayer(layerUrl: string) {
81182
let index = 0;
82183
for (const featureServiceConfig of this.config.featureServices) {
@@ -96,11 +197,6 @@ export class ArcAdminComponent implements OnInit {
96197
this.dialog.open<unknown, unknown, string>(this.editProcessingTemplate)
97198
}
98199

99-
onEditAttributes() {
100-
this.editConfig = this.copyConfig()
101-
this.dialog.open<unknown, unknown, string>(this.editAttributesTemplate)
102-
}
103-
104200
setField(field: string, value: any) {
105201
if (value != undefined && value.length == 0) {
106202
value = undefined

plugins/arcgis/web-app/projects/main/src/lib/arc-event/arc-event.component.html

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
<div class="arc-event">
2+
<mat-card appearance="outlined">
3+
<mat-card-header>
4+
<mat-card-title>
5+
Events
6+
</mat-card-title>
7+
<mat-card-subtitle>Change the ArcGIS layers each MAGE event sends its observations to.</mat-card-subtitle>
8+
</mat-card-header>
9+
<mat-card-content>
210
<section class="arc-event-sync">
3-
<header>
4-
<h2>Events</h2>
5-
<p class="subheading">Change the ArcGIS layers each MAGE event sends its observations to.</p>
6-
</header>
711
<div class="arcEvents" *ngIf="!model.events.length">
812
<div class="arcEvent">
913
There are no events synchronizing to ArcGIS layers.
@@ -32,7 +36,9 @@ <h2>Events</h2>
3236
</ng-container>
3337
</div>
3438
</section>
35-
</div>
39+
</mat-card-content>
40+
</mat-card>
41+
3642
<ng-template #editEventDialog let-data>
3743
<h2 matDialogTitle>ArcGIS layers that MAGE event named {{currentEditingEvent.name}} is synchronizing</h2>
3844
<mat-dialog-content>
@@ -48,4 +54,5 @@ <h2 matDialogTitle>ArcGIS layers that MAGE event named {{currentEditingEvent.nam
4854
<button mat-flat-button color="primary" matDialogClose
4955
(click)="saveChanges()">SAVE</button>
5056
</mat-dialog-actions>
51-
</ng-template>
57+
</ng-template>
58+
</div>

plugins/arcgis/web-app/projects/main/src/lib/arc-layer/arc-layer-delete-dialog.component.spec.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
1-
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2-
import { HttpClientTestingModule } from '@angular/common/http/testing';
3-
import { MatDialogRef } from '@angular/material/dialog';
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
3+
import { HttpClientModule } from '@angular/common/http';
4+
import { MatDialogModule } from '@angular/material/dialog';
45
import { ArcLayerDeleteDialogComponent } from './arc-layer-delete-dialog.component';
6+
import { ArcService } from '../arc.service'
57

68
describe('Arc Layer Delete Dialog', () => {
79
let component: ArcLayerDeleteDialogComponent;
810
let fixture: ComponentFixture<ArcLayerDeleteDialogComponent>;
911

10-
beforeEach(waitForAsync(() => {
11-
TestBed.configureTestingModule({
12+
beforeEach(async () => {
13+
await TestBed.configureTestingModule({
14+
imports: [HttpClientModule, MatDialogModule],
1215
declarations: [ArcLayerDeleteDialogComponent],
13-
imports: [HttpClientTestingModule],
14-
providers: [{
15-
provide: MatDialogRef,
16-
useValue: {}
17-
},]
16+
providers: [
17+
{
18+
provide: MatDialogRef,
19+
useValue: {
20+
close: jasmine.createSpy('close')
21+
}
22+
},
23+
{
24+
provide: MAT_DIALOG_DATA,
25+
useValue: {}
26+
},
27+
ArcService
28+
]
1829
}).compileComponents();
19-
}));
30+
});
2031

2132
beforeEach(() => {
2233
fixture = TestBed.createComponent(ArcLayerDeleteDialogComponent);
2334
component = fixture.componentInstance;
35+
fixture.detectChanges();
2436
});
2537

26-
2738
it('should create', () => {
2839
expect(component).toBeTruthy();
2940
});

plugins/arcgis/web-app/projects/main/src/lib/arc-layer/arc-layer-dialog.component.spec.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
1-
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2-
import { HttpClientTestingModule } from '@angular/common/http/testing';
3-
import { MatDialogRef } from '@angular/material/dialog';
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
3+
import { HttpClientModule } from '@angular/common/http';
4+
import { MatDialogModule } from '@angular/material/dialog';
45
import { ArcLayerDialogComponent } from './arc-layer-dialog.component';
6+
import { ArcService } from '../arc.service';
57

68
describe('Arc Layer Dialog', () => {
79
let component: ArcLayerDialogComponent;
810
let fixture: ComponentFixture<ArcLayerDialogComponent>;
911

10-
beforeEach(waitForAsync(() => {
11-
TestBed.configureTestingModule({
12+
beforeEach(async () => {
13+
await TestBed.configureTestingModule({
14+
imports: [HttpClientModule, MatDialogModule],
1215
declarations: [ArcLayerDialogComponent],
13-
imports: [HttpClientTestingModule],
14-
providers: [{
15-
provide: MatDialogRef,
16-
useValue: {}
17-
},]
16+
providers: [
17+
{
18+
provide: MatDialogRef,
19+
useValue: {
20+
close: jasmine.createSpy('close')
21+
}
22+
},
23+
{
24+
provide: MAT_DIALOG_DATA,
25+
useValue: {}
26+
},
27+
ArcService
28+
]
1829
}).compileComponents();
19-
}));
30+
});
2031

2132
beforeEach(() => {
2233
fixture = TestBed.createComponent(ArcLayerDialogComponent);
2334
component = fixture.componentInstance;
35+
fixture.detectChanges();
2436
});
2537

26-
2738
it('should create', () => {
2839
expect(component).toBeTruthy();
2940
});

plugins/arcgis/web-app/projects/main/src/lib/arc-layer/arc-layer.component.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<div class="arc-layer">
2+
<mat-card appearance="outlined">
23
<section class="arc-service">
34
<header>
45
<h2>Feature Layers</h2>
@@ -34,4 +35,5 @@ <h2>Feature Layers</h2>
3435
</div>
3536
</div>
3637
</section>
38+
</mat-card>
3739
</div>

plugins/arcgis/web-app/projects/main/src/lib/arc-layer/arc-layer.component.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,8 @@ section {
8383
height: inherit;
8484
line-height: inherit;
8585
width: inherit;
86-
}
86+
}
87+
88+
mat-card {
89+
margin-bottom: 16px;
90+
}

0 commit comments

Comments
 (0)