@iapps/ng-dhis2-ui 1.1.65 → 1.1.66
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 +169 -26
- package/fesm2022/iapps-ng-dhis2-ui.mjs.map +1 -1
- package/lib/modules/line-list/containers/line-list.component.d.ts +2 -1
- package/lib/modules/line-list/models/line-list.models.d.ts +24 -5
- package/lib/modules/line-list/utils/line-list-utils.d.ts +1 -1
- package/package.json +1 -1
|
@@ -3300,7 +3300,9 @@ class LineListService {
|
|
|
3300
3300
|
this.httpClient = httpClient;
|
|
3301
3301
|
}
|
|
3302
3302
|
getProgramMetadata(programId) {
|
|
3303
|
-
return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name
|
|
3303
|
+
return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name,shortName,formName,code,optionSetValue,valueType,
|
|
3304
|
+
optionSet[id,name,options[id,name,code]]]]],programTrackedEntityAttributes[*,trackedEntityAttribute[id,name,unique,generated,formName,code,optionSetValue
|
|
3305
|
+
,valueType,optionSet[id,name,options[id,name,code]]]]`);
|
|
3304
3306
|
}
|
|
3305
3307
|
// private getTrackedEntityInstances(
|
|
3306
3308
|
// programId: string,
|
|
@@ -3353,7 +3355,6 @@ class LineListService {
|
|
|
3353
3355
|
// **Step 1:** Extract unique orgUnits from enrollments
|
|
3354
3356
|
const uniqueOrgUnitIds = new Set();
|
|
3355
3357
|
if (response && response.trackedEntities) {
|
|
3356
|
-
console.log('THIS IS HERE', JSON.stringify(response));
|
|
3357
3358
|
response.trackedEntities.forEach((tei) => {
|
|
3358
3359
|
tei.enrollments?.forEach((enrollment) => {
|
|
3359
3360
|
if (enrollment.program === programId) {
|
|
@@ -3470,25 +3471,151 @@ const getProgramStageData = (response, programStageId, pager) => {
|
|
|
3470
3471
|
});
|
|
3471
3472
|
return { columns: entityColumns, data: dataElementsData };
|
|
3472
3473
|
};
|
|
3473
|
-
const getTrackedEntityData = (
|
|
3474
|
+
// export const getTrackedEntityData = (
|
|
3475
|
+
// response: LineListResponse,
|
|
3476
|
+
// programId: string,
|
|
3477
|
+
// pager: any,
|
|
3478
|
+
// isOptionSetNameVisible: boolean,
|
|
3479
|
+
// filters?: FilterConfig[]
|
|
3480
|
+
// ): {
|
|
3481
|
+
// columns: ColumnDefinition[];
|
|
3482
|
+
// data: TableRow[];
|
|
3483
|
+
// filteredEntityColumns: ColumnDefinition[];
|
|
3484
|
+
// } => {
|
|
3485
|
+
// let teis =
|
|
3486
|
+
// (response.data as TrackedEntityResponse)?.trackedEntities ??
|
|
3487
|
+
// (response.data as TrackedEntityResponse)?.instances ??
|
|
3488
|
+
// [];
|
|
3489
|
+
// const programMetaData = response.metadata.programTrackedEntityAttributes;
|
|
3490
|
+
// // //organisation units from metadata
|
|
3491
|
+
// // let orgUnitsFromMetaData = response.metadata.organisationUnits;
|
|
3492
|
+
// // //a Map to efficiently look up orgUnit names by ID
|
|
3493
|
+
// // const orgUnitMap = new Map<string, string>(
|
|
3494
|
+
// // orgUnitsFromMetaData.map((ou: { id: string; name: string }) => [
|
|
3495
|
+
// // ou.id,
|
|
3496
|
+
// // ou.name,
|
|
3497
|
+
// // ])
|
|
3498
|
+
// // );
|
|
3499
|
+
// const orgUnitMap = (response.data as TrackedEntityResponse).orgUnitsMap;
|
|
3500
|
+
// const mappedProgramMetadataAttributes = programMetaData.map((attr) => ({
|
|
3501
|
+
// displayInList: attr.displayInList,
|
|
3502
|
+
// searchable: attr.searchable,
|
|
3503
|
+
// id: attr.trackedEntityAttribute.id,
|
|
3504
|
+
// }));
|
|
3505
|
+
// const programAttributesMap = programMetaData.reduce(
|
|
3506
|
+
// (acc: { [key: string]: string }, attribute: any) => {
|
|
3507
|
+
// if (attribute.displayInList) {
|
|
3508
|
+
// acc[attribute.id] = attribute.displayName;
|
|
3509
|
+
// }
|
|
3510
|
+
// return acc;
|
|
3511
|
+
// },
|
|
3512
|
+
// {}
|
|
3513
|
+
// );
|
|
3514
|
+
// if (filters) {
|
|
3515
|
+
// teis = getFilteredTrackedEntites(teis, filters);
|
|
3516
|
+
// }
|
|
3517
|
+
// const allAttributes = new Set<string>();
|
|
3518
|
+
// teis.forEach((tei: any) => {
|
|
3519
|
+
// const matchingEnrollment = tei.enrollments.find(
|
|
3520
|
+
// (enrollment: any) => enrollment.program === programId
|
|
3521
|
+
// );
|
|
3522
|
+
// const attributes = matchingEnrollment
|
|
3523
|
+
// ? matchingEnrollment.attributes
|
|
3524
|
+
// : tei.attributes;
|
|
3525
|
+
// attributes.forEach((attr: any) => allAttributes.add(attr.attribute));
|
|
3526
|
+
// });
|
|
3527
|
+
// let entityColumns = Array.from(allAttributes).map((attrId: string) => {
|
|
3528
|
+
// const foundAttribute = teis
|
|
3529
|
+
// .flatMap((tei: any) => {
|
|
3530
|
+
// const matchingEnrollment = tei.enrollments.find(
|
|
3531
|
+
// (enrollment: any) => enrollment.program === programId
|
|
3532
|
+
// );
|
|
3533
|
+
// return matchingEnrollment
|
|
3534
|
+
// ? matchingEnrollment.attributes
|
|
3535
|
+
// : tei.attributes;
|
|
3536
|
+
// })
|
|
3537
|
+
// .find((attr: any) => attr.attribute === attrId);
|
|
3538
|
+
// return {
|
|
3539
|
+
// label: foundAttribute?.displayName || attrId,
|
|
3540
|
+
// key: attrId,
|
|
3541
|
+
// };
|
|
3542
|
+
// });
|
|
3543
|
+
// entityColumns = entityColumns.filter((column) => {
|
|
3544
|
+
// // Check if the column label is part of any value in programAttributesMap
|
|
3545
|
+
// return Object.values(programAttributesMap).some((value: string) =>
|
|
3546
|
+
// value.includes(column.label)
|
|
3547
|
+
// );
|
|
3548
|
+
// });
|
|
3549
|
+
// // Add orgUnit as the first column
|
|
3550
|
+
// entityColumns.unshift({
|
|
3551
|
+
// label: 'Location',
|
|
3552
|
+
// key: 'orgUnit',
|
|
3553
|
+
// });
|
|
3554
|
+
// const searchableAttributes = mappedProgramMetadataAttributes
|
|
3555
|
+
// .filter((attr) => attr.searchable && attr.displayInList)
|
|
3556
|
+
// .map((attr) => ({
|
|
3557
|
+
// // label: attr.trackedEntityAttribute.displayName,
|
|
3558
|
+
// key: attr.id,
|
|
3559
|
+
// }));
|
|
3560
|
+
// // Extract keys from searchableAttributes for quick lookup
|
|
3561
|
+
// const searchableKeys = new Set(searchableAttributes.map((attr) => attr.key));
|
|
3562
|
+
// // Filter entityColumns to keep only those whose key exists in searchableAttributes
|
|
3563
|
+
// const filteredEntityColumns = entityColumns.filter((column) =>
|
|
3564
|
+
// searchableKeys.has(column.key)
|
|
3565
|
+
// );
|
|
3566
|
+
// const attributesData = teis.map((tei: any, idx: number) => {
|
|
3567
|
+
// const row: TableRow = {
|
|
3568
|
+
// trackedEntityInstance: tei.trackedEntity,
|
|
3569
|
+
// index: (pager.page - 1) * pager.pageSize + idx + 1,
|
|
3570
|
+
// };
|
|
3571
|
+
// allAttributes.forEach((attrId: string) => (row[attrId] = ''));
|
|
3572
|
+
// const matchingEnrollment = tei.enrollments.find(
|
|
3573
|
+
// (enrollment: any) => enrollment.program === programId
|
|
3574
|
+
// );
|
|
3575
|
+
// const attributesToUse = matchingEnrollment
|
|
3576
|
+
// ? matchingEnrollment.attributes
|
|
3577
|
+
// : tei.attributes;
|
|
3578
|
+
// console.log('RESPONSE::: ', JSON.stringify(attributesToUse));
|
|
3579
|
+
// console.log('HERE WEARE', JSON.stringify(response.metadata));
|
|
3580
|
+
// if (isOptionSetNameVisible) {
|
|
3581
|
+
// attributesToUse.forEach(
|
|
3582
|
+
// (attr: any) => (row[attr.attribute] = attr.value)
|
|
3583
|
+
// );
|
|
3584
|
+
// } else {
|
|
3585
|
+
// attributesToUse.forEach(
|
|
3586
|
+
// (attr: any) => (row[attr.attribute] = attr.value)
|
|
3587
|
+
// );
|
|
3588
|
+
// }
|
|
3589
|
+
// //include orgUnit in the row for id access
|
|
3590
|
+
// row['orgUnitId'] = matchingEnrollment.orgUnit;
|
|
3591
|
+
// // Access the name of the orgUnit using the Map
|
|
3592
|
+
// // row['orgUnit'] = matchingEnrollment.orgUnitName;
|
|
3593
|
+
// row['orgUnit'] = orgUnitMap?.get(matchingEnrollment.orgUnit) || 'N/A';
|
|
3594
|
+
// // row['orgUnit'] =
|
|
3595
|
+
// // orgUnitMap && orgUnitMap[matchingEnrollment.orgUnit]
|
|
3596
|
+
// // ? orgUnitMap[matchingEnrollment.orgUnit]
|
|
3597
|
+
// // : 'N/A';
|
|
3598
|
+
// return row;
|
|
3599
|
+
// });
|
|
3600
|
+
// return {
|
|
3601
|
+
// columns: entityColumns,
|
|
3602
|
+
// data: attributesData,
|
|
3603
|
+
// filteredEntityColumns: filteredEntityColumns,
|
|
3604
|
+
// };
|
|
3605
|
+
// };
|
|
3606
|
+
const getTrackedEntityData = (response, programId, pager, isOptionSetNameVisible, filters) => {
|
|
3474
3607
|
let teis = response.data?.trackedEntities ??
|
|
3475
3608
|
response.data?.instances ??
|
|
3476
3609
|
[];
|
|
3477
3610
|
const programMetaData = response.metadata.programTrackedEntityAttributes;
|
|
3478
|
-
// //organisation units from metadata
|
|
3479
|
-
// let orgUnitsFromMetaData = response.metadata.organisationUnits;
|
|
3480
|
-
// //a Map to efficiently look up orgUnit names by ID
|
|
3481
|
-
// const orgUnitMap = new Map<string, string>(
|
|
3482
|
-
// orgUnitsFromMetaData.map((ou: { id: string; name: string }) => [
|
|
3483
|
-
// ou.id,
|
|
3484
|
-
// ou.name,
|
|
3485
|
-
// ])
|
|
3486
|
-
// );
|
|
3487
3611
|
const orgUnitMap = response.data.orgUnitsMap;
|
|
3488
3612
|
const mappedProgramMetadataAttributes = programMetaData.map((attr) => ({
|
|
3489
3613
|
displayInList: attr.displayInList,
|
|
3490
3614
|
searchable: attr.searchable,
|
|
3491
3615
|
id: attr.trackedEntityAttribute.id,
|
|
3616
|
+
optionSet: attr.trackedEntityAttribute.optionSetValue
|
|
3617
|
+
? attr.trackedEntityAttribute.optionSet
|
|
3618
|
+
: null,
|
|
3492
3619
|
}));
|
|
3493
3620
|
const programAttributesMap = programMetaData.reduce((acc, attribute) => {
|
|
3494
3621
|
if (attribute.displayInList) {
|
|
@@ -3522,7 +3649,6 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3522
3649
|
};
|
|
3523
3650
|
});
|
|
3524
3651
|
entityColumns = entityColumns.filter((column) => {
|
|
3525
|
-
// Check if the column label is part of any value in programAttributesMap
|
|
3526
3652
|
return Object.values(programAttributesMap).some((value) => value.includes(column.label));
|
|
3527
3653
|
});
|
|
3528
3654
|
// Add orgUnit as the first column
|
|
@@ -3533,12 +3659,9 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3533
3659
|
const searchableAttributes = mappedProgramMetadataAttributes
|
|
3534
3660
|
.filter((attr) => attr.searchable && attr.displayInList)
|
|
3535
3661
|
.map((attr) => ({
|
|
3536
|
-
// label: attr.trackedEntityAttribute.displayName,
|
|
3537
3662
|
key: attr.id,
|
|
3538
3663
|
}));
|
|
3539
|
-
// Extract keys from searchableAttributes for quick lookup
|
|
3540
3664
|
const searchableKeys = new Set(searchableAttributes.map((attr) => attr.key));
|
|
3541
|
-
// Filter entityColumns to keep only those whose key exists in searchableAttributes
|
|
3542
3665
|
const filteredEntityColumns = entityColumns.filter((column) => searchableKeys.has(column.key));
|
|
3543
3666
|
const attributesData = teis.map((tei, idx) => {
|
|
3544
3667
|
const row = {
|
|
@@ -3550,16 +3673,27 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3550
3673
|
const attributesToUse = matchingEnrollment
|
|
3551
3674
|
? matchingEnrollment.attributes
|
|
3552
3675
|
: tei.attributes;
|
|
3553
|
-
|
|
3554
|
-
|
|
3676
|
+
// If option set names are visible, transform the attribute values
|
|
3677
|
+
if (isOptionSetNameVisible) {
|
|
3678
|
+
attributesToUse.forEach((attr) => {
|
|
3679
|
+
const attributeMeta = programMetaData.find((metadata) => metadata.trackedEntityAttribute.id === attr.attribute);
|
|
3680
|
+
// Check if the attribute has an option set and map value to option name
|
|
3681
|
+
if (attributeMeta?.trackedEntityAttribute.optionSetValue) {
|
|
3682
|
+
const optionSet = attributeMeta?.trackedEntityAttribute?.optionSet;
|
|
3683
|
+
const option = optionSet?.options?.find((option) => option.code === attr.value);
|
|
3684
|
+
row[attr.attribute] = option ? option.name : attr.value;
|
|
3685
|
+
}
|
|
3686
|
+
else {
|
|
3687
|
+
row[attr.attribute] = attr.value;
|
|
3688
|
+
}
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
else {
|
|
3692
|
+
attributesToUse.forEach((attr) => (row[attr.attribute] = attr.value));
|
|
3693
|
+
}
|
|
3694
|
+
// Include orgUnit in the row for id access
|
|
3555
3695
|
row['orgUnitId'] = matchingEnrollment.orgUnit;
|
|
3556
|
-
// Access the name of the orgUnit using the Map
|
|
3557
|
-
// row['orgUnit'] = matchingEnrollment.orgUnitName;
|
|
3558
3696
|
row['orgUnit'] = orgUnitMap?.get(matchingEnrollment.orgUnit) || 'N/A';
|
|
3559
|
-
// row['orgUnit'] =
|
|
3560
|
-
// orgUnitMap && orgUnitMap[matchingEnrollment.orgUnit]
|
|
3561
|
-
// ? orgUnitMap[matchingEnrollment.orgUnit]
|
|
3562
|
-
// : 'N/A';
|
|
3563
3697
|
return row;
|
|
3564
3698
|
});
|
|
3565
3699
|
return {
|
|
@@ -3795,6 +3929,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3795
3929
|
this.firstValue = new EventEmitter();
|
|
3796
3930
|
this.filterRootOrgUnit = false;
|
|
3797
3931
|
this.showFilters = false;
|
|
3932
|
+
this.isOptionSetNameVisible = false;
|
|
3798
3933
|
this.setReactStateUpdaters = (updaters) => {
|
|
3799
3934
|
this.reactStateUpdaters = updaters;
|
|
3800
3935
|
};
|
|
@@ -3810,6 +3945,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3810
3945
|
});
|
|
3811
3946
|
const paginationRef = useRef(null);
|
|
3812
3947
|
const [programIdState, setProgramIdState] = useState(this.programId);
|
|
3948
|
+
const [isOptionSetNameVisibleState, setOptionSetNameVisible] = useState(this.isOptionSetNameVisible);
|
|
3813
3949
|
const [orgUnitState, setOrgUnitState] = useState(this.orgUnit);
|
|
3814
3950
|
const [programStageIdState, setProgramStageIdState] = useState(this.programStageId);
|
|
3815
3951
|
const [attributeFiltersState, setAttributeFiltersState] = useState(this.attributeFilters);
|
|
@@ -3838,6 +3974,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3838
3974
|
setStartDateState,
|
|
3839
3975
|
setEndDateState,
|
|
3840
3976
|
setIsButtonLoading,
|
|
3977
|
+
setOptionSetNameVisible
|
|
3841
3978
|
});
|
|
3842
3979
|
useEffect(() => {
|
|
3843
3980
|
this.setReactStateUpdaters?.(updateRefs.current);
|
|
@@ -3866,7 +4003,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3866
4003
|
total: responseData.total,
|
|
3867
4004
|
pageCount: responseData.pageCount,
|
|
3868
4005
|
};
|
|
3869
|
-
const { columns, data, filteredEntityColumns } = getTrackedEntityData(response, this.programId, pager, this.filters);
|
|
4006
|
+
const { columns, data, filteredEntityColumns } = getTrackedEntityData(response, this.programId, pager, this.isOptionSetNameVisible, this.filters);
|
|
3870
4007
|
entityColumns = columns;
|
|
3871
4008
|
entityData = data;
|
|
3872
4009
|
//TODO: Should be done on the parent
|
|
@@ -3910,6 +4047,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3910
4047
|
endDateState,
|
|
3911
4048
|
pager.page,
|
|
3912
4049
|
pager.pageSize,
|
|
4050
|
+
isOptionSetNameVisibleState
|
|
3913
4051
|
]);
|
|
3914
4052
|
const getDropdownOptions = (row) => {
|
|
3915
4053
|
return (this.actionOptions || []).map((option) => ({
|
|
@@ -4076,6 +4214,9 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
4076
4214
|
if (changes['programId']) {
|
|
4077
4215
|
this.reactStateUpdaters.setProgramIdState(this.programId);
|
|
4078
4216
|
}
|
|
4217
|
+
if (changes['isOptionSetNameVisible']) {
|
|
4218
|
+
this.reactStateUpdaters.setOptionSetNameVisible(this.isOptionSetNameVisible);
|
|
4219
|
+
}
|
|
4079
4220
|
if (changes['orgUnit']) {
|
|
4080
4221
|
this.reactStateUpdaters.setOrgUnitState(this.orgUnit);
|
|
4081
4222
|
}
|
|
@@ -4104,7 +4245,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
4104
4245
|
this.render();
|
|
4105
4246
|
}
|
|
4106
4247
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
4107
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "ng-dhis2-ui-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", attributeFilters: "attributeFilters", useOuModeWithOlderDHIS2Instance: "useOuModeWithOlderDHIS2Instance", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected", firstValue: "firstValue" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9FADBA!important;border-radius:4px!important;padding-left:16px}::ng-deep .custom-input input{border:none!important;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::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}\n"] }); }
|
|
4248
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "ng-dhis2-ui-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", attributeFilters: "attributeFilters", useOuModeWithOlderDHIS2Instance: "useOuModeWithOlderDHIS2Instance", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters", isOptionSetNameVisible: "isOptionSetNameVisible" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected", firstValue: "firstValue" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9FADBA!important;border-radius:4px!important;padding-left:16px}::ng-deep .custom-input input{border:none!important;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::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}\n"] }); }
|
|
4108
4249
|
}
|
|
4109
4250
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, decorators: [{
|
|
4110
4251
|
type: Component,
|
|
@@ -4147,6 +4288,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
|
|
|
4147
4288
|
type: Input
|
|
4148
4289
|
}], showFilters: [{
|
|
4149
4290
|
type: Input
|
|
4291
|
+
}], isOptionSetNameVisible: [{
|
|
4292
|
+
type: Input
|
|
4150
4293
|
}] } });
|
|
4151
4294
|
|
|
4152
4295
|
class LineListModule {
|