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,32 @@
/*
* 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 Divider from "@mui/material/Divider";
function DividerWidget(): JSX.Element
{
return (
<Divider sx={{padding: "1px", background: "red"}}/>
);
}
export default DividerWidget;

View File

@ -0,0 +1,108 @@
/*
* 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 {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import {Skeleton} from "@mui/material";
import Box from "@mui/material/Box";
import Icon from "@mui/material/Icon";
import Typography from "@mui/material/Typography";
import React from "react";
import Widget from "qqq/components/widgets/Widget";
import ValueUtils from "qqq/utils/qqq/ValueUtils";
interface Props
{
title: string;
data: any;
reloadWidgetCallback?: (params: string) => void;
}
FieldValueListWidget.defaultProps = {};
function FieldValueListWidget({title, data, reloadWidgetCallback}: Props): JSX.Element
{
if(data?.dropdownNeedsSelectedText)
{
return (
<Widget label={title} widgetData={data} reloadWidgetCallback={reloadWidgetCallback}>
<br />
</Widget>
);
}
if(!data.fields || !data.record)
{
const skeletons = [75, 50, 90];
return (
<Widget label={title}>
<Box p={3} pt={0} display="flex" flexDirection="column">
{skeletons.map((s) =>
(
<Box key={s} display="flex" flexDirection="row" pr={2}>
<Typography variant="button" pr={2}>
<Skeleton width={s + "px"} />
</Typography>
<Typography variant="button">
<Skeleton width={2*(s + (100 - (1.25*s))) + "px"} />
</Typography>
</Box>
))
}
</Box>
</Widget>
);
}
const fields = data.fields.map((f: any) => new QFieldMetaData(f));
const record = new QRecord(data.record);
const fieldLabelPrefixIconNames = data.fieldLabelPrefixIconNames ?? {};
const fieldLabelPrefixIconColors = data.fieldLabelPrefixIconColors ?? {};
const fieldIndentLevels = data.fieldIndentLevels ?? {};
return (
<Widget label={title} widgetData={data} reloadWidgetCallback={reloadWidgetCallback}>
<Box p={3} pt={0} display="flex" flexDirection="column">
{
fields.map((field: QFieldMetaData, index: number) => (
<Box key={field.label} flexDirection="row" pr={2} pl={3 * (fieldIndentLevels[field.name] ?? 0)}>
{
fieldLabelPrefixIconNames[field.name] &&
<Icon color={fieldLabelPrefixIconColors[field.name] ?? "primary"} sx={{position: "relative", top: "4px", paddingRight: "8px", width: "24px"}}>{fieldLabelPrefixIconNames[field.name]}</Icon>
}
{
field.label &&
<Typography variant="button" fontWeight="bold" pr={1} sx={{textTransform: "none", color: "#344767"}}>
{field.label}:
</Typography>
}
<Typography variant="button" fontWeight="regular" color="text" sx={{textTransform: "none", color: "#7b809a", fontWeight: 400}}>
{ValueUtils.getDisplayValue(field, record, "view")}
</Typography>
</Box>
))
}
</Box>
</Widget>
);
}
export default FieldValueListWidget;

View File

@ -0,0 +1,57 @@
/*
* 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 React from "react";
import MDTypography from "qqq/components/legacy/MDTypography";
interface Props
{
label: string;
url: string;
}
interface IframeProps
{
iframe: string;
}
function Iframe({iframe}: IframeProps)
{
return (<div dangerouslySetInnerHTML={{__html: iframe || ""}} />);
}
function QuickSightChart({label, url}: Props): JSX.Element
{
const iframe = `<iframe style='border: 0 solid #04aaef; height: 411px; width: 99%' title=${label} src=${url} />`;
return (
<Card sx={{height: "100%"}}>
<Box padding="1rem">
<MDTypography variant="h5">{label}</MDTypography>
<Iframe iframe={iframe} />
</Box>
</Card>
);
}
export default QuickSightChart;

View File

@ -0,0 +1,162 @@
/*
* 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 {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";
import {useNavigate} from "react-router-dom";
import Widget, {AddNewRecordButton, HeaderLink, LabelComponent} from "qqq/components/widgets/Widget";
import DataGridUtils from "qqq/utils/DataGridUtils";
import Client from "qqq/utils/qqq/Client";
interface Props
{
title: string;
data: any;
}
RecordGridWidget.defaultProps = {};
const qController = Client.getInstance();
function RecordGridWidget({title, data}: Props): JSX.Element
{
const [rows, setRows] = useState([]);
const [columns, setColumns] = useState([]);
const navigate = useNavigate();
useEffect(() =>
{
if (data && data.childTableMetaData && data.queryOutput)
{
const records: QRecord[] = [];
const queryOutputRecords = data.queryOutput.records;
if (queryOutputRecords)
{
for (let i = 0; i < queryOutputRecords.length; i++)
{
records.push(new QRecord(queryOutputRecords[i]));
}
}
const tableMetaData = new QTableMetaData(data.childTableMetaData);
const {rows, columnsToRender} = DataGridUtils.makeRows(records, tableMetaData);
const childTablePath = data.tablePath + (data.tablePath.endsWith("/") ? "" : "/")
const columns = DataGridUtils.setupGridColumns(tableMetaData, columnsToRender, childTablePath);
////////////////////////////////////////////////////////////////
// do not not show the foreign-key column of the parent table //
////////////////////////////////////////////////////////////////
if(data.defaultValuesForNewChildRecords)
{
for (let i = 0; i < columns.length; i++)
{
if(data.defaultValuesForNewChildRecords[columns[i].field])
{
columns.splice(i, 1);
i--
}
}
}
setRows(rows);
setColumns(columns);
}
}, [data]);
const labelAdditionalComponentsLeft: LabelComponent[] = []
if(data && data.viewAllLink)
{
labelAdditionalComponentsLeft.push(new HeaderLink("View All", data.viewAllLink));
}
const labelAdditionalComponentsRight: LabelComponent[] = []
if(data && data.canAddChildRecord)
{
let disabledFields = data.disabledFieldsForNewChildRecords;
if(!disabledFields)
{
disabledFields = data.defaultValuesForNewChildRecords;
}
labelAdditionalComponentsRight.push(new AddNewRecordButton(data.childTableMetaData, data.defaultValuesForNewChildRecords, "Add new", disabledFields))
}
const handleRowClick = (params: GridRowParams, event: MuiEvent<React.MouseEvent>, details: GridCallbackDetails) =>
{
(async () =>
{
const qInstance = await qController.loadMetaData()
const tablePath = qInstance.getTablePathByName(data.childTableMetaData.name)
if(tablePath)
{
navigate(`${tablePath}/${params.id}`);
}
})();
};
return (
<Widget
label={title}
labelAdditionalComponentsLeft={labelAdditionalComponentsLeft}
labelAdditionalComponentsRight={labelAdditionalComponentsRight}
>
<DataGridPro
autoHeight
rows={rows}
disableSelectionOnClick
columns={columns}
rowBuffer={10}
getRowClassName={(params) => (params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd")}
onRowClick={handleRowClick}
// getRowHeight={() => "auto"} // maybe nice? wraps values in cells...
// components={{Toolbar: CustomToolbar, Pagination: CustomPagination, LoadingOverlay: Loading}}
// pinnedColumns={pinnedColumns}
// onPinnedColumnsChange={handlePinnedColumnsChange}
// pagination
// paginationMode="server"
// sortingMode="server"
// filterMode="server"
// page={pageNumber}
// checkboxSelection
// rowCount={totalRecords === null ? 0 : totalRecords}
// onPageSizeChange={handleRowsPerPageChange}
// onStateChange={handleStateChange}
// density={density}
// loading={loading}
// filterModel={filterModel}
// onFilterModelChange={handleFilterChange}
// columnVisibilityModel={columnVisibilityModel}
// onColumnVisibilityModelChange={handleColumnVisibilityChange}
// onColumnOrderChange={handleColumnOrderChange}
// onSelectionModelChange={selectionChanged}
// onSortModelChange={handleSortChange}
// sortingOrder={[ "asc", "desc" ]}
// sortModel={columnSortModel}
/>
</Widget>
);
}
export default RecordGridWidget;

View File

@ -0,0 +1,153 @@
/*
* 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 {Check, Pending, RocketLaunch} from "@mui/icons-material";
import {Icon, Skeleton, StepConnector} from "@mui/material";
import Box from "@mui/material/Box";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";
import Stepper from "@mui/material/Stepper";
import {withStyles} from "@mui/styles";
import React from "react";
import {NavLink} from "react-router-dom";
/////////////////////////////////////////////
// structure of expected stepper card data //
/////////////////////////////////////////////
export interface StepperCardData
{
title: string;
activeStep: number;
steps: {
label: string;
linkText: string;
linkURL: string;
iconOverride: string;
colorOverride: string;
}[];
}
////////////////////////////////////
// define properties and defaults //
////////////////////////////////////
interface Props
{
data: StepperCardData;
}
function StepperCard({data}: Props): JSX.Element
{
const activeStep = data && data.activeStep ? data.activeStep : 0;
const CustomizedConnector = withStyles({
line: {
color: "#344767",
marginTop: "9px",
marginRight: "30px",
marginLeft: "30px",
}
})(StepConnector);
// console.log(`data ${JSON.stringify(data)}`);
return (
<Stepper connector={<CustomizedConnector />} activeStep={activeStep} alternativeLabel sx={{paddingBottom: "0px", boxShadow: "none", background: "white"}}>
{
data && data.steps ? (
data.steps.map((step, index) => (
<Step key={step.label}>
{
index < activeStep && (
<Box>
<StepLabel icon={step.iconOverride ? <Icon>{step.iconOverride}</Icon> : <Check />} sx={{
color: step.colorOverride ?? "green",
fontSize: "35px",
"& .MuiStepLabel-label.Mui-completed.MuiStepLabel-alternativeLabel":
{
color: `${step.colorOverride ?? "green"} !important`,
}
}}>{step.label}</StepLabel>
</Box>
)
}
{
index > activeStep && (
<Box>
<StepLabel icon={step.iconOverride ? <Icon>{step.iconOverride}</Icon> : <Pending />} sx={{
color: step.colorOverride ?? "#ced4da",
fontSize: "35px",
"& .MuiStepLabel-label.MuiStepLabel-alternativeLabel":
{
color: `${step.colorOverride ?? "#ced4da"} !important`,
}
}}>{step.label}</StepLabel>
</Box>
)
}
{
index === activeStep && (
<Box>
<StepLabel icon={step.iconOverride ? <Icon>{step.iconOverride}</Icon> : <RocketLaunch />} sx={{
color: step.colorOverride ?? "#04aaef",
fontSize: "35px",
"& .MuiStepLabel-label.MuiStepLabel-alternativeLabel":
{
color: `${step.colorOverride ?? "#344767"} !important`,
}
}}>{step.label}</StepLabel>
{
step.linkURL && (
<Box sx={{textAlign: "center", fontSize: "14px"}}>
<NavLink to={step.linkURL}>{step.linkText}</NavLink>
</Box>
)
}
</Box>
)
}
</Step>
))
) : (
Array(5).fill(0).map((_, i) =>
<Step key={`step-${i}`}>
<Box>
<StepLabel icon={<Pending />} sx={{
color: "#ced4da",
fontSize: "35px",
"& .MuiStepLabel-label.MuiStepLabel-alternativeLabel":
{
color: "#ced4da !important",
}
}}><Skeleton /></StepLabel>
</Box>
</Step>
)
)
}
</Stepper>
);
}
export default StepperCard;

View File

@ -0,0 +1,144 @@
/*
* 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 {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import {Box, Grid} from "@mui/material";
import {VectorMap} from "@react-jvectormap/core";
import {usAea} from "@react-jvectormap/unitedstates";
import React, {useEffect, useState} from "react";
import Client from "qqq/utils/qqq/Client";
////////////////////////////////////////////////
// structure of expected US and A widget data //
////////////////////////////////////////////////
export interface MapMarkerData
{
name: string;
latitude: number;
longitude: number;
}
export interface USMapWidgetData
{
height: string;
markers?: MapMarkerData[];
}
////////////////////////////////////
// define properties and defaults //
////////////////////////////////////
interface Props
{
widgetIndex: number;
label: string;
icon?: string;
reloadWidgetCallback?: (widgetIndex: number, params: string) => void;
data: USMapWidgetData;
}
const qController = Client.getInstance();
function USMapWidget(props: Props, ): JSX.Element
{
const [qInstance, setQInstance] = useState(null as QInstance);
useEffect(() =>
{
(async () =>
{
const newQInstance = await qController.loadMetaData();
setQInstance(newQInstance);
})();
}, []);
return (
<Grid container>
<Grid item xs={12} sx={{height: props.data?.height}}>
{
props.data?.height && (
<Box mt={3} sx={{height: "100%"}}>
<VectorMap
map={usAea}
zoomOnScroll={false}
zoomButtons={false}
markersSelectable
backgroundColor="transparent"
markers={[
{
name: "edison",
latLng: [40.5274, -74.3933],
},
{
name: "stockton",
latLng: [37.975556, -121.300833],
},
{
name: "patterson",
latLng: [37.473056, -121.132778],
},
]}
regionStyle={{
initial: {
fill: "#dee2e7",
"fill-opacity": 1,
stroke: "none",
"stroke-width": 0,
"stroke-opacity": 0,
},
}}
markerStyle={{
initial: {
fill: "#e91e63",
stroke: "#ffffff",
"stroke-width": 5,
"stroke-opacity": 0.5,
r: 7,
},
hover: {
fill: "E91E63",
stroke: "#ffffff",
"stroke-width": 5,
"stroke-opacity": 0.5,
},
selected: {
fill: "E91E63",
stroke: "#ffffff",
"stroke-width": 5,
"stroke-opacity": 0.5,
},
}}
style={{
marginTop: "-1.5rem",
}}
onRegionTipShow={() => false}
onMarkerTipShow={() => false}
/>
</Box>
)
}
</Grid>
</Grid>
);
}
export default USMapWidget;