]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: support custom executing template in table cells
authorKiefer Chang <kiefer.chang@suse.com>
Wed, 28 Oct 2020 07:18:26 +0000 (15:18 +0800)
committerKiefer Chang <kiefer.chang@suse.com>
Mon, 16 Nov 2020 08:02:22 +0000 (16:02 +0800)
Now we can modify the style of a table that has an executing state
by providing a custom config when declaring columns: e.g.,

```
    this.columns = [
      {
        prop: 'id',
        name: $localize`ID`,
        flexGrow: 1,
        cellTransformation: CellTemplate.executing,
        customTemplateConfig: {
          valueClass: 'a',
          executingClass: 'b'
        }
      },
```

Which makes the cell value render with class `a` and the executing state
(e.g. (updating)) render with class `b`.

Signed-off-by: Kiefer Chang <kiefer.chang@suse.com>
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/enum/cell-template.enum.ts

index 85473621490a3129f73ecc30e7b2acec3472f56e..0d5460a989e80482359f32042c91f130aa42a3c2 100644 (file)
 </ng-template>
 
 <ng-template #executingTpl
+             let-column="column"
              let-row="row"
              let-value="value">
   <i [ngClass]="[icons.spinner, icons.spin]"
      *ngIf="row.cdExecuting"></i>
-  {{ value }}
+  <span [ngClass]="column?.customTemplateConfig?.valueClass">
+    {{ value }}
+  </span>
   <span *ngIf="row.cdExecuting"
-        class="text-muted italic">({{ row.cdExecuting }})</span>
+        [ngClass]="column?.customTemplateConfig?.executingClass ? column.customTemplateConfig.executingClass : 'text-muted italic'">({{ row.cdExecuting }})</span>
 </ng-template>
 
 <ng-template #classAddingTpl
index b060d99b0456c4c953e3118722bbb875462e5c44..f3d4f4e36c5c6b03e5807c2209fa82391f62f9eb 100644 (file)
@@ -1,5 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { FormsModule } from '@angular/forms';
+import { By } from '@angular/platform-browser';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { RouterTestingModule } from '@angular/router/testing';
 
@@ -8,6 +9,7 @@ import { NgxDatatableModule } from '@swimlane/ngx-datatable';
 import _ from 'lodash';
 
 import { ComponentsModule } from '~/app/shared/components/components.module';
+import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
 import { CdTableColumnFilter } from '~/app/shared/models/cd-table-column-filter';
 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
@@ -514,6 +516,56 @@ describe('TableComponent', () => {
     });
   });
 
+  describe('test cell transformations', () => {
+    interface ExecutingTemplateConfig {
+      valueClass?: string;
+      executingClass?: string;
+    }
+
+    const testExecutingTemplate = (templateConfig?: ExecutingTemplateConfig) => {
+      const state = 'updating';
+      const value = component.data[0].a;
+
+      component.autoReload = -1;
+      component.columns[0].cellTransformation = CellTemplate.executing;
+      if (templateConfig) {
+        component.columns[0].customTemplateConfig = templateConfig;
+      }
+      component.data[0].cdExecuting = state;
+      fixture.detectChanges();
+
+      const elements = fixture.debugElement
+        .query(By.css('datatable-body-row datatable-body-cell'))
+        .queryAll(By.css('span'));
+      expect(elements.length).toBe(2);
+
+      // Value
+      const valueElement = elements[0];
+      if (templateConfig?.valueClass) {
+        templateConfig.valueClass.split(' ').forEach((clz) => {
+          expect(valueElement.classes).toHaveProperty(clz);
+        });
+      }
+      expect(valueElement.nativeElement.textContent.trim()).toBe(`${value}`);
+      // Executing state
+      const executingElement = elements[1];
+      if (templateConfig?.executingClass) {
+        templateConfig.executingClass.split(' ').forEach((clz) => {
+          expect(executingElement.classes).toHaveProperty(clz);
+        });
+      }
+      expect(executingElement.nativeElement.textContent.trim()).toBe(`(${state})`);
+    };
+
+    it.only('should display executing template', () => {
+      testExecutingTemplate();
+    });
+
+    it.only('should display executing template with custom classes', () => {
+      testExecutingTemplate({ valueClass: 'a b', executingClass: 'c d' });
+    });
+  });
+
   describe('reload data', () => {
     beforeEach(() => {
       component.ngOnInit();
index 586f4376f04bd5593babf48bfb1c3c36d1a55ff3..73ce1f23919f78f7a0a0f65dbe1dcad3a5c3ca38 100644 (file)
@@ -4,6 +4,16 @@ export enum CellTemplate {
   perSecond = 'perSecond',
   checkIcon = 'checkIcon',
   routerLink = 'routerLink',
+  // Display the cell with an executing state. The state can be set to the `cdExecuting`
+  // attribute of table rows.
+  // It supports an optional custom configuration:
+  // {
+  //   ...
+  //   cellTransformation: CellTemplate.executing,
+  //   customTemplateConfig: {
+  //     valueClass?: string;       // Cell value classes.
+  //     executingClass?: string;   // Executing state classes.
+  // }
   executing = 'executing',
   classAdding = 'classAdding',
   // Display the cell value as a badge. The template