You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by ne...@apache.org on 2022/06/28 00:45:49 UTC

[helix] branch master updated: Add Types for Ideal State, fix Payload Format (#2168)

This is an automated email from the ASF dual-hosted git repository.

nealsun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/helix.git


The following commit(s) were added to refs/heads/master by this push:
     new 3b28b4e6d Add Types for Ideal State, fix Payload Format (#2168)
3b28b4e6d is described below

commit 3b28b4e6db980533a1db937fbc740ace28e3b5ec
Author: Micah Stubbs <mi...@gmail.com>
AuthorDate: Mon Jun 27 17:45:44 2022 -0700

    Add Types for Ideal State, fix Payload Format (#2168)
    
    Add types for IdealState in helix-front. Fix an associated JSON serialization bug.
---
 helix-front/.prettierignore                        |  1 +
 helix-front/angular.json                           |  5 +---
 helix-front/client/app/core/helix.service.ts       |  2 +-
 .../client/app/resource/shared/resource.service.ts |  8 ++----
 .../shared/node-viewer/node-viewer.component.html  | 12 ++++++--
 .../shared/node-viewer/node-viewer.component.ts    | 33 ++++++++++++++++++++--
 helix-front/client/app/shared/shared.module.ts     |  2 +-
 helix-front/server/controllers/helix.ts            |  2 ++
 8 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/helix-front/.prettierignore b/helix-front/.prettierignore
index ca49e9bca..712db9e7f 100644
--- a/helix-front/.prettierignore
+++ b/helix-front/.prettierignore
@@ -4,3 +4,4 @@ node
 node_modules
 target
 package.json
+coverage/
diff --git a/helix-front/angular.json b/helix-front/angular.json
index c23dfaf66..c81813ddf 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 1f46d7def..c9e899e89 100644
--- a/helix-front/client/app/core/helix.service.ts
+++ b/helix-front/client/app/core/helix.service.ts
@@ -29,7 +29,7 @@ export class HelixService {
       .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 601a62ff0..5c8385c71 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 { Injectable } from '@angular/core';
 
 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 @@ export class ResourceService extends HelixService {
   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 9e9b95ff0..e37776b4b 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 de98a1c76..de4f807ed 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 { Settings } from '../../core/settings';
 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 @@ export class NodeViewerComponent implements OnInit {
 
     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 @@ export class NodeViewerComponent implements OnInit {
           () => {
             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 9f18ecee1..11bea9b95 100644
--- a/helix-front/client/app/shared/shared.module.ts
+++ b/helix-front/client/app/shared/shared.module.ts
@@ -34,7 +34,7 @@ import { DisabledLabelComponent } from './disabled-label/disabled-label.componen
     FormsModule,
     NgxDatatableModule,
     NgxJsonViewerModule,
-    AceEditorModule
+    AceEditorModule,
   ],
   declarations: [
     InputDialogComponent,
diff --git a/helix-front/server/controllers/helix.ts b/helix-front/server/controllers/helix.ts
index 1203b2727..d5d9dbd44 100644
--- a/helix-front/server/controllers/helix.ts
+++ b/helix-front/server/controllers/helix.ts
@@ -51,6 +51,8 @@ export class HelixCtrl {
       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);
         }