diff --git a/hat/assets/js/apps/Iaso/domains/dataSources/components/ExportToDHIS2Dialog.js b/hat/assets/js/apps/Iaso/domains/dataSources/components/ExportToDHIS2Dialog.js index c28bcdeca0..00145cdf4c 100644 --- a/hat/assets/js/apps/Iaso/domains/dataSources/components/ExportToDHIS2Dialog.js +++ b/hat/assets/js/apps/Iaso/domains/dataSources/components/ExportToDHIS2Dialog.js @@ -1,34 +1,34 @@ -import React, { useCallback, useRef, useEffect, useState } from 'react'; -import { string, number, object, arrayOf, func } from 'prop-types'; -import { Grid, Box, Divider, Typography } from '@mui/material'; +import { Box, Divider, Grid, Typography } from '@mui/material'; import { makeStyles } from '@mui/styles'; import { LoadingSpinner, useSafeIntl } from 'bluesquare-components'; +import { arrayOf, func, number, object, string } from 'prop-types'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import ConfirmCancelDialogComponent from '../../../components/dialogs/ConfirmCancelDialogComponent'; import InputComponent from '../../../components/forms/InputComponent.tsx'; +import { ModalSubTitle } from '../../../components/forms/ModalSubTitle'; import { useFormState } from '../../../hooks/form'; -import MESSAGES from '../messages'; -import { - useDataSourceVersions, - useOrgUnitTypes, - postToDHIS2, - csvPreview, - useDataSourceForVersion, -} from '../requests'; +import { useSnackMutation } from '../../../libs/apiHooks.ts'; import { commaSeparatedIdsToArray, commaSeparatedIdsToStringArray, convertFormStateToDict, } from '../../../utils/forms'; +import { useGetValidationStatus } from '../../forms/hooks/useGetValidationStatus.ts'; import { OrgUnitTreeviewModal } from '../../orgUnits/components/TreeView/OrgUnitTreeviewModal'; -import { ModalSubTitle } from '../../../components/forms/ModalSubTitle'; +import MESSAGES from '../messages'; +import { + csvPreview, + postToDHIS2, + useDataSourceForVersion, + useDataSourceVersions, + useOrgUnitTypes, +} from '../requests'; import { - useFieldsToExport, FIELDS_TO_EXPORT, dataSourceVersionsAsOptions, + useFieldsToExport, versionsAsOptionsWithSourceName, } from '../utils'; -import { useSnackMutation } from '../../../libs/apiHooks.ts'; -import { useGetValidationStatus } from '../../forms/hooks/useGetValidationStatus.ts'; const style = theme => ({ noCreds: { diff --git a/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSourceVersion.ts b/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSourceVersion.ts new file mode 100644 index 0000000000..ab3aaadb8b --- /dev/null +++ b/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSourceVersion.ts @@ -0,0 +1,28 @@ +/* eslint-disable camelcase */ +import { UseQueryResult } from 'react-query'; +import { getRequest } from '../../../libs/Api'; +import { useSnackQuery } from '../../../libs/apiHooks'; +import { Version } from '../types/dataSources'; + +const getDataSourceVersion = async ( + version: string | undefined, +): Promise => { + return getRequest(`/api/sourceversions/${version}/`); +}; + +export const useGetDataSourceVersion = ( + versionId: string | undefined, +): UseQueryResult => { + const queryKey: any[] = ['sourceVersions', versionId]; + return useSnackQuery({ + queryKey, + queryFn: () => getDataSourceVersion(versionId), + snackErrorMsg: undefined, + options: { + staleTime: 60000, + cacheTime: 1000 * 60 * 5, + keepPreviousData: true, + enabled: !!versionId, + }, + }); +}; diff --git a/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSources.ts b/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSources.ts index 46f56d9c05..033c8282bf 100644 --- a/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSources.ts +++ b/hat/assets/js/apps/Iaso/domains/dataSources/hooks/useGetDataSources.ts @@ -22,6 +22,7 @@ export const useGetDataSource = ( staleTime: 60000, cacheTime: 1000 * 60 * 5, keepPreviousData: true, + enabled: !!sourceId, }, }); }; diff --git a/hat/assets/js/apps/Iaso/domains/dataSources/types/dataSources.ts b/hat/assets/js/apps/Iaso/domains/dataSources/types/dataSources.ts index 59e0591986..e7efa0d52f 100644 --- a/hat/assets/js/apps/Iaso/domains/dataSources/types/dataSources.ts +++ b/hat/assets/js/apps/Iaso/domains/dataSources/types/dataSources.ts @@ -1,3 +1,5 @@ +import { OrgUnitStatus } from '../../orgUnits/types/orgUnit'; + /* eslint-disable camelcase */ export type Project = { name: string; @@ -15,9 +17,14 @@ export type Version = { created_at: string; updated_at: string; org_units_count: number; + data_source_name: string; + data_source: number; + tree_config_status_fields: OrgUnitStatus[]; + is_default: boolean; }; export type DataSource = { + id: number; name: string; read_only: boolean; description: string; @@ -26,4 +33,5 @@ export type DataSource = { projects: Project[]; default_version: Version; credentials: Credentials; + tree_config_status_fields: OrgUnitStatus[]; }; diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/OrgUnitTreeviewModal.tsx b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/OrgUnitTreeviewModal.tsx index 00a2a0fb06..4223d371b2 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/OrgUnitTreeviewModal.tsx +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/OrgUnitTreeviewModal.tsx @@ -9,19 +9,20 @@ import React, { FunctionComponent, useCallback, useEffect, - useMemo, useRef, useState, } from 'react'; import ConfirmCancelDialogComponent from '../../../../components/dialogs/ConfirmCancelDialogComponent'; -import { OrgUnit, OrgUnitStatus } from '../../types/orgUnit'; +import { OrgUnit } from '../../types/orgUnit'; import { getOrgUnitAncestors } from '../../utils'; import { OrgUnitLabel } from '../OrgUnitLabel'; import { OrgUnitTreeviewPicker } from './OrgUnitTreeviewPicker'; -import { SettingsPopper } from './SettingsPopper'; +import { Settings, SettingsPopper } from './SettingsPopper'; +import { SourceDescription } from './SourceDescription'; import { TreeViewLabel } from './TreeViewLabel'; import { MESSAGES } from './messages'; import { getChildrenData, getRootData, searchOrgUnits } from './requests'; +import { DEFAULT_CONFIG, useSourceConfig } from './useSourceConfig'; import { formatInitialSelectedIds, formatInitialSelectedParents, @@ -71,15 +72,10 @@ const OrgUnitTreeviewModal: FunctionComponent = ({ useIcon = false, }) => { const theme = useTheme(); - const [settings, setSettings] = useState({ + const [settings, setSettings] = useState({ displayTypes: true, - // those three need to be prefilled with source config - displayValid: true, - displayRejected: false, - displayNew: false, + statusSettings: DEFAULT_CONFIG, }); - console.log('source', source); - const [selectedOrgUnits, setSelectedOrgUnits] = useState(initialSelection); const [selectedOrgUnitsIds, setSelectedOrgUnitsIds] = useState( @@ -147,23 +143,16 @@ const OrgUnitTreeviewModal: FunctionComponent = ({ }, [selectedOrgUnitsIdsCopy, selectedOrgUnitParentsCopy], ); - - const { displayTypes, displayValid, displayRejected, displayNew } = - settings; - - const validationStatus = useMemo(() => { - return [ - ...(displayValid ? ['VALID'] : []), - ...(displayRejected ? ['REJECTED'] : []), - ...(displayNew ? ['NEW'] : []), - ] as OrgUnitStatus[]; - }, [displayValid, displayRejected, displayNew]); - + const { displayTypes, statusSettings } = settings; + const { sourceSettings, isFetchingSource, sourceInfos } = useSourceConfig( + source, + version, + ); const getRootDataWithSource = useCallback(async () => { const key = version ? 'version' : 'source'; const value = version || source; - return getRootData(value, key, validationStatus); - }, [source, version, validationStatus]); + return getRootData(value, key, statusSettings); + }, [source, version, statusSettings]); const searchOrgUnitsWithSource = useCallback( async (value, count) => { @@ -172,10 +161,10 @@ const OrgUnitTreeviewModal: FunctionComponent = ({ count, source, version, - validationStatus, + statusSettings, }); }, - [source, version, validationStatus], + [source, version, statusSettings], ); const resetSelection = useCallback(() => { @@ -217,6 +206,18 @@ const OrgUnitTreeviewModal: FunctionComponent = ({ resetSelection(); } }, [resetTrigger, hardReset, resetSelection]); + + useEffect(() => { + if (sourceSettings && !isFetchingSource) { + setSettings({ + ...settings, + statusSettings: sourceSettings, + }); + } + // only update status settings if source settings are changed + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isFetchingSource, sourceSettings]); + return ( // @ts-ignore = ({ multiselect={multiselect} placeholder={titleMessage} required={required} - disabled={disabled} + disabled={disabled || isFetchingSource} label={(orgUnit: OrgUnit) => ( = ({ - getChildrenData(id, validationStatus) - } + getChildrenData={id => getChildrenData(id, statusSettings)} getRootData={getRootDataWithSource} label={(orgUnit: OrgUnit) => ( = ({ if (allowedTypes.length === 0) return true; return allowedTypes.includes(item.org_unit_type_id); }} - dependency={validationStatus} - childrenDependency={validationStatus} + dependency={statusSettings} + childrenDependency={statusSettings} /> + + + ); diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SettingsPopper.tsx b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SettingsPopper.tsx index fe305cebe2..bfe38c54e7 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SettingsPopper.tsx +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SettingsPopper.tsx @@ -20,13 +20,12 @@ import React, { useState, } from 'react'; import { SxStyles } from '../../../../types/general'; +import { OrgUnitStatus } from '../../types/orgUnit'; import { MESSAGES } from './messages'; export type Settings = { displayTypes: boolean; - displayValid: boolean; - displayRejected: boolean; - displayNew: boolean; + statusSettings: OrgUnitStatus[]; }; const styles: SxStyles = { @@ -44,12 +43,10 @@ const styles: SxStyles = { position: 'relative', }, }; - -const settingKeys: string[] = [ - 'displayTypes', - 'displayValid', - 'displayRejected', - 'displayNew', +const POSSIBLE_ORG_UNIT_STATUSES: OrgUnitStatus[] = [ + 'VALID', + 'REJECTED', + 'NEW', ]; type Props = { @@ -71,12 +68,31 @@ export const SettingsPopper: FunctionComponent = ({ [anchorEl], ); - const handleChangeSettings = useCallback( - (setting: string) => { - setSettings(prevSettings => ({ - ...prevSettings, - [setting]: !prevSettings[setting], - })); + const handleChangeTypes = useCallback(() => { + setSettings(prevSettings => ({ + ...prevSettings, + displayTypes: !prevSettings.displayTypes, + })); + }, [setSettings]); + + const handleChangeVisibleStatus = useCallback( + (status: OrgUnitStatus) => { + setSettings(prevSettings => { + const currentStatuses = prevSettings.statusSettings; + const statusIndex = currentStatuses.indexOf(status); + if (statusIndex === -1) { + // Status not in array, add it + return { + ...prevSettings, + statusSettings: [...currentStatuses, status], + }; + } + // Status in array, remove it + return { + ...prevSettings, + statusSettings: currentStatuses.filter(s => s !== status), + }; + }); }, [setSettings], ); @@ -107,20 +123,39 @@ export const SettingsPopper: FunctionComponent = ({ }} > - {settingKeys.map(settingKey => ( - + + + } + label={formatMessage(MESSAGES.displayTypes)} + /> + + {POSSIBLE_ORG_UNIT_STATUSES.map(status => ( + - handleChangeSettings(settingKey) + handleChangeVisibleStatus( + status, + ) } color="primary" /> } - label={formatMessage(MESSAGES[settingKey])} + label={formatMessage( + MESSAGES[`display${status}`], + )} /> ))} diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SourceDescription.tsx b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SourceDescription.tsx new file mode 100644 index 0000000000..0cdd1ec5e2 --- /dev/null +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/SourceDescription.tsx @@ -0,0 +1,30 @@ +import { Box, Typography } from '@mui/material'; +import { textPlaceholder, useSafeIntl } from 'bluesquare-components'; +import React, { FunctionComponent } from 'react'; +import { MESSAGES } from './messages'; +import { SourceInfos } from './useSourceConfig'; + +type Props = { + sourceInfos?: SourceInfos; +}; + +export const SourceDescription: FunctionComponent = ({ + sourceInfos, +}) => { + const { formatMessage } = useSafeIntl(); + return ( + + + {formatMessage(MESSAGES.source)}:{' '} + {sourceInfos?.sourceName || textPlaceholder} + {' - '} + {formatMessage(MESSAGES.version)}:{' '} + {sourceInfos?.versionNumber || textPlaceholder} + + + ); +}; diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/messages.ts b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/messages.ts index e4c772c32f..81f3d08af4 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/messages.ts +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/messages.ts @@ -29,18 +29,26 @@ const MESSAGES = defineMessages({ id: 'blsq.treeview.displayTypes', defaultMessage: 'Show organisation unit types', }, - displayValid: { + displayVALID: { id: 'blsq.treeview.displayValid', defaultMessage: 'Show valid organisation unit types', }, - displayRejected: { + displayREJECTED: { id: 'blsq.treeview.displayRejected', defaultMessage: 'Show rejected organisation unit', }, - displayNew: { + displayNEW: { id: 'blsq.treeview.displayNew', defaultMessage: 'Show new organisation unit types', }, + source: { + defaultMessage: 'Source', + id: 'iaso.forms.source', + }, + version: { + defaultMessage: 'Version', + id: 'iaso.label.version', + }, }); export { MESSAGES }; diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/requests.ts b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/requests.ts index c979eaeab3..294ef3ecca 100644 --- a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/requests.ts +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/requests.ts @@ -6,8 +6,8 @@ import { enqueueSnackbar } from '../../../../redux/snackBarsReducer'; import { dispatch } from '../../../../redux/store'; import { OrgUnit, OrgUnitStatus } from '../../types/orgUnit'; -const getValidationStatus = (validationStatus: OrgUnitStatus[]): string => { - return validationStatus +const getValidationStatus = (statusSettings: OrgUnitStatus[]): string => { + return statusSettings .map(status => `&validation_status=${status}`) .join(''); }; @@ -16,12 +16,12 @@ const baseApiUrl = '/api/orgunits/tree/'; export const getChildrenData = async ( id: string, - validationStatus: OrgUnitStatus[], + statusSettings: OrgUnitStatus[], ): Promise => { try { const response = await getRequest( `${baseApiUrl}?parent_id=${id}&ignoreEmptyNames=true${getValidationStatus( - validationStatus, + statusSettings, )}`, ); return response.map((orgUnit: any) => ({ @@ -40,9 +40,9 @@ export const getChildrenData = async ( const makeUrl = ( id?: string | number, type?: string, - validationStatus: OrgUnitStatus[] = ['VALID'], + statusSettings: OrgUnitStatus[] = ['VALID'], ): string => { - const validationStatusString = getValidationStatus(validationStatus); + const validationStatusString = getValidationStatus(statusSettings); let typePrefix; switch (type) { @@ -63,10 +63,10 @@ const makeUrl = ( export const getRootData = async ( id?: string | number, type = 'source', - validationStatus: OrgUnitStatus[] = ['VALID'], + statusSettings: OrgUnitStatus[] = ['VALID'], ): Promise => { try { - const response = await getRequest(makeUrl(id, type, validationStatus)); + const response = await getRequest(makeUrl(id, type, statusSettings)); return response.map((orgUnit: any) => ({ ...orgUnit, id: orgUnit.id.toString(), @@ -83,11 +83,11 @@ export const getRootData = async ( const endpoint = `${baseApiUrl}search`; const search = ( input1: string, - validationStatus: OrgUnitStatus[] = ['VALID'], + statusSettings: OrgUnitStatus[] = ['VALID'], input2?: string | number, type?: string, ): string => { - const validationStatusString = getValidationStatus(validationStatus); + const validationStatusString = getValidationStatus(statusSettings); let typeParam = ''; if (type === 'version') { @@ -106,13 +106,13 @@ const makeSearchUrl = ({ count, source, version, - validationStatus = ['VALID'], + statusSettings = ['VALID'], }: { value: string; count: number; source?: string | number; version?: string | number; - validationStatus?: OrgUnitStatus[]; + statusSettings?: OrgUnitStatus[]; }): string => { let searchType = ''; if (source) { @@ -123,7 +123,7 @@ const makeSearchUrl = ({ const searchId = source || version; return `${endpoint}?${search( value, - validationStatus, + statusSettings, searchId, searchType, )}&${sortingAndPaging(count)}`; @@ -134,13 +134,13 @@ export const searchOrgUnits = async ({ count, source, version, - validationStatus = ['VALID'], + statusSettings = ['VALID'], }: { value: string; count: number; source?: string | number; version?: string | number; - validationStatus?: OrgUnitStatus[]; + statusSettings?: OrgUnitStatus[]; }): Promise => { try { const url = makeSearchUrl({ @@ -148,7 +148,7 @@ export const searchOrgUnits = async ({ count, source, version, - validationStatus, + statusSettings, }); const result = await getRequest(url); return result.results; @@ -175,22 +175,22 @@ export const useGetOrgUnit = ( const getOrgUnits = async ( orgUnitsIds: string[] | string, - validationStatus = 'all', + statusSettings = 'all', ): Promise => { const idsString = Array.isArray(orgUnitsIds) ? orgUnitsIds.join(',') : orgUnitsIds; - const searchParam = `[{"validation_status":"${validationStatus}","search": "ids:${idsString}" }]`; + const searchParam = `[{"validation_status":"${statusSettings}","search": "ids:${idsString}" }]`; return getRequest(`/api/orgunits/?limit=10&searches=${searchParam}`); }; export const useGetMultipleOrgUnits = ( orgUnitsIds: string[] | string, - validationStatus = 'all', + statusSettings = 'all', ): UseQueryResult => { return useSnackQuery({ - queryKey: ['orgunits', orgUnitsIds, validationStatus], - queryFn: () => getOrgUnits(orgUnitsIds, validationStatus), + queryKey: ['orgunits', orgUnitsIds, statusSettings], + queryFn: () => getOrgUnits(orgUnitsIds, statusSettings), options: { enabled: Boolean(orgUnitsIds?.length), select: (data: any) => (data ? data.orgunits : {}), diff --git a/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/useSourceConfig.ts b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/useSourceConfig.ts new file mode 100644 index 0000000000..a0f5207636 --- /dev/null +++ b/hat/assets/js/apps/Iaso/domains/orgUnits/components/TreeView/useSourceConfig.ts @@ -0,0 +1,86 @@ +import { useMemo } from 'react'; +import { User, useCurrentUser } from '../../../../utils/usersUtils'; +import { useGetDataSourceVersion } from '../../../dataSources/hooks/useGetDataSourceVersion'; +import { useGetDataSource } from '../../../dataSources/hooks/useGetDataSources'; +import { OrgUnitStatus } from '../../types/orgUnit'; + +export type SourceInfos = { + sourceName?: string; + sourceId?: number; + versionNumber?: number; + versionId?: number; +}; + +type Config = { + sourceSettings: OrgUnitStatus[]; + isFetchingSource: boolean; + sourceInfos?: SourceInfos; +}; + +export const DEFAULT_CONFIG: OrgUnitStatus[] = ['VALID']; + +export const useSourceConfig = ( + sourceId: number | string | undefined, + versionId: number | string | undefined, +): Config => { + const currentUser: User = useCurrentUser(); + const { data: source, isFetching: isFetchingSource } = useGetDataSource( + sourceId ? `${sourceId}` : undefined, + ); + const { data: version, isFetching: isFetchingVersion } = + useGetDataSourceVersion(versionId ? `${versionId}` : undefined); + return useMemo(() => { + const defaultUserConfig = + currentUser.account.default_version?.data_source + ?.tree_config_status_fields; + + let sourceSettings = DEFAULT_CONFIG; + let sourceInfos: SourceInfos | undefined; + if (sourceId && source && !isFetchingSource) { + if (source?.tree_config_status_fields?.length > 0) { + sourceSettings = source.tree_config_status_fields; + } + sourceInfos = { + sourceName: source.name, + sourceId: source.id, + versionNumber: source.default_version?.number, + versionId: source.default_version?.id, + }; + } else if (versionId && version && !isFetchingVersion) { + if (version?.tree_config_status_fields?.length > 0) { + sourceSettings = version.tree_config_status_fields; + } + sourceInfos = { + sourceName: version.data_source_name, + sourceId: version.data_source, + versionNumber: version.number, + versionId: version.id, + }; + } else if (!sourceId && !versionId && defaultUserConfig) { + if (defaultUserConfig?.length > 0) { + sourceSettings = defaultUserConfig; + } + const defaultVersion = currentUser.account.default_version; + sourceInfos = { + sourceName: defaultVersion?.data_source?.name, + sourceId: defaultVersion?.data_source?.id, + versionNumber: defaultVersion?.number, + versionId: defaultVersion?.id, + }; + } + + return { + sourceSettings, + isFetchingSource, + sourceInfos, + }; + }, [ + currentUser.account.default_version, + sourceId, + source, + isFetchingSource, + versionId, + version, + isFetchingVersion, + ]); +}; diff --git a/hat/assets/js/apps/Iaso/utils/usersUtils.ts b/hat/assets/js/apps/Iaso/utils/usersUtils.ts index cfca2e3b4d..564362ead4 100644 --- a/hat/assets/js/apps/Iaso/utils/usersUtils.ts +++ b/hat/assets/js/apps/Iaso/utils/usersUtils.ts @@ -1,5 +1,6 @@ /* eslint-disable camelcase */ import { useSelector } from 'react-redux'; +import { OrgUnitStatus } from '../domains/orgUnits/types/orgUnit'; import { Project } from '../domains/projects/types/project'; export type Profile = { @@ -31,6 +32,7 @@ export type DataSource = { updated_at: number; org_units_count: number; }[]; + tree_config_status_fields: OrgUnitStatus[]; }; export type DefaultVersion = { diff --git a/iaso/api/source_versions.py b/iaso/api/source_versions.py index 911531595a..b92796ce4e 100644 --- a/iaso/api/source_versions.py +++ b/iaso/api/source_versions.py @@ -1,14 +1,14 @@ from django.http import HttpResponse -from rest_framework import serializers, permissions +from rest_framework import permissions, serializers from rest_framework.decorators import action from rest_framework.response import Response -from iaso.models import DataSource -from iaso.models import SourceVersion -from .common import ModelViewSet, CONTENT_TYPE_CSV, HasPermission +from hat.menupermissions import models as permission +from iaso.models import DataSource, SourceVersion + +from .common import CONTENT_TYPE_CSV, HasPermission, ModelViewSet from .source_versions_serializers import DiffSerializer, ExportSerializer from .tasks import TaskSerializer -from hat.menupermissions import models as permission class SourceVersionSerializer(serializers.ModelSerializer): @@ -29,6 +29,10 @@ class SourceVersionSerializer(serializers.ModelSerializer): def get_is_default(self, source_version: SourceVersion) -> bool: return source_version.data_source.default_version == source_version + tree_config_status_fields = serializers.ListField( + child=serializers.CharField(), source="data_source.tree_config_status_fields", read_only=True + ) + class Meta: model = SourceVersion fields = [ @@ -41,6 +45,7 @@ class Meta: "data_source_name", "is_default", "org_units_count", + "tree_config_status_fields", ] def validate_data_source(self, value): diff --git a/iaso/models/data_source.py b/iaso/models/data_source.py index c5fada5c66..57d500eb8a 100644 --- a/iaso/models/data_source.py +++ b/iaso/models/data_source.py @@ -54,6 +54,7 @@ def as_dict(self): "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "versions": [v.as_dict_without_data_source() for v in versions], + "tree_config_status_fields": self.tree_config_status_fields, } def as_list(self):