From 791b50b89367590b5af8441786860a02bc40dbb4 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 17 Oct 2023 19:23:02 -0500 Subject: [PATCH] Redo export buttons as JSX Elements that get passed into Widget.tsx, rather than "Component" objects. something to do with when things are getting bound, was making the export buttons never have data. This was done with labelAdditionalElementsLeft, similar to labelAdditionalComponentsLeft. In theory, maybe, this is better, and we should remove all the additionalComponents left & right... --- src/qqq/components/widgets/Widget.tsx | 85 ++++--------------- .../widgets/misc/RecordGridWidget.tsx | 81 ++++++++++++------ .../components/widgets/tables/TableWidget.tsx | 43 +++++++--- 3 files changed, 105 insertions(+), 104 deletions(-) diff --git a/src/qqq/components/widgets/Widget.tsx b/src/qqq/components/widgets/Widget.tsx index da59312..66e749d 100644 --- a/src/qqq/components/widgets/Widget.tsx +++ b/src/qqq/components/widgets/Widget.tsx @@ -30,7 +30,7 @@ import Tooltip from "@mui/material/Tooltip/Tooltip"; import Typography from "@mui/material/Typography"; import parse from "html-react-parser"; import React, {useEffect, useState} from "react"; -import {Link, NavigateFunction, useNavigate} from "react-router-dom"; +import {NavigateFunction, useNavigate} from "react-router-dom"; import colors from "qqq/components/legacy/colors"; import DropdownMenu, {DropdownOption} from "qqq/components/widgets/components/DropdownMenu"; @@ -46,6 +46,7 @@ export interface WidgetData dropdownNeedsSelectedText?: string; hasPermission?: boolean; errorLoading?: boolean; + [other: string]: any; } @@ -53,6 +54,7 @@ export interface WidgetData interface Props { labelAdditionalComponentsLeft: LabelComponent[]; + labelAdditionalElementsLeft: JSX.Element[]; labelAdditionalComponentsRight: LabelComponent[]; widgetMetaData?: QWidgetMetaData; widgetData?: WidgetData; @@ -70,6 +72,7 @@ Widget.defaultProps = { widgetMetaData: {}, widgetData: {}, labelAdditionalComponentsLeft: [], + labelAdditionalElementsLeft: [], labelAdditionalComponentsRight: [], }; @@ -88,34 +91,8 @@ export class LabelComponent { render = (args: LabelComponentRenderArgs): JSX.Element => { - return (
Unsupported component type
) - } -} - - -/******************************************************************************* - ** - *******************************************************************************/ -export class HeaderLink extends LabelComponent -{ - label: string; - to: string - - constructor(label: string, to: string) - { - super(); - this.label = label; - this.to = to; - } - - render = (args: LabelComponentRenderArgs): JSX.Element => - { - return ( - - {this.to ? {this.label} : null} - - ); - } + return (
Unsupported component type
); + }; } @@ -141,8 +118,8 @@ export class AddNewRecordButton extends LabelComponent openEditForm = (navigate: any, table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any) => { - navigate(`#/createChild=${table.name}/defaultValues=${JSON.stringify(defaultValues)}/disabledFields=${JSON.stringify(disabledFields)}`) - } + navigate(`#/createChild=${table.name}/defaultValues=${JSON.stringify(defaultValues)}/disabledFields=${JSON.stringify(disabledFields)}`); + }; render = (args: LabelComponentRenderArgs): JSX.Element => { @@ -151,35 +128,7 @@ export class AddNewRecordButton extends LabelComponent ); - } -} - - -/******************************************************************************* - ** - *******************************************************************************/ -export class ExportDataButton extends LabelComponent -{ - callbackToExport: any; - tooltipTitle: string; - isDisabled: boolean; - - constructor(callbackToExport: any, isDisabled = false, tooltipTitle: string = "Export") - { - super(); - this.callbackToExport = callbackToExport; - this.isDisabled = isDisabled; - this.tooltipTitle = tooltipTitle; - } - - render = (args: LabelComponentRenderArgs): JSX.Element => - { - return ( - - - - ); - } + }; } @@ -227,7 +176,7 @@ export class Dropdown extends LabelComponent /> ); - } + }; } @@ -251,7 +200,7 @@ export class ReloadControl extends LabelComponent ); - } + }; } @@ -372,7 +321,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element if (index < 0) { - throw(`Could not find table name for label ${tableName}`); + throw (`Could not find table name for label ${tableName}`); } dropdownData[index] = (changedData) ? changedData.id : null; @@ -394,7 +343,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element } } - reloadWidget(dropdownData) + reloadWidget(dropdownData); } } @@ -422,7 +371,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element { console.log(`No reload widget callback in ${props.widgetMetaData.label}`); } - } + }; const toggleFullScreenWidget = () => { @@ -434,14 +383,14 @@ function Widget(props: React.PropsWithChildren): JSX.Element { setFullScreenWidgetClassName("fullScreenWidget"); } - } + }; const hasPermission = props.widgetData?.hasPermission === undefined || props.widgetData?.hasPermission === true; const isSet = (v: any): boolean => { return (v !== null && v !== undefined); - } + }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // to avoid taking up the space of the Box with the label and icon and label-components (since it has a height), only output that box if we need any of the components // @@ -450,6 +399,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element if (hasPermission) { needLabelBox ||= (labelComponentsLeft && labelComponentsLeft.length > 0); + needLabelBox ||= (props.labelAdditionalElementsLeft && props.labelAdditionalElementsLeft.length > 0); needLabelBox ||= (labelComponentsRight && labelComponentsRight.length > 0); needLabelBox ||= isSet(props.widgetMetaData?.icon); needLabelBox ||= isSet(props.widgetData?.label); @@ -530,6 +480,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element }) ) } + {props.labelAdditionalElementsLeft} { diff --git a/src/qqq/components/widgets/misc/RecordGridWidget.tsx b/src/qqq/components/widgets/misc/RecordGridWidget.tsx index 6f02ba8..1f97113 100644 --- a/src/qqq/components/widgets/misc/RecordGridWidget.tsx +++ b/src/qqq/components/widgets/misc/RecordGridWidget.tsx @@ -22,10 +22,14 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData"; import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord"; +import Button from "@mui/material/Button"; +import Icon from "@mui/material/Icon"; +import Tooltip from "@mui/material/Tooltip/Tooltip"; +import Typography from "@mui/material/Typography"; import {DataGridPro, GridCallbackDetails, GridRowParams, MuiEvent} from "@mui/x-data-grid-pro"; import React, {useEffect, useState} from "react"; -import {useNavigate} from "react-router-dom"; -import Widget, {AddNewRecordButton, ExportDataButton, HeaderLink, LabelComponent} from "qqq/components/widgets/Widget"; +import {useNavigate, Link} from "react-router-dom"; +import Widget, {AddNewRecordButton, LabelComponent} from "qqq/components/widgets/Widget"; import DataGridUtils from "qqq/utils/DataGridUtils"; import HtmlUtils from "qqq/utils/HtmlUtils"; import Client from "qqq/utils/qqq/Client"; @@ -47,6 +51,8 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element const [records, setRecords] = useState([] as QRecord[]) const [columns, setColumns] = useState([]); const [allColumns, setAllColumns] = useState([]) + const [csv, setCsv] = useState(null as string); + const [fileName, setFileName] = useState(null as string); const navigate = useNavigate(); useEffect(() => @@ -75,6 +81,7 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // capture all-columns to use for the export (before we might splice some away from the on-screen display) // ///////////////////////////////////////////////////////////////////////////////////////////////////////////// + const allColumns = [... columns]; setAllColumns(JSON.parse(JSON.stringify(columns))); //////////////////////////////////////////////////////////////// @@ -95,39 +102,42 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element setRows(rows); setRecords(records) setColumns(columns); - } - }, [data]); - const exportCallback = () => - { - let csv = ""; - for (let i = 0; i < allColumns.length; i++) - { - csv += `${i > 0 ? "," : ""}"${ValueUtils.cleanForCsv(allColumns[i].headerName)}"` - } - csv += "\n"; - - for (let i = 0; i < records.length; i++) - { - for (let j = 0; j < allColumns.length; j++) + let csv = ""; + for (let i = 0; i < allColumns.length; i++) { - const value = records[i].displayValues.get(allColumns[j].field) ?? records[i].values.get(allColumns[j].field) - csv += `${j > 0 ? "," : ""}"${ValueUtils.cleanForCsv(value)}"` + csv += `${i > 0 ? "," : ""}"${ValueUtils.cleanForCsv(allColumns[i].headerName)}"` } csv += "\n"; - } - const fileName = (data?.label ?? widgetMetaData.label) + " " + ValueUtils.formatDateTimeForFileName(new Date()) + ".csv"; - HtmlUtils.download(fileName, csv); - } + for (let i = 0; i < records.length; i++) + { + for (let j = 0; j < allColumns.length; j++) + { + const value = records[i].displayValues.get(allColumns[j].field) ?? records[i].values.get(allColumns[j].field) + csv += `${j > 0 ? "," : ""}"${ValueUtils.cleanForCsv(value)}"` + } + csv += "\n"; + } + + const fileName = (data?.label ?? widgetMetaData.label) + " " + ValueUtils.formatDateTimeForFileName(new Date()) + ".csv"; + + setCsv(csv); + setFileName(fileName); + } + }, [data]); /////////////////// // view all link // /////////////////// - const labelAdditionalComponentsLeft: LabelComponent[] = [] + const labelAdditionalElementsLeft: JSX.Element[] = []; if(data && data.viewAllLink) { - labelAdditionalComponentsLeft.push(new HeaderLink("View All", data.viewAllLink)); + labelAdditionalElementsLeft.push( + + View All + + ) } /////////////////// @@ -149,7 +159,26 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element } } - labelAdditionalComponentsLeft.push(new ExportDataButton(() => exportCallback(), isExportDisabled, tooltipTitle)) + const onExportClick = () => + { + if(csv) + { + HtmlUtils.download(fileName, csv); + } + else + { + alert("There is no data available to export.") + } + } + + if(widgetMetaData?.showExportButton) + { + labelAdditionalElementsLeft.push( + + + + ); + } //////////////////// // add new button // @@ -184,7 +213,7 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element - { if (props.widgetData && rows && columns) { - console.log(props.widgetData); - let csv = ""; for (let j = 0; j < columns.length; j++) { @@ -98,16 +98,37 @@ function TableWidget(props: Props): JSX.Element csv += "\n"; } - console.log(csv); + setCsv(csv); const fileName = (props.widgetData.label ?? props.widgetMetaData.label) + " " + ValueUtils.formatDateTimeForFileName(new Date()) + ".csv"; + setFileName(fileName) + + console.log(`useEffect, setting fileName ${fileName}`); + } + + }, [props.widgetMetaData, props.widgetData]); + + const onExportClick = () => + { + if(csv) + { HtmlUtils.download(fileName, csv); } else { - alert("There is no data available to export."); + alert("There is no data available to export.") } - }; + } + + const labelAdditionalElementsLeft: JSX.Element[] = []; + if(props.widgetMetaData?.showExportButton) + { + labelAdditionalElementsLeft.push( + + + + ); + } return ( props.reloadWidgetCallback(data)} footerHTML={props.widgetData?.footerHTML} isChild={props.isChild} - labelAdditionalComponentsLeft={props.widgetMetaData?.showExportButton ? [new ExportDataButton(() => exportCallback(), isExportDisabled)] : []} + labelAdditionalElementsLeft={labelAdditionalElementsLeft} >