diff --git a/hat/assets/js/apps/Iaso/constants/urls.ts b/hat/assets/js/apps/Iaso/constants/urls.ts index cfc0ee368e..c6de893d11 100644 --- a/hat/assets/js/apps/Iaso/constants/urls.ts +++ b/hat/assets/js/apps/Iaso/constants/urls.ts @@ -183,6 +183,7 @@ export const baseRouteConfigs: Record = { 'userRoles', 'withLocation', 'projectIds', + 'source_version_id', 'paymentStatus', ...paginationPathParams, 'paymentIds', diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/Filter/ReviewOrgUnitChangesFilter.tsx b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/Filter/ReviewOrgUnitChangesFilter.tsx index a404573b15..8948d42498 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/Filter/ReviewOrgUnitChangesFilter.tsx +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/Filter/ReviewOrgUnitChangesFilter.tsx @@ -1,5 +1,11 @@ -import React, { FunctionComponent, useCallback, useMemo } from 'react'; -import { Box, Grid } from '@mui/material'; +import React, { + FunctionComponent, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; +import { Box, Grid, Typography } from '@mui/material'; import { useSafeIntl } from 'bluesquare-components'; import { FilterButton } from '../../../../components/FilterButton'; import { useFilterState } from '../../../../hooks/useFilterState'; @@ -8,8 +14,6 @@ import { baseUrls } from '../../../../constants/urls'; import MESSAGES from '../messages'; import { OrgUnitTreeviewModal } from '../../components/TreeView/OrgUnitTreeviewModal'; import { useGetOrgUnit } from '../../components/TreeView/requests'; -// IA-3641 uncomment when UI has been refactored to limlit size of API call -// import { useGetGroupDropdown } from '../../hooks/requests/useGetGroups'; import { useGetOrgUnitTypesDropdownOptions } from '../../orgUnitTypes/hooks/useGetOrgUnitTypesDropdownOptions'; import { DropdownOptions } from '../../../../types/utils'; import DatesRange from '../../../../components/filters/DatesRange'; @@ -21,23 +25,44 @@ import { useGetProfilesDropdown } from '../../../instances/hooks/useGetProfilesD import { useGetUserRolesDropDown } from '../../../userRoles/hooks/requests/useGetUserRoles'; import { useGetProjectsDropdownOptions } from '../../../projects/hooks/requests'; import { usePaymentStatusOptions } from '../hooks/api/useGetPaymentStatusOptions'; +import { useGetGroupDropdown } from '../../hooks/requests/useGetGroups'; +import { useGetDataSources } from '../../hooks/requests/useGetDataSources'; +import { useDefaultSourceVersion } from '../../../dataSources/utils'; +import { useGetVersionLabel } from '../../hooks/useGetVersionLabel'; const baseUrl = baseUrls.orgUnitsChangeRequest; -type Props = { params: ApproveOrgUnitParams }; +type Props = { + params: ApproveOrgUnitParams; + selectedVersionId: string; + setSelectedVersionId: (id: string) => void; + dataSource: string; + setDataSource: (id: string) => void; +}; + +const styles = { + advancedSettings: { + color: theme => theme.palette.primary.main, + alignSelf: 'center', + textAlign: 'right', + flex: '1', + cursor: 'pointer', + }, +}; export const ReviewOrgUnitChangesFilter: FunctionComponent = ({ params, + selectedVersionId, + setSelectedVersionId, + dataSource, + setDataSource, }) => { - const { formatMessage } = useSafeIntl(); + const defaultSourceVersion = useDefaultSourceVersion(); + const { filters, handleSearch, handleChange, filtersUpdated } = useFilterState({ baseUrl, params }); + const { data: dataSources, isFetching: isFetchingDataSources } = + useGetDataSources(true); const { data: initialOrgUnit } = useGetOrgUnit(params.parent_id); - // IA-3641 hard coding values fro groups dropdown until refactor - // const { data: groupOptions, isLoading: isLoadingGroups } = - // useGetGroupDropdown({}); - const groupOptions = []; - const isLoadingGroups = false; - // IA-3641 -----END const { data: orgUnitTypeOptions, isLoading: isLoadingTypes } = useGetOrgUnitTypesDropdownOptions(); const { data: forms, isFetching: isLoadingForms } = useGetForms(); @@ -49,6 +74,7 @@ export const ReviewOrgUnitChangesFilter: FunctionComponent = ({ useGetProjectsDropdownOptions(); const { data: paymentStatuses, isFetching: isFetchingPaymentStatuses } = usePaymentStatusOptions(); + const formOptions = useMemo( () => forms?.map(form => ({ @@ -57,6 +83,43 @@ export const ReviewOrgUnitChangesFilter: FunctionComponent = ({ })) || [], [forms], ); + const initialDataSource = useMemo( + () => + dataSources?.find( + source => + source.value === defaultSourceVersion.source.id.toString(), + )?.value || '', + [dataSources, defaultSourceVersion.source.id], + ); + + const [showAdvancedSettings, setShowAdvancedSettings] = useState(false); + const { formatMessage } = useSafeIntl(); + + const { + data: groupOptions, + isLoading: isLoadingGroups, + refetch: refetchGroups, + } = useGetGroupDropdown( + selectedVersionId ? { defaultVersion: selectedVersionId } : {}, + ); + + useEffect(() => { + if (selectedVersionId) { + refetchGroups(); + } + }, [selectedVersionId, refetchGroups]); + + useEffect(() => { + const updatedDataSource = dataSources?.find( + source => + source.value === defaultSourceVersion.source.id.toString(), + )?.value; + + if (updatedDataSource) { + setDataSource(updatedDataSource as unknown as string); + } + }, [dataSources, defaultSourceVersion.source.id, setDataSource]); + const statusOptions: DropdownOptions[] = useMemo( () => [ { @@ -82,6 +145,52 @@ export const ReviewOrgUnitChangesFilter: FunctionComponent = ({ [handleChange], ); + const handleDataSourceVersionChange = useCallback( + (key, newValue) => { + if (key === 'source') { + setDataSource(newValue); + const selectedSource = dataSources?.filter( + source => source.value === newValue, + )[0]; + setSelectedVersionId( + selectedSource?.original?.default_version.id.toString(), + ); + handleChange( + 'source_version_id', + selectedSource?.original?.default_version.id, + ); + } else { + setSelectedVersionId(newValue.toString()); + handleChange('source_version_id', newValue); + } + filters.groups = []; + }, + [ + dataSources, + filters, + handleChange, + setDataSource, + setSelectedVersionId, + ], + ); + + const getVersionLabel = useGetVersionLabel(dataSources); + + const versionsDropDown = useMemo(() => { + if (!dataSources || !dataSource) return []; + return ( + dataSources + .filter( + src => (src.value as unknown as string) === dataSource, + )[0] + ?.original?.versions.sort((a, b) => a.number - b.number) + .map(version => ({ + label: getVersionLabel(version.id), + value: version.id.toString(), + })) ?? [] + ); + }, [dataSource, dataSources, getVersionLabel]); + return ( @@ -117,15 +226,70 @@ export const ReviewOrgUnitChangesFilter: FunctionComponent = ({ options={groupOptions} loading={isLoadingGroups} labelString={formatMessage(MESSAGES.group)} - disabled - helperText={formatMessage(MESSAGES.featureDisabled)} /> + + {!showAdvancedSettings && ( + setShowAdvancedSettings(true)} + > + {formatMessage(MESSAGES.showAdvancedSettings)} + + )} + {showAdvancedSettings && ( + <> + + + + + + setShowAdvancedSettings(false) + } + > + {formatMessage( + MESSAGES.hideAdvancedSettings, + )} + + + + )} + { handleChange('parent_id', orgUnit?.id); }} diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/hooks/api/useGetApprovalProposals.ts b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/hooks/api/useGetApprovalProposals.ts index d01e31f66a..50f9d27dbb 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/hooks/api/useGetApprovalProposals.ts +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/hooks/api/useGetApprovalProposals.ts @@ -34,6 +34,7 @@ export const useGetApprovalProposals = ( projects: params.projectIds, payment_status: params.paymentStatus, payment_ids: params.paymentIds, + source_version_id: params.source_version_id, potential_payment_ids: params.potentialPaymentIds, }; diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/index.tsx b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/index.tsx index c8a28b8859..a20dc549b2 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/index.tsx +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/index.tsx @@ -1,7 +1,7 @@ import { Box } from '@mui/material'; import { makeStyles } from '@mui/styles'; import { commonStyles, getTableUrl, useSafeIntl } from 'bluesquare-components'; -import React, { FunctionComponent, useMemo } from 'react'; +import React, { FunctionComponent, useMemo, useState } from 'react'; import DownloadButtonsComponent from '../../../components/DownloadButtonsComponent'; import TopBar from '../../../components/nav/TopBarComponent'; import { ReviewOrgUnitChangesFilter } from './Filter/ReviewOrgUnitChangesFilter'; @@ -11,6 +11,7 @@ import MESSAGES from './messages'; import { ApproveOrgUnitParams } from './types'; import { useParamsObject } from '../../../routing/hooks/useParamsObject'; import { baseUrls } from '../../../constants/urls'; +import { useDefaultSourceVersion } from '../../dataSources/utils'; /* # Org Unit Change Request @@ -79,6 +80,7 @@ export const ReviewOrgUnitChanges: FunctionComponent = () => { users: params.userIds, user_roles: params.userRoles, with_location: params.withLocation, + source_version_id: params.source_version_id, }), [ params.created_at_after, @@ -87,6 +89,7 @@ export const ReviewOrgUnitChanges: FunctionComponent = () => { params.groups, params.org_unit_type_id, params.parent_id, + params.source_version_id, params.status, params.userIds, params.userRoles, @@ -95,12 +98,26 @@ export const ReviewOrgUnitChanges: FunctionComponent = () => { ); const csv_url = getTableUrl(endPointUrl, csv_params); + const defaultSourceVersion = useDefaultSourceVersion(); + const [selectedVersionId, setSelectedVersionId] = useState( + defaultSourceVersion.version.id.toString(), + ); + const [dataSource, setDataSource] = useState( + defaultSourceVersion.source.id.toString(), + ); + params.source_version_id = selectedVersionId; return (
- + diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/messages.ts b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/messages.ts index 401727049e..a7edcc8072 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/messages.ts +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/messages.ts @@ -221,6 +221,22 @@ const MESSAGES = defineMessages({ id: 'iaso.label.featureDisabled', defaultMessage: 'Feature temporarily disabled', }, + showAdvancedSettings: { + id: 'iaso.form.label.showAdvancedSettings', + defaultMessage: 'Show advanced settings', + }, + hideAdvancedSettings: { + id: 'iaso.form.label.hideAdvancedSettings', + defaultMessage: 'Hide advanced settings', + }, + source: { + defaultMessage: 'Source', + id: 'iaso.orgUnits.source', + }, + sourceVersion: { + id: 'iaso.form.label.sourceVersion', + defaultMessage: 'Source version', + }, }); export default MESSAGES; diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/types.ts b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/types.ts index 7e162e6ecf..7899a6cb0e 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/types.ts +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/reviewChanges/types.ts @@ -19,6 +19,7 @@ export type ApproveOrgUnitParams = UrlParams & { paymentStatus?: 'pending' | 'sent' | 'rejected' | 'paid'; paymentIds?: string; // comma separated ids potentialPaymentIds?: string; // comma separated ids + source_version_id?: string; }; export type OrgUnitChangeRequestDetailParams = UrlParams & { diff --git a/hat/assets/js/cypress/integration/05 - orgUnits/reviewChanges/changeRequest.spec.js b/hat/assets/js/cypress/integration/05 - orgUnits/reviewChanges/changeRequest.spec.js index 678881ca12..f071d98fba 100644 --- a/hat/assets/js/cypress/integration/05 - orgUnits/reviewChanges/changeRequest.spec.js +++ b/hat/assets/js/cypress/integration/05 - orgUnits/reviewChanges/changeRequest.spec.js @@ -539,7 +539,7 @@ describe('Organisations changes', () => { 'have.attr', 'href', // `/api/orgunits/changes/export_to_csv/?&groups=2,3&status=new`, - `/api/orgunits/changes/export_to_csv/?&status=new`, + `/api/orgunits/changes/export_to_csv/?&status=new&source_version_id=3`, ); }); }); diff --git a/iaso/api/groups.py b/iaso/api/groups.py index a7c702e42c..549430aefb 100644 --- a/iaso/api/groups.py +++ b/iaso/api/groups.py @@ -164,12 +164,15 @@ def dropdown(self, request, *args): if user and user.is_authenticated: account = user.iaso_profile.account # Filter on version ids (linked to the account)"" - versions = SourceVersion.objects.filter(data_source__projects__account=account) + default_version = self.request.query_params.get("defaultVersion", account.default_version.id) + versions = SourceVersion.objects.filter(data_source__projects__account=account, pk=default_version) else: # this check if project need auth project = Project.objects.get_for_user_and_app_id(user, app_id) - versions = SourceVersion.objects.filter(data_source__projects=project) + default_version = self.request.query_params.get("defaultVersion", project.account.default_version.id) + versions = SourceVersion.objects.filter(data_source__projects=project, pk=default_version) + groups = Group.objects.filter(source_version__in=versions).distinct() queryset = self.filter_queryset(groups) diff --git a/iaso/api/org_unit_change_requests/filters.py b/iaso/api/org_unit_change_requests/filters.py index 35b1f37fa2..35a7b67877 100644 --- a/iaso/api/org_unit_change_requests/filters.py +++ b/iaso/api/org_unit_change_requests/filters.py @@ -3,6 +3,7 @@ from django.db.models import Q from django.db.models.query import QuerySet from django.utils.translation import gettext_lazy as _ +from iaso.models.data_source import SourceVersion from rest_framework.exceptions import ValidationError from iaso.api.common import parse_comma_separated_numeric_values from iaso.models import OrgUnit, OrgUnitChangeRequest @@ -36,9 +37,11 @@ class OrgUnitChangeRequestListFilter(django_filters.rest_framework.FilterSet): potential_payment_ids = django_filters.CharFilter( method="filter_potential_payments", label=_("Potential Payment IDs (comma-separated)") ) + source_version_id = django_filters.NumberFilter(field_name="org_unit__version", label=_("Source version ID")) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.form.fields["created_at"].fields[0].input_formats = settings.API_DATE_INPUT_FORMATS self.form.fields["created_at"].fields[-1].input_formats = settings.API_DATE_INPUT_FORMATS diff --git a/iaso/api/org_unit_change_requests/views.py b/iaso/api/org_unit_change_requests/views.py index 5c8bc08065..77b0e9a1eb 100644 --- a/iaso/api/org_unit_change_requests/views.py +++ b/iaso/api/org_unit_change_requests/views.py @@ -75,6 +75,7 @@ def get_queryset(self): "old_parent", "new_org_unit_type", "old_org_unit_type", + "org_unit__version", ) .prefetch_related( "org_unit__groups", @@ -88,6 +89,7 @@ def get_queryset(self): ) .exclude_soft_deleted_new_reference_instances() ) + return org_units_change_requests.filter(org_unit__in=org_units) def has_org_unit_permission(self, org_unit_to_change: OrgUnit) -> None: