import {Component, Input, OnInit, ViewChild} from '@angular/core'; import {ApiService, ResourceNotAvailableOfflineError} from '../../../service/api.service'; import {AlertController, LoadingController, ModalController} from '@ionic/angular'; import {ColumnsComponent} from './columns/columns.component'; import {AgGridAngular} from 'ag-grid-angular'; import {NumericEditorComponent} from './editors/numeric/numeric-editor.component'; import {ParagraphEditorComponent} from './editors/paragraph/paragraph-editor.component'; import {BooleanEditorComponent} from './editors/boolean/boolean-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'; import {EditorNodeContract} from '../../nodes/EditorNode.contract'; import {EditorService} from '../../../service/editor.service'; @Component({ selector: 'editor-database', templateUrl: './database.component.html', styleUrls: ['./database.component.scss'], }) export class DatabaseComponent extends EditorNodeContract implements OnInit { @Input() nodeId: string; @Input() editorUUID?: string; @ViewChild('agGridElement') agGridElement: AgGridAngular; public dbRecord: any; public pendingSetup = true; public dirty = false; public lastClickRow = -1; public dbName = ''; public notAvailableOffline = false; protected dbId!: string; title = 'app'; columnDefs = []; rowData = []; public isDark() { return document.body.classList.contains('dark'); } public get readonly() { return !this.node || !this.editorService.canEdit(); } constructor( protected api: ApiService, protected modals: ModalController, protected alerts: AlertController, protected loader: LoadingController, public editorService: EditorService, ) { super(); } public isDirty(): boolean | Promise { return this.dirty; } public needsSave(): boolean | Promise { return this.dirty; } public needsLoad(): boolean | Promise { return this.node && this.pendingSetup; } public writeChangesToNode(): void | Promise { this.node.Value.Mode = 'database'; } ngOnInit() { this.editorService = this.editorService.getEditor(this.editorUUID); this.editorService.registerNodeEditor(this.nodeId, this).then(() => { console.log('database editor', this); }); } onCellValueChanged() { this.dirty = true; this.editorService.triggerSave(); } async onManageColumns() { if ( this.readonly ) { return; } const modal = await this.modals.create({ component: ColumnsComponent, componentProps: {columnSets: this.columnDefs}, }); modal.onDidDismiss().then(result => { this.setColumns(result.data); }); await modal.present(); } onInsertRow() { if ( this.readonly ) { return; } this.rowData.push({}); this.agGridElement.api.setRowData(this.rowData); this.dirty = true; this.editorService.triggerSave(); } async onRemoveRow() { if ( this.readonly ) { return; } const alert = await this.alerts.create({ header: 'Are you sure?', message: `You are about to delete row ${this.lastClickRow + 1}. This cannot be undone.`, buttons: [ { text: 'Keep It', role: 'cancel', }, { text: 'Delete It', handler: () => { this.rowData = this.rowData.filter((x, i) => { return i !== this.lastClickRow; }); this.agGridElement.api.setRowData(this.rowData); this.lastClickRow = -1; this.dirty = true; this.editorService.triggerSave(); }, } ], }); await alert.present(); } onRowClicked($event) { this.lastClickRow = $event.rowIndex; } setColumns(data) { this.columnDefs = data.map(x => { x.editable = !this.readonly; // Set editors and renderers for different types if ( x.Type === 'text' ) { x.editor = 'agTextCellEditor'; } else if ( x.Type === 'number' ) { x.cellEditorFramework = NumericEditorComponent; } else if ( x.Type === 'paragraph' ) { x.cellEditorFramework = ParagraphEditorComponent; } else if ( x.Type === 'boolean' ) { x.cellRendererFramework = BooleanRendererComponent; x.cellEditorFramework = BooleanEditorComponent; } else if ( x.Type === 'select' ) { 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; } return x; }); this.agGridElement.api.setColumnDefs(this.columnDefs); this.dirty = true; this.editorService.triggerSave(); } public async performLoad(): Promise { if ( !this.node.Value ) { this.node.Value = {}; } // Load the database record itself if ( !this.node.Value.Value && this.editorService.canEdit() ) { this.dbRecord = await this.api.createDatabase(this.page.UUID, this.node.UUID); this.dbName = this.dbRecord.Name; this.node.Value.Mode = 'database'; this.node.Value.Value = this.dbRecord.UUID; this.node.value = this.dbRecord.UUID; } else { try { this.dbRecord = await this.api.getDatabase(this.page.UUID, this.node.UUID, this.node.Value.Value); this.dbName = this.dbRecord.Name; this.notAvailableOffline = false; } catch (e: unknown) { if ( e instanceof ResourceNotAvailableOfflineError ) { this.notAvailableOffline = true; } else { throw e; } } } // Load the columns const columns = await this.api.getDatabaseColumns(this.page.UUID, this.node.UUID, this.node.Value.Value); this.setColumns(columns); const rows = await this.api.getDatabaseEntries(this.page.UUID, this.node.UUID, this.node.Value.Value); this.rowData = rows.map(x => x.RowData); this.agGridElement.api.setRowData(this.rowData); this.pendingSetup = false; this.dirty = false; } public async performDelete(): Promise { await this.api.deleteDatabase(this.page.UUID, this.node.UUID, this.node.Value.Value); } public async performSave(): Promise { // Save the columns first await this.api.saveDatabaseColumns(this.page.UUID, this.node.UUID, this.node.Value.Value, this.columnDefs); // Save the data const rows = await this.api.saveDatabaseEntries(this.page.UUID, this.node.UUID, this.node.Value.Value, this.rowData); this.rowData = rows.map(x => x.RowData); this.agGridElement.api.setRowData(this.rowData); // Save the name await this.api.saveDatabaseName(this.page.UUID, this.node.UUID, this.node.Value.Value, this.dbName); this.dirty = false; } }