@asaleh37/ui-base 25.8.26 → 25.8.31-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/index.d.ts +22 -6
  2. package/dist/index.js +5 -5
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +6 -6
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +1 -1
  7. package/src/components/administration/dev/AttachmentConfigGrid.tsx +1 -0
  8. package/src/components/administration/dev/DataQueryGrid.tsx +26 -16
  9. package/src/components/administration/dev/DatasourceConnectionGrid.tsx +1 -0
  10. package/src/components/administration/dev/EntityParameterGrid.tsx +94 -67
  11. package/src/components/administration/dev/MailSenderConfigGrid.tsx +1 -0
  12. package/src/components/administration/dev/MailTemplateGrid.tsx +1 -0
  13. package/src/components/administration/dev/NotificationGrid.tsx +5 -2
  14. package/src/components/administration/dev/ReportGrid.tsx +102 -111
  15. package/src/components/administration/dev/WidgetGrid.tsx +96 -147
  16. package/src/components/administration/dev/WorkflowDocumentGrid.tsx +2 -23
  17. package/src/components/templates/DataEntryTemplates/DataEntryTypes.ts +41 -16
  18. package/src/components/templates/DataEntryTemplates/DataEntryUtil.ts +20 -10
  19. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementField.tsx +80 -60
  20. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/Datefield.tsx +1 -1
  21. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/DatetimeField.tsx +1 -1
  22. package/src/components/templates/DataEntryTemplates/TemplateDataForm/TemplateForm.tsx +83 -65
  23. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGrid.tsx +8 -5
  24. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridTopBar.tsx +3 -1
  25. package/src/components/templates/report/ReportViewer.tsx +24 -138
  26. package/src/components/templates/visuals/DashboardViewer.tsx +49 -5
  27. package/src/components/templates/visuals/WidgetViewer.tsx +24 -14
  28. package/src/examples/ExampleGrid.tsx +134 -0
  29. package/src/hooks/useParameterPanel.tsx +168 -0
  30. package/src/layout/MainContent.tsx +47 -50
  31. package/src/locales/arabic/devLocalsAr.json +2 -2
  32. package/src/locales/english/devLocalsEn.json +2 -2
  33. package/src/navigationItems/index.tsx +1 -1
  34. package/src/routes/index.ts +1 -1
  35. package/src/util/AppUtils.ts +2 -0
@@ -1,20 +1,10 @@
1
1
  import { useEffect, useState } from "react";
2
- import { useAxios, useWindow } from "../../../hooks";
3
- import TemplateForm from "../DataEntryTemplates/TemplateDataForm/TemplateForm";
4
- import { useTranslation } from "react-i18next";
5
- import { FormElementProps } from "../DataEntryTemplates/DataEntryTypes";
6
- import {
7
- Accordion,
8
- AccordionDetails,
9
- AccordionSummary,
10
- Box,
11
- Icon,
12
- IconButton,
13
- Typography,
14
- } from "@mui/material";
2
+ import { useAxios } from "../../../hooks";
3
+
4
+ import { Box, IconButton } from "@mui/material";
15
5
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
16
6
  import ExcelReportViewer from "./ExcelReportViewer";
17
- import { GridExpandMoreIcon } from "@mui/x-data-grid-premium";
7
+ import { useParameterPanel } from "../../../hooks/useParameterPanel";
18
8
 
19
9
  type ReportViewerState =
20
10
  | "ERROR"
@@ -32,28 +22,6 @@ type ReportViewerProps = {
32
22
  jasperOutPutFileType?: "pdf" | "word" | "excel";
33
23
  };
34
24
 
35
- type ReportParameter = {
36
- parameterCode: string;
37
- parameterLabel: string;
38
- parameterValueFormat?: string;
39
- parameterValueField?: string;
40
- parameterDisplayField?: string;
41
- parameterDataset?: Array<any>;
42
- parameterDataQueryId?: number;
43
- hidden?: boolean;
44
- mandatory?: boolean;
45
- defaultValue?: any;
46
- parameterType:
47
- | "text"
48
- | "number"
49
- | "date"
50
- | "datetime"
51
- | "combobox"
52
- | "checkbox"
53
- | "html"
54
- | "lookup";
55
- };
56
-
57
25
  const ReportViewer: React.FC<ReportViewerProps> = (props) => {
58
26
  const [blobUrl, setBlobUrl] = useState(null);
59
27
  const [errorMessage, setErrorMessage] = useState(null);
@@ -64,38 +32,15 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
64
32
  const { handleGetRequest, handlePostRequest, HandleDownloadHTTPPostPDF } =
65
33
  useAxios();
66
34
  const [reportInfo, setReportInfo] = useState<any>(null);
67
- const [reportParametersValues, setReportParametersValues] = useState<any>({
68
- ...props?.reportParametersValues,
35
+ const {
36
+ ParameterPanel,
37
+ parametersValues,
38
+ panelElements,
39
+ setParametersValues,
40
+ } = useParameterPanel({
41
+ parameters: reportInfo?.reportParameters || [],
42
+ initialParameterValues: { ...props?.reportParametersValues },
69
43
  });
70
- const [reportParametersElements, setReportParametersElements] = useState<
71
- Array<FormElementProps>
72
- >([]);
73
- const { t } = useTranslation();
74
-
75
- const getFormElementsFromReportParameters = (
76
- reportParameters: Array<ReportParameter>
77
- ) => {
78
- const formElements: Array<FormElementProps> = [];
79
- for (const reportParameter of reportParameters) {
80
- const formElement: FormElementProps = {
81
- type: "field",
82
- mode: "props",
83
- props: {
84
- fieldLabel: reportParameter?.parameterLabel,
85
- fieldName: reportParameter?.parameterCode,
86
- fieldType: reportParameter?.parameterType,
87
- hidden: reportParameter?.hidden,
88
- formProps: { fieldSize: { lg: 4, md: 6, sm: 12 } },
89
- required: reportParameter?.mandatory,
90
- defaultValue:
91
- reportParametersValues[reportParameter?.parameterCode] ||
92
- reportParameter?.defaultValue,
93
- },
94
- };
95
- formElements.push(formElement);
96
- }
97
- return formElements;
98
- };
99
44
  const loadReportData = async () => {
100
45
  setReportViewerState("LOADING_METADATA");
101
46
  await handleGetRequest({
@@ -104,14 +49,11 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
104
49
  parameters: { reportCode: props.reportCode },
105
50
  successCallBkFn: (response: any) => {
106
51
  setReportInfo(response.data);
107
- setReportParametersElements(
108
- getFormElementsFromReportParameters(response.data.reportParameters)
109
- );
110
52
  if (
111
53
  props?.byPassParameterEntry === true ||
112
54
  response.data.reportParameters.length == 0
113
55
  ) {
114
- runReport(response.data, reportParametersValues);
56
+ runReport(parametersValues);
115
57
  setReportViewerState("WAITING_RESULT");
116
58
  } else {
117
59
  setReportViewerState("WAITING_PARAMETER_INPUT");
@@ -126,9 +68,9 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
126
68
  });
127
69
  };
128
70
 
129
- const runReport = async (reportInfoProp, params) => {
71
+ const runReport = async (params) => {
130
72
  setReportViewerState("WAITING_RESULT");
131
- if (reportInfoProp?.reportType === "Excel") {
73
+ if (reportInfo?.reportType === "Excel") {
132
74
  await handlePostRequest({
133
75
  endPointURI: "api/v1/public/report/run",
134
76
  showMask: true,
@@ -143,7 +85,7 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
143
85
  setExcelReportData(response.data);
144
86
  },
145
87
  });
146
- } else if (reportInfoProp?.reportType) {
88
+ } else if (reportInfo?.reportType) {
147
89
  await HandleDownloadHTTPPostPDF({
148
90
  endPointURI: "api/v1/public/report/run",
149
91
  showMask: true,
@@ -186,7 +128,7 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
186
128
  // Clean up
187
129
  document.body.removeChild(link);
188
130
  window.URL.revokeObjectURL(url);
189
- }
131
+ }
190
132
  },
191
133
  failureCallBkFn: (response) => {
192
134
  setErrorMessage(
@@ -235,14 +177,9 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
235
177
  <>
236
178
  {props?.byPassParameterEntry === true ? (
237
179
  <></>
238
- ) : reportParametersElements.length > 0 ? (
180
+ ) : reportInfo?.reportParameters.length > 0 ? (
239
181
  <IconButton
240
182
  onClick={() => {
241
- setReportParametersElements(
242
- getFormElementsFromReportParameters(
243
- reportInfo.reportParameters
244
- )
245
- );
246
183
  setReportViewerState("WAITING_PARAMETER_INPUT");
247
184
  }}
248
185
  >
@@ -255,7 +192,7 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
255
192
  <FontAwesomeIcon
256
193
  icon="refresh"
257
194
  onClick={() => {
258
- runReport(reportInfo, reportParametersValues);
195
+ runReport(parametersValues);
259
196
  }}
260
197
  />
261
198
  </IconButton>
@@ -279,58 +216,7 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
279
216
  >
280
217
  {reportViewerState === "WAITING_PARAMETER_INPUT" &&
281
218
  reportInfo?.reportType != "Excel" ? (
282
- <Accordion defaultExpanded sx={{ width: "100%" }} expanded={true}>
283
- <AccordionSummary>
284
- <Box
285
- sx={{
286
- display: "flex",
287
- alignItems: "center",
288
- justifyContent: "center",
289
- }}
290
- >
291
- <FontAwesomeIcon
292
- style={{ marginLeft: 5, marginRight: 5 }}
293
- icon="search"
294
- />
295
- <Typography component="span">Filters</Typography>
296
- </Box>
297
- </AccordionSummary>
298
- <AccordionDetails>
299
- <Box>
300
- <TemplateForm
301
- saveButtonSpecs={{
302
- label: t("SHOW_REPORT_BTN_LABEL"),
303
- icon: "search",
304
- actionButtonVariant: "outlined",
305
- actionButtonColor: "success",
306
- hidden: true,
307
- }}
308
- cancelButtonSpecs={{
309
- label: t("RESET_BTN_LABEL"),
310
- icon: "eraser",
311
- actionButtonVariant: "outlined",
312
- actionButtonColor: "error",
313
- }}
314
- apiActions={{
315
- deleteRecordById: async () => {
316
- return true;
317
- },
318
- saveRecord: async (params) => {
319
- if (params != undefined) {
320
- setReportParametersValues(params);
321
- } else {
322
- setReportParametersValues({});
323
- }
324
- runReport(reportInfo, params);
325
- },
326
- reloadData: async () => {},
327
- loadRecordById: async () => {},
328
- }}
329
- elements={reportParametersElements}
330
- />
331
- </Box>
332
- </AccordionDetails>
333
- </Accordion>
219
+ <ParameterPanel searchBtnClickCallBk={runReport} />
334
220
  ) : reportViewerState === "SHOWING_RESULT" ||
335
221
  ((reportViewerState === "WAITING_PARAMETER_INPUT" ||
336
222
  reportViewerState === "WAITING_RESULT") &&
@@ -340,11 +226,11 @@ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
340
226
  reportData={excelReportData}
341
227
  setReportData={setExcelReportData}
342
228
  reloadReport={async () => {
343
- runReport(reportInfo, reportParametersValues);
229
+ runReport(parametersValues);
344
230
  }}
345
- gridLoadParameters={reportParametersElements}
346
- gridLoadParametersValues={reportParametersValues}
347
- setGridLoadParametersValues={setReportParametersValues}
231
+ gridLoadParameters={panelElements}
232
+ gridLoadParametersValues={parametersValues}
233
+ setGridLoadParametersValues={setParametersValues}
348
234
  />
349
235
  ) : (
350
236
  <iframe
@@ -4,6 +4,7 @@ import { useAxios } from "../../../hooks";
4
4
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
5
  import WidgetViewer, { Widget } from "./WidgetViewer";
6
6
  import { useNavigate } from "react-router-dom";
7
+ import { useParameterPanel } from "../../../hooks/useParameterPanel";
7
8
 
8
9
  type DashboardViewerProps = {
9
10
  dashboardCode: string;
@@ -43,9 +44,40 @@ const DashboardViewer: React.FC<DashboardViewerProps> = (props) => {
43
44
  dashboardParameters: [],
44
45
  widgets: [],
45
46
  });
46
- const [dashboardParameterValues, setDashboardParameterValues] = useState<{
47
- [key: string]: any;
48
- }>(props?.parameters || {});
47
+ const { ParameterPanel, parametersValues } = useParameterPanel({
48
+ parameters: dashboardInfo?.dashboardParameters || [],
49
+ initialParameterValues: {},
50
+ });
51
+ const [loadCounter, setLoadCounter] = useState(0);
52
+ const [loadDashboard, setLoadDashboard] = useState<boolean>(false);
53
+ useEffect(() => {
54
+ if (
55
+ dashboardInfo.dashboardCode != undefined &&
56
+ dashboardInfo.dashboardCode != null &&
57
+ dashboardInfo.dashboardCode != ""
58
+ ) {
59
+ setLoadDashboard(false);
60
+ let shouldLoadWidgets = true;
61
+ if (dashboardInfo?.dashboardParameters.length > 0) {
62
+ for (const parameter of dashboardInfo?.dashboardParameters) {
63
+ if (parameter?.mandatory === true) {
64
+ if (
65
+ parametersValues[parameter.parameterCode] === undefined ||
66
+ parametersValues[parameter.parameterCode] === null ||
67
+ parametersValues[parameter.parameterCode] === ""
68
+ ) {
69
+ shouldLoadWidgets = false;
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ if (shouldLoadWidgets) {
76
+ setLoadDashboard(shouldLoadWidgets);
77
+ }
78
+ setLoadCounter(loadCounter + 1);
79
+ }
80
+ }, [dashboardInfo?.dashboardParameters, parametersValues]);
49
81
  const navigate = useNavigate();
50
82
  const { handleGetRequest, handlePostRequest } = useAxios();
51
83
  const loadDashboardInfo = async () => {
@@ -96,11 +128,19 @@ const DashboardViewer: React.FC<DashboardViewerProps> = (props) => {
96
128
  <Box>{dashboardInfo?.dashboardTitle}</Box>
97
129
  <Box sx={{ flex: 1 }}></Box>
98
130
  </Box>
131
+ {dashboardInfo?.dashboardParameters.length > 0 ? (
132
+ <ParameterPanel searchBtnClickCallBk={async (params) => {
133
+ setLoadCounter(loadCounter + 1);
134
+ }} />
135
+ ) : (
136
+ <></>
137
+ )}
99
138
  <Grid2
100
139
  container
101
140
  spacing={1}
102
141
  sx={{
103
- flexGrow: 1,
142
+ // flexGrow: 1,
143
+ height: "fit-content",
104
144
  overflowY: "auto",
105
145
  padding: 1,
106
146
  }}
@@ -121,7 +161,11 @@ const DashboardViewer: React.FC<DashboardViewerProps> = (props) => {
121
161
  }}
122
162
  size={{ md: widget?.width, sm: 12 }}
123
163
  >
124
- <WidgetViewer {...widget} />
164
+ <WidgetViewer
165
+ {...widget}
166
+ parameterValues={parametersValues}
167
+ loadWidget={loadDashboard}
168
+ />
125
169
  </Grid2>
126
170
  );
127
171
  })}
@@ -14,6 +14,8 @@ import TemplateGauge from "./charts/TemplateGauge";
14
14
  import TemplateLineProgress from "./charts/TemplateLineProgress";
15
15
 
16
16
  export type Widget = {
17
+ loadWidget: boolean;
18
+ loadCounter: number;
17
19
  widgetName: string;
18
20
  widgetDescription: string;
19
21
  title: string;
@@ -51,26 +53,32 @@ const WidgetViewer: React.FC<Widget> = (props) => {
51
53
  },
52
54
  failureCallBkFn: () => {
53
55
  setWidgetLoading(false);
54
- setData(null);
56
+ setData([]);
55
57
  },
56
58
  });
57
59
  };
58
60
  useEffect(() => {
59
- getWidgetData();
60
- }, [props.parameterValues]);
61
+ if (props.loadWidget) {
62
+ getWidgetData();
63
+ } else {
64
+ setWidgetLoading(false);
65
+ }
66
+ }, [props.loadWidget, props.loadCounter]);
61
67
 
62
68
  let total = 0;
63
69
  if (data.length == 1) {
64
70
  total = 100;
65
- }
66
- if (
67
- props.widgetType === "CircularProgress" ||
68
- props.widgetType === "LinearProgress"
69
- ) {
70
- for (const record of data) {
71
- total += record[props.verticalAxisField];
71
+ } else {
72
+ if (
73
+ props.widgetType === "CircularProgress" ||
74
+ props.widgetType === "LinearProgress"
75
+ ) {
76
+ for (const record of data) {
77
+ total += record[props.verticalAxisField];
78
+ }
72
79
  }
73
80
  }
81
+
74
82
  return (
75
83
  <>
76
84
  {props.widgetType === "LineChart" ||
@@ -90,10 +98,12 @@ const WidgetViewer: React.FC<Widget> = (props) => {
90
98
  <Box
91
99
  sx={{
92
100
  flex: 1,
101
+ padding: 1,
102
+ height: "90%",
93
103
  display: "flex",
94
104
  alignItems: "center",
95
105
  justifyContent: "center",
96
- width: "100%",
106
+ width: "90%",
97
107
  }}
98
108
  >
99
109
  {isWidgetLoading ? (
@@ -130,7 +140,7 @@ const WidgetViewer: React.FC<Widget> = (props) => {
130
140
  widgetTitle={props.title}
131
141
  labelField={props.horizontalAxisField}
132
142
  valueField={props.verticalAxisField}
133
- widgetType="Line"
143
+ widgetType="Pie"
134
144
  />
135
145
  ) : (
136
146
  <Grid2
@@ -155,8 +165,8 @@ const WidgetViewer: React.FC<Widget> = (props) => {
155
165
  key={index}
156
166
  widgetTitle={""}
157
167
  record={record}
158
- labelField={props.verticalAxisField}
159
- valueField={props.horizontalAxisField}
168
+ labelField={props.horizontalAxisField}
169
+ valueField={props.verticalAxisField}
160
170
  />
161
171
  </Grid2>
162
172
  );
@@ -0,0 +1,134 @@
1
+ import { useState } from "react";
2
+ import { FormElementProps, TemplateGrid } from "../components";
3
+ import { useApiActions } from "../hooks";
4
+
5
+ const ExampleGrid: React.FC = () => {
6
+ const [data, setData] = useState([]);
7
+ const options = [
8
+ { value: 1, display: "Male" },
9
+ { value: 2, display: "Female" },
10
+ ];
11
+ const apiActions = useApiActions({
12
+ findAll: undefined,
13
+ commonStoreKey: undefined,
14
+ deleteById: undefined,
15
+ deleteByIdParamName: undefined,
16
+ findById: undefined,
17
+ findByIdParamName: undefined,
18
+ save: undefined,
19
+ setData: setData,
20
+ });
21
+ const elements: FormElementProps[] = [
22
+ {
23
+ mode: "props",
24
+ props: { fieldLabel: "ID", fieldName: "id", fieldType: "number" },
25
+ type: "field",
26
+ },
27
+ {
28
+ mode: "props",
29
+ props: {
30
+ fieldLabel: "Gender",
31
+ fieldName: "gender",
32
+ fieldType: "combobox",
33
+ options,
34
+ optionValueField: "value",
35
+ optionDisplayField: "display",
36
+ formProps: {
37
+ onValueChangeCallBack(
38
+ formValues,
39
+ value,
40
+ formManager,
41
+ formActions,
42
+ selectedRecord
43
+ ) {
44
+ if (value == 1) {
45
+ formActions.disableField("bithdate");
46
+ formManager.setValue("bithdate", new Date());
47
+ formManager.setValue("active", true);
48
+ formManager.setValue("type", value);
49
+ } else {
50
+ formActions.enableField("bithdate");
51
+ formManager.setValue("bithdate", null);
52
+ formManager.setValue("active", false);
53
+ }
54
+ formManager.setValue("type", value);
55
+ },
56
+ },
57
+ },
58
+ type: "field",
59
+ },
60
+ {
61
+ mode: "props",
62
+ props: {
63
+ fieldLabel: "Gender",
64
+ fieldName: "type",
65
+ fieldType: "combobox",
66
+ options,
67
+ optionValueField: "value",
68
+ optionDisplayField: "display",
69
+ },
70
+ type: "field",
71
+ },
72
+ {
73
+ mode: "props",
74
+ props: {
75
+ fieldLabel: "Name",
76
+ fieldName: "name",
77
+ required: true,
78
+ fieldType: "text",
79
+ gridProps: { hidden: false },
80
+ formProps: {
81
+ onValueChangeCallBack(
82
+ formValues,
83
+ value,
84
+ formManager,
85
+ formActions,
86
+ selectedRecord
87
+ ) {},
88
+ },
89
+ },
90
+ type: "field",
91
+ },
92
+ {
93
+ mode: "props",
94
+ props: {
95
+ fieldLabel: "Birthdate",
96
+ fieldName: "bithdate",
97
+ required: true,
98
+ fieldType: "date",
99
+ gridProps: { hidden: false },
100
+ },
101
+ type: "field",
102
+ },
103
+ {
104
+ mode: "props",
105
+ props: {
106
+ fieldLabel: "Active",
107
+ fieldName: "active",
108
+ required: true,
109
+ fieldType: "checkbox",
110
+ gridProps: { hidden: false },
111
+ },
112
+ type: "field",
113
+ },
114
+ ];
115
+ return (
116
+ <TemplateGrid
117
+ apiActions={apiActions}
118
+ data={data}
119
+ setData={setData}
120
+ editMode={{
121
+ editMode: "modal",
122
+ specs: {
123
+ modalTitle: "Example Modal Form",
124
+ modalIcon: "user",
125
+ },
126
+ }}
127
+ formElements={elements}
128
+ girdIcon={"user"}
129
+ gridTitle="Example Grid "
130
+ />
131
+ );
132
+ };
133
+
134
+ export default ExampleGrid;