Feedback from code reviews

This commit is contained in:
2022-08-11 10:26:59 -05:00
parent 6506115bb0
commit ca39a34970
15 changed files with 176 additions and 196 deletions

View File

@ -60,6 +60,7 @@
"max-len": "off",
"no-console": "off",
"no-constant-condition": "off",
"no-continue": "off",
"no-shadow": "off",
"no-unused-vars": "off",
"no-plusplus": "off",

View File

@ -13,7 +13,7 @@
"@fullcalendar/interaction": "5.10.0",
"@fullcalendar/react": "5.10.0",
"@fullcalendar/timegrid": "5.10.0",
"@kingsrook/qqq-frontend-core": "1.0.8",
"@kingsrook/qqq-frontend-core": "1.0.9",
"@mui/icons-material": "5.4.1",
"@mui/material": "5.4.1",
"@mui/styled-engine": "5.4.1",

View File

@ -35,7 +35,6 @@ import {setMiniSidenav, setOpenConfigurator, useMaterialUIController} from "cont
import nfLogo from "assets/images/nutrifresh_one_icon_white.png";
import {Md5} from "ts-md5/dist/md5";
import {useCookies} from "react-cookie";
import {QAppMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppMetaData";
import EntityCreate from "./qqq/pages/entity-create";
import EntityList from "./qqq/pages/entity-list";
import EntityView from "./qqq/pages/entity-view";
@ -51,6 +50,7 @@ import QClient from "./qqq/utils/QClient";
import {QAppNodeType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppNodeType";
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import QProcessUtils from "qqq/utils/QProcessUtils";
import {QAppTreeNode} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppTreeNode";
///////////////////////////////////////////////////////////////////////////////////////////////
// define the parts of the nav that are static - before the qqq tables etc get dynamic added //
@ -94,6 +94,7 @@ export default function App()
} = useAuth0();
const [loadingToken, setLoadingToken] = useState(false);
const [isFullyAuthenticated, setIsFullyAuthenticated] = useState(false);
const [profileRoutes, setProfileRoutes] = useState({});
useEffect(() =>
{
@ -137,8 +138,6 @@ export default function App()
const [sideNavRoutes, setSideNavRoutes] = useState(getStaticRoutes());
const [appRoutes, setAppRoutes] = useState(null as any);
const dynamicAppChildElement = <AppHome />;
////////////////////////////////////////////
// load qqq meta data to make more routes //
////////////////////////////////////////////
@ -152,7 +151,7 @@ export default function App()
(async () =>
{
function addAppToSideNavList(app: QAppMetaData, appList: any[], parentPath: string, depth: number)
function addAppToSideNavList(app: QAppTreeNode, appList: any[], parentPath: string, depth: number)
{
const path = `${parentPath}/${app.name}`;
if (app.type !== QAppNodeType.APP)
@ -160,62 +159,65 @@ export default function App()
return;
}
if (app.type === QAppNodeType.APP && depth <= 2)
if (depth > 2)
{
const childList: any[] = [];
app.children.forEach((child: QAppMetaData) =>
{
addAppToSideNavList(child, childList, path, depth + 1);
});
console.warn("App depth is greater than 2 - not including app in side nav...");
return;
}
if (childList.length === 0)
{
if (depth === 0)
{
/////////////////////////////////////////////////////
// at level 0, the entry must always be a collapse //
/////////////////////////////////////////////////////
appList.push({
type: "collapse",
name: app.label,
key: app.name,
route: path,
icon: <Icon fontSize="medium">{app.iconName}</Icon>,
noCollapse: true,
component: <AppHome />,
});
}
else
{
appList.push({
name: app.label,
key: app.name,
route: path,
icon: <Icon fontSize="medium">{app.iconName}</Icon>,
component: <AppHome />,
});
}
}
else
const childList: any[] = [];
app.children.forEach((child: QAppTreeNode) =>
{
addAppToSideNavList(child, childList, path, depth + 1);
});
if (childList.length === 0)
{
if (depth === 0)
{
/////////////////////////////////////////////////////
// at level 0, the entry must always be a collapse //
/////////////////////////////////////////////////////
appList.push({
type: "collapse",
name: app.label,
key: app.name,
dropdown: true,
route: path,
icon: <Icon fontSize="medium">{app.iconName}</Icon>,
collapse: childList,
noCollapse: true,
component: <AppHome />,
});
}
else
{
appList.push({
name: app.label,
key: app.name,
route: path,
icon: <Icon fontSize="medium">{app.iconName}</Icon>,
component: <AppHome />,
});
}
}
else
{
appList.push({
type: "collapse",
name: app.label,
key: app.name,
dropdown: true,
icon: <Icon fontSize="medium">{app.iconName}</Icon>,
collapse: childList,
});
}
}
function addAppToAppRoutesList(metaData: QInstance, app: QAppMetaData, routeList: any[], parentPath: string, depth: number)
function addAppToAppRoutesList(metaData: QInstance, app: QAppTreeNode, routeList: any[], parentPath: string, depth: number)
{
const path = `${parentPath}/${app.name}`;
if (app.type === QAppNodeType.APP)
{
app.children.forEach((child: QAppMetaData) =>
app.children.forEach((child: QAppTreeNode) =>
{
addAppToAppRoutesList(metaData, child, routeList, path, depth + 1);
});
@ -261,16 +263,6 @@ export default function App()
const processesForTable = QProcessUtils.getProcessesForTable(metaData, table.name, true);
processesForTable.forEach((process) =>
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// special provision for the standard bulk processes - strip the table name from the process name //
// todo - this var isn't used - is this needed?
////////////////////////////////////////////////////////////////////////////////////////////////////
let processName = process.name;
if (processName.startsWith(`${process.tableName}.`))
{
processName = processName.replace(`${process.tableName}.`, "");
}
routeList.push({
name: process.label,
key: process.name,
@ -295,11 +287,11 @@ export default function App()
{
const metaData = await QClient.getInstance().loadMetaData();
let profileRoute = {};
let profileRoutes = {};
const gravatarBase = "http://www.gravatar.com/avatar/";
const hash = Md5.hashStr(user.email);
const profilePicture = `${gravatarBase}${hash}`;
profileRoute = {
profileRoutes = {
type: "collapse",
name: user.name,
key: user.name,
@ -319,6 +311,7 @@ export default function App()
},
],
};
setProfileRoutes(profileRoutes);
const sideNavAppList = [] as any[];
const appRoutesList = [] as any[];
@ -331,7 +324,7 @@ export default function App()
const newSideNavRoutes = getStaticRoutes();
// @ts-ignore
newSideNavRoutes.unshift(profileRoute);
newSideNavRoutes.unshift(profileRoutes);
for (let i = 0; i < sideNavAppList.length; i++)
{
newSideNavRoutes.push(sideNavAppList[i]);
@ -386,6 +379,9 @@ export default function App()
document.scrollingElement.scrollTop = 0;
}, [pathname]);
///////////////////////////////////////////////////////////////////////////////////////////
// convert an object that works for the Sidenav into one that works for the react-router //
///////////////////////////////////////////////////////////////////////////////////////////
const getRoutes = (allRoutes: any[]): any => allRoutes.map(
(route: {
collapse: any;
@ -452,7 +448,8 @@ export default function App()
<Routes>
<Route path="*" element={<Navigate to="/dashboards/analytics" />} />
{appRoutes && getRoutes(appRoutes)}
{sideNavRoutes && getRoutes(sideNavRoutes)}
{getRoutes(getStaticRoutes())}
{profileRoutes && getRoutes([profileRoutes])}
</Routes>
</ThemeProvider>
)

View File

@ -29,6 +29,8 @@ import Avatar from "@mui/material/Avatar";
import Icon from "@mui/material/Icon";
import QRecordSidebar from "qqq/components/QRecordSidebar";
import QTableUtils from "qqq/utils/QTableUtils";
import colors from "assets/theme/base/colors";
import {QSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QSection";
interface Props
{
@ -46,6 +48,7 @@ function EntityForm({table, id}: Props): JSX.Element
const [initialValues, setInitialValues] = useState({} as { [key: string]: string });
const [formFields, setFormFields] = useState(null as Map<string, any>);
const [t1sectionName, setT1SectionName] = useState(null as string);
const [nonT1Sections, setNonT1Sections] = useState([] as QSection[]);
const [alertContent, setAlertContent] = useState("");
@ -53,7 +56,7 @@ function EntityForm({table, id}: Props): JSX.Element
const [formValues, setFormValues] = useState({} as { [key: string]: string });
const [tableMetaData, setTableMetaData] = useState(null as QTableMetaData);
const [record, setRecord] = useState(null as QRecord);
const [tableSections, setTableSections] = useState(null as any);
const [tableSections, setTableSections] = useState(null as QSection[]);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const navigate = useNavigate();
@ -76,7 +79,7 @@ function EntityForm({table, id}: Props): JSX.Element
{
return <div>Loading...</div>;
}
return <QDynamicForm formData={formData} primaryKeyId={tableMetaData.primaryKeyField} />;
return <QDynamicForm formData={formData} />;
}
if (!asyncLoadInited)
@ -131,6 +134,7 @@ function EntityForm({table, id}: Props): JSX.Element
/////////////////////////////////////
const dynamicFormFieldsBySection = new Map<string, any>();
let t1sectionName;
const nonT1Sections: QSection[] = [];
for (let i = 0; i < tableSections.length; i++)
{
const section = tableSections[i];
@ -140,6 +144,11 @@ function EntityForm({table, id}: Props): JSX.Element
{
const fieldName = section.fieldNames[j];
const field = tableMetaData.fields.get(fieldName);
////////////////////////////////////////////////////////////////////////////////////////////
// if id !== null - means we're on the edit screen -- show all fields on the edit screen. //
// || (or) we're on the insert screen in which case, only show editable fields. //
////////////////////////////////////////////////////////////////////////////////////////////
if (id !== null || field.isEditable)
{
sectionDynamicFormFields.push(dynamicFormFields[fieldName]);
@ -153,6 +162,7 @@ function EntityForm({table, id}: Props): JSX.Element
////////////////////////////////////////////////////////////////////////////////////////////////
tableSections.splice(i, 1);
i--;
continue;
}
else
{
@ -166,8 +176,13 @@ function EntityForm({table, id}: Props): JSX.Element
{
t1sectionName = section.name;
}
else
{
nonT1Sections.push(section);
}
}
setT1SectionName(t1sectionName);
setNonT1Sections(nonT1Sections);
setFormFields(dynamicFormFieldsBySection);
setValidations(Yup.object().shape(formValidations));
@ -177,6 +192,11 @@ function EntityForm({table, id}: Props): JSX.Element
const handleCancelClicked = () =>
{
///////////////////////////////////////////////////////////////////////////////////////
// todo - we might have rather just done a navigate(-1) (to keep history clean) //
// but if the user used the anchors on the page, this doesn't effectively cancel... //
// what we have here pushed a new history entry (I think?), so could be better //
///////////////////////////////////////////////////////////////////////////////////////
if (id !== null)
{
const path = `${location.pathname.replace(/\/edit$/, "")}`;
@ -274,7 +294,7 @@ function EntityForm({table, id}: Props): JSX.Element
<Card id={`${t1sectionName}`} sx={{overflow: "visible"}}>
<MDBox display="flex" p={3} pb={1}>
<MDBox mr={1.5}>
<Avatar sx={{bgcolor: "rgb(26, 115, 232)"}}>
<Avatar sx={{bgcolor: colors.info.main}}>
<Icon>
{tableMetaData?.iconName}
</Icon>
@ -295,23 +315,22 @@ function EntityForm({table, id}: Props): JSX.Element
}
</Card>
</MDBox>
{tableSections && formFields ? tableSections.map((section: any) => (section.name !== t1sectionName
? (
<MDBox key={`edit-card-${section.name}`} pb={3}>
<Card id={section.name} sx={{overflow: "visible"}}>
<MDTypography variant="h5" p={3} pb={1}>
{section.label}
</MDTypography>
<MDBox pb={3} px={3}>
<MDBox p={3} width="100%">
{
getFormSection(values, touched, formFields.get(section.name), errors)
}
</MDBox>
{formFields && nonT1Sections.length ? nonT1Sections.map((section: QSection) => (
<MDBox key={`edit-card-${section.name}`} pb={3}>
<Card id={section.name} sx={{overflow: "visible"}}>
<MDTypography variant="h5" p={3} pb={1}>
{section.label}
</MDTypography>
<MDBox pb={3} px={3}>
<MDBox p={3} width="100%">
{
getFormSection(values, touched, formFields.get(section.name), errors)
}
</MDBox>
</Card>
</MDBox>
) : null)) : null}
</MDBox>
</Card>
</MDBox>
)) : null}
<MDBox component="div" p={3}>
<Grid container justifyContent="flex-end" spacing={3}>

View File

@ -58,7 +58,7 @@ import {
} from "context";
// qqq
import QBreadcrumbs from "qqq/components/QBreadcrumbs";
import QBreadcrumbs, {routeToLabel} from "qqq/components/QBreadcrumbs";
// Declaring prop types for Navbar
interface Props
@ -156,7 +156,7 @@ function Navbar({absolute, light, isMini}: Props): JSX.Element
},
});
const breadcrumbTitle = route[route.length - 1].replace(/([A-Z])/g, " $1").trim();
const breadcrumbTitle = routeToLabel(route[route.length - 1]);
return (
<AppBar

View File

@ -44,9 +44,14 @@ const ucFirst = (input: string): string =>
return (input.substring(0, 1).toUpperCase() + input.substring(1));
};
const routeToLabel = (route: string): string =>
export const routeToLabel = (route: string): string =>
{
const label = ucFirst(route.replace(".", " ").replace("-", " ").replace("_", " ").replace(/([A-Z])/g, " $1"));
const label = ucFirst(route
.replace(".", " ")
.replace("-", " ")
.replace("_", " ")
.replace(/([a-z])([A-Z]+)/g, "$1 $2") // transform personUSA => person USA
.replace(/^([A-Z]+)([A-Z])([a-z])/, "$1 $2$3")); // transform USAPerson => USA Person
return (label);
};

View File

@ -61,12 +61,10 @@ interface QDeleteButtonProps
export function QDeleteButton({onClickHandler}: QDeleteButtonProps): JSX.Element
{
return (
<MDBox ml={3} mr={3}>
<MDBox width={standardWidth}>
<MDButton variant="gradient" color="primary" size="small" onClick={onClickHandler} fullWidth startIcon={<Icon>delete</Icon>}>
Delete
</MDButton>
</MDBox>
<MDBox ml={3} mr={3} width={standardWidth}>
<MDButton variant="gradient" color="primary" size="small" onClick={onClickHandler} fullWidth startIcon={<Icon>delete</Icon>}>
Delete
</MDButton>
</MDBox>
);
}
@ -74,13 +72,11 @@ export function QDeleteButton({onClickHandler}: QDeleteButtonProps): JSX.Element
export function QEditButton(): JSX.Element
{
return (
<MDBox>
<MDBox width={standardWidth}>
<Link to="edit">
<MDBox width={standardWidth}>
<MDButton variant="gradient" color="dark" size="small" fullWidth startIcon={<Icon>edit</Icon>}>
Edit
</MDButton>
</MDBox>
<MDButton variant="gradient" color="dark" size="small" fullWidth startIcon={<Icon>edit</Icon>}>
Edit
</MDButton>
</Link>
</MDBox>
);

View File

@ -34,7 +34,6 @@ import QDynamicFormField from "qqq/components/QDynamicFormField";
interface Props {
formLabel?: string;
formData: any;
primaryKeyId?: string;
bulkEditMode?: boolean;
bulkEditSwitchChangeHandler?: any
}
@ -42,7 +41,7 @@ interface Props {
function QDynamicForm(props: Props): JSX.Element
{
const {
formData, formLabel, primaryKeyId, bulkEditMode, bulkEditSwitchChangeHandler,
formData, formLabel, bulkEditMode, bulkEditSwitchChangeHandler,
} = props;
const {
formFields, values, errors, touched,
@ -116,7 +115,7 @@ function QDynamicForm(props: Props): JSX.Element
error={errors[fieldName] && touched[fieldName]}
bulkEditMode={bulkEditMode}
bulkEditSwitchChangeHandler={bulkEditSwitchChanged}
success={!errors[fieldName] && touched[fieldName]}
success={`${values[fieldName]}` !== "" && !errors[fieldName] && touched[fieldName]}
/>
</Grid>
);
@ -129,7 +128,6 @@ function QDynamicForm(props: Props): JSX.Element
QDynamicForm.defaultProps = {
formLabel: undefined,
primaryKeyId: undefined,
bulkEditMode: false,
bulkEditSwitchChangeHandler: () =>
{},

View File

@ -26,7 +26,6 @@ import {ErrorMessage, Field} from "formik";
import MDBox from "components/MDBox";
import MDTypography from "components/MDTypography";
import MDInput from "components/MDInput";
import QDynamicForm from "qqq/components/QDynamicForm";
import React, {useState} from "react";
import Grid from "@mui/material/Grid";
import Switch from "@mui/material/Switch";

View File

@ -28,9 +28,10 @@ import MDBox from "components/MDBox";
import MDTypography from "components/MDTypography";
import Card from "@mui/material/Card";
import {Theme} from "@mui/material/styles";
import {QSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QSection";
interface Props {
tableSections: any;
tableSections: QSection[];
light?: boolean;
}
@ -40,11 +41,11 @@ function QRecordSidebar({tableSections, light}: Props): JSX.Element
<Card sx={{borderRadius: ({borders: {borderRadius}}) => borderRadius.lg, position: "sticky", top: "1%"}}>
<MDBox component="ul" display="flex" flexDirection="column" p={2} m={0} sx={{listStyle: "none"}}>
{
tableSections ? tableSections.map(({icon, label, name}: any, key: number) => (
<MDBox key={`section-${name}`} component="li" pt={key === 0 ? 0 : 1}>
tableSections ? tableSections.map((section: QSection, key: number) => (
<MDBox key={`section-${section.name}`} component="li" pt={key === 0 ? 0 : 1}>
<MDTypography
component="a"
href={`#${name}`}
href={`#${section.name}`}
variant="button"
fontWeight="regular"
sx={({
@ -65,9 +66,9 @@ function QRecordSidebar({tableSections, light}: Props): JSX.Element
})}
>
<MDBox mr={1.5} lineHeight={1} color="black">
<Icon fontSize="small">{icon}</Icon>
<Icon fontSize="small">{section.iconName}</Icon>
</MDBox>
{label}
{section.label}
</MDTypography>
</MDBox>
)) : null

View File

@ -29,7 +29,6 @@ import MDBox from "components/MDBox";
import EntityForm from "qqq/components/EntityForm";
import BaseLayout from "qqq/components/BaseLayout";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {useParams} from "react-router-dom";
interface Props
{

View File

@ -134,6 +134,7 @@ function EntityList({table}: Props): JSX.Element
const [columnVisibilityModel, setColumnVisibilityModel] = useState(defaultVisibility);
const [gridMouseDownX, setGridMouseDownX] = useState(0);
const [gridMouseDownY, setGridMouseDownY] = useState(0);
const [pinnedColumns, setPinnedColumns] = useState({left: ["__check__", "id"]});
const instance = useRef({timer: null});
const [, forceUpdate] = useReducer((x) => x + 1, 0);
@ -223,6 +224,7 @@ function EntityList({table}: Props): JSX.Element
});
setColumnSortModel(columnSortModel);
}
setPinnedColumns({left: ["__check__", tableMetaData.primaryKeyField]});
const qFilter = buildQFilter();
@ -626,15 +628,8 @@ function EntityList({table}: Props): JSX.Element
// eslint-disable-next-line react/no-unstable-nested-components
function CustomToolbar()
{
function gtcMouseDown(e: React.MouseEvent<HTMLDivElement>)
{
console.log(e.target);
}
return (
<GridToolbarContainer
onMouseDown={(e) => gtcMouseDown(e)}
>
<GridToolbarContainer>
<div>
<Button
id="refresh-button"
@ -711,7 +706,7 @@ function EntityList({table}: Props): JSX.Element
<MenuItem onClick={bulkLoadClicked}>Bulk Load</MenuItem>
<MenuItem onClick={bulkEditClicked}>Bulk Edit</MenuItem>
<MenuItem onClick={bulkDeleteClicked}>Bulk Delete</MenuItem>
<MenuItem divider />
{tableProcesses.length > 0 && <MenuItem divider />}
{tableProcesses.map((process) => (
<MenuItem key={process.name} onClick={() => processClicked(process)}>{process.label}</MenuItem>
))}
@ -759,9 +754,7 @@ function EntityList({table}: Props): JSX.Element
<MDBox display="flex" justifyContent="flex-end" alignItems="flex-start" mb={2}>
<MDBox display="flex" width="150px">
{tableProcesses.length > 0 && (
<QActionsMenuButton isOpen={actionsMenu} onClickHandler={openActionsMenu} />
)}
<QActionsMenuButton isOpen={actionsMenu} onClickHandler={openActionsMenu} />
{renderActionsMenu}
</MDBox>
@ -774,7 +767,7 @@ function EntityList({table}: Props): JSX.Element
<MDBox height="100%">
<DataGridPro
components={{Toolbar: CustomToolbar, Pagination: CustomPagination, LoadingOverlay: Loading}}
pinnedColumns={{left: ["__check__", "id"]}}
initialState={{pinnedColumns: pinnedColumns}}
pagination
paginationMode="server"
sortingMode="server"

View File

@ -52,6 +52,8 @@ import Icon from "@mui/material/Icon";
import Avatar from "@mui/material/Avatar";
import QRecordSidebar from "qqq/components/QRecordSidebar";
import QTableUtils from "qqq/utils/QTableUtils";
import colors from "assets/theme/base/colors";
import {QSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QSection";
const qController = QClient.getInstance();
@ -73,11 +75,13 @@ function ViewContents({id, table}: Props): JSX.Element
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
const [nameValues, setNameValues] = useState([] as JSX.Element[]);
const [sectionFieldElements, setSectionFieldElements] = useState(null as Map<string, JSX.Element[]>);
const [t1Section, setT1Section] = useState(null as JSX.Element);
const [open, setOpen] = useState(false);
const [deleteConfirmationOpen, setDeleteConfirmationOpen] = useState(false);
const [tableMetaData, setTableMetaData] = useState(null);
const [record, setRecord] = useState(null as QRecord);
const [tableSections, setTableSections] = useState(null as any);
const [tableSections, setTableSections] = useState([] as QSection[]);
const [t1SectionName, setT1SectionName] = useState(null as string);
const [t1SectionElement, setT1SectionElement] = useState(null as JSX.Element);
const [nonT1TableSections, setNonT1TableSections] = useState([] as QSection[]);
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
const [actionsMenu, setActionsMenu] = useState(null);
const [searchParams] = useSearchParams();
@ -120,6 +124,7 @@ function ViewContents({id, table}: Props): JSX.Element
// make elements with the values for each section //
////////////////////////////////////////////////////
const sectionFieldElements = new Map();
const nonT1TableSections = [];
for (let i = 0; i < tableSections.length; i++)
{
const section = tableSections[i];
@ -145,45 +150,29 @@ function ViewContents({id, table}: Props): JSX.Element
if (section.tier === "T1")
{
setT1Section(sectionFieldElements.get(section.name));
setT1SectionElement(sectionFieldElements.get(section.name));
setT1SectionName(section.name);
}
else
{
nonT1TableSections.push(tableSections[i]);
}
}
setSectionFieldElements(sectionFieldElements);
// todo - delete this
const sortedKeys = [...record.values.keys()].sort();
sortedKeys.forEach((key) =>
{
if (key !== tableMetaData.primaryKeyField)
{
nameValues.push(
<MDBox key={key} display="flex" py={1} pr={2}>
<MDTypography variant="button" fontWeight="bold" textTransform="capitalize">
{tableMetaData.fields.get(key).label}
: &nbsp;
</MDTypography>
<MDTypography variant="button" fontWeight="regular" color="text">
&nbsp;
{QValueUtils.getDisplayValue(tableMetaData.fields.get(key), record)}
</MDTypography>
</MDBox>,
);
}
});
setNameValues(nameValues);
setNonT1TableSections(nonT1TableSections);
forceUpdate();
})();
}
const handleClickConfirmOpen = () =>
const handleClickDeleteButton = () =>
{
setOpen(true);
setDeleteConfirmationOpen(true);
};
const handleClickConfirmClose = () =>
const handleDeleteConfirmClose = () =>
{
setOpen(false);
setDeleteConfirmationOpen(false);
};
const handleDelete = (event: { preventDefault: () => void }) =>
@ -225,12 +214,12 @@ function ViewContents({id, table}: Props): JSX.Element
<MenuItem onClick={() =>
{
setActionsMenu(null);
handleClickConfirmOpen();
handleClickDeleteButton();
}}
>
Delete
</MenuItem>
<MenuItem divider />
{tableProcesses.length > 0 && <MenuItem divider />}
{tableProcesses.map((process) => (
<MenuItem key={process.name} onClick={() => processClicked(process)}>{process.label}</MenuItem>
))}
@ -261,10 +250,10 @@ function ViewContents({id, table}: Props): JSX.Element
<Grid container spacing={3}>
<Grid item xs={12} mb={3}>
<Card>
<Card id={t1SectionName}>
<MDBox display="flex" p={3} pb={1}>
<MDBox mr={1.5}>
<Avatar sx={{bgcolor: "rgb(26, 115, 232)"}}>
<Avatar sx={{bgcolor: colors.info.main}}>
<Icon>
{tableMetaData?.iconName}
</Icon>
@ -274,33 +263,29 @@ function ViewContents({id, table}: Props): JSX.Element
<MDTypography variant="h5">
{tableMetaData && record ? `Viewing ${tableMetaData?.label}: ${record?.recordLabel}` : ""}
</MDTypography>
{tableProcesses.length > 0 && (
<QActionsMenuButton isOpen={actionsMenu} onClickHandler={openActionsMenu} />
)}
<QActionsMenuButton isOpen={actionsMenu} onClickHandler={openActionsMenu} />
{renderActionsMenu}
</MDBox>
</MDBox>
{t1Section ? (<MDBox p={3} pt={0}>{t1Section}</MDBox>) : null}
{t1SectionElement ? (<MDBox p={3} pt={0}>{t1SectionElement}</MDBox>) : null}
</Card>
</Grid>
</Grid>
{tableSections && sectionFieldElements ? tableSections.map(({
icon, label, name, fieldNames, tier,
}: any) => (tier !== "T1"
? (
<MDBox mb={3} key={name}>
<Card key={name} id={name} sx={{overflow: "visible"}}>
<MDTypography variant="h5" p={3} pb={1}>
{label}
</MDTypography>
<MDBox p={3} pt={0} flexDirection="column">{sectionFieldElements.get(name)}</MDBox>
</Card>
</MDBox>
) : null)) : null}
{nonT1TableSections.length > 0 ? nonT1TableSections.map(({
iconName, label, name, fieldNames, tier,
}: any) => (
<MDBox mb={3} key={name}>
<Card key={name} id={name} sx={{overflow: "visible"}}>
<MDTypography variant="h5" p={3} pb={1}>
{label}
</MDTypography>
<MDBox p={3} pt={0} flexDirection="column">{sectionFieldElements.get(name)}</MDBox>
</Card>
</MDBox>
)) : null}
<MDBox component="form" p={3}>
<Grid container justifyContent="flex-end" spacing={3}>
<QDeleteButton onClickHandler={handleClickConfirmOpen} />
<QDeleteButton onClickHandler={handleClickDeleteButton} />
<QEditButton />
</Grid>
</MDBox>
@ -310,8 +295,8 @@ function ViewContents({id, table}: Props): JSX.Element
{/* Delete confirmation Dialog */}
<Dialog
open={open}
onClose={handleClickConfirmClose}
open={deleteConfirmationOpen}
onClose={handleDeleteConfirmClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
@ -322,7 +307,7 @@ function ViewContents({id, table}: Props): JSX.Element
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClickConfirmClose}>No</Button>
<Button onClick={handleDeleteConfirmClose}>No</Button>
<Button onClick={handleDelete} autoFocus>
Yes
</Button>

View File

@ -81,7 +81,8 @@
/* shrink font on in the pagination control */
.MuiTablePagination-displayedRows,
.MuiTablePagination-selectLabel,
.MuiTablePagination-select.MuiSelect-select.MuiSelect-standard
.MuiTablePagination-select.MuiSelect-select.MuiSelect-standard,
.MuiDataGrid-selectedRowCount
{
font-size: 0.85rem !important;
}
@ -93,14 +94,8 @@
border-radius: 5px !important;
}
/* hide the selected row count (we show our own) */
.MuiDataGrid-selectedRowCount
{
visibility: hidden !important;
}
/* move the green check / red x down to align with the calendar icon */
.MuiFormControl-root
{
background-position-y: 1.4rem;
background-position-y: 1.4rem !important;
}

View File

@ -20,6 +20,7 @@
*/
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QSection";
/*******************************************************************************
** Utility class for working with QQQ Tables
@ -27,27 +28,18 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QT
*******************************************************************************/
class QTableUtils
{
public static getSectionsForRecordSidebar(tableMetaData: QTableMetaData): any
public static getSectionsForRecordSidebar(tableMetaData: QTableMetaData): QSection[]
{
const tableSections = [];
if (tableMetaData.sections)
{
for (let i = 0; i < tableMetaData.sections.length; i++)
{
const section = tableMetaData.sections[i];
tableSections.push({
icon: section.iconName, label: section.label, name: section.name, fieldNames: section.fieldNames, tier: section.tier,
});
}
return (tableMetaData.sections);
}
else
{
tableSections.push({
icon: "description", label: "All Fields", name: "allFields", fieldNames: [...tableMetaData.fields.keys()],
});
return ([new QSection({
iconName: "description", label: "All Fields", name: "allFields", fieldNames: [...tableMetaData.fields.keys()],
})]);
}
return (tableSections);
}
}