diff --git a/src/components/Table/ComplexTagTable.tsx b/src/components/Table/ComplexTagTable.tsx index 2220b6c8..1a2281ec 100644 --- a/src/components/Table/ComplexTagTable.tsx +++ b/src/components/Table/ComplexTagTable.tsx @@ -4,16 +4,29 @@ import { Button, Table } from 'react-bootstrap'; import { useAppSelector } from '../../store/hooks'; import { t } from 'i18next'; import { ComplexTagResponse } from '../../features/planSimulation/providers/types'; +import { TagToDelete } from '../../features/tagging/components/ComplexTagging'; +import { useKeycloak } from '@react-keycloak/web'; +import { TAG_ACCESS_OVERRIDE } from '../../constants'; interface Props { columns: { name: string; sortValue?: string; accessor: string; key: string }[]; data: ComplexTagResponse[] | undefined; clickHandler: (identifier: any) => void; showAccessPanelHandler: (tag: any) => void; + setShowDeleteTagPanel: (show: boolean) => void; + setSelectedTagToDelete: (tag: TagToDelete) => void; } //TODO: Complete sorting -const ComplexTagTable = ({ columns, data, clickHandler, showAccessPanelHandler }: Props) => { +const ComplexTagTable = ({ + columns, + data, + clickHandler, + showAccessPanelHandler, + setShowDeleteTagPanel, + setSelectedTagToDelete +}: Props) => { + const { keycloak } = useKeycloak(); const isDarkMode = useAppSelector(state => state.darkMode.value); return ( @@ -36,7 +49,7 @@ const ComplexTagTable = ({ columns, data, clickHandler, showAccessPanelHandler } if (el.accessor) { let val = dataEl[el.accessor]; - if (Array.isArray(val) && val.length) { + if (el.accessor === 'complexTagVariables') { return ( @@ -45,19 +58,52 @@ const ComplexTagTable = ({ columns, data, clickHandler, showAccessPanelHandler } } else if (el.accessor === 'access') { return ( - + {dataEl['owner'] || keycloak.hasRealmRole(TAG_ACCESS_OVERRIDE) ? ( + + ) : null} + + ); + } else if (el.accessor === 'delete') { + return ( + + {dataEl['owner'] || keycloak.hasRealmRole(TAG_ACCESS_OVERRIDE) ? ( + + ) : null} + + ); + } + if (el.accessor === 'owners') { + return ( + + {dataEl['owners'].map((owner: any) => ( +

{owner.username}

+ ))} ); } else { - return {val.toString()}; + return {val?.toString()}; } } return null; diff --git a/src/components/Table/EntityTagTable.tsx b/src/components/Table/EntityTagTable.tsx index 1733d903..60cc9a5f 100644 --- a/src/components/Table/EntityTagTable.tsx +++ b/src/components/Table/EntityTagTable.tsx @@ -6,6 +6,9 @@ import { useAppSelector } from '../../store/hooks'; import { formatDate } from '../../utils'; import { t } from 'i18next'; import { TagUpdateRequest } from '../../features/tagging/providers/types'; +import { TagToDelete } from '../../features/tagging/components/ComplexTagging'; +import { TAG_ACCESS_OVERRIDE } from '../../constants'; +import { useKeycloak } from '@react-keycloak/web'; interface Props { columns: { name: string; sortValue?: string; accessor?: string; key?: string }[]; @@ -15,6 +18,8 @@ interface Props { clickAccessor?: string; updateTag: (tag: TagUpdateRequest) => void; showAccessPanelHandler: (tag: any) => void; + setShowDeleteTagPanel: (show: boolean) => void; + setSelectedTagToDelete: (tag: TagToDelete) => void; } const DATE_FORMATS = [ @@ -35,12 +40,14 @@ const EntityTagTable = ({ clickHandler, clickAccessor, updateTag, - showAccessPanelHandler + showAccessPanelHandler, + setShowDeleteTagPanel, + setSelectedTagToDelete }: Props) => { const [sortDirection, setSortDirection] = useState(false); const [activeSortField, setActiveSortField] = useState(''); const isDarkMode = useAppSelector(state => state.darkMode.value); - + const { keycloak } = useKeycloak(); return ( @@ -116,7 +123,7 @@ const EntityTagTable = ({ ); } else if (el.name === 'access') { - return dataEl['aggregate'] ? ( + return dataEl['owner'] || keycloak.hasRealmRole(TAG_ACCESS_OVERRIDE) ? ( ) : null; + } else if (el.name === 'owners') { + return ( + + ); + } else if (el.accessor === 'delete') { + return ( + + ); } else { return ; } diff --git a/src/components/Table/MetadataEntityTagTable.tsx b/src/components/Table/MetadataEntityTagTable.tsx index 95444272..33011f10 100644 --- a/src/components/Table/MetadataEntityTagTable.tsx +++ b/src/components/Table/MetadataEntityTagTable.tsx @@ -60,6 +60,8 @@ const MetadataEntityTagTable = ({ data, setMetadataList, metadataList, columns } tagAccGrantsUser: entityTag.tagAccGrantsUser, tagAccGrantsOrganization: entityTag.tagAccGrantsOrganization, public: entityTag.public, + owners: entityTag.owners, + owner: entityTag.owner, children: entityTag.children?.map(child => { return { tag: child.tag, @@ -74,7 +76,9 @@ const MetadataEntityTagTable = ({ data, setMetadataList, metadataList, columns } created: child.created, tagAccGrantsUser: child.tagAccGrantsUser, tagAccGrantsOrganization: child.tagAccGrantsOrganization, - public: child.public + public: child.public, + owners: child.owners, + owner: child.owner }; }) }); @@ -95,7 +99,7 @@ const MetadataEntityTagTable = ({ data, setMetadataList, metadataList, columns }
+ {dataEl['owners'].map((owner: any) => ( +

{owner.username}

+ ))} +
+ {(dataEl['owner'] && !dataEl['aggregate']) || keycloak.hasRealmRole(TAG_ACCESS_OVERRIDE) ? ( + + ) : null} + {dataEl[el.accessor]?.toString()}
{headerGroups.map(headerGroup => ( - + {headerGroup.headers.map(column => { return ( + {row.cells.map(cell => { const cellData = cell.row.original; return cell.column.id === 'selected' ? ( ) : cell.column.id === 'orgGrants' ? ( ) : cell.column.id === 'aggregate' ? ( + ) : cell.column.id === 'owner' ? ( + + ) : cell.column.id === 'owners' ? ( + ) : ( ); diff --git a/src/components/Table/MetadataEntityTagTable2.tsx b/src/components/Table/MetadataEntityTagTable2.tsx index 2040071d..50a88679 100644 --- a/src/components/Table/MetadataEntityTagTable2.tsx +++ b/src/components/Table/MetadataEntityTagTable2.tsx @@ -62,6 +62,8 @@ const MetadataEntityTagTable2 = ({ data, setMetadataList, metadataList, columns tagAccGrantsUser: entityTag.tagAccGrantsUser, tagAccGrantsOrganization: entityTag.tagAccGrantsOrganization, public: entityTag.public, + owners: entityTag.owners, + owner: entityTag.owner, children: entityTag.children?.map(child => { return { tag: child.tag, @@ -76,7 +78,9 @@ const MetadataEntityTagTable2 = ({ data, setMetadataList, metadataList, columns created: child.created, tagAccGrantsUser: child.tagAccGrantsUser, tagAccGrantsOrganization: child.tagAccGrantsOrganization, - public: child.public + public: child.public, + owners: child.owners, + owner: child.owner }; }) }); diff --git a/src/components/Table/MetadataImportTable.tsx b/src/components/Table/MetadataImportTable.tsx index 20b85c33..961db2f6 100644 --- a/src/components/Table/MetadataImportTable.tsx +++ b/src/components/Table/MetadataImportTable.tsx @@ -7,6 +7,8 @@ import { Column, Row, useExpanded, useTable } from 'react-table'; import { MetadataFileImportResponse } from '../../features/metaDataImport/type'; import MetadataEntityTagTable from './MetadataEntityTagTable'; import { EntityTagResponse } from '../../features/planSimulation/providers/types'; +import { TAG_ACCESS_OVERRIDE } from '../../constants'; +import { useKeycloak } from '@react-keycloak/web'; interface Props { data: MetadataFileImportResponse[]; @@ -18,7 +20,7 @@ interface Props { const MetadataImportTable = ({ data, setMetadataList }: Props) => { const isDarkMode = useAppSelector(state => state.darkMode.value); - + const { keycloak } = useKeycloak(); const columnsForMetadataTables = React.useMemo[]>( () => [ { @@ -54,7 +56,8 @@ const MetadataImportTable = ({ data, setMetadataList }: Props) => { { Header: 'tag', accessor: 'tag' }, { Header: 'type', accessor: 'valueType' }, { Header: 'aggregate', accessor: 'aggregate' }, - + { Header: 'owner', accessor: 'owner' }, + { Header: 'owners', accessor: 'owners' }, { Header: 'isPublic', accessor: 'public' }, { Header: 'orgGrants' }, { Header: 'userGrants' }, @@ -114,6 +117,8 @@ const MetadataImportTable = ({ data, setMetadataList }: Props) => { { Header: 'uploadDate', accessor: 'uploadDatetime' }, { Header: 'status', accessor: 'status' }, { Header: 'uploadedBy', accessor: 'uploadedBy' }, + { Header: 'owner', accessor: 'owner' }, + { Header: 'owners', accessor: 'owners' }, { Header: 'selected', accessor: 'selected' } ], [] @@ -152,6 +157,8 @@ const MetadataImportTable = ({ data, setMetadataList }: Props) => { tagAccGrantsUser: entityTag.tagAccGrantsUser, tagAccGrantsOrganization: entityTag.tagAccGrantsOrganization, public: entityTag.public, + owners: entityTag.owners, + owner: entityTag.owner, children: entityTag.children?.map(child => { return { tag: child.tag, @@ -166,7 +173,9 @@ const MetadataImportTable = ({ data, setMetadataList }: Props) => { created: child.created, tagAccGrantsUser: child.tagAccGrantsUser, tagAccGrantsOrganization: child.tagAccGrantsOrganization, - public: child.public + public: child.public, + owners: child.owners, + owner: child.owner }; }) }); @@ -210,22 +219,40 @@ const MetadataImportTable = ({ data, setMetadataList }: Props) => { <> {row.cells.map(cell => { - return cell.column.id === 'selected' ? ( - - ) : ( - - ); + if (cell.column.id === 'selected') { + return ( + + ); + } else if (cell.column.id === 'owner') { + return ; + } else if (cell.column.id === 'owners') { + return ( + + ); + } else { + return ; + } })} {(row as any).isExpanded ? ( - + ) : ( '' diff --git a/src/constants/roles.ts b/src/constants/roles.ts index 292e142f..d4206707 100644 --- a/src/constants/roles.ts +++ b/src/constants/roles.ts @@ -63,3 +63,6 @@ export const REVEAL_SIMULATION_EDIT = 'reveal_simulation_edit'; //METADATA IMPORT export const METADATA_FILE_IMPORT = 'metadata_file_import'; + +//METADATA IMPORT +export const TAG_ACCESS_OVERRIDE = 'tag_access_override'; diff --git a/src/features/access/components/TagAccessOrgUserExpandingTable.tsx b/src/features/access/components/TagAccessOrgUserExpandingTable.tsx index 7cf43a4a..7e9ab0bc 100644 --- a/src/features/access/components/TagAccessOrgUserExpandingTable.tsx +++ b/src/features/access/components/TagAccessOrgUserExpandingTable.tsx @@ -424,7 +424,7 @@ const TagAccessOrgUserExpandingTable = ({ {row.cells.map(cell => { const cellData = cell.row.original as any; - if (cell.column.id === 'select') { + if (cell.column.id === 'select' && cell.row.original.identifier !== 'unassigned') { return (
{ prepareRow(row); return ( -
- {' '} - setSelected(evt, row.original.identifier)} - /> + {cellData.owner ? ( + setSelected(evt, row.original.identifier)} + /> + ) : null} @@ -172,6 +177,14 @@ const MetadataEntityTagTable = ({ data, setMetadataList, metadataList, columns } {cellData.public ? 'true' : 'false'}{cellData.aggregate ? 'true' : 'false'}{cellData.owner ? 'true' : 'false'} + {cellData.owners.map(owner => ( +

{owner.username}

+ ))} +
{cell.render('Cell')}
- setSelected(evt, row.original.identifier)} - /> - {cell.render('Cell')} + {cell.row.original.owner || keycloak.hasRealmRole(TAG_ACCESS_OVERRIDE) ? ( + setSelected(evt, row.original.identifier)} + /> + ) : ( + '' + )} + {cell.row.original.owner ? 'true' : 'false'} + {cell.row.original.owners.map(owner => ( +

{owner.username}

+ ))} +
{cell.render('Cell')}
{renderRowSubComponent(row)} + {renderRowSubComponent(row)} +
@@ -458,7 +458,6 @@ const TagAccessOrgUserExpandingTable = ({ })}
-

makePublic: {String(makePublic)}

); }; diff --git a/src/features/access/components/TagAccessOrganization.tsx b/src/features/access/components/TagAccessOrganization.tsx index da85294d..f98dd125 100644 --- a/src/features/access/components/TagAccessOrganization.tsx +++ b/src/features/access/components/TagAccessOrganization.tsx @@ -1,7 +1,7 @@ import React, { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; import { Accordion, Col, FormCheck, OverlayTrigger, Row, Tooltip } from 'react-bootstrap'; import { getOrganizationCount, getOrganizationList, getUserList } from '../api'; -import { OrganizationModel } from '../providers/types'; +import { Code, OrganizationModel } from '../providers/types'; import Paginator from '../../../components/Pagination'; import { PAGINATION_DEFAULT_SIZE } from '../../../constants'; import { DebounceInput } from 'react-debounce-input'; @@ -97,7 +97,21 @@ const TagAccessOrganization = ({ metadata, updatedMetadata, setUpdatedMetadata } } }); - let orgListAdapted: OrganizationModelAdapted[] = organizations.content.map(org => { + let orgListAmended: OrganizationModel[] = [ + ...organizations.content, + { + active: true, + headOf: [], + type: { + code: Code.Team, + valueCodableConcept: 'Users' + }, + name: 'Unassigned Users', + identifier: 'unassigned', + partOf: 'unassigned' + } + ]; + let orgListAdapted: OrganizationModelAdapted[] = orgListAmended.map(org => { return { active: org.active, headOf: addUserToHeadOf(org.headOf, orgUserList), @@ -294,7 +308,6 @@ const TagAccessOrganization = ({ metadata, updatedMetadata, setUpdatedMetadata } }} />
-

makePublic: {String(makePublic)}

{t('organizationPage.organization')} ({organizationCount})
diff --git a/src/features/metaDataImport/components/fileImport/MetaFileImport.tsx b/src/features/metaDataImport/components/fileImport/MetaFileImport.tsx index 0fb26fef..aaf46f7e 100644 --- a/src/features/metaDataImport/components/fileImport/MetaFileImport.tsx +++ b/src/features/metaDataImport/components/fileImport/MetaFileImport.tsx @@ -47,7 +47,9 @@ const MetaFileImport = () => { status: fileImport.status, identifier: fileImport.identifier, uploadDatetime: fileImport.uploadDatetime, - uploadedBy: fileImport.uploadedBy + uploadedBy: fileImport.uploadedBy, + owner: fileImport.owner, + owners: fileImport.owners }; return newFileImport; @@ -80,6 +82,8 @@ const MetaFileImport = () => { const meta = new EntityTagResponse( metaEvent.identifier, metaEvent.tag, + metaEvent.owner, + metaEvent.owners, metaEvent.definition, metaEvent.valueType, metaEvent.aggregate, @@ -102,6 +106,8 @@ const MetaFileImport = () => { const metaChildObj = new EntityTagResponse( metaChild.identifier, metaChild.tag, + metaChild.owner, + metaChild.owners, metaChild.definition, metaChild.valueType, metaChild.aggregate, diff --git a/src/features/metaDataImport/type.ts b/src/features/metaDataImport/type.ts index 9dbcc541..39da1d00 100644 --- a/src/features/metaDataImport/type.ts +++ b/src/features/metaDataImport/type.ts @@ -8,4 +8,11 @@ export interface MetadataFileImportResponse { uploadedBy: string; selected?: boolean; entityTagEvents?: EntityTagResponse[]; + owner: boolean; + owners: Owners[]; +} + +export interface Owners { + id: string; + username: string; } diff --git a/src/features/planSimulation/api/index.ts b/src/features/planSimulation/api/index.ts index 10ac3710..6f4819de 100644 --- a/src/features/planSimulation/api/index.ts +++ b/src/features/planSimulation/api/index.ts @@ -5,12 +5,13 @@ import { EntityTag, LookupEntityType, PersonMeta, - PlanningLocationResponse + PlanningLocationResponse, + TagResponse } from '../providers/types'; import { SimulationCountResponse, SimulationRequestData } from '../components/Simulation'; import { SaveHierarchyRequest, SaveHierarchyResponse } from '../components/modals/SaveHierarchyModal'; -import { ComplexTagRequest } from '../../tagging/components/ComplexTagging'; +import { ComplexTagRequest, TagToDelete } from '../../tagging/components/ComplexTagging'; export const getEntityList = async (): Promise => { const data = await api.get(`entityTag/entityType`).then(res => res.data); @@ -22,8 +23,8 @@ export const getEntityTags = async (): Promise => { return data; }; -export const getDataAssociatedEntityTags = async (hierarchyIdentifier: string): Promise => { - const data = await api.get('entityTag/dataAssociated/' + hierarchyIdentifier).then(res => res.data); +export const getDataAssociatedEntityTags = async (hierarchyIdentifier: string): Promise => { + const data = await api.get('entityTag/dataAssociated/' + hierarchyIdentifier).then(res => res.data); return data; }; @@ -175,3 +176,12 @@ export const getComplexTagReponses = async (): Promise => const data = await api.get('entityTag/complex').then(res => res.data); return data; }; +export const deleteComplexTag = async (tag: TagToDelete): Promise => { + const data = await api.post(`entityTag/complex/delete`, tag).then(res => res.data); + return data; +}; + +export const deleteSimpleTags = async (tag: TagToDelete[]): Promise => { + const data = await api.post(`entityTag/delete`, tag).then(res => res.data); + return data; +}; diff --git a/src/features/planSimulation/components/MetadataFormula/MetadataFormulaPanel.tsx b/src/features/planSimulation/components/MetadataFormula/MetadataFormulaPanel.tsx index eeaf3d8c..3fd75579 100644 --- a/src/features/planSimulation/components/MetadataFormula/MetadataFormulaPanel.tsx +++ b/src/features/planSimulation/components/MetadataFormula/MetadataFormulaPanel.tsx @@ -69,7 +69,7 @@ const MetadataFormulaPanel = ({ showModal, closeHandler, combinedHierarchyList, if (selectedHierarchy) { let tagsMeta: EntityTag[] = []; getDataAssociatedEntityTags(selectedHierarchy.identifier).then(res => { - tagsMeta = res; + tagsMeta = res.entityTagResponses; setEntityTags(tagsMeta); let tagsEvent: EntityTag[] = []; getEventBasedEntityTags().then(result => { diff --git a/src/features/planSimulation/components/Simulation.tsx b/src/features/planSimulation/components/Simulation.tsx index 04941a03..755cb744 100644 --- a/src/features/planSimulation/components/Simulation.tsx +++ b/src/features/planSimulation/components/Simulation.tsx @@ -11,7 +11,6 @@ import { getGeneratedLocationHierarchyList, getLocationHierarchyList } from '../ import { LocationHierarchyModel } from '../../location/providers/types'; import { evaluate, isNumeric } from 'mathjs'; import { - getComplexTagReponses, getDataAssociatedEntityTags, getEntityList, getEventBasedEntityTags, @@ -196,10 +195,10 @@ const Simulation = () => { Promise.all([ getLocationHierarchyList(50, 0, true), getEntityList(), - getGeneratedLocationHierarchyList(), - getComplexTagReponses() + getGeneratedLocationHierarchyList() + // getComplexTagReponses() ]) - .then(([locationHierarchyList, entityList, generatedHierarchyList, complexTagResponses]) => { + .then(([locationHierarchyList, entityList, generatedHierarchyList]) => { let generatedHierarchyItems = generatedHierarchyList?.map(generatedHierarchy => { return { identifier: generatedHierarchy.identifier, @@ -224,7 +223,7 @@ const Simulation = () => { let entityObj = entityList.find(entity => entity.code === 'Location'); setSelectedEntity(entityObj?.identifier); - setComplexTags(complexTagResponses); + // setComplexTags(complexTagResponses); }) .catch(err => toast.error(err)); }, []); @@ -1048,7 +1047,7 @@ const Simulation = () => { if (selectedHierarchy) { let tagsMeta: EntityTag[] = []; getDataAssociatedEntityTags(selectedHierarchy.identifier).then(res => { - tagsMeta = res; + tagsMeta = res.entityTagResponses; setEntityTags(tagsMeta); let tagsEvent: EntityTag[] = []; getEventBasedEntityTags().then(result => { @@ -1059,6 +1058,7 @@ const Simulation = () => { setEntityTags(allTags); } }); + setComplexTags(res.complexTagDtos); }); } }, [selectedHierarchy]); diff --git a/src/features/planSimulation/providers/types.ts b/src/features/planSimulation/providers/types.ts index 2c75f2a3..60d267ac 100644 --- a/src/features/planSimulation/providers/types.ts +++ b/src/features/planSimulation/providers/types.ts @@ -2,12 +2,18 @@ import { Feature, MultiPolygon, Polygon, Properties, Point } from '@turf/turf'; import { LngLatBounds } from 'mapbox-gl'; import { AnalysisLayer } from '../components/Simulation'; import { TagWithFormulaSymbol } from '../components/MetadataFormula/MetadataFormulaPanel'; +import { Owners } from '../../metaDataImport/type'; export enum HierarchyType { GENERATED = 'generated', SAVED = 'saved' } +export interface TagResponse { + entityTagResponses: EntityTag[]; + complexTagDtos: ComplexTagResponse[]; +} + export interface EntityTag { identifier: string; tag: string; @@ -38,10 +44,14 @@ export class BaseTag { resultingOrgs?: OrgGrant[]; resultingUsers?: UserGrant[]; selected?: boolean; + owner: boolean; + owners: Owners[]; constructor( identifier: string, tag: string, + owner: boolean, + owners: Owners[], publicval?: boolean, tagAccGrantsOrganization?: OrgGrant[], tagAccGrantsUser?: UserGrant[], @@ -57,6 +67,8 @@ export class BaseTag { this.resultingUsers = resultingUsers; this.resultingOrgs = resultingOrgs; this.selected = selected; + this.owner = owner; + this.owners = owners; } } @@ -72,6 +84,8 @@ export class EntityTagResponse extends BaseTag { constructor( identifier: string, tag: string, + owner: boolean, + owners: Owners[], definition: string, valueType: string, aggregate: boolean, @@ -89,6 +103,8 @@ export class EntityTagResponse extends BaseTag { super( identifier, tag, + owner, + owners, publicVal, tagAccGrantsOrganization, tagAccGrantsUser, @@ -122,6 +138,8 @@ export class ComplexTagResponse extends BaseTag { tagName: string, tags: TagWithFormulaSymbol[], formula: string, + owner: boolean, + owners: Owners[], calculateValue?: number, publicVal?: boolean, tagAccGrantsOrganization?: OrgGrant[], @@ -130,7 +148,18 @@ export class ComplexTagResponse extends BaseTag { resultingOrgs?: OrgGrant[], resultingUsers?: UserGrant[] ) { - super(id, tagName, publicVal, tagAccGrantsOrganization, tagAccGrantsUser, resultingOrgs, resultingUsers, selected); + super( + id, + tagName, + owner, + owners, + publicVal, + tagAccGrantsOrganization, + tagAccGrantsUser, + resultingOrgs, + resultingUsers, + selected + ); this.id = id; this.hierarchyId = hierarchyId; this.hierarchyType = hierarchyType; diff --git a/src/features/resourcePlanning/components/ConfigTab/ConfigTab.tsx b/src/features/resourcePlanning/components/ConfigTab/ConfigTab.tsx index 0e817962..5e77026c 100644 --- a/src/features/resourcePlanning/components/ConfigTab/ConfigTab.tsx +++ b/src/features/resourcePlanning/components/ConfigTab/ConfigTab.tsx @@ -76,7 +76,7 @@ const ConfigTab = () => { if (selectedHierarchy && selectedHierarchy.identifier) { getDataAssociatedEntityTags(selectedHierarchy.identifier) .then(res => { - setEntityTags(res); + setEntityTags(res.entityTagResponses); }) .catch(err => toast.error(err)); } diff --git a/src/features/tagging/components/ComplexTagging.tsx b/src/features/tagging/components/ComplexTagging.tsx index fcb387b2..cd6ef578 100644 --- a/src/features/tagging/components/ComplexTagging.tsx +++ b/src/features/tagging/components/ComplexTagging.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { getGeneratedLocationHierarchyList, getLocationHierarchyList } from '../../location/api'; -import { getComplexTagReponses, getEntityList } from '../../planSimulation/api'; +import { deleteComplexTag, getComplexTagReponses, getEntityList } from '../../planSimulation/api'; import { ComplexTagResponse, HierarchyType } from '../../planSimulation/providers/types'; import { toast } from 'react-toastify'; import { LocationHierarchyModel } from '../../location/providers/types'; @@ -15,6 +15,7 @@ import { REVEAL_SIMULATION_EDIT } from '../../../constants'; import AuthorizedElement from '../../../components/AuthorizedElement'; import TagAccess from '../../access/TagAccess'; import MetadataFormulaPanelViewOnly from '../../planSimulation/components/MetadataFormula/MetadataFormulaPanelViewOnly'; +import DeleteTag from './DeleteTag'; export interface ComplexTagRequest { hierarchyId: string; @@ -24,6 +25,11 @@ export interface ComplexTagRequest { formula: string; } +export interface TagToDelete { + id: string; + type: string; + tag: string; +} const ComplexTagging = () => { const [combinedHierarchyList, setCombinedHierarchyList] = useState(); const { t } = useTranslation(); @@ -32,6 +38,8 @@ const ComplexTagging = () => { const [complexTags, setComplexTags] = useState(); const [selectedComplexTag, setSelectedComplexTag] = useState(); const [showTagAccess, setShowTagAccess] = useState(false); + const [showDeleteTagPanel, setShowDeleteTagPanel] = useState(false); + const [selectedTagToDelete, setSelectedTagToDelete] = useState(); const [selectedMetadata, setSelectedMetadata] = useState([]); useEffect(() => { @@ -73,6 +81,8 @@ const ComplexTagging = () => { tag.tagName, tag.tags, tag.formula, + tag.owner, + tag.owners, tag.calculateValue, tag.public, tag.tagAccGrantsOrganization, @@ -89,6 +99,15 @@ const ComplexTagging = () => { getComplexTagReponses().then(data => setComplexTags(data)); }; + const proceedToDeleteComplexTag = (tag?: TagToDelete) => { + if (tag) { + deleteComplexTag(tag).then(() => { + setShowDeleteTagPanel(false); + getComplexTagReponses().then(data => setComplexTags(data)); + }); + } + }; + return ( <>

@@ -114,20 +133,28 @@ const ComplexTagging = () => {


- { - setSelectedComplexTag(dataEl); - setViewCreateComplexTagPanel(true); - }} - showAccessPanelHandler={setShowTagAccessWithSelectedTag} - /> + {complexTags && complexTags?.length > 0 ? ( + { + setSelectedComplexTag(dataEl); + setViewCreateComplexTagPanel(true); + }} + showAccessPanelHandler={setShowTagAccessWithSelectedTag} + setShowDeleteTagPanel={setShowDeleteTagPanel} + setSelectedTagToDelete={setSelectedTagToDelete} + /> + ) : ( +

No data found.

+ )} {showCreateComplexTagPanel && ( { type={'complexTag'} /> )} + {showDeleteTagPanel && ( + + )} ); }; diff --git a/src/features/tagging/components/DeleteTag.tsx b/src/features/tagging/components/DeleteTag.tsx new file mode 100644 index 00000000..db80f7fb --- /dev/null +++ b/src/features/tagging/components/DeleteTag.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { Button, Modal } from 'react-bootstrap'; +import { TagToDelete } from './ComplexTagging'; + +interface Props { + showDeleteTagPanel: boolean; + setShowDeleteTagPanel: (show: boolean) => void; + selectedTagToDelete?: TagToDelete; + selectedTagsToDelete?: TagToDelete[]; + proceedToDeleteTag?: (tag?: TagToDelete) => void; + proceedToDeleteTags?: (tag?: TagToDelete[]) => void; +} + +const DeleteTag = ({ + showDeleteTagPanel, + setShowDeleteTagPanel, + selectedTagToDelete, + proceedToDeleteTag, + proceedToDeleteTags, + selectedTagsToDelete +}: Props) => { + return ( + setShowDeleteTagPanel(false)}> + Delete Tag + + + {selectedTagsToDelete && selectedTagsToDelete?.length > 0 + ? 'Are you sure you want to delete the following tags:' + : 'Are you sure you want to delete tag:'} + + <> + {selectedTagsToDelete && selectedTagsToDelete?.length > 0 + ? selectedTagsToDelete.map(tag =>

{tag.tag}

) + : selectedTagToDelete?.tag} + +
+ + + + +
+ ); +}; +export default DeleteTag; diff --git a/src/features/tagging/components/Tagging.tsx b/src/features/tagging/components/Tagging.tsx index 0b0ac8f2..6b173db2 100644 --- a/src/features/tagging/components/Tagging.tsx +++ b/src/features/tagging/components/Tagging.tsx @@ -13,6 +13,9 @@ import AuthorizedElement from '../../../components/AuthorizedElement'; import { EntityTagResponse } from '../../planSimulation/providers/types'; import TagAccess from '../../access/TagAccess'; +import { TagToDelete } from './ComplexTagging'; +import DeleteTag from './DeleteTag'; +import { deleteSimpleTags } from '../../planSimulation/api'; const columnsNotForDisplay = [ 'identifier', @@ -28,7 +31,8 @@ const columnsNotForDisplay = [ 'addToMetadata', 'fieldType', 'referenceFields', - 'generationFormula' + 'generationFormula', + 'owner' ]; const Tagging = () => { @@ -39,6 +43,9 @@ const Tagging = () => { const [currentSearchInput, setCurrentSearchInput] = useState(''); const [showTagAccess, setShowTagAccess] = useState(false); const [selectedMetadata, setSelectedMetadata] = useState([]); + const [showDeleteTagPanel, setShowDeleteTagPanel] = useState(false); + const [selectedTagToDelete, setSelectedTagToDelete] = useState(); + const [selectedTagsToDelete, setSelectedTagsToDelete] = useState(); const loadData = useCallback((size: number, page: number, filter?: string, field?: string, direction?: boolean) => { getAllGlobalTags(size, page, filter, field, direction) @@ -52,6 +59,23 @@ const Tagging = () => { loadData(PAGINATION_DEFAULT_SIZE, 0); }, [loadData]); + useEffect(() => { + console.log(selectedTagToDelete); + let tags = tagList?.content + .filter(tag => { + return tag.referencedTag === selectedTagToDelete?.id; + }) + .map(tag => { + return { + id: tag.identifier, + type: 'Simple', + tag: tag.tag + }; + }); + console.log(tags); + setSelectedTagsToDelete(tags); + }, [selectedTagToDelete, tagList]); + const paginationHandler = (size: number, page: number) => { loadData(size, page, currentSearchInput, currentSortField, currentSortDirection); }; @@ -86,11 +110,11 @@ const Tagging = () => { accessor: 'tag', sortValue: 'access' }); - // columns.unshift({ - // name: 'expander', - // accessor: 'expander', - // sortValue: 'expander' - // }); + columns.push({ + name: 'delete', + accessor: 'delete', + sortValue: 'delete' + }); return columns; }; const setShowTagAccessWithSelectedTag = (tag: any) => { @@ -106,7 +130,9 @@ const Tagging = () => { created: tag.created, metadataImportId: tag.metadataImportId, tagAccGrantsUser: tag.tagAccGrantsUser, - tagAccGrantsOrganization: tag.tagAccGrantsOrganization + tagAccGrantsOrganization: tag.tagAccGrantsOrganization, + owner: tag.owner, + owners: tag.owners } ]); }; @@ -116,6 +142,15 @@ const Tagging = () => { loadData(PAGINATION_DEFAULT_SIZE, 0); }; + const proceedToDeleteSimpleTag = (tags?: TagToDelete[]) => { + if (tags) { + deleteSimpleTags(tags).then(() => { + setShowDeleteTagPanel(false); + loadData(PAGINATION_DEFAULT_SIZE, 0); + }); + } + }; + return ( <>

@@ -149,6 +184,8 @@ const Tagging = () => { data={tagList?.content} updateTag={updateSimulationDisplay} showAccessPanelHandler={setShowTagAccessWithSelectedTag} + setShowDeleteTagPanel={setShowDeleteTagPanel} + setSelectedTagToDelete={setSelectedTagToDelete} /> { type={'tag'} /> )} + {showDeleteTagPanel && ( + + )} ); }; diff --git a/src/features/tagging/components/createModal/CreateTag.tsx b/src/features/tagging/components/createModal/CreateTag.tsx index 992ae5ed..2c1dfb31 100644 --- a/src/features/tagging/components/createModal/CreateTag.tsx +++ b/src/features/tagging/components/createModal/CreateTag.tsx @@ -5,7 +5,6 @@ import { toast } from 'react-toastify'; import { BOOLEAN_STRING_AGGREGATION, DATA_AGGREGATION, NUMBER_AGGREGATION } from '../../../../constants'; import { createTag } from '../../api'; import { TagCreateRequest } from '../../providers/types'; -import Select from 'react-select'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; interface Props { @@ -13,8 +12,6 @@ interface Props { } const CreateTag = ({ closeHandler }: Props) => { - const [aggregation, setAggregation] = useState([]); - const { register, handleSubmit, @@ -49,7 +46,6 @@ const CreateTag = ({ closeHandler }: Props) => { selected = BOOLEAN_STRING_AGGREGATION; break; } - setAggregation(selected); }, [selectedValueType]); const submitHandler = (form: TagCreateRequest) => { @@ -130,36 +126,6 @@ const CreateTag = ({ closeHandler }: Props) => { {errors.valueType && {errors.valueType?.message}} - - Aggregation Method - ( -