@iapps/ng-dhis2-ui 1.2.146 → 1.2.154
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.
- package/fesm2022/iapps-ng-dhis2-ui.mjs +447 -480
- package/fesm2022/iapps-ng-dhis2-ui.mjs.map +1 -1
- package/index.d.ts +29 -24
- package/package.json +1 -1
|
@@ -3838,37 +3838,273 @@ const DropdownMenu$1 = (props) => {
|
|
|
3838
3838
|
} }))));
|
|
3839
3839
|
};
|
|
3840
3840
|
|
|
3841
|
-
|
|
3842
|
-
//
|
|
3843
|
-
//
|
|
3841
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3842
|
+
// // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
3843
|
+
// // Use of this source code is governed by a BSD-style
|
|
3844
|
+
// // license that can be found in the LICENSE file.
|
|
3845
|
+
// import {
|
|
3846
|
+
// ActionOptionOrientation,
|
|
3847
|
+
// DropdownMenuOption,
|
|
3848
|
+
// LineListActionOption,
|
|
3849
|
+
// } from '../../models';
|
|
3850
|
+
// import { DropdownMenu } from '../dropdown-menu';
|
|
3851
|
+
// import React from 'react';
|
|
3852
|
+
// import { ButtonStrip, Button, colors } from '@dhis2/ui';
|
|
3853
|
+
// import { TableRow } from '../../models/line-list.models';
|
|
3854
|
+
// import { LineListRowActionFilterConfig } from '@iapps/d2-web-sdk';
|
|
3855
|
+
// export const DataTableActions = (props: {
|
|
3856
|
+
// data: TableRow;
|
|
3857
|
+
// actionOptions: LineListActionOption[];
|
|
3858
|
+
// rowActionFilterConfig: LineListRowActionFilterConfig;
|
|
3859
|
+
// actionOptionOrientation: ActionOptionOrientation;
|
|
3860
|
+
// onClick: (dropdownOption: LineListActionOption) => void;
|
|
3861
|
+
// }) => {
|
|
3862
|
+
// const {
|
|
3863
|
+
// data,
|
|
3864
|
+
// actionOptions,
|
|
3865
|
+
// rowActionFilterConfig,
|
|
3866
|
+
// actionOptionOrientation,
|
|
3867
|
+
// onClick,
|
|
3868
|
+
// } = props;
|
|
3869
|
+
// console.log(
|
|
3870
|
+
// 'REACHED HERE AND IMPROVE THE FOLLOWING::: ',
|
|
3871
|
+
// // JSON.stringify(data),
|
|
3872
|
+
// rowActionFilterConfig
|
|
3873
|
+
// );
|
|
3874
|
+
// switch (actionOptionOrientation) {
|
|
3875
|
+
// case 'BUTTON':
|
|
3876
|
+
// return (
|
|
3877
|
+
// <ButtonStrip>
|
|
3878
|
+
// {actionOptions.map((option) => (
|
|
3879
|
+
// <Button
|
|
3880
|
+
// key={option.label}
|
|
3881
|
+
// onClick={() => onClick(option)}
|
|
3882
|
+
// icon={option.icon ? <option.icon /> : <></>}
|
|
3883
|
+
// small
|
|
3884
|
+
// destructive={option.destructive}
|
|
3885
|
+
// >
|
|
3886
|
+
// {!option.iconOnly ? option.label : ''}
|
|
3887
|
+
// </Button>
|
|
3888
|
+
// ))}
|
|
3889
|
+
// </ButtonStrip>
|
|
3890
|
+
// );
|
|
3891
|
+
// case 'DROPDOWN':
|
|
3892
|
+
// return (
|
|
3893
|
+
// <DropdownMenu
|
|
3894
|
+
// dropdownOptions={actionOptions}
|
|
3895
|
+
// onClick={(option) => {
|
|
3896
|
+
// onClick(option);
|
|
3897
|
+
// }}
|
|
3898
|
+
// />
|
|
3899
|
+
// );
|
|
3900
|
+
// case 'LINK':
|
|
3901
|
+
// return (
|
|
3902
|
+
// <div
|
|
3903
|
+
// style={{
|
|
3904
|
+
// display: 'flex',
|
|
3905
|
+
// gap: 16,
|
|
3906
|
+
// alignItems: 'center',
|
|
3907
|
+
// }}
|
|
3908
|
+
// >
|
|
3909
|
+
// {actionOptions.map((option) => (
|
|
3910
|
+
// <a
|
|
3911
|
+
// style={{
|
|
3912
|
+
// cursor: 'pointer',
|
|
3913
|
+
// textDecoration: 'underline',
|
|
3914
|
+
// fontSize: 14,
|
|
3915
|
+
// display: 'flex',
|
|
3916
|
+
// alignItems: 'center',
|
|
3917
|
+
// gap: 4,
|
|
3918
|
+
// color: option.destructive ? colors.red700 : colors.grey900,
|
|
3919
|
+
// }}
|
|
3920
|
+
// key={option.label}
|
|
3921
|
+
// onClick={(event: any) => {
|
|
3922
|
+
// event.stopPropagation();
|
|
3923
|
+
// onClick(option);
|
|
3924
|
+
// }}
|
|
3925
|
+
// >
|
|
3926
|
+
// {option.icon ? <option.icon /> : <></>}
|
|
3927
|
+
// {!option.iconOnly ? <span>{option.label}</span> : <></>}
|
|
3928
|
+
// </a>
|
|
3929
|
+
// ))}
|
|
3930
|
+
// </div>
|
|
3931
|
+
// );
|
|
3932
|
+
// default:
|
|
3933
|
+
// return <></>;
|
|
3934
|
+
// }
|
|
3935
|
+
// };
|
|
3936
|
+
const extractTeiPayloadFromRow = (row) => row?.responseData?.value ?? null;
|
|
3937
|
+
/** Operator matcher (fast + predictable) */
|
|
3938
|
+
const matchesOperator = (actual, op, expected) => {
|
|
3939
|
+
const actualStr = actual == null ? '' : String(actual);
|
|
3940
|
+
const expectedList = Array.isArray(expected)
|
|
3941
|
+
? expected.map(String)
|
|
3942
|
+
: expected != null
|
|
3943
|
+
? [String(expected)]
|
|
3944
|
+
: [];
|
|
3945
|
+
switch (op) {
|
|
3946
|
+
case 'EXISTS':
|
|
3947
|
+
return actual != null;
|
|
3948
|
+
case 'NOT_EXISTS':
|
|
3949
|
+
return actual == null;
|
|
3950
|
+
case 'HAS_VALUE':
|
|
3951
|
+
return actualStr.trim().length > 0;
|
|
3952
|
+
case 'NO_VALUE':
|
|
3953
|
+
return actualStr.trim().length === 0;
|
|
3954
|
+
case 'EQ':
|
|
3955
|
+
return actualStr === (expectedList[0] ?? '');
|
|
3956
|
+
case 'NEQ':
|
|
3957
|
+
return actualStr !== (expectedList[0] ?? '');
|
|
3958
|
+
case 'IN':
|
|
3959
|
+
return expectedList.includes(actualStr);
|
|
3960
|
+
case 'NOT_IN':
|
|
3961
|
+
return !expectedList.includes(actualStr);
|
|
3962
|
+
default:
|
|
3963
|
+
return false;
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
/**
|
|
3967
|
+
* Extract facts needed for rule evaluation from the TEI payload.
|
|
3968
|
+
* This is O(enrollments + events + attributes) and uses plain objects for speed.
|
|
3969
|
+
*/
|
|
3970
|
+
const buildTeiFacts = (teiPayload) => {
|
|
3971
|
+
const enrolledProgramIds = new Set();
|
|
3972
|
+
const eventCountByStageId = Object.create(null);
|
|
3973
|
+
const attributeValueById = Object.create(null);
|
|
3974
|
+
const attributeValueByCode = Object.create(null);
|
|
3975
|
+
const enrollments = teiPayload.enrollments ?? [];
|
|
3976
|
+
for (const enrollment of enrollments) {
|
|
3977
|
+
if (enrollment?.program)
|
|
3978
|
+
enrolledProgramIds.add(enrollment.program);
|
|
3979
|
+
const events = enrollment?.events ?? [];
|
|
3980
|
+
for (const ev of events) {
|
|
3981
|
+
const stageId = ev?.programStage;
|
|
3982
|
+
if (!stageId)
|
|
3983
|
+
continue;
|
|
3984
|
+
eventCountByStageId[stageId] = (eventCountByStageId[stageId] ?? 0) + 1;
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
const attributes = teiPayload.attributes ?? [];
|
|
3988
|
+
for (const attr of attributes) {
|
|
3989
|
+
const attrId = attr?.attribute;
|
|
3990
|
+
const attrCode = attr?.code;
|
|
3991
|
+
const value = attr?.value;
|
|
3992
|
+
if (attrId)
|
|
3993
|
+
attributeValueById[attrId] = value;
|
|
3994
|
+
if (attrCode)
|
|
3995
|
+
attributeValueByCode[attrCode] = value;
|
|
3996
|
+
}
|
|
3997
|
+
return {
|
|
3998
|
+
enrolledProgramIds,
|
|
3999
|
+
eventCountByStageId,
|
|
4000
|
+
attributeValueById,
|
|
4001
|
+
attributeValueByCode,
|
|
4002
|
+
};
|
|
4003
|
+
};
|
|
4004
|
+
const doesRuleMatchFacts = (rule, facts) => {
|
|
4005
|
+
// Enrollment condition
|
|
4006
|
+
if (rule.enrollment) {
|
|
4007
|
+
const hasEnrollment = facts.enrolledProgramIds.has(rule.enrollment.programId);
|
|
4008
|
+
if (hasEnrollment !== rule.enrollment.mustExist)
|
|
4009
|
+
return false;
|
|
4010
|
+
}
|
|
4011
|
+
// Stage event existence condition
|
|
4012
|
+
if (rule.stageEvent) {
|
|
4013
|
+
const count = facts.eventCountByStageId[rule.stageEvent.programStageId] ?? 0;
|
|
4014
|
+
const hasStageEvent = count > 0;
|
|
4015
|
+
if (hasStageEvent !== rule.stageEvent.mustExist)
|
|
4016
|
+
return false;
|
|
4017
|
+
}
|
|
4018
|
+
// Attribute condition (support by id OR code)
|
|
4019
|
+
if (rule.attribute) {
|
|
4020
|
+
const value = rule.attribute.attributeId
|
|
4021
|
+
? facts.attributeValueById[rule.attribute.attributeId]
|
|
4022
|
+
: undefined;
|
|
4023
|
+
if (!matchesOperator(value, rule.attribute.op, rule.attribute.value))
|
|
4024
|
+
return false;
|
|
4025
|
+
}
|
|
4026
|
+
return true;
|
|
4027
|
+
};
|
|
4028
|
+
const compileFilterConfig = (config) => {
|
|
4029
|
+
if (!config?.enabled)
|
|
4030
|
+
return null;
|
|
4031
|
+
// Sort once, not per row render
|
|
4032
|
+
const rulesSorted = [...(config.rules ?? [])].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
4033
|
+
return {
|
|
4034
|
+
enabled: true,
|
|
4035
|
+
fallback: config.fallback ?? 'NO_FILTER',
|
|
4036
|
+
combine: config.combine ?? 'APPLY_ALL',
|
|
4037
|
+
rulesSorted,
|
|
4038
|
+
};
|
|
4039
|
+
};
|
|
4040
|
+
const computeAllowedActionIdsForRow = (baseActionIds, compiled, facts) => {
|
|
4041
|
+
const matchedRules = [];
|
|
4042
|
+
for (const rule of compiled.rulesSorted) {
|
|
4043
|
+
if (doesRuleMatchFacts(rule, facts)) {
|
|
4044
|
+
matchedRules.push(rule);
|
|
4045
|
+
if (compiled.combine === 'FIRST_MATCH')
|
|
4046
|
+
break;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
// If nothing matched: return base or empty depending on fallback
|
|
4050
|
+
if (matchedRules.length === 0) {
|
|
4051
|
+
return compiled.fallback === 'NO_FILTER' ? baseActionIds : [];
|
|
4052
|
+
}
|
|
4053
|
+
let allowed = new Set(baseActionIds);
|
|
4054
|
+
for (const rule of matchedRules) {
|
|
4055
|
+
if (rule.effect === 'HIDE') {
|
|
4056
|
+
for (const actionId of rule.actions)
|
|
4057
|
+
allowed.delete(actionId);
|
|
4058
|
+
}
|
|
4059
|
+
else {
|
|
4060
|
+
// SHOW_ONLY
|
|
4061
|
+
allowed = new Set(rule.actions.filter((id) => allowed.has(id)));
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
return Array.from(allowed);
|
|
4065
|
+
};
|
|
3844
4066
|
const DataTableActions = (props) => {
|
|
3845
|
-
const { data, actionOptions, actionOptionOrientation, onClick } = props;
|
|
3846
|
-
|
|
4067
|
+
const { data: row, actionOptions, rowActionFilterConfig, actionOptionOrientation: orientation, onClick: onActionClick, } = props;
|
|
4068
|
+
const compiledConfig = useMemo(() => compileFilterConfig(rowActionFilterConfig), [rowActionFilterConfig]);
|
|
4069
|
+
const visibleActions = useMemo(() => {
|
|
4070
|
+
const base = actionOptions ?? [];
|
|
4071
|
+
// No config => show base
|
|
4072
|
+
if (!compiledConfig)
|
|
4073
|
+
return base;
|
|
4074
|
+
// Extract embedded TEI payload (already available in row)
|
|
4075
|
+
const teiPayload = extractTeiPayloadFromRow(row);
|
|
4076
|
+
// If no payload => do not filter (your requirement)
|
|
4077
|
+
if (!teiPayload)
|
|
4078
|
+
return base;
|
|
4079
|
+
// Prefer stable action id; fallback to label as legacy
|
|
4080
|
+
const baseActionIds = base.map((a) => a.id ?? a.label);
|
|
4081
|
+
const facts = buildTeiFacts(teiPayload);
|
|
4082
|
+
const allowedIds = computeAllowedActionIdsForRow(baseActionIds, compiledConfig, facts);
|
|
4083
|
+
// If allowedIds equals baseActionIds, this filter is basically no-op,
|
|
4084
|
+
// but we keep a cheap Set to filter objects correctly.
|
|
4085
|
+
const allowedSet = new Set(allowedIds);
|
|
4086
|
+
return base.filter((a) => allowedSet.has(a.id ?? a.label));
|
|
4087
|
+
}, [actionOptions, row, compiledConfig]);
|
|
4088
|
+
switch (orientation) {
|
|
3847
4089
|
case 'BUTTON':
|
|
3848
|
-
return (React__default.createElement(ButtonStrip$1, null,
|
|
4090
|
+
return (React__default.createElement(ButtonStrip$1, null, visibleActions.map((action) => (React__default.createElement(Button$1, { key: action.id ?? action.label, onClick: () => onActionClick(action), icon: action.icon ? React__default.createElement(action.icon, null) : React__default.createElement(React__default.Fragment, null), small: true, destructive: action.destructive }, !action.iconOnly ? action.label : '')))));
|
|
3849
4091
|
case 'DROPDOWN':
|
|
3850
|
-
return (React__default.createElement(DropdownMenu$1, { dropdownOptions:
|
|
3851
|
-
onClick(option);
|
|
3852
|
-
} }));
|
|
4092
|
+
return (React__default.createElement(DropdownMenu$1, { dropdownOptions: visibleActions, onClick: (action) => onActionClick(action) }));
|
|
3853
4093
|
case 'LINK':
|
|
3854
|
-
return (React__default.createElement("div", { style: {
|
|
3855
|
-
display: 'flex',
|
|
3856
|
-
gap: 16,
|
|
3857
|
-
alignItems: 'center',
|
|
3858
|
-
} }, actionOptions.map((option) => (React__default.createElement("a", { style: {
|
|
4094
|
+
return (React__default.createElement("div", { style: { display: 'flex', gap: 16, alignItems: 'center' } }, visibleActions.map((action) => (React__default.createElement("a", { key: action.id ?? action.label, style: {
|
|
3859
4095
|
cursor: 'pointer',
|
|
3860
4096
|
textDecoration: 'underline',
|
|
3861
4097
|
fontSize: 14,
|
|
3862
4098
|
display: 'flex',
|
|
3863
4099
|
alignItems: 'center',
|
|
3864
4100
|
gap: 4,
|
|
3865
|
-
color:
|
|
3866
|
-
},
|
|
4101
|
+
color: action.destructive ? colors$1.red700 : colors$1.grey900,
|
|
4102
|
+
}, onClick: (event) => {
|
|
3867
4103
|
event.stopPropagation();
|
|
3868
|
-
|
|
4104
|
+
onActionClick(action);
|
|
3869
4105
|
} },
|
|
3870
|
-
|
|
3871
|
-
!
|
|
4106
|
+
action.icon ? React__default.createElement(action.icon, null) : React__default.createElement(React__default.Fragment, null),
|
|
4107
|
+
!action.iconOnly ? React__default.createElement("span", null, action.label) : React__default.createElement(React__default.Fragment, null))))));
|
|
3872
4108
|
default:
|
|
3873
4109
|
return React__default.createElement(React__default.Fragment, null);
|
|
3874
4110
|
}
|
|
@@ -3900,7 +4136,7 @@ const TableCell = ({ cell, getTextColorFromBackGround, }) => {
|
|
|
3900
4136
|
React__default.createElement("div", { className: "text-sm text-gray-800" }, cell?.value || '-')));
|
|
3901
4137
|
};
|
|
3902
4138
|
|
|
3903
|
-
const TableRow = ({ row, columns, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, isChecked, onToggle, selectable, showActionButtons, }) => {
|
|
4139
|
+
const TableRow = ({ row, columns, getTextColorFromBackGround, actionOptions, rowActionFilterConfig, actionOptionOrientation, actionSelected, isChecked, onToggle, selectable, showActionButtons, }) => {
|
|
3904
4140
|
const handleCheckBoxChange = () => {
|
|
3905
4141
|
onToggle(row);
|
|
3906
4142
|
};
|
|
@@ -3909,7 +4145,7 @@ const TableRow = ({ row, columns, getTextColorFromBackGround, actionOptions, act
|
|
|
3909
4145
|
React__default.createElement(Checkbox, { onChange: handleCheckBoxChange, checked: isChecked }))),
|
|
3910
4146
|
columns.map((col) => {
|
|
3911
4147
|
if (col.key === 'actions') {
|
|
3912
|
-
return (React__default.createElement(DataTableCell, { key: col.key }, actionOptions && showActionButtons && (React__default.createElement(DataTableActions, { actionOptions: actionOptions, data: row, actionOptionOrientation: actionOptionOrientation, onClick: (option) => {
|
|
4148
|
+
return (React__default.createElement(DataTableCell, { key: col.key }, actionOptions && showActionButtons && (React__default.createElement(DataTableActions, { actionOptions: actionOptions, rowActionFilterConfig: rowActionFilterConfig, data: row, actionOptionOrientation: actionOptionOrientation, onClick: (option) => {
|
|
3913
4149
|
const data = row['responseData']?.['value'];
|
|
3914
4150
|
if (option.onClick)
|
|
3915
4151
|
option.onClick(data);
|
|
@@ -3961,13 +4197,13 @@ const TableRow = ({ row, columns, getTextColorFromBackGround, actionOptions, act
|
|
|
3961
4197
|
// )}
|
|
3962
4198
|
// </DHISTableBody>
|
|
3963
4199
|
// );
|
|
3964
|
-
const TableBody = ({ data, columns, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, selectedRows, onRowToggle, selectable, showActionButtons, error, }) => (React__default.createElement(TableBody$1, null, error ? (React__default.createElement(DataTableRow, null,
|
|
4200
|
+
const TableBody = ({ data, columns, getTextColorFromBackGround, actionOptions, rowActionFilterConfig, actionOptionOrientation, actionSelected, selectedRows, onRowToggle, selectable, showActionButtons, error, }) => (React__default.createElement(TableBody$1, null, error ? (React__default.createElement(DataTableRow, null,
|
|
3965
4201
|
React__default.createElement(DataTableCell, { colSpan: columns.length.toString(), style: {
|
|
3966
4202
|
textAlign: 'center',
|
|
3967
4203
|
fontWeight: 'bold',
|
|
3968
4204
|
color: 'red',
|
|
3969
4205
|
padding: '20px',
|
|
3970
|
-
} }, error))) : data.length > 0 ? (data.map((row) => (React__default.createElement(TableRow, { key: row.index.value, row: row, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected, isChecked: selectedRows.some((r) => r.index?.value === row.index?.value), onToggle: onRowToggle, selectable: selectable, showActionButtons: showActionButtons })))) : (React__default.createElement(DataTableRow, null,
|
|
4206
|
+
} }, error))) : data.length > 0 ? (data.map((row) => (React__default.createElement(TableRow, { key: row.index.value, row: row, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, rowActionFilterConfig: rowActionFilterConfig, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected, isChecked: selectedRows.some((r) => r.index?.value === row.index?.value), onToggle: onRowToggle, selectable: selectable, showActionButtons: showActionButtons })))) : (React__default.createElement(DataTableRow, null,
|
|
3971
4207
|
React__default.createElement(DataTableCell, { colSpan: columns.length.toString(), style: {
|
|
3972
4208
|
textAlign: 'center',
|
|
3973
4209
|
fontWeight: 'bold',
|
|
@@ -4024,7 +4260,7 @@ const TableFooter = ({ pager, setPager, columns }) => {
|
|
|
4024
4260
|
// </DataTable>
|
|
4025
4261
|
// );
|
|
4026
4262
|
// };
|
|
4027
|
-
const LineListTable = ({ columns, data, pager, setPager, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, selectable, rowsSelected, showActionButtons, error }) => {
|
|
4263
|
+
const LineListTable = ({ columns, data, pager, setPager, getTextColorFromBackGround, actionOptions, rowActionFilterConfig, actionOptionOrientation, actionSelected, selectable, rowsSelected, showActionButtons, error }) => {
|
|
4028
4264
|
const [selectedRows, setSelectedRows] = useState([]);
|
|
4029
4265
|
const handleRowToggle = (row) => {
|
|
4030
4266
|
const exists = selectedRows.find((r) => r.index?.value === row.index?.value);
|
|
@@ -4041,7 +4277,7 @@ const LineListTable = ({ columns, data, pager, setPager, getTextColorFromBackGro
|
|
|
4041
4277
|
};
|
|
4042
4278
|
return (React__default.createElement(DataTable, null,
|
|
4043
4279
|
React__default.createElement(TableHeader, { columns: columns, allSelected: selectedRows.length === data.length && data.length > 0, onSelectAll: handleSelectAll, selectable: selectable, showActionButtons: showActionButtons }),
|
|
4044
|
-
React__default.createElement(TableBody, { data: data, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected, selectedRows: selectedRows, onRowToggle: handleRowToggle, selectable: selectable, showActionButtons: showActionButtons, error: error }),
|
|
4280
|
+
React__default.createElement(TableBody, { data: data, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, rowActionFilterConfig: rowActionFilterConfig, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected, selectedRows: selectedRows, onRowToggle: handleRowToggle, selectable: selectable, showActionButtons: showActionButtons, error: error }),
|
|
4045
4281
|
React__default.createElement(TableFooter, { columns: columns, pager: pager, setPager: setPager })));
|
|
4046
4282
|
};
|
|
4047
4283
|
|
|
@@ -4397,6 +4633,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
4397
4633
|
super(...arguments);
|
|
4398
4634
|
this.actionOptionOrientation = 'DROPDOWN';
|
|
4399
4635
|
this.dataQueryFilters = [];
|
|
4636
|
+
this.hydrateForActionFiltering = true;
|
|
4400
4637
|
this.isButtonLoading = false;
|
|
4401
4638
|
this.filterRootOrgUnit = false;
|
|
4402
4639
|
this.showFilters = false;
|
|
@@ -4432,6 +4669,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
4432
4669
|
const [attributeFiltersState, setAttributeFiltersState] = useState(this.attributeFilters);
|
|
4433
4670
|
const [dataQueryFiltersState, setDataQueryFiltersState] = useState(this.dataQueryFilters);
|
|
4434
4671
|
const [tempDataQueryFiltersState, setTempDataQueryFiltersState] = useState(this.dataQueryFilters);
|
|
4672
|
+
const [rowActionFilterConfig, setRowActionFilterConfig] = useState(this.lineListRowActionFilterConfig);
|
|
4435
4673
|
const [startDateState, setStartDateState] = useState(this.startDate);
|
|
4436
4674
|
const [tempStartDateState, setTempStartDateState] = useState(this.startDate);
|
|
4437
4675
|
const [endDateState, setEndDateState] = useState(this.endDate);
|
|
@@ -4926,6 +5164,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
4926
5164
|
setPager: setPager,
|
|
4927
5165
|
getTextColorFromBackGround: getTextColorFromBackGround,
|
|
4928
5166
|
actionOptions: this.actionOptions,
|
|
5167
|
+
rowActionFilterConfig: this.lineListRowActionFilterConfig,
|
|
4929
5168
|
actionOptionOrientation: this.actionOptionOrientation,
|
|
4930
5169
|
actionSelected: this.actionSelected,
|
|
4931
5170
|
selectable: selectable,
|
|
@@ -4981,7 +5220,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
4981
5220
|
this.render();
|
|
4982
5221
|
}
|
|
4983
5222
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: LineListTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
4984
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.3", type: LineListTableComponent, isStandalone: false, selector: "ng-dhis2-ui-line-list", inputs: { triggerToken: "triggerToken", programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", actionOptionOrientation: "actionOptionOrientation", attributeFilters: "attributeFilters", useOuModeWithOlderDHIS2Instance: "useOuModeWithOlderDHIS2Instance", startDate: "startDate", endDate: "endDate", dataQueryFilters: "dataQueryFilters", ouMode: "ouMode", isButtonLoading: "isButtonLoading", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters", isOptionSetNameVisible: "isOptionSetNameVisible", allowRowsSelection: "allowRowsSelection", enrollmentStatus: "enrollmentStatus", filterableColumnIds: "filterableColumnIds", triggerRefetch: "triggerRefetch", eventStatus: "eventStatus", showActionButtons: "showActionButtons", showEnrollmentDates: "showEnrollmentDates", showDownloadButton: "showDownloadButton", searcheableDataElements: "searcheableDataElements" }, outputs: { actionSelected: "actionSelected", rowsSelected: "rowsSelected" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-input div{margin:0!important}::ng-deep .custom-input label{font-size:12px;padding-right:0}::ng-deep .custom-input input{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::ng-deep .custom-input [data-test=calendar-clear-button]{background-color:#f2f2f2!important;color:#870808!important;border-radius:6px!important;padding:4px 10px!important;font-size:0!important}::ng-deep .custom-input [data-test=calendar-clear-button]:before{content:\"\\2715\";font-size:14px;color:#870808}::ng-deep .custom-input [data-test=calendar-clear-button]:hover{background-color:#ddd}::ng-deep .calendar-input-wrapper{position:relative}::ng-deep .calendar-input-wrapper .custom-input{position:relative;width:100%;display:flex;align-items:center}::ng-deep .calendar-input-wrapper [data-test=calendar-clear-button]{right:8px;bottom:14px;margin:auto;display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:0!important;background-color:#a0adba!important;border-radius:50%;padding:2px;cursor:pointer}::ng-deep .calendar-input-wrapper [data-test=calendar-clear-button]:before{content:\"\\2715\";font-size:10px;color:#f0f0f0}::ng-deep .calendar-input-wrapper input{padding-right:40px!important;height:40px;line-height:40px;box-sizing:border-box}::ng-deep .custom-input label{color:gray!important;opacity:1}::ng-deep .table-top-toolbar{background-color:var(--colors-grey100)!important;color:var(--colors-grey900)!important}::ng-deep .custom-select-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-select-input div{margin:0!important}::ng-deep .custom-select-input [data-test=dhis2-uiwidgets-singleselectfield-label]{font-size:12px;color:gray!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]:focus-within{box-shadow:none!important}::ng-deep .custom-select-input input:focus{border:none!important;box-shadow:none!important}\n"] }); }
|
|
5223
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.3", type: LineListTableComponent, isStandalone: false, selector: "ng-dhis2-ui-line-list", inputs: { triggerToken: "triggerToken", programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", actionOptionOrientation: "actionOptionOrientation", attributeFilters: "attributeFilters", useOuModeWithOlderDHIS2Instance: "useOuModeWithOlderDHIS2Instance", startDate: "startDate", endDate: "endDate", dataQueryFilters: "dataQueryFilters", lineListRowActionFilterConfig: "lineListRowActionFilterConfig", hydrateForActionFiltering: "hydrateForActionFiltering", ouMode: "ouMode", isButtonLoading: "isButtonLoading", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters", isOptionSetNameVisible: "isOptionSetNameVisible", allowRowsSelection: "allowRowsSelection", enrollmentStatus: "enrollmentStatus", filterableColumnIds: "filterableColumnIds", triggerRefetch: "triggerRefetch", eventStatus: "eventStatus", showActionButtons: "showActionButtons", showEnrollmentDates: "showEnrollmentDates", showDownloadButton: "showDownloadButton", searcheableDataElements: "searcheableDataElements" }, outputs: { actionSelected: "actionSelected", rowsSelected: "rowsSelected" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-input div{margin:0!important}::ng-deep .custom-input label{font-size:12px;padding-right:0}::ng-deep .custom-input input{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::ng-deep .custom-input [data-test=calendar-clear-button]{background-color:#f2f2f2!important;color:#870808!important;border-radius:6px!important;padding:4px 10px!important;font-size:0!important}::ng-deep .custom-input [data-test=calendar-clear-button]:before{content:\"\\2715\";font-size:14px;color:#870808}::ng-deep .custom-input [data-test=calendar-clear-button]:hover{background-color:#ddd}::ng-deep .calendar-input-wrapper{position:relative}::ng-deep .calendar-input-wrapper .custom-input{position:relative;width:100%;display:flex;align-items:center}::ng-deep .calendar-input-wrapper [data-test=calendar-clear-button]{right:8px;bottom:14px;margin:auto;display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:0!important;background-color:#a0adba!important;border-radius:50%;padding:2px;cursor:pointer}::ng-deep .calendar-input-wrapper [data-test=calendar-clear-button]:before{content:\"\\2715\";font-size:10px;color:#f0f0f0}::ng-deep .calendar-input-wrapper input{padding-right:40px!important;height:40px;line-height:40px;box-sizing:border-box}::ng-deep .custom-input label{color:gray!important;opacity:1}::ng-deep .table-top-toolbar{background-color:var(--colors-grey100)!important;color:var(--colors-grey900)!important}::ng-deep .custom-select-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-select-input div{margin:0!important}::ng-deep .custom-select-input [data-test=dhis2-uiwidgets-singleselectfield-label]{font-size:12px;color:gray!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]:focus-within{box-shadow:none!important}::ng-deep .custom-select-input input:focus{border:none!important;box-shadow:none!important}\n"] }); }
|
|
4985
5224
|
}
|
|
4986
5225
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: LineListTableComponent, decorators: [{
|
|
4987
5226
|
type: Component,
|
|
@@ -5008,6 +5247,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImpor
|
|
|
5008
5247
|
type: Input
|
|
5009
5248
|
}], dataQueryFilters: [{
|
|
5010
5249
|
type: Input
|
|
5250
|
+
}], lineListRowActionFilterConfig: [{
|
|
5251
|
+
type: Input
|
|
5252
|
+
}], hydrateForActionFiltering: [{
|
|
5253
|
+
type: Input
|
|
5011
5254
|
}], ouMode: [{
|
|
5012
5255
|
type: Input
|
|
5013
5256
|
}], isButtonLoading: [{
|
|
@@ -7785,6 +8028,15 @@ class FieldCascadeUtil {
|
|
|
7785
8028
|
}
|
|
7786
8029
|
case ParentMatchMode.CONTAINS: {
|
|
7787
8030
|
// boundary-safe contains (segment-based)
|
|
8031
|
+
// const nana = FieldCascadeUtil.containsPathSegments(
|
|
8032
|
+
// childPath,
|
|
8033
|
+
// parentEffective,
|
|
8034
|
+
// separator
|
|
8035
|
+
// );
|
|
8036
|
+
// console.log("MAMA::: ", childPath);
|
|
8037
|
+
// console.log("MAMA 1111::: ", parentEffective);
|
|
8038
|
+
// console.log("MAMA 2222::: ", separator);
|
|
8039
|
+
// console.log("MAMA 2222::: ", separator);
|
|
7788
8040
|
return FieldCascadeUtil.containsPathSegments(childPath, parentEffective, separator);
|
|
7789
8041
|
}
|
|
7790
8042
|
default: {
|
|
@@ -7829,10 +8081,10 @@ class FieldCascadeUtil {
|
|
|
7829
8081
|
const childPath = FieldCascadeUtil.getChildOptionPath(opt, pathField, sep);
|
|
7830
8082
|
if (!childPath)
|
|
7831
8083
|
continue;
|
|
7832
|
-
console.log('CHILDPATH::: ', childPath);
|
|
7833
|
-
console.log('PARENTEFFECTIVE::: ', parentEffective);
|
|
7834
|
-
console.log('MODE::: ', mode);
|
|
7835
|
-
console.log('SEP::: ', sep);
|
|
8084
|
+
// console.log('CHILDPATH::: ', childPath);
|
|
8085
|
+
// console.log('PARENTEFFECTIVE::: ', parentEffective);
|
|
8086
|
+
// console.log('MODE::: ', mode);
|
|
8087
|
+
// console.log('SEP::: ', sep);
|
|
7836
8088
|
if (FieldCascadeUtil.matchesChildToParent(childPath, parentEffective, mode, sep)) {
|
|
7837
8089
|
out.push(opt);
|
|
7838
8090
|
}
|
|
@@ -8566,6 +8818,84 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
8566
8818
|
// Stable React key, avoids generateUUID re-mounting.
|
|
8567
8819
|
return String(option?.value ?? option?.id ?? option?.code ?? option?.label ?? '');
|
|
8568
8820
|
}
|
|
8821
|
+
formatValueForHtmlInputFromDhis(rawValue, isDateTimeField) {
|
|
8822
|
+
if (rawValue == null)
|
|
8823
|
+
return '';
|
|
8824
|
+
const trimmed = String(rawValue).trim();
|
|
8825
|
+
if (!trimmed)
|
|
8826
|
+
return '';
|
|
8827
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
8828
|
+
if (!isDateTimeField) {
|
|
8829
|
+
// Already in HTML date format
|
|
8830
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
8831
|
+
return trimmed;
|
|
8832
|
+
}
|
|
8833
|
+
// ISO-like datetime -> preserve calendar date portion directly
|
|
8834
|
+
const datePartMatch = trimmed.match(/^(\d{4}-\d{2}-\d{2})[T\s]/);
|
|
8835
|
+
if (datePartMatch) {
|
|
8836
|
+
return datePartMatch[1];
|
|
8837
|
+
}
|
|
8838
|
+
// Fallback parse only if needed
|
|
8839
|
+
const date = new Date(trimmed);
|
|
8840
|
+
if (Number.isNaN(date.getTime())) {
|
|
8841
|
+
return '';
|
|
8842
|
+
}
|
|
8843
|
+
return (`${date.getFullYear()}-` +
|
|
8844
|
+
`${pad(date.getMonth() + 1)}-` +
|
|
8845
|
+
`${pad(date.getDate())}`);
|
|
8846
|
+
}
|
|
8847
|
+
// Already in HTML datetime-local format
|
|
8848
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(trimmed)) {
|
|
8849
|
+
return trimmed;
|
|
8850
|
+
}
|
|
8851
|
+
// ISO-like datetime with optional seconds/timezone -> keep YYYY-MM-DDTHH:mm only
|
|
8852
|
+
const dateTimeMatch = trimmed.match(/^(\d{4}-\d{2}-\d{2})[T\s](\d{2}):(\d{2})/);
|
|
8853
|
+
if (dateTimeMatch) {
|
|
8854
|
+
return `${dateTimeMatch[1]}T${dateTimeMatch[2]}:${dateTimeMatch[3]}`;
|
|
8855
|
+
}
|
|
8856
|
+
const parsedDate = new Date(trimmed);
|
|
8857
|
+
if (Number.isNaN(parsedDate.getTime())) {
|
|
8858
|
+
return '';
|
|
8859
|
+
}
|
|
8860
|
+
const year = parsedDate.getFullYear();
|
|
8861
|
+
const month = pad(parsedDate.getMonth() + 1);
|
|
8862
|
+
const day = pad(parsedDate.getDate());
|
|
8863
|
+
const hours = pad(parsedDate.getHours());
|
|
8864
|
+
const minutes = pad(parsedDate.getMinutes());
|
|
8865
|
+
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
|
8866
|
+
}
|
|
8867
|
+
pickEarlierDateLimit(metadataMax, systemMax) {
|
|
8868
|
+
if (!metadataMax && !systemMax)
|
|
8869
|
+
return undefined;
|
|
8870
|
+
if (!metadataMax)
|
|
8871
|
+
return systemMax;
|
|
8872
|
+
if (!systemMax)
|
|
8873
|
+
return metadataMax;
|
|
8874
|
+
return metadataMax < systemMax ? metadataMax : systemMax;
|
|
8875
|
+
}
|
|
8876
|
+
getNowForHtmlDateInput(isDateTimeField) {
|
|
8877
|
+
const now = new Date();
|
|
8878
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
8879
|
+
const datePart = `${now.getFullYear()}-` +
|
|
8880
|
+
`${pad(now.getMonth() + 1)}-` +
|
|
8881
|
+
`${pad(now.getDate())}`;
|
|
8882
|
+
if (!isDateTimeField) {
|
|
8883
|
+
return datePart;
|
|
8884
|
+
}
|
|
8885
|
+
const timePart = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
|
8886
|
+
return `${datePart}T${timePart}`;
|
|
8887
|
+
}
|
|
8888
|
+
resolveHtmlMax(field, isDateTimeField) {
|
|
8889
|
+
// When future dates are allowed, do not limit picker selection at all
|
|
8890
|
+
if (field.allowFutureDate === true) {
|
|
8891
|
+
return undefined;
|
|
8892
|
+
}
|
|
8893
|
+
const metadataMax = field.max
|
|
8894
|
+
? this.formatValueForHtmlInputFromDhis(String(field.max), isDateTimeField)
|
|
8895
|
+
: undefined;
|
|
8896
|
+
const systemMax = this.getNowForHtmlDateInput(isDateTimeField);
|
|
8897
|
+
return this.pickEarlierDateLimit(metadataMax, systemMax);
|
|
8898
|
+
}
|
|
8569
8899
|
#getInputField() {
|
|
8570
8900
|
return () => {
|
|
8571
8901
|
const fg = this.form();
|
|
@@ -8678,6 +9008,9 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
8678
9008
|
setDisabled(baseDisabled || cascadeDisable);
|
|
8679
9009
|
// filter options
|
|
8680
9010
|
const nextOptions = FieldCascadeUtil.filterChildOptionsByParentPath(field.options ?? [], cascade, parentStr);
|
|
9011
|
+
// console.log("NOEW PARENT STR::: ", JSON.stringify(parentStr));
|
|
9012
|
+
// console.log("NOEW FIELD OPTIONS::: ", JSON.stringify(field.options));
|
|
9013
|
+
// console.log("NOEW PARENT CASCADE::: ", JSON.stringify(cascade));
|
|
8681
9014
|
setFilteredOptions(nextOptions);
|
|
8682
9015
|
// clear invalid child on parent change if configured
|
|
8683
9016
|
if (merged.clearOnParentChange && reason === 'parentChange') {
|
|
@@ -8770,18 +9103,23 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
8770
9103
|
case 'date':
|
|
8771
9104
|
case 'date-time': {
|
|
8772
9105
|
const isDateTimeField = f.type === 'date-time';
|
|
8773
|
-
const inputType = isDateTimeField
|
|
8774
|
-
|
|
8775
|
-
|
|
9106
|
+
const inputType = isDateTimeField
|
|
9107
|
+
? 'datetime-local'
|
|
9108
|
+
: 'date';
|
|
9109
|
+
const allowFutureDate = f.allowFutureDate === true;
|
|
9110
|
+
const htmlValue = value != null && String(value).trim() !== ''
|
|
9111
|
+
? this.formatValueForHtmlInputFromDhis(String(value), isDateTimeField)
|
|
9112
|
+
: '';
|
|
9113
|
+
const htmlMin = f.min != null && String(f.min).trim() !== ''
|
|
8776
9114
|
? this.formatValueForHtmlInputFromDhis(String(f.min), isDateTimeField)
|
|
8777
9115
|
: undefined;
|
|
8778
|
-
const
|
|
8779
|
-
?
|
|
8780
|
-
:
|
|
8781
|
-
|
|
8782
|
-
|
|
9116
|
+
const htmlMax = allowFutureDate
|
|
9117
|
+
? undefined
|
|
9118
|
+
: f.max
|
|
9119
|
+
? this.pickEarlierDateLimit(this.formatValueForHtmlInputFromDhis(String(f.max), isDateTimeField), this.getNowForHtmlDateInput(isDateTimeField))
|
|
9120
|
+
: this.getNowForHtmlDateInput(isDateTimeField);
|
|
8783
9121
|
return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: inputType, inputWidth: inputWidth, required: f.required, name: f.id, label: this.label(), min: htmlMin, max: htmlMax, placeholder: this.placeholder(), value: htmlValue, readOnly: disabled, onChange: ({ value: newValue }) => {
|
|
8784
|
-
const normalized = this.normalizeDateValueFromHtmlInput(newValue, isDateTimeField,
|
|
9122
|
+
const normalized = this.normalizeDateValueFromHtmlInput(newValue, isDateTimeField, allowFutureDate);
|
|
8785
9123
|
onValueChange(normalized);
|
|
8786
9124
|
}, onBlur: () => checkValueUniqueness() }));
|
|
8787
9125
|
}
|
|
@@ -8830,71 +9168,20 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
8830
9168
|
`${pad(date.getHours())}:` +
|
|
8831
9169
|
`${pad(date.getMinutes())}`);
|
|
8832
9170
|
}
|
|
8833
|
-
formatValueForHtmlInputFromDhis(rawValue, isDateTimeField) {
|
|
8834
|
-
if (!rawValue)
|
|
8835
|
-
return '';
|
|
8836
|
-
const trimmed = rawValue.trim();
|
|
8837
|
-
if (!trimmed)
|
|
8838
|
-
return '';
|
|
8839
|
-
const pad = (n) => String(n).padStart(2, '0');
|
|
8840
|
-
if (!isDateTimeField) {
|
|
8841
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
8842
|
-
return trimmed;
|
|
8843
|
-
}
|
|
8844
|
-
const date = new Date(trimmed);
|
|
8845
|
-
if (Number.isNaN(date.getTime())) {
|
|
8846
|
-
return '';
|
|
8847
|
-
}
|
|
8848
|
-
return (`${date.getFullYear()}-` +
|
|
8849
|
-
`${pad(date.getMonth() + 1)}-` +
|
|
8850
|
-
`${pad(date.getDate())}`);
|
|
8851
|
-
}
|
|
8852
|
-
const parsedDate = new Date(trimmed);
|
|
8853
|
-
if (Number.isNaN(parsedDate.getTime())) {
|
|
8854
|
-
return '';
|
|
8855
|
-
}
|
|
8856
|
-
const year = parsedDate.getFullYear();
|
|
8857
|
-
const month = pad(parsedDate.getMonth() + 1);
|
|
8858
|
-
const day = pad(parsedDate.getDate());
|
|
8859
|
-
const hours = pad(parsedDate.getHours());
|
|
8860
|
-
const minutes = pad(parsedDate.getMinutes());
|
|
8861
|
-
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
|
8862
|
-
}
|
|
8863
|
-
getNowForHtmlDateInput(isDateTimeField) {
|
|
8864
|
-
const now = new Date();
|
|
8865
|
-
const pad = (n) => String(n).padStart(2, '0');
|
|
8866
|
-
const datePart = `${now.getFullYear()}-` +
|
|
8867
|
-
`${pad(now.getMonth() + 1)}-` +
|
|
8868
|
-
`${pad(now.getDate())}`;
|
|
8869
|
-
if (!isDateTimeField) {
|
|
8870
|
-
return datePart;
|
|
8871
|
-
}
|
|
8872
|
-
const timePart = `${pad(now.getHours())}:` + `${pad(now.getMinutes())}`;
|
|
8873
|
-
return `${datePart}T${timePart}`;
|
|
8874
|
-
}
|
|
8875
|
-
pickEarlierDateLimit(metadataMax, systemMax) {
|
|
8876
|
-
if (!metadataMax && !systemMax)
|
|
8877
|
-
return undefined;
|
|
8878
|
-
if (!metadataMax)
|
|
8879
|
-
return systemMax;
|
|
8880
|
-
if (!systemMax)
|
|
8881
|
-
return metadataMax;
|
|
8882
|
-
return metadataMax < systemMax ? metadataMax : systemMax;
|
|
8883
|
-
}
|
|
8884
9171
|
/**
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
normalizeDateValueFromHtmlInput(inputValue, isDateTimeField,
|
|
9172
|
+
* Normalizes value from the HTML input into DHIS storage format.
|
|
9173
|
+
*
|
|
9174
|
+
* For date:
|
|
9175
|
+
* - Input: "YYYY-MM-DD"
|
|
9176
|
+
* - Output: "YYYY-MM-DD"
|
|
9177
|
+
*
|
|
9178
|
+
* For datetime:
|
|
9179
|
+
* - Input: "YYYY-MM-DDTHH:mm" (local)
|
|
9180
|
+
* - Output: ISO string in UTC: "YYYY-MM-DDTHH:mm:ss.sssZ"
|
|
9181
|
+
*
|
|
9182
|
+
* If allowFutureDate = false, any value beyond "now" is clamped to now.
|
|
9183
|
+
*/
|
|
9184
|
+
normalizeDateValueFromHtmlInput(inputValue, isDateTimeField, allowFutureDate) {
|
|
8898
9185
|
const trimmed = (inputValue ?? '').trim();
|
|
8899
9186
|
if (!trimmed)
|
|
8900
9187
|
return null;
|
|
@@ -8902,7 +9189,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
8902
9189
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
8903
9190
|
return null;
|
|
8904
9191
|
}
|
|
8905
|
-
if (
|
|
9192
|
+
if (!allowFutureDate) {
|
|
8906
9193
|
const todayStr = this.getNowForHtmlDateInput(false);
|
|
8907
9194
|
if (trimmed > todayStr) {
|
|
8908
9195
|
return todayStr;
|
|
@@ -8920,13 +9207,10 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
8920
9207
|
if (Number.isNaN(localDate.getTime())) {
|
|
8921
9208
|
return null;
|
|
8922
9209
|
}
|
|
8923
|
-
if (
|
|
9210
|
+
if (!allowFutureDate) {
|
|
8924
9211
|
const now = new Date();
|
|
8925
9212
|
if (localDate.getTime() > now.getTime()) {
|
|
8926
|
-
// Option A: clamp to now
|
|
8927
9213
|
return now.toISOString();
|
|
8928
|
-
// Option B: reject:
|
|
8929
|
-
// return null;
|
|
8930
9214
|
}
|
|
8931
9215
|
}
|
|
8932
9216
|
// Store as UTC ISO string with millis, e.g. "2025-11-26T21:01:00.000Z"
|
|
@@ -9964,6 +10248,7 @@ class FormFieldGroup {
|
|
|
9964
10248
|
controlType: FieldUtil.getFieldControlType(fieldMetaData['valueType'], hasOptions),
|
|
9965
10249
|
metaType: fieldMetaData['metaType'],
|
|
9966
10250
|
stepId: fieldMetaData['stepId'],
|
|
10251
|
+
allowFutureDate: fieldMetaData['allowFutureDate'],
|
|
9967
10252
|
extension,
|
|
9968
10253
|
});
|
|
9969
10254
|
})
|
|
@@ -10549,6 +10834,7 @@ class FormUtil {
|
|
|
10549
10834
|
min: field.min,
|
|
10550
10835
|
max: field.max,
|
|
10551
10836
|
maxLength: field.maxLength,
|
|
10837
|
+
allowFutureDate: field.allowFutureDate,
|
|
10552
10838
|
});
|
|
10553
10839
|
});
|
|
10554
10840
|
}
|
|
@@ -11464,78 +11750,84 @@ class ProgramEntryFormFieldUtil {
|
|
|
11464
11750
|
});
|
|
11465
11751
|
}
|
|
11466
11752
|
// #getGeometryField(): IFormField<string> | null {
|
|
11467
|
-
//
|
|
11468
|
-
//
|
|
11469
|
-
//
|
|
11470
|
-
// JSON.stringify(rawFeatureType)
|
|
11471
|
-
// );
|
|
11472
|
-
// const featureType = rawFeatureType.toUpperCase() as
|
|
11753
|
+
// if (this.config?.hideGeometryField) return null;
|
|
11754
|
+
// const effectiveFeatureTypeRaw = this.#resolveEffectiveFeatureType();
|
|
11755
|
+
// const normalizedFeatureType = effectiveFeatureTypeRaw.toUpperCase() as
|
|
11473
11756
|
// | 'NONE'
|
|
11474
11757
|
// | 'POINT'
|
|
11475
11758
|
// | 'POLYGON'
|
|
11476
11759
|
// | 'MULTI_POLYGON'
|
|
11477
11760
|
// | '';
|
|
11478
|
-
// const
|
|
11479
|
-
//
|
|
11480
|
-
//
|
|
11481
|
-
//
|
|
11482
|
-
// if (!
|
|
11483
|
-
//
|
|
11484
|
-
//
|
|
11485
|
-
//
|
|
11486
|
-
//
|
|
11487
|
-
// }
|
|
11488
|
-
// const sharedOptions = {
|
|
11489
|
-
// required: true,
|
|
11490
|
-
// disabled: this.config?.disableRegistrationUnit ?? false,
|
|
11491
|
-
// isGeometryField: true as const,
|
|
11492
|
-
// };
|
|
11493
|
-
// const label =
|
|
11494
|
-
// featureType === 'POINT' ? 'Location (coordinates)' : 'Boundary (polygon)';
|
|
11761
|
+
// const supportsGeometry =
|
|
11762
|
+
// normalizedFeatureType === 'POINT' ||
|
|
11763
|
+
// normalizedFeatureType === 'POLYGON' ||
|
|
11764
|
+
// normalizedFeatureType === 'MULTI_POLYGON';
|
|
11765
|
+
// if (!supportsGeometry) return null;
|
|
11766
|
+
// const geometryFieldLabel =
|
|
11767
|
+
// normalizedFeatureType === 'POINT'
|
|
11768
|
+
// ? 'Location (coordinates)'
|
|
11769
|
+
// : 'Boundary (polygon)';
|
|
11495
11770
|
// return new FormField<string>({
|
|
11496
11771
|
// id: 'geometry',
|
|
11497
11772
|
// key: 'geometry',
|
|
11498
|
-
// label,
|
|
11499
11773
|
// code: 'geometry',
|
|
11774
|
+
// label: geometryFieldLabel,
|
|
11500
11775
|
// controlType: 'coordinate',
|
|
11501
|
-
//
|
|
11776
|
+
// required: true,
|
|
11777
|
+
// disabled: this.config?.disableGeometryField ?? false,
|
|
11778
|
+
// isGeometryField: true,
|
|
11502
11779
|
// });
|
|
11503
11780
|
// }
|
|
11504
11781
|
#getGeometryField() {
|
|
11505
|
-
|
|
11782
|
+
// Hide by default unless explicitly enabled
|
|
11783
|
+
if (this.config?.hideGeometryField !== false)
|
|
11506
11784
|
return null;
|
|
11507
|
-
const
|
|
11508
|
-
const
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
normalizedFeatureType === 'MULTI_POLYGON';
|
|
11785
|
+
const featureType = this.#resolveEffectiveFeatureType().toUpperCase();
|
|
11786
|
+
const supportsGeometry = featureType === 'POINT' ||
|
|
11787
|
+
featureType === 'POLYGON' ||
|
|
11788
|
+
featureType === 'MULTI_POLYGON';
|
|
11512
11789
|
if (!supportsGeometry)
|
|
11513
11790
|
return null;
|
|
11514
|
-
const
|
|
11515
|
-
? 'Location (coordinates)'
|
|
11516
|
-
: 'Boundary (polygon)';
|
|
11791
|
+
const label = featureType === 'POINT' ? 'Location (coordinates)' : 'Boundary (polygon)';
|
|
11517
11792
|
return new FormField({
|
|
11518
11793
|
id: 'geometry',
|
|
11519
11794
|
key: 'geometry',
|
|
11520
11795
|
code: 'geometry',
|
|
11521
|
-
label
|
|
11796
|
+
label,
|
|
11522
11797
|
controlType: 'coordinate',
|
|
11523
11798
|
required: true,
|
|
11524
|
-
disabled: this.config?.
|
|
11799
|
+
disabled: this.config?.disableGeometryField ?? false,
|
|
11525
11800
|
isGeometryField: true,
|
|
11526
11801
|
});
|
|
11527
11802
|
}
|
|
11803
|
+
// #resolveEffectiveFeatureType(): string {
|
|
11804
|
+
// const programMeta = this.program;
|
|
11805
|
+
// const configuredProgramStageId = this.config?.programStage;
|
|
11806
|
+
// if (configuredProgramStageId && programMeta?.programStages?.length) {
|
|
11807
|
+
// const configuredStage = programMeta.programStages.find(
|
|
11808
|
+
// (stage: ProgramStage) => stage?.id === configuredProgramStageId
|
|
11809
|
+
// );
|
|
11810
|
+
// const stageFeatureTypeRaw = configuredStage?.featureType ?? '';
|
|
11811
|
+
// if (stageFeatureTypeRaw) return String(stageFeatureTypeRaw);
|
|
11812
|
+
// }
|
|
11813
|
+
// const programFeatureTypeRaw = (programMeta as Program)?.featureType ?? '';
|
|
11814
|
+
// return String(programFeatureTypeRaw);
|
|
11815
|
+
// }
|
|
11528
11816
|
#resolveEffectiveFeatureType() {
|
|
11529
11817
|
const programMeta = this.program;
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11818
|
+
if (!programMeta)
|
|
11819
|
+
return '';
|
|
11820
|
+
const configuredStageId = this.config?.programStage;
|
|
11821
|
+
if (configuredStageId && Array.isArray(programMeta.programStages)) {
|
|
11822
|
+
const stage = programMeta.programStages.find((s) => s?.id === configuredStageId);
|
|
11823
|
+
const stageFeatureType = String(stage?.featureType ?? '').trim();
|
|
11824
|
+
if (stageFeatureType) {
|
|
11825
|
+
return stageFeatureType;
|
|
11826
|
+
}
|
|
11536
11827
|
}
|
|
11537
|
-
|
|
11538
|
-
|
|
11828
|
+
// 2) Fallback to program (enrollment-level) featureType
|
|
11829
|
+
const programFeatureType = String(programMeta?.featureType ?? '').trim();
|
|
11830
|
+
return programFeatureType;
|
|
11539
11831
|
}
|
|
11540
11832
|
#getEnrollmentDateField() {
|
|
11541
11833
|
if (this.config.hideEnrollmentDate || this.config.programStage) {
|
|
@@ -11660,6 +11952,8 @@ class ProgramEntryFormFieldUtil {
|
|
|
11660
11952
|
controlType: FieldUtil.getFieldControlType(field.valueType, hasOptions),
|
|
11661
11953
|
metaType: field.metaType,
|
|
11662
11954
|
stepId: field.stepId,
|
|
11955
|
+
allowFutureDate: field
|
|
11956
|
+
.allowFutureDate,
|
|
11663
11957
|
extension,
|
|
11664
11958
|
});
|
|
11665
11959
|
})
|
|
@@ -11696,334 +11990,6 @@ class ProgramStageEntryFormSection {
|
|
|
11696
11990
|
}
|
|
11697
11991
|
}
|
|
11698
11992
|
|
|
11699
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
11700
|
-
// // // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
11701
|
-
// // // Use of this source code is governed by a BSD-style
|
|
11702
|
-
// // // license that can be found in the LICENSE file.
|
|
11703
|
-
// import { camelCase, isUndefined } from 'lodash';
|
|
11704
|
-
// import { Program, ProgramStage, ProgramStageSection } from '@iapps/d2-web-sdk';
|
|
11705
|
-
// import {
|
|
11706
|
-
// IProgramStageEntryFormSection,
|
|
11707
|
-
// ProgramStageEntryFormSection,
|
|
11708
|
-
// } from '../models/program-stage-entry-form-section.model';
|
|
11709
|
-
// import { ProgramEntryFormConfig } from '../models/program-entry-form.config';
|
|
11710
|
-
// import { IFormField } from '../../form/interfaces/form-field.interface';
|
|
11711
|
-
// import { FieldDropdown } from '../../form/models/field-dropdown.model';
|
|
11712
|
-
// import { FormField } from '../../form/models/form-field.model';
|
|
11713
|
-
// import { FieldUtil } from '../../form/utils';
|
|
11714
|
-
// import { ProgramEntryFormFieldUtil } from './program-entry-form-field.util';
|
|
11715
|
-
// // import {
|
|
11716
|
-
// // IProgramStageEntryFormSection,
|
|
11717
|
-
// // ProgramEntryFormConfig,
|
|
11718
|
-
// // ProgramStageEntryFormSection,
|
|
11719
|
-
// // } from '../models';
|
|
11720
|
-
// // TODO: START - DEPRECATED APPROACH
|
|
11721
|
-
// // import { Program, ProgramStage, ProgramStageSection } from '@iapps/d2-web-sdk';
|
|
11722
|
-
// // import {
|
|
11723
|
-
// // IProgramStageEntryFormSection,
|
|
11724
|
-
// // ProgramEntryFormConfig,
|
|
11725
|
-
// // ProgramStageEntryFormSection,
|
|
11726
|
-
// // } from '../models';
|
|
11727
|
-
// // export class ProgramStageEntryFormSectionUtil {
|
|
11728
|
-
// // constructor(
|
|
11729
|
-
// // private program: Program,
|
|
11730
|
-
// // private config: ProgramEntryFormConfig
|
|
11731
|
-
// // ) {}
|
|
11732
|
-
// // // get getProgramStageSections(): IProgramStageEntryFormSection[] {
|
|
11733
|
-
// // // return (this.program.programStages || []).flatMap((stage) =>
|
|
11734
|
-
// // // (stage.programStageSections || []).map(
|
|
11735
|
-
// // // (programStageSection: ProgramStageSection) =>
|
|
11736
|
-
// // // new ProgramStageSection(programStageSection)
|
|
11737
|
-
// // // )
|
|
11738
|
-
// // // );
|
|
11739
|
-
// // // }
|
|
11740
|
-
// // get programStageEntryFormSections(): IProgramStageEntryFormSection[] {
|
|
11741
|
-
// // return (this.program.programStages || []).flatMap((stage: ProgramStage) =>
|
|
11742
|
-
// // (stage.programStageSections || []).map(
|
|
11743
|
-
// // (section: ProgramStageSection) =>
|
|
11744
|
-
// // new ProgramStageEntryFormSection({
|
|
11745
|
-
// // id: section.id,
|
|
11746
|
-
// // name: section.displayName,
|
|
11747
|
-
// // description: '',
|
|
11748
|
-
// // formFields: fieldsForSection(stage, section),
|
|
11749
|
-
// // orientation: 'HORIZONTAL',
|
|
11750
|
-
// // })
|
|
11751
|
-
// // )
|
|
11752
|
-
// // );
|
|
11753
|
-
// // }
|
|
11754
|
-
// // }
|
|
11755
|
-
// // TODO: END - DEPRECATED APPROACH
|
|
11756
|
-
// // export class ProgramStageEntryFormSectionUtil {
|
|
11757
|
-
// // constructor(
|
|
11758
|
-
// // private program: Program,
|
|
11759
|
-
// // private config: ProgramEntryFormConfig
|
|
11760
|
-
// // ) {}
|
|
11761
|
-
// // get programStageEntryFormSections(): IProgramStageEntryFormSection[] {
|
|
11762
|
-
// // const stageId = this.#getStageIdFromConfig();
|
|
11763
|
-
// // if (!stageId) return [];
|
|
11764
|
-
// // const programStage = this.#findStageById(stageId);
|
|
11765
|
-
// // if (!programStage) return [];
|
|
11766
|
-
// // return (programStage.programStageSections || []).map(
|
|
11767
|
-
// // (section: ProgramStageSection) =>
|
|
11768
|
-
// // new ProgramStageEntryFormSection({
|
|
11769
|
-
// // id: section.id,
|
|
11770
|
-
// // name: section.displayName,
|
|
11771
|
-
// // description: section?.description,
|
|
11772
|
-
// // formFields: this.#mapSectionToFormFields(programStage, section),
|
|
11773
|
-
// // orientation: 'HORIZONTAL',
|
|
11774
|
-
// // })
|
|
11775
|
-
// // );
|
|
11776
|
-
// // }
|
|
11777
|
-
// // #getStageIdFromConfig(): string | null {
|
|
11778
|
-
// // const programStageRef: any = (this.config as any)?.programStage;
|
|
11779
|
-
// // if (!programStageRef) return null;
|
|
11780
|
-
// // if (typeof programStageRef === 'string' && programStageRef.trim()) {
|
|
11781
|
-
// // return programStageRef.trim();
|
|
11782
|
-
// // }
|
|
11783
|
-
// // const candidateId =
|
|
11784
|
-
// // programStageRef.id ??
|
|
11785
|
-
// // programStageRef.stageId ??
|
|
11786
|
-
// // programStageRef.programStageId ??
|
|
11787
|
-
// // programStageRef.value?.id ??
|
|
11788
|
-
// // null;
|
|
11789
|
-
// // return typeof candidateId === 'string' && candidateId.trim()
|
|
11790
|
-
// // ? candidateId.trim()
|
|
11791
|
-
// // : null;
|
|
11792
|
-
// // }
|
|
11793
|
-
// // #findStageById(stageId: string): ProgramStage | null {
|
|
11794
|
-
// // return (
|
|
11795
|
-
// // (this.program.programStages || []).find(
|
|
11796
|
-
// // (stage: ProgramStage) => (stage as any)?.id === stageId
|
|
11797
|
-
// // ) ?? null
|
|
11798
|
-
// // );
|
|
11799
|
-
// // }
|
|
11800
|
-
// // #mapSectionToFormFields(
|
|
11801
|
-
// // stage: ProgramStage,
|
|
11802
|
-
// // section: ProgramStageSection
|
|
11803
|
-
// // ): IFormField<string>[] {
|
|
11804
|
-
// // const stageDataElements: any[] =
|
|
11805
|
-
// // (stage as any).programStageDataElements || [];
|
|
11806
|
-
// // const sectionElementIds: string[] =
|
|
11807
|
-
// // (section as any).dataElements?.map((d: { id: string }) => d.id) ??
|
|
11808
|
-
// // (section as any).dataElementsIds ??
|
|
11809
|
-
// // [];
|
|
11810
|
-
// // const relevantStageElements = sectionElementIds.length
|
|
11811
|
-
// // ? stageDataElements.filter((pde) =>
|
|
11812
|
-
// // sectionElementIds.includes(pde?.dataElement?.id)
|
|
11813
|
-
// // )
|
|
11814
|
-
// // : stageDataElements;
|
|
11815
|
-
// // const mappedFields = relevantStageElements
|
|
11816
|
-
// // .map((pde) => this.#mapDataElementToFormField(pde, stage.id))
|
|
11817
|
-
// // .filter((field): field is IFormField<string> => field != null)
|
|
11818
|
-
// // .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
11819
|
-
// // const extraReportFields = (this as any)?.reportFields ?? [];
|
|
11820
|
-
// // return [...extraReportFields, ...mappedFields];
|
|
11821
|
-
// // }
|
|
11822
|
-
// // #mapDataElementToFormField(
|
|
11823
|
-
// // pde: any,
|
|
11824
|
-
// // stageId: string
|
|
11825
|
-
// // ): IFormField<string> | null {
|
|
11826
|
-
// // const dataElement = pde?.dataElement;
|
|
11827
|
-
// // if (!dataElement?.id) return null;
|
|
11828
|
-
// // const baseField = {
|
|
11829
|
-
// // id: dataElement.id,
|
|
11830
|
-
// // code: dataElement.code,
|
|
11831
|
-
// // formName: dataElement.formName,
|
|
11832
|
-
// // name: dataElement.displayName,
|
|
11833
|
-
// // mandatory: !!pde.compulsory,
|
|
11834
|
-
// // valueType: dataElement.valueType,
|
|
11835
|
-
// // sortOrder: pde.sortOrder,
|
|
11836
|
-
// // stepId: stageId,
|
|
11837
|
-
// // optionSet: dataElement.optionSet,
|
|
11838
|
-
// // };
|
|
11839
|
-
// // const options = FieldDropdown.getDropdownOptions(baseField);
|
|
11840
|
-
// // const hasOptions = options?.length > 0;
|
|
11841
|
-
// // const fieldExtension = this.config.formFieldExtensions?.find(
|
|
11842
|
-
// // (fx: any) => fx?.id === baseField.id
|
|
11843
|
-
// // );
|
|
11844
|
-
// // const autoAssignedValue = this.#getAutoAssignedValue(baseField);
|
|
11845
|
-
// // if (
|
|
11846
|
-
// // !isUndefined(autoAssignedValue) &&
|
|
11847
|
-
// // this.config.hideCustomAssignedFields
|
|
11848
|
-
// // ) {
|
|
11849
|
-
// // return null;
|
|
11850
|
-
// // }
|
|
11851
|
-
// // return new FormField<string>({
|
|
11852
|
-
// // ...baseField,
|
|
11853
|
-
// // label: baseField.formName || baseField.name,
|
|
11854
|
-
// // key: baseField.code ? camelCase(baseField.code) : baseField.id,
|
|
11855
|
-
// // required: baseField.mandatory,
|
|
11856
|
-
// // type: FieldUtil.getFieldType(baseField.valueType),
|
|
11857
|
-
// // options,
|
|
11858
|
-
// // disabled: this.#getDisabledStatus(baseField),
|
|
11859
|
-
// // order: baseField.sortOrder,
|
|
11860
|
-
// // hasOptions,
|
|
11861
|
-
// // controlType: FieldUtil.getFieldControlType(
|
|
11862
|
-
// // baseField.valueType,
|
|
11863
|
-
// // hasOptions
|
|
11864
|
-
// // ),
|
|
11865
|
-
// // extension: fieldExtension,
|
|
11866
|
-
// // });
|
|
11867
|
-
// // }
|
|
11868
|
-
// // #getAutoAssignedValue(field: any): unknown {
|
|
11869
|
-
// // const impl = (this as any)?.['#getAutoAssignedValue'];
|
|
11870
|
-
// // return typeof impl === 'function' ? impl.call(this, field) : undefined;
|
|
11871
|
-
// // }
|
|
11872
|
-
// // #getDisabledStatus(field: any): boolean {
|
|
11873
|
-
// // const impl = (this as any)?.['#getDisabledStatus'];
|
|
11874
|
-
// // return typeof impl === 'function' ? impl.call(this, field) : false;
|
|
11875
|
-
// // }
|
|
11876
|
-
// // }
|
|
11877
|
-
// export class ProgramStageEntryFormSectionUtil {
|
|
11878
|
-
// private readonly fieldUtil: ProgramEntryFormFieldUtil;
|
|
11879
|
-
// constructor(
|
|
11880
|
-
// private readonly program: Program,
|
|
11881
|
-
// private readonly config: ProgramEntryFormConfig
|
|
11882
|
-
// ) {
|
|
11883
|
-
// this.fieldUtil = new ProgramEntryFormFieldUtil(program, config);
|
|
11884
|
-
// }
|
|
11885
|
-
// get programStageEntryFormSections(): IProgramStageEntryFormSection[] {
|
|
11886
|
-
// const stageId = this.#getStageIdFromConfig();
|
|
11887
|
-
// if (!stageId || !this.program) {
|
|
11888
|
-
// return [];
|
|
11889
|
-
// }
|
|
11890
|
-
// const programStage = this.#findStageById(stageId);
|
|
11891
|
-
// if (!programStage) {
|
|
11892
|
-
// return [];
|
|
11893
|
-
// }
|
|
11894
|
-
// const sections: IProgramStageEntryFormSection[] = [];
|
|
11895
|
-
// const basicDetailsFields = this.fieldUtil.eventReportFields;
|
|
11896
|
-
// if (basicDetailsFields?.length) {
|
|
11897
|
-
// sections.push(
|
|
11898
|
-
// new ProgramStageEntryFormSection({
|
|
11899
|
-
// id: `${programStage.id}_basic_information`,
|
|
11900
|
-
// name: 'Basic Information',
|
|
11901
|
-
// description: '',
|
|
11902
|
-
// formFields: basicDetailsFields,
|
|
11903
|
-
// orientation: 'VERTICAL',
|
|
11904
|
-
// })
|
|
11905
|
-
// );
|
|
11906
|
-
// }
|
|
11907
|
-
// const stageSections = programStage.programStageSections ?? [];
|
|
11908
|
-
// for (const section of stageSections) {
|
|
11909
|
-
// const sectionFormFields = this.#mapSectionToFormFields(
|
|
11910
|
-
// programStage,
|
|
11911
|
-
// section
|
|
11912
|
-
// );
|
|
11913
|
-
// if (!sectionFormFields.length) {
|
|
11914
|
-
// continue;
|
|
11915
|
-
// }
|
|
11916
|
-
// sections.push(
|
|
11917
|
-
// new ProgramStageEntryFormSection({
|
|
11918
|
-
// id: section.id,
|
|
11919
|
-
// name: section.displayName,
|
|
11920
|
-
// description: section?.description,
|
|
11921
|
-
// formFields: sectionFormFields,
|
|
11922
|
-
// orientation: 'HORIZONTAL',
|
|
11923
|
-
// })
|
|
11924
|
-
// );
|
|
11925
|
-
// }
|
|
11926
|
-
// return sections;
|
|
11927
|
-
// }
|
|
11928
|
-
// #getStageIdFromConfig(): string | null {
|
|
11929
|
-
// const programStageRef: any = (this.config as any)?.programStage;
|
|
11930
|
-
// if (!programStageRef) return null;
|
|
11931
|
-
// if (typeof programStageRef === 'string' && programStageRef.trim()) {
|
|
11932
|
-
// return programStageRef.trim();
|
|
11933
|
-
// }
|
|
11934
|
-
// const candidateId =
|
|
11935
|
-
// programStageRef.id ??
|
|
11936
|
-
// programStageRef.stageId ??
|
|
11937
|
-
// programStageRef.programStageId ??
|
|
11938
|
-
// programStageRef.value?.id ??
|
|
11939
|
-
// null;
|
|
11940
|
-
// return typeof candidateId === 'string' && candidateId.trim()
|
|
11941
|
-
// ? candidateId.trim()
|
|
11942
|
-
// : null;
|
|
11943
|
-
// }
|
|
11944
|
-
// #findStageById(stageId: string): ProgramStage | null {
|
|
11945
|
-
// return (
|
|
11946
|
-
// (this.program.programStages || []).find(
|
|
11947
|
-
// (stage: ProgramStage) => (stage as any)?.id === stageId
|
|
11948
|
-
// ) ?? null
|
|
11949
|
-
// );
|
|
11950
|
-
// }
|
|
11951
|
-
// #mapSectionToFormFields(
|
|
11952
|
-
// stage: ProgramStage,
|
|
11953
|
-
// section: ProgramStageSection
|
|
11954
|
-
// ): IFormField<string>[] {
|
|
11955
|
-
// const stageDataElements: any[] =
|
|
11956
|
-
// (stage as any).programStageDataElements || [];
|
|
11957
|
-
// const sectionElementIds: string[] =
|
|
11958
|
-
// (section as any).dataElements?.map((d: { id: string }) => d.id) ??
|
|
11959
|
-
// (section as any).dataElementsIds ??
|
|
11960
|
-
// [];
|
|
11961
|
-
// const relevantStageElements = sectionElementIds.length
|
|
11962
|
-
// ? stageDataElements.filter((pde) =>
|
|
11963
|
-
// sectionElementIds.includes(pde?.dataElement?.id)
|
|
11964
|
-
// )
|
|
11965
|
-
// : stageDataElements;
|
|
11966
|
-
// const mappedFields = relevantStageElements
|
|
11967
|
-
// .map((pde) => this.#mapDataElementToFormField(pde, stage.id))
|
|
11968
|
-
// .filter((field): field is IFormField<string> => field != null)
|
|
11969
|
-
// .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
11970
|
-
// return mappedFields;
|
|
11971
|
-
// }
|
|
11972
|
-
// #mapDataElementToFormField(
|
|
11973
|
-
// pde: any,
|
|
11974
|
-
// stageId: string
|
|
11975
|
-
// ): IFormField<string> | null {
|
|
11976
|
-
// const dataElement = pde?.dataElement;
|
|
11977
|
-
// if (!dataElement?.id) return null;
|
|
11978
|
-
// const baseField = {
|
|
11979
|
-
// id: dataElement.id,
|
|
11980
|
-
// code: dataElement.code,
|
|
11981
|
-
// formName: dataElement.formName,
|
|
11982
|
-
// name: dataElement.displayName,
|
|
11983
|
-
// mandatory: !!pde.compulsory,
|
|
11984
|
-
// valueType: dataElement.valueType,
|
|
11985
|
-
// sortOrder: pde.sortOrder,
|
|
11986
|
-
// stepId: stageId,
|
|
11987
|
-
// optionSet: dataElement.optionSet,
|
|
11988
|
-
// };
|
|
11989
|
-
// const options = FieldDropdown.getDropdownOptions(baseField);
|
|
11990
|
-
// const hasOptions = options?.length > 0;
|
|
11991
|
-
// const fieldExtension = this.config.formFieldExtensions?.find(
|
|
11992
|
-
// (fx: any) => fx?.id === baseField.id
|
|
11993
|
-
// );
|
|
11994
|
-
// const autoAssignedValue = this.#getAutoAssignedValue(baseField);
|
|
11995
|
-
// if (
|
|
11996
|
-
// !isUndefined(autoAssignedValue) &&
|
|
11997
|
-
// this.config.hideCustomAssignedFields
|
|
11998
|
-
// ) {
|
|
11999
|
-
// return null;
|
|
12000
|
-
// }
|
|
12001
|
-
// return new FormField<string>({
|
|
12002
|
-
// ...baseField,
|
|
12003
|
-
// label: baseField.formName || baseField.name,
|
|
12004
|
-
// key: baseField.code ? camelCase(baseField.code) : baseField.id,
|
|
12005
|
-
// required: baseField.mandatory,
|
|
12006
|
-
// type: FieldUtil.getFieldType(baseField.valueType),
|
|
12007
|
-
// options,
|
|
12008
|
-
// disabled: this.#getDisabledStatus(baseField),
|
|
12009
|
-
// order: baseField.sortOrder,
|
|
12010
|
-
// hasOptions,
|
|
12011
|
-
// controlType: FieldUtil.getFieldControlType(
|
|
12012
|
-
// baseField.valueType,
|
|
12013
|
-
// hasOptions
|
|
12014
|
-
// ),
|
|
12015
|
-
// extension: fieldExtension,
|
|
12016
|
-
// });
|
|
12017
|
-
// }
|
|
12018
|
-
// #getAutoAssignedValue(field: any): unknown {
|
|
12019
|
-
// const impl = (this as any)?.['#getAutoAssignedValue'];
|
|
12020
|
-
// return typeof impl === 'function' ? impl.call(this, field) : undefined;
|
|
12021
|
-
// }
|
|
12022
|
-
// #getDisabledStatus(field: any): boolean {
|
|
12023
|
-
// const impl = (this as any)?.['#getDisabledStatus'];
|
|
12024
|
-
// return typeof impl === 'function' ? impl.call(this, field) : false;
|
|
12025
|
-
// }
|
|
12026
|
-
// }
|
|
12027
11993
|
class ProgramStageEntryFormSectionUtil {
|
|
12028
11994
|
#sortedCanonicalStageFieldsCache = null;
|
|
12029
11995
|
constructor(program, config) {
|
|
@@ -12136,6 +12102,7 @@ class ProgramStageEntryFormSectionUtil {
|
|
|
12136
12102
|
valueType: dataElementDefinition.valueType,
|
|
12137
12103
|
sortOrder: programStageDataElement.sortOrder,
|
|
12138
12104
|
stepId: programStageId,
|
|
12105
|
+
allowFutureDate: programStageDataElement.allowFutureDate,
|
|
12139
12106
|
optionSet: dataElementDefinition.optionSet,
|
|
12140
12107
|
};
|
|
12141
12108
|
const dropdownOptions = FieldDropdown.getDropdownOptions(fieldBaseConfig);
|