diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleCli.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleCli.java
index 78884a30..cd828001 100644
--- a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleCli.java
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleCli.java
@@ -24,6 +24,7 @@ package com.kingsrook.sampleapp;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.frontend.picocli.QPicoCliImplementation;
+import com.kingsrook.sampleapp.metadata.SampleMetaDataProvider;
/*******************************************************************************
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleJavalinServer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleJavalinServer.java
index fdbc0249..7ec4a911 100644
--- a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleJavalinServer.java
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleJavalinServer.java
@@ -25,6 +25,7 @@ package com.kingsrook.sampleapp;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
+import com.kingsrook.sampleapp.metadata.SampleMetaDataProvider;
import io.javalin.Javalin;
import io.javalin.plugin.bundled.CorsPluginConfig;
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/SampleMetaDataProvider.java
similarity index 99%
rename from qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java
rename to qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/SampleMetaDataProvider.java
index af71a039..ec2aa618 100644
--- a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/SampleMetaDataProvider.java
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/SampleMetaDataProvider.java
@@ -1,6 +1,6 @@
/*
* QQQ - Low-code Application Framework for Engineers.
- * Copyright (C) 2021-2022. Kingsrook, LLC
+ * Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-package com.kingsrook.sampleapp;
+package com.kingsrook.sampleapp.metadata;
import java.io.Serializable;
@@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerHelper;
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
@@ -127,6 +128,8 @@ public class SampleMetaDataProvider
qInstance.addProcess(defineProcessScreenThenSleep());
qInstance.addProcess(defineProcessSimpleThrow());
+ MetaDataProducerHelper.processAllMetaDataProducersInPackage(qInstance, SampleMetaDataProvider.class.getPackageName());
+
defineWidgets(qInstance);
defineBranding(qInstance);
defineApps(qInstance);
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleBarChartWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleBarChartWidgetMetaDataProducer.java
new file mode 100644
index 00000000..93f7f94a
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleBarChartWidgetMetaDataProducer.java
@@ -0,0 +1,124 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
+import com.kingsrook.qqq.frontend.materialdashboard.model.metadata.MaterialDashboardIconRoleNames;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleBarChart
+ *******************************************************************************/
+public class SampleBarChartWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleBarChartWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.BAR_CHART.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Bar Chart")
+ .withTooltip("This is a sample of a bar chart")
+ .withShowReloadButton(true)
+ .withIcon(MaterialDashboardIconRoleNames.TOP_RIGHT_INSIDE_CARD, new QIcon("sports").withColor("#8F00D8"))
+ .withCodeReference(new QCodeReference(SampleBarChartRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleBarChartRenderer extends AbstractWidgetRenderer
+ {
+ private List labels = new ArrayList<>();
+ private List colors = new ArrayList<>();
+ private List data = new ArrayList<>();
+ private List urls = new ArrayList<>();
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ private void addSlice(String label, String color, Number datum, String url)
+ {
+ labels.add(label);
+ colors.add(color);
+ data.add(datum);
+ urls.add(url);
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ addSlice("Apple", "#FF0000", 100, null);
+ addSlice("Orange", "#FF8000", 150, null);
+ addSlice("Banana", "#FFFF00", 75, null);
+ addSlice("Lime", "#00FF00", 100, null);
+ addSlice("Blueberry", "#0000FF", 200, null);
+
+ ChartData chartData = new ChartData()
+ .withChartData(new ChartData.Data()
+ .withLabels(labels)
+ .withDatasets(List.of(
+ new ChartData.Data.Dataset()
+ .withLabel("One")
+ .withData(data)
+ .withBackgroundColors(colors)
+ .withUrls(urls)
+ )));
+
+ chartData.setTitle("Bar Chart");
+
+ return (new RenderWidgetOutput(chartData));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleBigNumberBlocksWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleBigNumberBlocksWidgetMetaDataProducer.java
new file mode 100644
index 00000000..2907c722
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleBigNumberBlocksWidgetMetaDataProducer.java
@@ -0,0 +1,124 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.CompositeWidgetData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.bignumberblock.BigNumberBlockData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.bignumberblock.BigNumberStyles;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.bignumberblock.BigNumberValues;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.upordownnumber.UpOrDownNumberBlockData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.upordownnumber.UpOrDownNumberSlots;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.upordownnumber.UpOrDownNumberStyles;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.upordownnumber.UpOrDownNumberValues;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
+import com.kingsrook.qqq.frontend.materialdashboard.model.metadata.MaterialDashboardIconRoleNames;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleStatisticsWidget
+ *******************************************************************************/
+public class SampleBigNumberBlocksWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleBigNumberBlocksWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.COMPOSITE.getType())
+ .withGridColumns(12)
+ .withIsCard(true)
+ .withLabel("Big Number Blocks")
+ .withTooltip("This is a sample of a widget using Big Number Blocks")
+ .withShowReloadButton(false)
+ .withIcon(MaterialDashboardIconRoleNames.TOP_LEFT_INSIDE_CARD, new QIcon("blocks").withColor("skyblue"))
+ .withCodeReference(new QCodeReference(SampleBigNumberBlocksWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleBigNumberBlocksWidgetRenderer extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ CompositeWidgetData data = new CompositeWidgetData();
+ data.setLayout(CompositeWidgetData.Layout.FLEX_ROW_WRAPPED);
+
+ data.addBlock(new BigNumberBlockData()
+ .withLink("/same-link-for-all-parts")
+ .withTooltip("You can have the same tooltip for all parts")
+ .withStyles(new BigNumberStyles().withWidth("300px"))
+ .withValues(new BigNumberValues().withNumber("123").withHeading("Big Number with Simple Context").withContext("context")));
+
+ data.addBlock(new CompositeWidgetData()
+ .withLayout(CompositeWidgetData.Layout.FLEX_ROW_SPACE_BETWEEN)
+ .withBlock(new BigNumberBlockData()
+ .withLink("/default-link")
+ .withTooltip("You can have a default tooltip...")
+ .withStyles(new BigNumberStyles().withWidth("300px"))
+ .withValues(new BigNumberValues().withNumber("1,234").withHeading("Number with Up/Down Context")))
+ .withBlock(new UpOrDownNumberBlockData()
+ .withTooltip(UpOrDownNumberSlots.CONTEXT, "You can do a custom tooltip for each slot")
+ .withTooltip(UpOrDownNumberSlots.NUMBER, "This number has a customized color")
+ .withLink(UpOrDownNumberSlots.NUMBER, "/custom-link-per-slot")
+ .withStyles(new UpOrDownNumberStyles().withColorOverride("blue"))
+ .withValues(new UpOrDownNumberValues().withIsUp(false).withIsGood(false).withNumber("12,345").withContext("context")))
+ );
+
+ data.addBlock(new CompositeWidgetData()
+ .withLayout(CompositeWidgetData.Layout.FLEX_ROW_SPACE_BETWEEN)
+ .withBlock(new BigNumberBlockData()
+ .withStyles(new BigNumberStyles().withWidth("300px"))
+ .withValues(new BigNumberValues().withNumber("1,234").withHeading("Number with Stacked Up/Down Context")))
+ .withBlock(new UpOrDownNumberBlockData()
+ .withStyles(new UpOrDownNumberStyles().withIsStacked(true))
+ .withValues(new UpOrDownNumberValues().withIsUp(true).withIsGood(true).withNumber("123").withContext("context")))
+ );
+
+ return (new RenderWidgetOutput(data));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleHTMLWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleHTMLWidgetMetaDataProducer.java
new file mode 100644
index 00000000..277efefa
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleHTMLWidgetMetaDataProducer.java
@@ -0,0 +1,75 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.NoCodeWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.HtmlWrapper;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.QNoCodeWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.WidgetHtmlLine;
+import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
+import com.kingsrook.qqq.frontend.materialdashboard.model.metadata.MaterialDashboardIconRoleNames;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleHTMLWidget
+ *******************************************************************************/
+public class SampleHTMLWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleHTMLWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ QNoCodeWidgetMetaData widgetMetaData = (QNoCodeWidgetMetaData) new QNoCodeWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.HTML.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("HTML")
+ .withTooltip("This is a sample of an HTML widget")
+ .withShowReloadButton(false)
+ .withIcon(MaterialDashboardIconRoleNames.TOP_RIGHT_INSIDE_CARD, new QIcon("data_object").withColor("#D87E28"))
+ .withCodeReference(new QCodeReference(NoCodeWidgetRenderer.class));
+
+ widgetMetaData.withOutput(new WidgetHtmlLine()
+ .withWrapper(HtmlWrapper.BIG_CENTERED)
+ .withVelocityTemplate("Purely Custom"));
+
+ widgetMetaData.withOutput(new WidgetHtmlLine()
+ .withVelocityTemplate("User Defined HTML"));
+
+ return widgetMetaData;
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleLineChartWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleLineChartWidgetMetaDataProducer.java
new file mode 100644
index 00000000..6f595a82
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleLineChartWidgetMetaDataProducer.java
@@ -0,0 +1,85 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleLineChartWidget
+ *******************************************************************************/
+public class SampleLineChartWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleLineChartWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.LINE_CHART.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Line Chart")
+ .withTooltip("This is a sample of a Line Chart widget")
+ .withShowReloadButton(false)
+ .withCodeReference(new QCodeReference(SampleLineChartWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleLineChartWidgetRenderer extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ List labels = List.of("January", "February", "March", "April", "May");
+ List data = List.of(1753, 1830, 920, 1543, 1804);
+
+ String description = "Total units have been increasing over the last five months.";
+ return (new RenderWidgetOutput(new ChartData("Line Chart", description, "Units", labels, data)));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleMultiStatisticsWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleMultiStatisticsWidgetMetaDataProducer.java
new file mode 100644
index 00000000..bdbdf868
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleMultiStatisticsWidgetMetaDataProducer.java
@@ -0,0 +1,112 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.MultiStatisticsData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleMultiStatisticsWidget
+ *******************************************************************************/
+public class SampleMultiStatisticsWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleMultiStatisticsWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.MULTI_STATISTICS.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Multi Statistics")
+ .withTooltip("This is a sample of a multi-statistics widget")
+ .withShowReloadButton(true)
+ // .withIcon(MaterialDashboardIconRoleNames.TOP_RIGHT_INSIDE_CARD, new QIcon("local_shipping").withColor(WidgetConstants.COLOR_NEW_GREEN))
+ .withCodeReference(new QCodeReference(SampleStatisticsWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleStatisticsWidgetRenderer extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ MultiStatisticsData.StatisticsGroupData thisWeek = new MultiStatisticsData.StatisticsGroupData()
+ .withIcon("check")
+ .withIconColor("green")
+ .withHeader("This Week")
+ .withSubheader("(1/1/24 - 1/7/24")
+ .withStatisticList(List.of(
+ new MultiStatisticsData.StatisticsGroupData.Statistic("Red", 15, null),
+ new MultiStatisticsData.StatisticsGroupData.Statistic("Green", 20, null),
+ new MultiStatisticsData.StatisticsGroupData.Statistic("Blue", 25, null)
+ ));
+
+ MultiStatisticsData.StatisticsGroupData lastWeek = new MultiStatisticsData.StatisticsGroupData()
+ .withIcon("pending")
+ .withIconColor("red")
+ .withHeader("Last Week")
+ .withSubheader("(12/25/23 - 12/31/23")
+ .withStatisticList(List.of(
+ new MultiStatisticsData.StatisticsGroupData.Statistic("Red", 10, null),
+ new MultiStatisticsData.StatisticsGroupData.Statistic("Green", 25, null),
+ new MultiStatisticsData.StatisticsGroupData.Statistic("Blue", 17, null)
+ ));
+
+ MultiStatisticsData multiStatisticsData = new MultiStatisticsData()
+ .withTitle("Sample Multi Statsitics")
+ .withStatisticsGroupData(
+ List.of(
+ thisWeek,
+ lastWeek
+ )
+ );
+ return (new RenderWidgetOutput(multiStatisticsData));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SamplePieChartWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SamplePieChartWidgetMetaDataProducer.java
new file mode 100644
index 00000000..b6659ca0
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SamplePieChartWidgetMetaDataProducer.java
@@ -0,0 +1,134 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartSubheaderData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
+import com.kingsrook.qqq.frontend.materialdashboard.model.metadata.MaterialDashboardIconRoleNames;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SamplePieChart
+ *******************************************************************************/
+public class SamplePieChartWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SamplePieChartWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.PIE_CHART.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Pie Chart")
+ .withTooltip("This is a sample of a pie chart")
+ .withShowReloadButton(true)
+ .withIcon(MaterialDashboardIconRoleNames.TOP_RIGHT_INSIDE_CARD, new QIcon("add_alert").withColor("#10B8A6"))
+ .withCodeReference(new QCodeReference(SamplePieChartRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SamplePieChartRenderer extends AbstractWidgetRenderer
+ {
+ private List labels = new ArrayList<>();
+ private List colors = new ArrayList<>();
+ private List data = new ArrayList<>();
+ private List urls = new ArrayList<>();
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ private void addSlice(String label, String color, Number datum, String url)
+ {
+ labels.add(label);
+ colors.add(color);
+ data.add(datum);
+ urls.add(url);
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ addSlice("Apple", "#FF0000", 100, null);
+ addSlice("Orange", "#FF8000", 150, null);
+ addSlice("Banana", "#FFFF00", 75, null);
+ addSlice("Lime", "#00FF00", 100, null);
+ addSlice("Blueberry", "#0000FF", 200, null);
+
+ ChartData chartData = new ChartData()
+ .withChartData(new ChartData.Data()
+ .withLabels(labels)
+ .withDatasets(List.of(
+ new ChartData.Data.Dataset()
+ .withLabel("Pie")
+ .withData(data)
+ .withBackgroundColors(colors)
+ .withUrls(urls)
+ ))
+ );
+
+ ChartSubheaderData chartSubheaderData = new ChartSubheaderData()
+ .withMainNumber(1000)
+ .withVsPreviousNumber(100);
+ // .withMainNumberUrl(mainUrl)
+ // .withPreviousNumberUrl(previousUrl);
+
+ chartSubheaderData.calculatePercentsEtc(true);
+
+ chartData.setChartSubheaderData(chartSubheaderData);
+
+ return (new RenderWidgetOutput(chartData));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleSmallLineChartWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleSmallLineChartWidgetMetaDataProducer.java
new file mode 100644
index 00000000..8df08dc3
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleSmallLineChartWidgetMetaDataProducer.java
@@ -0,0 +1,85 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleSmallLineChartWidget
+ *******************************************************************************/
+public class SampleSmallLineChartWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleSmallLineChartWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.SMALL_LINE_CHART.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Small Line Chart")
+ .withTooltip("This is a sample of a Small Line Chart widget")
+ .withShowReloadButton(false)
+ .withCodeReference(new QCodeReference(SampleSmallLineChartWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleSmallLineChartWidgetRenderer extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ List labels = List.of("January", "February", "March", "April", "May");
+ List data = List.of(1753, 1830, 920, 1543, 1804);
+
+ String description = "Total units have been increasing over the last five months.";
+ return (new RenderWidgetOutput(new ChartData("Small Line Chart", description, "Units", labels, data)));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStackedBarChartWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStackedBarChartWidgetMetaDataProducer.java
new file mode 100644
index 00000000..9812ada3
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStackedBarChartWidgetMetaDataProducer.java
@@ -0,0 +1,150 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChartSubheaderData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
+import com.kingsrook.qqq.frontend.materialdashboard.model.metadata.MaterialDashboardIconRoleNames;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SamplePieChart
+ *******************************************************************************/
+public class SampleStackedBarChartWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleStackedBarChartWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.STACKED_BAR_CHART.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Stacked Bar Chart")
+ .withTooltip("This is a sample of a stacked bar chart")
+ .withShowReloadButton(true)
+ .withIcon(MaterialDashboardIconRoleNames.TOP_LEFT_INSIDE_CARD, new QIcon("new_releases").withColor("#6BA47D"))
+ .withCodeReference(new QCodeReference(SampleStackedBarChartRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleStackedBarChartRenderer extends AbstractWidgetRenderer
+ {
+ private List labels = new ArrayList<>();
+ private List colors = new ArrayList<>();
+ private List data = new ArrayList<>();
+ private List urls = new ArrayList<>();
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ private void addSlice(String label, String color, Number datum, String url)
+ {
+ labels.add(label);
+ colors.add(color);
+ data.add(datum);
+ urls.add(url);
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ addSlice("Apple", "#FF0000", 100, null);
+ addSlice("Orange", "#FF8000", 150, null);
+ addSlice("Banana", "#FFFF00", 75, null);
+ addSlice("Lime", "#00FF00", 100, null);
+ addSlice("Blueberry", "#0000FF", 200, null);
+
+ ChartData.Data.Dataset one = new ChartData.Data.Dataset()
+ .withLabel("One")
+ .withData(data)
+ .withBackgroundColors(colors)
+ .withUrls(urls);
+
+ labels = new ArrayList<>();
+ colors = new ArrayList<>();
+ data = new ArrayList<>();
+ urls = new ArrayList<>();
+
+ addSlice("Apple", "#FF0000", 50, null);
+ addSlice("Orange", "#FF8000", 100, null);
+ addSlice("Banana", "#FFFF00", 75, null);
+ addSlice("Lime", "#00FF00", 150, null);
+ addSlice("Blueberry", "#0000FF", 75, null);
+
+ ChartData.Data.Dataset two = new ChartData.Data.Dataset()
+ .withLabel("Two")
+ .withData(data)
+ .withBackgroundColors(colors)
+ .withUrls(urls);
+
+ ChartData chartData = new ChartData()
+ .withChartData(new ChartData.Data()
+ .withLabels(labels)
+ .withDatasets(List.of(one, two)));
+
+ ChartSubheaderData chartSubheaderData = new ChartSubheaderData()
+ .withMainNumber(1000)
+ .withVsPreviousNumber(100);
+ // .withMainNumberUrl(mainUrl)
+ // .withPreviousNumberUrl(previousUrl);
+
+ chartSubheaderData.calculatePercentsEtc(true);
+
+ chartData.setChartSubheaderData(chartSubheaderData);
+
+ return (new RenderWidgetOutput(chartData));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStatisticsWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStatisticsWidgetMetaDataProducer.java
new file mode 100644
index 00000000..bb2781d7
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStatisticsWidgetMetaDataProducer.java
@@ -0,0 +1,87 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.math.BigDecimal;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.StatisticsData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
+import com.kingsrook.qqq.frontend.materialdashboard.model.metadata.MaterialDashboardIconRoleNames;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleStatisticsWidget
+ *******************************************************************************/
+public class SampleStatisticsWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleStatisticsWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.STATISTICS.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Statistics")
+ .withTooltip("This is a sample of a statistics widget")
+ .withShowReloadButton(false)
+ .withIcon(MaterialDashboardIconRoleNames.TOP_LEFT_INSIDE_CARD, new QIcon("assessment").withColor("#0061FF"))
+ .withCodeReference(new QCodeReference(SampleStatisticsWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleStatisticsWidgetRenderer extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ StatisticsData data = new StatisticsData("98.5%", new BigDecimal("-10.0"), "vs prev week");
+ data.withCountContext("of 481");
+ data.withPercentageURL("http://www.google.com/");
+ return (new RenderWidgetOutput(data));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStepperWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStepperWidgetMetaDataProducer.java
new file mode 100644
index 00000000..10ff5ddf
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleStepperWidgetMetaDataProducer.java
@@ -0,0 +1,92 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.List;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.StepperData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleStepperWidget
+ *******************************************************************************/
+public class SampleStepperWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleStepperWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.STEPPER.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Stepper")
+ .withTooltip("This is a sample of a stepper widget")
+ .withShowReloadButton(false)
+ .withCodeReference(new QCodeReference(SampleStepperWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleStepperWidgetRenderer extends AbstractWidgetRenderer
+ {
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ List stepperDataList = List.of(
+ new StepperData.Step().withLabel("Step 1: Underpants").withLinkText("Underpants").withLinkURL("http://www.google.com"),
+ new StepperData.Step().withLabel("Step 2").withLinkText("??").withLinkURL("http://www.google.com"),
+ new StepperData.Step().withLabel("Step 3: Profit").withLinkText("Profit").withLinkURL("http://www.google.com")
+ );
+
+ StepperData stepper = new StepperData(
+ "Sample Stepper Widget",
+ 1,
+ stepperDataList
+ );
+ return (new RenderWidgetOutput(stepper));
+ }
+ }
+
+}
diff --git a/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleTableWidgetMetaDataProducer.java b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleTableWidgetMetaDataProducer.java
new file mode 100644
index 00000000..aff604ff
--- /dev/null
+++ b/qqq-sample-project/src/main/java/com/kingsrook/sampleapp/metadata/widgetsdashboard/SampleTableWidgetMetaDataProducer.java
@@ -0,0 +1,127 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. 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.sampleapp.metadata.widgetsdashboard;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
+import com.kingsrook.qqq.backend.core.exceptions.QException;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
+import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.TableData;
+import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
+import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducer;
+import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
+import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
+import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
+import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
+
+
+/*******************************************************************************
+ ** Meta Data Producer for SampleStatisticsWidget
+ *******************************************************************************/
+public class SampleTableWidgetMetaDataProducer extends MetaDataProducer
+{
+ public static final String NAME = "SampleTableWidget";
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public QWidgetMetaData produce(QInstance qInstance) throws QException
+ {
+ return new QWidgetMetaData()
+ .withName(NAME)
+ .withType(WidgetType.TABLE.getType())
+ .withGridColumns(4)
+ .withIsCard(true)
+ .withLabel("Table")
+ .withTooltip("This is a sample of a table widget")
+ .withShowReloadButton(false)
+ .withCodeReference(new QCodeReference(SampleTableWidgetRenderer.class));
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static class SampleTableWidgetRenderer extends AbstractWidgetRenderer
+ {
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Override
+ public RenderWidgetOutput render(RenderWidgetInput input) throws QException
+ {
+ ////////////////////////////////////
+ // setup datastructures for table //
+ ////////////////////////////////////
+ List