add multiselect editor, datetime editor, currency/datetime/boolean renderers, column reordering

This commit is contained in:
garrettmills 2020-02-19 01:12:59 -06:00
parent 1edd696bdb
commit 42f24914d5
15 changed files with 300 additions and 25 deletions

5
package-lock.json generated
View File

@ -7019,6 +7019,11 @@
"resolved": "https://registry.npmjs.org/mobx-angular/-/mobx-angular-3.0.3.tgz", "resolved": "https://registry.npmjs.org/mobx-angular/-/mobx-angular-3.0.3.tgz",
"integrity": "sha512-mZuuose70V+Sd0hMWDElpRe3mA6GhYjSQN3mHzqk2XWXRJ+eWQa/f3Lqhw+Me/Xd2etWsGR1hnRa1BfQ2ZDtpw==" "integrity": "sha512-mZuuose70V+Sd0hMWDElpRe3mA6GhYjSQN3mHzqk2XWXRJ+eWQa/f3Lqhw+Me/Xd2etWsGR1hnRa1BfQ2ZDtpw=="
}, },
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",

View File

@ -27,6 +27,7 @@
"ag-grid-community": "^22.1.1", "ag-grid-community": "^22.1.1",
"angular-tree-component": "^8.5.2", "angular-tree-component": "^8.5.2",
"core-js": "^2.5.4", "core-js": "^2.5.4",
"moment": "^2.24.0",
"ngx-monaco-editor": "^8.1.1", "ngx-monaco-editor": "^8.1.1",
"rxjs": "~6.5.1", "rxjs": "~6.5.1",
"tslib": "^1.9.0", "tslib": "^1.9.0",

View File

@ -19,6 +19,11 @@ import {ParagraphEditorComponent} from './editor/database/editors/paragraph/para
import {ParagraphModalComponent} from './editor/database/editors/paragraph/paragraph-modal.component'; import {ParagraphModalComponent} from './editor/database/editors/paragraph/paragraph-modal.component';
import {BooleanEditorComponent} from './editor/database/editors/boolean/boolean-editor.component'; import {BooleanEditorComponent} from './editor/database/editors/boolean/boolean-editor.component';
import {SelectEditorComponent} from './editor/database/editors/select/select-editor.component'; import {SelectEditorComponent} from './editor/database/editors/select/select-editor.component';
import {MultiSelectEditorComponent} from './editor/database/editors/select/multiselect-editor.component';
import {DatetimeEditorComponent} from './editor/database/editors/datetime/datetime-editor.component';
import {DatetimeRendererComponent} from './editor/database/renderers/datetime-renderer.component';
import {CurrencyRendererComponent} from './editor/database/renderers/currency-renderer.component';
import {BooleanRendererComponent} from './editor/database/renderers/boolean-renderer.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -37,6 +42,11 @@ import {SelectEditorComponent} from './editor/database/editors/select/select-edi
ParagraphModalComponent, ParagraphModalComponent,
BooleanEditorComponent, BooleanEditorComponent,
SelectEditorComponent, SelectEditorComponent,
MultiSelectEditorComponent,
DatetimeEditorComponent,
DatetimeRendererComponent,
CurrencyRendererComponent,
BooleanRendererComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -61,6 +71,11 @@ import {SelectEditorComponent} from './editor/database/editors/select/select-edi
ParagraphModalComponent, ParagraphModalComponent,
BooleanEditorComponent, BooleanEditorComponent,
SelectEditorComponent, SelectEditorComponent,
MultiSelectEditorComponent,
DatetimeEditorComponent,
DatetimeRendererComponent,
CurrencyRendererComponent,
BooleanRendererComponent,
], ],
exports: [ exports: [
HostComponent, HostComponent,
@ -78,6 +93,11 @@ import {SelectEditorComponent} from './editor/database/editors/select/select-edi
ParagraphModalComponent, ParagraphModalComponent,
BooleanEditorComponent, BooleanEditorComponent,
SelectEditorComponent, SelectEditorComponent,
MultiSelectEditorComponent,
DatetimeEditorComponent,
DatetimeRendererComponent,
CurrencyRendererComponent,
BooleanRendererComponent,
] ]
}) })
export class ComponentsModule {} export class ComponentsModule {}

View File

@ -21,7 +21,7 @@
<ion-input type="text" required [(ngModel)]="columnSets[i].headerName"></ion-input> <ion-input type="text" required [(ngModel)]="columnSets[i].headerName"></ion-input>
</ion-item> </ion-item>
</ion-col> </ion-col>
<ion-col size="5"> <ion-col size="4">
<ion-item> <ion-item>
<ion-label position="floating">Data Type</ion-label> <ion-label position="floating">Data Type</ion-label>
<ion-select interface="popover" [(ngModel)]="columnSets[i].Type"> <ion-select interface="popover" [(ngModel)]="columnSets[i].Type">
@ -30,19 +30,30 @@
<ion-select-option value="paragraph">Paragraph</ion-select-option> <ion-select-option value="paragraph">Paragraph</ion-select-option>
<ion-select-option value="boolean">Boolean</ion-select-option> <ion-select-option value="boolean">Boolean</ion-select-option>
<ion-select-option value="select">Select</ion-select-option> <ion-select-option value="select">Select</ion-select-option>
<!-- <ion-select-option value="currency">Currency</ion-select-option>--> <ion-select-option value="multiselect">Multi-Select</ion-select-option>
<!-- <ion-select-option value="datetime">Date-Time</ion-select-option>--> <ion-select-option value="datetime">Date-Time</ion-select-option>
<!-- <ion-select-option value="multiselect">Multi-Select</ion-select-option>--> <ion-select-option value="currency">Currency</ion-select-option>
<ion-select-option value="index">Incrementing Index</ion-select-option>
<!-- <ion-select-option value="person">Person</ion-select-option>--> <!-- <ion-select-option value="person">Person</ion-select-option>-->
<!-- <ion-select-option value="url">URL</ion-select-option>--> <!-- <ion-select-option value="url">URL</ion-select-option>-->
<!-- <ion-select-option value="email">E-Mail</ion-select-option>--> <!-- <ion-select-option value="email">E-Mail</ion-select-option>-->
</ion-select> </ion-select>
</ion-item> </ion-item>
</ion-col> </ion-col>
<ion-col size="2" align-items-center> <ion-col size="3" align-items-center>
<ion-row>
<ion-button fill="outline" color="light" (click)="onDeleteClick(i)"> <ion-button fill="outline" color="light" (click)="onDeleteClick(i)">
<ion-icon color="danger" name="trash"></ion-icon> <ion-icon color="danger" name="trash"></ion-icon>
</ion-button> </ion-button>
</ion-row>
<ion-row>
<ion-button fill="outline" color="light" size="small" (click)="onUpArrow(i)">
<ion-icon color="dark" name="arrow-up"></ion-icon>
</ion-button>
<ion-button fill="outline" color="light" size="small" (click)="onDownArrow(i)">
<ion-icon color="dark" name="arrow-down"></ion-icon>
</ion-button>
</ion-row>
</ion-col> </ion-col>
<ion-col size="5" *ngIf="columnSets[i].Type === 'boolean'"> <ion-col size="5" *ngIf="columnSets[i].Type === 'boolean'">
<ion-item> <ion-item>
@ -54,7 +65,7 @@
</ion-select> </ion-select>
</ion-item> </ion-item>
</ion-col> </ion-col>
<ion-col size="12" *ngIf="columnSets[i].Type === 'select'"> <ion-col size="12" *ngIf="columnSets[i].Type === 'select' || columnSets[i].Type === 'multiselect'">
<ion-button (click)="onAddOption(i)" fill="outline">Add Option</ion-button> <ion-button (click)="onAddOption(i)" fill="outline">Add Option</ion-button>
<ng-container *ngIf="columnSets[i].additionalData.options"> <ng-container *ngIf="columnSets[i].additionalData.options">
<ion-row *ngFor="let option of columnSets[i].additionalData.options; let n = index"> <ion-row *ngFor="let option of columnSets[i].additionalData.options; let n = index">
@ -65,13 +76,45 @@
</ion-item> </ion-item>
</ion-col> </ion-col>
<ion-col size="2"> <ion-col size="2">
<ion-button fill="outline" color="light" (click)="onDeleteOptionClick(i, n)"> <ion-button fill="outline" color="light" size="small" (click)="onDeleteOptionClick(i, n)">
<ion-icon color="danger" name="trash"></ion-icon> <ion-icon color="danger" name="trash"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>
</ng-container> </ng-container>
</ion-col> </ion-col>
<ion-col size="12" *ngIf="columnSets[i].Type === 'datetime'">
<ion-list>
<ion-radio-group value="YYYY-MM-DD h:mm a" [(ngModel)]="columnSets[i].additionalData.format">
<ion-list-header>Format</ion-list-header>
<ion-item>
<ion-label>Date Only</ion-label>
<ion-radio slot="start" value="YYYY-MM-DD"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Time Only</ion-label>
<ion-radio slot="start" value="h:mm a"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Both</ion-label>
<ion-radio slot="start" value="YYYY-MM-DD h:mm a"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
</ion-col>
<ion-col size="12" *ngIf="columnSets[i].Type === 'currency'">
<ion-item>
<ion-label position="floating">Currency</ion-label>
<ion-select [(ngModel)]="columnSets[i].additionalData.currency">
<ion-select-option value="USD">US Dollar</ion-select-option>
<ion-select-option value="EUR">Euro</ion-select-option>
<ion-select-option value="MXN">Mexican Peso</ion-select-option>
<ion-select-option value="CNY">Chinese Yuan</ion-select-option>
<ion-select-option value="XAG">Silver</ion-select-option>
<ion-select-option value="XAU">Gold</ion-select-option>
</ion-select>
</ion-item>
</ion-col>
</ion-row> </ion-row>
</ion-grid> </ion-grid>
</ion-content> </ion-content>

View File

@ -52,4 +52,20 @@ export class ColumnsComponent implements OnInit {
this.columnSets = newSets; this.columnSets = newSets;
} }
onUpArrow(i) {
if ( this.columnSets[i - 1] ) {
const temp = this.columnSets[i];
this.columnSets[i] = this.columnSets[i - 1];
this.columnSets[i - 1] = temp;
}
}
onDownArrow(i) {
if ( this.columnSets[i + 1] ) {
const temp = this.columnSets[i];
this.columnSets[i] = this.columnSets[i + 1];
this.columnSets[i + 1] = temp;
}
}
} }

View File

@ -9,6 +9,11 @@ import {NumericEditorComponent} from './editors/numeric/numeric-editor.component
import {ParagraphEditorComponent} from './editors/paragraph/paragraph-editor.component'; import {ParagraphEditorComponent} from './editors/paragraph/paragraph-editor.component';
import {BooleanEditorComponent} from './editors/boolean/boolean-editor.component'; import {BooleanEditorComponent} from './editors/boolean/boolean-editor.component';
import {SelectEditorComponent} from './editors/select/select-editor.component'; import {SelectEditorComponent} from './editors/select/select-editor.component';
import {MultiSelectEditorComponent} from './editors/select/multiselect-editor.component';
import {DatetimeEditorComponent} from './editors/datetime/datetime-editor.component';
import {DatetimeRendererComponent} from './renderers/datetime-renderer.component';
import {CurrencyRendererComponent} from './renderers/currency-renderer.component';
import {BooleanRendererComponent} from './renderers/boolean-renderer.component';
@Component({ @Component({
selector: 'editor-database', selector: 'editor-database',
@ -74,7 +79,7 @@ export class DatabaseComponent implements OnInit {
this.setColumns(result.data).subscribe(() => { this.setColumns(result.data).subscribe(() => {
const endpoint = `/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/set/${this.hostRecord.Value.Value}/columns` const endpoint = `/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/set/${this.hostRecord.Value.Value}/columns`
this.api.post(endpoint, {columns: this.columnDefs}).subscribe(res => { this.api.post(endpoint, {columns: this.columnDefs}).subscribe(res => {
// this.columnDefs = res.data; this.requestParentSave.emit(this);
}); });
}); });
} }
@ -208,15 +213,28 @@ export class DatabaseComponent implements OnInit {
} else if ( x.Type === 'paragraph' ) { } else if ( x.Type === 'paragraph' ) {
x.cellEditorFramework = ParagraphEditorComponent; x.cellEditorFramework = ParagraphEditorComponent;
} else if ( x.Type === 'boolean' ) { } else if ( x.Type === 'boolean' ) {
x.cellRendererFramework = BooleanRendererComponent;
x.cellEditorFramework = BooleanEditorComponent; x.cellEditorFramework = BooleanEditorComponent;
} else if ( x.Type === 'select' ) { } else if ( x.Type === 'select' ) {
x.cellEditorFramework = SelectEditorComponent; x.cellEditorFramework = SelectEditorComponent;
} else if ( x.Type === 'multiselect' ) {
x.cellEditorFramework = MultiSelectEditorComponent;
} else if ( x.Type === 'datetime' ) {
x.cellEditorFramework = DatetimeEditorComponent;
x.cellRendererFramework = DatetimeRendererComponent;
} else if ( x.Type === 'currency' ) {
x.cellEditorFramework = NumericEditorComponent;
x.cellRendererFramework = CurrencyRendererComponent;
} else if ( x.Type === 'index' ) {
x.editable = false;
} }
console.log({x}); console.log({x});
return x; return x;
}); });
this.agGridElement.api.setColumnDefs(this.columnDefs);
sub.next(); sub.next();
sub.complete(); sub.complete();
}); });

View File

@ -4,7 +4,7 @@ import {ICellEditorParams} from 'ag-grid-community';
@Component({ @Component({
selector: 'cell-editor-paragraph', selector: 'cell-editor-paragraph',
template: `<input #input [(ngModel)]="value" readonly (click)="onClick()">`, template: `<input #input [value]="display" readonly (click)="onClick()">`,
styles: [ styles: [
`input { `input {
width: 100%; width: 100%;
@ -14,7 +14,17 @@ import {ICellEditorParams} from 'ag-grid-community';
}) })
export class BooleanEditorComponent implements ICellEditorAngularComp, AfterViewInit { export class BooleanEditorComponent implements ICellEditorAngularComp, AfterViewInit {
private params: ICellEditorParams; private params: ICellEditorParams;
public value: string; public value: boolean;
public get display() {
if ( typeof this.value === 'undefined' ) {
return this.emptyValue;
} else if ( this.value ) {
return this.trueValue;
} else {
return this.falseValue;
}
}
protected trueValue = 'True'; protected trueValue = 'True';
protected falseValue = 'False'; protected falseValue = 'False';
@ -42,12 +52,12 @@ export class BooleanEditorComponent implements ICellEditorAngularComp, AfterView
} }
onClick() { onClick() {
if ( this.value === this.trueValue ) { if ( this.value === true ) {
this.value = this.falseValue; this.value = false;
} else if ( this.value === this.falseValue ) { } else if ( this.value === false ) {
this.value = this.emptyValue; this.value = undefined;
} else { } else {
this.value = this.trueValue; this.value = true;
} }
} }
} }

View File

@ -0,0 +1,33 @@
import {ICellEditorAngularComp} from 'ag-grid-angular';
import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {ICellEditorParams} from 'ag-grid-community';
import {IonDatetime} from '@ionic/angular';
@Component({
selector: 'cell-editor-select',
template: `<ion-datetime #picker [displayFormat]="format" [(ngModel)]="value" style="padding: 0 0 0 5px;"></ion-datetime>`,
})
export class DatetimeEditorComponent implements ICellEditorAngularComp, AfterViewInit {
public params: ICellEditorParams;
public value: string;
public format = 'YYYY-MM-DD h:mm a';
@ViewChild('picker', {static: false}) picker: IonDatetime;
agInit(params: ICellEditorParams): void {
this.params = params;
this.value = this.params.value;
// @ts-ignore
if ( this.params.colDef.additionalData.format ) {
// @ts-ignore
this.format = this.params.colDef.additionalData.format;
}
}
getValue(): any {
return this.value;
}
ngAfterViewInit(): void {
this.picker.open();
}
}

View File

@ -43,6 +43,10 @@ export class ParagraphEditorComponent implements ICellEditorAngularComp, AfterVi
} }
}).then(modal => { }).then(modal => {
modal.onDidDismiss().then(value => { modal.onDidDismiss().then(value => {
if ( typeof value.data === 'undefined' ) {
return;
}
this.value = String(value.data); this.value = String(value.data);
}); });
modal.present(); modal.present();

View File

@ -0,0 +1,36 @@
import {ICellEditorAngularComp} from 'ag-grid-angular';
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
import {ICellEditorParams} from 'ag-grid-community';
import {IonSelect} from '@ionic/angular';
@Component({
selector: 'cell-editor-multiselect',
template: `
<ion-select #select [(ngModel)]="value" style="padding: 0;"
[interfaceOptions]="{header: params.colDef.headerName, cssClass: 'big-alert'}" multiple="true">
<ion-select-option *ngFor="let option of options" [value]="option.value">{{ option.value }}</ion-select-option>
</ion-select>
`,
})
export class MultiSelectEditorComponent implements ICellEditorAngularComp, AfterViewInit {
public params: ICellEditorParams;
public value: string;
public options: Array<{value: string}> = [];
@ViewChild('select', {static: false}) select: IonSelect;
agInit(params: ICellEditorParams): void {
this.params = params;
this.value = this.params.value;
// @ts-ignore
this.options = this.params.colDef.additionalData.options;
}
getValue(): any {
return this.value;
}
ngAfterViewInit(): void {
this.select.open();
}
}

View File

@ -4,19 +4,13 @@ import {ICellEditorParams} from 'ag-grid-community';
import {IonSelect} from '@ionic/angular'; import {IonSelect} from '@ionic/angular';
@Component({ @Component({
selector: 'cell-editor-paragraph', selector: 'cell-editor-select',
template: ` template: `
<ion-select #select [(ngModel)]="value" style="padding: 0;" <ion-select #select [(ngModel)]="value" style="padding: 0;"
[interfaceOptions]="{header: params.colDef.headerName, cssClass: 'big-alert'}"> [interfaceOptions]="{header: params.colDef.headerName, cssClass: 'big-alert'}">
<ion-select-option *ngFor="let option of options" [value]="option.value">{{ option.value }}</ion-select-option> <ion-select-option *ngFor="let option of options" [value]="option.value">{{ option.value }}</ion-select-option>
</ion-select> </ion-select>
`, `,
styles: [
`input {
width: 100%;
border: 1px solid grey;
}`
],
}) })
export class SelectEditorComponent implements ICellEditorAngularComp, AfterViewInit { export class SelectEditorComponent implements ICellEditorAngularComp, AfterViewInit {
public params: ICellEditorParams; public params: ICellEditorParams;

View File

@ -0,0 +1,37 @@
import {ICellRendererAngularComp} from 'ag-grid-angular';
import {Component} from '@angular/core';
import {ICellRendererParams} from 'ag-grid-community';
import * as moment from 'moment';
@Component({
selector: 'editor-boolean-renderer',
template: `{{ display }}`,
})
export class BooleanRendererComponent implements ICellRendererAngularComp {
public params: ICellRendererParams;
public emptyValue = '';
public trueValue = 'True';
public falseValue = 'False';
agInit(params: ICellRendererParams): void {
this.params = params;
// @ts-ignore
const labelType = params.colDef.additionalData.labelType.split('_').map(x => x.charAt(0).toUpperCase() + x.slice(1));
this.trueValue = labelType[0];
this.falseValue = labelType[1];
}
public get display() {
if ( this.params.value === true ) {
return this.trueValue;
} else if ( this.params.value === false ) {
return this.falseValue;
} else {
return this.emptyValue;
}
}
refresh(params: any): boolean {
return false;
}
}

View File

@ -0,0 +1,23 @@
import {ICellRendererAngularComp} from 'ag-grid-angular';
import {Component} from '@angular/core';
import {ICellRendererParams} from 'ag-grid-community';
import * as moment from 'moment';
@Component({
selector: 'editor-currency-renderer',
template: `{{ params.value | currency: code }}`,
})
export class CurrencyRendererComponent implements ICellRendererAngularComp {
public params: ICellRendererParams;
public code = 'USD';
agInit(params: ICellRendererParams): void {
this.params = params;
// @ts-ignore
this.code = params.colDef.additionalData.currency;
}
refresh(params: any): boolean {
return false;
}
}

View File

@ -0,0 +1,30 @@
import {ICellRendererAngularComp} from 'ag-grid-angular';
import {Component} from '@angular/core';
import {ICellRendererParams} from 'ag-grid-community';
import * as moment from 'moment';
@Component({
selector: 'editor-datetime-renderer',
template: `{{ display }}`,
})
export class DatetimeRendererComponent implements ICellRendererAngularComp {
public params: ICellRendererParams;
public format = 'YYYY-MM-DD h:mm a';
agInit(params: ICellRendererParams): void {
this.params = params;
// @ts-ignore
this.format = params.colDef.additionalData.format;
}
public get display() {
if ( !this.params.value ) {
return '';
}
return moment(this.params.value).format(this.format);
}
refresh(params: any): boolean {
return false;
}
}

View File

@ -28,3 +28,8 @@
@import "~angular-tree-component/dist/angular-tree-component.css"; @import "~angular-tree-component/dist/angular-tree-component.css";
@import "~ag-grid-community/dist/styles/ag-grid.css"; @import "~ag-grid-community/dist/styles/ag-grid.css";
@import "~ag-grid-community/dist/styles/ag-theme-balham.css"; @import "~ag-grid-community/dist/styles/ag-theme-balham.css";
div.picker-wrapper {
border: 2px solid lightgrey !important;
border-radius: 7px !important;
}