Add Types for Ideal State, fix Payload Format (#2168)
Add types for IdealState in helix-front. Fix an associated JSON serialization bug.
diff --git a/helix-front/.prettierignore b/helix-front/.prettierignore
index ca49e9b..712db9e 100644
--- a/helix-front/.prettierignore
+++ b/helix-front/.prettierignore
@@ -4,3 +4,4 @@
node_modules
target
package.json
+coverage/
diff --git a/helix-front/angular.json b/helix-front/angular.json
index c23dfaf..c81813d 100644
--- a/helix-front/angular.json
+++ b/helix-front/angular.json
@@ -106,10 +106,7 @@
"node_modules/ace-builds/src-min/mode-json.js"
],
"styles": ["client/styles.scss", "client/theme.scss"],
- "assets": [
- "client/assets",
- "client/favicon.ico"
- ]
+ "assets": ["client/assets", "client/favicon.ico"]
}
},
"lint": {
diff --git a/helix-front/client/app/core/helix.service.ts b/helix-front/client/app/core/helix.service.ts
index 1f46d7d..c9e899e 100644
--- a/helix-front/client/app/core/helix.service.ts
+++ b/helix-front/client/app/core/helix.service.ts
@@ -29,7 +29,7 @@
.pipe(catchError(this.errorHandler));
}
- protected post(path: string, data: string): Observable<any> {
+ protected post(path: string, data: any): Observable<any> {
return this.http
.post(`${Settings.helixAPI}${this.getHelixKey()}${path}`, data, {
headers: this.getHeaders(),
diff --git a/helix-front/client/app/resource/shared/resource.service.ts b/helix-front/client/app/resource/shared/resource.service.ts
index 601a62f..5c8385c 100644
--- a/helix-front/client/app/resource/shared/resource.service.ts
+++ b/helix-front/client/app/resource/shared/resource.service.ts
@@ -3,10 +3,9 @@
import * as _ from 'lodash';
+import { IdealState } from '../../shared/node-viewer/node-viewer.component';
import { HelixService } from '../../core/helix.service';
import { Resource } from './resource.model';
-import { Cluster } from '../../cluster/shared/cluster.model';
-import { Node } from '../../shared/models/node.model';
@Injectable()
export class ResourceService extends HelixService {
@@ -114,12 +113,11 @@
public setIdealState(
clusterName: string,
resourceName: string,
- idealState: Node
+ idealState: IdealState
) {
return this.post(
`/clusters/${clusterName}/resources/${resourceName}/idealState?command=update`,
- JSON.stringify(idealState)
+ idealState
);
}
}
-
diff --git a/helix-front/client/app/shared/node-viewer/node-viewer.component.html b/helix-front/client/app/shared/node-viewer/node-viewer.component.html
index 9e9b95f..e37776b 100644
--- a/helix-front/client/app/shared/node-viewer/node-viewer.component.html
+++ b/helix-front/client/app/shared/node-viewer/node-viewer.component.html
@@ -34,9 +34,15 @@
</mat-button-toggle-group>
<section class="viewer" [ngSwitch]="group.value" fxFlexFill>
<ngx-json-viewer *ngSwitchCase="'tree'" [json]="obj"></ngx-json-viewer>
- <ace-editor *ngSwitchCase="'json'" [(text)]="objString" mode="json" theme="chrome"
- [options]="{useWorker: false}" style="min-height:300px;"
- #editor>
+ <ace-editor
+ *ngSwitchCase="'json'"
+ [(text)]="objString"
+ mode="json"
+ theme="chrome"
+ [options]="{ useWorker: false }"
+ style="min-height: 300px"
+ #editor
+ >
</ace-editor>
<section *ngSwitchCase="'table'">
<!-- TODO vxu: use mat-simple-table when it's available -->
diff --git a/helix-front/client/app/shared/node-viewer/node-viewer.component.ts b/helix-front/client/app/shared/node-viewer/node-viewer.component.ts
index de98a1c..de4f807 100644
--- a/helix-front/client/app/shared/node-viewer/node-viewer.component.ts
+++ b/helix-front/client/app/shared/node-viewer/node-viewer.component.ts
@@ -25,6 +25,13 @@
import { InputDialogComponent } from '../dialog/input-dialog/input-dialog.component';
import { ConfirmDialogComponent } from '../dialog/confirm-dialog/confirm-dialog.component';
+export type IdealState = {
+ id: string;
+ simpleFields?: { [key: string]: any };
+ listFields?: { [key: string]: any };
+ mapFields?: { [key: string]: any };
+};
+
config.set(
'basePath',
'https://cdn.jsdelivr.net/npm/ace-builds@1.6.0/src-noconflict/'
@@ -374,10 +381,29 @@
const path = this?.route?.snapshot?.data?.path;
if (path && path === 'idealState') {
+ const idealState: IdealState = {
+ id: this.resourceName,
+ };
+
+ // format the payload the way that helix-rest expects
+ // before: { simpleFields: [{ name: 'NUM_PARTITIONS', value: 2 }] };
+ // after: { simpleFields: { NUM_PARTITIONS: 2 } };
+ function appendIdealStateProperty(property: keyof Node) {
+ if (Array.isArray(newNode[property]) && newNode[property].length > 0) {
+ idealState[property] = {} as any;
+ (newNode[property] as any[]).forEach((field) => {
+ idealState[property][field.name] = field.value;
+ });
+ }
+ }
+ Object.keys(newNode).forEach((key) =>
+ appendIdealStateProperty(key as keyof Node)
+ );
+
const observer = this.resourceService.setIdealState(
this.clusterName,
this.resourceName,
- newNode
+ idealState
);
if (observer) {
@@ -386,7 +412,10 @@
() => {
this.helper.showSnackBar('Ideal State updated!');
},
- (error) => this.helper.showError(error),
+ (error) => {
+ this.helper.showError(error);
+ this.isLoading = false;
+ },
() => (this.isLoading = false)
);
}
diff --git a/helix-front/client/app/shared/shared.module.ts b/helix-front/client/app/shared/shared.module.ts
index 9f18ece..11bea9b 100644
--- a/helix-front/client/app/shared/shared.module.ts
+++ b/helix-front/client/app/shared/shared.module.ts
@@ -34,7 +34,7 @@
FormsModule,
NgxDatatableModule,
NgxJsonViewerModule,
- AceEditorModule
+ AceEditorModule,
],
declarations: [
InputDialogComponent,
diff --git a/helix-front/server/controllers/helix.ts b/helix-front/server/controllers/helix.ts
index 1203b27..d5d9dbd 100644
--- a/helix-front/server/controllers/helix.ts
+++ b/helix-front/server/controllers/helix.ts
@@ -51,6 +51,8 @@
request[method](options, (error, response, body) => {
if (error) {
res.status(500).send(error);
+ } else if (body?.error) {
+ res.status(500).send(body?.error);
} else {
res.status(response.statusCode).send(body);
}