Pull request #15: VM/RED-3687
Merge in SL/common-ui from VM/RED-3687 to master * commit '767837c0deb93c475afe30150b3c169726168277': RED-3686 - updated interfaces names RED-3687 - reverted table-content component updates RED-3687 - Remove AutoUnsubscribe directive
This commit is contained in:
commit
8549e57606
@ -1,10 +1,10 @@
|
|||||||
import { Directive, HostListener, inject, OnInit } from '@angular/core';
|
import { Directive, HostListener, inject, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||||
import { AutoUnsubscribe, hasFormChanged, IqserEventTarget } from '../utils';
|
import { hasFormChanged, IqserEventTarget } from '../utils';
|
||||||
import { ConfirmOptions } from '.';
|
import { ConfirmOptions } from '.';
|
||||||
import { ConfirmationDialogService } from './confirmation-dialog.service';
|
import { ConfirmationDialogService } from './confirmation-dialog.service';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom, Subscription } from 'rxjs';
|
||||||
import { LoadingService } from '../loading';
|
import { LoadingService } from '../loading';
|
||||||
import { Toaster } from '../services';
|
import { Toaster } from '../services';
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ export interface SaveOptions {
|
|||||||
* Make sure to remove the (submit)="save()" property from the form and to set type="button" on the save button
|
* Make sure to remove the (submit)="save()" property from the form and to set type="button" on the save button
|
||||||
* (otherwise the save request will be triggered twice).
|
* (otherwise the save request will be triggered twice).
|
||||||
* */
|
* */
|
||||||
export abstract class BaseDialogComponent extends AutoUnsubscribe implements OnInit {
|
export abstract class BaseDialogComponent implements OnDestroy {
|
||||||
form!: UntypedFormGroup;
|
form!: UntypedFormGroup;
|
||||||
initialFormValue!: Record<string, string>;
|
initialFormValue!: Record<string, string>;
|
||||||
protected readonly _formBuilder = inject(UntypedFormBuilder);
|
protected readonly _formBuilder = inject(UntypedFormBuilder);
|
||||||
@ -34,10 +34,11 @@ export abstract class BaseDialogComponent extends AutoUnsubscribe implements OnI
|
|||||||
protected readonly _toaster = inject(Toaster);
|
protected readonly _toaster = inject(Toaster);
|
||||||
readonly #confirmationDialogService = inject(ConfirmationDialogService);
|
readonly #confirmationDialogService = inject(ConfirmationDialogService);
|
||||||
readonly #dialog = inject(MatDialog);
|
readonly #dialog = inject(MatDialog);
|
||||||
|
#backdropClickSubscription = this._dialogRef.backdropClick().subscribe(() => {
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
|
|
||||||
protected constructor(protected readonly _dialogRef: MatDialogRef<BaseDialogComponent>, private readonly _isInEditMode?: boolean) {
|
protected constructor(protected readonly _dialogRef: MatDialogRef<BaseDialogComponent>, private readonly _isInEditMode?: boolean) {}
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
get valid(): boolean {
|
get valid(): boolean {
|
||||||
return this.form.valid;
|
return this.form.valid;
|
||||||
@ -53,10 +54,8 @@ export abstract class BaseDialogComponent extends AutoUnsubscribe implements OnI
|
|||||||
|
|
||||||
abstract save(options?: SaveOptions): void;
|
abstract save(options?: SaveOptions): void;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnDestroy(): void {
|
||||||
this.addSubscription = this._dialogRef.backdropClick().subscribe(() => {
|
this.#backdropClickSubscription.unsubscribe();
|
||||||
this.close();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { Directive } from '@angular/core';
|
import { Directive } from '@angular/core';
|
||||||
import { UntypedFormGroup } from '@angular/forms';
|
import { UntypedFormGroup } from '@angular/forms';
|
||||||
import { AutoUnsubscribe, hasFormChanged } from '../utils';
|
import { hasFormChanged } from '../utils';
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export abstract class BaseFormComponent extends AutoUnsubscribe {
|
export abstract class BaseFormComponent {
|
||||||
form!: UntypedFormGroup;
|
form!: UntypedFormGroup;
|
||||||
initialFormValue!: Record<string, string>;
|
initialFormValue!: Record<string, string>;
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import {
|
|||||||
ViewChild,
|
ViewChild,
|
||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { AutoUnsubscribe } from '../../utils';
|
|
||||||
import { IListable, ListingModes, TableColumnConfig } from '../models';
|
import { IListable, ListingModes, TableColumnConfig } from '../models';
|
||||||
import { ListingComponent } from '../listing-component.directive';
|
import { ListingComponent } from '../listing-component.directive';
|
||||||
import { EntitiesService } from '../services';
|
import { EntitiesService } from '../services';
|
||||||
@ -26,7 +25,7 @@ const SCROLLBAR_WIDTH = 11;
|
|||||||
templateUrl: './table.component.html',
|
templateUrl: './table.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class TableComponent<T extends IListable> extends AutoUnsubscribe implements OnChanges {
|
export class TableComponent<T extends IListable> implements OnChanges {
|
||||||
readonly listingModes = ListingModes;
|
readonly listingModes = ListingModes;
|
||||||
|
|
||||||
@Input() tableColumnConfigs!: readonly TableColumnConfig<T>[];
|
@Input() tableColumnConfigs!: readonly TableColumnConfig<T>[];
|
||||||
@ -56,9 +55,7 @@ export class TableComponent<T extends IListable> extends AutoUnsubscribe impleme
|
|||||||
private readonly _hostRef: ViewContainerRef,
|
private readonly _hostRef: ViewContainerRef,
|
||||||
private readonly _changeRef: ChangeDetectorRef,
|
private readonly _changeRef: ChangeDetectorRef,
|
||||||
readonly entitiesService: EntitiesService<T>,
|
readonly entitiesService: EntitiesService<T>,
|
||||||
) {
|
) {}
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
get tableHeaderLabel(): string | undefined {
|
get tableHeaderLabel(): string | undefined {
|
||||||
return this.listingComponent.tableHeaderLabel;
|
return this.listingComponent.tableHeaderLabel;
|
||||||
|
|||||||
@ -1,41 +1,43 @@
|
|||||||
<ng-container *ngIf="column.entities | async as entities">
|
<ng-container *ngIf="componentContext$ | async as ctx">
|
||||||
<div class="heading">
|
<ng-container *ngIf="ctx.entities as entities">
|
||||||
<span>{{ column.label | translate }} ({{ entities.length || 0 }})</span>
|
<div class="heading">
|
||||||
<span
|
<span>{{ column.label | translate }} ({{ entities.length || 0 }})</span>
|
||||||
(click)="enableSelection()"
|
|
||||||
*ngIf="!activeSelection && !selectionColumn && entities.length > 1"
|
|
||||||
class="all-caps-label primary pointer"
|
|
||||||
translate="workflow.selection.select"
|
|
||||||
></span>
|
|
||||||
<div *ngIf="activeSelection" class="d-flex">
|
|
||||||
<span (click)="selectAll()" class="all-caps-label primary pointer mr-10" translate="workflow.selection.all"></span>
|
|
||||||
<span (click)="selectNone()" class="all-caps-label primary pointer" translate="workflow.selection.none"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="activeSelection" class="multi-select mb-8">
|
|
||||||
<div class="selected-wrapper">
|
|
||||||
<iqser-round-checkbox
|
|
||||||
(click)="toggleSelectAll()"
|
|
||||||
[active]="allSelected$ | async"
|
|
||||||
[indeterminate]="indeterminate$ | async"
|
|
||||||
type="with-bg"
|
|
||||||
></iqser-round-checkbox>
|
|
||||||
|
|
||||||
<span
|
<span
|
||||||
[translateParams]="{ count: listingService.selectedLength$ | async }"
|
(click)="enableSelection()"
|
||||||
[translate]="'workflow.selection.count'"
|
*ngIf="!activeSelection && !selectionColumn && entities.length > 1"
|
||||||
class="all-caps-label"
|
class="all-caps-label primary pointer"
|
||||||
|
translate="workflow.selection.select"
|
||||||
></span>
|
></span>
|
||||||
|
<div *ngIf="activeSelection" class="d-flex">
|
||||||
|
<span (click)="selectAll()" class="all-caps-label primary pointer mr-10" translate="workflow.selection.all"></span>
|
||||||
|
<span (click)="selectNone()" class="all-caps-label primary pointer" translate="workflow.selection.none"></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="activeSelection" class="multi-select mb-8">
|
||||||
|
<div class="selected-wrapper">
|
||||||
|
<iqser-round-checkbox
|
||||||
|
(click)="toggleSelectAll()"
|
||||||
|
[active]="ctx.allSelected"
|
||||||
|
[indeterminate]="ctx.indeterminate"
|
||||||
|
type="with-bg"
|
||||||
|
></iqser-round-checkbox>
|
||||||
|
|
||||||
<div #bulkActionsContainer class="flex-1 overflow-hidden">
|
<span
|
||||||
<ng-container
|
[translateParams]="{ count: listingService.selectedLength$ | async }"
|
||||||
*ngIf="bulkActionsContainerWidth"
|
[translate]="'workflow.selection.count'"
|
||||||
[ngTemplateOutletContext]="{ maxWidth: bulkActionsContainerWidth }"
|
class="all-caps-label"
|
||||||
[ngTemplateOutlet]="bulkActions"
|
></span>
|
||||||
></ng-container>
|
</div>
|
||||||
|
|
||||||
|
<div #bulkActionsContainer class="flex-1 overflow-hidden">
|
||||||
|
<ng-container
|
||||||
|
*ngIf="bulkActionsContainerWidth"
|
||||||
|
[ngTemplateOutletContext]="{ maxWidth: bulkActionsContainerWidth }"
|
||||||
|
[ngTemplateOutlet]="bulkActions"
|
||||||
|
></ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<iqser-circle-button (action)="disableSelection()" [type]="circleButtonTypes.primary" icon="iqser:close"></iqser-circle-button>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
<iqser-circle-button (action)="disableSelection()" [type]="circleButtonTypes.primary" icon="iqser:close"></iqser-circle-button>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -14,17 +14,25 @@ import { combineLatest, Observable } from 'rxjs';
|
|||||||
import { filter, map, tap } from 'rxjs/operators';
|
import { filter, map, tap } from 'rxjs/operators';
|
||||||
import { CircleButtonTypes } from '../../../buttons';
|
import { CircleButtonTypes } from '../../../buttons';
|
||||||
import { IListable } from '../../models';
|
import { IListable } from '../../models';
|
||||||
import { AutoUnsubscribe, Debounce } from '../../../utils';
|
import { Debounce, ContextComponent } from '../../../utils';
|
||||||
import { ListingService } from '../../services';
|
import { ListingService } from '../../services';
|
||||||
import { WorkflowColumn } from '../models/workflow-column.model';
|
import { WorkflowColumn } from '../models/workflow-column.model';
|
||||||
|
|
||||||
|
interface ColumnHeaderContext {
|
||||||
|
entities: IListable[],
|
||||||
|
allSelected: boolean,
|
||||||
|
indeterminate: boolean,
|
||||||
|
selectedLength: number,
|
||||||
|
disableSelection: () => void,
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'iqser-column-header [column] [selectionColumn]',
|
selector: 'iqser-column-header [column] [selectionColumn]',
|
||||||
templateUrl: './column-header.component.html',
|
templateUrl: './column-header.component.html',
|
||||||
styleUrls: ['./column-header.component.scss'],
|
styleUrls: ['./column-header.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ColumnHeaderComponent<T extends IListable, K extends string> extends AutoUnsubscribe implements OnInit {
|
export class ColumnHeaderComponent<T extends IListable, K extends string> extends ContextComponent<ColumnHeaderContext> implements OnInit {
|
||||||
readonly circleButtonTypes = CircleButtonTypes;
|
readonly circleButtonTypes = CircleButtonTypes;
|
||||||
|
|
||||||
@Input() column!: WorkflowColumn<T, K>;
|
@Input() column!: WorkflowColumn<T, K>;
|
||||||
@ -32,9 +40,6 @@ export class ColumnHeaderComponent<T extends IListable, K extends string> extend
|
|||||||
@Input() bulkActions?: TemplateRef<unknown>;
|
@Input() bulkActions?: TemplateRef<unknown>;
|
||||||
@Output() readonly selectionColumnChange = new EventEmitter<WorkflowColumn<T, K> | undefined>();
|
@Output() readonly selectionColumnChange = new EventEmitter<WorkflowColumn<T, K> | undefined>();
|
||||||
|
|
||||||
allSelected$!: Observable<boolean>;
|
|
||||||
indeterminate$!: Observable<boolean>;
|
|
||||||
|
|
||||||
bulkActionsContainerWidth?: number;
|
bulkActionsContainerWidth?: number;
|
||||||
|
|
||||||
@ViewChild('bulkActionsContainer') bulkActionsContainer?: ElementRef;
|
@ViewChild('bulkActionsContainer') bulkActionsContainer?: ElementRef;
|
||||||
@ -48,18 +53,25 @@ export class ColumnHeaderComponent<T extends IListable, K extends string> extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.allSelected$ = combineLatest([this.listingService.selectedLength$, this.column.entities]).pipe(
|
const allSelected$ = combineLatest([this.listingService.selectedLength$, this.column.entities]).pipe(
|
||||||
map(([length, columnEntities]) => length > 0 && length === columnEntities.length),
|
map(([length, columnEntities]) => length > 0 && length === columnEntities.length),
|
||||||
);
|
);
|
||||||
this.indeterminate$ = combineLatest([this.listingService.selectedLength$, this.column.entities]).pipe(
|
const indeterminate$ = combineLatest([this.listingService.selectedLength$, this.column.entities]).pipe(
|
||||||
map(([length, columnEntities]) => length > 0 && length !== columnEntities.length),
|
map(([length, columnEntities]) => length > 0 && length !== columnEntities.length),
|
||||||
);
|
);
|
||||||
this.addSubscription = this.column.entities
|
const disableSelection$ = this.column.entities
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(entities => entities.length <= 1),
|
filter(entities => entities.length <= 1),
|
||||||
tap(() => this.disableSelection()),
|
tap(() => this.disableSelection()),
|
||||||
)
|
);
|
||||||
.subscribe();
|
|
||||||
|
super._initContext({
|
||||||
|
entities: this.column.entities,
|
||||||
|
allSelected: allSelected$,
|
||||||
|
indeterminate: indeterminate$,
|
||||||
|
selectedLength: this.listingService.selectedLength$,
|
||||||
|
disableSelection: disableSelection$,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSelectAll(): void {
|
toggleSelectAll(): void {
|
||||||
|
|||||||
@ -1,77 +1,79 @@
|
|||||||
<iqser-table-header [tableHeaderLabel]="listingComponent.tableHeaderLabel" listingMode="workflow">
|
<ng-container *ngIf="componentContext$ | async">
|
||||||
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
<iqser-table-header [tableHeaderLabel]="listingComponent.tableHeaderLabel" listingMode="workflow">
|
||||||
</iqser-table-header>
|
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
||||||
|
</iqser-table-header>
|
||||||
|
|
||||||
<iqser-empty-state
|
<iqser-empty-state
|
||||||
(action)="noDataAction.emit()"
|
(action)="noDataAction.emit()"
|
||||||
*ngIf="entitiesService.noData$ | async"
|
*ngIf="entitiesService.noData$ | async"
|
||||||
[buttonIcon]="noDataButtonIcon"
|
[buttonIcon]="noDataButtonIcon"
|
||||||
[buttonLabel]="noDataButtonLabel"
|
[buttonLabel]="noDataButtonLabel"
|
||||||
[icon]="noDataIcon"
|
[icon]="noDataIcon"
|
||||||
[showButton]="showNoDataButton"
|
[showButton]="showNoDataButton"
|
||||||
[text]="noDataText"
|
[text]="noDataText"
|
||||||
></iqser-empty-state>
|
></iqser-empty-state>
|
||||||
|
|
||||||
<div
|
|
||||||
*ngIf="(entitiesService.noData$ | async) === false && (draggingEntities$ | async) as draggingEntities"
|
|
||||||
cdkDropListGroup
|
|
||||||
class="columns-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
*ngFor="let column of config.columns"
|
*ngIf="(entitiesService.noData$ | async) === false && (draggingEntities$ | async) as draggingEntities"
|
||||||
[class.dragging]="dragging"
|
cdkDropListGroup
|
||||||
[class.list-can-receive]="isReceiving(column)"
|
class="columns-wrapper"
|
||||||
[class.list-dragging]="isDragging(column)"
|
|
||||||
[class.list-source]="isSource(column)"
|
|
||||||
[style.--color]="column.color"
|
|
||||||
class="column"
|
|
||||||
>
|
>
|
||||||
<iqser-column-header [(selectionColumn)]="selectionColumn" [bulkActions]="bulkActions" [column]="column"></iqser-column-header>
|
|
||||||
<div
|
<div
|
||||||
(cdkDropListDropped)="move($event)"
|
*ngFor="let column of config.columns"
|
||||||
*ngIf="column.entities | async as entities"
|
[class.dragging]="dragging"
|
||||||
[cdkDropListData]="entities"
|
[class.list-can-receive]="isReceiving(column)"
|
||||||
[cdkDropListEnterPredicate]="canMoveTo(column)"
|
[class.list-dragging]="isDragging(column)"
|
||||||
[class.multi-select-active]="selectionColumn === column"
|
[class.list-source]="isSource(column)"
|
||||||
[id]="column.key"
|
[style.--color]="column.color"
|
||||||
cdkDropList
|
class="column"
|
||||||
cdkDropListSortingDisabled
|
|
||||||
>
|
>
|
||||||
|
<iqser-column-header [(selectionColumn)]="selectionColumn" [bulkActions]="bulkActions" [column]="column"></iqser-column-header>
|
||||||
<div
|
<div
|
||||||
(cdkDragEnded)="stopDragging()"
|
(cdkDropListDropped)="move($event)"
|
||||||
(cdkDragStarted)="startDragging(column, $event)"
|
*ngIf="column.entities | async as entities"
|
||||||
(click)="selectionColumn === column && listingService.select(entity)"
|
[cdkDropListData]="entities"
|
||||||
*ngFor="let entity of entities; trackBy: trackBy"
|
[cdkDropListEnterPredicate]="canMoveTo(column)"
|
||||||
[cdkDragData]="entity"
|
[class.multi-select-active]="selectionColumn === column"
|
||||||
[class.no-border]="dragging && draggingEntities.includes(entity)"
|
[id]="column.key"
|
||||||
[class.selected]="all[entity.id].isSelected$ | async"
|
cdkDropList
|
||||||
[ngClass]="all[entity.id].classes$ | async"
|
cdkDropListSortingDisabled
|
||||||
cdkDrag
|
|
||||||
>
|
>
|
||||||
<ng-container *ngIf="!draggingEntities.includes(entity)">
|
<div
|
||||||
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: entity }"></ng-container>
|
(cdkDragEnded)="stopDragging()"
|
||||||
</ng-container>
|
(cdkDragStarted)="startDragging(column, $event)"
|
||||||
|
(click)="selectionColumn === column && listingService.select(entity)"
|
||||||
<ng-template cdkDragPlaceholder>
|
*ngFor="let entity of entities; trackBy: trackBy"
|
||||||
<div *ngFor="let e of draggingEntities" [style.min-height]="itemHeight + 'px'" class="placeholder"></div>
|
[cdkDragData]="entity"
|
||||||
</ng-template>
|
[class.no-border]="dragging && draggingEntities.includes(entity)"
|
||||||
|
[class.selected]="all[entity.id].isSelected$ | async"
|
||||||
<ng-template cdkDragPreview>
|
[ngClass]="all[entity.id].classes$ | async"
|
||||||
<ng-container *ngFor="let e of draggingEntities">
|
cdkDrag
|
||||||
<div
|
>
|
||||||
[class.selected]="all[e.id].isSelected$ | async"
|
<ng-container *ngIf="!draggingEntities.includes(entity)">
|
||||||
[ngClass]="all[e.id].classes$ | async"
|
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: entity }"></ng-container>
|
||||||
[style.width]="itemWidth + 'px'"
|
|
||||||
>
|
|
||||||
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: e }"></ng-container>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div (click)="addElement.emit()" *ngIf="column.key === addElementColumn" class="add-btn">
|
<ng-template cdkDragPlaceholder>
|
||||||
<mat-icon [svgIcon]="addElementIcon"></mat-icon>
|
<div *ngFor="let e of draggingEntities" [style.min-height]="itemHeight + 'px'" class="placeholder"></div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template cdkDragPreview>
|
||||||
|
<ng-container *ngFor="let e of draggingEntities">
|
||||||
|
<div
|
||||||
|
[class.selected]="all[e.id].isSelected$ | async"
|
||||||
|
[ngClass]="all[e.id].classes$ | async"
|
||||||
|
[style.width]="itemWidth + 'px'"
|
||||||
|
>
|
||||||
|
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: e }"></ng-container>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div (click)="addElement.emit()" *ngIf="column.key === addElementColumn" class="add-btn">
|
||||||
|
<mat-icon [svgIcon]="addElementIcon"></mat-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ng-container>
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ListingComponent } from '../listing-component.directive';
|
import { ListingComponent } from '../listing-component.directive';
|
||||||
import { CdkDragDrop, CdkDragStart, CdkDropList } from '@angular/cdk/drag-drop';
|
import { CdkDragDrop, CdkDragStart, CdkDropList } from '@angular/cdk/drag-drop';
|
||||||
import { AutoUnsubscribe, Debounce, trackByFactory } from '../../utils';
|
import { Debounce, trackByFactory, ContextComponent } from '../../utils';
|
||||||
import { IListable } from '../models';
|
import { IListable } from '../models';
|
||||||
import { EntitiesService, ListingService } from '../services';
|
import { EntitiesService, ListingService } from '../services';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
@ -24,13 +24,18 @@ import { WorkflowConfig } from './models/workflow-config.model';
|
|||||||
import { WorkflowColumn } from './models/workflow-column.model';
|
import { WorkflowColumn } from './models/workflow-column.model';
|
||||||
import { EntityWrapper } from './models/entity-wrapper.model';
|
import { EntityWrapper } from './models/entity-wrapper.model';
|
||||||
|
|
||||||
|
interface WorkflowContext {
|
||||||
|
updateConfigItems: unknown;
|
||||||
|
setupResizeObserver: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'iqser-workflow [itemTemplate] [config] [addElementIcon]',
|
selector: 'iqser-workflow [itemTemplate] [config] [addElementIcon]',
|
||||||
templateUrl: './workflow.component.html',
|
templateUrl: './workflow.component.html',
|
||||||
styleUrls: ['./workflow.component.scss'],
|
styleUrls: ['./workflow.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class WorkflowComponent<T extends IListable, K extends string> extends AutoUnsubscribe implements OnInit {
|
export class WorkflowComponent<T extends IListable, K extends string> extends ContextComponent<WorkflowContext> implements OnInit {
|
||||||
@Input() headerTemplate?: TemplateRef<unknown>;
|
@Input() headerTemplate?: TemplateRef<unknown>;
|
||||||
@Input() itemTemplate!: TemplateRef<T>;
|
@Input() itemTemplate!: TemplateRef<T>;
|
||||||
@Input() config!: WorkflowConfig<T, K>;
|
@Input() config!: WorkflowConfig<T, K>;
|
||||||
@ -81,14 +86,18 @@ export class WorkflowComponent<T extends IListable, K extends string> extends Au
|
|||||||
for (const column of this.config.columns) {
|
for (const column of this.config.columns) {
|
||||||
column.entities = new BehaviorSubject<T[]>([]);
|
column.entities = new BehaviorSubject<T[]>([]);
|
||||||
}
|
}
|
||||||
this.addSubscription = this.listingService.displayed$.pipe(tap(entities => this._updateConfigItems(entities))).subscribe();
|
const updateConfigItems$ = this.listingService.displayed$.pipe(tap(entities => this._updateConfigItems(entities)))
|
||||||
this.addSubscription = this.entitiesService.noData$
|
const setupResizeObserver$ = this.entitiesService.noData$
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(noData => noData),
|
filter(noData => noData),
|
||||||
tap(() => this._setupResizeObserver()),
|
tap(() => this._setupResizeObserver()),
|
||||||
)
|
);
|
||||||
.subscribe();
|
|
||||||
this._setupResizeObserver();
|
this._setupResizeObserver();
|
||||||
|
|
||||||
|
super._initContext({
|
||||||
|
updateConfigItems: updateConfigItems$,
|
||||||
|
setupResizeObserver: setupResizeObserver$
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
canMoveTo(column: WorkflowColumn<T, K>): () => boolean {
|
canMoveTo(column: WorkflowColumn<T, K>): () => boolean {
|
||||||
|
|||||||
17
src/lib/utils/context.component.ts
Normal file
17
src/lib/utils/context.component.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { combineLatest, Observable, of } from 'rxjs';
|
||||||
|
import { map, startWith } from 'rxjs/operators';
|
||||||
|
import { ValuesOf } from './types/utility-types';
|
||||||
|
|
||||||
|
export class ContextComponent<T> {
|
||||||
|
componentContext$: Observable<T> | null = of({} as T);
|
||||||
|
|
||||||
|
protected _initContext(context: Record<string, Observable<ValuesOf<T>>>): void {
|
||||||
|
const observables = Object.values(context).map(obs => obs.pipe(startWith(null)));
|
||||||
|
const keys = Object.keys(context);
|
||||||
|
this.componentContext$ = combineLatest(observables).pipe(map(values => this._mapKeysToObs(keys, values)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _mapKeysToObs(keys: string[], observables: (ValuesOf<T> | null) []): T {
|
||||||
|
return keys.reduce((acc, key, index) => ({ ...acc, [key]: observables[index] }), {} as T);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,3 +15,4 @@ export * from './types/iqser-types';
|
|||||||
export * from './pruning-translation-loader';
|
export * from './pruning-translation-loader';
|
||||||
export * from './custom-route-reuse.strategy';
|
export * from './custom-route-reuse.strategy';
|
||||||
export * from './headers-configuration';
|
export * from './headers-configuration';
|
||||||
|
export * from './context.component';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user