diff --git a/src/main/java/com/kingsrook/qqq/frontend/materialdashboard/model/metadata/MaterialDashboardIconRoleNames.java b/src/main/java/com/kingsrook/qqq/frontend/materialdashboard/model/metadata/MaterialDashboardIconRoleNames.java
new file mode 100644
index 0000000..6d1377d
--- /dev/null
+++ b/src/main/java/com/kingsrook/qqq/frontend/materialdashboard/model/metadata/MaterialDashboardIconRoleNames.java
@@ -0,0 +1,31 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2023. 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 .
+ */
+
+package com.kingsrook.qqq.frontend.materialdashboard.model.metadata;
+
+
+/*******************************************************************************
+ **
+ *******************************************************************************/
+public interface MaterialDashboardIconRoleNames
+{
+ String TOP_RIGHT_INSIDE_CARD = "topRightInsideCard";
+}
diff --git a/src/qqq/components/widgets/DashboardWidgets.tsx b/src/qqq/components/widgets/DashboardWidgets.tsx
index 057f02c..edd577c 100644
--- a/src/qqq/components/widgets/DashboardWidgets.tsx
+++ b/src/qqq/components/widgets/DashboardWidgets.tsx
@@ -22,11 +22,14 @@ import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Q
import {Skeleton} from "@mui/material";
import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid";
+import Tab from "@mui/material/Tab";
+import Tabs from "@mui/material/Tabs";
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 TabPanel from "qqq/components/misc/TabPanel";
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";
@@ -44,7 +47,7 @@ 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 Widget, {HeaderIcon, WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT, LabelComponent} from "qqq/components/widgets/Widget";
import ProcessRun from "qqq/pages/processes/ProcessRun";
import Client from "qqq/utils/qqq/Client";
import TableWidget from "./tables/TableWidget";
@@ -58,9 +61,10 @@ interface Props
tableName?: string;
entityPrimaryKey?: string;
omitWrappingGridContainer: boolean;
- areChildren?: boolean
- childUrlParams?: string
- parentWidgetMetaData?: QWidgetMetaData
+ areChildren?: boolean;
+ childUrlParams?: string;
+ parentWidgetMetaData?: QWidgetMetaData;
+ wrapWidgetsInTabPanels: boolean;
}
DashboardWidgets.defaultProps = {
@@ -70,10 +74,11 @@ DashboardWidgets.defaultProps = {
omitWrappingGridContainer: false,
areChildren: false,
childUrlParams: "",
- parentWidgetMetaData: null
+ parentWidgetMetaData: null,
+ wrapWidgetsInTabPanels: false,
};
-function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omitWrappingGridContainer, areChildren, childUrlParams, parentWidgetMetaData}: Props): JSX.Element
+function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omitWrappingGridContainer, areChildren, childUrlParams, parentWidgetMetaData, wrapWidgetsInTabPanels}: Props): JSX.Element
{
const location = useLocation();
const [widgetData, setWidgetData] = useState([] as any[]);
@@ -84,6 +89,13 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
const [haveLoadedParams, setHaveLoadedParams] = useState(false);
const {accentColor} = useContext(QContext);
+ const [selectedTab, setSelectedTab] = useState(0);
+
+ const changeTab = (newValue: number) =>
+ {
+ setSelectedTab(newValue);
+ };
+
useEffect(() =>
{
setWidgetData([]);
@@ -102,15 +114,15 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
widgetData[i] = await qController.widget(widgetMetaData.name, urlParams);
setWidgetData(widgetData);
setWidgetCounter(widgetCounter + 1);
- if(widgetData[i])
+ if (widgetData[i])
{
widgetData[i]["errorLoading"] = false;
}
}
- catch(e)
+ catch (e)
{
console.error(e);
- if(widgetData[i])
+ if (widgetData[i])
{
widgetData[i]["errorLoading"] = true;
}
@@ -123,7 +135,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
const reloadWidget = async (index: number, data: string) =>
{
- (async() =>
+ (async () =>
{
const urlParams = getQueryParams(widgetMetaDataList[index], data);
setCurrentUrlParams(urlParams);
@@ -140,7 +152,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
widgetData[index]["errorLoading"] = false;
}
}
- catch(e)
+ catch (e)
{
console.error(e);
if (widgetData[index])
@@ -151,7 +163,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
forceUpdate();
})();
- }
+ };
function getQueryParams(widgetMetaData: QWidgetMetaData, extraParams: string): string
{
@@ -178,36 +190,36 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
}
}
- if(entityPrimaryKey)
+ if (entityPrimaryKey)
{
paramMap.set("id", entityPrimaryKey);
}
- if(tableName)
+ if (tableName)
{
paramMap.set("tableName", tableName);
}
- if(extraParams)
+ if (extraParams)
{
let pairs = extraParams.split("&");
for (let i = 0; i < pairs.length; i++)
{
let nameValue = pairs[i].split("=");
- if(nameValue.length == 2)
+ if (nameValue.length == 2)
{
paramMap.set(nameValue[0], nameValue[1]);
}
}
}
- if(childUrlParams)
+ if (childUrlParams)
{
let pairs = childUrlParams.split("&");
for (let i = 0; i < pairs.length; i++)
{
let nameValue = pairs[i].split("=");
- if(nameValue.length == 2)
+ if (nameValue.length == 2)
{
paramMap.set(nameValue[0], nameValue[1]);
}
@@ -227,6 +239,16 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
const renderWidget = (widgetMetaData: QWidgetMetaData, i: number): JSX.Element =>
{
+ const labelAdditionalComponentsRight: LabelComponent[] = [];
+ if (widgetMetaData && widgetMetaData.icons)
+ {
+ const topRightInsideCardIcon = widgetMetaData.icons.get("topRightInsideCard");
+ if (topRightInsideCardIcon)
+ {
+ labelAdditionalComponentsRight.push(new HeaderIcon(topRightInsideCardIcon.name, topRightInsideCardIcon.color));
+ }
+ }
+
return (
{
@@ -270,8 +292,9 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
widgetData={widgetData[i]}
reloadWidgetCallback={(data) => reloadWidget(i, data)}
isChild={areChildren}
+ labelAdditionalComponentsRight={labelAdditionalComponentsRight}
>
-
+
)
}
@@ -381,10 +404,12 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
widgetData={widgetData[i]}
reloadWidgetCallback={(data) => reloadWidget(i, data)}
isChild={areChildren}
+ labelAdditionalComponentsRight={labelAdditionalComponentsRight}
>
@@ -436,11 +461,11 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
{
widgetMetaData.type === "fieldValueList" && (
widgetData && widgetData[i] &&
- reloadWidget(i, data)}
- />
+ reloadWidget(i, data)}
+ />
)
}
{
@@ -461,32 +486,61 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
}
);
- }
+ };
const body: JSX.Element =
(
<>
{
- widgetMetaDataList.map((widgetMetaData, i) => (
- omitWrappingGridContainer
- ? widgetMetaData && renderWidget(widgetMetaData, i)
- :
- widgetMetaData &&
- {renderWidget(widgetMetaData, i)}
-
- ))
+ widgetMetaDataList.map((widgetMetaData, i) =>
+ {
+ let renderedWidget = widgetMetaData ? renderWidget(widgetMetaData, i) : (<>>);
+
+ if (!omitWrappingGridContainer)
+ {
+ renderedWidget = (
+ {renderedWidget}
+ );
+ }
+
+ if (wrapWidgetsInTabPanels)
+ {
+ renderedWidget = (
+ {renderedWidget}
+ );
+ }
+
+ return ({renderedWidget})
+ })
}
>
);
+ const tabs = widgetMetaDataList && wrapWidgetsInTabPanels ?
+ changeTab(newValue)}
+ variant="standard"
+ >
+ {widgetMetaDataList.map((widgetMetaData, i) => (
+
+ ))}
+
+ : <>>
+
return (
widgetCount > 0 ? (
- omitWrappingGridContainer ? body :
- (
-
- {body}
-
- )
+ <>
+ {tabs}
+ {
+ omitWrappingGridContainer ? body : (
+
+ {body}
+
+ )
+ }
+ >
) : null
);
}