/* 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 {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData"; import {Skeleton} from "@mui/material"; import Box from "@mui/material/Box"; import Grid from "@mui/material/Grid"; import parse from "html-react-parser"; import React, {useContext, useEffect, useReducer, useState} from "react"; import {useLocation} from "react-router-dom"; import QContext from "QContext"; import MDTypography from "qqq/components/legacy/MDTypography"; import BarChart from "qqq/components/widgets/charts/barchart/BarChart"; import HorizontalBarChart from "qqq/components/widgets/charts/barchart/HorizontalBarChart"; import DefaultLineChart from "qqq/components/widgets/charts/linechart/DefaultLineChart"; import SmallLineChart from "qqq/components/widgets/charts/linechart/SmallLineChart"; import PieChart from "qqq/components/widgets/charts/piechart/PieChart"; import StackedBarChart from "qqq/components/widgets/charts/StackedBarChart"; import DataBagViewer from "qqq/components/widgets/misc/DataBagViewer"; import DividerWidget from "qqq/components/widgets/misc/Divider"; import FieldValueListWidget from "qqq/components/widgets/misc/FieldValueListWidget"; import QuickSightChart from "qqq/components/widgets/misc/QuickSightChart"; import RecordGridWidget from "qqq/components/widgets/misc/RecordGridWidget"; import ScriptViewer from "qqq/components/widgets/misc/ScriptViewer"; import StepperCard from "qqq/components/widgets/misc/StepperCard"; import USMapWidget from "qqq/components/widgets/misc/USMapWidget"; import ParentWidget from "qqq/components/widgets/ParentWidget"; import MultiStatisticsCard from "qqq/components/widgets/statistics/MultiStatisticsCard"; import StatisticsCard from "qqq/components/widgets/statistics/StatisticsCard"; import Widget, {WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT} from "qqq/components/widgets/Widget"; import ProcessRun from "qqq/pages/processes/ProcessRun"; import Client from "qqq/utils/qqq/Client"; import TableWidget from "./tables/TableWidget"; const qController = Client.getInstance(); interface Props { widgetMetaDataList: QWidgetMetaData[]; tableName?: string; entityPrimaryKey?: string; omitWrappingGridContainer: boolean; areChildren?: boolean childUrlParams?: string parentWidgetMetaData?: QWidgetMetaData } DashboardWidgets.defaultProps = { widgetMetaDataList: null, tableName: null, entityPrimaryKey: null, omitWrappingGridContainer: false, areChildren: false, childUrlParams: "", parentWidgetMetaData: null }; function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omitWrappingGridContainer, areChildren, childUrlParams, parentWidgetMetaData}: Props): JSX.Element { const location = useLocation(); const [widgetData, setWidgetData] = useState([] as any[]); const [widgetCounter, setWidgetCounter] = useState(0); const [, forceUpdate] = useReducer((x) => x + 1, 0); const [currentUrlParams, setCurrentUrlParams] = useState(null as string); const [haveLoadedParams, setHaveLoadedParams] = useState(false); const {accentColor} = useContext(QContext); useEffect(() => { setWidgetData([]); for (let i = 0; i < widgetMetaDataList.length; i++) { const widgetMetaData = widgetMetaDataList[i]; const urlParams = getQueryParams(widgetMetaData, null); setCurrentUrlParams(urlParams); setHaveLoadedParams(true); widgetData[i] = {}; (async () => { try { widgetData[i] = await qController.widget(widgetMetaData.name, urlParams); setWidgetData(widgetData); setWidgetCounter(widgetCounter + 1); if(widgetData[i]) { widgetData[i]["errorLoading"] = false; } } catch(e) { console.error(e); if(widgetData[i]) { widgetData[i]["errorLoading"] = true; } } forceUpdate(); })(); } }, [widgetMetaDataList]); const reloadWidget = async (index: number, data: string) => { (async() => { const urlParams = getQueryParams(widgetMetaDataList[index], data); setCurrentUrlParams(urlParams); widgetData[index] = {}; try { widgetData[index] = await qController.widget(widgetMetaDataList[index].name, urlParams); setWidgetCounter(widgetCounter + 1); setWidgetData(widgetData); if (widgetData[index]) { widgetData[index]["errorLoading"] = false; } } catch(e) { console.error(e); if (widgetData[index]) { widgetData[index]["errorLoading"] = true; } } forceUpdate(); })(); } function getQueryParams(widgetMetaData: QWidgetMetaData, extraParams: string): string { let paramMap = new Map(); ///////////////////////////////////////////////////////////////////////////// // see if local storage is used for any widget dropdowns, if so, look them // // up and append to the query string // ///////////////////////////////////////////////////////////////////////////// let thisWidgetHasDropdowns = widgetMetaData && widgetMetaData.storeDropdownSelections && widgetMetaData.dropdowns; let parentWidgetHasDropdowns = parentWidgetMetaData && parentWidgetMetaData.storeDropdownSelections && parentWidgetMetaData.dropdowns; if (thisWidgetHasDropdowns || parentWidgetHasDropdowns) { const metaDataToUse = (thisWidgetHasDropdowns) ? widgetMetaData : parentWidgetMetaData; for (let i = 0; i < metaDataToUse.dropdowns.length; i++) { const dropdownName = metaDataToUse.dropdowns[i].possibleValueSourceName; const localStorageKey = `${WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT}.${metaDataToUse.name}.${dropdownName}`; const json = JSON.parse(localStorage.getItem(localStorageKey)); if (json) { paramMap.set(dropdownName, json.id); } } } if(entityPrimaryKey) { paramMap.set("id", entityPrimaryKey); } if(tableName) { paramMap.set("tableName", tableName); } if(extraParams) { let pairs = extraParams.split("&"); for (let i = 0; i < pairs.length; i++) { let nameValue = pairs[i].split("="); if(nameValue.length == 2) { paramMap.set(nameValue[0], nameValue[1]); } } } if(childUrlParams) { let pairs = childUrlParams.split("&"); for (let i = 0; i < pairs.length; i++) { let nameValue = pairs[i].split("="); if(nameValue.length == 2) { paramMap.set(nameValue[0], nameValue[1]); } } } let paramsFromMap = ""; for (let key of paramMap.keys()) { paramsFromMap += `${key}=${paramMap.get(key)}&`; } return paramsFromMap; } const widgetCount = widgetMetaDataList ? widgetMetaDataList.length : 0; const renderWidget = (widgetMetaData: QWidgetMetaData, i: number): JSX.Element => { return ( { haveLoadedParams && widgetMetaData.type === "parentWidget" && ( ) } { widgetMetaData.type === "usaMap" && ( ) } { widgetMetaData.type === "table" && ( reloadWidget(i, data)} isChild={areChildren} /> ) } { widgetMetaData.type === "stackedBarChart" && ( reloadWidget(i, data)} isChild={areChildren} > ) } { widgetMetaData.type === "process" && widgetData[i]?.processMetaData && ( reloadWidget(i, data)} showReloadControl={false} >
) } { widgetMetaData.type === "stepper" && ( reloadWidget(i, data)} > ) } { widgetMetaData.type === "html" && ( reloadWidget(i, data)} widgetData={widgetData[i]} > { widgetData && widgetData[i] && widgetData[i].html ? ( parse(widgetData[i].html) ) : } ) } { widgetMetaData.type === "smallLineChart" && ( ) } { widgetMetaData.type === "statistics" && ( reloadWidget(i, data)} > ) } { widgetMetaData.type === "multiStatistics" && ( ) } { widgetMetaData.type === "quickSightChart" && ( ) } { widgetMetaData.type === "barChart" && ( ) } { widgetMetaData.type === "pieChart" && ( reloadWidget(i, data)} isChild={areChildren} >
) } { widgetMetaData.type === "divider" && ( ) } { widgetMetaData.type === "horizontalBarChart" && ( ) } { widgetMetaData.type === "lineChart" && ( reloadWidget(i, data)} isChild={areChildren} > ) } { widgetMetaData.type === "childRecordList" && ( widgetData && widgetData[i] && ) } { widgetMetaData.type === "fieldValueList" && ( widgetData && widgetData[i] && reloadWidget(i, data)} /> ) } { widgetMetaData.type === "dataBagViewer" && ( widgetData && widgetData[i] && widgetData[i].queryParams && ) } { widgetMetaData.type === "scriptViewer" && ( widgetData && widgetData[i] && widgetData[i].queryParams && ) }
); } const body: JSX.Element = ( <> { widgetMetaDataList.map((widgetMetaData, i) => ( omitWrappingGridContainer ? widgetMetaData && renderWidget(widgetMetaData, i) : widgetMetaData && {renderWidget(widgetMetaData, i)} )) } ); return ( widgetCount > 0 ? ( omitWrappingGridContainer ? body : ( {body} ) ) : null ); } export default DashboardWidgets;