Преглед изворни кода

admin-panel: check editor: implemented sort feature

Christian Kahlau пре 2 година
родитељ
комит
1de37a14e7

+ 3 - 3
ng/src/app/components/service-check-editor/service-check-adapter/service-check-adapter.component.html

@@ -1,11 +1,11 @@
 <ng-container *ngIf="stringModel !== undefined; else complexModel">
-  <app-service-check-string [model]="stringModel"></app-service-check-string>
+  <app-service-check-string [model]="stringModel" [sortVisible]="sortVisible" (sort)="sort.emit($event)"></app-service-check-string>
 </ng-container>
 <ng-template #complexModel>
   <ng-container *ngIf="conjunction; else disjunctModel">
-    <app-service-check-conjunction [model]="conjunction" [sortVisible]="sortVisible"></app-service-check-conjunction>
+    <app-service-check-conjunction [model]="conjunction" [sortVisible]="sortVisible" (sort)="sort.emit($event)"></app-service-check-conjunction>
   </ng-container>
   <ng-template #disjunctModel>
-    <app-service-check-disjunction [model]="disjunction" [sortVisible]="sortVisible"></app-service-check-disjunction>
+    <app-service-check-disjunction [model]="disjunction" [sortVisible]="sortVisible" (sort)="sort.emit($event)"></app-service-check-disjunction>
   </ng-template>
 </ng-template>

+ 2 - 2
ng/src/app/components/service-check-editor/service-check-adapter/service-check-adapter.component.ts

@@ -2,13 +2,14 @@ import { Component, Input, ViewChild } from '@angular/core';
 import { ServiceCheckConjunctionComponent } from 'src/app/components/service-check-editor/service-check-conjunction/service-check-conjunction.component';
 import { ServiceCheckDisjunctionComponent } from 'src/app/components/service-check-editor/service-check-disjunction/service-check-disjunction.component';
 import { ServiceCheckStringComponent } from 'src/app/components/service-check-editor/service-check-string/service-check-string.component';
+import { SortableComponent } from 'src/app/components/service-check-editor/sortable.component';
 
 @Component({
   selector: 'app-service-check-adapter',
   templateUrl: './service-check-adapter.component.html',
   styleUrls: ['./service-check-adapter.component.scss']
 })
-export class ServiceCheckAdapterComponent {
+export class ServiceCheckAdapterComponent extends SortableComponent {
   @ViewChild(ServiceCheckDisjunctionComponent) disCmp?: ServiceCheckDisjunctionComponent;
   @ViewChild(ServiceCheckConjunctionComponent) conCmp?: ServiceCheckConjunctionComponent;
   @ViewChild(ServiceCheckStringComponent) expCmp?: ServiceCheckStringComponent;
@@ -28,7 +29,6 @@ export class ServiceCheckAdapterComponent {
   public get model() {
     return this._model;
   }
-  @Input() sortVisible: { up: boolean; down: boolean } = { up: true, down: true };
 
   private _model!: string | CheckDisjunction | CheckConjunction;
   public stringModel?: string;

+ 15 - 6
ng/src/app/components/service-check-editor/service-check-conjunction/service-check-conjunction.component.html

@@ -6,17 +6,26 @@
     class="d-flex flex-column align-items-center h-100 bg-max"
     style="grid-column: 1 / span 1"
     [style.grid-row]="'1 / span ' + (model?.and?.length ?? 0) + 1">
-    <fa-icon *ngIf="sortVisible.up" [icon]="fa.up" class="text-muted"></fa-icon>
+    <fa-icon *ngIf="sortVisible.up" [icon]="fa.up" class="text-muted pointer" (click)="sort.emit('up')"></fa-icon>
     <div class="flex-fill label-upright-vertical">AND</div>
-    <fa-icon [icon]="fa.times" class="text-danger"></fa-icon>
-    <fa-icon *ngIf="sortVisible.down" [icon]="fa.down" class="text-muted"></fa-icon>
+    <fa-icon *ngIf="sortVisible.down" [icon]="fa.down" class="text-muted pointer" (click)="sort.emit('down')"></fa-icon>
   </div>
 
   <div *ngFor="let check of model?.and; index as i" style="grid-column: 2 / span 1" [style.grid-row]="i + 1 + ' / span 1'" [class.border-top]="i > 0">
-    <app-service-check-adapter [model]="check" [sortVisible]="{ up: i > 0, down: (model?.and?.length ?? 0) > i + 1 }"></app-service-check-adapter>
+    <app-service-check-adapter
+      [model]="check"
+      [sortVisible]="{ up: i > 0, down: (model?.and?.length ?? 0) > i + 1 }"
+      (sort)="onSubSort(i, $event)"></app-service-check-adapter>
   </div>
 
-  <div style="grid-column: 2 / span 1" [style.grid-row]="(model?.and?.length ?? 0) + 1 + ' / span 1'" class="ps-2 border-top">
-    <app-service-check-button-controls (create)="model?.and?.push($event)"></app-service-check-button-controls>
+  <div
+    style="grid-column: 2 / span 1"
+    [style.grid-row]="(model?.and?.length ?? 0) + 1 + ' / span 1'"
+    class="d-flex align-items-end ps-2"
+    [class.border-top]="model?.and?.length ?? 0 > 0">
+    <div class="d-flex align-items-baseline w-100">
+      <app-service-check-button-controls class="flex-fill" (create)="model?.and?.push($event)"></app-service-check-button-controls>
+      <fa-icon [icon]="fa.times" class="text-danger ps-2 pe-2"></fa-icon>
+    </div>
   </div>
 </div>

+ 13 - 2
ng/src/app/components/service-check-editor/service-check-conjunction/service-check-conjunction.component.ts

@@ -2,20 +2,31 @@ import { Component, Input, QueryList, ViewChildren } from '@angular/core';
 import { faCaretDown, faCaretUp, faTimes } from '@fortawesome/free-solid-svg-icons';
 
 import { ServiceCheckAdapterComponent } from 'src/app/components/service-check-editor/service-check-adapter/service-check-adapter.component';
+import { SortableComponent, SortDirection } from 'src/app/components/service-check-editor/sortable.component';
 
 @Component({
   selector: 'app-service-check-conjunction',
   templateUrl: './service-check-conjunction.component.html',
   styleUrls: ['./service-check-conjunction.component.scss']
 })
-export class ServiceCheckConjunctionComponent {
+export class ServiceCheckConjunctionComponent extends SortableComponent {
   @ViewChildren(ServiceCheckAdapterComponent) adapters!: QueryList<ServiceCheckAdapterComponent>;
   @Input() model?: CheckConjunction;
-  @Input() sortVisible: { up: boolean; down: boolean } = { up: true, down: true };
 
   public fa = { times: faTimes, down: faCaretDown, up: faCaretUp };
 
   public collect() {
     return { and: this.adapters.map(adpt => adpt.collect()) };
   }
+
+  public onSubSort(idx: number, dir: SortDirection) {
+    if (!this.model?.and) return;
+
+    const a = this.model.and.splice(idx, 1);
+    if (dir === 'up') {
+      this.model.and.splice(idx - 1, 0, ...a);
+    } else {
+      this.model.and.splice(idx + 1, 0, ...a);
+    }
+  }
 }

+ 15 - 6
ng/src/app/components/service-check-editor/service-check-disjunction/service-check-disjunction.component.html

@@ -1,16 +1,25 @@
 <div *ngIf="model" class="d-grid w-100 check-disjunction" [style.grid-template-rows]="'repeat(' + (model.length + 1) + ', max-content)'">
   <div class="d-flex flex-column align-items-center h-100 bg-peak" style="grid-column: 1 / span 1" [style.grid-row]="'1 / span ' + model.length + 1">
-    <fa-icon *ngIf="sortVisible.up" [icon]="fa.up" class="text-muted"></fa-icon>
+    <fa-icon *ngIf="sortVisible.up" [icon]="fa.up" class="text-muted pointer" (click)="sort.emit('up')"></fa-icon>
     <div class="flex-fill label-upright-vertical">OR</div>
-    <fa-icon [icon]="fa.times" class="text-danger"></fa-icon>
-    <fa-icon *ngIf="sortVisible.down" [icon]="fa.down" class="text-muted"></fa-icon>
+    <fa-icon *ngIf="sortVisible.down" [icon]="fa.down" class="text-muted pointer" (click)="sort.emit('down')"></fa-icon>
   </div>
 
   <div *ngFor="let check of model; index as i" style="grid-column: 2 / span 1" [style.grid-row]="i + 1 + ' / span 1'" [class.border-top]="i > 0">
-    <app-service-check-adapter [model]="check" [sortVisible]="{ up: i > 0, down: model.length > i + 1 }"></app-service-check-adapter>
+    <app-service-check-adapter
+      [model]="check"
+      [sortVisible]="{ up: i > 0, down: model.length > i + 1 }"
+      (sort)="onSubSort(i, $event)"></app-service-check-adapter>
   </div>
 
-  <div style="grid-column: 2 / span 1" [style.grid-row]="model.length + 1 + ' / span 1'" class="ps-2 border-top">
-    <app-service-check-button-controls (create)="model.push($event)"></app-service-check-button-controls>
+  <div
+    style="grid-column: 2 / span 1"
+    [style.grid-row]="model.length + 1 + ' / span 1'"
+    class="d-flex align-items-end ps-2"
+    [class.border-top]="model.length > 0">
+    <div class="d-flex align-items-baseline w-100">
+      <app-service-check-button-controls class="flex-fill" (create)="model.push($event)"></app-service-check-button-controls>
+      <fa-icon *ngIf="removable" [icon]="fa.times" class="text-danger ps-2 pe-2"></fa-icon>
+    </div>
   </div>
 </div>

+ 14 - 2
ng/src/app/components/service-check-editor/service-check-disjunction/service-check-disjunction.component.ts

@@ -2,20 +2,32 @@ import { Component, Input, QueryList, ViewChildren } from '@angular/core';
 import { faCaretDown, faCaretUp, faTimes } from '@fortawesome/free-solid-svg-icons';
 
 import { ServiceCheckAdapterComponent } from 'src/app/components/service-check-editor/service-check-adapter/service-check-adapter.component';
+import { SortableComponent, SortDirection } from 'src/app/components/service-check-editor/sortable.component';
 
 @Component({
   selector: 'app-service-check-disjunction',
   templateUrl: './service-check-disjunction.component.html',
   styleUrls: ['./service-check-disjunction.component.scss']
 })
-export class ServiceCheckDisjunctionComponent {
+export class ServiceCheckDisjunctionComponent extends SortableComponent {
   @ViewChildren(ServiceCheckAdapterComponent) adapters!: QueryList<ServiceCheckAdapterComponent>;
   @Input() model?: CheckDisjunction;
-  @Input() sortVisible: { up: boolean; down: boolean } = { up: true, down: true };
+  @Input() removable = true;
 
   public fa = { times: faTimes, down: faCaretDown, up: faCaretUp };
 
   public collect() {
     return this.adapters.map(adpt => adpt.collect());
   }
+
+  public onSubSort(idx: number, dir: SortDirection) {
+    if (!this.model) return;
+
+    const a = this.model.splice(idx, 1);
+    if (dir === 'up') {
+      this.model.splice(idx - 1, 0, ...a);
+    } else {
+      this.model.splice(idx + 1, 0, ...a);
+    }
+  }
 }

+ 11 - 1
ng/src/app/components/service-check-editor/service-check-string/service-check-string.component.html

@@ -1 +1,11 @@
-<input type="text" class="border-0 form-control w-100" [(ngModel)]="model" />
+<div class="input-group">
+  <div class="input-group-text text-secondary justify-content-center flex-column border-0 border-end p-0">
+    <fa-icon *ngIf="sortVisible.up" [icon]="fa.up" class="text-muted pointer" (click)="sort.emit('up')"></fa-icon>
+    <span [class.flex-fill]="sortVisible.up || sortVisible.down">
+      <fa-icon [icon]="fa.terminal" *ngIf="!sortVisible.up && !sortVisible.down"></fa-icon>
+    </span>
+    <fa-icon *ngIf="sortVisible.down" [icon]="fa.down" class="text-muted pointer" (click)="sort.emit('down')"></fa-icon>
+  </div>
+  <input type="text" class="border-0 form-control flex-fill" [(ngModel)]="model" />
+  <fa-icon [icon]="fa.times" class="text-danger align-self-center ps-2 pe-2"></fa-icon>
+</div>

+ 6 - 1
ng/src/app/components/service-check-editor/service-check-string/service-check-string.component.ts

@@ -1,13 +1,18 @@
 import { Component, Input } from '@angular/core';
+import { faCaretDown, faCaretUp, faTerminal, faTimes } from '@fortawesome/free-solid-svg-icons';
+
+import { SortableComponent } from '../sortable.component';
 
 @Component({
   selector: 'app-service-check-string',
   templateUrl: './service-check-string.component.html',
   styleUrls: ['./service-check-string.component.scss']
 })
-export class ServiceCheckStringComponent {
+export class ServiceCheckStringComponent extends SortableComponent {
   @Input() model?: string;
 
+  public fa = { down: faCaretDown, terminal: faTerminal, times: faTimes, up: faCaretUp };
+
   public collect() {
     return this.model ?? '';
   }

+ 9 - 0
ng/src/app/components/service-check-editor/sortable.component.ts

@@ -0,0 +1,9 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+export type SortDirection = 'up' | 'down';
+
+@Component({ template: '' })
+export abstract class SortableComponent {
+  @Input() sortVisible: { up: boolean; down: boolean } = { up: true, down: true };
+  @Output() sort: EventEmitter<SortDirection> = new EventEmitter();
+}

+ 4 - 1
ng/src/app/components/service-check-form/service-check-form.component.html

@@ -80,7 +80,10 @@
     <div class="col-12">
       <label class="mt-2">Check</label>
       <div class="mt-2 position-relative border">
-        <app-service-check-disjunction [model]="serviceCheck.checks" [sortVisible]="{ up: false, down: false }"></app-service-check-disjunction>
+        <app-service-check-disjunction
+          [model]="serviceCheck.checks"
+          [sortVisible]="{ up: false, down: false }"
+          [removable]="false"></app-service-check-disjunction>
       </div>
     </div>
   </div>

BIN
ng/src/favicon.ico


+ 14 - 8
ng/src/styles.scss

@@ -17,7 +17,7 @@
 }
 
 .bg-progress {
-  background-color: #e9ecef !important;
+  background-color: $progress-bg !important;
 }
 
 .text-avg {
@@ -35,12 +35,18 @@
 .check-disjunction,
 .check-conjunction {
   &.d-grid {
-    grid-template-columns: 26px 1fr;
-  }
-
-  .label-upright-vertical {
-    writing-mode: vertical-lr;
-    text-orientation: upright;
-    text-align: center;
+    grid-template-columns: 30px 1fr;
+
+    .label-upright-vertical {
+      writing-mode: vertical-lr;
+      text-orientation: upright;
+      text-align: center;
+    }
+
+    .input-group .input-group-text {
+      width: 31px;
+      min-height: 48px;
+      // font-size: 0.75rem;
+    }
   }
 }