@asaleh37/ui-base 1.2.3 → 1.2.5

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 (157) hide show
  1. package/dist/index.d.ts +20 -13
  2. package/dist/index.js +6 -6
  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 +15 -3
  7. package/src/components/App.tsx +1 -1
  8. package/src/components/BaseApp.tsx +2 -19
  9. package/src/components/administration/admin/OrgMemberRoleForm.tsx +83 -0
  10. package/src/components/administration/admin/OrganizationApplicationModuleGrid.tsx +131 -0
  11. package/src/components/administration/admin/OrganizationGrid.tsx +165 -0
  12. package/src/components/administration/admin/OrganizationMemberGrid.tsx +176 -0
  13. package/src/components/administration/admin/OrganizationMemberRoleGrid.tsx +87 -0
  14. package/src/components/{admin → administration/admin}/OrganizationRankGrid.tsx +49 -19
  15. package/src/components/administration/admin/OrganizationUnitGrid.tsx +139 -0
  16. package/src/components/administration/admin/OrganizationUnitTypeGrid.tsx +121 -0
  17. package/src/components/administration/admin/PersonGrid.tsx +195 -0
  18. package/src/components/{admin → administration/admin}/RoleAuthoritiesForm.tsx +30 -11
  19. package/src/components/administration/admin/SystemApplicationAuthorityGrid.tsx +142 -0
  20. package/src/components/administration/admin/SystemApplicationGrid.tsx +161 -0
  21. package/src/components/administration/admin/SystemApplicationModuleGrid.tsx +109 -0
  22. package/src/components/administration/admin/SystemApplicationRoleAuthorityGrid.tsx +67 -0
  23. package/src/components/administration/admin/SystemApplicationRoleGrid.tsx +130 -0
  24. package/src/components/administration/dev/BluePrintGrid.tsx +129 -0
  25. package/src/components/administration/dev/DashboardGrid.tsx +173 -0
  26. package/src/components/administration/dev/DashboardWidgetGrid.tsx +164 -0
  27. package/src/components/administration/dev/DataQueryGrid.tsx +206 -0
  28. package/src/components/administration/dev/DataQueryParameterGrid.tsx +191 -0
  29. package/src/components/administration/dev/DataQueryParametersForm.tsx +84 -0
  30. package/src/components/administration/dev/DatasourceConnectionGrid.tsx +150 -0
  31. package/src/components/administration/dev/EntityParameterGrid.tsx +279 -0
  32. package/src/components/administration/dev/LookupGrid.tsx +131 -0
  33. package/src/components/administration/dev/MailAttachmentGrid.tsx +155 -0
  34. package/src/components/administration/dev/MailBodyGrid.tsx +215 -0
  35. package/src/components/{admin → administration/dev}/MailNotificationQueueGrid.tsx +114 -26
  36. package/src/components/administration/dev/MailRecipientGrid.tsx +169 -0
  37. package/src/components/administration/dev/MailSenderConfigGrid.tsx +478 -0
  38. package/src/components/administration/dev/MailTemplateGrid.tsx +388 -0
  39. package/src/components/administration/dev/ReportGrid.tsx +504 -0
  40. package/src/components/administration/dev/ReportParameterGrid.tsx +186 -0
  41. package/src/components/administration/dev/ReportParametersForm.tsx +84 -0
  42. package/src/components/administration/dev/WidgetGrid.tsx +431 -0
  43. package/src/components/administration/dev/WorkflowDocumentActionGrid.tsx +264 -0
  44. package/src/components/administration/dev/WorkflowDocumentActionHistoryGrid.tsx +172 -0
  45. package/src/components/administration/dev/WorkflowDocumentActionMailGrid.tsx +161 -0
  46. package/src/components/administration/dev/WorkflowDocumentGrid.tsx +377 -0
  47. package/src/components/{admin → administration/dev}/WorkflowDocumentMailLogGrid.tsx +87 -10
  48. package/src/components/administration/dev/WorkflowDocumentStatusGrid.tsx +243 -0
  49. package/src/components/common/ChangeOrgForm.tsx +81 -0
  50. package/src/components/common/Home.tsx +28 -22
  51. package/src/components/common/LoadingMask.tsx +9 -4
  52. package/src/components/common/Login.tsx +9 -13
  53. package/src/components/templates/DataEntryTemplates/DataEntryTypes.ts +30 -6
  54. package/src/components/templates/DataEntryTemplates/DataEntryUtil.ts +46 -5
  55. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementField.tsx +64 -5
  56. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementGroup.tsx +11 -3
  57. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/CheckBox.tsx +2 -2
  58. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/ComboBox.tsx +1 -2
  59. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/HtmlEditor.tsx +144 -0
  60. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/SystemLookupCombobox.tsx +55 -0
  61. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/TemplateTextField.tsx +9 -1
  62. package/src/components/templates/DataEntryTemplates/TemplateDataForm/TemplateForm.tsx +45 -5
  63. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/DataGridColumnsUtil.tsx +8 -7
  64. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGrid.tsx +38 -10
  65. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridRecordAction.tsx +4 -1
  66. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridTopBar.tsx +3 -4
  67. package/src/components/templates/TransferList.tsx +16 -6
  68. package/src/components/templates/index.ts +0 -2
  69. package/src/components/templates/report/ExcelReportViewer.tsx +65 -0
  70. package/src/components/templates/report/ReportViewer.tsx +382 -0
  71. package/src/components/templates/visuals/DashboardRouteView.tsx +9 -0
  72. package/src/components/templates/visuals/DashboardViewer.tsx +148 -0
  73. package/src/components/templates/visuals/WidgetViewer.tsx +198 -0
  74. package/src/components/templates/visuals/charts/TemplateBarChart.tsx +9 -2
  75. package/src/components/templates/visuals/charts/TemplateDataCard.tsx +6 -31
  76. package/src/components/templates/visuals/charts/TemplateGauge.tsx +8 -3
  77. package/src/components/templates/visuals/charts/TemplateLineChart.tsx +8 -2
  78. package/src/components/templates/visuals/charts/TemplateLineProgress.tsx +5 -3
  79. package/src/components/templates/visuals/charts/TemplatePieChart.tsx +1 -2
  80. package/src/components/templates/workflow/WorkflowDocumentPanel.tsx +581 -0
  81. package/src/components/templates/workflow/WorkflowDocumentTimeLine.tsx +134 -0
  82. package/src/hooks/UseSession.tsx +3 -7
  83. package/src/hooks/UseWindow.tsx +2 -1
  84. package/src/hooks/useAxios.tsx +9 -27
  85. package/src/hooks/useLookupGridColumn.tsx +35 -0
  86. package/src/layout/Layout.tsx +2 -46
  87. package/src/layout/MainContent.tsx +60 -7
  88. package/src/layout/MobileDrawer.tsx +5 -5
  89. package/src/layout/NavigationTree.tsx +0 -1
  90. package/src/layout/RouteWrapper.tsx +36 -0
  91. package/src/layout/SideBar.tsx +15 -10
  92. package/src/layout/TopBar.tsx +139 -71
  93. package/src/locales/arabic/adminLocalsAr.json +81 -344
  94. package/src/locales/arabic/common.json +11 -1
  95. package/src/locales/arabic/devLocalsAr.json +280 -0
  96. package/src/locales/arabic/index.ts +2 -0
  97. package/src/locales/english/adminLocalsEn.json +86 -346
  98. package/src/locales/english/common.json +11 -1
  99. package/src/locales/english/devLocalsEn.json +281 -0
  100. package/src/locales/english/index.ts +3 -0
  101. package/src/main.tsx +5 -6
  102. package/src/navigationItems/Administration/adminNavigationItems.tsx +65 -99
  103. package/src/navigationItems/Administration/index.tsx +10 -65
  104. package/src/redux/features/administration/AdministrationStoresMetaData.ts +45 -12
  105. package/src/redux/features/common/AppLayoutSlice.ts +0 -8
  106. package/src/redux/features/common/CommonStoreSlice.ts +4 -0
  107. package/src/redux/features/common/SideBarSlice.ts +29 -0
  108. package/src/redux/features/common/UserSessionSlice.ts +15 -23
  109. package/src/redux/store.ts +1 -1
  110. package/src/routes/administration/adminRoutes.tsx +41 -222
  111. package/src/routes/administration/devRoutes.tsx +90 -0
  112. package/src/routes/administration/index.ts +5 -1
  113. package/src/routes/index.ts +1 -0
  114. package/src/styles/index.css +3 -3
  115. package/src/util/AppUtils.ts +5 -0
  116. package/vite.config.ts +14 -0
  117. package/src/components/admin/AttachmentGrid.tsx +0 -116
  118. package/src/components/admin/AuthorityGrid.tsx +0 -88
  119. package/src/components/admin/BluePrintGrid.tsx +0 -55
  120. package/src/components/admin/BluePrintPageGrid.tsx +0 -85
  121. package/src/components/admin/BluePrintPointGrid.tsx +0 -85
  122. package/src/components/admin/DashboardGrid.tsx +0 -95
  123. package/src/components/admin/DashboardWidgetGrid.tsx +0 -75
  124. package/src/components/admin/DataQueryGrid.tsx +0 -75
  125. package/src/components/admin/DataQueryParameterGrid.tsx +0 -98
  126. package/src/components/admin/DatasourceConnectionGrid.tsx +0 -98
  127. package/src/components/admin/EmployeeGrid.tsx +0 -105
  128. package/src/components/admin/EntityParameterGrid.tsx +0 -125
  129. package/src/components/admin/ExcelUploaderDetailGrid.tsx +0 -78
  130. package/src/components/admin/ExcelUploaderHeaderGrid.tsx +0 -78
  131. package/src/components/admin/LookupGrid.tsx +0 -95
  132. package/src/components/admin/MailAttachmentGrid.tsx +0 -65
  133. package/src/components/admin/MailBodyGrid.tsx +0 -105
  134. package/src/components/admin/MailRecipientGrid.tsx +0 -75
  135. package/src/components/admin/MailTemplateGrid.tsx +0 -145
  136. package/src/components/admin/NewTableGrid.tsx +0 -65
  137. package/src/components/admin/NotificationGrid.tsx +0 -115
  138. package/src/components/admin/NotificationQueueGrid.tsx +0 -125
  139. package/src/components/admin/OrganizationApplicationGrid.tsx +0 -81
  140. package/src/components/admin/OrganizationGrid.tsx +0 -65
  141. package/src/components/admin/OrganizationUnitGrid.tsx +0 -85
  142. package/src/components/admin/OrganizationUserGrid.tsx +0 -75
  143. package/src/components/admin/OrganizationUserRoleGrid.tsx +0 -98
  144. package/src/components/admin/ReportGrid.tsx +0 -155
  145. package/src/components/admin/ReportParameterGrid.tsx +0 -95
  146. package/src/components/admin/RoleAuthorityGrid.tsx +0 -65
  147. package/src/components/admin/RoleGrid.tsx +0 -132
  148. package/src/components/admin/UserAccountGrid.tsx +0 -65
  149. package/src/components/admin/UserRequestGrid.tsx +0 -145
  150. package/src/components/admin/WidgetGrid.tsx +0 -175
  151. package/src/components/admin/WorkflowDocumentActionGrid.tsx +0 -111
  152. package/src/components/admin/WorkflowDocumentActionHistoryGrid.tsx +0 -111
  153. package/src/components/admin/WorkflowDocumentActionMailGrid.tsx +0 -71
  154. package/src/components/admin/WorkflowDocumentGrid.tsx +0 -185
  155. package/src/components/admin/WorkflowDocumentStatusGrid.tsx +0 -121
  156. package/src/components/templates/visuals/TemplateDashboard.tsx +0 -126
  157. package/src/redux/features/CounterSlice.tsx +0 -13
@@ -40,11 +40,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
40
40
  import TemplateGridRecordAction from "./TemplateGridRecordAction";
41
41
  import TemplateForm from "../TemplateDataForm/TemplateForm";
42
42
  import { useSelector } from "react-redux";
43
- import { RootState } from "../../../../redux/store";
44
43
  import { useTranslation } from "react-i18next";
45
44
  import useSession from "../../../../hooks/UseSession";
46
45
  import { useConfirmationWindow } from "../../../../hooks/UseConfirmationWindow";
47
46
  import { useWindow } from "../../../../hooks/UseWindow";
47
+ import { useAxios } from "../../../../hooks";
48
+ import useLookupGridColumn from "../../../../hooks/useLookupGridColumn";
49
+ import { ContinuousColorLegend } from "@mui/x-charts";
48
50
  let currentNewRecordIndex = -1;
49
51
 
50
52
  interface GridState {
@@ -76,6 +78,11 @@ const saveGridState = (gridStateKey: string, statePart: GridState) => {
76
78
  const PIN_FIXED_COLUMNS = ["__check__", "actions"];
77
79
 
78
80
  const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
81
+ const AppLayout = useSelector((state: any) => state.AppLayout);
82
+ const { getLookupOptions } = useLookupGridColumn();
83
+ const [generatedColumns, setGeneratedColumns] = useState<
84
+ Array<TemplateGridColDef>
85
+ >([]);
79
86
  const { t } = useTranslation();
80
87
  const fields = getAllFields(props.formElements);
81
88
  const hiddenFields = [];
@@ -104,7 +111,7 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
104
111
  }
105
112
 
106
113
  const themeDirection = useSelector(
107
- (state: RootState) => state.AppLayout.appDirection
114
+ (state: any) => state.AppLayout.appDirection
108
115
  );
109
116
 
110
117
  const clearGridState = () => {
@@ -152,7 +159,24 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
152
159
  const [recordToDelete, setRecordToDelete] = useState<any>(null);
153
160
  const [recordToEdit, setRecordToEdit] = useState<any>(null);
154
161
  const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
155
-
162
+ const adjustGridColumns = async () => {
163
+ let gridColumns = constructGridColumnsFromFields(
164
+ fields,
165
+ props?.editMode?.editMode === "row" || false,
166
+ t
167
+ );
168
+ for (let gridColumn of gridColumns) {
169
+ if (gridColumn?.lookupType) {
170
+ gridColumn.displayField =
171
+ AppLayout.appDirection === "ltr"
172
+ ? "lookupEnDisplay"
173
+ : "lookupArDisplay";
174
+ gridColumn.options = await getLookupOptions(gridColumn.lookupType);
175
+ gridColumn.valueField = "lookupValue";
176
+ }
177
+ }
178
+ setGeneratedColumns(gridColumns);
179
+ };
156
180
  const [rowSelectionModel, setRowSelectionModel] =
157
181
  useState<GridRowSelectionModel>({ ids: new Set(), type: "include" });
158
182
  let keyColumnName: string = "id";
@@ -161,11 +185,6 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
161
185
  }
162
186
  const setData = props.setData;
163
187
  const validationSchema = z.object(constructValidationSchema(fields));
164
- const generatedColumns = constructGridColumnsFromFields(
165
- fields,
166
- props?.editMode?.editMode === "row" || false,
167
- t
168
- );
169
188
  let isEditAllowed = true;
170
189
  if (props?.editAction?.authority) {
171
190
  isEditAllowed = session.isUserAuthorized(props.editAction.authority);
@@ -265,6 +284,7 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
265
284
  if (props?.editMode?.editMode === "form") {
266
285
  navigate(props.editMode.specs.formRoute);
267
286
  } else if (props?.editMode?.editMode === "modal") {
287
+ setRecordToEdit(null);
268
288
  setFormWindowState(true);
269
289
  } else if (props?.editMode?.editMode === "row") {
270
290
  currentNewRecordIndex = currentNewRecordIndex - 1;
@@ -591,8 +611,13 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
591
611
  if (props?.autoLoad === undefined || props.autoLoad === true) {
592
612
  props.apiActions.reloadData(props?.gridLoadParametersValues);
593
613
  }
614
+ adjustGridColumns();
594
615
  }, []);
595
616
 
617
+ useEffect(() => {
618
+ adjustGridColumns();
619
+ }, [themeDirection, props.formElements]);
620
+
596
621
  const handleColumnVisibilityChange = (model: GridColumnVisibilityModel) => {
597
622
  setColumnVisibilityModel(model);
598
623
  if (props?.gridStateKey) {
@@ -673,6 +698,7 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
673
698
  />
674
699
  ) : (
675
700
  <TemplateForm
701
+ formLoadCallBk={props.formLoadCallBk}
676
702
  recordIdToEdit={
677
703
  recordToEdit ? recordToEdit[keyColumnName] : undefined
678
704
  }
@@ -699,7 +725,7 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
699
725
  {props?.hideBackButton === undefined && !props?.hideBackButton ? (
700
726
  <IconButton
701
727
  onClick={() => {
702
- navigate("-1", { replace: true });
728
+ navigate(-1, { replace: true });
703
729
  }}
704
730
  >
705
731
  <FontAwesomeIcon icon="arrow-left" />
@@ -735,9 +761,10 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
735
761
  )}
736
762
 
737
763
  {props?.gridLoadParameters &&
764
+ props?.gridLoadParameters.length > 0 &&
738
765
  props?.gridLoadParametersValues &&
739
766
  props?.setGridLoadParametersValues ? (
740
- <Accordion defaultExpanded>
767
+ <Accordion defaultExpanded sx={{ width: "100%" }}>
741
768
  <AccordionSummary expandIcon={<GridExpandMoreIcon />}>
742
769
  <Box
743
770
  sx={{
@@ -836,6 +863,7 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
836
863
  }}
837
864
  pinnedColumns={pinnedColumns}
838
865
  onPinnedColumnsChange={handlePinnedColumnsChange}
866
+ sx={{ width: "100%" }}
839
867
  />
840
868
  </>
841
869
  );
@@ -77,7 +77,10 @@ const TemplateGridRecordAction: React.FC<RecordAction> = (
77
77
  setOpen(true);
78
78
  } else {
79
79
  await rowAction.actionFn(rowAction.record);
80
- if (rowAction?.reloadData) {
80
+ if (
81
+ rowAction?.gridActionProps?.reloadGridAfterAction === true &&
82
+ rowAction?.reloadData
83
+ ) {
81
84
  rowAction.reloadData();
82
85
  }
83
86
  }
@@ -94,10 +94,11 @@ const TemplateGridTopBar: React.FC<TemplateGridTopBarProps> = (
94
94
  <></>
95
95
  )}
96
96
  {props?.templateProps?.rowActions ? (
97
- props.templateProps.rowActions.map((rowAction) =>
97
+ props.templateProps.rowActions.map((rowAction, index) =>
98
98
  rowAction?.gridActionProps?.multiRecord === true ? (
99
99
  <TemplateGridMultiRecordAction
100
100
  {...rowAction}
101
+ key={index}
101
102
  reloadData={async () => {
102
103
  props.templateProps.apiActions.reloadData(
103
104
  props?.templateProps?.gridLoadParametersValues
@@ -106,9 +107,7 @@ const TemplateGridTopBar: React.FC<TemplateGridTopBarProps> = (
106
107
  recordIdsToProcessActionOn={gridSelection.selectedRecordIds}
107
108
  recordsToProcessActionOn={gridSelection.selectedRecords}
108
109
  />
109
- ) : (
110
- <></>
111
- )
110
+ ) : null
112
111
  )
113
112
  ) : (
114
113
  <></>
@@ -2,7 +2,6 @@ import * as React from "react";
2
2
  import List from "@mui/material/List";
3
3
  import Card from "@mui/material/Card";
4
4
  import CardHeader from "@mui/material/CardHeader";
5
- import ListItem from "@mui/material/ListItem";
6
5
  import ListItemText from "@mui/material/ListItemText";
7
6
  import ListItemIcon from "@mui/material/ListItemIcon";
8
7
  import Checkbox from "@mui/material/Checkbox";
@@ -39,15 +38,25 @@ const TransferList: React.FC<TransferListProps> = ({
39
38
  setSelection,
40
39
  }) => {
41
40
  const [checked, setChecked] = React.useState([]);
42
- const [left, setLeft] = React.useState(options);
43
- const [right, setRight] = React.useState(selectedOptions);
44
-
41
+ const [left, setLeft] = React.useState<Array<any>>([]);
42
+ const [right, setRight] = React.useState<Array<any>>([]);
45
43
  const [leftFilterValue, setLeftFilterValue] = React.useState<string>("");
46
44
  const [rightFilterValue, setRightFilterValue] = React.useState<string>("");
47
45
 
48
46
  const leftChecked = intersection(checked, left);
49
47
  const rightChecked = intersection(checked, right);
50
48
 
49
+ React.useEffect(() => {
50
+ if (options) {
51
+ setLeft([...options]);
52
+ }
53
+ }, [options]);
54
+ React.useEffect(() => {
55
+ if (selectedOptions) {
56
+ setRight([...selectedOptions]);
57
+ }
58
+ }, [selectedOptions]);
59
+
51
60
  const handleToggle = (value) => () => {
52
61
  const currentIndex = checked.indexOf(value);
53
62
  const newChecked = [...checked];
@@ -95,8 +104,9 @@ const TransferList: React.FC<TransferListProps> = ({
95
104
  title: string,
96
105
  unfilteredItems: Array<any>,
97
106
  side: "left" | "right"
98
- ) => {
107
+ ) => {
99
108
  const items = unfilteredItems.filter((option: any) => {
109
+
100
110
  if (option[displayField]) {
101
111
  const value: string = option[displayField];
102
112
  if (
@@ -176,7 +186,7 @@ const TransferList: React.FC<TransferListProps> = ({
176
186
  key={value[valueField]}
177
187
  role="listitem"
178
188
  onClick={handleToggle(value)}
179
- sx={{ cursor: "pointer" }}
189
+ sx={{ cursor: "pointer" }}
180
190
  >
181
191
  <ListItemIcon>
182
192
  <Checkbox
@@ -1,5 +1,4 @@
1
1
  export { default as TransferList } from "./TransferList";
2
- export { default as TemplateDashboard } from "./visuals/TemplateDashboard";
3
2
  export { default as TemplateBarChart } from "./visuals/charts/TemplateBarChart";
4
3
  export { default as TemplateDataCard } from "./visuals/charts/TemplateDataCard";
5
4
  export { default as TemplateGauge } from "./visuals/charts/TemplateGauge";
@@ -15,5 +14,4 @@ export { default as TemplateForm } from "./DataEntryTemplates/TemplateDataForm/T
15
14
  export { default as TemplateGrid } from "./DataEntryTemplates/TemplateDataGrid/TemplateGrid";
16
15
 
17
16
  export type * from "./DataEntryTemplates/DataEntryTypes";
18
- export type { DashboardProps } from "./visuals/TemplateDashboard";
19
17
  export type { TransferListProps } from "./TransferList";
@@ -0,0 +1,65 @@
1
+ import { useEffect, useState } from "react";
2
+ import TemplateGrid from "../DataEntryTemplates/TemplateDataGrid/TemplateGrid";
3
+ import { FormElementProps } from "../DataEntryTemplates/DataEntryTypes";
4
+
5
+ type ExcelReportViewerProps = {
6
+ reportData: Array<any>;
7
+ setReportData: (data) => void;
8
+ reloadReport: () => void;
9
+ gridLoadParameters?: Array<FormElementProps>;
10
+ gridLoadParametersValues?: { [key: string]: any };
11
+ setGridLoadParametersValues?: any;
12
+ };
13
+
14
+ const getGridColumnsFromRecord = (data: Array<any>) => {
15
+ if (data.length === 0) {
16
+ return [];
17
+ }
18
+ const formElements: Array<FormElementProps> = [];
19
+ for (const key of Object.keys(data[0])) {
20
+ const formElement: FormElementProps = {
21
+ type: "field",
22
+ mode: "props",
23
+ props: {
24
+ fieldLabel: key,
25
+ fieldName: key,
26
+ fieldType: "text",
27
+ },
28
+ };
29
+ formElements.push(formElement);
30
+ }
31
+ console.log("formElements", formElements);
32
+ return formElements;
33
+ };
34
+
35
+ const ExcelReportViewer: React.FC<ExcelReportViewerProps> = (props) => {
36
+ console.log("reportdata", props.reportData);
37
+ return (
38
+ <TemplateGrid
39
+ data={props.reportData}
40
+ disableDefaultAction={true}
41
+ setData={props.setReportData}
42
+ formElements={getGridColumnsFromRecord(props.reportData)}
43
+ gridLoadParameters={props.gridLoadParameters}
44
+ gridLoadParametersValues={props.gridLoadParametersValues}
45
+ setGridLoadParametersValues={props.setGridLoadParametersValues}
46
+ editMode={{ editMode: "none" }}
47
+ girdIcon={"file-excel"}
48
+ gridTitle="Report"
49
+ autoLoad={true}
50
+ hideInfoBar={true}
51
+ apiActions={{
52
+ deleteRecordById: async () => {
53
+ return true;
54
+ },
55
+ loadRecordById: async () => {},
56
+ reloadData: async () => {
57
+ props.reloadReport();
58
+ },
59
+ saveRecord: async () => {},
60
+ }}
61
+ />
62
+ );
63
+ };
64
+
65
+ export default ExcelReportViewer;
@@ -0,0 +1,382 @@
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";
15
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
16
+ import ExcelReportViewer from "./ExcelReportViewer";
17
+ import { GridExpandMoreIcon } from "@mui/x-data-grid-premium";
18
+
19
+ type ReportViewerState =
20
+ | "ERROR"
21
+ | "WAITING_REPORT_CODE"
22
+ | "LOADING_METADATA"
23
+ | "WAITING_PARAMETER_INPUT"
24
+ | "WAITING_RESULT"
25
+ | "SHOWING_RESULT";
26
+
27
+ type ReportViewerProps = {
28
+ reportCode: string;
29
+ resultMode: "Request" | "App";
30
+ reportParametersValues?: { [key: string]: any };
31
+ byPassParameterEntry?: boolean;
32
+ jasperOutPutFileType?: "pdf" | "word" | "excel";
33
+ };
34
+
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
+ const ReportViewer: React.FC<ReportViewerProps> = (props) => {
58
+ const [blobUrl, setBlobUrl] = useState(null);
59
+ const [errorMessage, setErrorMessage] = useState(null);
60
+ const [excelReportData, setExcelReportData] = useState<Array<any>>([]);
61
+ const [reportViewerState, setReportViewerState] = useState<ReportViewerState>(
62
+ "WAITING_REPORT_CODE"
63
+ );
64
+ const { handleGetRequest, handlePostRequest, HandleDownloadHTTPPostPDF } =
65
+ useAxios();
66
+ const [reportInfo, setReportInfo] = useState<any>(null);
67
+ const [reportParametersValues, setReportParametersValues] = useState<any>({
68
+ ...props?.reportParametersValues,
69
+ });
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
+ const loadReportData = async () => {
100
+ setReportViewerState("LOADING_METADATA");
101
+ await handleGetRequest({
102
+ endPointURI: "api/v1/dev/report/metadata",
103
+ showMask: true,
104
+ parameters: { reportCode: props.reportCode },
105
+ successCallBkFn: (response: any) => {
106
+ setReportInfo(response.data);
107
+ setReportParametersElements(
108
+ getFormElementsFromReportParameters(response.data.reportParameters)
109
+ );
110
+ if (
111
+ props?.byPassParameterEntry === true ||
112
+ response.data.reportParameters.length == 0
113
+ ) {
114
+ runReport(response.data, reportParametersValues);
115
+ setReportViewerState("WAITING_RESULT");
116
+ } else {
117
+ setReportViewerState("WAITING_PARAMETER_INPUT");
118
+ }
119
+ },
120
+ failureCallBkFn: (response) => {
121
+ setErrorMessage(
122
+ "Failed loading report metadata ... contact your administrator"
123
+ );
124
+ setReportViewerState("ERROR");
125
+ },
126
+ });
127
+ };
128
+
129
+ const runReport = async (reportInfoProp, params) => {
130
+ setReportViewerState("WAITING_RESULT");
131
+ if (reportInfoProp?.reportType === "Excel") {
132
+ await handlePostRequest({
133
+ endPointURI: "api/v1/dev/report/run",
134
+ showMask: true,
135
+ data: {
136
+ reportCode: props.reportCode,
137
+ parameters: params,
138
+ resultMode: props.resultMode,
139
+ jasperOutPutFileType: props.jasperOutPutFileType,
140
+ },
141
+ successCallBkFn: (response: any) => {
142
+ setReportViewerState("SHOWING_RESULT");
143
+ setExcelReportData(response.data);
144
+ },
145
+ });
146
+ } else if (reportInfoProp?.reportType) {
147
+ await HandleDownloadHTTPPostPDF({
148
+ endPointURI: "api/v1/dev/report/run",
149
+ showMask: true,
150
+ data: {
151
+ reportCode: props.reportCode,
152
+ parameters: params,
153
+ resultMode: props.resultMode,
154
+ jasperOutPutFileType: props.jasperOutPutFileType,
155
+ },
156
+ successCallBkFn: (response: any) => {
157
+ setReportViewerState("SHOWING_RESULT");
158
+ const contentDisposition = response.headers["content-disposition"];
159
+ let filename = "downloaded_file";
160
+ if (
161
+ contentDisposition &&
162
+ contentDisposition.indexOf("filename=") !== -1
163
+ ) {
164
+ const match = contentDisposition.match(/filename="?([^"]+)"?/);
165
+ if (match && match[1]) filename = match[1];
166
+ }
167
+ if (filename.includes("pdf")) {
168
+ const file = new Blob([response.data], { type: "application/pdf" });
169
+ const url = URL.createObjectURL(file);
170
+ setBlobUrl(url);
171
+ } else {
172
+ const blob = new Blob([response.data], {
173
+ type: response.headers["content-type"],
174
+ });
175
+ // Create a temporary anchor element
176
+ const url = window.URL.createObjectURL(blob);
177
+ const link = document.createElement("a");
178
+ link.href = url;
179
+ // Optional: Try to get filename from response headers
180
+
181
+ link.download = filename;
182
+ document.body.appendChild(link);
183
+ link.click();
184
+
185
+ // Clean up
186
+ document.body.removeChild(link);
187
+ window.URL.revokeObjectURL(url);
188
+ }
189
+ console.log(response);
190
+ },
191
+ failureCallBkFn: (response) => {
192
+ setErrorMessage(
193
+ "Failed To run report ... contact your administrator"
194
+ );
195
+ setReportViewerState("ERROR");
196
+ },
197
+ });
198
+ }
199
+ };
200
+
201
+ useEffect(() => {
202
+ if (props?.reportCode) {
203
+ loadReportData();
204
+ }
205
+ }, [
206
+ props.reportCode,
207
+ props.byPassParameterEntry,
208
+ props.reportParametersValues,
209
+ props.jasperOutPutFileType,
210
+ props.resultMode,
211
+ ]);
212
+
213
+ return (
214
+ <>
215
+ <Box
216
+ sx={{
217
+ display: "flex",
218
+ alignItems: "center",
219
+ justifyContent: "center",
220
+ width: "100%",
221
+ }}
222
+ >
223
+ <Box sx={{ flex: 1, textAlign: "center", marginBottom: 1 }}>
224
+ <FontAwesomeIcon
225
+ icon={
226
+ reportInfo?.reportType === "Excel" ? "file-excel" : "file-pdf"
227
+ }
228
+ color={reportInfo?.reportType === "Excel" ? "darkgreen" : "darkred"}
229
+ style={{ marginRight: 10, marginLeft: 10 }}
230
+ />
231
+ {reportInfo?.reportName}
232
+ </Box>
233
+ {reportInfo?.reportType != "Excel" ? (
234
+ reportViewerState === "SHOWING_RESULT" ? (
235
+ <>
236
+ {props?.byPassParameterEntry === true ? (
237
+ <></>
238
+ ) : reportParametersElements.length > 0 ? (
239
+ <IconButton
240
+ onClick={() => {
241
+ setReportParametersElements(
242
+ getFormElementsFromReportParameters(
243
+ reportInfo.reportParameters
244
+ )
245
+ );
246
+ setReportViewerState("WAITING_PARAMETER_INPUT");
247
+ }}
248
+ >
249
+ <FontAwesomeIcon icon="filter" />
250
+ </IconButton>
251
+ ) : (
252
+ <></>
253
+ )}
254
+ <IconButton>
255
+ <FontAwesomeIcon
256
+ icon="refresh"
257
+ onClick={() => {
258
+ runReport(reportInfo, reportParametersValues);
259
+ }}
260
+ />
261
+ </IconButton>
262
+ </>
263
+ ) : (
264
+ <></>
265
+ )
266
+ ) : (
267
+ <></>
268
+ )}
269
+ </Box>
270
+ <Box
271
+ sx={{
272
+ flexGrow: 1,
273
+ width: "100%",
274
+ display: "flex",
275
+ flexDirection: "column",
276
+ alignItems: "center",
277
+ justifyContent: "flex-start",
278
+ }}
279
+ >
280
+ {reportViewerState === "WAITING_PARAMETER_INPUT" &&
281
+ 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>
334
+ ) : reportViewerState === "SHOWING_RESULT" ||
335
+ ((reportViewerState === "WAITING_PARAMETER_INPUT" ||
336
+ reportViewerState === "WAITING_RESULT") &&
337
+ reportInfo?.reportType === "Excel") ? (
338
+ reportInfo?.reportType === "Excel" ? (
339
+ <ExcelReportViewer
340
+ reportData={excelReportData}
341
+ setReportData={setExcelReportData}
342
+ reloadReport={async () => {
343
+ runReport(reportInfo, reportParametersValues);
344
+ }}
345
+ gridLoadParameters={reportParametersElements}
346
+ gridLoadParametersValues={reportParametersValues}
347
+ setGridLoadParametersValues={setReportParametersValues}
348
+ />
349
+ ) : (
350
+ <iframe
351
+ src={blobUrl}
352
+ width="100%"
353
+ height="100%"
354
+ title="PDF Preview"
355
+ style={{ border: "1px solid #ccc", marginTop: "20px" }}
356
+ ></iframe>
357
+ )
358
+ ) : reportViewerState === "ERROR" ? (
359
+ <Box
360
+ sx={{
361
+ display: "flex",
362
+ flex: 1,
363
+ alignItems: "center",
364
+ justifyContent: "center",
365
+ }}
366
+ >
367
+ <FontAwesomeIcon
368
+ icon="circle-exclamation"
369
+ color="darkred"
370
+ style={{ marginRight: 10, marginLeft: 10 }}
371
+ />
372
+ {errorMessage}
373
+ </Box>
374
+ ) : (
375
+ <></>
376
+ )}
377
+ </Box>
378
+ </>
379
+ );
380
+ };
381
+
382
+ export default ReportViewer;
@@ -0,0 +1,9 @@
1
+ import { useParams } from "react-router-dom";
2
+ import DashboardViewer from "./DashboardViewer";
3
+
4
+ const DashboardRouteView: React.FC = () => {
5
+ const { dashboardCode } = useParams();
6
+ return <DashboardViewer dashboardCode={dashboardCode} />;
7
+ };
8
+
9
+ export default DashboardRouteView;