/* * QQQ - Low-code Application Framework for Engineers. * Copyright (C) 2021-2022. Kingsrook, LLC * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States * contact@kingsrook.com * https://github.com/Kingsrook/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {GridPinnedColumns} from "@mui/x-data-grid-pro"; import quickSightChart from "qqq/components/widgets/misc/QuickSightChart"; import DataGridUtils from "qqq/utils/DataGridUtils"; import TableUtils from "qqq/utils/qqq/TableUtils"; /******************************************************************************* ** member object *******************************************************************************/ interface Column { name: string; isVisible: boolean; width: number; pinned?: "left" | "right"; } /******************************************************************************* ** Model for all info we'll store about columns on a query screen. *******************************************************************************/ export default class QQueryColumns { columns: Column[] = []; /******************************************************************************* ** factory function - build a QQueryColumns object from JSON (string or parsed object). ** ** input json is must look like if you JSON.stringify this class - that is: ** {columns: [{name:"",isVisible:true,width:0,pinned:"left"},{}...]} *******************************************************************************/ public static buildFromJSON = (json: string | any): QQueryColumns => { const queryColumns = new QQueryColumns(); if (typeof json == "string") { json = JSON.parse(json); } queryColumns.columns = json.columns; return (queryColumns); }; /******************************************************************************* ** factory function - build a default QQueryColumns object for a table ** *******************************************************************************/ public static buildDefaultForTable = (table: QTableMetaData): QQueryColumns => { const queryColumns = new QQueryColumns(); queryColumns.columns = []; queryColumns.columns.push({name: "__check__", isVisible: true, width: 100, pinned: "left"}); const fields = this.getSortedFieldsFromTable(table); fields.forEach((field) => { const column: Column = {name: field.name, isVisible: true, width: DataGridUtils.getColumnWidthForField(field, table)}; queryColumns.columns.push(column); if (field.name == table.primaryKeyField) { column.pinned = "left"; } }); table.exposedJoins?.forEach((exposedJoin) => { const joinFields = this.getSortedFieldsFromTable(exposedJoin.joinTable); joinFields.forEach((field) => { const column: Column = {name: `${exposedJoin.joinTable.name}.${field.name}`, isVisible: false, width: DataGridUtils.getColumnWidthForField(field, null)}; queryColumns.columns.push(column); }); }); return (queryColumns); }; /******************************************************************************* ** *******************************************************************************/ public addColumnForNewField = (table: QTableMetaData, fieldName: string, defaultVisibilityIfInMainTable: boolean): void => { const [field, tableForField] = TableUtils.getFieldAndTable(table, fieldName) let column: Column; if(tableForField.name == table.name) { column = {name: field.name, isVisible: defaultVisibilityIfInMainTable, width: DataGridUtils.getColumnWidthForField(field, table)}; } else { column = {name: `${tableForField.name}.${field.name}`, isVisible: false, width: DataGridUtils.getColumnWidthForField(field, null)}; } this.columns.push(column); } /******************************************************************************* ** *******************************************************************************/ public deleteColumnForOldField = (table: QTableMetaData, fieldName: string): void => { for (let i = 0; i < this.columns.length; i++) { if(this.columns[i].name == fieldName) { this.columns.splice(i, 1); return; } } console.log(`Couldn't find column to be deleted, for name [${fieldName}]`); } /******************************************************************************* ** *******************************************************************************/ private static getSortedFieldsFromTable(table: QTableMetaData) { const fields = [...table.fields.values()]; fields.sort((a: QFieldMetaData, b: QFieldMetaData) => { return a.name.localeCompare(b.name); }); return fields; } /******************************************************************************* ** *******************************************************************************/ public getVisibleColumnCount(): number { let rs = 0; for (let i = 0; i < this.columns.length; i++) { if(this.columns[i].name == "__check__") { continue; } if(this.columns[i].isVisible) { rs++; } } return (rs); } /******************************************************************************* ** *******************************************************************************/ public getVisibilityToggleStates(): { [name: string]: boolean } { const rs: {[name: string]: boolean} = {}; for (let i = 0; i < this.columns.length; i++) { rs[this.columns[i].name] = this.columns[i].isVisible; } return (rs); } /******************************************************************************* ** *******************************************************************************/ public setIsVisible(name: string, isVisible: boolean) { for (let i = 0; i < this.columns.length; i++) { if(this.columns[i].name == name) { this.columns[i].isVisible = isVisible; break; } } } /******************************************************************************* ** *******************************************************************************/ public updateVisibility = (visibilityModel: { [name: string]: boolean }): void => { for (let i = 0; i < this.columns.length; i++) { const name = this.columns[i].name; this.columns[i].isVisible = visibilityModel[name]; } }; /******************************************************************************* ** *******************************************************************************/ public updateColumnOrder = (names: string[]): void => { const newColumns: Column[] = []; const rest: Column[] = []; for (let i = 0; i < this.columns.length; i++) { const column = this.columns[i]; const index = names.indexOf(column.name); if (index > -1) { newColumns[index] = column; } else { rest.push(column); } } this.columns = [...newColumns, ...rest]; }; /******************************************************************************* ** *******************************************************************************/ public updateColumnWidth = (name: string, width: number): void => { for (let i = 0; i < this.columns.length; i++) { if (this.columns[i].name == name) { this.columns[i].width = width; } } }; /******************************************************************************* ** *******************************************************************************/ public setPinnedLeftColumns = (names: string[]): void => { const leftPins: Column[] = []; const rest: Column[] = []; for (let i = 0; i < this.columns.length; i++) { const column = this.columns[i]; const pinIndex = names ? names.indexOf(column.name) : -1; if (pinIndex > -1) { column.pinned = "left"; leftPins[pinIndex] = column; } else { if (column.pinned == "left") { column.pinned = undefined; } rest.push(column); } } this.columns = [...leftPins, ...rest]; }; /******************************************************************************* ** *******************************************************************************/ public setPinnedRightColumns = (names: string[]): void => { const rightPins: Column[] = []; const rest: Column[] = []; for (let i = 0; i < this.columns.length; i++) { const column = this.columns[i]; const pinIndex = names ? names.indexOf(column.name) : -1; if (pinIndex > -1) { column.pinned = "right"; rightPins[pinIndex] = column; } else { if (column.pinned == "right") { column.pinned = undefined; } rest.push(column); } } this.columns = [...rest, ...rightPins]; }; /******************************************************************************* ** *******************************************************************************/ public getColumnSortValues = (): { [name: string]: number } => { const sortValues: { [name: string]: number } = {}; for (let i = 0; i < this.columns.length; i++) { sortValues[this.columns[i].name] = i; } return sortValues; }; /******************************************************************************* ** *******************************************************************************/ public getColumnWidths = (): { [name: string]: number } => { const widths: { [name: string]: number } = {}; for (let i = 0; i < this.columns.length; i++) { const column = this.columns[i]; widths[column.name] = column.width; } return widths; }; /******************************************************************************* ** *******************************************************************************/ public toGridPinnedColumns = (): GridPinnedColumns => { const gridPinnedColumns: GridPinnedColumns = {left: [], right: []}; for (let i = 0; i < this.columns.length; i++) { const column = this.columns[i]; if (column.pinned == "left") { gridPinnedColumns.left.push(column.name); } else if (column.pinned == "right") { gridPinnedColumns.right.push(column.name); } } return gridPinnedColumns; }; /******************************************************************************* ** *******************************************************************************/ public toColumnVisibilityModel = (): { [index: string]: boolean } => { const columnVisibilityModel: { [index: string]: boolean } = {}; for (let i = 0; i < this.columns.length; i++) { const column = this.columns[i]; columnVisibilityModel[column.name] = column.isVisible; } return columnVisibilityModel; }; } /******************************************************************************* ** subclass of QQueryColumns - used as a marker, to indicate that the table ** isn't yet loaded, so it just a placeholder. *******************************************************************************/ export class PreLoadQueryColumns extends QQueryColumns { }