@iapps/ng-dhis2-ui 1.2.146 → 1.2.153

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.
@@ -3838,37 +3838,273 @@ const DropdownMenu$1 = (props) => {
3838
3838
  } }))));
3839
3839
  };
3840
3840
 
3841
- // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
3842
- // Use of this source code is governed by a BSD-style
3843
- // license that can be found in the LICENSE file.
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
- switch (actionOptionOrientation) {
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, actionOptions.map((option) => (React__default.createElement(Button$1, { key: option.label, onClick: () => onClick(option), icon: option.icon ? React__default.createElement(option.icon, null) : React__default.createElement(React__default.Fragment, null), small: true, destructive: option.destructive }, !option.iconOnly ? option.label : '')))));
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: actionOptions, onClick: (option) => {
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: option.destructive ? colors$1.red700 : colors$1.grey900,
3866
- }, key: option.label, onClick: (event) => {
4101
+ color: action.destructive ? colors$1.red700 : colors$1.grey900,
4102
+ }, onClick: (event) => {
3867
4103
  event.stopPropagation();
3868
- onClick(option);
4104
+ onActionClick(action);
3869
4105
  } },
3870
- option.icon ? React__default.createElement(option.icon, null) : React__default.createElement(React__default.Fragment, null),
3871
- !option.iconOnly ? React__default.createElement("span", null, option.label) : React__default.createElement(React__default.Fragment, null))))));
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
  }
@@ -8678,6 +8930,9 @@ class BaseFormFieldComponent extends ReactWrapperModule {
8678
8930
  setDisabled(baseDisabled || cascadeDisable);
8679
8931
  // filter options
8680
8932
  const nextOptions = FieldCascadeUtil.filterChildOptionsByParentPath(field.options ?? [], cascade, parentStr);
8933
+ // console.log("NOEW PARENT STR::: ", JSON.stringify(parentStr));
8934
+ // console.log("NOEW FIELD OPTIONS::: ", JSON.stringify(field.options));
8935
+ // console.log("NOEW PARENT CASCADE::: ", JSON.stringify(cascade));
8681
8936
  setFilteredOptions(nextOptions);
8682
8937
  // clear invalid child on parent change if configured
8683
8938
  if (merged.clearOnParentChange && reason === 'parentChange') {
@@ -11464,78 +11719,84 @@ class ProgramEntryFormFieldUtil {
11464
11719
  });
11465
11720
  }
11466
11721
  // #getGeometryField(): IFormField<string> | null {
11467
- // const rawFeatureType = this.program?.featureType ?? '';
11468
- // console.log(
11469
- // 'REACHED HERE AND FEATURE TYPE ACTIVATED::: ',
11470
- // JSON.stringify(rawFeatureType)
11471
- // );
11472
- // const featureType = rawFeatureType.toUpperCase() as
11722
+ // if (this.config?.hideGeometryField) return null;
11723
+ // const effectiveFeatureTypeRaw = this.#resolveEffectiveFeatureType();
11724
+ // const normalizedFeatureType = effectiveFeatureTypeRaw.toUpperCase() as
11473
11725
  // | 'NONE'
11474
11726
  // | 'POINT'
11475
11727
  // | 'POLYGON'
11476
11728
  // | 'MULTI_POLYGON'
11477
11729
  // | '';
11478
- // const isGeometryProgram =
11479
- // featureType === 'POINT' ||
11480
- // featureType === 'POLYGON' ||
11481
- // featureType === 'MULTI_POLYGON';
11482
- // if (!isGeometryProgram) {
11483
- // if (this.config?.hideGeometryField) {
11484
- // return null;
11485
- // }
11486
- // return null;
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)';
11730
+ // const supportsGeometry =
11731
+ // normalizedFeatureType === 'POINT' ||
11732
+ // normalizedFeatureType === 'POLYGON' ||
11733
+ // normalizedFeatureType === 'MULTI_POLYGON';
11734
+ // if (!supportsGeometry) return null;
11735
+ // const geometryFieldLabel =
11736
+ // normalizedFeatureType === 'POINT'
11737
+ // ? 'Location (coordinates)'
11738
+ // : 'Boundary (polygon)';
11495
11739
  // return new FormField<string>({
11496
11740
  // id: 'geometry',
11497
11741
  // key: 'geometry',
11498
- // label,
11499
11742
  // code: 'geometry',
11743
+ // label: geometryFieldLabel,
11500
11744
  // controlType: 'coordinate',
11501
- // ...sharedOptions,
11745
+ // required: true,
11746
+ // disabled: this.config?.disableGeometryField ?? false,
11747
+ // isGeometryField: true,
11502
11748
  // });
11503
11749
  // }
11504
11750
  #getGeometryField() {
11505
- if (this.config?.hideGeometryField)
11751
+ // Hide by default unless explicitly enabled
11752
+ if (this.config?.hideGeometryField !== false)
11506
11753
  return null;
11507
- const effectiveFeatureTypeRaw = this.#resolveEffectiveFeatureType();
11508
- const normalizedFeatureType = effectiveFeatureTypeRaw.toUpperCase();
11509
- const supportsGeometry = normalizedFeatureType === 'POINT' ||
11510
- normalizedFeatureType === 'POLYGON' ||
11511
- normalizedFeatureType === 'MULTI_POLYGON';
11754
+ const featureType = this.#resolveEffectiveFeatureType().toUpperCase();
11755
+ const supportsGeometry = featureType === 'POINT' ||
11756
+ featureType === 'POLYGON' ||
11757
+ featureType === 'MULTI_POLYGON';
11512
11758
  if (!supportsGeometry)
11513
11759
  return null;
11514
- const geometryFieldLabel = normalizedFeatureType === 'POINT'
11515
- ? 'Location (coordinates)'
11516
- : 'Boundary (polygon)';
11760
+ const label = featureType === 'POINT' ? 'Location (coordinates)' : 'Boundary (polygon)';
11517
11761
  return new FormField({
11518
11762
  id: 'geometry',
11519
11763
  key: 'geometry',
11520
11764
  code: 'geometry',
11521
- label: geometryFieldLabel,
11765
+ label,
11522
11766
  controlType: 'coordinate',
11523
11767
  required: true,
11524
- disabled: this.config?.disableRegistrationUnit ?? false,
11768
+ disabled: this.config?.disableGeometryField ?? false,
11525
11769
  isGeometryField: true,
11526
11770
  });
11527
11771
  }
11772
+ // #resolveEffectiveFeatureType(): string {
11773
+ // const programMeta = this.program;
11774
+ // const configuredProgramStageId = this.config?.programStage;
11775
+ // if (configuredProgramStageId && programMeta?.programStages?.length) {
11776
+ // const configuredStage = programMeta.programStages.find(
11777
+ // (stage: ProgramStage) => stage?.id === configuredProgramStageId
11778
+ // );
11779
+ // const stageFeatureTypeRaw = configuredStage?.featureType ?? '';
11780
+ // if (stageFeatureTypeRaw) return String(stageFeatureTypeRaw);
11781
+ // }
11782
+ // const programFeatureTypeRaw = (programMeta as Program)?.featureType ?? '';
11783
+ // return String(programFeatureTypeRaw);
11784
+ // }
11528
11785
  #resolveEffectiveFeatureType() {
11529
11786
  const programMeta = this.program;
11530
- const configuredProgramStageId = this.config?.programStage;
11531
- if (configuredProgramStageId && programMeta?.programStages?.length) {
11532
- const configuredStage = programMeta.programStages.find((stage) => stage?.id === configuredProgramStageId);
11533
- const stageFeatureTypeRaw = configuredStage?.featureType ?? '';
11534
- if (stageFeatureTypeRaw)
11535
- return String(stageFeatureTypeRaw);
11536
- }
11537
- const programFeatureTypeRaw = programMeta?.featureType ?? '';
11538
- return String(programFeatureTypeRaw);
11787
+ if (!programMeta)
11788
+ return '';
11789
+ const configuredStageId = this.config?.programStage;
11790
+ if (configuredStageId && Array.isArray(programMeta.programStages)) {
11791
+ const stage = programMeta.programStages.find((s) => s?.id === configuredStageId);
11792
+ const stageFeatureType = String(stage?.featureType ?? '').trim();
11793
+ if (stageFeatureType) {
11794
+ return stageFeatureType;
11795
+ }
11796
+ }
11797
+ // 2) Fallback to program (enrollment-level) featureType
11798
+ const programFeatureType = String(programMeta?.featureType ?? '').trim();
11799
+ return programFeatureType;
11539
11800
  }
11540
11801
  #getEnrollmentDateField() {
11541
11802
  if (this.config.hideEnrollmentDate || this.config.programStage) {