mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 12:50:43 +00:00
SPRINT-19: updates to various widgets for new dashboard, cleanups
This commit is contained in:
1233
package-lock.json
generated
1233
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
"@auth0/auth0-react": "1.10.2",
|
||||
"@emotion/react": "11.7.1",
|
||||
"@emotion/styled": "11.6.0",
|
||||
"@kingsrook/qqq-frontend-core": "1.0.44",
|
||||
"@kingsrook/qqq-frontend-core": "1.0.45",
|
||||
"@mui/icons-material": "5.4.1",
|
||||
"@mui/material": "5.11.1",
|
||||
"@mui/styles": "5.11.1",
|
||||
@ -27,6 +27,7 @@
|
||||
"chroma-js": "2.4.2",
|
||||
"datejs": "1.0.0-rc3",
|
||||
"downshift": "3.2.10",
|
||||
"faker": "5.5.3",
|
||||
"form-data": "4.0.0",
|
||||
"formik": "2.2.9",
|
||||
"html-react-parser": "1.4.8",
|
||||
@ -77,6 +78,7 @@
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "6.5.1",
|
||||
"@types/chroma-js": "2.1.3",
|
||||
"@types/faker": "5.5.9",
|
||||
"@types/react-table": "7.7.9",
|
||||
"@typescript-eslint/eslint-plugin": "5.10.2",
|
||||
"@typescript-eslint/parser": "5.10.2",
|
||||
|
@ -1,17 +1,17 @@
|
||||
/**
|
||||
=========================================================
|
||||
* Material Dashboard 2 PRO React TS - v1.0.0
|
||||
=========================================================
|
||||
=========================================================
|
||||
* Material Dashboard 2 PRO React TS - v1.0.0
|
||||
=========================================================
|
||||
|
||||
* Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
|
||||
* Copyright 2022 Creative Tim (https://www.creative-tim.com)
|
||||
* Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
|
||||
* Copyright 2022 Creative Tim (https://www.creative-tim.com)
|
||||
|
||||
Coded by www.creative-tim.com
|
||||
Coded by www.creative-tim.com
|
||||
|
||||
=========================================================
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*/
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The base colors for the Material Dashboard 2 PRO React TSUI Dashboard PRO Material.
|
||||
@ -20,370 +20,405 @@ Coded by www.creative-tim.com
|
||||
*/
|
||||
|
||||
// types
|
||||
interface ColorsTypes {
|
||||
main: string;
|
||||
focus: string;
|
||||
interface ColorsTypes
|
||||
{
|
||||
main: string;
|
||||
focus: string;
|
||||
}
|
||||
|
||||
interface GradientsTypes {
|
||||
main: string;
|
||||
state: string;
|
||||
interface GradientsTypes
|
||||
{
|
||||
main: string;
|
||||
state: string;
|
||||
}
|
||||
|
||||
interface SocialMediaColorsTypes {
|
||||
main: string;
|
||||
dark: string;
|
||||
interface SocialMediaColorsTypes
|
||||
{
|
||||
main: string;
|
||||
dark: string;
|
||||
}
|
||||
|
||||
interface BadgeColorsTypes {
|
||||
background: string;
|
||||
text: string;
|
||||
interface BadgeColorsTypes
|
||||
{
|
||||
background: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface Types {
|
||||
background:
|
||||
| {
|
||||
default: string;
|
||||
sidenav?: string;
|
||||
card?: string;
|
||||
interface Types
|
||||
{
|
||||
background:
|
||||
| {
|
||||
default: string;
|
||||
sidenav?: string;
|
||||
card?: string;
|
||||
}
|
||||
| any;
|
||||
white:
|
||||
| {
|
||||
main: string;
|
||||
focus: string;
|
||||
}
|
||||
| any;
|
||||
text:
|
||||
| {
|
||||
main: string;
|
||||
focus: string;
|
||||
primary?: string;
|
||||
secondary?: string;
|
||||
disabled?: string;
|
||||
}
|
||||
| any;
|
||||
transparent:
|
||||
| {
|
||||
main: string;
|
||||
}
|
||||
| any;
|
||||
black:
|
||||
| {
|
||||
light: string;
|
||||
main: string;
|
||||
focus: string;
|
||||
}
|
||||
| any;
|
||||
primary: ColorsTypes | any;
|
||||
secondary: ColorsTypes | any;
|
||||
info: ColorsTypes | any;
|
||||
success: ColorsTypes | any;
|
||||
warning: ColorsTypes | any;
|
||||
error: ColorsTypes | any;
|
||||
light: ColorsTypes | any;
|
||||
dark: ColorsTypes | any;
|
||||
grey:
|
||||
| {
|
||||
[key: string | number]: string;
|
||||
}
|
||||
| any;
|
||||
gradients:
|
||||
| {
|
||||
primary: GradientsTypes;
|
||||
secondary: GradientsTypes;
|
||||
info: GradientsTypes;
|
||||
success: GradientsTypes;
|
||||
warning: GradientsTypes;
|
||||
error: GradientsTypes;
|
||||
light: GradientsTypes;
|
||||
dark: GradientsTypes;
|
||||
custom1: GradientsTypes;
|
||||
custom2: GradientsTypes;
|
||||
custom3: GradientsTypes;
|
||||
custom4: GradientsTypes;
|
||||
custom5: GradientsTypes;
|
||||
}
|
||||
| any;
|
||||
socialMediaColors:
|
||||
| {
|
||||
facebook: SocialMediaColorsTypes;
|
||||
twitter: SocialMediaColorsTypes;
|
||||
instagram: SocialMediaColorsTypes;
|
||||
linkedin: SocialMediaColorsTypes;
|
||||
pinterest: SocialMediaColorsTypes;
|
||||
youtube: SocialMediaColorsTypes;
|
||||
vimeo: SocialMediaColorsTypes;
|
||||
slack: SocialMediaColorsTypes;
|
||||
dribbble: SocialMediaColorsTypes;
|
||||
github: SocialMediaColorsTypes;
|
||||
reddit: SocialMediaColorsTypes;
|
||||
tumblr: SocialMediaColorsTypes;
|
||||
}
|
||||
| any;
|
||||
badgeColors:
|
||||
| {
|
||||
primary: BadgeColorsTypes;
|
||||
secondary: BadgeColorsTypes;
|
||||
info: BadgeColorsTypes;
|
||||
success: BadgeColorsTypes;
|
||||
warning: BadgeColorsTypes;
|
||||
error: BadgeColorsTypes;
|
||||
light: BadgeColorsTypes;
|
||||
dark: BadgeColorsTypes;
|
||||
}
|
||||
| any;
|
||||
coloredShadows:
|
||||
| {
|
||||
[key: string]: string;
|
||||
}
|
||||
| any;
|
||||
inputBorderColor: string;
|
||||
tabs:
|
||||
| {
|
||||
indicator:
|
||||
| {
|
||||
boxShadow: string;
|
||||
}
|
||||
| any;
|
||||
white:
|
||||
| {
|
||||
main: string;
|
||||
focus: string;
|
||||
}
|
||||
| any;
|
||||
text:
|
||||
| {
|
||||
main: string;
|
||||
focus: string;
|
||||
primary?: string;
|
||||
secondary?: string;
|
||||
disabled?: string;
|
||||
}
|
||||
| any;
|
||||
transparent:
|
||||
| {
|
||||
main: string;
|
||||
}
|
||||
| any;
|
||||
black:
|
||||
| {
|
||||
light: string;
|
||||
main: string;
|
||||
focus: string;
|
||||
}
|
||||
| any;
|
||||
primary: ColorsTypes | any;
|
||||
secondary: ColorsTypes | any;
|
||||
info: ColorsTypes | any;
|
||||
success: ColorsTypes | any;
|
||||
warning: ColorsTypes | any;
|
||||
error: ColorsTypes | any;
|
||||
light: ColorsTypes | any;
|
||||
dark: ColorsTypes | any;
|
||||
grey:
|
||||
| {
|
||||
[key: string | number]: string;
|
||||
}
|
||||
| any;
|
||||
gradients:
|
||||
| {
|
||||
primary: GradientsTypes;
|
||||
secondary: GradientsTypes;
|
||||
info: GradientsTypes;
|
||||
success: GradientsTypes;
|
||||
warning: GradientsTypes;
|
||||
error: GradientsTypes;
|
||||
light: GradientsTypes;
|
||||
dark: GradientsTypes;
|
||||
}
|
||||
| any;
|
||||
socialMediaColors:
|
||||
| {
|
||||
facebook: SocialMediaColorsTypes;
|
||||
twitter: SocialMediaColorsTypes;
|
||||
instagram: SocialMediaColorsTypes;
|
||||
linkedin: SocialMediaColorsTypes;
|
||||
pinterest: SocialMediaColorsTypes;
|
||||
youtube: SocialMediaColorsTypes;
|
||||
vimeo: SocialMediaColorsTypes;
|
||||
slack: SocialMediaColorsTypes;
|
||||
dribbble: SocialMediaColorsTypes;
|
||||
github: SocialMediaColorsTypes;
|
||||
reddit: SocialMediaColorsTypes;
|
||||
tumblr: SocialMediaColorsTypes;
|
||||
}
|
||||
| any;
|
||||
badgeColors:
|
||||
| {
|
||||
primary: BadgeColorsTypes;
|
||||
secondary: BadgeColorsTypes;
|
||||
info: BadgeColorsTypes;
|
||||
success: BadgeColorsTypes;
|
||||
warning: BadgeColorsTypes;
|
||||
error: BadgeColorsTypes;
|
||||
light: BadgeColorsTypes;
|
||||
dark: BadgeColorsTypes;
|
||||
}
|
||||
| any;
|
||||
coloredShadows:
|
||||
| {
|
||||
[key: string]: string;
|
||||
}
|
||||
| any;
|
||||
inputBorderColor: string;
|
||||
tabs:
|
||||
| {
|
||||
indicator:
|
||||
| {
|
||||
boxShadow: string;
|
||||
}
|
||||
| any;
|
||||
}
|
||||
| any;
|
||||
| any;
|
||||
}
|
||||
| any;
|
||||
}
|
||||
|
||||
const colors: Types = {
|
||||
background: {
|
||||
default: "#f0f2f5",
|
||||
},
|
||||
background: {
|
||||
default: "#f0f2f5",
|
||||
},
|
||||
|
||||
text: {
|
||||
main: "#7b809a",
|
||||
focus: "#7b809a",
|
||||
},
|
||||
text: {
|
||||
main: "#7b809a",
|
||||
focus: "#7b809a",
|
||||
},
|
||||
|
||||
transparent: {
|
||||
main: "transparent",
|
||||
},
|
||||
transparent: {
|
||||
main: "transparent",
|
||||
},
|
||||
|
||||
white: {
|
||||
main: "#ffffff",
|
||||
focus: "#ffffff",
|
||||
},
|
||||
white: {
|
||||
main: "#ffffff",
|
||||
focus: "#ffffff",
|
||||
},
|
||||
|
||||
black: {
|
||||
light: "#000000",
|
||||
main: "#000000",
|
||||
focus: "#000000",
|
||||
},
|
||||
black: {
|
||||
light: "#000000",
|
||||
main: "#000000",
|
||||
focus: "#000000",
|
||||
},
|
||||
|
||||
primary: {
|
||||
main: "#e91e63",
|
||||
focus: "#e91e63",
|
||||
},
|
||||
primary: {
|
||||
main: "#e91e63",
|
||||
focus: "#e91e63",
|
||||
},
|
||||
|
||||
secondary: {
|
||||
main: "#7b809a",
|
||||
focus: "#8f93a9",
|
||||
},
|
||||
secondary: {
|
||||
main: "#7b809a",
|
||||
focus: "#8f93a9",
|
||||
},
|
||||
|
||||
info: {
|
||||
main: "#04aaef",
|
||||
focus: "#1662C4",
|
||||
},
|
||||
info: {
|
||||
main: "#04aaef",
|
||||
focus: "#1662C4",
|
||||
},
|
||||
|
||||
success: {
|
||||
main: "#4CAF50",
|
||||
focus: "#67bb6a",
|
||||
},
|
||||
success: {
|
||||
main: "#4CAF50",
|
||||
focus: "#67bb6a",
|
||||
},
|
||||
|
||||
warning: {
|
||||
main: "#fb8c00",
|
||||
focus: "#fc9d26",
|
||||
},
|
||||
warning: {
|
||||
main: "#fb8c00",
|
||||
focus: "#fc9d26",
|
||||
},
|
||||
|
||||
error: {
|
||||
main: "#F44335",
|
||||
focus: "#f65f53",
|
||||
},
|
||||
error: {
|
||||
main: "#F44335",
|
||||
focus: "#f65f53",
|
||||
},
|
||||
|
||||
light: {
|
||||
main: "#f0f2f5",
|
||||
focus: "#f0f2f5",
|
||||
},
|
||||
light: {
|
||||
main: "#f0f2f5",
|
||||
focus: "#f0f2f5",
|
||||
},
|
||||
|
||||
dark: {
|
||||
main: "#344767",
|
||||
focus: "#2c3c58",
|
||||
},
|
||||
dark: {
|
||||
main: "#344767",
|
||||
focus: "#2c3c58",
|
||||
},
|
||||
|
||||
grey: {
|
||||
100: "#f8f9fa",
|
||||
200: "#f0f2f5",
|
||||
300: "#dee2e6",
|
||||
400: "#ced4da",
|
||||
500: "#adb5bd",
|
||||
600: "#6c757d",
|
||||
700: "#495057",
|
||||
800: "#343a40",
|
||||
900: "#212529",
|
||||
},
|
||||
grey: {
|
||||
100: "#f8f9fa",
|
||||
200: "#f0f2f5",
|
||||
300: "#dee2e6",
|
||||
400: "#ced4da",
|
||||
500: "#adb5bd",
|
||||
600: "#6c757d",
|
||||
700: "#495057",
|
||||
800: "#343a40",
|
||||
900: "#212529",
|
||||
},
|
||||
|
||||
gradients: {
|
||||
primary: {
|
||||
main: "#EC407A",
|
||||
state: "#D81B60",
|
||||
},
|
||||
gradients: {
|
||||
primary: {
|
||||
main: "#EC407A",
|
||||
state: "#D81B60",
|
||||
},
|
||||
|
||||
secondary: {
|
||||
main: "#747b8a",
|
||||
state: "#495361",
|
||||
},
|
||||
secondary: {
|
||||
main: "#747b8a",
|
||||
state: "#495361",
|
||||
},
|
||||
|
||||
info: {
|
||||
main: "#49a3f1",
|
||||
state: "#04aaef",
|
||||
},
|
||||
info: {
|
||||
main: "#49a3f1",
|
||||
state: "#04aaef",
|
||||
},
|
||||
|
||||
success: {
|
||||
main: "#66BB6A",
|
||||
state: "#43A047",
|
||||
},
|
||||
success: {
|
||||
main: "#66BB6A",
|
||||
state: "#43A047",
|
||||
},
|
||||
|
||||
warning: {
|
||||
main: "#FFA726",
|
||||
state: "#FB8C00",
|
||||
},
|
||||
warning: {
|
||||
main: "#FFA726",
|
||||
state: "#FB8C00",
|
||||
},
|
||||
|
||||
error: {
|
||||
main: "#EF5350",
|
||||
state: "#E53935",
|
||||
},
|
||||
error: {
|
||||
main: "#EF5350",
|
||||
state: "#E53935",
|
||||
},
|
||||
|
||||
light: {
|
||||
main: "#EBEFF4",
|
||||
state: "#CED4DA",
|
||||
},
|
||||
light: {
|
||||
main: "#EBEFF4",
|
||||
state: "#CED4DA",
|
||||
},
|
||||
|
||||
dark: {
|
||||
main: "#42424a",
|
||||
state: "#191919",
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
main: "#42424a",
|
||||
state: "#191919",
|
||||
},
|
||||
|
||||
socialMediaColors: {
|
||||
facebook: {
|
||||
main: "#3b5998",
|
||||
dark: "#344e86",
|
||||
},
|
||||
custom1: {
|
||||
main: "#3aaf85",
|
||||
state: "#8c28c2",
|
||||
},
|
||||
|
||||
twitter: {
|
||||
main: "#55acee",
|
||||
dark: "#3ea1ec",
|
||||
},
|
||||
custom2: {
|
||||
main: "#0077b5",
|
||||
state: "#ffe120",
|
||||
},
|
||||
|
||||
instagram: {
|
||||
main: "#125688",
|
||||
dark: "#0e456d",
|
||||
},
|
||||
custom3: {
|
||||
main: "#ea4c89",
|
||||
state: "#000000",
|
||||
},
|
||||
|
||||
linkedin: {
|
||||
main: "#0077b5",
|
||||
dark: "#00669c",
|
||||
},
|
||||
custom4: {
|
||||
main: "#0077b5",
|
||||
state: "#747474",
|
||||
},
|
||||
|
||||
pinterest: {
|
||||
main: "#cc2127",
|
||||
dark: "#b21d22",
|
||||
},
|
||||
custom5: {
|
||||
main: "#0077b5",
|
||||
state: "#ffcefa",
|
||||
},
|
||||
},
|
||||
|
||||
youtube: {
|
||||
main: "#e52d27",
|
||||
dark: "#d41f1a",
|
||||
},
|
||||
socialMediaColors: {
|
||||
facebook: {
|
||||
main: "#3b5998",
|
||||
dark: "#344e86",
|
||||
},
|
||||
|
||||
vimeo: {
|
||||
main: "#1ab7ea",
|
||||
dark: "#13a3d2",
|
||||
},
|
||||
twitter: {
|
||||
main: "#55acee",
|
||||
dark: "#3ea1ec",
|
||||
},
|
||||
|
||||
slack: {
|
||||
main: "#3aaf85",
|
||||
dark: "#329874",
|
||||
},
|
||||
instagram: {
|
||||
main: "#125688",
|
||||
dark: "#0e456d",
|
||||
},
|
||||
|
||||
dribbble: {
|
||||
main: "#ea4c89",
|
||||
dark: "#e73177",
|
||||
},
|
||||
linkedin: {
|
||||
main: "#0077b5",
|
||||
dark: "#00669c",
|
||||
},
|
||||
|
||||
github: {
|
||||
main: "#24292e",
|
||||
dark: "#171a1d",
|
||||
},
|
||||
pinterest: {
|
||||
main: "#cc2127",
|
||||
dark: "#b21d22",
|
||||
},
|
||||
|
||||
reddit: {
|
||||
main: "#ff4500",
|
||||
dark: "#e03d00",
|
||||
},
|
||||
youtube: {
|
||||
main: "#e52d27",
|
||||
dark: "#d41f1a",
|
||||
},
|
||||
|
||||
tumblr: {
|
||||
main: "#35465c",
|
||||
dark: "#2a3749",
|
||||
},
|
||||
},
|
||||
vimeo: {
|
||||
main: "#1ab7ea",
|
||||
dark: "#13a3d2",
|
||||
},
|
||||
|
||||
badgeColors: {
|
||||
primary: {
|
||||
background: "#f8b3ca",
|
||||
text: "#cc084b",
|
||||
},
|
||||
slack: {
|
||||
main: "#3aaf85",
|
||||
dark: "#329874",
|
||||
},
|
||||
|
||||
secondary: {
|
||||
background: "#d7d9e1",
|
||||
text: "#6c757d",
|
||||
},
|
||||
dribbble: {
|
||||
main: "#ea4c89",
|
||||
dark: "#e73177",
|
||||
},
|
||||
|
||||
info: {
|
||||
background: "#aecef7",
|
||||
text: "#095bc6",
|
||||
},
|
||||
github: {
|
||||
main: "#24292e",
|
||||
dark: "#171a1d",
|
||||
},
|
||||
|
||||
success: {
|
||||
background: "#bce2be",
|
||||
text: "#339537",
|
||||
},
|
||||
reddit: {
|
||||
main: "#ff4500",
|
||||
dark: "#e03d00",
|
||||
},
|
||||
|
||||
warning: {
|
||||
background: "#ffd59f",
|
||||
text: "#c87000",
|
||||
},
|
||||
tumblr: {
|
||||
main: "#35465c",
|
||||
dark: "#2a3749",
|
||||
},
|
||||
},
|
||||
|
||||
error: {
|
||||
background: "#fcd3d0",
|
||||
text: "#f61200",
|
||||
},
|
||||
badgeColors: {
|
||||
primary: {
|
||||
background: "#f8b3ca",
|
||||
text: "#cc084b",
|
||||
},
|
||||
|
||||
light: {
|
||||
background: "#ffffff",
|
||||
text: "#c7d3de",
|
||||
},
|
||||
secondary: {
|
||||
background: "#d7d9e1",
|
||||
text: "#6c757d",
|
||||
},
|
||||
|
||||
dark: {
|
||||
background: "#8097bf",
|
||||
text: "#1e2e4a",
|
||||
},
|
||||
},
|
||||
info: {
|
||||
background: "#aecef7",
|
||||
text: "#095bc6",
|
||||
},
|
||||
|
||||
coloredShadows: {
|
||||
primary: "#e91e62",
|
||||
secondary: "#110e0e",
|
||||
info: "#00bbd4",
|
||||
success: "#4caf4f",
|
||||
warning: "#ff9900",
|
||||
error: "#f44336",
|
||||
light: "#adb5bd",
|
||||
dark: "#404040",
|
||||
},
|
||||
success: {
|
||||
background: "#bce2be",
|
||||
text: "#339537",
|
||||
},
|
||||
|
||||
inputBorderColor: "#d2d6da",
|
||||
warning: {
|
||||
background: "#ffd59f",
|
||||
text: "#c87000",
|
||||
},
|
||||
|
||||
tabs: {
|
||||
indicator: { boxShadow: "#ddd" },
|
||||
},
|
||||
error: {
|
||||
background: "#fcd3d0",
|
||||
text: "#f61200",
|
||||
},
|
||||
|
||||
light: {
|
||||
background: "#ffffff",
|
||||
text: "#c7d3de",
|
||||
},
|
||||
|
||||
dark: {
|
||||
background: "#8097bf",
|
||||
text: "#1e2e4a",
|
||||
},
|
||||
},
|
||||
|
||||
coloredShadows: {
|
||||
primary: "#e91e62",
|
||||
secondary: "#110e0e",
|
||||
info: "#00bbd4",
|
||||
success: "#4caf4f",
|
||||
warning: "#ff9900",
|
||||
error: "#f44336",
|
||||
light: "#adb5bd",
|
||||
dark: "#404040",
|
||||
},
|
||||
|
||||
inputBorderColor: "#d2d6da",
|
||||
|
||||
tabs: {
|
||||
indicator: {boxShadow: "#ddd"},
|
||||
},
|
||||
};
|
||||
|
||||
export default colors;
|
||||
|
@ -80,6 +80,11 @@ const MDBadgeDot: FC<Props> = forwardRef(
|
||||
"error",
|
||||
"light",
|
||||
"dark",
|
||||
"custom1",
|
||||
"custom2",
|
||||
"custom3",
|
||||
"custom4",
|
||||
"custom5"
|
||||
];
|
||||
|
||||
const colorValues = {
|
||||
@ -90,10 +95,14 @@ const MDBadgeDot: FC<Props> = forwardRef(
|
||||
"warning": "#fb8c00",
|
||||
"error": "#F44335",
|
||||
"light": "#f0f2f5",
|
||||
"dark": "#344767"
|
||||
"dark": "#344767",
|
||||
"custom1": "#8c28c2",
|
||||
"custom2": "#ffe120",
|
||||
"custom3": "#000000",
|
||||
"custom4": "#747474",
|
||||
"custom5": "#ffcefa"
|
||||
} as any;
|
||||
|
||||
const validColorIndex = validColors.findIndex((el) => el === color);
|
||||
return (
|
||||
<Box ref={ref} display="flex" alignItems="center" p={padding} {...rest}>
|
||||
<Box
|
||||
|
@ -34,7 +34,8 @@ 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 PieChartCard from "qqq/components/widgets/charts/piechart/PieChartCard";
|
||||
import PieChart from "qqq/components/widgets/charts/piechart/PieChart";
|
||||
import StackedBarChart from "qqq/components/widgets/charts/StackedBarChart";
|
||||
import DividerWidget from "qqq/components/widgets/misc/Divider";
|
||||
import FieldValueListWidget from "qqq/components/widgets/misc/FieldValueListWidget";
|
||||
import QuickSightChart from "qqq/components/widgets/misc/QuickSightChart";
|
||||
@ -161,13 +162,13 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
{
|
||||
widgetMetaData.type === "parentWidget" && (
|
||||
<ParentWidget
|
||||
icon={widgetMetaData.icon}
|
||||
entityPrimaryKey={entityPrimaryKey}
|
||||
tableName={tableName}
|
||||
widgetIndex={i}
|
||||
label={widgetMetaData.label}
|
||||
widgetMetaData={widgetMetaData}
|
||||
data={widgetData[i]}
|
||||
reloadWidgetCallback={reloadWidget}
|
||||
storeDropdownSelections={widgetMetaData.storeDropdownSelections}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -184,30 +185,34 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
{
|
||||
widgetMetaData.type === "table" && (
|
||||
<Widget
|
||||
label={widgetData[i]?.label}
|
||||
isCard={widgetMetaData.isCard}
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={widgetData[i]}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}
|
||||
isChild={areChildren}
|
||||
>
|
||||
<TableCard
|
||||
color="info"
|
||||
title={widgetMetaData.label}
|
||||
linkText={widgetData[i]?.linkText}
|
||||
linkURL={widgetData[i]?.linkURL}
|
||||
noRowsFoundHTML={widgetData[i]?.noRowsFoundHTML}
|
||||
data={widgetData[i]}
|
||||
dropdownOptions={widgetData[i]?.dropdownOptions}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}
|
||||
widgetIndex={i}
|
||||
/>
|
||||
</Widget>
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "stackedBarChart" && (
|
||||
<Widget
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={widgetData[i]}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}
|
||||
isChild={areChildren}
|
||||
>
|
||||
<StackedBarChart data={widgetData[i]?.chartData}/>
|
||||
</Widget>
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "process" && widgetData[i]?.processMetaData && (
|
||||
<Widget
|
||||
label={widgetData[i]?.processMetaData?.label}
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={widgetData[i]}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}>
|
||||
<div>
|
||||
@ -234,7 +239,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "html" && (
|
||||
<Widget label={widgetMetaData.label}>
|
||||
<Widget widgetMetaData={widgetMetaData}>
|
||||
<Box px={1} pt={0} pb={2}>
|
||||
<MDTypography component="div" variant="button" color="text" fontWeight="light">
|
||||
{
|
||||
@ -247,15 +252,6 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
</Widget>
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "multiStatistics" && (
|
||||
<MultiStatisticsCard
|
||||
color="info"
|
||||
title={widgetMetaData.label}
|
||||
data={widgetData[i]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "smallLineChart" && (
|
||||
<SmallLineChart
|
||||
@ -267,6 +263,25 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "statistics" && (
|
||||
widgetData && widgetData[i] && (
|
||||
<Widget
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={widgetData[i]}
|
||||
isChild={areChildren}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}>
|
||||
<StatisticsCard
|
||||
title={widgetMetaData.label}
|
||||
color={colors.info.main}
|
||||
icon={widgetMetaData.icon}
|
||||
data={widgetData[i]}
|
||||
increaseIsGood={true}
|
||||
/>
|
||||
</Widget>
|
||||
)
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "simpleStatistics" && (
|
||||
widgetData && widgetData[i] && (
|
||||
@ -280,16 +295,12 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "statistics" && (
|
||||
widgetData && widgetData[i] && (
|
||||
<StatisticsCard
|
||||
title={widgetMetaData.label}
|
||||
color={colors.info.main}
|
||||
icon={widgetMetaData.icon}
|
||||
data={widgetData[i]}
|
||||
increaseIsGood={true}
|
||||
/>
|
||||
)
|
||||
widgetMetaData.type === "multiStatistics" && (
|
||||
<MultiStatisticsCard
|
||||
color="info"
|
||||
title={widgetMetaData.label}
|
||||
data={widgetData[i]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
@ -310,11 +321,19 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "pieChart" && (
|
||||
<PieChartCard
|
||||
title={widgetMetaData.label}
|
||||
description={widgetData[i]?.description}
|
||||
data={widgetData[i]?.chartData}
|
||||
/>
|
||||
<Widget
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={widgetData[i]}
|
||||
isChild={areChildren}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}>
|
||||
|
||||
<div>
|
||||
<PieChart
|
||||
chartData={widgetData[i]?.chartData}
|
||||
description={widgetData[i]?.description}
|
||||
/>
|
||||
</div>
|
||||
</Widget>
|
||||
)
|
||||
}
|
||||
{
|
||||
@ -362,7 +381,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
widgetMetaData.type === "childRecordList" && (
|
||||
widgetData && widgetData[i] &&
|
||||
<RecordGridWidget
|
||||
title={widgetMetaData.label}
|
||||
widgetMetaData={widgetMetaData}
|
||||
data={widgetData[i]}
|
||||
/>
|
||||
)
|
||||
@ -372,7 +391,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
|
||||
widgetMetaData.type === "fieldValueList" && (
|
||||
widgetData && widgetData[i] &&
|
||||
<FieldValueListWidget
|
||||
title={widgetMetaData.label}
|
||||
widgetMetaData={widgetMetaData}
|
||||
data={widgetData[i]}
|
||||
reloadWidgetCallback={(data) => reloadWidget(i, data)}
|
||||
/>
|
||||
|
@ -50,18 +50,18 @@ export interface ParentWidgetData
|
||||
////////////////////////////////////
|
||||
interface Props
|
||||
{
|
||||
widgetMetaData?: QWidgetMetaData;
|
||||
widgetIndex: number;
|
||||
label: string;
|
||||
icon?: string;
|
||||
data: ParentWidgetData;
|
||||
reloadWidgetCallback?: (widgetIndex: number, params: string) => void;
|
||||
entityPrimaryKey?: string;
|
||||
tableName?: string;
|
||||
storeDropdownSelections?: boolean;
|
||||
}
|
||||
|
||||
|
||||
const qController = Client.getInstance();
|
||||
function ParentWidget({widgetIndex, label, icon, data, reloadWidgetCallback, entityPrimaryKey, tableName}: Props, ): JSX.Element
|
||||
function ParentWidget({widgetMetaData, widgetIndex, data, reloadWidgetCallback, entityPrimaryKey, tableName, storeDropdownSelections}: Props, ): JSX.Element
|
||||
{
|
||||
const [childUrlParams, setChildUrlParams] = useState("");
|
||||
const [qInstance, setQInstance] = useState(null as QInstance);
|
||||
@ -99,12 +99,12 @@ function ParentWidget({widgetIndex, label, icon, data, reloadWidgetCallback, ent
|
||||
// @ts-ignore
|
||||
return (
|
||||
<Widget
|
||||
icon={icon}
|
||||
label={label}
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={data}
|
||||
storeDropdownSelections={storeDropdownSelections}
|
||||
reloadWidgetCallback={parentReloadWidgetCallback}
|
||||
>
|
||||
<Box px={3} sx={{width: "100%"}}>
|
||||
<Box sx={{height: "100%", width: "100%"}}>
|
||||
<DashboardWidgets widgetMetaDataList={widgets} entityPrimaryKey={entityPrimaryKey} tableName={tableName} childUrlParams={childUrlParams} areChildren={true}/>
|
||||
</Box>
|
||||
</Widget>
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Card from "@mui/material/Card";
|
||||
@ -44,21 +45,19 @@ export interface WidgetData
|
||||
|
||||
interface Props
|
||||
{
|
||||
icon?: string;
|
||||
label: string;
|
||||
labelAdditionalComponentsLeft: LabelComponent[];
|
||||
labelAdditionalComponentsRight: LabelComponent[];
|
||||
widgetMetaData?: QWidgetMetaData;
|
||||
widgetData?: WidgetData;
|
||||
children: JSX.Element;
|
||||
reloadWidgetCallback?: (params: string) => void;
|
||||
isChild?: boolean;
|
||||
isCard?: boolean;
|
||||
storeDropdownSelections?: boolean;
|
||||
}
|
||||
|
||||
Widget.defaultProps = {
|
||||
isCard: true,
|
||||
isChild: false,
|
||||
label: null,
|
||||
widgetMetaData: {},
|
||||
widgetData: {},
|
||||
labelAdditionalComponentsLeft: [],
|
||||
labelAdditionalComponentsRight: [],
|
||||
@ -121,6 +120,8 @@ export class Dropdown extends LabelComponent
|
||||
}
|
||||
|
||||
|
||||
const WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT = "qqq.widgets.dropdownData";
|
||||
|
||||
|
||||
function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
{
|
||||
@ -133,7 +134,7 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
navigate(`#/createChild=${table.name}/defaultValues=${JSON.stringify(defaultValues)}/disabledFields=${JSON.stringify(disabledFields)}`)
|
||||
}
|
||||
|
||||
function renderComponent(component: LabelComponent)
|
||||
function renderComponent(component: LabelComponent, index: number)
|
||||
{
|
||||
if(component instanceof HeaderLink)
|
||||
{
|
||||
@ -157,10 +158,23 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
|
||||
if (component instanceof Dropdown)
|
||||
{
|
||||
let defaultValue = null;
|
||||
const dropdownName = props.widgetData.dropdownNameList[index];
|
||||
const localStorageKey = `${WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT}.${props.widgetMetaData.name}.${dropdownName}`;
|
||||
if(props.storeDropdownSelections)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// see if an existing value is stored in local storage, and if so set it in dropdown //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
defaultValue = JSON.parse(localStorage.getItem(localStorageKey));
|
||||
}
|
||||
|
||||
const dropdown = component as Dropdown
|
||||
return (
|
||||
<Box my={2} mr={2} sx={{float: "right"}}>
|
||||
<DropdownMenu
|
||||
localStorageKey={localStorageKey}
|
||||
defaultValue={defaultValue}
|
||||
sx={{width: 200, marginLeft: "15px"}}
|
||||
label={`Select ${dropdown.label}`}
|
||||
dropdownOptions={dropdown.options}
|
||||
@ -199,12 +213,14 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
// find the index base on selected label //
|
||||
///////////////////////////////////////////
|
||||
const tableName = dropdownLabel.replace("Select ", "");
|
||||
let dropdownName = "";
|
||||
let index = -1;
|
||||
for (let i = 0; i < props.widgetData.dropdownLabelList.length; i++)
|
||||
{
|
||||
if (tableName === props.widgetData.dropdownLabelList[i])
|
||||
{
|
||||
index = i;
|
||||
dropdownName = props.widgetData.dropdownNameList[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -217,6 +233,22 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
dropdownData[index] = (changedData) ? changedData.id : null;
|
||||
setDropdownData(dropdownData);
|
||||
setCounter(counter + 1);
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// if should store in local storage, do so now //
|
||||
// or remove if dropdown was cleared out //
|
||||
/////////////////////////////////////////////////
|
||||
if(props.storeDropdownSelections)
|
||||
{
|
||||
if (changedData?.id)
|
||||
{
|
||||
localStorage.setItem(`${WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT}.${props.widgetMetaData.name}.${dropdownName}`, JSON.stringify(changedData));
|
||||
}
|
||||
else
|
||||
{
|
||||
localStorage.removeItem(`${WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT}.${props.widgetMetaData.name}.${dropdownName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,61 +277,62 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(`No reload widget callback in ${props.label}`)
|
||||
console.log(`No reload widget callback in ${props.widgetMetaData.label}`)
|
||||
}
|
||||
}
|
||||
}, [counter]);
|
||||
|
||||
const widgetContent =
|
||||
<Box sx={{width: "100%"}}>
|
||||
{
|
||||
(props.icon || props.label) && (
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" sx={{width: "100%"}}>
|
||||
<Box py={2}>
|
||||
{
|
||||
props.icon && (
|
||||
<Box
|
||||
ml={3}
|
||||
mt={-4}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
width: "64px",
|
||||
height: "64px",
|
||||
borderRadius: "8px",
|
||||
background: colors.info.main,
|
||||
color: "#ffffff",
|
||||
float: "left"
|
||||
}}
|
||||
>
|
||||
<Icon fontSize="medium" color="inherit">
|
||||
{props.icon}
|
||||
</Icon>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
<Typography variant={props.isChild ? "h6" : "h5"} fontWeight="medium" p={3} display="inline">
|
||||
{props.label}
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" sx={{width: "100%"}}>
|
||||
<Box pt={2}>
|
||||
{
|
||||
props.widgetMetaData?.icon && (
|
||||
<Box
|
||||
ml={3}
|
||||
mt={-4}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
width: "64px",
|
||||
height: "64px",
|
||||
borderRadius: "8px",
|
||||
background: colors.info.main,
|
||||
color: "#ffffff",
|
||||
float: "left"
|
||||
}}
|
||||
>
|
||||
<Icon fontSize="medium" color="inherit">
|
||||
{props.widgetMetaData.icon}
|
||||
</Icon>
|
||||
</Box>
|
||||
|
||||
)
|
||||
}
|
||||
{
|
||||
props.widgetMetaData?.label && (
|
||||
<Typography variant="h5" fontWeight="medium" pl={3} display="inline">
|
||||
{props.widgetMetaData.label}
|
||||
</Typography>
|
||||
{
|
||||
props.labelAdditionalComponentsLeft.map((component, i) =>
|
||||
{
|
||||
return (<span key={i}>{renderComponent(component)}</span>);
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
<Box pr={1}>
|
||||
{
|
||||
effectiveLabelAdditionalComponentsRight.map((component, i) =>
|
||||
{
|
||||
return (<span key={i}>{renderComponent(component)}</span>);
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
{
|
||||
props.labelAdditionalComponentsLeft.map((component, i) =>
|
||||
{
|
||||
return (<span key={i}>{renderComponent(component, i)}</span>);
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
<Box>
|
||||
{
|
||||
effectiveLabelAdditionalComponentsRight.map((component, i) =>
|
||||
{
|
||||
return (<span key={i}>{renderComponent(component, i)}</span>);
|
||||
})
|
||||
}
|
||||
</Box>
|
||||
</Box>
|
||||
{
|
||||
props.widgetData?.dropdownNeedsSelectedText ? (
|
||||
<Box pb={3} pr={3} sx={{width: "100%", textAlign: "right"}}>
|
||||
@ -313,7 +346,7 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||
}
|
||||
</Box>;
|
||||
|
||||
return props.isCard ? <Card sx={{width: "100%"}}>{widgetContent}</Card> : widgetContent;
|
||||
return props.widgetMetaData?.isCard ? <Card sx={{marginTop: props.widgetMetaData?.icon ? 2 : 0, width: "100%"}}>{widgetContent}</Card> : widgetContent;
|
||||
}
|
||||
|
||||
export default Widget;
|
||||
|
37
src/qqq/components/widgets/charts/DefaultChartData.tsx
Normal file
37
src/qqq/components/widgets/charts/DefaultChartData.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const chartColors = ["info", "warning", "primary", "success", "error", "secondary", "dark", "custom1", "custom2", "custom3", "custom4", "custom5"];
|
||||
|
||||
|
||||
//////////////////////////////////////////
|
||||
// structure of default chart data //
|
||||
//////////////////////////////////////////
|
||||
export interface DefaultChartData
|
||||
{
|
||||
labels: string[];
|
||||
datasets: [
|
||||
{
|
||||
label: string;
|
||||
data: number[];
|
||||
backgroundColor: string;
|
||||
} ]
|
||||
};
|
84
src/qqq/components/widgets/charts/StackedBarChart.tsx
Normal file
84
src/qqq/components/widgets/charts/StackedBarChart.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import Box from "@mui/material/Box";
|
||||
import {BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, Title, Tooltip,} from "chart.js";
|
||||
import React from "react";
|
||||
import {Bar} from "react-chartjs-2";
|
||||
import colors from "qqq/assets/theme/base/colors";
|
||||
import {chartColors, DefaultChartData} from "qqq/components/widgets/charts/DefaultChartData";
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend
|
||||
);
|
||||
|
||||
export const options = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
interface Props
|
||||
{
|
||||
data: DefaultChartData;
|
||||
}
|
||||
|
||||
const {gradients} = colors;
|
||||
function StackedBarChart({data}: Props): JSX.Element
|
||||
{
|
||||
const handleClick = (e: Array<{}>) =>
|
||||
{
|
||||
/*
|
||||
if(e && e.length > 0 && data?.dataset?.urls && data?.dataset?.urls.length)
|
||||
{
|
||||
// @ts-ignore
|
||||
navigate(chartData.dataset.urls[e[0]["index"]]);
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
data?.datasets.forEach((dataset: any, index: number) =>
|
||||
{
|
||||
if(! dataset.backgroundColor)
|
||||
{
|
||||
dataset.backgroundColor = gradients[chartColors[index]].state;
|
||||
}
|
||||
});
|
||||
|
||||
return <Box p={3}><Bar data={data} options={options} getElementsAtEvent={handleClick} /></Box>;
|
||||
}
|
||||
|
||||
export default StackedBarChart;
|
@ -19,13 +19,17 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Card} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import Card from "@mui/material/Card";
|
||||
import Icon from "@mui/material/Icon";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import parse from "html-react-parser";
|
||||
import {ReactNode, useMemo} from "react";
|
||||
import React, {useMemo} from "react";
|
||||
import {Pie} from "react-chartjs-2";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import MDBadgeDot from "qqq/components/legacy/MDBadgeDot";
|
||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||
import {chartColors} from "qqq/components/widgets/charts/DefaultChartData";
|
||||
import configs from "qqq/components/widgets/charts/piechart/PieChartConfigs";
|
||||
|
||||
//////////////////////////////////////////
|
||||
@ -38,6 +42,7 @@ export interface PieChartData
|
||||
label: string;
|
||||
backgroundColors?: string[];
|
||||
data: number[];
|
||||
urls?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
@ -45,64 +50,78 @@ export interface PieChartData
|
||||
// Declaring props types for PieChart
|
||||
interface Props
|
||||
{
|
||||
icon?: {
|
||||
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
|
||||
component: ReactNode;
|
||||
};
|
||||
title?: string;
|
||||
description?: string;
|
||||
height?: string | number;
|
||||
chart: PieChartData;
|
||||
chartData: PieChartData;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
function PieChart({icon, title, description, height, chart}: Props): JSX.Element
|
||||
function PieChart({description, chartData}: Props): JSX.Element
|
||||
{
|
||||
const {data, options} = configs(chart?.labels || [], chart?.dataset || {});
|
||||
const navigate = useNavigate();
|
||||
|
||||
const renderChart = (
|
||||
<Box py={2} pr={2} pl={icon.component ? 1 : 2}>
|
||||
{title || description ? (
|
||||
<Box display="flex" px={description ? 1 : 0} pt={description ? 1 : 0}>
|
||||
{icon.component && (
|
||||
<Box
|
||||
width="4rem"
|
||||
height="4rem"
|
||||
borderRadius="xl"
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
color="white"
|
||||
mt={-5}
|
||||
mr={2}
|
||||
sx={{backgroundColor: icon.color || "info"}}
|
||||
>
|
||||
<Icon fontSize="medium">{icon.component}</Icon>
|
||||
if (chartData && chartData.dataset)
|
||||
{
|
||||
chartData.dataset.backgroundColors = chartColors;
|
||||
}
|
||||
|
||||
const {data, options} = configs(chartData?.labels || [], chartData?.dataset || {});
|
||||
|
||||
const handleClick = (e: Array<{}>) =>
|
||||
{
|
||||
if(e && e.length > 0 && chartData?.dataset?.urls && chartData?.dataset?.urls.length)
|
||||
{
|
||||
// @ts-ignore
|
||||
navigate(chartData.dataset.urls[e[0]["index"]]);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card sx={{boxShadow: "none", height: "100%", width: "100%", display: "flex", flexGrow: 1}}>
|
||||
<Box mt={3}>
|
||||
<Grid container alignItems="center">
|
||||
<Grid item xs={5}>
|
||||
|
||||
<Box py={2} pr={2} pl={2}>
|
||||
{useMemo(
|
||||
() => (
|
||||
<Pie data={data} options={options} getElementsAtEvent={handleClick} />
|
||||
),
|
||||
[chartData]
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
<Box mt={icon.component ? -2 : 0}>
|
||||
{title && <MDTypography variant="h6">{title}</MDTypography>}
|
||||
<Box mb={2}>
|
||||
<MDTypography component="div" variant="button" color="text">
|
||||
{parse(description)}
|
||||
</MDTypography>
|
||||
</Grid>
|
||||
<Grid item xs={7}>
|
||||
<Box pr={1}>
|
||||
{
|
||||
data && data.labels ? (
|
||||
(data.labels.map((label: string, index: number) => (
|
||||
<Box key={index}>
|
||||
<MDBadgeDot color={chartColors[index]} size="sm" badgeContent={label} />
|
||||
</Box>
|
||||
)
|
||||
))) : null
|
||||
}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
) : null}
|
||||
{useMemo(
|
||||
() => (
|
||||
<Box height={height}>
|
||||
<Pie data={data} options={options} />
|
||||
</Box>
|
||||
),
|
||||
[chart, height]
|
||||
)}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Divider />
|
||||
{
|
||||
description && (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Box pb={2} px={2} display="flex" flexDirection={{xs: "column", sm: "row"}} mt="auto">
|
||||
<MDTypography variant="button" color="text" fontWeight="light">
|
||||
{parse(description)}
|
||||
</MDTypography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
</Box>
|
||||
</Card>
|
||||
);
|
||||
|
||||
return title || description ? <Card>{renderChart}</Card> : renderChart;
|
||||
}
|
||||
|
||||
// Declaring default props for PieChart
|
||||
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Box from "@mui/material/Box";
|
||||
import Card from "@mui/material/Card";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import parse from "html-react-parser";
|
||||
import MDBadgeDot from "qqq/components/legacy/MDBadgeDot";
|
||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||
import PieChart, {PieChartData} from "qqq/components/widgets/charts/piechart/PieChart";
|
||||
|
||||
// Declaring props types for PieChart
|
||||
interface Props
|
||||
{
|
||||
title?: string;
|
||||
description?: string;
|
||||
data: PieChartData;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
function PieChartCard({title, description, data}: Props): JSX.Element
|
||||
{
|
||||
const allBackgroundColors = ["info", "warning", "primary", "success", "error", "secondary", "dark"];
|
||||
|
||||
if (data && data.dataset)
|
||||
{
|
||||
data.dataset.backgroundColors = allBackgroundColors;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card sx={{height: "100%", width: "100%", display: "flex"}}>
|
||||
<Box display="flex" pt={2} px={2}>
|
||||
<MDTypography variant="h5">{title}</MDTypography>
|
||||
</Box>
|
||||
<Box mt={3}>
|
||||
<Grid container alignItems="center">
|
||||
<Grid item xs={7}>
|
||||
<PieChart chart={data} height="9.5rem" />
|
||||
</Grid>
|
||||
<Grid item xs={5}>
|
||||
<Box pr={1}>
|
||||
{
|
||||
data && data.labels ? (
|
||||
(data.labels.map((label: string, index: number) => (
|
||||
<Box key={index}>
|
||||
<MDBadgeDot color={allBackgroundColors[index]} size="sm" badgeContent={label} />
|
||||
</Box>
|
||||
)
|
||||
))) : null
|
||||
}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Divider />
|
||||
{
|
||||
description && (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Box pb={2} px={2} display="flex" flexDirection={{xs: "column", sm: "row"}} mt="auto">
|
||||
<MDTypography variant="button" color="text" fontWeight="light">
|
||||
{parse(description)}
|
||||
</MDTypography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
</Box>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default PieChartCard;
|
@ -59,16 +59,12 @@ function configs(labels: any, datasets: any)
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: "index",
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
|
@ -23,7 +23,7 @@ import {Theme} from "@mui/material";
|
||||
import Autocomplete from "@mui/material/Autocomplete";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {SxProps} from "@mui/system";
|
||||
import React from "react";
|
||||
import React, {useEffect} from "react";
|
||||
|
||||
|
||||
export interface DropdownOption
|
||||
@ -37,14 +37,25 @@ export interface DropdownOption
|
||||
/////////////////////////
|
||||
interface Props
|
||||
{
|
||||
defaultValue?: any;
|
||||
localStorageKey?: string;
|
||||
label?: string;
|
||||
dropdownOptions?: DropdownOption[];
|
||||
onChangeCallback?: (dropdownLabel: string, data: any) => void;
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
function DropdownMenu({label, dropdownOptions, onChangeCallback, sx}: Props): JSX.Element
|
||||
function DropdownMenu({localStorageKey, defaultValue, label, dropdownOptions, onChangeCallback, sx}: Props): JSX.Element
|
||||
{
|
||||
useEffect(() =>
|
||||
{
|
||||
if(defaultValue)
|
||||
{
|
||||
console.log("CALLING CALLBACK...")
|
||||
onChangeCallback(label, JSON.parse(localStorage.getItem(localStorageKey)));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleOnChange = (event: any, value: any, reason: string) =>
|
||||
{
|
||||
onChangeCallback(label, value);
|
||||
@ -54,12 +65,14 @@ function DropdownMenu({label, dropdownOptions, onChangeCallback, sx}: Props): JS
|
||||
dropdownOptions ? (
|
||||
<span style={{whiteSpace: "nowrap"}}>
|
||||
<Autocomplete
|
||||
defaultValue={defaultValue}
|
||||
size="small"
|
||||
disablePortal
|
||||
id={`${label}-combo-box`}
|
||||
options={dropdownOptions}
|
||||
sx={{...sx, cursor: "pointer"}}
|
||||
onChange={handleOnChange}
|
||||
isOptionEqualToValue={(option, value) => option.id === value.id}
|
||||
renderInput={(params: any) => <TextField {...params} label={label} />}
|
||||
renderOption={(props, option: DropdownOption) => (
|
||||
<li {...props} style={{whiteSpace: "normal"}}>{option.label}</li>
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {Skeleton} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
@ -31,19 +32,19 @@ import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||
|
||||
interface Props
|
||||
{
|
||||
title: string;
|
||||
widgetMetaData: QWidgetMetaData;
|
||||
data: any;
|
||||
reloadWidgetCallback?: (params: string) => void;
|
||||
}
|
||||
|
||||
FieldValueListWidget.defaultProps = {};
|
||||
|
||||
function FieldValueListWidget({title, data, reloadWidgetCallback}: Props): JSX.Element
|
||||
function FieldValueListWidget({widgetMetaData, data, reloadWidgetCallback}: Props): JSX.Element
|
||||
{
|
||||
if(data?.dropdownNeedsSelectedText)
|
||||
{
|
||||
return (
|
||||
<Widget label={title} widgetData={data} reloadWidgetCallback={reloadWidgetCallback}>
|
||||
<Widget widgetMetaData={widgetMetaData} widgetData={data} reloadWidgetCallback={reloadWidgetCallback}>
|
||||
<br />
|
||||
</Widget>
|
||||
);
|
||||
@ -53,7 +54,7 @@ function FieldValueListWidget({title, data, reloadWidgetCallback}: Props): JSX.E
|
||||
{
|
||||
const skeletons = [75, 50, 90];
|
||||
return (
|
||||
<Widget label={title}>
|
||||
<Widget widgetMetaData={widgetMetaData}>
|
||||
<Box p={3} pt={0} display="flex" flexDirection="column">
|
||||
{skeletons.map((s) =>
|
||||
(
|
||||
@ -79,7 +80,7 @@ function FieldValueListWidget({title, data, reloadWidgetCallback}: Props): JSX.E
|
||||
const fieldIndentLevels = data.fieldIndentLevels ?? {};
|
||||
|
||||
return (
|
||||
<Widget label={title} widgetData={data} reloadWidgetCallback={reloadWidgetCallback}>
|
||||
<Widget widgetMetaData={widgetMetaData} widgetData={data} reloadWidgetCallback={reloadWidgetCallback}>
|
||||
<Box p={3} pt={0} display="flex" flexDirection="column">
|
||||
{
|
||||
fields.map((field: QFieldMetaData, index: number) => (
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
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 {DataGridPro, GridCallbackDetails, GridRowParams, MuiEvent} from "@mui/x-data-grid-pro";
|
||||
import React, {useEffect, useState} from "react";
|
||||
@ -30,7 +31,7 @@ import Client from "qqq/utils/qqq/Client";
|
||||
|
||||
interface Props
|
||||
{
|
||||
title: string;
|
||||
widgetMetaData: QWidgetMetaData;
|
||||
data: any;
|
||||
}
|
||||
|
||||
@ -38,7 +39,7 @@ RecordGridWidget.defaultProps = {};
|
||||
|
||||
const qController = Client.getInstance();
|
||||
|
||||
function RecordGridWidget({title, data}: Props): JSX.Element
|
||||
function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element
|
||||
{
|
||||
const [rows, setRows] = useState([]);
|
||||
const [columns, setColumns] = useState([]);
|
||||
@ -121,7 +122,7 @@ function RecordGridWidget({title, data}: Props): JSX.Element
|
||||
|
||||
return (
|
||||
<Widget
|
||||
label={title}
|
||||
widgetMetaData={widgetMetaData}
|
||||
labelAdditionalComponentsLeft={labelAdditionalComponentsLeft}
|
||||
labelAdditionalComponentsRight={labelAdditionalComponentsRight}
|
||||
>
|
||||
|
@ -19,11 +19,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {CircularProgress, Typography} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import Card from "@mui/material/Card";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Icon from "@mui/material/Icon";
|
||||
import {ReactNode} from "react";
|
||||
import React, {ReactNode} from "react";
|
||||
import {NavLink} from "react-router-dom";
|
||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||
|
||||
///////////////////////////////////////////
|
||||
@ -31,8 +31,9 @@ import MDTypography from "qqq/components/legacy/MDTypography";
|
||||
///////////////////////////////////////////
|
||||
export interface StatisticsCardData
|
||||
{
|
||||
title: string;
|
||||
count: number;
|
||||
countFontSize: string;
|
||||
countURL?: string;
|
||||
percentageAmount: number;
|
||||
percentageLabel: string;
|
||||
}
|
||||
@ -42,7 +43,6 @@ export interface StatisticsCardData
|
||||
/////////////////////////
|
||||
interface Props
|
||||
{
|
||||
title: string
|
||||
data: StatisticsCardData;
|
||||
color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark";
|
||||
icon: ReactNode;
|
||||
@ -61,7 +61,7 @@ StatisticsCard.defaultProps = {
|
||||
increaseIsGood: true
|
||||
};
|
||||
|
||||
function StatisticsCard({title, data, color, icon, increaseIsGood}: Props): JSX.Element
|
||||
function StatisticsCard({data, color, icon, increaseIsGood}: Props): JSX.Element
|
||||
{
|
||||
const {count, percentageAmount, percentageLabel} = data;
|
||||
|
||||
@ -90,39 +90,30 @@ function StatisticsCard({title, data, color, icon, increaseIsGood}: Props): JSX.
|
||||
|
||||
return (
|
||||
|
||||
<Card sx={{height: "100%", alignItems: "stretch", flexGrow: 1, display: "flex", marginTop: 3, paddingTop: "0px"}}>
|
||||
<Box display="flex" justifyContent="space-between" pt={1} px={2}>
|
||||
<Box
|
||||
color="#ffffff"
|
||||
borderRadius="xl"
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
width="4rem"
|
||||
height="4rem"
|
||||
mt={-3}
|
||||
sx={{borderRadius: "10px", backgroundColor: color}}
|
||||
>
|
||||
<Icon fontSize="medium" color="inherit">
|
||||
{icon}
|
||||
</Icon>
|
||||
</Box>
|
||||
<Box textAlign="right" lineHeight={1.25}>
|
||||
<MDTypography variant="button" fontWeight="light" color="text">
|
||||
{title}
|
||||
</MDTypography>
|
||||
{
|
||||
count !== undefined ? (
|
||||
<MDTypography variant="h4">{count.toLocaleString()}</MDTypography>
|
||||
) : null
|
||||
}
|
||||
</Box>
|
||||
<Box mt={0} sx={{height: "100%", flexGrow: 1, flexDirection: "column", display: "flex", paddingTop: "0px"}}>
|
||||
<Box mt={0} display="flex" justifyContent="center">
|
||||
{
|
||||
count !== undefined ? (
|
||||
<Typography mt={0} sx={{color: "#344767", display: "flex", alignContent: "flex-end", fontSize: data?.countFontSize ? data?.countFontSize : "40px"}}>
|
||||
{
|
||||
data.countURL ? (
|
||||
<NavLink to={data.countURL}>{count.toLocaleString()}</NavLink>
|
||||
) : (
|
||||
count.toLocaleString()
|
||||
)
|
||||
}
|
||||
</Typography>
|
||||
) : (
|
||||
<CircularProgress sx={{marginTop: "1rem", marginBottom: "20px"}} color="inherit" size={data?.countFontSize ? data.countFontSize : 30}/>
|
||||
)
|
||||
}
|
||||
</Box>
|
||||
{
|
||||
percentageAmount !== undefined && percentageAmount !== 0 ? (
|
||||
<Box px={2}>
|
||||
<Divider />
|
||||
<MDTypography component="p" variant="button" color="text" display="flex">
|
||||
<Box pb={2}>
|
||||
|
||||
<Divider sx={{marginTop: "0px"}} />
|
||||
<MDTypography pl={3} component="p" variant="button" color="text" display="flex">
|
||||
<MDTypography
|
||||
component="span"
|
||||
variant="button"
|
||||
@ -136,7 +127,7 @@ function StatisticsCard({title, data, color, icon, increaseIsGood}: Props): JSX.
|
||||
</Box>
|
||||
) : null
|
||||
}
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -51,20 +51,12 @@ export interface TableDataInput
|
||||
/////////////////////////
|
||||
interface Props
|
||||
{
|
||||
title: string;
|
||||
linkText?: string;
|
||||
linkURL?: string;
|
||||
noRowsFoundHTML?: string;
|
||||
data: TableDataInput;
|
||||
reloadWidgetCallback?: (params: string) => void;
|
||||
widgetIndex?: number;
|
||||
isChild?: boolean;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const qController = Client.getInstance();
|
||||
function TableCard({noRowsFoundHTML, data, reloadWidgetCallback}: Props): JSX.Element
|
||||
function TableCard({noRowsFoundHTML, data}: Props): JSX.Element
|
||||
{
|
||||
const [qInstance, setQInstance] = useState(null as QInstance);
|
||||
|
||||
|
@ -114,6 +114,14 @@ async function getDefaultFilter(tableMetaData: QTableMetaData, searchParams: URL
|
||||
{
|
||||
values = await qController.possibleValues(tableMetaData.name, field.name, "", values);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// log message if no values were returned //
|
||||
////////////////////////////////////////////
|
||||
if (! values || values.length === 0)
|
||||
{
|
||||
console.warn("WARNING: No possible values were returned for [" + field.possibleValueSourceName + "] for values [" + criteria.values + "].");
|
||||
}
|
||||
}
|
||||
|
||||
defaultFilter.items.push({
|
||||
|
Reference in New Issue
Block a user