Refresh items, add btn, some css fixes

This commit is contained in:
Adina Țeudan 2021-09-28 00:39:03 +03:00
parent 5973631a1d
commit 5d0bb11c65
4 changed files with 100 additions and 30 deletions

View File

@ -23,7 +23,6 @@ export abstract class ListingComponent<T extends Listable> extends AutoUnsubscri
readonly listingMode$: Observable<ListingMode>; readonly listingMode$: Observable<ListingMode>;
readonly routerLinkFn?: (entity: T) => string | string[]; readonly routerLinkFn?: (entity: T) => string | string[];
// TODO: These should be somewhere in table listing, not generic listing
abstract readonly tableColumnConfigs: readonly TableColumnConfig<T>[]; abstract readonly tableColumnConfigs: readonly TableColumnConfig<T>[];
abstract readonly tableHeaderLabel: string; abstract readonly tableHeaderLabel: string;

View File

@ -12,7 +12,7 @@
[class.list-source]="isSource(column)" [class.list-source]="isSource(column)"
[style.--color]="column.color" [style.--color]="column.color"
class="column"> class="column">
<div class="heading">{{ column.label | translate }} ({{column.entities.length}})</div> <div class="heading">{{ column.label | translate }} ({{column.entities?.length || 0}})</div>
<div <div
(cdkDropListDropped)="move($event)" (cdkDropListDropped)="move($event)"
[cdkDropListData]="column.entities" [cdkDropListData]="column.entities"
@ -25,6 +25,9 @@
<div *cdkDragPlaceholder [style.--height]="itemHeight"></div> <div *cdkDragPlaceholder [style.--height]="itemHeight"></div>
<ng-container *ngTemplateOutlet="itemTemplate; context: { entity: entity }"></ng-container> <ng-container *ngTemplateOutlet="itemTemplate; context: { entity: entity }"></ng-container>
</div> </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>

View File

@ -38,8 +38,7 @@
} }
> .heading { > .heading {
margin-left: 18px; margin: 0 18px 16px 18px;
margin-bottom: 16px;
} }
&.dragging { &.dragging {
@ -60,7 +59,7 @@
var(--iqser-white) 8px var(--iqser-white) 8px
); );
> .heading, ::ng-deep.cdk-drag > * { > .heading, .add-btn, ::ng-deep.cdk-drag > * {
opacity: 0.3; opacity: 0.3;
} }
@ -76,11 +75,9 @@
min-height: calc(100% - 36px); min-height: calc(100% - 36px);
} }
.cdk-drag { .cdk-drag {
background-color: var(--iqser-white); background-color: var(--iqser-white);
transition: background-color 0.2s, box-shadow 0.2s;
border-radius: 8px;
margin: 0 8px 4px 8px;
&:last-child { &:last-child {
margin-bottom: 8px; margin-bottom: 8px;
@ -93,6 +90,31 @@
&:hover { &:hover {
background-color: var(--iqser-grey-6); background-color: var(--iqser-grey-6);
}
}
.add-btn {
background-color: var(--iqser-grey-6);
padding: 10px;
text-align: center;
cursor: pointer;
mat-icon {
width: 14px;
height: 14px;
}
&:hover {
background-color: var(--iqser-grey-4);
}
}
.cdk-drag, .add-btn {
transition: background-color 0.2s, box-shadow 0.2s;
border-radius: 8px;
margin: 0 8px 4px 8px;
&:hover {
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15); box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
} }
} }

View File

@ -1,4 +1,16 @@
import { ChangeDetectionStrategy, Component, forwardRef, Inject, Input, OnInit, QueryList, TemplateRef, ViewChildren } from '@angular/core'; import {
ChangeDetectionStrategy,
Component,
EventEmitter,
forwardRef,
Inject,
Input,
OnInit,
Output,
QueryList,
TemplateRef,
ViewChildren
} from '@angular/core';
import { ListingComponent } from '../listing-component.directive'; import { ListingComponent } from '../listing-component.directive';
import { Listable, ListingModes } from '../models'; import { Listable, ListingModes } from '../models';
import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop'; import { CdkDrag, CdkDragDrop, CdkDropList } from '@angular/cdk/drag-drop';
@ -16,6 +28,7 @@ interface WorkflowColumn<T, K> {
export interface WorkflowConfig<T, K> { export interface WorkflowConfig<T, K> {
key: string; key: string;
itemVersionFn: (entity: T) => string;
columns: WorkflowColumn<T, K>[]; columns: WorkflowColumn<T, K>[];
} }
@ -30,23 +43,22 @@ export class WorkflowComponent<T extends Listable, K extends string> implements
@Input() headerTemplate?: TemplateRef<unknown>; @Input() headerTemplate?: TemplateRef<unknown>;
@Input() @Required() itemTemplate!: TemplateRef<T>; @Input() @Required() itemTemplate!: TemplateRef<T>;
@Input() @Required() config!: WorkflowConfig<T, K>; @Input() @Required() config!: WorkflowConfig<T, K>;
@Input() @Required() itemHeight!: string;
@Input() itemClasses?: { [key: string]: (e: T) => boolean }; @Input() itemClasses?: { [key: string]: (e: T) => boolean };
@Input() addElementIcon?: string;
@Input() addElementColumn?: K;
@Output() readonly addElement = new EventEmitter<void>();
dragging = false; dragging = false;
sourceColumn?: WorkflowColumn<T, K>; sourceColumn?: WorkflowColumn<T, K>;
@ViewChildren(CdkDropList) private readonly _dropLists!: QueryList<CdkDropList>; @ViewChildren(CdkDropList) private readonly _dropLists!: QueryList<CdkDropList>;
private _existingEntities: { [key: string]: T } = {};
constructor( constructor(
@Inject(forwardRef(() => ListingComponent)) private _parent: ListingComponent<T>, @Inject(forwardRef(() => ListingComponent)) private _parent: ListingComponent<T>,
private readonly _loadingService: LoadingService private readonly _loadingService: LoadingService
) {} ) {}
_itemHeight = 0;
get itemHeight(): string {
return `${this._itemHeight}px`;
}
get listingComponent(): ListingComponent<T> { get listingComponent(): ListingComponent<T> {
return this._parent; return this._parent;
} }
@ -106,31 +118,65 @@ export class WorkflowComponent<T extends Listable, K extends string> implements
return this._dropLists?.find(list => list.id === id); return this._dropLists?.find(list => list.id === id);
} }
private _computeItemHeight(): void {
const items = document.getElementsByClassName('cdk-drag');
if (items.length) {
this._itemHeight = items[0].getBoundingClientRect().height;
}
}
private _updateConfigItems(entities: T[]) { private _updateConfigItems(entities: T[]) {
// Disable updating while dragging // Disable updating while dragging
if (this.dragging) { if (this.dragging) {
return; return;
} }
// TODO ... // Remove deleted entities
this.config.columns.forEach(column => { const updatedIds = entities.map(entity => entity.id);
column.entities = []; for (const id of Object.keys(this._existingEntities)) {
}); if (!updatedIds.includes(id)) {
this._removeEntity(this._existingEntities[id]);
}
}
// Add or move updated entities
entities.forEach(entity => { entities.forEach(entity => {
const column = this._getColumnByKey(entity[this.config.key]); const shouldAdd = this._shouldAdd(entity);
if (column) { const shouldMove = this._shouldMove(entity);
column.entities?.push(entity);
if (shouldMove) {
this._removeEntity(entity);
}
if (shouldAdd || shouldMove) {
this._addEntity(entity);
} }
}); });
this._computeItemHeight(); // this._computeItemHeight();
}
private _addEntity(entity: T): void {
this._existingEntities[entity.id] = entity;
const column = this._getColumnByKey(entity[this.config.key] as K);
if (column) {
if (!column.entities) {
column.entities = [];
}
column.entities.push(entity);
}
}
private _removeEntity(entity: T): void {
const existingEntity = this._existingEntities[entity.id];
const column = this._getColumnByKey(existingEntity[this.config.key] as K);
if (column) {
const idx = (column.entities as T[]).findIndex(item => item.id === entity.id);
column.entities?.splice(idx, 1);
}
delete this._existingEntities[entity.id];
}
private _shouldMove(entity: T): boolean {
const existingEntity = this._existingEntities[entity.id];
return existingEntity && this.config.itemVersionFn(entity) !== this.config.itemVersionFn(existingEntity);
}
private _shouldAdd(entity: T): boolean {
return !this._existingEntities[entity.id];
} }
private _getColumnByKey(key: K): WorkflowColumn<T, K> { private _getColumnByKey(key: K): WorkflowColumn<T, K> {