SPRINT-18: fixed to dashboards, removed and moved around all the things

This commit is contained in:
Tim Chamberlain
2023-01-04 11:40:21 -06:00
parent e49f178738
commit 267580b44b
460 changed files with 9717 additions and 11057 deletions

View File

@ -0,0 +1,319 @@
/*
* 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 {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Card from "@mui/material/Card";
import Icon from "@mui/material/Icon";
import Typography from "@mui/material/Typography";
import React, {useEffect, useState} from "react";
import {Link, useNavigate} from "react-router-dom";
import colors from "qqq/components/legacy/colors";
import DropdownMenu, {DropdownOption} from "qqq/components/widgets/components/DropdownMenu";
export interface WidgetData
{
dropdownLabelList?: string[];
dropdownNameList?: string[];
dropdownDataList?: {
id: string,
label: string
}[][];
dropdownNeedsSelectedText?: string;
}
interface Props
{
icon?: string;
label: string;
labelAdditionalComponentsLeft: LabelComponent[];
labelAdditionalComponentsRight: LabelComponent[];
widgetData?: WidgetData;
children: JSX.Element;
reloadWidgetCallback?: (params: string) => void;
isChild?: boolean;
isCard?: boolean;
}
Widget.defaultProps = {
isCard: true,
isChild: false,
label: null,
widgetData: {},
labelAdditionalComponentsLeft: [],
labelAdditionalComponentsRight: [],
};
export class LabelComponent
{
}
export class HeaderLink extends LabelComponent
{
label: string;
to: string
constructor(label: string, to: string)
{
super();
this.label = label;
this.to = to;
}
}
export class AddNewRecordButton extends LabelComponent
{
table: QTableMetaData;
label: string;
defaultValues: any;
disabledFields: any;
constructor(table: QTableMetaData, defaultValues: any, label: string = "Add new", disabledFields: any = defaultValues)
{
super();
this.table = table;
this.label = label;
this.defaultValues = defaultValues;
this.disabledFields = disabledFields;
}
}
export class Dropdown extends LabelComponent
{
label: string;
options: DropdownOption[];
onChangeCallback: any
constructor(label: string, options: DropdownOption[], onChangeCallback: any)
{
super();
this.label = label;
this.options = options;
this.onChangeCallback = onChangeCallback;
}
}
function Widget(props: React.PropsWithChildren<Props>): JSX.Element
{
const navigate = useNavigate();
const [dropdownData, setDropdownData] = useState([]);
const [counter, setCounter] = useState(0);
function openEditForm(table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any)
{
navigate(`#/createChild=${table.name}/defaultValues=${JSON.stringify(defaultValues)}/disabledFields=${JSON.stringify(disabledFields)}`)
}
function renderComponent(component: LabelComponent)
{
if(component instanceof HeaderLink)
{
const link = component as HeaderLink
return (
<Typography variant="body2" p={2} display="inline">
{link.to ? <Link to={link.to}>{link.label}</Link> : null}
</Typography>
);
}
if (component instanceof AddNewRecordButton)
{
const addNewRecordButton = component as AddNewRecordButton
return (
<Typography variant="body2" p={2} pr={1} display="inline">
<Button onClick={() => openEditForm(addNewRecordButton.table, null, addNewRecordButton.defaultValues, addNewRecordButton.disabledFields)}>{addNewRecordButton.label}</Button>
</Typography>
);
}
if (component instanceof Dropdown)
{
const dropdown = component as Dropdown
return (
<Box my={2} mr={2} sx={{float: "right"}}>
<DropdownMenu
sx={{width: 200, marginLeft: "15px"}}
label={`Select ${dropdown.label}`}
dropdownOptions={dropdown.options}
onChangeCallback={dropdown.onChangeCallback}
/>
</Box>
);
}
return (<div>Unsupported component type.</div>)
}
///////////////////////////////////////////////////////////////////
// make dropdowns from the widgetData appear as label-components //
///////////////////////////////////////////////////////////////////
const effectiveLabelAdditionalComponentsRight: LabelComponent[] = [];
if(props.labelAdditionalComponentsRight)
{
props.labelAdditionalComponentsRight.map((component) => effectiveLabelAdditionalComponentsRight.push(component));
}
if(props.widgetData && props.widgetData.dropdownDataList)
{
props.widgetData.dropdownDataList?.map((dropdownData: any, index: number) =>
{
effectiveLabelAdditionalComponentsRight.push(new Dropdown(props.widgetData.dropdownLabelList[index], dropdownData, handleDataChange))
});
}
function handleDataChange(dropdownLabel: string, changedData: any)
{
if(dropdownData)
{
///////////////////////////////////////////
// find the index base on selected label //
///////////////////////////////////////////
const tableName = dropdownLabel.replace("Select ", "");
let index = -1;
for (let i = 0; i < props.widgetData.dropdownLabelList.length; i++)
{
if (tableName === props.widgetData.dropdownLabelList[i])
{
index = i;
break;
}
}
if (index < 0)
{
throw(`Could not find table name for label ${tableName}`);
}
dropdownData[index] = (changedData) ? changedData.id : null;
setDropdownData(dropdownData);
setCounter(counter + 1);
}
}
useEffect(() =>
{
if(dropdownData)
{
let params = "";
for (let i = 0; i < dropdownData.length; i++)
{
if (i > 0)
{
params += "&";
}
params += `${props.widgetData.dropdownNameList[i]}=`;
if(dropdownData[i])
{
params += `${dropdownData[i]}`;
}
}
if(props.reloadWidgetCallback)
{
props.reloadWidgetCallback(params);
}
else
{
console.log(`No reload widget callback in ${props.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}
</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.widgetData?.dropdownNeedsSelectedText ? (
<Box pb={3} pr={3} sx={{width: "100%", textAlign: "right"}}>
<Typography variant="body2">
{props.widgetData?.dropdownNeedsSelectedText}
</Typography>
</Box>
) : (
props.children
)
}
</Box>;
return props.isCard ? <Card sx={{width: "100%"}}>{widgetContent}</Card> : widgetContent;
}
export default Widget;