mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-21 22:58:43 +00:00
Compare commits
19 Commits
snapshot-f
...
snapshot-f
Author | SHA1 | Date | |
---|---|---|---|
71a1bfaa6b | |||
d9e9a0be08 | |||
aefb282a0e | |||
fb57718c1c | |||
ba213b038b | |||
69daf47021 | |||
1d24b9b40c | |||
f44ba8d6d3 | |||
dc131d5189 | |||
2b5cc1610f | |||
a36bdb1474 | |||
c2926d26e8 | |||
eb42a86655 | |||
b7f715f832 | |||
16a08cfd42 | |||
f5919c66ab | |||
d750ef0930 | |||
267ead925b | |||
f925ad9116 |
@ -1,12 +0,0 @@
|
|||||||
import {defineConfig} from "cypress";
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
e2e: {
|
|
||||||
viewportHeight: 1000,
|
|
||||||
viewportWidth: 1200,
|
|
||||||
setupNodeEvents(on, config)
|
|
||||||
{
|
|
||||||
// implement node event listeners here
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
20141
package-lock.json
generated
20141
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
|||||||
"@auth0/auth0-react": "1.10.2",
|
"@auth0/auth0-react": "1.10.2",
|
||||||
"@emotion/react": "11.7.1",
|
"@emotion/react": "11.7.1",
|
||||||
"@emotion/styled": "11.6.0",
|
"@emotion/styled": "11.6.0",
|
||||||
"@kingsrook/qqq-frontend-core": "1.0.100",
|
"@kingsrook/qqq-frontend-core": "1.0.102",
|
||||||
"@mui/icons-material": "5.4.1",
|
"@mui/icons-material": "5.4.1",
|
||||||
"@mui/material": "5.11.1",
|
"@mui/material": "5.11.1",
|
||||||
"@mui/styles": "5.11.1",
|
"@mui/styles": "5.11.1",
|
||||||
|
@ -44,9 +44,9 @@ import MDTypography from "qqq/components/legacy/MDTypography";
|
|||||||
import HelpContent from "qqq/components/misc/HelpContent";
|
import HelpContent from "qqq/components/misc/HelpContent";
|
||||||
import QRecordSidebar from "qqq/components/misc/RecordSidebar";
|
import QRecordSidebar from "qqq/components/misc/RecordSidebar";
|
||||||
import DynamicFormWidget from "qqq/components/widgets/misc/DynamicFormWidget";
|
import DynamicFormWidget from "qqq/components/widgets/misc/DynamicFormWidget";
|
||||||
|
import FilterAndColumnsSetupWidget from "qqq/components/widgets/misc/FilterAndColumnsSetupWidget";
|
||||||
import PivotTableSetupWidget from "qqq/components/widgets/misc/PivotTableSetupWidget";
|
import PivotTableSetupWidget from "qqq/components/widgets/misc/PivotTableSetupWidget";
|
||||||
import RecordGridWidget, {ChildRecordListData} from "qqq/components/widgets/misc/RecordGridWidget";
|
import RecordGridWidget, {ChildRecordListData} from "qqq/components/widgets/misc/RecordGridWidget";
|
||||||
import ReportSetupWidget from "qqq/components/widgets/misc/ReportSetupWidget";
|
|
||||||
import {FieldRule, FieldRuleAction, FieldRuleTrigger} from "qqq/models/fields/FieldRules";
|
import {FieldRule, FieldRuleAction, FieldRuleTrigger} from "qqq/models/fields/FieldRules";
|
||||||
import HtmlUtils from "qqq/utils/HtmlUtils";
|
import HtmlUtils from "qqq/utils/HtmlUtils";
|
||||||
import Client from "qqq/utils/qqq/Client";
|
import Client from "qqq/utils/qqq/Client";
|
||||||
@ -88,7 +88,7 @@ EntityForm.defaultProps = {
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
let formikSetFieldValueFunction = (field: string, value: any, shouldValidate?: boolean): void =>
|
let formikSetFieldValueFunction = (field: string, value: any, shouldValidate?: boolean): void =>
|
||||||
{
|
{
|
||||||
}
|
};
|
||||||
|
|
||||||
function EntityForm(props: Props): JSX.Element
|
function EntityForm(props: Props): JSX.Element
|
||||||
{
|
{
|
||||||
@ -119,11 +119,12 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
||||||
|
const [modalDataChangedCounter, setModalDataChangedCount] = useState(0);
|
||||||
|
|
||||||
const [notAllowedError, setNotAllowedError] = useState(null as string);
|
const [notAllowedError, setNotAllowedError] = useState(null as string);
|
||||||
|
|
||||||
const [formValuesJSON, setFormValuesJSON] = useState("");
|
const [formValuesJSON, setFormValuesJSON] = useState("");
|
||||||
const [formValues, setFormValues] = useState({} as {[name: string]: any});
|
const [formValues, setFormValues] = useState({} as { [name: string]: any });
|
||||||
|
|
||||||
const {pageHeader, setPageHeader} = useContext(QContext);
|
const {pageHeader, setPageHeader} = useContext(QContext);
|
||||||
|
|
||||||
@ -282,6 +283,8 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
setRenderedWidgetSections(newRenderedWidgetSections);
|
setRenderedWidgetSections(newRenderedWidgetSections);
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
|
|
||||||
|
setModalDataChangedCount(modalDataChangedCounter + 1);
|
||||||
|
|
||||||
setShowEditChildForm(null);
|
setShowEditChildForm(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +294,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const newRenderedWidgetSections: {[name: string]: JSX.Element} = {};
|
const newRenderedWidgetSections: { [name: string]: JSX.Element } = {};
|
||||||
for (let widgetName in renderedWidgetSections)
|
for (let widgetName in renderedWidgetSections)
|
||||||
{
|
{
|
||||||
const widgetMetaData = metaData.widgets.get(widgetName);
|
const widgetMetaData = metaData.widgets.get(widgetName);
|
||||||
@ -351,12 +354,11 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** if we have a widget that wants to set form-field values, they can take this
|
** if we have a widget that wants to set form-field values, they can take this
|
||||||
** function in as a callback, and then call it with their values.
|
** function in as a callback, and then call it with their values.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function setFormFieldValuesFromWidget(values: {[name: string]: any})
|
function setFormFieldValuesFromWidget(values: { [name: string]: any })
|
||||||
{
|
{
|
||||||
for (let key in values)
|
for (let key in values)
|
||||||
{
|
{
|
||||||
@ -370,13 +372,13 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function getWidgetSection(widgetMetaData: QWidgetMetaData, widgetData: any): JSX.Element
|
function getWidgetSection(widgetMetaData: QWidgetMetaData, widgetData: any): JSX.Element
|
||||||
{
|
{
|
||||||
if(widgetMetaData.type == "childRecordList")
|
if (widgetMetaData.type == "childRecordList")
|
||||||
{
|
{
|
||||||
widgetData.viewAllLink = null;
|
widgetData.viewAllLink = null;
|
||||||
widgetMetaData.showExportButton = false;
|
widgetMetaData.showExportButton = false;
|
||||||
|
|
||||||
return <RecordGridWidget
|
return <RecordGridWidget
|
||||||
key={new Date().getTime()} // added so that editing values actually re-renders...
|
key={`${formValues["tableName"]}-${modalDataChangedCounter}`}
|
||||||
widgetMetaData={widgetMetaData}
|
widgetMetaData={widgetMetaData}
|
||||||
data={widgetData}
|
data={widgetData}
|
||||||
disableRowClick
|
disableRowClick
|
||||||
@ -388,18 +390,27 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(widgetMetaData.type == "reportSetup")
|
if (widgetMetaData.type == "filterAndColumnsSetup")
|
||||||
{
|
{
|
||||||
return <ReportSetupWidget
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if the widget metadata specifies a table name, set form values to that so widget knows which to use //
|
||||||
|
// (for the case when it is not being specified by a separate field in the record) //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if (widgetMetaData?.defaultValues?.has("tableName"))
|
||||||
|
{
|
||||||
|
formValues["tableName"] = widgetMetaData?.defaultValues.get("tableName");
|
||||||
|
}
|
||||||
|
|
||||||
|
return <FilterAndColumnsSetupWidget
|
||||||
key={formValues["tableName"]} // todo, is this good? it was added so that editing values actually re-renders...
|
key={formValues["tableName"]} // todo, is this good? it was added so that editing values actually re-renders...
|
||||||
isEditable={true}
|
isEditable={true}
|
||||||
widgetMetaData={widgetMetaData}
|
widgetMetaData={widgetMetaData}
|
||||||
recordValues={formValues}
|
recordValues={formValues}
|
||||||
onSaveCallback={setFormFieldValuesFromWidget}
|
onSaveCallback={setFormFieldValuesFromWidget}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(widgetMetaData.type == "pivotTableSetup")
|
if (widgetMetaData.type == "pivotTableSetup")
|
||||||
{
|
{
|
||||||
return <PivotTableSetupWidget
|
return <PivotTableSetupWidget
|
||||||
key={formValues["tableName"]} // todo, is this good? it was added so that editing values actually re-renders...
|
key={formValues["tableName"]} // todo, is this good? it was added so that editing values actually re-renders...
|
||||||
@ -407,10 +418,10 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
widgetMetaData={widgetMetaData}
|
widgetMetaData={widgetMetaData}
|
||||||
recordValues={formValues}
|
recordValues={formValues}
|
||||||
onSaveCallback={setFormFieldValuesFromWidget}
|
onSaveCallback={setFormFieldValuesFromWidget}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(widgetMetaData.type == "dynamicForm")
|
if (widgetMetaData.type == "dynamicForm")
|
||||||
{
|
{
|
||||||
return <DynamicFormWidget
|
return <DynamicFormWidget
|
||||||
key={formValues["savedReportId"]} // todo - pull this from the metaData (could do so above too...)
|
key={formValues["savedReportId"]} // todo - pull this from the metaData (could do so above too...)
|
||||||
@ -420,10 +431,10 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
recordValues={formValues}
|
recordValues={formValues}
|
||||||
record={record}
|
record={record}
|
||||||
onSaveCallback={setFormFieldValuesFromWidget}
|
onSaveCallback={setFormFieldValuesFromWidget}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<Box>Unsupported widget type: {widgetMetaData.type}</Box>)
|
return (<Box>Unsupported widget type: {widgetMetaData.type}</Box>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -449,12 +460,12 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
function setupFieldRules(tableMetaData: QTableMetaData)
|
function setupFieldRules(tableMetaData: QTableMetaData)
|
||||||
{
|
{
|
||||||
const mdbMetaData = tableMetaData?.supplementalTableMetaData?.get("materialDashboard");
|
const mdbMetaData = tableMetaData?.supplementalTableMetaData?.get("materialDashboard");
|
||||||
if(!mdbMetaData)
|
if (!mdbMetaData)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mdbMetaData.fieldRules)
|
if (mdbMetaData.fieldRules)
|
||||||
{
|
{
|
||||||
const newFieldRules: FieldRule[] = [];
|
const newFieldRules: FieldRule[] = [];
|
||||||
for (let i = 0; i < mdbMetaData.fieldRules.length; i++)
|
for (let i = 0; i < mdbMetaData.fieldRules.length; i++)
|
||||||
@ -488,15 +499,15 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
const tableSections = TableUtils.getSectionsForRecordSidebar(tableMetaData, [...tableMetaData.fields.keys()], (section: QTableSection) =>
|
const tableSections = TableUtils.getSectionsForRecordSidebar(tableMetaData, [...tableMetaData.fields.keys()], (section: QTableSection) =>
|
||||||
{
|
{
|
||||||
const widget = metaData.widgets.get(section.widgetName);
|
const widget = metaData?.widgets.get(section.widgetName);
|
||||||
if(widget)
|
if (widget)
|
||||||
{
|
{
|
||||||
if(widget.type == "childRecordList" && widget.defaultValues?.has("manageAssociationName"))
|
if (widget.type == "childRecordList" && widget.defaultValues?.has("manageAssociationName"))
|
||||||
{
|
{
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(widget.type == "reportSetup" || widget.type == "pivotTableSetup" || widget.type == "dynamicForm")
|
if (widget.type == "filterAndColumnsSetup" || widget.type == "pivotTableSetup" || widget.type == "dynamicForm")
|
||||||
{
|
{
|
||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
@ -680,7 +691,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hasFields = section.fieldNames && section.fieldNames.length > 0;
|
const hasFields = section.fieldNames && section.fieldNames.length > 0;
|
||||||
if(hasFields)
|
if (hasFields)
|
||||||
{
|
{
|
||||||
for (let j = 0; j < section.fieldNames.length; j++)
|
for (let j = 0; j < section.fieldNames.length; j++)
|
||||||
{
|
{
|
||||||
@ -719,7 +730,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const widgetMetaData = metaData.widgets.get(section.widgetName);
|
const widgetMetaData = metaData?.widgets.get(section.widgetName);
|
||||||
const widgetData = await qController.widget(widgetMetaData.name, makeQueryStringWithIdAndObject(tableMetaData, defaultValues));
|
const widgetData = await qController.widget(widgetMetaData.name, makeQueryStringWithIdAndObject(tableMetaData, defaultValues));
|
||||||
|
|
||||||
newRenderedWidgetSections[section.widgetName] = getWidgetSection(widgetMetaData, widgetData);
|
newRenderedWidgetSections[section.widgetName] = getWidgetSection(widgetMetaData, widgetData);
|
||||||
@ -1000,19 +1011,19 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function makeQueryStringWithIdAndObject(tableMetaData: QTableMetaData, object: {[key: string]: any})
|
function makeQueryStringWithIdAndObject(tableMetaData: QTableMetaData, object: { [key: string]: any })
|
||||||
{
|
{
|
||||||
const queryParamsArray: string[] = [];
|
const queryParamsArray: string[] = [];
|
||||||
if(props.id)
|
if (props.id)
|
||||||
{
|
{
|
||||||
queryParamsArray.push(`${tableMetaData.primaryKeyField}=${encodeURIComponent(props.id)}`)
|
queryParamsArray.push(`${tableMetaData.primaryKeyField}=${encodeURIComponent(props.id)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(object)
|
if (object)
|
||||||
{
|
{
|
||||||
for (let key in object)
|
for (let key in object)
|
||||||
{
|
{
|
||||||
queryParamsArray.push(`${key}=${encodeURIComponent(object[key])}`)
|
queryParamsArray.push(`${key}=${encodeURIComponent(object[key])}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1023,7 +1034,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
async function reloadWidget(widgetName: string, additionalQueryParamsForWidget: {[key: string]: any })
|
async function reloadWidget(widgetName: string, additionalQueryParamsForWidget: { [key: string]: any })
|
||||||
{
|
{
|
||||||
const widgetData = await qController.widget(widgetName, makeQueryStringWithIdAndObject(tableMetaData, additionalQueryParamsForWidget));
|
const widgetData = await qController.widget(widgetName, makeQueryStringWithIdAndObject(tableMetaData, additionalQueryParamsForWidget));
|
||||||
const widgetMetaData = metaData.widgets.get(widgetName);
|
const widgetMetaData = metaData.widgets.get(widgetName);
|
||||||
@ -1045,11 +1056,11 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** process a form-field having a changed value (e.g., apply field rules).
|
** process a form-field having a changed value (e.g., apply field rules).
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function handleChangedFieldValue(fieldName: string, oldValue: any, newValue: any, valueChangesToMake: {[fieldName: string]: any})
|
function handleChangedFieldValue(fieldName: string, oldValue: any, newValue: any, valueChangesToMake: { [fieldName: string]: any })
|
||||||
{
|
{
|
||||||
for (let fieldRule of fieldRules)
|
for (let fieldRule of fieldRules)
|
||||||
{
|
{
|
||||||
if(fieldRule.trigger == FieldRuleTrigger.ON_CHANGE && fieldRule.sourceField == fieldName)
|
if (fieldRule.trigger == FieldRuleTrigger.ON_CHANGE && fieldRule.sourceField == fieldName)
|
||||||
{
|
{
|
||||||
switch (fieldRule.action)
|
switch (fieldRule.action)
|
||||||
{
|
{
|
||||||
@ -1058,7 +1069,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
valueChangesToMake[fieldRule.targetField] = null;
|
valueChangesToMake[fieldRule.targetField] = null;
|
||||||
break;
|
break;
|
||||||
case FieldRuleAction.RELOAD_WIDGET:
|
case FieldRuleAction.RELOAD_WIDGET:
|
||||||
const additionalQueryParamsForWidget: {[key: string]: any} = {};
|
const additionalQueryParamsForWidget: { [key: string]: any } = {};
|
||||||
additionalQueryParamsForWidget[fieldRule.sourceField] = newValue;
|
additionalQueryParamsForWidget[fieldRule.sourceField] = newValue;
|
||||||
reloadWidget(fieldRule.targetWidget, additionalQueryParamsForWidget);
|
reloadWidget(fieldRule.targetWidget, additionalQueryParamsForWidget);
|
||||||
}
|
}
|
||||||
@ -1148,21 +1159,21 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// if we have values from formik, look at them //
|
// if we have values from formik, look at them //
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
if(values)
|
if (values)
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// use stringified values as cheap/easy way to see if any are changed //
|
// use stringified values as cheap/easy way to see if any are changed //
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
const newFormValuesJSON = JSON.stringify(values);
|
const newFormValuesJSON = JSON.stringify(values);
|
||||||
if(formValuesJSON != newFormValuesJSON)
|
if (formValuesJSON != newFormValuesJSON)
|
||||||
{
|
{
|
||||||
const valueChangesToMake: {[fieldName: string]: any} = {};
|
const valueChangesToMake: { [fieldName: string]: any } = {};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// if the form is dirty (e.g., we're not doing the initial load), //
|
// if the form is dirty (e.g., we're not doing the initial load), //
|
||||||
// then process rules for any changed fields //
|
// then process rules for any changed fields //
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
if(dirty)
|
if (dirty)
|
||||||
{
|
{
|
||||||
for (let fieldName in values)
|
for (let fieldName in values)
|
||||||
{
|
{
|
||||||
@ -1194,7 +1205,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
setFieldValue(fieldName, valueChangesToMake[fieldName], false);
|
setFieldValue(fieldName, valueChangesToMake[fieldName], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFormValues(formValues)
|
setFormValues(formValues);
|
||||||
setFormValuesJSON(JSON.stringify(values));
|
setFormValuesJSON(JSON.stringify(values));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ export function GotoRecordButton(props: GotoRecordButtonProps): JSX.Element
|
|||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{
|
{
|
||||||
props.buttonVisible && hasGotoFieldNames(props.tableMetaData) && <Button onClick={openGoto}>Go To...</Button>
|
props.buttonVisible && hasGotoFieldNames(props.tableMetaData) && <Button onClick={openGoto} sx={{whiteSpace: "nowrap"}}>Go To...</Button>
|
||||||
}
|
}
|
||||||
<GotoRecordDialog metaData={props.metaData} tableMetaData={props.tableMetaData} tableVariant={props.tableVariant} isOpen={gotoIsOpen} closeHandler={closeGoto} mayClose={props.mayClose} subHeader={props.subHeader} />
|
<GotoRecordDialog metaData={props.metaData} tableMetaData={props.tableMetaData} tableVariant={props.tableVariant} isOpen={gotoIsOpen} closeHandler={closeGoto} mayClose={props.mayClose} subHeader={props.subHeader} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||||
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
|
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
|
||||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||||
import Box from "@mui/material/Box";
|
import {Box} from "@mui/material";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import Icon from "@mui/material/Icon";
|
import Icon from "@mui/material/Icon";
|
||||||
import {Theme} from "@mui/material/styles";
|
import {Theme} from "@mui/material/styles";
|
||||||
@ -76,12 +76,12 @@ function QRecordSidebar({tableSections, widgetMetaDataList, light, stickyTop}: P
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card sx={{borderRadius: "0.75rem", position: "sticky", top: stickyTop, overflow: "auto", maxHeight: "calc(100vh - 2rem)"}}>
|
<Card sx={{borderRadius: "0.75rem", position: "sticky", top: stickyTop, overflow: "hidden", maxHeight: "calc(100vh - 2rem)"}}>
|
||||||
<Box component="ul" display="flex" flexDirection="column" p={2} m={0} sx={{listStyle: "none"}}>
|
<Box component="ul" display="flex" flexDirection="column" p={2} m={0} sx={{listStyle: "none", overflow: "auto", height: "100%"}}>
|
||||||
{
|
{
|
||||||
sidebarEntries ? sidebarEntries.map((entry: SidebarEntry, key: number) => (
|
sidebarEntries ? sidebarEntries.map((entry: SidebarEntry, key: number) => (
|
||||||
|
|
||||||
<HashLink key={`section-link-${entry.name}`} to={`#${entry.name}`}>
|
<Box key={`section-link-${entry.name}`} onClick={() => document.getElementById(entry.name).scrollIntoView()} sx={{cursor: "pointer"}}>
|
||||||
<Box key={`section-${entry.name}`} component="li" pt={key === 0 ? 0 : 1}>
|
<Box key={`section-${entry.name}`} component="li" pt={key === 0 ? 0 : 1}>
|
||||||
<MDTypography
|
<MDTypography
|
||||||
variant="button"
|
variant="button"
|
||||||
@ -112,7 +112,7 @@ function QRecordSidebar({tableSections, widgetMetaDataList, light, stickyTop}: P
|
|||||||
|
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
</Box>
|
</Box>
|
||||||
</HashLink>
|
</Box>
|
||||||
)) : null
|
)) : null
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -25,7 +25,8 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QT
|
|||||||
import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
|
import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
|
||||||
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
||||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||||
import {Alert, Box, Button} from "@mui/material";
|
import {Alert, Button} from "@mui/material";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
import Dialog from "@mui/material/Dialog";
|
import Dialog from "@mui/material/Dialog";
|
||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
@ -94,12 +95,12 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab
|
|||||||
|
|
||||||
const {accentColor, accentColorLight, userId: currentUserId} = useContext(QContext);
|
const {accentColor, accentColorLight, userId: currentUserId} = useContext(QContext);
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// this component is used by <RecordQuery> - but that component has different usages - //
|
// this component is used by <RecordQuery> - but that component has different usages - //
|
||||||
// e.g., the full-fledged query screen, but also, within other screens (e.g., a modal //
|
// e.g., the full-fledged query screen, but also, within other screens (e.g., a modal //
|
||||||
// under the ReportSetupWidget). So, there are some behaviors we only want when we're //
|
// under the FilterAndColumnsSetupWidget). So, there are some behaviors we only want when //
|
||||||
// on the full-fledged query screen, such as changing the URL with saved view ids. //
|
// we're on the full-fledged query screen, such as changing the URL with saved view ids. //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
const isQueryScreen = queryScreenUsage == "queryScreen";
|
const isQueryScreen = queryScreenUsage == "queryScreen";
|
||||||
|
|
||||||
const openSavedViewsMenu = (event: any) => setSavedViewsMenu(event.currentTarget);
|
const openSavedViewsMenu = (event: any) => setSavedViewsMenu(event.currentTarget);
|
||||||
|
@ -22,16 +22,16 @@
|
|||||||
|
|
||||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||||
import {Box, Skeleton} from "@mui/material";
|
import {Box, Skeleton} from "@mui/material";
|
||||||
import React from "react";
|
|
||||||
import {BlockData} from "qqq/components/widgets/blocks/BlockModels";
|
import {BlockData} from "qqq/components/widgets/blocks/BlockModels";
|
||||||
import WidgetBlock from "qqq/components/widgets/WidgetBlock";
|
import WidgetBlock from "qqq/components/widgets/WidgetBlock";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
|
||||||
interface CompositeData
|
interface CompositeData
|
||||||
{
|
{
|
||||||
blocks: BlockData[];
|
blocks: BlockData[];
|
||||||
styleOverrides?: any;
|
styleOverrides?: any;
|
||||||
layout?: string
|
layout?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -57,7 +57,14 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP
|
|||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
let layout = data?.layout;
|
let layout = data?.layout;
|
||||||
let boxStyle: any = {};
|
let boxStyle: any = {};
|
||||||
if (layout == "FLEX_ROW_WRAPPED")
|
if (layout == "FLEX_COLUMN")
|
||||||
|
{
|
||||||
|
boxStyle.display = "flex";
|
||||||
|
boxStyle.flexDirection = "column";
|
||||||
|
boxStyle.flexWrap = "wrap";
|
||||||
|
boxStyle.gap = "0.5rem";
|
||||||
|
}
|
||||||
|
else if (layout == "FLEX_ROW_WRAPPED")
|
||||||
{
|
{
|
||||||
boxStyle.display = "flex";
|
boxStyle.display = "flex";
|
||||||
boxStyle.flexDirection = "row";
|
boxStyle.flexDirection = "row";
|
||||||
@ -68,7 +75,7 @@ export default function CompositeWidget({widgetMetaData, data}: CompositeWidgetP
|
|||||||
{
|
{
|
||||||
boxStyle.display = "flex";
|
boxStyle.display = "flex";
|
||||||
boxStyle.flexDirection = "row";
|
boxStyle.flexDirection = "row";
|
||||||
boxStyle.justifyContent = "space-between"
|
boxStyle.justifyContent = "space-between";
|
||||||
boxStyle.gap = "0.25rem";
|
boxStyle.gap = "0.25rem";
|
||||||
}
|
}
|
||||||
else if (layout == "TABLE_SUB_ROW_DETAILS")
|
else if (layout == "TABLE_SUB_ROW_DETAILS")
|
||||||
|
@ -40,17 +40,17 @@ import DataBagViewer from "qqq/components/widgets/misc/DataBagViewer";
|
|||||||
import DividerWidget from "qqq/components/widgets/misc/Divider";
|
import DividerWidget from "qqq/components/widgets/misc/Divider";
|
||||||
import DynamicFormWidget from "qqq/components/widgets/misc/DynamicFormWidget";
|
import DynamicFormWidget from "qqq/components/widgets/misc/DynamicFormWidget";
|
||||||
import FieldValueListWidget from "qqq/components/widgets/misc/FieldValueListWidget";
|
import FieldValueListWidget from "qqq/components/widgets/misc/FieldValueListWidget";
|
||||||
|
import FilterAndColumnsSetupWidget from "qqq/components/widgets/misc/FilterAndColumnsSetupWidget";
|
||||||
import PivotTableSetupWidget from "qqq/components/widgets/misc/PivotTableSetupWidget";
|
import PivotTableSetupWidget from "qqq/components/widgets/misc/PivotTableSetupWidget";
|
||||||
import QuickSightChart from "qqq/components/widgets/misc/QuickSightChart";
|
import QuickSightChart from "qqq/components/widgets/misc/QuickSightChart";
|
||||||
import RecordGridWidget from "qqq/components/widgets/misc/RecordGridWidget";
|
import RecordGridWidget from "qqq/components/widgets/misc/RecordGridWidget";
|
||||||
import ReportSetupWidget from "qqq/components/widgets/misc/ReportSetupWidget";
|
|
||||||
import ScriptViewer from "qqq/components/widgets/misc/ScriptViewer";
|
import ScriptViewer from "qqq/components/widgets/misc/ScriptViewer";
|
||||||
import StepperCard from "qqq/components/widgets/misc/StepperCard";
|
import StepperCard from "qqq/components/widgets/misc/StepperCard";
|
||||||
import USMapWidget from "qqq/components/widgets/misc/USMapWidget";
|
import USMapWidget from "qqq/components/widgets/misc/USMapWidget";
|
||||||
import ParentWidget from "qqq/components/widgets/ParentWidget";
|
import ParentWidget from "qqq/components/widgets/ParentWidget";
|
||||||
import MultiStatisticsCard from "qqq/components/widgets/statistics/MultiStatisticsCard";
|
import MultiStatisticsCard from "qqq/components/widgets/statistics/MultiStatisticsCard";
|
||||||
import StatisticsCard from "qqq/components/widgets/statistics/StatisticsCard";
|
import StatisticsCard from "qqq/components/widgets/statistics/StatisticsCard";
|
||||||
import Widget, {HeaderIcon, LabelComponent, WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT} from "qqq/components/widgets/Widget";
|
import Widget, {HeaderIcon, LabelComponent, WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT, WidgetData} from "qqq/components/widgets/Widget";
|
||||||
import WidgetBlock from "qqq/components/widgets/WidgetBlock";
|
import WidgetBlock from "qqq/components/widgets/WidgetBlock";
|
||||||
import ProcessRun from "qqq/pages/processes/ProcessRun";
|
import ProcessRun from "qqq/pages/processes/ProcessRun";
|
||||||
import Client from "qqq/utils/qqq/Client";
|
import Client from "qqq/utils/qqq/Client";
|
||||||
@ -258,11 +258,11 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
|||||||
** helper function, to convert values from a QRecord values map to a regular old
|
** helper function, to convert values from a QRecord values map to a regular old
|
||||||
** js object
|
** js object
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function convertQRecordValuesFromMapToObject(record: QRecord): {[name: string]: any}
|
function convertQRecordValuesFromMapToObject(record: QRecord): { [name: string]: any }
|
||||||
{
|
{
|
||||||
const rs: {[name: string]: any} = {};
|
const rs: { [name: string]: any } = {};
|
||||||
|
|
||||||
if(record && record.values)
|
if (record && record.values)
|
||||||
{
|
{
|
||||||
record.values.forEach((value, key) => rs[key] = value);
|
record.values.forEach((value, key) => rs[key] = value);
|
||||||
}
|
}
|
||||||
@ -293,7 +293,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box key={`${widgetMetaData.name}-${i}`} sx={{alignItems: "stretch", flexGrow: 1, display: "flex", marginTop: "0px", paddingTop: "0px", width: "100%", height: "100%"}}>
|
<Box key={`${widgetMetaData.name}-${i}`} sx={{alignItems: "stretch", flexGrow: 1, display: "flex", marginTop: "0px", paddingTop: "0px", width: "100%", height: "100%", flexDirection: widgetMetaData.type == "multiTable" ? "column" : "row"}}>
|
||||||
{
|
{
|
||||||
haveLoadedParams && widgetMetaData.type === "parentWidget" && (
|
haveLoadedParams && widgetMetaData.type === "parentWidget" && (
|
||||||
<ParentWidget
|
<ParentWidget
|
||||||
@ -343,6 +343,20 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
widgetMetaData.type === "multiTable" && (
|
||||||
|
widgetData[i]?.tableDataList?.map((tableData: WidgetData, index: number) =>
|
||||||
|
<Box pb={3} key={`${widgetMetaData.type}-${index}`}>
|
||||||
|
<TableWidget
|
||||||
|
widgetMetaData={widgetMetaData}
|
||||||
|
widgetData={tableData}
|
||||||
|
reloadWidgetCallback={(data) => reloadWidget(i, data)}
|
||||||
|
isChild={areChildren}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
{
|
{
|
||||||
widgetMetaData.type === "stackedBarChart" && (
|
widgetMetaData.type === "stackedBarChart" && (
|
||||||
<Widget
|
<Widget
|
||||||
@ -584,17 +598,19 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
widgetMetaData.type === "reportSetup" && (
|
widgetMetaData.type === "filterAndColumnsSetup" && (
|
||||||
widgetData && widgetData[i] && widgetData[i].queryParams &&
|
widgetData && widgetData[i] && widgetData[i].queryParams &&
|
||||||
<ReportSetupWidget isEditable={false} widgetMetaData={widgetMetaData} recordValues={convertQRecordValuesFromMapToObject(record)} onSaveCallback={() =>
|
<FilterAndColumnsSetupWidget isEditable={false} widgetMetaData={widgetMetaData} recordValues={convertQRecordValuesFromMapToObject(record)} onSaveCallback={() =>
|
||||||
{}} />
|
{
|
||||||
|
}} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
widgetMetaData.type === "pivotTableSetup" && (
|
widgetMetaData.type === "pivotTableSetup" && (
|
||||||
widgetData && widgetData[i] && widgetData[i].queryParams &&
|
widgetData && widgetData[i] && widgetData[i].queryParams &&
|
||||||
<PivotTableSetupWidget isEditable={false} widgetMetaData={widgetMetaData} recordValues={convertQRecordValuesFromMapToObject(record)} onSaveCallback={() =>
|
<PivotTableSetupWidget isEditable={false} widgetMetaData={widgetMetaData} recordValues={convertQRecordValuesFromMapToObject(record)} onSaveCallback={() =>
|
||||||
{}} />
|
{
|
||||||
|
}} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -21,14 +21,16 @@
|
|||||||
|
|
||||||
|
|
||||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Icon from "@mui/material/Icon";
|
import Icon from "@mui/material/Icon";
|
||||||
import Tooltip from "@mui/material/Tooltip/Tooltip";
|
import Tooltip from "@mui/material/Tooltip/Tooltip";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import React from "react";
|
|
||||||
import colors from "qqq/assets/theme/base/colors";
|
import colors from "qqq/assets/theme/base/colors";
|
||||||
import {WidgetData} from "qqq/components/widgets/Widget";
|
import {WidgetData} from "qqq/components/widgets/Widget";
|
||||||
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||||
|
import React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Utility class used by Widgets
|
** Utility class used by Widgets
|
||||||
@ -51,6 +53,17 @@ export class WidgetUtils
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static generateLabelLink = (linkText: string, linkURL: string): JSX.Element =>
|
||||||
|
{
|
||||||
|
return (<Box key={1} fontSize="1rem" pl={1} display="inline" position="relative">
|
||||||
|
(<Link to={linkURL}>{linkText}</Link>)
|
||||||
|
</Box>);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -97,4 +110,4 @@ export class WidgetUtils
|
|||||||
return (fileName);
|
return (fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ export default function NumberIconBadgeBlock({widgetMetaData, data}: StandardBlo
|
|||||||
{
|
{
|
||||||
data.values.iconName &&
|
data.values.iconName &&
|
||||||
<BlockElementWrapper metaData={widgetMetaData} data={data} slot="icon">
|
<BlockElementWrapper metaData={widgetMetaData} data={data} slot="icon">
|
||||||
<Icon style={{color: data.styles.color, fontSize: "1rem", position: "relative", top: "3px"}}>{data.values.iconName}</Icon>
|
<Icon style={{color: data.styles.color, fontSize: "1rem", marginLeft: "2px", position: "relative", top: "4px"}}>{data.values.iconName}</Icon>
|
||||||
</BlockElementWrapper>
|
</BlockElementWrapper>
|
||||||
}
|
}
|
||||||
</div>);
|
</div>);
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||||
|
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
|
||||||
|
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
||||||
|
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
|
||||||
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
||||||
import {Alert, Collapse} from "@mui/material";
|
import {Alert, Collapse} from "@mui/material";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
@ -42,7 +45,7 @@ import Client from "qqq/utils/qqq/Client";
|
|||||||
import FilterUtils from "qqq/utils/qqq/FilterUtils";
|
import FilterUtils from "qqq/utils/qqq/FilterUtils";
|
||||||
import React, {useContext, useEffect, useRef, useState} from "react";
|
import React, {useContext, useEffect, useRef, useState} from "react";
|
||||||
|
|
||||||
interface ReportSetupWidgetProps
|
interface FilterAndColumnsSetupWidgetProps
|
||||||
{
|
{
|
||||||
isEditable: boolean;
|
isEditable: boolean;
|
||||||
widgetMetaData: QWidgetMetaData;
|
widgetMetaData: QWidgetMetaData;
|
||||||
@ -50,7 +53,7 @@ interface ReportSetupWidgetProps
|
|||||||
onSaveCallback?: (values: { [name: string]: any }) => void;
|
onSaveCallback?: (values: { [name: string]: any }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportSetupWidget.defaultProps = {
|
FilterAndColumnsSetupWidget.defaultProps = {
|
||||||
onSaveCallback: null
|
onSaveCallback: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,9 +83,10 @@ const qController = Client.getInstance();
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Component for editing the main setup of a report - that is: filter & columns
|
** Component for editing the main setup of a report - that is: filter & columns
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
export default function ReportSetupWidget({isEditable, widgetMetaData, recordValues, onSaveCallback}: ReportSetupWidgetProps): JSX.Element
|
export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData, recordValues, onSaveCallback}: FilterAndColumnsSetupWidgetProps): JSX.Element
|
||||||
{
|
{
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
const [hideColumns, setHideColumns] = useState(widgetMetaData?.defaultValues?.has("hideColumns") && widgetMetaData?.defaultValues?.get("hideColumns"));
|
||||||
const [tableMetaData, setTableMetaData] = useState(null as QTableMetaData);
|
const [tableMetaData, setTableMetaData] = useState(null as QTableMetaData);
|
||||||
|
|
||||||
const [alertContent, setAlertContent] = useState(null as string);
|
const [alertContent, setAlertContent] = useState(null as string);
|
||||||
@ -101,15 +105,36 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
|
|||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// load values from record //
|
// load values from record //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
let queryFilter = recordValues["queryFilterJson"] && JSON.parse(recordValues["queryFilterJson"]) as QQueryFilter;
|
let columns: QQueryColumns = null;
|
||||||
let usingDefaultEmptyFilter = false;
|
let usingDefaultEmptyFilter = false;
|
||||||
|
let queryFilter = recordValues["queryFilterJson"] && JSON.parse(recordValues["queryFilterJson"]) as QQueryFilter;
|
||||||
if (!queryFilter)
|
if (!queryFilter)
|
||||||
{
|
{
|
||||||
queryFilter = new QQueryFilter();
|
queryFilter = new QQueryFilter();
|
||||||
usingDefaultEmptyFilter = true;
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if there is no queryFilter provided, see if there are default fields from which a query should be seeded //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const defaultFilterFields = getDefaultFilterFieldNames(widgetMetaData);
|
||||||
|
if (defaultFilterFields?.length > 0)
|
||||||
|
{
|
||||||
|
defaultFilterFields.forEach((fieldName: string) =>
|
||||||
|
{
|
||||||
|
if (recordValues[fieldName])
|
||||||
|
{
|
||||||
|
queryFilter.addCriteria(new QFilterCriteria(fieldName, QCriteriaOperator.EQUALS, [recordValues[fieldName]]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queryFilter.addOrderBy(new QFilterOrderBy("id", false));
|
||||||
|
queryFilter = Object.assign({}, queryFilter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
usingDefaultEmptyFilter = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let columns: QQueryColumns = null;
|
|
||||||
if (recordValues["columnsJson"])
|
if (recordValues["columnsJson"])
|
||||||
{
|
{
|
||||||
columns = QQueryColumns.buildFromJSON(recordValues["columnsJson"]);
|
columns = QQueryColumns.buildFromJSON(recordValues["columnsJson"]);
|
||||||
@ -120,11 +145,20 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if (recordValues["tableName"] && (tableMetaData == null || tableMetaData.name != recordValues["tableName"]))
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if a default table name specified, use it, otherwise use it from the record values //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
let tableName = widgetMetaData?.defaultValues?.get("tableName");
|
||||||
|
if (!tableName && recordValues["tableName"] && (tableMetaData == null || tableMetaData.name != recordValues["tableName"]))
|
||||||
|
{
|
||||||
|
tableName = recordValues["tableName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tableName)
|
||||||
{
|
{
|
||||||
(async () =>
|
(async () =>
|
||||||
{
|
{
|
||||||
const tableMetaData = await qController.loadTableMetaData(recordValues["tableName"]);
|
const tableMetaData = await qController.loadTableMetaData(tableName);
|
||||||
setTableMetaData(tableMetaData);
|
setTableMetaData(tableMetaData);
|
||||||
|
|
||||||
const queryFilterForFrontend = Object.assign({}, queryFilter);
|
const queryFilterForFrontend = Object.assign({}, queryFilter);
|
||||||
@ -132,7 +166,21 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
|
|||||||
setFrontendQueryFilter(queryFilterForFrontend);
|
setFrontendQueryFilter(queryFilterForFrontend);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}, [recordValues]);
|
}, [JSON.stringify(recordValues)]);
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
function getDefaultFilterFieldNames(widgetMetaData: QWidgetMetaData)
|
||||||
|
{
|
||||||
|
if (widgetMetaData?.defaultValues?.has("filterDefaultFieldNames"))
|
||||||
|
{
|
||||||
|
return (widgetMetaData.defaultValues.get("filterDefaultFieldNames").split(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -140,8 +188,27 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function openEditor()
|
function openEditor()
|
||||||
{
|
{
|
||||||
|
let missingRequiredFields = [] as string[];
|
||||||
|
getDefaultFilterFieldNames(widgetMetaData)?.forEach((fieldName: string) =>
|
||||||
|
{
|
||||||
|
if (!recordValues[fieldName])
|
||||||
|
{
|
||||||
|
missingRequiredFields.push(tableMetaData.fields.get(fieldName).label);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// display an alert and return if any required fields are missing //
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
if (missingRequiredFields.length > 0)
|
||||||
|
{
|
||||||
|
setAlertContent("The following fields must first be selected to add Additional Order Filters: '" + missingRequiredFields.join(", ") + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (recordValues["tableName"])
|
if (recordValues["tableName"])
|
||||||
{
|
{
|
||||||
|
setAlertContent(null);
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,7 +339,14 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
|
|||||||
const labelAdditionalElementsRight: JSX.Element[] = [];
|
const labelAdditionalElementsRight: JSX.Element[] = [];
|
||||||
if (isEditable)
|
if (isEditable)
|
||||||
{
|
{
|
||||||
labelAdditionalElementsRight.push(<HeaderLinkButtonComponent key="filterAndColumnsHeader" label="Edit Filters and Columns" onClickCallback={openEditor} disabled={tableMetaData == null} disabledTooltip={selectTableFirstTooltipTitle} />);
|
if (!hideColumns)
|
||||||
|
{
|
||||||
|
labelAdditionalElementsRight.push(<HeaderLinkButtonComponent key="filterAndColumnsHeader" label="Edit Filters and Columns" onClickCallback={openEditor} disabled={tableMetaData == null} disabledTooltip={selectTableFirstTooltipTitle} />);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
labelAdditionalElementsRight.push(<HeaderLinkButtonComponent key="filterAndColumnsHeader" label="Edit Filters" onClickCallback={openEditor} disabled={tableMetaData == null} disabledTooltip={selectTableFirstTooltipTitle} />);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -306,34 +380,36 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
!isEditable && <Box color={colors.gray.main}>Your report has no filters.</Box>
|
!isEditable && <Box color={colors.gray.main}>No filters are configured.</Box>
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
<Box pt="1rem">
|
{!hideColumns && (
|
||||||
<h5>Columns</h5>
|
<Box pt="1rem">
|
||||||
<Box display="flex" flexWrap="wrap" fontSize="1rem">
|
<h5>Columns</h5>
|
||||||
{
|
<Box display="flex" flexWrap="wrap" fontSize="1rem">
|
||||||
mayShowColumnsPreview() &&
|
{
|
||||||
columns.columns.map((column, i) => <React.Fragment key={`column-${i}`}>{renderColumn(column)}</React.Fragment>)
|
mayShowColumnsPreview() &&
|
||||||
}
|
columns.columns.map((column, i) => <React.Fragment key={`column-${i}`}>{renderColumn(column)}</React.Fragment>)
|
||||||
{
|
}
|
||||||
!mayShowColumnsPreview() &&
|
{
|
||||||
<Box width="100%" sx={{fontSize: "1rem", background: "#FFFFFF"}} minHeight={"2.375rem"} p={"0.5rem"} pb={"0.125rem"}>
|
!mayShowColumnsPreview() &&
|
||||||
{
|
<Box width="100%" sx={{fontSize: "1rem", background: "#FFFFFF"}} minHeight={"2.375rem"} p={"0.5rem"} pb={"0.125rem"}>
|
||||||
isEditable &&
|
{
|
||||||
<Tooltip title={selectTableFirstTooltipTitle}>
|
isEditable &&
|
||||||
<span><Button disabled={!recordValues["tableName"]} sx={unborderedButtonSX} onClick={openEditor}>+ Add Columns</Button></span>
|
<Tooltip title={selectTableFirstTooltipTitle}>
|
||||||
</Tooltip>
|
<span><Button disabled={!recordValues["tableName"]} sx={unborderedButtonSX} onClick={openEditor}>+ Add Columns</Button></span>
|
||||||
}
|
</Tooltip>
|
||||||
{
|
}
|
||||||
!isEditable && <Box color={colors.gray.main}>Your report has no columns.</Box>
|
{
|
||||||
}
|
!isEditable && <Box color={colors.gray.main}>No columns are selected.</Box>
|
||||||
</Box>
|
}
|
||||||
}
|
</Box>
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
)}
|
||||||
{
|
{
|
||||||
modalOpen &&
|
modalOpen &&
|
||||||
<Modal open={modalOpen} onClose={(event, reason) => closeEditor(event, reason)}>
|
<Modal open={modalOpen} onClose={(event, reason) => closeEditor(event, reason)}>
|
@ -39,9 +39,9 @@ import colors from "qqq/assets/theme/base/colors";
|
|||||||
import {QCancelButton, QSaveButton} from "qqq/components/buttons/DefaultButtons";
|
import {QCancelButton, QSaveButton} from "qqq/components/buttons/DefaultButtons";
|
||||||
import FieldAutoComplete from "qqq/components/misc/FieldAutoComplete";
|
import FieldAutoComplete from "qqq/components/misc/FieldAutoComplete";
|
||||||
import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent";
|
import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent";
|
||||||
|
import {buttonSX, unborderedButtonSX} from "qqq/components/widgets/misc/FilterAndColumnsSetupWidget";
|
||||||
import {PivotTableGroupByElement} from "qqq/components/widgets/misc/PivotTableGroupByElement";
|
import {PivotTableGroupByElement} from "qqq/components/widgets/misc/PivotTableGroupByElement";
|
||||||
import {PivotTableValueElement} from "qqq/components/widgets/misc/PivotTableValueElement";
|
import {PivotTableValueElement} from "qqq/components/widgets/misc/PivotTableValueElement";
|
||||||
import {buttonSX, unborderedButtonSX} from "qqq/components/widgets/misc/ReportSetupWidget";
|
|
||||||
import Widget, {HeaderToggleComponent} from "qqq/components/widgets/Widget";
|
import Widget, {HeaderToggleComponent} from "qqq/components/widgets/Widget";
|
||||||
import {PivotObjectKey, PivotTableDefinition, PivotTableFunction, pivotTableFunctionLabels, PivotTableGroupBy, PivotTableValue} from "qqq/models/misc/PivotTableDefinitionModels";
|
import {PivotObjectKey, PivotTableDefinition, PivotTableFunction, pivotTableFunctionLabels, PivotTableGroupBy, PivotTableValue} from "qqq/models/misc/PivotTableDefinitionModels";
|
||||||
import QQueryColumns from "qqq/models/query/QQueryColumns";
|
import QQueryColumns from "qqq/models/query/QQueryColumns";
|
||||||
|
@ -30,8 +30,6 @@ import TableContainer from "@mui/material/TableContainer";
|
|||||||
import TableRow from "@mui/material/TableRow";
|
import TableRow from "@mui/material/TableRow";
|
||||||
import Tooltip from "@mui/material/Tooltip";
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
import parse from "html-react-parser";
|
import parse from "html-react-parser";
|
||||||
import React, {useEffect, useMemo, useState} from "react";
|
|
||||||
import {useAsyncDebounce, useExpanded, useGlobalFilter, usePagination, useSortBy, useTable} from "react-table";
|
|
||||||
import colors from "qqq/assets/theme/base/colors";
|
import colors from "qqq/assets/theme/base/colors";
|
||||||
import MDInput from "qqq/components/legacy/MDInput";
|
import MDInput from "qqq/components/legacy/MDInput";
|
||||||
import MDPagination from "qqq/components/legacy/MDPagination";
|
import MDPagination from "qqq/components/legacy/MDPagination";
|
||||||
@ -43,6 +41,8 @@ import DefaultCell from "qqq/components/widgets/tables/cells/DefaultCell";
|
|||||||
import ImageCell from "qqq/components/widgets/tables/cells/ImageCell";
|
import ImageCell from "qqq/components/widgets/tables/cells/ImageCell";
|
||||||
import {TableDataInput} from "qqq/components/widgets/tables/TableCard";
|
import {TableDataInput} from "qqq/components/widgets/tables/TableCard";
|
||||||
import WidgetBlock from "qqq/components/widgets/WidgetBlock";
|
import WidgetBlock from "qqq/components/widgets/WidgetBlock";
|
||||||
|
import React, {useEffect, useMemo, useState} from "react";
|
||||||
|
import {useAsyncDebounce, useExpanded, useGlobalFilter, usePagination, useSortBy, useTable} from "react-table";
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
@ -106,17 +106,17 @@ function DataTable({
|
|||||||
entries = entriesPerPageOptions ? entriesPerPageOptions : ["10", "25", "50", "100"];
|
entries = entriesPerPageOptions ? entriesPerPageOptions : ["10", "25", "50", "100"];
|
||||||
|
|
||||||
let widths = [];
|
let widths = [];
|
||||||
for(let i = 0; i<table.columns.length; i++)
|
for (let i = 0; i < table.columns.length; i++)
|
||||||
{
|
{
|
||||||
const column = table.columns[i];
|
const column = table.columns[i];
|
||||||
if(column.type !== "hidden")
|
if (column.type !== "hidden")
|
||||||
{
|
{
|
||||||
widths.push(table.columns[i].width ?? "1fr");
|
widths.push(table.columns[i].width ?? "1fr");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let showExpandColumn = false;
|
let showExpandColumn = false;
|
||||||
if(table.rows)
|
if (table.rows)
|
||||||
{
|
{
|
||||||
for (let i = 0; i < table.rows.length; i++)
|
for (let i = 0; i < table.rows.length; i++)
|
||||||
{
|
{
|
||||||
@ -129,7 +129,7 @@ function DataTable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const columnsToMemo = [...table.columns];
|
const columnsToMemo = [...table.columns];
|
||||||
if(showExpandColumn)
|
if (showExpandColumn)
|
||||||
{
|
{
|
||||||
widths.push("60px");
|
widths.push("60px");
|
||||||
columnsToMemo.push(
|
columnsToMemo.push(
|
||||||
@ -173,11 +173,11 @@ function DataTable({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(table.columnHeaderTooltips)
|
if (table.columnHeaderTooltips)
|
||||||
{
|
{
|
||||||
for (let column of columnsToMemo)
|
for (let column of columnsToMemo)
|
||||||
{
|
{
|
||||||
if(table.columnHeaderTooltips[column.accessor])
|
if (table.columnHeaderTooltips[column.accessor])
|
||||||
{
|
{
|
||||||
column.tooltip = table.columnHeaderTooltips[column.accessor];
|
column.tooltip = table.columnHeaderTooltips[column.accessor];
|
||||||
}
|
}
|
||||||
@ -297,7 +297,7 @@ function DataTable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let visibleFooterRows = 1;
|
let visibleFooterRows = 1;
|
||||||
if(expanded && expanded[`${table.rows.length-1}`])
|
if (expanded && expanded[`${table.rows.length - 1}`])
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// todo - should count how many are expanded... //
|
// todo - should count how many are expanded... //
|
||||||
@ -308,7 +308,7 @@ function DataTable({
|
|||||||
function getTable(includeHead: boolean, rows: any, isFooter: boolean)
|
function getTable(includeHead: boolean, rows: any, isFooter: boolean)
|
||||||
{
|
{
|
||||||
let boxStyle = {};
|
let boxStyle = {};
|
||||||
if(fixedStickyLastRow)
|
if (fixedStickyLastRow)
|
||||||
{
|
{
|
||||||
boxStyle = isFooter
|
boxStyle = isFooter
|
||||||
? {borderTop: `0.0625rem solid ${colors.grayLines.main};`, backgroundColor: "#EEEEEE"}
|
? {borderTop: `0.0625rem solid ${colors.grayLines.main};`, backgroundColor: "#EEEEEE"}
|
||||||
@ -316,7 +316,7 @@ function DataTable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let innerBoxStyle = {};
|
let innerBoxStyle = {};
|
||||||
if(fixedStickyLastRow && isFooter)
|
if (fixedStickyLastRow && isFooter)
|
||||||
{
|
{
|
||||||
innerBoxStyle = {overflowY: "auto", scrollbarGutter: "stable"};
|
innerBoxStyle = {overflowY: "auto", scrollbarGutter: "stable"};
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ function DataTable({
|
|||||||
includeHead && (
|
includeHead && (
|
||||||
<Box component="thead" sx={{position: "sticky", top: 0, background: "white", zIndex: 10}}>
|
<Box component="thead" sx={{position: "sticky", top: 0, background: "white", zIndex: 10}}>
|
||||||
{headerGroups.map((headerGroup: any, i: number) => (
|
{headerGroups.map((headerGroup: any, i: number) => (
|
||||||
<TableRow key={i} {...headerGroup.getHeaderGroupProps()} sx={{display: "grid", gridTemplateColumns: gridTemplateColumns}}>
|
<TableRow key={i} {...headerGroup.getHeaderGroupProps()} sx={{display: "grid", alignItems: "flex-end", gridTemplateColumns: gridTemplateColumns}}>
|
||||||
{headerGroup.headers.map((column: any) => (
|
{headerGroup.headers.map((column: any) => (
|
||||||
column.type !== "hidden" && (
|
column.type !== "hidden" && (
|
||||||
<DataTableHeadCell
|
<DataTableHeadCell
|
||||||
@ -356,10 +356,10 @@ function DataTable({
|
|||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
// don't do an end-border on nested rows - unless they're the last one in a set //
|
// don't do an end-border on nested rows - unless they're the last one in a set //
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
if(row.depth > 0)
|
if (row.depth > 0)
|
||||||
{
|
{
|
||||||
overrideNoEndBorder = true;
|
overrideNoEndBorder = true;
|
||||||
if(key + 1 < rows.length && rows[key + 1].depth == 0)
|
if (key + 1 < rows.length && rows[key + 1].depth == 0)
|
||||||
{
|
{
|
||||||
overrideNoEndBorder = false;
|
overrideNoEndBorder = false;
|
||||||
}
|
}
|
||||||
@ -368,17 +368,17 @@ function DataTable({
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// don't do end-border on the footer //
|
// don't do end-border on the footer //
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
if(isFooter)
|
if (isFooter)
|
||||||
{
|
{
|
||||||
overrideNoEndBorder = true;
|
overrideNoEndBorder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let background = "initial";
|
let background = "initial";
|
||||||
if(isFooter)
|
if (isFooter)
|
||||||
{
|
{
|
||||||
background = "#EEEEEE";
|
background = "#EEEEEE";
|
||||||
}
|
}
|
||||||
else if(row.depth > 0 || row.isExpanded)
|
else if (row.depth > 0 || row.isExpanded)
|
||||||
{
|
{
|
||||||
background = "#FAFAFA";
|
background = "#FAFAFA";
|
||||||
}
|
}
|
||||||
@ -453,7 +453,7 @@ function DataTable({
|
|||||||
|
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box></Box>
|
</Box></Box>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -28,13 +28,13 @@ import TableBody from "@mui/material/TableBody";
|
|||||||
import TableContainer from "@mui/material/TableContainer";
|
import TableContainer from "@mui/material/TableContainer";
|
||||||
import TableRow from "@mui/material/TableRow";
|
import TableRow from "@mui/material/TableRow";
|
||||||
import parse from "html-react-parser";
|
import parse from "html-react-parser";
|
||||||
import React, {useEffect, useState} from "react";
|
|
||||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||||
import DataTableBodyCell from "qqq/components/widgets/tables/cells/DataTableBodyCell";
|
import DataTableBodyCell from "qqq/components/widgets/tables/cells/DataTableBodyCell";
|
||||||
import DataTableHeadCell from "qqq/components/widgets/tables/cells/DataTableHeadCell";
|
import DataTableHeadCell from "qqq/components/widgets/tables/cells/DataTableHeadCell";
|
||||||
import DefaultCell from "qqq/components/widgets/tables/cells/DefaultCell";
|
import DefaultCell from "qqq/components/widgets/tables/cells/DefaultCell";
|
||||||
import DataTable from "qqq/components/widgets/tables/DataTable";
|
import DataTable from "qqq/components/widgets/tables/DataTable";
|
||||||
import Client from "qqq/utils/qqq/Client";
|
import Client from "qqq/utils/qqq/Client";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
@ -43,7 +43,7 @@ import Client from "qqq/utils/qqq/Client";
|
|||||||
export interface TableDataInput
|
export interface TableDataInput
|
||||||
{
|
{
|
||||||
columns: { [key: string]: any }[];
|
columns: { [key: string]: any }[];
|
||||||
columnHeaderTooltips?: { [columnName: string]: string | JSX.Element }
|
columnHeaderTooltips?: { [columnName: string]: string | JSX.Element };
|
||||||
rows: { [key: string]: any }[];
|
rows: { [key: string]: any }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +63,7 @@ interface Props
|
|||||||
}
|
}
|
||||||
|
|
||||||
const qController = Client.getInstance();
|
const qController = Client.getInstance();
|
||||||
|
|
||||||
function TableCard({noRowsFoundHTML, data, rowsPerPage, hidePaginationDropdown, fixedStickyLastRow, fixedHeight, widgetMetaData}: Props): JSX.Element
|
function TableCard({noRowsFoundHTML, data, rowsPerPage, hidePaginationDropdown, fixedStickyLastRow, fixedHeight, widgetMetaData}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const [qInstance, setQInstance] = useState(null as QInstance);
|
const [qInstance, setQInstance] = useState(null as QInstance);
|
||||||
@ -108,7 +109,7 @@ function TableCard({noRowsFoundHTML, data, rowsPerPage, hidePaginationDropdown,
|
|||||||
<TableContainer sx={{boxShadow: "none"}}>
|
<TableContainer sx={{boxShadow: "none"}}>
|
||||||
<Table>
|
<Table>
|
||||||
<Box component="thead">
|
<Box component="thead">
|
||||||
<TableRow key="header">
|
<TableRow sx={{alignItems: "flex-end"}} key="header">
|
||||||
{Array(8).fill(0).map((_, i) =>
|
{Array(8).fill(0).map((_, i) =>
|
||||||
<DataTableHeadCell key={`head-${i}`} sorted={false} width="auto" align="center">
|
<DataTableHeadCell key={`head-${i}`} sorted={false} width="auto" align="center">
|
||||||
<Skeleton width="100%" />
|
<Skeleton width="100%" />
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import {htmlToText} from "html-to-text";
|
import {htmlToText} from "html-to-text";
|
||||||
import React, {useContext, useEffect, useState} from "react";
|
|
||||||
import QContext from "QContext";
|
import QContext from "QContext";
|
||||||
import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent";
|
import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent";
|
||||||
import TableCard from "qqq/components/widgets/tables/TableCard";
|
import TableCard from "qqq/components/widgets/tables/TableCard";
|
||||||
@ -31,6 +30,7 @@ import Widget, {WidgetData} from "qqq/components/widgets/Widget";
|
|||||||
import {WidgetUtils} from "qqq/components/widgets/WidgetUtils";
|
import {WidgetUtils} from "qqq/components/widgets/WidgetUtils";
|
||||||
import HtmlUtils from "qqq/utils/HtmlUtils";
|
import HtmlUtils from "qqq/utils/HtmlUtils";
|
||||||
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||||
|
import React, {useContext, useEffect, useState} from "react";
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
@ -40,8 +40,7 @@ interface Props
|
|||||||
isChild?: boolean;
|
isChild?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
TableWidget.defaultProps = {
|
TableWidget.defaultProps = {};
|
||||||
};
|
|
||||||
|
|
||||||
function TableWidget(props: Props): JSX.Element
|
function TableWidget(props: Props): JSX.Element
|
||||||
{
|
{
|
||||||
@ -86,7 +85,7 @@ function TableWidget(props: Props): JSX.Element
|
|||||||
|
|
||||||
const cell = rows[i][columns[j].accessor];
|
const cell = rows[i][columns[j].accessor];
|
||||||
let text = cell;
|
let text = cell;
|
||||||
if(columns[j].type != "default")
|
if (columns[j].type != "default")
|
||||||
{
|
{
|
||||||
text = htmlToText(cell,
|
text = htmlToText(cell,
|
||||||
{
|
{
|
||||||
@ -105,7 +104,7 @@ function TableWidget(props: Props): JSX.Element
|
|||||||
setCsv(csv);
|
setCsv(csv);
|
||||||
|
|
||||||
const fileName = WidgetUtils.makeExportFileName(props.widgetData, props.widgetMetaData);
|
const fileName = WidgetUtils.makeExportFileName(props.widgetData, props.widgetMetaData);
|
||||||
setFileName(fileName)
|
setFileName(fileName);
|
||||||
|
|
||||||
console.log(`useEffect, setting fileName ${fileName}`);
|
console.log(`useEffect, setting fileName ${fileName}`);
|
||||||
}
|
}
|
||||||
@ -114,24 +113,28 @@ function TableWidget(props: Props): JSX.Element
|
|||||||
|
|
||||||
const onExportClick = () =>
|
const onExportClick = () =>
|
||||||
{
|
{
|
||||||
if(props.widgetData?.csvData)
|
if (props.widgetData?.csvData)
|
||||||
{
|
{
|
||||||
const csv = WidgetUtils.widgetCsvDataToString(props.widgetData);
|
const csv = WidgetUtils.widgetCsvDataToString(props.widgetData);
|
||||||
const fileName = WidgetUtils.makeExportFileName(props.widgetData, props.widgetMetaData);
|
const fileName = WidgetUtils.makeExportFileName(props.widgetData, props.widgetMetaData);
|
||||||
HtmlUtils.download(fileName, csv);
|
HtmlUtils.download(fileName, csv);
|
||||||
}
|
}
|
||||||
else if(csv)
|
else if (csv)
|
||||||
{
|
{
|
||||||
HtmlUtils.download(fileName, csv);
|
HtmlUtils.download(fileName, csv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alert("There is no data available to export.")
|
alert("There is no data available to export.");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const labelAdditionalElementsLeft: JSX.Element[] = [];
|
const labelAdditionalElementsLeft: JSX.Element[] = [];
|
||||||
if(props.widgetMetaData?.showExportButton)
|
if (props.widgetData?.linkText && props.widgetData?.linkURL)
|
||||||
|
{
|
||||||
|
labelAdditionalElementsLeft.push(WidgetUtils.generateLabelLink(props.widgetData?.linkText, props.widgetData?.linkURL));
|
||||||
|
}
|
||||||
|
if (props.widgetMetaData?.showExportButton)
|
||||||
{
|
{
|
||||||
labelAdditionalElementsLeft.push(WidgetUtils.generateExportButton(onExportClick));
|
labelAdditionalElementsLeft.push(WidgetUtils.generateExportButton(onExportClick));
|
||||||
}
|
}
|
||||||
@ -139,14 +142,14 @@ function TableWidget(props: Props): JSX.Element
|
|||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// look for column-header tooltips from helpContent //
|
// look for column-header tooltips from helpContent //
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
const columnHeaderTooltips: {[columnName: string]: JSX.Element} = {}
|
const columnHeaderTooltips: { [columnName: string]: JSX.Element } = {};
|
||||||
for (let column of props.widgetData?.columns ?? [])
|
for (let column of props.widgetData?.columns ?? [])
|
||||||
{
|
{
|
||||||
const helpRoles = ["ALL_SCREENS"]
|
const helpRoles = ["ALL_SCREENS"];
|
||||||
const slotName = `columnHeader=${column.accessor}`;
|
const slotName = `columnHeader=${column.accessor}`;
|
||||||
const showHelp = helpHelpActive || hasHelpContent(props.widgetMetaData?.helpContent?.get(slotName), helpRoles);
|
const showHelp = helpHelpActive || hasHelpContent(props.widgetMetaData?.helpContent?.get(slotName), helpRoles);
|
||||||
|
|
||||||
if(showHelp)
|
if (showHelp)
|
||||||
{
|
{
|
||||||
const formattedHelpContent = <HelpContent helpContents={props.widgetMetaData?.helpContent?.get(slotName)} roles={helpRoles} helpContentKey={`widget:${props.widgetMetaData?.name};slot:${slotName}`} />;
|
const formattedHelpContent = <HelpContent helpContents={props.widgetMetaData?.helpContent?.get(slotName)} roles={helpRoles} helpContentKey={`widget:${props.widgetMetaData?.name};slot:${slotName}`} />;
|
||||||
columnHeaderTooltips[column.accessor] = formattedHelpContent;
|
columnHeaderTooltips[column.accessor] = formattedHelpContent;
|
||||||
|
@ -54,7 +54,7 @@ import DynamicFormUtils from "qqq/components/forms/DynamicFormUtils";
|
|||||||
import MDButton from "qqq/components/legacy/MDButton";
|
import MDButton from "qqq/components/legacy/MDButton";
|
||||||
import MDProgress from "qqq/components/legacy/MDProgress";
|
import MDProgress from "qqq/components/legacy/MDProgress";
|
||||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||||
import HelpContent from "qqq/components/misc/HelpContent";
|
import HelpContent, {hasHelpContent} from "qqq/components/misc/HelpContent";
|
||||||
import QRecordSidebar from "qqq/components/misc/RecordSidebar";
|
import QRecordSidebar from "qqq/components/misc/RecordSidebar";
|
||||||
import {GoogleDriveFolderPickerWrapper} from "qqq/components/processes/GoogleDriveFolderPickerWrapper";
|
import {GoogleDriveFolderPickerWrapper} from "qqq/components/processes/GoogleDriveFolderPickerWrapper";
|
||||||
import ProcessSummaryResults from "qqq/components/processes/ProcessSummaryResults";
|
import ProcessSummaryResults from "qqq/components/processes/ProcessSummaryResults";
|
||||||
@ -94,7 +94,7 @@ const BACKOFF_AMOUNT = 1.5;
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
let formikSetFieldValueFunction = (field: string, value: any, shouldValidate?: boolean): void =>
|
let formikSetFieldValueFunction = (field: string, value: any, shouldValidate?: boolean): void =>
|
||||||
{
|
{
|
||||||
}
|
};
|
||||||
|
|
||||||
function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, isReport, recordIds, closeModalHandler, forceReInit, overrideLabel}: Props): JSX.Element
|
function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, isReport, recordIds, closeModalHandler, forceReInit, overrideLabel}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
@ -134,9 +134,9 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
||||||
const [showFullHelpText, setShowFullHelpText] = useState(false);
|
const [showFullHelpText, setShowFullHelpText] = useState(false);
|
||||||
|
|
||||||
const [renderedWidgets, setRenderedWidgets] = useState({} as {[step: string]: {[widgetName: string]: any}});
|
const [renderedWidgets, setRenderedWidgets] = useState({} as { [step: string]: { [widgetName: string]: any } });
|
||||||
|
|
||||||
const {pageHeader, recordAnalytics, setPageHeader} = useContext(QContext);
|
const {pageHeader, recordAnalytics, setPageHeader, helpHelpActive} = useContext(QContext);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// for setting the processError state - call this function, which will also set the isUserFacingError state //
|
// for setting the processError state - call this function, which will also set the isUserFacingError state //
|
||||||
@ -238,15 +238,15 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
setShowFullHelpText(!showFullHelpText);
|
setShowFullHelpText(!showFullHelpText);
|
||||||
};
|
};
|
||||||
|
|
||||||
const download = (processValues: {[key: string]: string}) =>
|
const download = (processValues: { [key: string]: string }) =>
|
||||||
{
|
{
|
||||||
let url;
|
let url;
|
||||||
let fileName = processValues.downloadFileName;
|
let fileName = processValues.downloadFileName;
|
||||||
if(processValues.serverFilePath)
|
if (processValues.serverFilePath)
|
||||||
{
|
{
|
||||||
url = `/download/${encodeURIComponent(processValues.downloadFileName)}?filePath=${encodeURIComponent(processValues.serverFilePath)}`;
|
url = `/download/${encodeURIComponent(processValues.downloadFileName)}?filePath=${encodeURIComponent(processValues.serverFilePath)}`;
|
||||||
}
|
}
|
||||||
else if(processValues.storageTableName && processValues.storageReference)
|
else if (processValues.storageTableName && processValues.storageReference)
|
||||||
{
|
{
|
||||||
url = `/download/${encodeURIComponent(processValues.downloadFileName)}?storageTableName=${encodeURIComponent(processValues.storageTableName)}&storageReference=${encodeURIComponent(processValues.storageReference)}`;
|
url = `/download/${encodeURIComponent(processValues.downloadFileName)}?storageTableName=${encodeURIComponent(processValues.storageTableName)}&storageReference=${encodeURIComponent(processValues.storageReference)}`;
|
||||||
}
|
}
|
||||||
@ -291,19 +291,19 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function renderWidget(widgetName: string)
|
function renderWidget(widgetName: string)
|
||||||
{
|
{
|
||||||
if(!renderedWidgets[activeStep.name])
|
if (!renderedWidgets[activeStep.name])
|
||||||
{
|
{
|
||||||
renderedWidgets[activeStep.name] = {};
|
renderedWidgets[activeStep.name] = {};
|
||||||
setRenderedWidgets(renderedWidgets);
|
setRenderedWidgets(renderedWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(renderedWidgets[activeStep.name][widgetName])
|
if (renderedWidgets[activeStep.name][widgetName])
|
||||||
{
|
{
|
||||||
return renderedWidgets[activeStep.name][widgetName];
|
return renderedWidgets[activeStep.name][widgetName];
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgetMetaData = qInstance.widgets.get(widgetName);
|
const widgetMetaData = qInstance.widgets.get(widgetName);
|
||||||
if(!widgetMetaData)
|
if (!widgetMetaData)
|
||||||
{
|
{
|
||||||
return (<Alert color="error">Unrecognized widget name: {widgetName}</Alert>);
|
return (<Alert color="error">Unrecognized widget name: {widgetName}</Alert>);
|
||||||
}
|
}
|
||||||
@ -311,12 +311,12 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
const queryStringParts: string[] = [];
|
const queryStringParts: string[] = [];
|
||||||
for (let name in processValues)
|
for (let name in processValues)
|
||||||
{
|
{
|
||||||
queryStringParts.push(`${name}=${encodeURIComponent(processValues[name])}`)
|
queryStringParts.push(`${name}=${encodeURIComponent(processValues[name])}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderedWidget = (<Box m={-2}>
|
const renderedWidget = (<Box m={-2}>
|
||||||
<DashboardWidgets widgetMetaDataList={[widgetMetaData]} omitWrappingGridContainer={true} childUrlParams={queryStringParts.join("&")} />
|
<DashboardWidgets widgetMetaDataList={[widgetMetaData]} omitWrappingGridContainer={true} childUrlParams={queryStringParts.join("&")} />
|
||||||
</Box>)
|
</Box>);
|
||||||
renderedWidgets[activeStep.name][widgetName] = renderedWidget;
|
renderedWidgets[activeStep.name][widgetName] = renderedWidget;
|
||||||
return renderedWidget;
|
return renderedWidget;
|
||||||
}
|
}
|
||||||
@ -367,8 +367,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
</MDTypography>
|
</MDTypography>
|
||||||
<Box component="div" py={3}>
|
<Box component="div" py={3}>
|
||||||
<Grid container justifyContent="flex-end" spacing={3}>
|
<Grid container justifyContent="flex-end" spacing={3}>
|
||||||
{isModal ? <QCancelButton onClickHandler={handleCancelClicked} disabled={false} label="Close" />
|
{isModal ? <QCancelButton onClickHandler={() => handleCancelClicked(true)} disabled={false} label="Close" />
|
||||||
: !isWidget && <QCancelButton onClickHandler={handleCancelClicked} disabled={false} />
|
: !isWidget && <QCancelButton onClickHandler={() => handleCancelClicked(true)} disabled={false} />
|
||||||
}
|
}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
@ -455,14 +455,12 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo not commit - not ready - need process (or screen) meta-data to have helpContents...
|
/////////////////////////////////////
|
||||||
/*
|
// screen(step)-level help content //
|
||||||
///////////////////////////////
|
/////////////////////////////////////
|
||||||
// screen-level help content //
|
|
||||||
///////////////////////////////
|
|
||||||
let helpRoles = ["PROCESS_SCREEN", "ALL_SCREENS"];
|
let helpRoles = ["PROCESS_SCREEN", "ALL_SCREENS"];
|
||||||
const formattedHelpContent = <HelpContent helpContents={process.helpContents} roles={helpRoles} helpContentKey={`table:${tableName};section:${section.name}`} />;
|
const showHelp = helpHelpActive || hasHelpContent(step.helpContents, helpRoles);
|
||||||
*/
|
const formattedHelpContent = <HelpContent helpContents={step.helpContents} roles={helpRoles} helpContentKey={`process:${processName};step:${step?.name}`} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -479,13 +477,10 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
/*
|
showHelp &&
|
||||||
// todo not commit - not ready - need process (or screen) meta-data to have helpContents...
|
<Box fontSize={"0.875rem"} color={colors.blueGray.main} pb={2}>
|
||||||
formattedHelpContent &&
|
|
||||||
<Box px={"1.5rem"} fontSize={"0.875rem"} color={colors.blueGray.main}>
|
|
||||||
{formattedHelpContent}
|
{formattedHelpContent}
|
||||||
</Box>
|
</Box>
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -505,7 +500,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
// edit the formData object to just include those. //
|
// edit the formData object to just include those. //
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
let formDataToUse = formData;
|
let formDataToUse = formData;
|
||||||
if(component.values && component.values.includeFieldNames)
|
if (component.values && component.values.includeFieldNames)
|
||||||
{
|
{
|
||||||
formDataToUse = Object.assign({}, formData);
|
formDataToUse = Object.assign({}, formData);
|
||||||
|
|
||||||
@ -613,21 +608,21 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
component.type === QComponentType.EDIT_FORM &&
|
component.type === QComponentType.EDIT_FORM &&
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
component.values?.sectionLabel ?
|
component.values?.sectionLabel ?
|
||||||
<Box py={1.5}>
|
<Box py={1.5}>
|
||||||
<Card sx={{scrollMarginTop: "20px"}}>
|
<Card sx={{scrollMarginTop: "20px"}}>
|
||||||
<MDTypography variant="h5" p={3} pl={2} pb={1}>
|
<MDTypography variant="h5" p={3} pl={2} pb={1}>
|
||||||
{component.values?.sectionLabel}
|
{component.values?.sectionLabel}
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
<Box pt={0} p={2}>
|
<Box pt={0} p={2}>
|
||||||
<QDynamicForm formData={formDataToUse} helpRoles={helpRoles} helpContentKeyPrefix={`process:${processName};`} />
|
<QDynamicForm formData={formDataToUse} helpRoles={helpRoles} helpContentKeyPrefix={`process:${processName};`} />
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
</Box> : <QDynamicForm formData={formDataToUse} helpRoles={helpRoles} helpContentKeyPrefix={`process:${processName};`} />
|
</Box> : <QDynamicForm formData={formDataToUse} helpRoles={helpRoles} helpContentKeyPrefix={`process:${processName};`} />
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
component.type === QComponentType.VIEW_FORM && step.viewFields && (
|
component.type === QComponentType.VIEW_FORM && step.viewFields && (
|
||||||
@ -1018,7 +1013,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DynamicFormUtils.addPossibleValueProps(newDynamicFormFields, fullFieldList, tableMetaData.name, null, null);
|
DynamicFormUtils.addPossibleValueProps(newDynamicFormFields, fullFieldList, tableMetaData?.name, null, null);
|
||||||
|
|
||||||
setFormFields(newDynamicFormFields);
|
setFormFields(newDynamicFormFields);
|
||||||
setValidationScheme(Yup.object().shape(newFormValidations));
|
setValidationScheme(Yup.object().shape(newFormValidations));
|
||||||
@ -1084,14 +1079,18 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
setProcessValues(qJobComplete.values);
|
setProcessValues(qJobComplete.values);
|
||||||
setQJobRunning(null);
|
setQJobRunning(null);
|
||||||
|
|
||||||
if(formikSetFieldValueFunction)
|
if (formikSetFieldValueFunction)
|
||||||
{
|
{
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// reset field values in formik //
|
// reset field values in formik //
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
for (let key in qJobComplete.values)
|
for (let key in qJobComplete.values)
|
||||||
{
|
{
|
||||||
formikSetFieldValueFunction(key, qJobComplete.values[key]);
|
if (Object.hasOwn(formFields, key))
|
||||||
|
{
|
||||||
|
console.log(`(re)setting form field [${key}] to [${qJobComplete.values[key]}]`);
|
||||||
|
formikSetFieldValueFunction(key, qJobComplete.values[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,7 +1098,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
// if the process step sent a new frontend-step-list, then refresh what we have in state (constructing new full model objects) //
|
// if the process step sent a new frontend-step-list, then refresh what we have in state (constructing new full model objects) //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
const updatedFrontendStepList = qJobComplete.updatedFrontendStepList;
|
const updatedFrontendStepList = qJobComplete.updatedFrontendStepList;
|
||||||
if(updatedFrontendStepList)
|
if (updatedFrontendStepList)
|
||||||
{
|
{
|
||||||
setSteps(updatedFrontendStepList);
|
setSteps(updatedFrontendStepList);
|
||||||
}
|
}
|
||||||
@ -1402,8 +1401,20 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelClicked = () =>
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
const handleCancelClicked = (isClose: boolean) =>
|
||||||
{
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// unless this is a 'close', then tell backend we're cancelling //
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
if (!isClose)
|
||||||
|
{
|
||||||
|
Client.getInstance().processCancel(processName, processUUID);
|
||||||
|
}
|
||||||
|
|
||||||
if (isModal && closeModalHandler)
|
if (isModal && closeModalHandler)
|
||||||
{
|
{
|
||||||
closeModalHandler(null, "cancelClicked");
|
closeModalHandler(null, "cancelClicked");
|
||||||
@ -1416,6 +1427,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
navigate(path, {replace: true});
|
navigate(path, {replace: true});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const mainCardStyles: any = {};
|
const mainCardStyles: any = {};
|
||||||
const formStyles: any = {};
|
const formStyles: any = {};
|
||||||
mainCardStyles.minHeight = `calc(100vh - ${isModal ? 150 : 400}px)`;
|
mainCardStyles.minHeight = `calc(100vh - ${isModal ? 150 : 400}px)`;
|
||||||
@ -1491,8 +1503,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
<Box p={3}>
|
<Box p={3}>
|
||||||
<Box pb={isWidget ? 6 : "initial"}>
|
<Box pb={isWidget ? 6 : "initial"}>
|
||||||
{/***************************************************************************
|
{/***************************************************************************
|
||||||
** step content - e.g., the appropriate form or other screen for the step **
|
** step content - e.g., the appropriate form or other screen for the step **
|
||||||
***************************************************************************/}
|
***************************************************************************/}
|
||||||
{getDynamicStepContent(
|
{getDynamicStepContent(
|
||||||
activeStepIndex,
|
activeStepIndex,
|
||||||
activeStep,
|
activeStep,
|
||||||
@ -1508,8 +1520,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
setFieldValue,
|
setFieldValue,
|
||||||
)}
|
)}
|
||||||
{/********************************
|
{/********************************
|
||||||
** back &| next/submit buttons **
|
** back &| next/submit buttons **
|
||||||
********************************/}
|
********************************/}
|
||||||
<Box mt={6} width="100%" display="flex" justifyContent="space-between" position={isWidget ? "absolute" : "initial"} bottom={isWidget ? "3rem" : "initial"} right={isWidget ? "1.5rem" : "initial"}>
|
<Box mt={6} width="100%" display="flex" justifyContent="space-between" position={isWidget ? "absolute" : "initial"} bottom={isWidget ? "3rem" : "initial"} right={isWidget ? "1.5rem" : "initial"}>
|
||||||
{true || activeStepIndex === 0 ? (
|
{true || activeStepIndex === 0 ? (
|
||||||
<Box />
|
<Box />
|
||||||
@ -1527,7 +1539,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
noMoreSteps && <QCancelButton
|
noMoreSteps && <QCancelButton
|
||||||
onClickHandler={handleCancelClicked}
|
onClickHandler={() => handleCancelClicked(true)}
|
||||||
label={isModal ? "Close" : "Return"}
|
label={isModal ? "Close" : "Return"}
|
||||||
iconName={isModal ? "cancel" : "arrow_back"}
|
iconName={isModal ? "cancel" : "arrow_back"}
|
||||||
disabled={isSubmitting} />
|
disabled={isSubmitting} />
|
||||||
@ -1538,7 +1550,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
<Grid container justifyContent="flex-end" spacing={3}>
|
<Grid container justifyContent="flex-end" spacing={3}>
|
||||||
{
|
{
|
||||||
!isWidget && (
|
!isWidget && (
|
||||||
<QCancelButton onClickHandler={handleCancelClicked} disabled={isSubmitting} />
|
<QCancelButton onClickHandler={() => handleCancelClicked(false)} disabled={isSubmitting} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<QSubmitButton label={nextButtonLabel} iconName={nextButtonIcon} disabled={isSubmitting} />
|
<QSubmitButton label={nextButtonLabel} iconName={nextButtonIcon} disabled={isSubmitting} />
|
||||||
@ -1553,7 +1565,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
|
@ -535,7 +535,7 @@ function RecordView({table, record: overrideRecord, launchProcess}: Props): JSX.
|
|||||||
|
|
||||||
setPageHeader(record.recordLabel);
|
setPageHeader(record.recordLabel);
|
||||||
|
|
||||||
if (!launchingProcess)
|
if (!launchingProcess && !activeModalProcess)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -421,6 +421,14 @@ input[type="search"]::-webkit-search-results-decoration
|
|||||||
font-size: 2rem !important;
|
font-size: 2rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-order-release-icon
|
||||||
|
{
|
||||||
|
font-size: 1.5rem !important;
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-schedule-icon
|
.dashboard-schedule-icon
|
||||||
{
|
{
|
||||||
font-size: 1.1rem !important;
|
font-size: 1.1rem !important;
|
||||||
@ -653,6 +661,11 @@ input[type="search"]::-webkit-search-results-decoration
|
|||||||
min-height: unset !important;
|
min-height: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.MuiDataGrid-columnHeaders
|
||||||
|
{
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
|
|
||||||
/* new style for toggle buttons */
|
/* new style for toggle buttons */
|
||||||
.MuiToggleButtonGroup-root
|
.MuiToggleButtonGroup-root
|
||||||
{
|
{
|
||||||
@ -708,3 +721,66 @@ input[type="search"]::-webkit-search-results-decoration
|
|||||||
color: white;
|
color: white;
|
||||||
background-color: #0062FF !important;
|
background-color: #0062FF !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.helpContentAlert
|
||||||
|
{
|
||||||
|
padding: 6px 16px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1.6;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert .MuiAlert-icon
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
margin-right: 12px;
|
||||||
|
padding: 7px 0;
|
||||||
|
font-size: 22px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert .MuiAlert-icon .material-icons-round
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert .MuiAlert-message
|
||||||
|
{
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert.success
|
||||||
|
{
|
||||||
|
background-color: rgb(240, 248, 241);
|
||||||
|
color: rgb(44, 76, 46);
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert.success .MuiAlert-icon .material-icons-round
|
||||||
|
{
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert.warning
|
||||||
|
{
|
||||||
|
background-color: rgb(254, 245, 234);
|
||||||
|
color: rgb(100, 65, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert.warning .MuiAlert-icon .material-icons-round
|
||||||
|
{
|
||||||
|
color: #fb8c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert.error
|
||||||
|
{
|
||||||
|
background-color: rgb(254, 239, 238);
|
||||||
|
color: rgb(98, 41, 37);
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpContentAlert.error .MuiAlert-icon .material-icons-round
|
||||||
|
{
|
||||||
|
color: #F44335;
|
||||||
|
}
|
||||||
|
@ -822,7 +822,7 @@
|
|||||||
"reportSetupWidget": {
|
"reportSetupWidget": {
|
||||||
"name": "reportSetupWidget",
|
"name": "reportSetupWidget",
|
||||||
"label": "Filters and Columns",
|
"label": "Filters and Columns",
|
||||||
"type": "reportSetup",
|
"type": "filterAndColumnsSetup",
|
||||||
"isCard": true,
|
"isCard": true,
|
||||||
"storeDropdownSelections": false,
|
"storeDropdownSelections": false,
|
||||||
"showReloadButton": true,
|
"showReloadButton": true,
|
||||||
|
Reference in New Issue
Block a user