From c38b911ededaaeead68b4a3339300eaf6fcaf5a3 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Tue, 17 Sep 2024 11:37:27 +0300 Subject: [PATCH 01/33] Fetching vendor property for each resource [#82] Signed-off-by: Zoltan Magyari --- src/services/cypherQueryApiService.ts | 30 ++++++++++++++++----------- src/types/resources.model.ts | 3 ++- src/utils/dataMapper.ts | 3 ++- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/services/cypherQueryApiService.ts b/src/services/cypherQueryApiService.ts index 0db28714..dfdd0bef 100644 --- a/src/services/cypherQueryApiService.ts +++ b/src/services/cypherQueryApiService.ts @@ -67,25 +67,31 @@ export const CypherQueryApiService = { */ async getAllResources(typeFilters: Asset[]): Promise { const whereDataResource = typeFilters.length ? ` - WHERE ANY (label IN labels(n) WHERE label IN [ '${typeFilters.map(asset => asset.label).join('\', \'')}']) - AND 'DataResource' IN labels(n) - AND NOT n.uri STARTS WITH 'bnode://'` + WHERE ANY (label IN labels(resource) WHERE label IN [ '${typeFilters.map(asset => asset.label).join('\', \'')}']) + AND 'DataResource' IN labels(resource) + AND NOT resource.uri STARTS WITH 'bnode://'` : '' - const matchFormatNode = ` - OPTIONAL MATCH(m) - WHERE n.uri IN m.claimsGraphUri - AND ANY(label IN labels(m) WHERE label CONTAINS 'Format')` + const matchFormatPropertyNode = ` + OPTIONAL MATCH(formatProperty) + WHERE resource.uri IN formatProperty.claimsGraphUri + AND ANY(label IN labels(formatProperty) WHERE label CONTAINS 'Format')` + + const matchCopyrightOwnedBy = ` + OPTIONAL MATCH(copyrightOwner) + WHERE copyrightOwner.uri = resource.copyrightOwnedBy` return cypherQuery({ statement: ` - MATCH (n) + MATCH (resource) ${whereDataResource} - ${matchFormatNode} + ${matchFormatPropertyNode} + ${matchCopyrightOwnedBy} RETURN - properties(n) AS properties, - labels(n) AS labels, - properties(m).type AS format`, + properties(resource) AS properties, + labels(resource) AS labels, + properties(formatProperty).type AS format, + properties(copyrightOwner).legalName AS vendor`, }) }, diff --git a/src/types/resources.model.ts b/src/types/resources.model.ts index f0e78b49..71898fd9 100644 --- a/src/types/resources.model.ts +++ b/src/types/resources.model.ts @@ -4,5 +4,6 @@ export interface Resource { description: string, uri: string, claimsGraphUri: string[], - format: string + format: string, + vendor: string } diff --git a/src/utils/dataMapper.ts b/src/utils/dataMapper.ts index 2c0f6559..dae90a20 100644 --- a/src/utils/dataMapper.ts +++ b/src/utils/dataMapper.ts @@ -34,9 +34,10 @@ export function mapServiceOfferings(selfDescriptions: ServiceOfferingInput): Ser })); } -type ResourceInputProperties = Exclude +type ResourceInputProperties = Exclude export interface ResourceInput { items: { + vendor: string, format: string, labels: string[], properties: ResourceInputProperties; From 7466f89b79de91547d0823a74076ddb93fcc7d7f Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Thu, 19 Sep 2024 05:09:16 +0300 Subject: [PATCH 02/33] Remove circular dependency Signed-off-by: Zoltan Magyari --- src/components/resources/Resources.tsx | 12 +-- .../resources/helpers/resourceDataFlow.ts | 62 +++++++++++- .../helpers/resourceFilterAssetHelper.ts | 5 +- .../helpers/resourceFilterAssetsDataFlow.ts | 31 ------ .../resources/helpers/resourcesHelper.ts | 87 ++++++++++++----- .../hooks/useResourceFilterAssets.ts | 74 -------------- .../resources/hooks/useResources.ts | 97 ++++++++++--------- src/services/cypherQueryApiService.ts | 37 ++++--- 8 files changed, 199 insertions(+), 206 deletions(-) delete mode 100644 src/components/resources/helpers/resourceFilterAssetsDataFlow.ts delete mode 100644 src/components/resources/hooks/useResourceFilterAssets.ts diff --git a/src/components/resources/Resources.tsx b/src/components/resources/Resources.tsx index 08cd38ab..50a0092e 100644 --- a/src/components/resources/Resources.tsx +++ b/src/components/resources/Resources.tsx @@ -12,7 +12,6 @@ import LoadingIndicator from '../loading_view/LoadingIndicator'; import NoContent from '../nocontent/NoContent'; import SearchBar from '../searchBar/SearchBar'; -import { Asset } from './helpers/resourceFilterAssetHelper'; import { useResources } from './hooks/useResources'; const Resources = () => { @@ -24,8 +23,8 @@ const Resources = () => { typeAssets, formatAssets, vendorAssets, - search, - updateAssetFilter + updateSearchText, + updateFilterAsset, } = useResources(); return ( @@ -37,14 +36,11 @@ const Resources = () => { typeAssets={typeAssets} formatAssets={formatAssets} vendorAssets={vendorAssets} - updateAssetFilter={(asset: Asset) => { - console.debug('update filter:', asset); - updateAssetFilter(asset); - }} + updateAssetFilter={updateFilterAsset} /> - + diff --git a/src/components/resources/helpers/resourceDataFlow.ts b/src/components/resources/helpers/resourceDataFlow.ts index 7d64cd23..547f71f0 100644 --- a/src/components/resources/helpers/resourceDataFlow.ts +++ b/src/components/resources/helpers/resourceDataFlow.ts @@ -1,15 +1,69 @@ import { CypherQueryApiService as cypherQuery } from '../../../services/cypherQueryApiService'; +import { + fetchAllOntologiesFromSchemas, + getResourceFormats, + getResourceTypes +} from '../../../services/ontologyService.utils'; +import { fetchAllSchemas } from '../../../services/schemaApiService'; +import { fetchAllShapesFromSchemas } from '../../../services/shapeService.utils'; import { Resource } from '../../../types/resources.model'; import { mapResources } from '../../../utils/dataMapper'; -import { Asset } from './resourceFilterAssetHelper'; +export interface ResourceSearchPageData { + resources: Resource[], + resourceTypes: string[], + resourceFormats: string[] +} + +export const loadResourceSearchPageData = async (): Promise => { + const { resourceTypes, resourceFormats } = await loadResourceFilterAssets(); + const resources = await loadResources(resourceTypes); + + return { + resources, + resourceTypes, + resourceFormats + } +} -export const loadResources = async (typeAssets: Asset[]): Promise => { - return cypherQuery - .getAllResources(typeAssets) +/** + * Loads resources for which the following criteria are met: + * - the node labels should contain at least one of the selected filters passed in as `typeFilter` param + * - the node labels should contain the DataResource label too + * - only main nodes (for which the uri does not start with `pnode://`) are returned as result + * + * @param resourceTypes only resources with this label will be loaded + * @return the list of resources + */ +const loadResources = async (resourceTypes: string[]): Promise => + cypherQuery + .getAllResources(resourceTypes) .then((resourceInput) => mapResources(resourceInput)) .catch(error => { console.error('Error fetching resources:', error); throw error; }); + +/** + * Loads resource filter assets. + * + * @return a list of each resource assets + */ +const loadResourceFilterAssets = async (): Promise<{ + resourceTypes: string[]; + resourceFormats: string[]; +}> => { + try { + const schemas = await fetchAllSchemas(); + const shapes = await fetchAllShapesFromSchemas(schemas); + const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes) + + const resourceTypes = getResourceTypes(ontologies); + const resourceFormats = getResourceFormats(ontologies); + + return { resourceTypes, resourceFormats }; + } catch (error) { + console.error('Error loading filter assets', error); + throw error; + } } diff --git a/src/components/resources/helpers/resourceFilterAssetHelper.ts b/src/components/resources/helpers/resourceFilterAssetHelper.ts index e753a4b5..6c52cc26 100644 --- a/src/components/resources/helpers/resourceFilterAssetHelper.ts +++ b/src/components/resources/helpers/resourceFilterAssetHelper.ts @@ -36,7 +36,7 @@ type UpdateAssetFilterMethod = ( * @param formatAssets the current format assets list * @param setFormatAssets the setter of the format assets list */ -export const updateAssetFilter: UpdateAssetFilterMethod = (asset, { +export const updateFilterAsset: UpdateAssetFilterMethod = (asset, { typeAssets, setTypeAssets, formatAssets, @@ -67,7 +67,7 @@ export const updateAssetFilter: UpdateAssetFilterMethod = (asset, { export const createAsset = ( label: string, type: AssetTypes, - disabled: boolean = false + disabled: boolean = true ): Asset => ({ id: label, type, @@ -90,3 +90,4 @@ export const disableNonAvailableAssets = (assets: Asset[], availableAssetIds: st disabled: !availableAssetIds.some(availableAssetId => availableAssetId === asset.id) })) ) + diff --git a/src/components/resources/helpers/resourceFilterAssetsDataFlow.ts b/src/components/resources/helpers/resourceFilterAssetsDataFlow.ts deleted file mode 100644 index 493277ca..00000000 --- a/src/components/resources/helpers/resourceFilterAssetsDataFlow.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - fetchAllOntologiesFromSchemas, - getResourceFormats, - getResourceTypes -} from '../../../services/ontologyService.utils'; -import { fetchAllSchemas } from '../../../services/schemaApiService'; -import { fetchAllShapesFromSchemas } from '../../../services/shapeService.utils'; - -/** - * Loads resource filter assets. - * - * @return a list of each resource assets - */ -export const loadResourceFilterAssets = async (): Promise<{ - resourceTypes: string[]; - resourceFormats: string[]; -}> => { - try { - const schemas = await fetchAllSchemas(); - const shapes = await fetchAllShapesFromSchemas(schemas); - const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes) - - const resourceTypes = getResourceTypes(ontologies); - const resourceFormats = getResourceFormats(ontologies); - - return { resourceTypes, resourceFormats }; - } catch (error) { - console.error('Error loading filter assets', error); - throw error; - } -} diff --git a/src/components/resources/helpers/resourcesHelper.ts b/src/components/resources/helpers/resourcesHelper.ts index 727e0079..4a6530d3 100644 --- a/src/components/resources/helpers/resourcesHelper.ts +++ b/src/components/resources/helpers/resourcesHelper.ts @@ -1,6 +1,6 @@ import { Resource } from '../../../types/resources.model'; -import { Asset, FORMAT_ASSETS, TYPE_ASSETS } from './resourceFilterAssetHelper'; +import { Asset, createAsset, FORMAT_ASSETS, TYPE_ASSETS } from './resourceFilterAssetHelper'; /** * Checks if a resource corresponds to a certain criteria represented by the asset. @@ -10,21 +10,13 @@ import { Asset, FORMAT_ASSETS, TYPE_ASSETS } from './resourceFilterAssetHelper'; * @return true if corresponds, false otherwise */ export const assetFilterPredicate = (resource: Resource, assets: Asset[]): boolean => { - let typeFiltersApply = true; - const typeAssets = assets - .filter(asset => asset.value && asset.type === TYPE_ASSETS) - if (typeAssets.length) { - typeFiltersApply = typeAssets - .some(asset => typeAssetPredicate(resource, asset)) - } + const typeAssets = assets.filter(asset => asset.value && asset.type === TYPE_ASSETS) + const typeFiltersApply = !typeAssets.length + || typeAssets.some(asset => typeAssetPredicate(resource, asset)) - let formatFiltersApply = true; - const formatAssets = assets - .filter(asset => asset.value && asset.type === FORMAT_ASSETS) - if (formatAssets.length) { - formatFiltersApply = formatAssets - .some(asset => formatAssetPredicate(resource, asset)) - } + const formatAssets = assets.filter(asset => asset.value && asset.type === FORMAT_ASSETS) + const formatFiltersApply = !formatAssets.length + || formatAssets.some(asset => formatAssetPredicate(resource, asset)) return typeFiltersApply && formatFiltersApply } @@ -76,14 +68,65 @@ export const removeDataResourceLabels = (resources: Resource[]) => { */ export const applyFilters = (resources: Resource[], searchText: string, assets: Asset[]): Resource[] => ( resources + .filter(resource => assetFilterPredicate(resource, assets)) .filter(resource => Object .entries(resource) .some(property => !searchText || - String(property[1]).toLowerCase() - .includes(searchText.toLowerCase()) + getPropertyValue(property).toLowerCase() + .includes(searchText.toLowerCase()) ) - ) - .filter(resource => - assetFilterPredicate(resource, assets) - ) -) + )) + +const getPropertyValue = (objectEntry: [string, any]) => String(objectEntry[1]) + +export const createTypeAssets = (types: string[], resources: Resource[]) => { + const resourceLabels = getAllLabels(resources); + return types.map(type => createAsset(type, 'typeAssets', !resourceLabels.has(type))); +} + +export const getAllLabels = (resources: Resource[]) => + new Set( + resources + .map(resource => resource.labels) + .flat() + ); + +export const createFormatAssets = ( + formats: string[], + typeAssets: Asset[], + resources: Resource[], + initiallySelected: Asset[] +) => { + let selectedTypeAssets = typeAssets + .filter(asset => !asset.disabled && asset.value) + .map(asset => asset.id) + + // If nothing is selected it is considered that all enabled ones are selected + if (!selectedTypeAssets.length) { + selectedTypeAssets = typeAssets + .filter(asset => !asset.disabled) + .map(asset => asset.id); + } + + // Get formats only from selected resources + const resourceFormats = + getAllFormats(resources + .filter(resource => resource.labels + .some(label => selectedTypeAssets.includes(label)))); + + return formats.map(format => ({ + id: format, + type: 'formatAssets', + label: format, + value: initiallySelected.some(asset => asset.id === format), + disabled: !resourceFormats.has(format) + } as Asset)); +} + +export const getAllFormats = (resources: Resource[]) => + new Set( + resources + .map(resource => resource.format) + .flat() + ); + diff --git a/src/components/resources/hooks/useResourceFilterAssets.ts b/src/components/resources/hooks/useResourceFilterAssets.ts deleted file mode 100644 index 7bb3bb93..00000000 --- a/src/components/resources/hooks/useResourceFilterAssets.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { - Asset, - createAsset, - disableNonAvailableAssets, - FORMAT_ASSETS, - TYPE_ASSETS, - updateAssetFilter, - VENDOR_ASSETS, -} from '../helpers/resourceFilterAssetHelper'; -import { loadResourceFilterAssets } from '../helpers/resourceFilterAssetsDataFlow'; - -interface IUseFilterAssets { - isLoadingAssets: boolean; - typeAssets: Asset[]; - formatAssets: Asset[]; - vendorAssets: Asset[]; - setAvailableTypeAssetIds: (assets: string[]) => void; - setAvailableFormatAssetIds: (assets: string[]) => void; - updateAssetFilter: (asset: Asset) => void; -} - -export const useResourceFilterAssets = (): IUseFilterAssets => { - const [isLoading, setIsLoading] = useState(true); - const [typeAssets, setTypeAssets] = useState([]); - const [availableTypeAssetIds, setAvailableTypeAssetIds] = useState([]); - const [formatAssets, setFormatAssets] = useState([]); - const [availableFormatAssetIds, setAvailableFormatAssetIds] = useState([]); - - useEffect(() => { - loadResourceFilterAssets() - .then(({ resourceTypes, resourceFormats }) => { - console.debug('resourceTypes:', resourceTypes); - setTypeAssets(resourceTypes.map((resourceType) => createAsset(resourceType, TYPE_ASSETS))); - console.debug('resourceFormats:', resourceFormats); - setFormatAssets(resourceFormats.map((resourceFormat => createAsset(resourceFormat, FORMAT_ASSETS)))) - }) - .finally(() => { - setIsLoading(false); - }); - - }, []); - - useEffect(() => { - setTypeAssets(disableNonAvailableAssets(typeAssets, availableTypeAssetIds)) - }, [availableTypeAssetIds]) - - useEffect(() => { - setFormatAssets(disableNonAvailableAssets(formatAssets, availableFormatAssetIds)) - }, [availableFormatAssetIds]) - - return { - isLoadingAssets: isLoading, - typeAssets, - formatAssets, - vendorAssets: [ - // Demo values for vendor assets. Should be replaced by dynamic loading of vendor information. At the moment this - // information is not available in the ontologies and shacl shapes. It can not be retrieved from the backend. - createAsset('3D Mapping', VENDOR_ASSETS, true), - createAsset('TrainGraphics', VENDOR_ASSETS, true), - createAsset('DLR', VENDOR_ASSETS, true), - ], - setAvailableTypeAssetIds, - setAvailableFormatAssetIds, - updateAssetFilter: (asset: Asset) => updateAssetFilter(asset, { - setTypeAssets, - typeAssets, - setFormatAssets, - formatAssets - }) - , - } -}; diff --git a/src/components/resources/hooks/useResources.ts b/src/components/resources/hooks/useResources.ts index cd2984e8..0b127f49 100644 --- a/src/components/resources/hooks/useResources.ts +++ b/src/components/resources/hooks/useResources.ts @@ -1,79 +1,86 @@ import { useEffect, useMemo, useState } from 'react'; import { Resource } from '../../../types/resources.model'; -import { loadResources } from '../helpers/resourceDataFlow'; -import { applyFilters, removeDataResourceLabels } from '../helpers/resourcesHelper'; - -import { useResourceFilterAssets } from './useResourceFilterAssets'; +import { loadResourceSearchPageData } from '../helpers/resourceDataFlow'; +import { Asset, updateFilterAsset } from '../helpers/resourceFilterAssetHelper'; +import { applyFilters, createFormatAssets, createTypeAssets, removeDataResourceLabels } from '../helpers/resourcesHelper'; export type ResourcesViewState = 'LOADING' | 'SHOW_RESOURCES' | 'SHOW_NO_RESULTS'; export const useResources = () => { const [resources, setResources] = useState([]) + + const [typeAssets, setTypeAssets] = useState([]); + const [formatAssets, setFormatAssets] = useState([]); + const [vendorAssets, setVendorAssets] = useState([]); + const [isLoading, setIsLoading] = useState(true); const [searchText, setSearchText] = useState('') - const { - isLoadingAssets, - typeAssets, - formatAssets, - vendorAssets, - setAvailableTypeAssetIds, - setAvailableFormatAssetIds, - updateAssetFilter - } = useResourceFilterAssets(); useEffect(() => { - if (!isLoadingAssets) { - loadResources(typeAssets) - .then((fetchedResources) => { - setResources(fetchedResources); - setAvailableTypeAssetIds(removeDataResourceLabels(fetchedResources).map(resource => resource.labels).flat() - ) - }) - .finally(() => setIsLoading(false)); - } - }, [isLoadingAssets]); + loadResourceSearchPageData() + .then((data) => { + setResources(data.resources); + + const resourceTypeAssets = createTypeAssets(data.resourceTypes, data.resources); + setTypeAssets(resourceTypeAssets); - const filterAssets = useMemo(() => [typeAssets, formatAssets, vendorAssets].flat(), - [typeAssets, formatAssets, vendorAssets]) + const resourceFormatAssets = createFormatAssets( + data.resourceFormats, + resourceTypeAssets, + data.resources, + [] + ); + setFormatAssets(resourceFormatAssets); + }) + .finally(() => setIsLoading(false)); + }, []); - const filteredResources = useMemo(() => applyFilters(resources, searchText, filterAssets), - [resources, searchText, filterAssets]) + const filteredResources = useMemo(() => applyFilters( + resources, + searchText, + [...typeAssets, ...formatAssets, ...vendorAssets] + ), + [resources, searchText, typeAssets, formatAssets, vendorAssets]) + // Recreate format filter assets in order to update their disables flag when type filter asset has been changed. useEffect(() => { - setAvailableFormatAssetIds(filteredResources - .filter(resource => !!resource.format) - .map(resource => resource.format)) - // Depending on the length of the filtered resources is important. Otherwise, there is a cyclic dependency in this - // hook. The filtered resources list depends on the format asset list. The format asset list depends on the - // available format asset id list. The available format asset id list is changed inside this use effect. If this - // use effect was depending on the filtered resource list instead of its length it would have triggered an - // infinite rerender cycle. By using the length, even when filtered resource list is rerendered the length - // wouldn't change only if there is a change in the filters. - }, [filteredResources.length]); + const formats = formatAssets.map(asset => asset.id); + const selectedFormats = formatAssets.filter(asset => asset.value); + + setFormatAssets(createFormatAssets( + formats, + typeAssets, + resources, + selectedFormats + )) + }, [typeAssets]); const state = useMemo(() => { - if (isLoading || isLoadingAssets) { + if (isLoading) { return 'LOADING' } else if (filteredResources.length) { return 'SHOW_RESOURCES' } else { return 'SHOW_NO_RESULTS' } - }, [filteredResources, isLoading, isLoadingAssets]) + }, [filteredResources, isLoading]) - const search = (filter: string) => { - setSearchText(filter) - }; + const updateSearchText = (filter: string) => setSearchText(filter); return { resources: removeDataResourceLabels(filteredResources), - state, typeAssets, formatAssets, vendorAssets, - search, - updateAssetFilter + state, + updateSearchText, + updateFilterAsset: (asset: Asset) => updateFilterAsset(asset, { + typeAssets, + setTypeAssets, + formatAssets, + setFormatAssets + }) } } diff --git a/src/services/cypherQueryApiService.ts b/src/services/cypherQueryApiService.ts index dfdd0bef..1d915c22 100644 --- a/src/services/cypherQueryApiService.ts +++ b/src/services/cypherQueryApiService.ts @@ -1,6 +1,5 @@ import axios from 'axios'; -import { Asset } from '../components/resources/helpers/resourceFilterAssetHelper'; import { ISelfDescription, ResourceInput, ServiceOfferingInput } from '../utils/dataMapper'; const getHeaders = () => { @@ -63,30 +62,28 @@ export const CypherQueryApiService = { /** * Returns all resources of type included in the type asset list passed in as parameter. * - * @param typeFilters the list of requested resource types + * @param types the list of requested resource types */ - async getAllResources(typeFilters: Asset[]): Promise { - const whereDataResource = typeFilters.length ? ` - WHERE ANY (label IN labels(resource) WHERE label IN [ '${typeFilters.map(asset => asset.label).join('\', \'')}']) - AND 'DataResource' IN labels(resource) - AND NOT resource.uri STARTS WITH 'bnode://'` - : '' - - const matchFormatPropertyNode = ` - OPTIONAL MATCH(formatProperty) - WHERE resource.uri IN formatProperty.claimsGraphUri - AND ANY(label IN labels(formatProperty) WHERE label CONTAINS 'Format')` - - const matchCopyrightOwnedBy = ` - OPTIONAL MATCH(copyrightOwner) - WHERE copyrightOwner.uri = resource.copyrightOwnedBy` + async getAllResources(types: string[]): Promise { + if (!types.length) { + return { items: [] }; + } + const typeLabels = types.join('\', \''); return cypherQuery({ statement: ` MATCH (resource) - ${whereDataResource} - ${matchFormatPropertyNode} - ${matchCopyrightOwnedBy} + WHERE ANY (label IN labels(resource) WHERE label IN [ '${typeLabels}']) + AND 'DataResource' IN labels(resource) + AND NOT resource.uri STARTS WITH 'bnode://' + + OPTIONAL MATCH(formatProperty) + WHERE resource.uri IN formatProperty.claimsGraphUri + AND ANY(label IN labels(formatProperty) WHERE label CONTAINS 'Format') + + OPTIONAL MATCH(copyrightOwner) + WHERE copyrightOwner.uri = resource.copyrightOwnedBy + RETURN properties(resource) AS properties, labels(resource) AS labels, From eb23e292b597b6816e9c7de1a443e6ca6ab6ce80 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Thu, 19 Sep 2024 11:27:00 +0300 Subject: [PATCH 03/33] Create schema state in redux Signed-off-by: Zoltan Magyari --- src/actions/schemasActions.ts | 27 +++++++++++++++++++++++++++ src/actions/{types.js => types.ts} | 11 ++++++++--- src/reducers/index.js | 6 +++--- src/reducers/schemasReducer.ts | 26 ++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/actions/schemasActions.ts rename src/actions/{types.js => types.ts} (61%) create mode 100644 src/reducers/schemasReducer.ts diff --git a/src/actions/schemasActions.ts b/src/actions/schemasActions.ts new file mode 100644 index 00000000..f3fc27b3 --- /dev/null +++ b/src/actions/schemasActions.ts @@ -0,0 +1,27 @@ +import { Ontology } from '../types/ontologies.model'; +import { Shape } from '../types/shapes.model'; + +import { SET_ALL_SCHEMAS, SET_ALL_SCHEMAS_LOADING_ERROR } from './types'; + +export type AllSchemas = { + ontologies: Ontology[]; + shapes: Shape[]; +} + +export type AllSchemasError = { + error: string; +} + +export type AllSchemasAction = + { type: 'SET_ALL_SCHEMAS', payload: AllSchemas } | + { type: 'SET_ALL_SCHEMAS_LOADING_ERROR', payload: AllSchemasError } + +export const schemasLoadedAction = (payload: AllSchemas): AllSchemasAction => ({ + type: SET_ALL_SCHEMAS, + payload +}) + +export const schemasLoadingErrorAction = (payload: AllSchemasError): AllSchemasAction => ({ + type: SET_ALL_SCHEMAS_LOADING_ERROR, + payload +}) diff --git a/src/actions/types.js b/src/actions/types.ts similarity index 61% rename from src/actions/types.js rename to src/actions/types.ts index 3c9e94fb..dfa995a6 100644 --- a/src/actions/types.js +++ b/src/actions/types.ts @@ -1,5 +1,6 @@ -export const SIGN_IN_MENU = 'SIGN_IN_MENU'; -export const NOT_SIGN_IN_MENU = 'NOT_SIGN_IN_MENU'; +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// export const SIGN_IN = 'SIGN_IN'; export const SIGN_OUT = 'SIGN_OUT'; export const UPDATE_SEARCH_FILTER_CRITERIA = 'UPDATE_SEARCH_FILTER_CRITERIA'; @@ -7,7 +8,6 @@ export const UPDATE_SEARCH_PAGE_NUMBER = 'UPDATE_SEARCH_PAGE_NUMBER'; export const UPDATE_SEARCH_TYPE = 'UPDATE_SEARCH_TYPE'; export const UPDATE_SEARCH_TYPE_AND_TERM = 'UPDATE_SEARCH_TYPE_AND_TYPE'; export const UPDATE_SEARCH_FROM_HOME = 'UPDATE_SEARCH_FROM_HOME'; -export const UPDATE_SELECTED_PAGE = 'UPDATE_SELECTED_PAGE'; export const SET_DESCRIPTOR_FILE = 'SET_DESCRIPTOR_FILE'; export const RESET_DESCRIPTOR_FILE = 'RESET_DESCRIPTOR_FILE'; export const LCM_SERVICES_LOADED = 'LCM_SERVICES_LOADED'; @@ -15,3 +15,8 @@ export const RESET_LCM_SERVICES = 'RESET_LCM_SERVICES'; export const LCM_SELECT_SERVICE = 'LCM_SELECT_SERVICE'; export const CHANGE_USER_ROLE = 'CHANGE_USER_ROLE' +//////////////////////////////////////////////////////////////////////////////// +// Schemas +//////////////////////////////////////////////////////////////////////////////// +export const SET_ALL_SCHEMAS = 'SET_ALL_SCHEMAS'; +export const SET_ALL_SCHEMAS_LOADING_ERROR = 'SET_ALL_SCHEMAS_LOADING_ERROR'; diff --git a/src/reducers/index.js b/src/reducers/index.js index 1159ab59..eb6521ac 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,15 +1,15 @@ import { combineReducers } from 'redux'; -// import signinReducer from "./signinReducer"; import searchCriteriaStore from './SearchCriteriaStore'; import lcmReducer from './lcmReducer'; +import schemas from './schemasReducer' import serviceDescriptorReducer from './serviceDescriptorReducer'; import userReducer from './userReducer'; export default combineReducers({ - // signin: signinReducer, user: userReducer, searchCriteriaStore: searchCriteriaStore, serviceDescriptor: serviceDescriptorReducer, - lcm: lcmReducer + lcm: lcmReducer, + schemas, }); diff --git a/src/reducers/schemasReducer.ts b/src/reducers/schemasReducer.ts new file mode 100644 index 00000000..fd662845 --- /dev/null +++ b/src/reducers/schemasReducer.ts @@ -0,0 +1,26 @@ +import { AllSchemas, AllSchemasAction, AllSchemasError } from '../actions/schemasActions'; +import { SET_ALL_SCHEMAS, SET_ALL_SCHEMAS_LOADING_ERROR } from '../actions/types'; + +type IsLoading = { isLoading: boolean; } +export type AllSchemasState = (AllSchemas & { hasError: false } | AllSchemasError & { hasError: true }) & IsLoading + +const initialState: AllSchemasState = { + isLoading: true, + hasError: false, + shapes: [], + ontologies: [] +} + +export default (state: AllSchemasState = initialState, action: AllSchemasAction) => { + switch (action.type) { + + case SET_ALL_SCHEMAS: + return { ...action.payload, isLoading: false, hasError: false } + + case SET_ALL_SCHEMAS_LOADING_ERROR: + return { error: action.payload, isLoading: false, hasError: true } + + } + return state + +} From f8549d32620c7c289c6c9b2526b7e1405c7010d6 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Thu, 19 Sep 2024 11:30:35 +0300 Subject: [PATCH 04/33] Create SchemasContext - in order to fetch ontologies and shacl shapes already when the app has started. - a useSchemas hook was crated inorder to simplify the refactoring in case the context is not the right place to fetch the data. Signed-off-by: Zoltan Magyari --- src/context/ResourceContext.tsx | 53 ------------------------------- src/context/SchemasContext.tsx | 56 +++++++++++++++++++++++++++++++++ src/hooks/useSchemas.ts | 39 +++++++++++++++++++++++ src/index.js | 7 +++-- 4 files changed, 99 insertions(+), 56 deletions(-) delete mode 100644 src/context/ResourceContext.tsx create mode 100644 src/context/SchemasContext.tsx create mode 100644 src/hooks/useSchemas.ts diff --git a/src/context/ResourceContext.tsx b/src/context/ResourceContext.tsx deleted file mode 100644 index 06d867a9..00000000 --- a/src/context/ResourceContext.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { createContext, ReactNode } from 'react'; - -// TODO: It is an example how to create a context. It is not used yet and does not contain any useful state either. - -/** - * Defines the type of the data stored in the context - */ -interface ResourceStore { - // TODO: define store data type here -} - -/** - * Initial values in the resource store context - */ -const initialState = { - // TODO: Define initial state of the store -} as ResourceStore; - -/** - * Definition of the {@link ResourceStore} context - * - * Usage: const { var1, var2, ... } = useContext(ResourceContext) - */ -const ResourceContext = createContext(initialState); - -/** - * Defines the type of the {@link ResourceContextProvider}'s input props - */ -interface ResourceContextProviderProps { - children: ReactNode; -} - -/** - * Provider for the {@link ResourceContext} - * - * Contains the global states of the resources and anything else that needs to be accessible via the context. - * - * @param children in order to use it like a React component and make available the states to all children - * components, it has to be passed in as input prop. - */ -export const ResourceContextProvider: React.FC = ({ children }) => { - // TODO: define global state variables and functions here - - return ( - - {children} - - ); -}; - diff --git a/src/context/SchemasContext.tsx b/src/context/SchemasContext.tsx new file mode 100644 index 00000000..645689eb --- /dev/null +++ b/src/context/SchemasContext.tsx @@ -0,0 +1,56 @@ +import React, { createContext, ReactNode } from 'react'; + +import { useSchemas } from '../hooks/useSchemas'; +import { AllSchemasState } from '../reducers/schemasReducer'; + +/** + * Defines the type of the data stored in the context + */ +type SchemasStore = AllSchemasState + +/** + * Initial values in the resource store context + */ +const initialState = { + shapes: [], + ontologies: [], + isLoading: true, + hasError: false +} as SchemasStore; + +/** + * Definition of the {@link SchemasStore} context + * + * Usage: const { var1, var2, ... } = useContext(SchemasContext) + */ +export const SchemasContext = createContext(initialState); + +/** + * Defines the type of the {@link SchemasContextProvider}'s input props + */ +interface ResourceContextProviderProps { + children: ReactNode; +} + +/** + * Provider for the {@link SchemasContext} + * + * Contains the global states of the resources and anything else that needs to be accessible via the context. + * + * @param children in order to use it like a React component and make available the states to all children + * components, it has to be passed in as input prop. + */ +export const SchemasContextProvider: React.FC = ({ children }) => { + const { isLoading, shapes, ontologies } = useSchemas(); + + return ( + + {children} + + ); +}; + diff --git a/src/hooks/useSchemas.ts b/src/hooks/useSchemas.ts new file mode 100644 index 00000000..6a52d516 --- /dev/null +++ b/src/hooks/useSchemas.ts @@ -0,0 +1,39 @@ +import { useContext, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import { schemasLoadedAction } from '../actions/schemasActions'; +import { AuthContext } from '../context/AuthContextProvider'; +import { fetchAllOntologiesFromSchemas } from '../services/ontologyService.utils'; +import { fetchAllSchemas } from '../services/schemaApiService'; +import { fetchAllShapesFromSchemas } from '../services/shapeService.utils'; + +export const useSchemas = () => { + const authContext = useContext(AuthContext); + const dispatch = useDispatch(); + const { isLoading, shapes, ontologies } = useSelector((state) => ({ + isLoading: state.schemas.isLoading, + shapes: state.schemas.shapes, + ontologies: state.schemas.ontologies + })) + + useEffect(() => { + if (authContext.isAuthenticated) { + (async () => { + const schemas = await fetchAllSchemas(); + const shapes = await fetchAllShapesFromSchemas(schemas); + const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes) + + dispatch(schemasLoadedAction({ + shapes, + ontologies + })) + })(); + } + }, [authContext.isAuthenticated]); + + return { + isLoading, + shapes, + ontologies + } +} diff --git a/src/index.js b/src/index.js index 5507f4db..2b35f722 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ import { Provider } from 'react-redux'; import './i18n'; import App from './App'; import AuthContextProvider from './context/AuthContextProvider'; -import { ResourceContextProvider } from './context/ResourceContext'; +import { SchemasContextProvider } from './context/SchemasContext'; import reducers from './reducers'; import './index.css'; @@ -36,6 +36,7 @@ const store = configureStore({ preloadedState: persistedStore, }); +// TODO: May be not the entire store should be saved into cookies. It has to be refactored. store.subscribe(() => { saveToLocalStorage(store.getState()); }); @@ -46,9 +47,9 @@ const root = createRoot(container); // createRoot(container!) if you use TypeScr root.render( - + - + ); From 644026c43e1e3a42b18f7ef75771f84293ce7e96 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 20 Sep 2024 06:33:10 +0300 Subject: [PATCH 05/33] Fix redux state type Signed-off-by: Zoltan Magyari --- src/configureStore.ts | 11 ++++++++++ src/index.js | 9 ++------ src/reducers/index.js | 15 ------------- src/reducers/index.ts | 50 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 src/configureStore.ts delete mode 100644 src/reducers/index.js create mode 100644 src/reducers/index.ts diff --git a/src/configureStore.ts b/src/configureStore.ts new file mode 100644 index 00000000..c2a79694 --- /dev/null +++ b/src/configureStore.ts @@ -0,0 +1,11 @@ +import { configureStore as configure_store } from '@reduxjs/toolkit'; +import { Store } from 'redux'; + +import reducers, { AppState } from './reducers'; + +export const configureStore = (persistedStore: any): Store => + configure_store({ + reducer: reducers, + preloadedState: persistedStore, + }) + diff --git a/src/index.js b/src/index.js index 2b35f722..58d49cf6 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,12 @@ -import { configureStore } from '@reduxjs/toolkit'; import React from 'react'; import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; import './i18n'; import App from './App'; +import { configureStore } from './configureStore'; import AuthContextProvider from './context/AuthContextProvider'; import { SchemasContextProvider } from './context/SchemasContext'; -import reducers from './reducers'; import './index.css'; @@ -30,11 +29,7 @@ const loadFromLocalStorage = () => { }; const persistedStore = loadFromLocalStorage(); - -const store = configureStore({ - reducer: reducers, - preloadedState: persistedStore, -}); +const store = configureStore(persistedStore); // TODO: May be not the entire store should be saved into cookies. It has to be refactored. store.subscribe(() => { diff --git a/src/reducers/index.js b/src/reducers/index.js deleted file mode 100644 index eb6521ac..00000000 --- a/src/reducers/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import { combineReducers } from 'redux'; - -import searchCriteriaStore from './SearchCriteriaStore'; -import lcmReducer from './lcmReducer'; -import schemas from './schemasReducer' -import serviceDescriptorReducer from './serviceDescriptorReducer'; -import userReducer from './userReducer'; - -export default combineReducers({ - user: userReducer, - searchCriteriaStore: searchCriteriaStore, - serviceDescriptor: serviceDescriptorReducer, - lcm: lcmReducer, - schemas, -}); diff --git a/src/reducers/index.ts b/src/reducers/index.ts new file mode 100644 index 00000000..8abef4be --- /dev/null +++ b/src/reducers/index.ts @@ -0,0 +1,50 @@ +import { Reducer } from 'react'; +import { AnyAction, combineReducers } from 'redux'; + +import { Ontology } from '../types/ontologies.model'; +import { Resource } from '../types/resources.model'; +import { Shape } from '../types/shapes.model'; + +import searchCriteriaStore from './SearchCriteriaStore'; +import lcmReducer from './lcmReducer'; +import resources from './resourcesReducer'; +import schemas from './schemasReducer'; +import serviceDescriptorReducer from './serviceDescriptorReducer'; +import userReducer from './userReducer'; + +export interface AppState { +// TODO: It is a quick fix to make the redux state to have a type in the typescript files. Each property type must be +// declared properly. + user: { + 'first_name': string, + 'family_name': string, + 'email': string, + 'user_role': string, + 'organization_url': string, + 'organization_name': string, + 'organization_realm': string + }, + // searchCriteriaStore: { ... }, + // serviceDescriptor: { ... }, + // lcm: { ... }, + schemas: { + isLoading: true, + hasError: false, + shapes: Shape[], + ontologies: Ontology[], + }, + resources: { + isLoading: true, + hasError: false, + resources: Resource[] + } +} + +export default combineReducers>({ + user: userReducer, + searchCriteriaStore: searchCriteriaStore, + serviceDescriptor: serviceDescriptorReducer, + lcm: lcmReducer, + schemas, + resources, +}); From 943e979fc73b9a8b0d627102e99bc3be23bcd0b7 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 20 Sep 2024 11:28:24 +0300 Subject: [PATCH 06/33] Create resources state in redux Signed-off-by: Zoltan Magyari --- src/actions/resourcesActions.ts | 25 +++++++++++++++++++++++++ src/actions/types.ts | 9 ++++++--- src/reducers/resourcesReducer.ts | 25 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/actions/resourcesActions.ts create mode 100644 src/reducers/resourcesReducer.ts diff --git a/src/actions/resourcesActions.ts b/src/actions/resourcesActions.ts new file mode 100644 index 00000000..74b493fb --- /dev/null +++ b/src/actions/resourcesActions.ts @@ -0,0 +1,25 @@ +import { Resource } from '../types/resources.model'; + +import { SET_ALL_RESOURCES, SET_ALL_RESOURCES_LOADING_ERROR } from './types'; + +export type AllResources = { + resources: Resource[] +}; + +export type AllResourceError = { + error: string; +} + +export type AllResourcesAction = + { type: 'SET_ALL_RESOURCES', payload: AllResources } | + { type: 'SET_ALL_RESOURCES_LOADING_ERROR', payload: AllResourceError } + +export const resourcesLoadedAction = (payload: AllResources): AllResourcesAction => ({ + type: SET_ALL_RESOURCES, + payload +}) + +export const resourcesLoadingErrorAction = (payload: AllResourceError): AllResourcesAction => ({ + type: SET_ALL_RESOURCES_LOADING_ERROR, + payload +}) diff --git a/src/actions/types.ts b/src/actions/types.ts index dfa995a6..40be0001 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -1,6 +1,3 @@ -//////////////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////////////// export const SIGN_IN = 'SIGN_IN'; export const SIGN_OUT = 'SIGN_OUT'; export const UPDATE_SEARCH_FILTER_CRITERIA = 'UPDATE_SEARCH_FILTER_CRITERIA'; @@ -20,3 +17,9 @@ export const CHANGE_USER_ROLE = 'CHANGE_USER_ROLE' //////////////////////////////////////////////////////////////////////////////// export const SET_ALL_SCHEMAS = 'SET_ALL_SCHEMAS'; export const SET_ALL_SCHEMAS_LOADING_ERROR = 'SET_ALL_SCHEMAS_LOADING_ERROR'; + +//////////////////////////////////////////////////////////////////////////////// +// Resources +//////////////////////////////////////////////////////////////////////////////// +export const SET_ALL_RESOURCES = 'SET_ALL_RESOURCES'; +export const SET_ALL_RESOURCES_LOADING_ERROR = 'SET_ALL_RESOURCES_LOADING_ERROR'; diff --git a/src/reducers/resourcesReducer.ts b/src/reducers/resourcesReducer.ts new file mode 100644 index 00000000..b74a121b --- /dev/null +++ b/src/reducers/resourcesReducer.ts @@ -0,0 +1,25 @@ +import { AllResourceError, AllResources, AllResourcesAction } from '../actions/resourcesActions'; +import { SET_ALL_RESOURCES, SET_ALL_RESOURCES_LOADING_ERROR } from '../actions/types'; + +type IsLoading = { isLoading: boolean; } +export type AllResourcesState = (AllResources & { hasError: false } | AllResourceError & { hasError: true }) & IsLoading + +const initialState: AllResourcesState = { + isLoading: true, + hasError: false, + resources: [] +} + +export default (state: AllResourcesState = initialState, action: AllResourcesAction) => { + switch (action.type) { + + case SET_ALL_RESOURCES: + return { ...action.payload, isLoading: false, hasError: false } + + case SET_ALL_RESOURCES_LOADING_ERROR: + return { error: action.payload, isLoading: false, hasError: true } + + } + return state + +} From 113094323a0bcfcff60209ea98ab447dac2d6a69 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 20 Sep 2024 14:55:33 +0300 Subject: [PATCH 07/33] Implement the vendor and fix circular reference and rerendering problem Signed-off-by: Zoltan Magyari --- src/components/resources/Resources.tsx | 10 +- .../resources/helpers/resourceDataFlow.ts | 50 +---- .../helpers/resourceFilterAssetHelper.ts | 180 ++++++++++++------ .../resources/helpers/resourcesHelper.ts | 126 +----------- .../resources/hooks/useResources.ts | 170 +++++++++++------ src/services/ontologyService.utils.ts | 8 +- src/types/resources.model.ts | 4 +- src/utils/dataMapper.ts | 9 +- tests/services/ontologyService.utils.test.ts | 2 +- 9 files changed, 256 insertions(+), 303 deletions(-) diff --git a/src/components/resources/Resources.tsx b/src/components/resources/Resources.tsx index 50a0092e..a7204526 100644 --- a/src/components/resources/Resources.tsx +++ b/src/components/resources/Resources.tsx @@ -19,7 +19,7 @@ const Resources = () => { const { t } = useTranslation(); const { resources, - state, + viewContentType, typeAssets, formatAssets, vendorAssets, @@ -39,11 +39,11 @@ const Resources = () => { updateAssetFilter={updateFilterAsset} /> - + - - + + { resources.map((resource) => ( { + visible={viewContentType === 'SHOW_NO_RESULTS'}/> diff --git a/src/components/resources/helpers/resourceDataFlow.ts b/src/components/resources/helpers/resourceDataFlow.ts index 547f71f0..ccf9c6d5 100644 --- a/src/components/resources/helpers/resourceDataFlow.ts +++ b/src/components/resources/helpers/resourceDataFlow.ts @@ -1,31 +1,7 @@ import { CypherQueryApiService as cypherQuery } from '../../../services/cypherQueryApiService'; -import { - fetchAllOntologiesFromSchemas, - getResourceFormats, - getResourceTypes -} from '../../../services/ontologyService.utils'; -import { fetchAllSchemas } from '../../../services/schemaApiService'; -import { fetchAllShapesFromSchemas } from '../../../services/shapeService.utils'; import { Resource } from '../../../types/resources.model'; import { mapResources } from '../../../utils/dataMapper'; -export interface ResourceSearchPageData { - resources: Resource[], - resourceTypes: string[], - resourceFormats: string[] -} - -export const loadResourceSearchPageData = async (): Promise => { - const { resourceTypes, resourceFormats } = await loadResourceFilterAssets(); - const resources = await loadResources(resourceTypes); - - return { - resources, - resourceTypes, - resourceFormats - } -} - /** * Loads resources for which the following criteria are met: * - the node labels should contain at least one of the selected filters passed in as `typeFilter` param @@ -35,7 +11,7 @@ export const loadResourceSearchPageData = async (): Promise => +export const loadResources = async (resourceTypes: string[]): Promise => cypherQuery .getAllResources(resourceTypes) .then((resourceInput) => mapResources(resourceInput)) @@ -43,27 +19,3 @@ const loadResources = async (resourceTypes: string[]): Promise => console.error('Error fetching resources:', error); throw error; }); - -/** - * Loads resource filter assets. - * - * @return a list of each resource assets - */ -const loadResourceFilterAssets = async (): Promise<{ - resourceTypes: string[]; - resourceFormats: string[]; -}> => { - try { - const schemas = await fetchAllSchemas(); - const shapes = await fetchAllShapesFromSchemas(schemas); - const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes) - - const resourceTypes = getResourceTypes(ontologies); - const resourceFormats = getResourceFormats(ontologies); - - return { resourceTypes, resourceFormats }; - } catch (error) { - console.error('Error loading filter assets', error); - throw error; - } -} diff --git a/src/components/resources/helpers/resourceFilterAssetHelper.ts b/src/components/resources/helpers/resourceFilterAssetHelper.ts index 6c52cc26..7614231e 100644 --- a/src/components/resources/helpers/resourceFilterAssetHelper.ts +++ b/src/components/resources/helpers/resourceFilterAssetHelper.ts @@ -1,3 +1,5 @@ +import { Resource } from '../../../types/resources.model'; + export const TYPE_ASSETS = 'typeAssets'; export const FORMAT_ASSETS = 'formatAssets'; export const VENDOR_ASSETS = 'vendorAssets'; @@ -15,79 +17,135 @@ export interface Asset { } /** - * The type of the updateAssetFilter method + * Creates from a resource type string list a resource type asset list. + * + * @param resourceTypes the resource type string list + * @param resources the list of resources to determine which asset should be disabled. + * @return the list of resource type assets. */ -type UpdateAssetFilterMethod = ( - asset: Asset, - assetFilterInterface: { - typeAssets: Asset[] - setTypeAssets: (assets: Asset[]) => void - formatAssets: Asset[] - setFormatAssets: (assets: Asset[]) => void - }) => void; +export const createTypeAssets = (resourceTypes: string[], resources: Resource[]) => { + const resourceLabels = getAllLabels(resources); + return resourceTypes.map(type => ({ + id: type, + type: 'typeAssets', + label: type, + value: false, + disabled: !resourceLabels.has(type) + } as Asset)); +} /** - * Update logic of an asset. Based on the type of the asset calls the proper setter and uses the proper current - * values to generate the updated values. + * Returns a set of all available labels in the list of resources. * - * @param asset to be updated - * @param typeAssets the current type assets list - * @param setTypeAssets the setter of the type assets list - * @param formatAssets the current format assets list - * @param setFormatAssets the setter of the format assets list + * @param resources the list of resources to look for the labels in. + * @return the set of available labels. */ -export const updateFilterAsset: UpdateAssetFilterMethod = (asset, { - typeAssets, - setTypeAssets, - formatAssets, - setFormatAssets -}) => { - switch (asset.type) { - case TYPE_ASSETS: - setTypeAssets(typeAssets - .map(item => item.id === asset.id ? asset : item)) - break - case FORMAT_ASSETS: - setFormatAssets(formatAssets - .map(item => item.id === asset.id ? asset : item)) - break - default: - console.info('The \'updateAsset\' method is not implemented for the following asset', asset); - } +export const getAllLabels = (resources: Resource[]) => + new Set( + resources + .map(resource => resource.labels) + .flat() + .filter(label => !!label) + ); + +/** + * Creates from a resource format string list a resource format asset list. + * + * @param resourceFormats the resource format string list. + * @param prevFormatAssets the previous format asset list in order to preserve the selected state of the asset. + * @param resources the list of resources to determine which asset should be disabled. + * @return the list of resource format assets. + */ +export const createFormatAssets = ( + resourceFormats: string[], + prevFormatAssets: Asset[], + resources: Resource[], +) => { + const availableFormats = getAllFormats(resources); + return resourceFormats.map(format => ({ + id: format, + type: 'formatAssets', + label: format, + value: prevFormatAssets.some(asset => asset.value && asset.id === format), + disabled: !availableFormats.has(format) + } as Asset)) +} + +/** + * Returns a set of all available formats in the list of resources. + * + * @param resources the list of resources to look for the formats in. + * @return the set of available labels. + */ +const getAllFormats = (resources: Resource[]) => + new Set( + resources + .map(resource => resource.format) + .flat() + .filter(label => !!label) + ); + +/** + * Creates from a resource vendor string list a resource vendor asset list. + * + * @param resourceVendors the resource vendor string list. + * @param prevVendorAssets the previous vendor asset list in order to preserve the selected state of the asset. + * @param resources the list of resources to determine which asset should be disabled. + * @return the list of resource vendor assets. + */ +export const createVendorAssets = ( + resourceVendors: string[], + prevVendorAssets: Asset[], + resources: Resource[], +) => { + const availableVendors = getResourceVendors(resources); + return resourceVendors.map(vendor => ({ + id: vendor, + type: 'vendorAssets', + label: vendor, + value: prevVendorAssets.some(asset => asset.value && asset.id === vendor), + disabled: !availableVendors.has(vendor) + } as Asset)) } /** - * Asset object factory. + * Returns a set of all available vendors in the list of resources. * - * @param label displayed on the UI - * @param type of the asset - * @param disabled should appear disabled on the UI - * @return the new asset + * @param resources the list of resources to look for the formats in. + * @return the set of available labels. + */ +export const getResourceVendors = (resources: Resource[]) => + new Set( + resources + .map(resource => resource.vendor) + .flat() + .filter(label => !!label) + ); + +/** + * Represents a list of assets that are selected. It has an ALL option which means that everything is selected. No + * list should be provided. */ -export const createAsset = ( - label: string, - type: AssetTypes, - disabled: boolean = true -): Asset => ({ - id: label, - type, - label, - value: false, - disabled -}) +export type SelectedAssets = 'ALL' | string[]; /** - * Makes a copy of the assets list, where all items which ids are not present in the available asset id list are - * marked as disabled. + * Returns the selected assets from the list. It has an ALL option which means that everything is selected. No list + * should be provided. + * + * An asset is considered selected when it is not disabled and its value is true. * - * @param assets original asset list - * @param availableAssetIds asset ids which are considered as available - * @return the updated asset list + * If no asset is selected it is considered that everything is selected and in that case it is returned 'ALL'. + * + * @param assets list to be filtered for the selected one. */ -export const disableNonAvailableAssets = (assets: Asset[], availableAssetIds: string[]): Asset[] => ( - assets.map((asset) => ({ - ...asset, - disabled: !availableAssetIds.some(availableAssetId => availableAssetId === asset.id) - })) -) +export const getSelectedAssets = (assets: Asset[]): SelectedAssets => { + let selectedAssets = assets + .filter(asset => !asset.disabled && asset.value) + .map(asset => asset.id) + // If type filter is selected it is considered that all enabled ones are selected + if (!selectedAssets.length) { + return 'ALL' + } + return selectedAssets; +} diff --git a/src/components/resources/helpers/resourcesHelper.ts b/src/components/resources/helpers/resourcesHelper.ts index 4a6530d3..0318b022 100644 --- a/src/components/resources/helpers/resourcesHelper.ts +++ b/src/components/resources/helpers/resourcesHelper.ts @@ -1,132 +1,24 @@ import { Resource } from '../../../types/resources.model'; -import { Asset, createAsset, FORMAT_ASSETS, TYPE_ASSETS } from './resourceFilterAssetHelper'; - -/** - * Checks if a resource corresponds to a certain criteria represented by the asset. - * - * @param resource to be checked - * @param assets contains the method and the information to check against - * @return true if corresponds, false otherwise - */ -export const assetFilterPredicate = (resource: Resource, assets: Asset[]): boolean => { - const typeAssets = assets.filter(asset => asset.value && asset.type === TYPE_ASSETS) - const typeFiltersApply = !typeAssets.length - || typeAssets.some(asset => typeAssetPredicate(resource, asset)) - - const formatAssets = assets.filter(asset => asset.value && asset.type === FORMAT_ASSETS) - const formatFiltersApply = !formatAssets.length - || formatAssets.some(asset => formatAssetPredicate(resource, asset)) - - return typeFiltersApply && formatFiltersApply -} - /** - * Checks if a resource is of a certain type defined in the asset. + * Returns the value of an object property represented as an object entry. * - * @param resource to be checked - * @param asset containing the type to be checked against. - * @return true if it is, false otherwise. + * @param objectEntry the object property for which the value should be returned. */ -const typeAssetPredicate = (resource: Resource, asset: Asset): boolean => ( - resource.labels - .map(label => label.toLowerCase()) - .includes(asset.label.toLowerCase()) -) +export const getPropertyValue = (objectEntry: [string, any]) => String(objectEntry[1]) /** - * Checks if a resource has a certain format defined in the asset. - * - * @param resource to be checked - * @param asset containing the format to be checked against. - * @return true if it is, false otherwise. - */ -const formatAssetPredicate = (resource: Resource, asset: Asset): boolean => { - return !!resource.format && resource.format.toLowerCase() === asset.label.toLowerCase(); -} - -/** - * Removes from the labels list of each resource the following labels: 'resource', 'DataResource'. + * Removes from the labels list of each resource the labels which are not a type of resource * This has relevance when displaying the resource list. We do not want to show the above-mentioned labels. * - * @param resources the original resource list + * @param resources the original resource list. + * @param reosurceTypes the types to be considered as resource types. + * @return returns copy of the original resources without the labels. */ -export const removeDataResourceLabels = (resources: Resource[]) => { +export const removeNonResourceTypeLabels = (resources: Resource[], reosurceTypes: string[]) => { return resources.map(resource => ({ ...resource, - labels: resource.labels.filter(label => !['Resource', 'DataResource'].includes(label)) + labels: resource.labels.filter(label => reosurceTypes.includes(label)) })); } -/** - * Creates a new list from the resources list, applying the searchText filter and the assets filter to it. - * - * @param resources list to create the filtered from - * @param searchText is looked up in all its props - * @param assets a list of assets based on which a resources are selected - * @return the new filtered list - */ -export const applyFilters = (resources: Resource[], searchText: string, assets: Asset[]): Resource[] => ( - resources - .filter(resource => assetFilterPredicate(resource, assets)) - .filter(resource => Object - .entries(resource) - .some(property => !searchText || - getPropertyValue(property).toLowerCase() - .includes(searchText.toLowerCase()) - ) - )) - -const getPropertyValue = (objectEntry: [string, any]) => String(objectEntry[1]) - -export const createTypeAssets = (types: string[], resources: Resource[]) => { - const resourceLabels = getAllLabels(resources); - return types.map(type => createAsset(type, 'typeAssets', !resourceLabels.has(type))); -} - -export const getAllLabels = (resources: Resource[]) => - new Set( - resources - .map(resource => resource.labels) - .flat() - ); - -export const createFormatAssets = ( - formats: string[], - typeAssets: Asset[], - resources: Resource[], - initiallySelected: Asset[] -) => { - let selectedTypeAssets = typeAssets - .filter(asset => !asset.disabled && asset.value) - .map(asset => asset.id) - - // If nothing is selected it is considered that all enabled ones are selected - if (!selectedTypeAssets.length) { - selectedTypeAssets = typeAssets - .filter(asset => !asset.disabled) - .map(asset => asset.id); - } - - // Get formats only from selected resources - const resourceFormats = - getAllFormats(resources - .filter(resource => resource.labels - .some(label => selectedTypeAssets.includes(label)))); - - return formats.map(format => ({ - id: format, - type: 'formatAssets', - label: format, - value: initiallySelected.some(asset => asset.id === format), - disabled: !resourceFormats.has(format) - } as Asset)); -} - -export const getAllFormats = (resources: Resource[]) => - new Set( - resources - .map(resource => resource.format) - .flat() - ); - diff --git a/src/components/resources/hooks/useResources.ts b/src/components/resources/hooks/useResources.ts index 0b127f49..16abe50e 100644 --- a/src/components/resources/hooks/useResources.ts +++ b/src/components/resources/hooks/useResources.ts @@ -1,86 +1,138 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useContext, useEffect, useMemo, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; -import { Resource } from '../../../types/resources.model'; -import { loadResourceSearchPageData } from '../helpers/resourceDataFlow'; -import { Asset, updateFilterAsset } from '../helpers/resourceFilterAssetHelper'; -import { applyFilters, createFormatAssets, createTypeAssets, removeDataResourceLabels } from '../helpers/resourcesHelper'; +import { resourcesLoadedAction, resourcesLoadingErrorAction } from '../../../actions/resourcesActions'; +import { SchemasContext } from '../../../context/SchemasContext'; +import { AppState } from '../../../reducers'; +import { getResourceFormats, getResourceTypes } from '../../../services/ontologyService.utils'; +import { loadResources } from '../helpers/resourceDataFlow'; +import { + Asset, + createFormatAssets, + createTypeAssets, + createVendorAssets, + FORMAT_ASSETS, + getResourceVendors, + getSelectedAssets, + TYPE_ASSETS, + VENDOR_ASSETS +} from '../helpers/resourceFilterAssetHelper'; +import { getPropertyValue, removeNonResourceTypeLabels } from '../helpers/resourcesHelper'; -export type ResourcesViewState = 'LOADING' | 'SHOW_RESOURCES' | 'SHOW_NO_RESULTS'; +export type ResourcesSearchPageContentType = 'LOADING' | 'SHOW_RESOURCES' | 'SHOW_NO_RESULTS'; export const useResources = () => { - const [resources, setResources] = useState([]) + const dispatch = useDispatch(); + + const schemas = useContext(SchemasContext); + const { resources } = useSelector((state: AppState) => ({ + resources: state.resources + })) const [typeAssets, setTypeAssets] = useState([]); const [formatAssets, setFormatAssets] = useState([]); const [vendorAssets, setVendorAssets] = useState([]); - - const [isLoading, setIsLoading] = useState(true); - const [searchText, setSearchText] = useState('') + const [searchText, setSearchText] = useState(''); useEffect(() => { - loadResourceSearchPageData() - .then((data) => { - setResources(data.resources); - - const resourceTypeAssets = createTypeAssets(data.resourceTypes, data.resources); - setTypeAssets(resourceTypeAssets); - - const resourceFormatAssets = createFormatAssets( - data.resourceFormats, - resourceTypeAssets, - data.resources, - [] - ); - setFormatAssets(resourceFormatAssets); + if (!schemas.isLoading && !schemas.hasError) { + const resourceTypes = Array.from(getResourceTypes(schemas.ontologies)); + loadResources(resourceTypes) + .then(resources => { + dispatch(resourcesLoadedAction({ resources })); + setTypeAssets(createTypeAssets(resourceTypes, resources)); + }) + .catch(error => dispatch(resourcesLoadingErrorAction(error))) + } + }, [schemas.isLoading]); + + const resourcesWithTypeFilterApplied = useMemo(() => !resources.hasError + ? resources.resources + .filter((resource) => { + const selectedAssets = getSelectedAssets(typeAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(type => resource.labels.includes(type)) + }) - .finally(() => setIsLoading(false)); - }, []); + : [], + [typeAssets]); + + useEffect(() => { + const resourceFormats = !schemas.isLoading && !schemas.hasError + ? Array.from(getResourceFormats(schemas.ontologies)) : []; - const filteredResources = useMemo(() => applyFilters( - resources, - searchText, - [...typeAssets, ...formatAssets, ...vendorAssets] - ), - [resources, searchText, typeAssets, formatAssets, vendorAssets]) + setFormatAssets((prevFormatAssets) => + createFormatAssets(resourceFormats, prevFormatAssets, resourcesWithTypeFilterApplied)); + }, [resourcesWithTypeFilterApplied]); + + const resourcesWithFormatFilterApplied = useMemo(() => resourcesWithTypeFilterApplied + .filter(resource => { + const selectedAssets = getSelectedAssets(formatAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(format => resource.format === format) + }), [formatAssets]) - // Recreate format filter assets in order to update their disables flag when type filter asset has been changed. useEffect(() => { - const formats = formatAssets.map(asset => asset.id); - const selectedFormats = formatAssets.filter(asset => asset.value); - - setFormatAssets(createFormatAssets( - formats, - typeAssets, - resources, - selectedFormats - )) - }, [typeAssets]); - - const state = useMemo(() => { - if (isLoading) { + const resourceVendors = !resources.hasError + ? Array.from(getResourceVendors(resources.resources)) : []; + + setVendorAssets((prevVendorAssets) => + createVendorAssets(resourceVendors, prevVendorAssets, resourcesWithFormatFilterApplied)); + }, [resourcesWithFormatFilterApplied]); + + const resourcesWithVendorFilterApplied = useMemo(() => resourcesWithFormatFilterApplied + .filter(resource => { + const selectedAssets = getSelectedAssets(vendorAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(vendor => resource.vendor === vendor) + }), [vendorAssets]) + + const resourcesWithSearchTextFilterApplied = useMemo(() => resourcesWithVendorFilterApplied + .filter(resource => Object + .entries(resource) + .some(property => !searchText || + getPropertyValue(property).toLowerCase() + .includes(searchText.toLowerCase())) + ), [resourcesWithVendorFilterApplied, searchText]); + + const viewContentType = useMemo(() => { + if (resources.isLoading) { return 'LOADING' - } else if (filteredResources.length) { + } else if (resourcesWithVendorFilterApplied.length) { return 'SHOW_RESOURCES' } else { return 'SHOW_NO_RESULTS' } - }, [filteredResources, isLoading]) - - const updateSearchText = (filter: string) => setSearchText(filter); + }, [resourcesWithSearchTextFilterApplied, resources.isLoading]) return { - resources: removeDataResourceLabels(filteredResources), + resources: removeNonResourceTypeLabels( + resourcesWithSearchTextFilterApplied, + typeAssets.map(asset => asset.id) + ), typeAssets, formatAssets, vendorAssets, - state, - updateSearchText, - updateFilterAsset: (asset: Asset) => updateFilterAsset(asset, { - typeAssets, - setTypeAssets, - formatAssets, - setFormatAssets - }) + viewContentType, + updateSearchText: (filter: string) => setSearchText(filter), + updateFilterAsset: (asset: Asset) => { + switch (asset.type) { + case TYPE_ASSETS: + setTypeAssets(typeAssets + .map(item => item.id === asset.id ? asset : item)) + break + case FORMAT_ASSETS: + setFormatAssets(formatAssets + .map(item => item.id === asset.id ? asset : item)) + break + case VENDOR_ASSETS: + setVendorAssets(vendorAssets + .map(item => item.id === asset.id ? asset : item)) + break + default: + console.info('The \'updateAsset\' method is not implemented for the following asset', asset); + } + } } } diff --git a/src/services/ontologyService.utils.ts b/src/services/ontologyService.utils.ts index bfa14ee0..13ee7b22 100644 --- a/src/services/ontologyService.utils.ts +++ b/src/services/ontologyService.utils.ts @@ -183,10 +183,10 @@ export const getUniqueLinks = (ontologies: Ontology[]) => { * Returns all resource types. Resource types are the individual names of all subclasses of the DataResource class. * * @param ontologies serving as the source of information - * @return a list of resource types + * @return a set of resource types */ -export const getResourceTypes = (ontologies: Ontology[]): string[] => { - return Array.from(new Set( +export const getResourceTypes = (ontologies: Ontology[]): Set => { + return new Set( ontologies .map(ontology => ontology.relatedShapes .filter(relatedShape => isSubclassOfDataResource(ontology, relatedShape)) @@ -196,7 +196,7 @@ export const getResourceTypes = (ontologies: Ontology[]): string[] => { .flat() ) .flat() - )) + ) } /** diff --git a/src/types/resources.model.ts b/src/types/resources.model.ts index 71898fd9..719325ab 100644 --- a/src/types/resources.model.ts +++ b/src/types/resources.model.ts @@ -1,9 +1,9 @@ export interface Resource { + vendor: string, + format: string, labels: string[], name: string, description: string, uri: string, claimsGraphUri: string[], - format: string, - vendor: string } diff --git a/src/utils/dataMapper.ts b/src/utils/dataMapper.ts index dae90a20..b77e7e67 100644 --- a/src/utils/dataMapper.ts +++ b/src/utils/dataMapper.ts @@ -46,11 +46,10 @@ export interface ResourceInput { export function mapResources(selfDescriptions: ResourceInput): Resource[] { const resources = selfDescriptions - .items.map(({ format, properties, labels }) => ({ - ...properties, - labels, - format - })); + .items.map((selfDescriptionItem) => { + const { properties, ...resource } = selfDescriptionItem; + return { ...resource, ...properties } + }); console.debug('resources', resources) return resources; } diff --git a/tests/services/ontologyService.utils.test.ts b/tests/services/ontologyService.utils.test.ts index dbda8fb8..5943ea4f 100644 --- a/tests/services/ontologyService.utils.test.ts +++ b/tests/services/ontologyService.utils.test.ts @@ -89,7 +89,7 @@ describe('getResourceType', () => { const shapes = await fetchAllShapesFromSchemas(schemas) const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes); const resourceTypes = getResourceTypes(ontologies) - expect(resourceTypes).toEqual(['HdMap', 'EnvironmentModel']) + expect(resourceTypes).toEqual(new Set(['HdMap', 'EnvironmentModel'])); }) }) From fefb54655a6ab9b2b29c975588ff65e3863b8625 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 20 Sep 2024 17:02:14 +0300 Subject: [PATCH 08/33] Move schema fetching back to the initial loading of the resources page. Signed-off-by: Zoltan Magyari --- src/actions/schemasActions.ts | 27 --------- src/actions/types.ts | 6 -- .../resources/hooks/useResources.ts | 6 +- src/context/ResourceContext.tsx | 53 ++++++++++++++++ src/context/SchemasContext.tsx | 56 ----------------- src/helpers/schemasDataFlow.ts | 21 +++++++ src/helpers/schemasReducer.ts | 60 +++++++++++++++++++ src/hooks/useSchemas.ts | 49 ++++++--------- src/index.js | 6 +- src/reducers/index.ts | 10 ---- src/reducers/schemasReducer.ts | 26 -------- src/reducers/useThunkReducer.ts | 38 ++++++++++++ 12 files changed, 196 insertions(+), 162 deletions(-) delete mode 100644 src/actions/schemasActions.ts create mode 100644 src/context/ResourceContext.tsx delete mode 100644 src/context/SchemasContext.tsx create mode 100644 src/helpers/schemasDataFlow.ts create mode 100644 src/helpers/schemasReducer.ts delete mode 100644 src/reducers/schemasReducer.ts create mode 100644 src/reducers/useThunkReducer.ts diff --git a/src/actions/schemasActions.ts b/src/actions/schemasActions.ts deleted file mode 100644 index f3fc27b3..00000000 --- a/src/actions/schemasActions.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Ontology } from '../types/ontologies.model'; -import { Shape } from '../types/shapes.model'; - -import { SET_ALL_SCHEMAS, SET_ALL_SCHEMAS_LOADING_ERROR } from './types'; - -export type AllSchemas = { - ontologies: Ontology[]; - shapes: Shape[]; -} - -export type AllSchemasError = { - error: string; -} - -export type AllSchemasAction = - { type: 'SET_ALL_SCHEMAS', payload: AllSchemas } | - { type: 'SET_ALL_SCHEMAS_LOADING_ERROR', payload: AllSchemasError } - -export const schemasLoadedAction = (payload: AllSchemas): AllSchemasAction => ({ - type: SET_ALL_SCHEMAS, - payload -}) - -export const schemasLoadingErrorAction = (payload: AllSchemasError): AllSchemasAction => ({ - type: SET_ALL_SCHEMAS_LOADING_ERROR, - payload -}) diff --git a/src/actions/types.ts b/src/actions/types.ts index 40be0001..91134ef7 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -12,12 +12,6 @@ export const RESET_LCM_SERVICES = 'RESET_LCM_SERVICES'; export const LCM_SELECT_SERVICE = 'LCM_SELECT_SERVICE'; export const CHANGE_USER_ROLE = 'CHANGE_USER_ROLE' -//////////////////////////////////////////////////////////////////////////////// -// Schemas -//////////////////////////////////////////////////////////////////////////////// -export const SET_ALL_SCHEMAS = 'SET_ALL_SCHEMAS'; -export const SET_ALL_SCHEMAS_LOADING_ERROR = 'SET_ALL_SCHEMAS_LOADING_ERROR'; - //////////////////////////////////////////////////////////////////////////////// // Resources //////////////////////////////////////////////////////////////////////////////// diff --git a/src/components/resources/hooks/useResources.ts b/src/components/resources/hooks/useResources.ts index 16abe50e..99caf315 100644 --- a/src/components/resources/hooks/useResources.ts +++ b/src/components/resources/hooks/useResources.ts @@ -1,8 +1,8 @@ -import { useContext, useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { resourcesLoadedAction, resourcesLoadingErrorAction } from '../../../actions/resourcesActions'; -import { SchemasContext } from '../../../context/SchemasContext'; +import { useSchemas } from '../../../hooks/useSchemas'; import { AppState } from '../../../reducers'; import { getResourceFormats, getResourceTypes } from '../../../services/ontologyService.utils'; import { loadResources } from '../helpers/resourceDataFlow'; @@ -23,8 +23,8 @@ export type ResourcesSearchPageContentType = 'LOADING' | 'SHOW_RESOURCES' | 'SHO export const useResources = () => { const dispatch = useDispatch(); + const schemas = useSchemas(); - const schemas = useContext(SchemasContext); const { resources } = useSelector((state: AppState) => ({ resources: state.resources })) diff --git a/src/context/ResourceContext.tsx b/src/context/ResourceContext.tsx new file mode 100644 index 00000000..06d867a9 --- /dev/null +++ b/src/context/ResourceContext.tsx @@ -0,0 +1,53 @@ +import React, { createContext, ReactNode } from 'react'; + +// TODO: It is an example how to create a context. It is not used yet and does not contain any useful state either. + +/** + * Defines the type of the data stored in the context + */ +interface ResourceStore { + // TODO: define store data type here +} + +/** + * Initial values in the resource store context + */ +const initialState = { + // TODO: Define initial state of the store +} as ResourceStore; + +/** + * Definition of the {@link ResourceStore} context + * + * Usage: const { var1, var2, ... } = useContext(ResourceContext) + */ +const ResourceContext = createContext(initialState); + +/** + * Defines the type of the {@link ResourceContextProvider}'s input props + */ +interface ResourceContextProviderProps { + children: ReactNode; +} + +/** + * Provider for the {@link ResourceContext} + * + * Contains the global states of the resources and anything else that needs to be accessible via the context. + * + * @param children in order to use it like a React component and make available the states to all children + * components, it has to be passed in as input prop. + */ +export const ResourceContextProvider: React.FC = ({ children }) => { + // TODO: define global state variables and functions here + + return ( + + {children} + + ); +}; + diff --git a/src/context/SchemasContext.tsx b/src/context/SchemasContext.tsx deleted file mode 100644 index 645689eb..00000000 --- a/src/context/SchemasContext.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React, { createContext, ReactNode } from 'react'; - -import { useSchemas } from '../hooks/useSchemas'; -import { AllSchemasState } from '../reducers/schemasReducer'; - -/** - * Defines the type of the data stored in the context - */ -type SchemasStore = AllSchemasState - -/** - * Initial values in the resource store context - */ -const initialState = { - shapes: [], - ontologies: [], - isLoading: true, - hasError: false -} as SchemasStore; - -/** - * Definition of the {@link SchemasStore} context - * - * Usage: const { var1, var2, ... } = useContext(SchemasContext) - */ -export const SchemasContext = createContext(initialState); - -/** - * Defines the type of the {@link SchemasContextProvider}'s input props - */ -interface ResourceContextProviderProps { - children: ReactNode; -} - -/** - * Provider for the {@link SchemasContext} - * - * Contains the global states of the resources and anything else that needs to be accessible via the context. - * - * @param children in order to use it like a React component and make available the states to all children - * components, it has to be passed in as input prop. - */ -export const SchemasContextProvider: React.FC = ({ children }) => { - const { isLoading, shapes, ontologies } = useSchemas(); - - return ( - - {children} - - ); -}; - diff --git a/src/helpers/schemasDataFlow.ts b/src/helpers/schemasDataFlow.ts new file mode 100644 index 00000000..a627c13f --- /dev/null +++ b/src/helpers/schemasDataFlow.ts @@ -0,0 +1,21 @@ +import { ThunkDispatch } from '../reducers/useThunkReducer'; +import { fetchAllOntologiesFromSchemas } from '../services/ontologyService.utils'; +import { fetchAllSchemas } from '../services/schemaApiService'; +import { fetchAllShapesFromSchemas } from '../services/shapeService.utils'; + +import { schemasLoadedAction, schemasLoadingErrorAction } from './schemasReducer'; + +export const loadSchemas = async (dispatch: ThunkDispatch) => { + try { + const schemas = await fetchAllSchemas(); + const shapes = await fetchAllShapesFromSchemas(schemas); + const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes) + + dispatch(schemasLoadedAction({ + shapes, + ontologies + })) + } catch (error) { + dispatch(schemasLoadingErrorAction(error)) + } +} diff --git a/src/helpers/schemasReducer.ts b/src/helpers/schemasReducer.ts new file mode 100644 index 00000000..ce6acab7 --- /dev/null +++ b/src/helpers/schemasReducer.ts @@ -0,0 +1,60 @@ +import { AnyAction } from 'redux'; + +import { Ontology } from '../types/ontologies.model'; +import { Shape } from '../types/shapes.model'; + +//////////////////////////////////////////////////////////////////////////////// +// Action types +//////////////////////////////////////////////////////////////////////////////// +const SET_ALL_SCHEMAS = 'SET_ALL_SCHEMAS'; +const SET_ALL_SCHEMAS_LOADING_ERROR = 'SET_ALL_SCHEMAS_LOADING_ERROR'; + +//////////////////////////////////////////////////////////////////////////////// +// Type definitions +//////////////////////////////////////////////////////////////////////////////// +type IsLoading = { isLoading: boolean; } + +type AllSchemas = { + ontologies: Ontology[]; + shapes: Shape[]; +} + +type AllSchemasError = { + error: string; +} + +// TODO: Extend the AnyAction type +type AllSchemasAction = + { type: 'SET_ALL_SCHEMAS', payload: AllSchemas } | + { type: 'SET_ALL_SCHEMAS_LOADING_ERROR', payload: AllSchemasError } + +export type AllSchemasState = (AllSchemas & { hasError: false } | AllSchemasError & { hasError: true }) & IsLoading + +//////////////////////////////////////////////////////////////////////////////// +// Reducer +//////////////////////////////////////////////////////////////////////////////// +export const schemasReducer = (state: AllSchemasState, action: AnyAction): AllSchemasState => { + switch (action.type) { + + case SET_ALL_SCHEMAS: + return { ...action.payload, isLoading: false, hasError: false } + + case SET_ALL_SCHEMAS_LOADING_ERROR: + return { ...action.payload, isLoading: false, hasError: true } + + } + return state +} + +//////////////////////////////////////////////////////////////////////////////// +// Actions +//////////////////////////////////////////////////////////////////////////////// +export const schemasLoadedAction = (payload: AllSchemas): AllSchemasAction => ({ + type: SET_ALL_SCHEMAS, + payload +}) + +export const schemasLoadingErrorAction = (payload: AllSchemasError): AllSchemasAction => ({ + type: SET_ALL_SCHEMAS_LOADING_ERROR, + payload +}) diff --git a/src/hooks/useSchemas.ts b/src/hooks/useSchemas.ts index 6a52d516..35699e2b 100644 --- a/src/hooks/useSchemas.ts +++ b/src/hooks/useSchemas.ts @@ -1,39 +1,26 @@ -import { useContext, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useEffect } from 'react'; -import { schemasLoadedAction } from '../actions/schemasActions'; -import { AuthContext } from '../context/AuthContextProvider'; -import { fetchAllOntologiesFromSchemas } from '../services/ontologyService.utils'; -import { fetchAllSchemas } from '../services/schemaApiService'; -import { fetchAllShapesFromSchemas } from '../services/shapeService.utils'; +import { loadSchemas } from '../helpers/schemasDataFlow'; +import { AllSchemasState, schemasReducer } from '../helpers/schemasReducer'; +import { useThunkReducer } from '../reducers/useThunkReducer'; -export const useSchemas = () => { - const authContext = useContext(AuthContext); - const dispatch = useDispatch(); - const { isLoading, shapes, ontologies } = useSelector((state) => ({ - isLoading: state.schemas.isLoading, - shapes: state.schemas.shapes, - ontologies: state.schemas.ontologies - })) +export const initialState: AllSchemasState = { + isLoading: true, + hasError: false, + shapes: [], + ontologies: [] +} - useEffect(() => { - if (authContext.isAuthenticated) { - (async () => { - const schemas = await fetchAllSchemas(); - const shapes = await fetchAllShapesFromSchemas(schemas); - const ontologies = await fetchAllOntologiesFromSchemas(schemas, shapes) +export const useSchemas = (): AllSchemasState => { + const [schemas, dispatch] = useThunkReducer(schemasReducer, initialState); - dispatch(schemasLoadedAction({ - shapes, - ontologies - })) - })(); - } - }, [authContext.isAuthenticated]); + useEffect( + () => dispatch(loadSchemas), + [] + ); return { - isLoading, - shapes, - ontologies + ...schemas } } + diff --git a/src/index.js b/src/index.js index 58d49cf6..a0875706 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ import './i18n'; import App from './App'; import { configureStore } from './configureStore'; import AuthContextProvider from './context/AuthContextProvider'; -import { SchemasContextProvider } from './context/SchemasContext'; +import { ResourceContextProvider } from './context/ResourceContext'; import './index.css'; @@ -42,9 +42,9 @@ const root = createRoot(container); // createRoot(container!) if you use TypeScr root.render( - + - + ); diff --git a/src/reducers/index.ts b/src/reducers/index.ts index 8abef4be..43bdce9e 100644 --- a/src/reducers/index.ts +++ b/src/reducers/index.ts @@ -1,14 +1,11 @@ import { Reducer } from 'react'; import { AnyAction, combineReducers } from 'redux'; -import { Ontology } from '../types/ontologies.model'; import { Resource } from '../types/resources.model'; -import { Shape } from '../types/shapes.model'; import searchCriteriaStore from './SearchCriteriaStore'; import lcmReducer from './lcmReducer'; import resources from './resourcesReducer'; -import schemas from './schemasReducer'; import serviceDescriptorReducer from './serviceDescriptorReducer'; import userReducer from './userReducer'; @@ -27,12 +24,6 @@ export interface AppState { // searchCriteriaStore: { ... }, // serviceDescriptor: { ... }, // lcm: { ... }, - schemas: { - isLoading: true, - hasError: false, - shapes: Shape[], - ontologies: Ontology[], - }, resources: { isLoading: true, hasError: false, @@ -45,6 +36,5 @@ export default combineReducers>({ searchCriteriaStore: searchCriteriaStore, serviceDescriptor: serviceDescriptorReducer, lcm: lcmReducer, - schemas, resources, }); diff --git a/src/reducers/schemasReducer.ts b/src/reducers/schemasReducer.ts deleted file mode 100644 index fd662845..00000000 --- a/src/reducers/schemasReducer.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { AllSchemas, AllSchemasAction, AllSchemasError } from '../actions/schemasActions'; -import { SET_ALL_SCHEMAS, SET_ALL_SCHEMAS_LOADING_ERROR } from '../actions/types'; - -type IsLoading = { isLoading: boolean; } -export type AllSchemasState = (AllSchemas & { hasError: false } | AllSchemasError & { hasError: true }) & IsLoading - -const initialState: AllSchemasState = { - isLoading: true, - hasError: false, - shapes: [], - ontologies: [] -} - -export default (state: AllSchemasState = initialState, action: AllSchemasAction) => { - switch (action.type) { - - case SET_ALL_SCHEMAS: - return { ...action.payload, isLoading: false, hasError: false } - - case SET_ALL_SCHEMAS_LOADING_ERROR: - return { error: action.payload, isLoading: false, hasError: true } - - } - return state - -} diff --git a/src/reducers/useThunkReducer.ts b/src/reducers/useThunkReducer.ts new file mode 100644 index 00000000..01653aa9 --- /dev/null +++ b/src/reducers/useThunkReducer.ts @@ -0,0 +1,38 @@ +import { Dispatch, Reducer, useCallback, useReducer } from 'react'; +import { AnyAction } from 'redux'; + +/** + * Thunk dispatch type definition + */ +export type ThunkDispatch = Dispatch; + +/** + * Thunk function type definition + */ +export type ThunkAction = ((dispatch: ThunkDispatch) => any) | ((dispatch: ThunkDispatch) => Promise); + +/** + * Custom dispatch that can handle both thunks and regular actions. + * + * @param reducer is a method that generates the next state based on the current one and a provided action. + * @param initialState is the initial state from which the reducer starts to generate the followup states. + */ +export const useThunkReducer = ( + reducer: Reducer, + initialState: State +): [State, Dispatch] => { + const [state, dispatch] = useReducer(reducer, initialState); + + const enhancedDispatch = useCallback( + (action: AnyAction | ThunkAction) => { + if (typeof action === 'function') { + action(dispatch); // If the action is a thunk (function), invoke it + } else { + dispatch(action); // Otherwise, pass the action to the reducer + } + }, + [dispatch] + ); + + return [state, enhancedDispatch]; +} From 44111c80ae892906a552f583e825061386f460e3 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 20 Sep 2024 18:36:51 +0300 Subject: [PATCH 09/33] Extract filtering logic into a standalone hook Signed-off-by: Zoltan Magyari --- src/components/Routes.tsx | 4 +- src/components/filter/Filter.tsx | 2 +- src/components/filter/FilterSection.tsx | 2 +- .../{Resources.tsx => ResourceSearchPage.tsx} | 4 +- ...AssetHelper.ts => resourceFilterHelper.ts} | 34 +++++ .../resources/hooks/useResourceFilter.ts | 85 ++++++++++++ .../resources/hooks/useResources.ts | 129 +++++------------- 7 files changed, 156 insertions(+), 104 deletions(-) rename src/components/resources/{Resources.tsx => ResourceSearchPage.tsx} (96%) rename src/components/resources/helpers/{resourceFilterAssetHelper.ts => resourceFilterHelper.ts} (82%) create mode 100644 src/components/resources/hooks/useResourceFilter.ts diff --git a/src/components/Routes.tsx b/src/components/Routes.tsx index 7e210df9..9f48025a 100644 --- a/src/components/Routes.tsx +++ b/src/components/Routes.tsx @@ -25,7 +25,7 @@ import ProtectedRoute from './protectedRoute/ProtectedRoute'; import ProvideAttributes from './provide/ProvideAttributes'; import ProvideOverview from './provide/ProvideOverview'; import ProvideSelection from './provide/ProvideSelection'; -import Resources from './resources/Resources'; +import ResourceSearchPage from './resources/ResourceSearchPage'; import ServiceOfferings from './serviceOfferings/ServiceOfferings'; import Shapes from './shapes/Shapes'; import SolutionPackagingView from './solutionPackaging/SolutionPackagingView'; @@ -42,7 +42,7 @@ const Routes: FC = () => ( )} /> )}/> )} /> - )} /> + )}/> )}/> )} /> )} /> diff --git a/src/components/filter/Filter.tsx b/src/components/filter/Filter.tsx index b4843047..5e4a1b07 100644 --- a/src/components/filter/Filter.tsx +++ b/src/components/filter/Filter.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; import Title from '../Title/Title'; -import { Asset } from '../resources/helpers/resourceFilterAssetHelper'; +import { Asset } from '../resources/helpers/resourceFilterHelper'; import styles from './Filter.module.css'; import { FilterSection } from './FilterSection'; diff --git a/src/components/filter/FilterSection.tsx b/src/components/filter/FilterSection.tsx index fc1ad932..8fbe2486 100644 --- a/src/components/filter/FilterSection.tsx +++ b/src/components/filter/FilterSection.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; -import { Asset } from '../resources/helpers/resourceFilterAssetHelper'; +import { Asset } from '../resources/helpers/resourceFilterHelper'; import Subtitle from '../subtitle/Subtitle'; import styles from './Filter.module.css'; diff --git a/src/components/resources/Resources.tsx b/src/components/resources/ResourceSearchPage.tsx similarity index 96% rename from src/components/resources/Resources.tsx rename to src/components/resources/ResourceSearchPage.tsx index a7204526..8041c3a8 100644 --- a/src/components/resources/Resources.tsx +++ b/src/components/resources/ResourceSearchPage.tsx @@ -14,7 +14,7 @@ import SearchBar from '../searchBar/SearchBar'; import { useResources } from './hooks/useResources'; -const Resources = () => { +const ResourceSearchPage = () => { const { t } = useTranslation(); const { @@ -64,4 +64,4 @@ const Resources = () => { ); }; -export default Resources; +export default ResourceSearchPage; diff --git a/src/components/resources/helpers/resourceFilterAssetHelper.ts b/src/components/resources/helpers/resourceFilterHelper.ts similarity index 82% rename from src/components/resources/helpers/resourceFilterAssetHelper.ts rename to src/components/resources/helpers/resourceFilterHelper.ts index 7614231e..08f49f6a 100644 --- a/src/components/resources/helpers/resourceFilterAssetHelper.ts +++ b/src/components/resources/helpers/resourceFilterHelper.ts @@ -149,3 +149,37 @@ export const getSelectedAssets = (assets: Asset[]): SelectedAssets => { } return selectedAssets; } + +type UpdateFilterAsset = ( + typeAssets: Asset[], + setTypeAssets: (assets: Asset[]) => void, + formatAssets: Asset[], + setFormatAssets: (assets: Asset[]) => void, + vendorAssets: Asset[], + setVendorAssets: (assets: Asset[]) => void, +) => (asset: Asset) => void; + +export const updateFilterAsset: UpdateFilterAsset = ( + typeAssets, setTypeAssets, + formatAssets, setFormatAssets, + vendorAssets, setVendorAssets +) => { + return (asset: Asset) => { + switch (asset.type) { + case TYPE_ASSETS: + setTypeAssets(typeAssets + .map(item => item.id === asset.id ? asset : item)) + break + case FORMAT_ASSETS: + setFormatAssets(formatAssets + .map(item => item.id === asset.id ? asset : item)) + break + case VENDOR_ASSETS: + setVendorAssets(vendorAssets + .map(item => item.id === asset.id ? asset : item)) + break + default: + console.info('The \'updateAsset\' method is not implemented for the following asset', asset); + } + }; +} diff --git a/src/components/resources/hooks/useResourceFilter.ts b/src/components/resources/hooks/useResourceFilter.ts new file mode 100644 index 00000000..021128f4 --- /dev/null +++ b/src/components/resources/hooks/useResourceFilter.ts @@ -0,0 +1,85 @@ +import { useEffect, useMemo, useState } from 'react'; + +import { getResourceFormats, getResourceTypes } from '../../../services/ontologyService.utils'; +import { Ontology } from '../../../types/ontologies.model'; +import { Resource } from '../../../types/resources.model'; +import { + Asset, + createFormatAssets, + createTypeAssets, + createVendorAssets, + getResourceVendors, + getSelectedAssets, + updateFilterAsset +} from '../helpers/resourceFilterHelper'; +import { getPropertyValue } from '../helpers/resourcesHelper'; + +export const useResourceFilter = (ontologies: Ontology[], resources: Resource[]) => { + const [typeAssets, setTypeAssets] = useState([]); + const [formatAssets, setFormatAssets] = useState([]); + const [vendorAssets, setVendorAssets] = useState([]); + const [searchText, setSearchText] = useState(''); + + useEffect(() => { + const resourceTypes = Array.from(getResourceTypes(ontologies)); + setTypeAssets(createTypeAssets(resourceTypes, resources)); + }, [resources]); + + const resourcesWithTypeFilterApplied = useMemo(() => resources + .filter((resource) => { + const selectedAssets = getSelectedAssets(typeAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(type => resource.labels.includes(type)) + + }), + [typeAssets]); + + useEffect(() => { + const resourceFormats = Array.from(getResourceFormats(ontologies)); + + setFormatAssets(createFormatAssets(resourceFormats, formatAssets, resourcesWithTypeFilterApplied)); + }, [resourcesWithTypeFilterApplied]); + + const resourcesWithFormatFilterApplied = useMemo(() => resourcesWithTypeFilterApplied + .filter(resource => { + const selectedAssets = getSelectedAssets(formatAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(format => resource.format === format) + }), [formatAssets]) + + useEffect(() => { + const resourceVendors = Array.from(getResourceVendors(resources)); + + setVendorAssets((prevVendorAssets) => + createVendorAssets(resourceVendors, prevVendorAssets, resourcesWithFormatFilterApplied)); + }, [resourcesWithFormatFilterApplied]); + + const resourcesWithVendorFilterApplied = useMemo(() => resourcesWithFormatFilterApplied + .filter(resource => { + const selectedAssets = getSelectedAssets(vendorAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(vendor => resource.vendor === vendor) + }), [vendorAssets]) + + const resourcesWithSearchTextFilterApplied = useMemo(() => resourcesWithVendorFilterApplied + .filter(resource => Object + .entries(resource) + .some(property => !searchText || + getPropertyValue(property).toLowerCase() + .includes(searchText.toLowerCase())) + ), [resourcesWithVendorFilterApplied, searchText]); + + return { + filteredResources: resourcesWithSearchTextFilterApplied, + typeAssets, + formatAssets, + vendorAssets, + updateSearchText: setSearchText, + updateFilterAsset: updateFilterAsset( + typeAssets, setTypeAssets, + formatAssets, setFormatAssets, + vendorAssets, setVendorAssets + ) + } +} + diff --git a/src/components/resources/hooks/useResources.ts b/src/components/resources/hooks/useResources.ts index 99caf315..c62f7fc9 100644 --- a/src/components/resources/hooks/useResources.ts +++ b/src/components/resources/hooks/useResources.ts @@ -1,138 +1,71 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { resourcesLoadedAction, resourcesLoadingErrorAction } from '../../../actions/resourcesActions'; import { useSchemas } from '../../../hooks/useSchemas'; import { AppState } from '../../../reducers'; -import { getResourceFormats, getResourceTypes } from '../../../services/ontologyService.utils'; +import { getResourceTypes } from '../../../services/ontologyService.utils'; import { loadResources } from '../helpers/resourceDataFlow'; -import { - Asset, - createFormatAssets, - createTypeAssets, - createVendorAssets, - FORMAT_ASSETS, - getResourceVendors, - getSelectedAssets, - TYPE_ASSETS, - VENDOR_ASSETS -} from '../helpers/resourceFilterAssetHelper'; -import { getPropertyValue, removeNonResourceTypeLabels } from '../helpers/resourcesHelper'; +import { removeNonResourceTypeLabels } from '../helpers/resourcesHelper'; + +import { useResourceFilter } from './useResourceFilter'; export type ResourcesSearchPageContentType = 'LOADING' | 'SHOW_RESOURCES' | 'SHOW_NO_RESULTS'; export const useResources = () => { const dispatch = useDispatch(); - const schemas = useSchemas(); - - const { resources } = useSelector((state: AppState) => ({ - resources: state.resources + const { + isLoading, + resources + } = useSelector((state: AppState) => ({ + isLoading: state.resources.isLoading, + resources: !state.resources.isLoading && !state.resources.hasError ? state.resources.resources : [] })) - const [typeAssets, setTypeAssets] = useState([]); - const [formatAssets, setFormatAssets] = useState([]); - const [vendorAssets, setVendorAssets] = useState([]); - const [searchText, setSearchText] = useState(''); + const schemas = useSchemas(); + const ontologies = useMemo(() => + !schemas.isLoading && !schemas.hasError ? schemas.ontologies : [], + [schemas.isLoading]); + + const { + filteredResources, + typeAssets, + formatAssets, + vendorAssets, + updateSearchText, + updateFilterAsset, + } = useResourceFilter(ontologies, resources); useEffect(() => { if (!schemas.isLoading && !schemas.hasError) { const resourceTypes = Array.from(getResourceTypes(schemas.ontologies)); loadResources(resourceTypes) - .then(resources => { - dispatch(resourcesLoadedAction({ resources })); - setTypeAssets(createTypeAssets(resourceTypes, resources)); - }) + .then(resources => dispatch(resourcesLoadedAction({ resources }))) .catch(error => dispatch(resourcesLoadingErrorAction(error))) } }, [schemas.isLoading]); - const resourcesWithTypeFilterApplied = useMemo(() => !resources.hasError - ? resources.resources - .filter((resource) => { - const selectedAssets = getSelectedAssets(typeAssets) - return selectedAssets === 'ALL' || selectedAssets - .some(type => resource.labels.includes(type)) - - }) - : [], - [typeAssets]); - - useEffect(() => { - const resourceFormats = !schemas.isLoading && !schemas.hasError - ? Array.from(getResourceFormats(schemas.ontologies)) : []; - - setFormatAssets((prevFormatAssets) => - createFormatAssets(resourceFormats, prevFormatAssets, resourcesWithTypeFilterApplied)); - }, [resourcesWithTypeFilterApplied]); - - const resourcesWithFormatFilterApplied = useMemo(() => resourcesWithTypeFilterApplied - .filter(resource => { - const selectedAssets = getSelectedAssets(formatAssets) - return selectedAssets === 'ALL' || selectedAssets - .some(format => resource.format === format) - }), [formatAssets]) - - useEffect(() => { - const resourceVendors = !resources.hasError - ? Array.from(getResourceVendors(resources.resources)) : []; - - setVendorAssets((prevVendorAssets) => - createVendorAssets(resourceVendors, prevVendorAssets, resourcesWithFormatFilterApplied)); - }, [resourcesWithFormatFilterApplied]); - - const resourcesWithVendorFilterApplied = useMemo(() => resourcesWithFormatFilterApplied - .filter(resource => { - const selectedAssets = getSelectedAssets(vendorAssets) - return selectedAssets === 'ALL' || selectedAssets - .some(vendor => resource.vendor === vendor) - }), [vendorAssets]) - - const resourcesWithSearchTextFilterApplied = useMemo(() => resourcesWithVendorFilterApplied - .filter(resource => Object - .entries(resource) - .some(property => !searchText || - getPropertyValue(property).toLowerCase() - .includes(searchText.toLowerCase())) - ), [resourcesWithVendorFilterApplied, searchText]); - const viewContentType = useMemo(() => { - if (resources.isLoading) { + if (isLoading) { return 'LOADING' - } else if (resourcesWithVendorFilterApplied.length) { + } else if (filteredResources.length) { return 'SHOW_RESOURCES' } else { return 'SHOW_NO_RESULTS' } - }, [resourcesWithSearchTextFilterApplied, resources.isLoading]) + }, [filteredResources, isLoading]); return { resources: removeNonResourceTypeLabels( - resourcesWithSearchTextFilterApplied, + filteredResources, typeAssets.map(asset => asset.id) ), typeAssets, formatAssets, vendorAssets, viewContentType, - updateSearchText: (filter: string) => setSearchText(filter), - updateFilterAsset: (asset: Asset) => { - switch (asset.type) { - case TYPE_ASSETS: - setTypeAssets(typeAssets - .map(item => item.id === asset.id ? asset : item)) - break - case FORMAT_ASSETS: - setFormatAssets(formatAssets - .map(item => item.id === asset.id ? asset : item)) - break - case VENDOR_ASSETS: - setVendorAssets(vendorAssets - .map(item => item.id === asset.id ? asset : item)) - break - default: - console.info('The \'updateAsset\' method is not implemented for the following asset', asset); - } - } + updateSearchText, + updateFilterAsset, } } From be2e7fde692aaed775ae86c935b327edc20764d3 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Mon, 23 Sep 2024 09:39:58 +0300 Subject: [PATCH 10/33] Use the useReducer state management inside useResourceFilter Signed-off-by: Zoltan Magyari --- .../resources/helpers/resourceFilterHelper.ts | 92 ++++++++----- .../helpers/resourceFilterReducer.ts | 126 ++++++++++++++++++ .../resources/hooks/useResourceFilter.ts | 87 +++--------- 3 files changed, 203 insertions(+), 102 deletions(-) create mode 100644 src/components/resources/helpers/resourceFilterReducer.ts diff --git a/src/components/resources/helpers/resourceFilterHelper.ts b/src/components/resources/helpers/resourceFilterHelper.ts index 08f49f6a..e9b1dd49 100644 --- a/src/components/resources/helpers/resourceFilterHelper.ts +++ b/src/components/resources/helpers/resourceFilterHelper.ts @@ -1,5 +1,10 @@ +import { getResourceFormats, getResourceTypes } from '../../../services/ontologyService.utils'; +import { Ontology } from '../../../types/ontologies.model'; import { Resource } from '../../../types/resources.model'; +import { ResourceFilterState } from './resourceFilterReducer'; +import { getPropertyValue } from './resourcesHelper'; + export const TYPE_ASSETS = 'typeAssets'; export const FORMAT_ASSETS = 'formatAssets'; export const VENDOR_ASSETS = 'vendorAssets'; @@ -150,36 +155,63 @@ export const getSelectedAssets = (assets: Asset[]): SelectedAssets => { return selectedAssets; } -type UpdateFilterAsset = ( - typeAssets: Asset[], - setTypeAssets: (assets: Asset[]) => void, - formatAssets: Asset[], - setFormatAssets: (assets: Asset[]) => void, - vendorAssets: Asset[], - setVendorAssets: (assets: Asset[]) => void, -) => (asset: Asset) => void; - -export const updateFilterAsset: UpdateFilterAsset = ( - typeAssets, setTypeAssets, - formatAssets, setFormatAssets, - vendorAssets, setVendorAssets +/** + * Calculates the filter assets from ontologies and resources. Calculates the new filtered resource list also. + * + * @param ontologies list of ontologies from which the filter assets should be calculated. + * @param resources list of resources from which the filter assets should be calculated. + * @param filters previous filter assets state in order to preserve an existing selection during the update of an asset. + * @return the new state of the {@link useResourceFilter} hook. + */ +export const calculateResourceFiltersAssetState = ( + ontologies: Ontology[], + resources: Resource[], + filters: ResourceFilterState ) => { - return (asset: Asset) => { - switch (asset.type) { - case TYPE_ASSETS: - setTypeAssets(typeAssets - .map(item => item.id === asset.id ? asset : item)) - break - case FORMAT_ASSETS: - setFormatAssets(formatAssets - .map(item => item.id === asset.id ? asset : item)) - break - case VENDOR_ASSETS: - setVendorAssets(vendorAssets - .map(item => item.id === asset.id ? asset : item)) - break - default: - console.info('The \'updateAsset\' method is not implemented for the following asset', asset); - } + const resourceTypes = Array.from(getResourceTypes(ontologies)); + const typeAssets = createTypeAssets(resourceTypes, resources) + .map(typeAsset => filters.typeAssets + .find(item => item.id === typeAsset.id) || typeAsset); + + const resourcesWithTypeFilterApplied = resources + .filter((resource) => { + const selectedAssets = getSelectedAssets(filters.typeAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(type => resource.labels.includes(type)) + }); + + const resourceFormats = Array.from(getResourceFormats(ontologies)); + const formatAssets = createFormatAssets(resourceFormats, filters.formatAssets, resourcesWithTypeFilterApplied); + + const resourcesWithFormatFilterApplied = resourcesWithTypeFilterApplied + .filter(resource => { + const selectedAssets = getSelectedAssets(filters.formatAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(format => resource.format === format) + }); + + const resourceVendors = Array.from(getResourceVendors(resources)); + const vendorAssets = createVendorAssets(resourceVendors, filters.vendorAssets, resourcesWithFormatFilterApplied); + + const resourcesWithVendorFilterApplied = resourcesWithFormatFilterApplied + .filter(resource => { + const selectedAssets = getSelectedAssets(filters.vendorAssets) + return selectedAssets === 'ALL' || selectedAssets + .some(vendor => resource.vendor === vendor) + }); + + const resourcesWithSearchTextFilterApplied = resourcesWithVendorFilterApplied + .filter(resource => Object + .entries(resource) + .some(property => !filters.searchText || + getPropertyValue(property).toLowerCase() + .includes(filters.searchText.toLowerCase())) + ); + + return { + typeAssets, + formatAssets, + vendorAssets, + filteredResources: resourcesWithSearchTextFilterApplied }; } diff --git a/src/components/resources/helpers/resourceFilterReducer.ts b/src/components/resources/helpers/resourceFilterReducer.ts new file mode 100644 index 00000000..aa872dc6 --- /dev/null +++ b/src/components/resources/helpers/resourceFilterReducer.ts @@ -0,0 +1,126 @@ +import { AnyAction } from 'redux'; + +import { Ontology } from '../../../types/ontologies.model'; +import { Resource } from '../../../types/resources.model'; + +import { Asset, calculateResourceFiltersAssetState } from './resourceFilterHelper'; + +//////////////////////////////////////////////////////////////////////////////// +// Action types +//////////////////////////////////////////////////////////////////////////////// +const SET_RESOURCE_FILTER_ASSETS = 'SET_RESOURCE_FILTER_ASSETS'; +const SET_SEARCH_TEXT = 'SET_SEARCH_TEXT'; +const UPDATE_FILTER_ASSET = 'UPDATE_FILTER_ASSET'; + +//////////////////////////////////////////////////////////////////////////////// +// Type definitions +//////////////////////////////////////////////////////////////////////////////// + +type ResourceFilterAssetState = { + filteredResources: Resource[], + typeAssets: Asset[], + formatAssets: Asset[], + vendorAssets: Asset[], +}; + +export type ResourceFilterState = ResourceFilterAssetState & { + searchText: string +} + +type ResourceFilterAction = + { + type: 'SET_RESOURCE_FILTER_ASSETS', payload: { + ontologies: Ontology[], + resources: Resource[] + } + } | + { + type: 'SET_SEARCH_TEXT', payload: { + searchText: string, + ontologies: Ontology[], + resources: Resource[] + } + } | + { + type: 'UPDATE_FILTER_ASSET', payload: { + asset: Asset, + ontologies: Ontology[], + resources: Resource[], + }, + } + +//////////////////////////////////////////////////////////////////////////////// +// Initial state +//////////////////////////////////////////////////////////////////////////////// +export const initialResourceFilterState: ResourceFilterState = { + filteredResources: [], + typeAssets: [], + formatAssets: [], + vendorAssets: [], + searchText: '' +} + +//////////////////////////////////////////////////////////////////////////////// +// Reducer +//////////////////////////////////////////////////////////////////////////////// +export const resourceFilterReducer = (state: ResourceFilterState, action: AnyAction): ResourceFilterState => { + switch (action.type) { + + case SET_RESOURCE_FILTER_ASSETS: + return { + ...state, + ...calculateResourceFiltersAssetState(action.payload.ontologies, action.payload.resources, initialResourceFilterState) + } + + case SET_SEARCH_TEXT: + return { + ...state, + ...calculateResourceFiltersAssetState(action.payload.ontologies, action.payload.resources, { + ...state, + searchText: action.payload.searchText + }), + searchText: action.payload.searchText + } + + case UPDATE_FILTER_ASSET: + return { + ...state, + ...calculateResourceFiltersAssetState(action.payload.ontologies, action.payload.resources, { + ...state, + typeAssets: state.typeAssets.map(item => item.id === action.payload.asset.id ? action.payload.asset : item), + formatAssets: state.formatAssets.map(item => item.id === action.payload.asset.id ? action.payload.asset : item), + vendorAssets: state.vendorAssets.map(item => item.id === action.payload.asset.id ? action.payload.asset : item) + }) + } + } + return state +} + +//////////////////////////////////////////////////////////////////////////////// +// Actions +//////////////////////////////////////////////////////////////////////////////// +export const setResourceFilterAssetsAction = ( + ontologies: Ontology[], + resources: Resource[]): ResourceFilterAction => ( + { + type: SET_RESOURCE_FILTER_ASSETS, + payload: { ontologies, resources } + }) + +export const setSearchTextAction = ( + searchText: string, + ontologies: Ontology[], + resources: Resource[]): ResourceFilterAction => ( + { + type: SET_SEARCH_TEXT, + payload: { searchText, ontologies, resources } + }) + +export const updateFilterAssetAction = ( + asset: Asset, + ontologies: Ontology[], + resources: Resource[]): ResourceFilterAction => ( + { + type: UPDATE_FILTER_ASSET, + payload: { asset, ontologies, resources } + }) diff --git a/src/components/resources/hooks/useResourceFilter.ts b/src/components/resources/hooks/useResourceFilter.ts index 021128f4..413ec40f 100644 --- a/src/components/resources/hooks/useResourceFilter.ts +++ b/src/components/resources/hooks/useResourceFilter.ts @@ -1,85 +1,28 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useReducer } from 'react'; -import { getResourceFormats, getResourceTypes } from '../../../services/ontologyService.utils'; import { Ontology } from '../../../types/ontologies.model'; import { Resource } from '../../../types/resources.model'; +import { Asset } from '../helpers/resourceFilterHelper'; import { - Asset, - createFormatAssets, - createTypeAssets, - createVendorAssets, - getResourceVendors, - getSelectedAssets, - updateFilterAsset -} from '../helpers/resourceFilterHelper'; -import { getPropertyValue } from '../helpers/resourcesHelper'; + initialResourceFilterState, + resourceFilterReducer, + setResourceFilterAssetsAction, + setSearchTextAction, + updateFilterAssetAction +} from '../helpers/resourceFilterReducer'; export const useResourceFilter = (ontologies: Ontology[], resources: Resource[]) => { - const [typeAssets, setTypeAssets] = useState([]); - const [formatAssets, setFormatAssets] = useState([]); - const [vendorAssets, setVendorAssets] = useState([]); - const [searchText, setSearchText] = useState(''); + const [filters, dispatch] = useReducer(resourceFilterReducer, initialResourceFilterState); useEffect(() => { - const resourceTypes = Array.from(getResourceTypes(ontologies)); - setTypeAssets(createTypeAssets(resourceTypes, resources)); - }, [resources]); - - const resourcesWithTypeFilterApplied = useMemo(() => resources - .filter((resource) => { - const selectedAssets = getSelectedAssets(typeAssets) - return selectedAssets === 'ALL' || selectedAssets - .some(type => resource.labels.includes(type)) - - }), - [typeAssets]); - - useEffect(() => { - const resourceFormats = Array.from(getResourceFormats(ontologies)); - - setFormatAssets(createFormatAssets(resourceFormats, formatAssets, resourcesWithTypeFilterApplied)); - }, [resourcesWithTypeFilterApplied]); - - const resourcesWithFormatFilterApplied = useMemo(() => resourcesWithTypeFilterApplied - .filter(resource => { - const selectedAssets = getSelectedAssets(formatAssets) - return selectedAssets === 'ALL' || selectedAssets - .some(format => resource.format === format) - }), [formatAssets]) - - useEffect(() => { - const resourceVendors = Array.from(getResourceVendors(resources)); - - setVendorAssets((prevVendorAssets) => - createVendorAssets(resourceVendors, prevVendorAssets, resourcesWithFormatFilterApplied)); - }, [resourcesWithFormatFilterApplied]); - - const resourcesWithVendorFilterApplied = useMemo(() => resourcesWithFormatFilterApplied - .filter(resource => { - const selectedAssets = getSelectedAssets(vendorAssets) - return selectedAssets === 'ALL' || selectedAssets - .some(vendor => resource.vendor === vendor) - }), [vendorAssets]) - - const resourcesWithSearchTextFilterApplied = useMemo(() => resourcesWithVendorFilterApplied - .filter(resource => Object - .entries(resource) - .some(property => !searchText || - getPropertyValue(property).toLowerCase() - .includes(searchText.toLowerCase())) - ), [resourcesWithVendorFilterApplied, searchText]); + dispatch(setResourceFilterAssetsAction(ontologies, resources)); + }, [ontologies, resources]); + const { searchText, ...resourceFilterAssetSate } = filters; return { - filteredResources: resourcesWithSearchTextFilterApplied, - typeAssets, - formatAssets, - vendorAssets, - updateSearchText: setSearchText, - updateFilterAsset: updateFilterAsset( - typeAssets, setTypeAssets, - formatAssets, setFormatAssets, - vendorAssets, setVendorAssets - ) + ...resourceFilterAssetSate, + updateSearchText: (searchText: string) => dispatch(setSearchTextAction(searchText, ontologies, resources)), + updateFilterAsset: (asset: Asset) => dispatch(updateFilterAssetAction(asset, ontologies, resources)) } } From 27c0f05169bed3e0f08e76826d8eb0230e38cc1a Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Mon, 23 Sep 2024 11:36:41 +0300 Subject: [PATCH 11/33] Move resource from redux to local state Signed-off-by: Zoltan Magyari --- src/actions/resourcesActions.ts | 25 ------- src/actions/types.ts | 6 -- .../helpers/resourceFilterReducer.ts | 1 - .../resources/helpers/resourcesReducer.ts | 66 +++++++++++++++++++ .../resources/hooks/useResources.ts | 28 ++++---- src/reducers/index.ts | 11 +--- src/reducers/resourcesReducer.ts | 25 ------- 7 files changed, 82 insertions(+), 80 deletions(-) delete mode 100644 src/actions/resourcesActions.ts create mode 100644 src/components/resources/helpers/resourcesReducer.ts delete mode 100644 src/reducers/resourcesReducer.ts diff --git a/src/actions/resourcesActions.ts b/src/actions/resourcesActions.ts deleted file mode 100644 index 74b493fb..00000000 --- a/src/actions/resourcesActions.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Resource } from '../types/resources.model'; - -import { SET_ALL_RESOURCES, SET_ALL_RESOURCES_LOADING_ERROR } from './types'; - -export type AllResources = { - resources: Resource[] -}; - -export type AllResourceError = { - error: string; -} - -export type AllResourcesAction = - { type: 'SET_ALL_RESOURCES', payload: AllResources } | - { type: 'SET_ALL_RESOURCES_LOADING_ERROR', payload: AllResourceError } - -export const resourcesLoadedAction = (payload: AllResources): AllResourcesAction => ({ - type: SET_ALL_RESOURCES, - payload -}) - -export const resourcesLoadingErrorAction = (payload: AllResourceError): AllResourcesAction => ({ - type: SET_ALL_RESOURCES_LOADING_ERROR, - payload -}) diff --git a/src/actions/types.ts b/src/actions/types.ts index 91134ef7..f4471b97 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -11,9 +11,3 @@ export const LCM_SERVICES_LOADED = 'LCM_SERVICES_LOADED'; export const RESET_LCM_SERVICES = 'RESET_LCM_SERVICES'; export const LCM_SELECT_SERVICE = 'LCM_SELECT_SERVICE'; export const CHANGE_USER_ROLE = 'CHANGE_USER_ROLE' - -//////////////////////////////////////////////////////////////////////////////// -// Resources -//////////////////////////////////////////////////////////////////////////////// -export const SET_ALL_RESOURCES = 'SET_ALL_RESOURCES'; -export const SET_ALL_RESOURCES_LOADING_ERROR = 'SET_ALL_RESOURCES_LOADING_ERROR'; diff --git a/src/components/resources/helpers/resourceFilterReducer.ts b/src/components/resources/helpers/resourceFilterReducer.ts index aa872dc6..7bdbc675 100644 --- a/src/components/resources/helpers/resourceFilterReducer.ts +++ b/src/components/resources/helpers/resourceFilterReducer.ts @@ -15,7 +15,6 @@ const UPDATE_FILTER_ASSET = 'UPDATE_FILTER_ASSET'; //////////////////////////////////////////////////////////////////////////////// // Type definitions //////////////////////////////////////////////////////////////////////////////// - type ResourceFilterAssetState = { filteredResources: Resource[], typeAssets: Asset[], diff --git a/src/components/resources/helpers/resourcesReducer.ts b/src/components/resources/helpers/resourcesReducer.ts new file mode 100644 index 00000000..3969f7e6 --- /dev/null +++ b/src/components/resources/helpers/resourcesReducer.ts @@ -0,0 +1,66 @@ +import { AnyAction } from 'redux'; + +import { Resource } from '../../../types/resources.model'; + +//////////////////////////////////////////////////////////////////////////////// +// Action types +//////////////////////////////////////////////////////////////////////////////// +const SET_ALL_RESOURCES = 'SET_ALL_RESOURCES'; +const SET_ALL_RESOURCES_LOADING_ERROR = 'SET_ALL_RESOURCES_LOADING_ERROR'; + +//////////////////////////////////////////////////////////////////////////////// +// Type definitions +//////////////////////////////////////////////////////////////////////////////// +type AllResources = { + resources: Resource[] +}; + +type AllResourceError = { + error: string; +} + +type IsLoading = { isLoading: boolean; } +export type AllResourcesState = (AllResources & { hasError: false } | AllResourceError & { hasError: true }) & IsLoading + +type AllResourcesAction = + { type: 'SET_ALL_RESOURCES', payload: AllResources } | + { type: 'SET_ALL_RESOURCES_LOADING_ERROR', payload: AllResourceError } + +//////////////////////////////////////////////////////////////////////////////// +// Initial state +//////////////////////////////////////////////////////////////////////////////// +export const initialResourceState: AllResourcesState = { + isLoading: true, + hasError: false, + resources: [] +} + +//////////////////////////////////////////////////////////////////////////////// +// Reducer +//////////////////////////////////////////////////////////////////////////////// +export const resourcesReducer = (state: AllResourcesState, action: AnyAction) => { + switch (action.type) { + + case SET_ALL_RESOURCES: + return { ...action.payload, isLoading: false, hasError: false } + + case SET_ALL_RESOURCES_LOADING_ERROR: + return { error: action.payload, isLoading: false, hasError: true } + + } + + return state +} + +//////////////////////////////////////////////////////////////////////////////// +// Actions +//////////////////////////////////////////////////////////////////////////////// +export const resourcesLoadedAction = (payload: AllResources): AllResourcesAction => ({ + type: SET_ALL_RESOURCES, + payload +}) + +export const resourcesLoadingErrorAction = (payload: AllResourceError): AllResourcesAction => ({ + type: SET_ALL_RESOURCES_LOADING_ERROR, + payload +}) diff --git a/src/components/resources/hooks/useResources.ts b/src/components/resources/hooks/useResources.ts index c62f7fc9..7f03e0a1 100644 --- a/src/components/resources/hooks/useResources.ts +++ b/src/components/resources/hooks/useResources.ts @@ -1,32 +1,34 @@ -import { useEffect, useMemo } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { Reducer, useEffect, useMemo, useReducer } from 'react'; +import { AnyAction } from 'redux'; -import { resourcesLoadedAction, resourcesLoadingErrorAction } from '../../../actions/resourcesActions'; import { useSchemas } from '../../../hooks/useSchemas'; -import { AppState } from '../../../reducers'; import { getResourceTypes } from '../../../services/ontologyService.utils'; import { loadResources } from '../helpers/resourceDataFlow'; import { removeNonResourceTypeLabels } from '../helpers/resourcesHelper'; +import { + AllResourcesState, + initialResourceState, + resourcesLoadedAction, + resourcesLoadingErrorAction, + resourcesReducer +} from '../helpers/resourcesReducer'; import { useResourceFilter } from './useResourceFilter'; export type ResourcesSearchPageContentType = 'LOADING' | 'SHOW_RESOURCES' | 'SHOW_NO_RESULTS'; export const useResources = () => { - const dispatch = useDispatch(); - const { - isLoading, - resources - } = useSelector((state: AppState) => ({ - isLoading: state.resources.isLoading, - resources: !state.resources.isLoading && !state.resources.hasError ? state.resources.resources : [] - })) - const schemas = useSchemas(); const ontologies = useMemo(() => !schemas.isLoading && !schemas.hasError ? schemas.ontologies : [], [schemas.isLoading]); + const [state, dispatch] = useReducer>(resourcesReducer, initialResourceState); + const { isLoading, resources } = useMemo(() => ({ + isLoading: state.isLoading, + resources: !state.isLoading && !state.hasError ? state.resources : [] + }), [state]); + const { filteredResources, typeAssets, diff --git a/src/reducers/index.ts b/src/reducers/index.ts index 43bdce9e..f28da69f 100644 --- a/src/reducers/index.ts +++ b/src/reducers/index.ts @@ -1,11 +1,8 @@ import { Reducer } from 'react'; import { AnyAction, combineReducers } from 'redux'; -import { Resource } from '../types/resources.model'; - import searchCriteriaStore from './SearchCriteriaStore'; import lcmReducer from './lcmReducer'; -import resources from './resourcesReducer'; import serviceDescriptorReducer from './serviceDescriptorReducer'; import userReducer from './userReducer'; @@ -24,17 +21,11 @@ export interface AppState { // searchCriteriaStore: { ... }, // serviceDescriptor: { ... }, // lcm: { ... }, - resources: { - isLoading: true, - hasError: false, - resources: Resource[] - } } export default combineReducers>({ user: userReducer, searchCriteriaStore: searchCriteriaStore, serviceDescriptor: serviceDescriptorReducer, - lcm: lcmReducer, - resources, + lcm: lcmReducer }); diff --git a/src/reducers/resourcesReducer.ts b/src/reducers/resourcesReducer.ts deleted file mode 100644 index b74a121b..00000000 --- a/src/reducers/resourcesReducer.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { AllResourceError, AllResources, AllResourcesAction } from '../actions/resourcesActions'; -import { SET_ALL_RESOURCES, SET_ALL_RESOURCES_LOADING_ERROR } from '../actions/types'; - -type IsLoading = { isLoading: boolean; } -export type AllResourcesState = (AllResources & { hasError: false } | AllResourceError & { hasError: true }) & IsLoading - -const initialState: AllResourcesState = { - isLoading: true, - hasError: false, - resources: [] -} - -export default (state: AllResourcesState = initialState, action: AllResourcesAction) => { - switch (action.type) { - - case SET_ALL_RESOURCES: - return { ...action.payload, isLoading: false, hasError: false } - - case SET_ALL_RESOURCES_LOADING_ERROR: - return { error: action.payload, isLoading: false, hasError: true } - - } - return state - -} From 041f5cfef99390fd925327170b1f1d8ad993a6d1 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Tue, 24 Sep 2024 21:26:57 +0300 Subject: [PATCH 12/33] Fix eslint: remove unnecessary quotes from props Signed-off-by: Zoltan Magyari --- .eslintrc.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index e61b3282..d8fc530d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -19,6 +19,10 @@ "import" ], "rules": { + "quote-props": [ + "error", + "as-needed" + ], "no-const-assign": "warn", "no-this-before-super": "warn", "no-undef": "warn", @@ -44,7 +48,10 @@ "no-trailing-spaces": ["error"], "quotes": ["error", "single"], "object-curly-spacing": ["error", "always"], - "eol-last": ["error", "always"] + "eol-last": [ + "error", + "always" + ] }, "extends": [ "eslint:recommended", From 1d4026ecc370b259e3b719ea408bb95e80193466 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Tue, 24 Sep 2024 21:27:58 +0300 Subject: [PATCH 13/33] Git workflow for running jest test Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 60 ++++++++++++++++++++++++++++++ jest.config.js | 11 ++++++ 2 files changed, 71 insertions(+) create mode 100644 .github/workflows/branch-push.yaml diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml new file mode 100644 index 00000000..8b7df05b --- /dev/null +++ b/.github/workflows/branch-push.yaml @@ -0,0 +1,60 @@ +name: CI pipeline + +on: + pull_request: + branches: + - "**" # Runs on all pull requests + +jobs: + check-test-coverage: + # The coverage is configured inside 'jest.config.js' by setting the 'coverageThreshold' + name: Checking test coverage (must be over 90%) + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [ 20.17 ] # Define Node.js latest LTS version (update as needed) + + steps: + # Step 1: Checkout the code + - name: Checkout repository + uses: actions/checkout@v4 + + # Step 2: Set up Node.js with the required version + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + # Step 3: Install dependencies + - name: Install dependencies + run: npm install + + # Step 4: Run Jest tests + - name: Run Jest tests + # TODO: Adapt to run coverage on changed files only. + # run: npm test -- --coverage # $(git diff --name-only origin/main...HEAD | grep '\.[jt]sx\?$' | grep -v '\ .test\.') + run: npm test -- --coverage + env: + CI: true # Ensures Jest runs in CI mode + + # Step 5: Upload test coverage results (optional, if you want to store it in the workflow run artifacts) + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage/lcov-report/ # Path to the HTML coverage report + retention-days: 7 + + # Step 6: Fail the job if there are uncovered files (js, ts, jsx, tsx) + # TODO: It needs to be implemented. + + # Step 7: Fail the job if the test coverage is below a threshold (optional) + # TODO: This should be removed because it is solved within 'jest.config.js' by setting the 'coverageThreshold'. + # - name: Check coverage threshold + # run: | + # COVERAGE=$(grep -o '"total": {.*}' coverage/coverage-summary.json | grep -o '"lines":{.*}$' | grep -o '"pct":[0-9]*' | grep -m 1 '"pct":[0-9]*' | grep -o '[0-9]*') + # if [ "$COVERAGE" -lt 90 ]; then + # echo "Test coverage below 90%. Coverage: $COVERAGE%" + # exit 1 + # fi diff --git a/jest.config.js b/jest.config.js index 34b6ad10..394dafc4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -25,5 +25,16 @@ module.exports = { moduleNameMapper: { '^axios$': '/node_modules/axios/dist/node/axios.cjs' + }, + + // Jest configurations + collectCoverage: true, // Enable coverage collection + coverageDirectory: 'coverage', // Output folder for coverage + collectCoverageFrom: ['./src/**'], // Specify the path from which Jest should collect coverage + coverageReporters: ['json', 'lcov', 'text', 'clover', 'json-summary'], // Add 'json-summary' to generate coverage-summary.json + coverageThreshold: { + global: { + lines: 90 // Line coverage must be over 90% + } } }; From 8b5d1cb04c8ed3734577b2decdb6a6404f48eb7c Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Wed, 25 Sep 2024 18:35:05 +0300 Subject: [PATCH 14/33] Fix missing React import Signed-off-by: Zoltan Magyari --- src/Search.js | 2 +- src/components/ItemCard/ItemCard.tsx | 2 +- src/components/ItemCard/ResourceCardContent.tsx | 2 +- src/components/Title/Title.tsx | 2 +- src/components/buttons/GaiaXButton.tsx | 2 +- src/components/cards/CardContainer.tsx | 2 +- src/components/filter/Filter.tsx | 2 +- src/components/filter/FilterSection.tsx | 2 +- src/components/header/Header.tsx | 2 +- src/components/layout/Horizontal.tsx | 2 +- src/components/layout/Main.tsx | 2 +- src/components/layout/Vertical.tsx | 2 +- src/components/navbar/Navbar.tsx | 2 +- src/components/participants/Participants.tsx | 2 +- src/components/searchBar/SearchBar.tsx | 2 +- src/components/solutionPackaging/SaveBookModal.js | 2 +- src/components/subtitle/Subtitle.tsx | 2 ++ src/pages/home/Home.tsx | 2 +- 18 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Search.js b/src/Search.js index 7e820f64..8110edf9 100644 --- a/src/Search.js +++ b/src/Search.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import { Component } from 'react'; +import React, { Component } from 'react'; import { useTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { useNavigate } from 'react-router-dom'; diff --git a/src/components/ItemCard/ItemCard.tsx b/src/components/ItemCard/ItemCard.tsx index 3e9c6ef0..819665fc 100644 --- a/src/components/ItemCard/ItemCard.tsx +++ b/src/components/ItemCard/ItemCard.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; import { Ontology } from '../../types/ontologies.model'; diff --git a/src/components/ItemCard/ResourceCardContent.tsx b/src/components/ItemCard/ResourceCardContent.tsx index 7b0ace3f..621b0909 100644 --- a/src/components/ItemCard/ResourceCardContent.tsx +++ b/src/components/ItemCard/ResourceCardContent.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; diff --git a/src/components/Title/Title.tsx b/src/components/Title/Title.tsx index a5679305..910965c4 100644 --- a/src/components/Title/Title.tsx +++ b/src/components/Title/Title.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import styles from './Title.module.css'; diff --git a/src/components/buttons/GaiaXButton.tsx b/src/components/buttons/GaiaXButton.tsx index 95a86e42..11aba4bb 100644 --- a/src/components/buttons/GaiaXButton.tsx +++ b/src/components/buttons/GaiaXButton.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import styles from './GaiaXButton.module.css'; diff --git a/src/components/cards/CardContainer.tsx b/src/components/cards/CardContainer.tsx index 30afa793..bcbda628 100644 --- a/src/components/cards/CardContainer.tsx +++ b/src/components/cards/CardContainer.tsx @@ -1,4 +1,4 @@ -import { FC, ReactNode } from 'react'; +import React, { FC, ReactNode } from 'react'; import Vertical from '../layout/Vertical'; diff --git a/src/components/filter/Filter.tsx b/src/components/filter/Filter.tsx index 5e4a1b07..8edaddb7 100644 --- a/src/components/filter/Filter.tsx +++ b/src/components/filter/Filter.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import Title from '../Title/Title'; import { Asset } from '../resources/helpers/resourceFilterHelper'; diff --git a/src/components/filter/FilterSection.tsx b/src/components/filter/FilterSection.tsx index 8fbe2486..5ad62ebb 100644 --- a/src/components/filter/FilterSection.tsx +++ b/src/components/filter/FilterSection.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import { Asset } from '../resources/helpers/resourceFilterHelper'; import Subtitle from '../subtitle/Subtitle'; diff --git a/src/components/header/Header.tsx b/src/components/header/Header.tsx index fb2d8115..85c95c0d 100644 --- a/src/components/header/Header.tsx +++ b/src/components/header/Header.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import React, { FC } from 'react'; import Title from '../Title/Title'; diff --git a/src/components/layout/Horizontal.tsx b/src/components/layout/Horizontal.tsx index 710860da..d8692667 100644 --- a/src/components/layout/Horizontal.tsx +++ b/src/components/layout/Horizontal.tsx @@ -1,4 +1,4 @@ -import { FC, ReactNode } from 'react'; +import React, { FC, ReactNode } from 'react'; import style from './Layout.module.css' diff --git a/src/components/layout/Main.tsx b/src/components/layout/Main.tsx index 545106fd..4ae1e9cc 100644 --- a/src/components/layout/Main.tsx +++ b/src/components/layout/Main.tsx @@ -1,4 +1,4 @@ -import { FC, ReactNode } from 'react'; +import React, { FC, ReactNode } from 'react'; import style from './Layout.module.css' diff --git a/src/components/layout/Vertical.tsx b/src/components/layout/Vertical.tsx index 6e922994..f996af2f 100644 --- a/src/components/layout/Vertical.tsx +++ b/src/components/layout/Vertical.tsx @@ -1,4 +1,4 @@ -import { FC, ReactNode } from 'react'; +import React, { FC, ReactNode } from 'react'; import style from './Layout.module.css' diff --git a/src/components/navbar/Navbar.tsx b/src/components/navbar/Navbar.tsx index 330eb79b..7e787bc7 100644 --- a/src/components/navbar/Navbar.tsx +++ b/src/components/navbar/Navbar.tsx @@ -3,7 +3,7 @@ import LanguageModal from 'components/modals/LanguageModal'; import { AuthContext } from 'context/AuthContextProvider'; import { useNavbar } from 'hooks/useNavbar'; import i18n from 'i18n'; -import { useContext, useState } from 'react'; +import React, { useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Link, NavLink } from 'react-router-dom'; diff --git a/src/components/participants/Participants.tsx b/src/components/participants/Participants.tsx index e1fcb490..6d216370 100644 --- a/src/components/participants/Participants.tsx +++ b/src/components/participants/Participants.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { CarLoader } from '../carLoader/CarLoader'; diff --git a/src/components/searchBar/SearchBar.tsx b/src/components/searchBar/SearchBar.tsx index 1ddc46e1..7996853f 100644 --- a/src/components/searchBar/SearchBar.tsx +++ b/src/components/searchBar/SearchBar.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, FC, useState } from 'react'; +import React, { ChangeEvent, FC, useState } from 'react'; import styles from './SearchBar.module.css'; diff --git a/src/components/solutionPackaging/SaveBookModal.js b/src/components/solutionPackaging/SaveBookModal.js index 994b72c8..0b10fbf5 100644 --- a/src/components/solutionPackaging/SaveBookModal.js +++ b/src/components/solutionPackaging/SaveBookModal.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import { useState } from 'react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import Modal from '../../Modal'; diff --git a/src/components/subtitle/Subtitle.tsx b/src/components/subtitle/Subtitle.tsx index a3fa6ec6..6ceada5a 100644 --- a/src/components/subtitle/Subtitle.tsx +++ b/src/components/subtitle/Subtitle.tsx @@ -1,3 +1,5 @@ +import React from 'react' + import styles from './Subtitle.module.css'; interface ISubtitle { diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index fdbf6fcc..57c70717 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -2,7 +2,7 @@ import Text from 'components/Text/Text'; import Title from 'components/Title/Title'; import HeaderWithImage from 'components/headerWithImage/HeaderWithImage'; import { AuthContext } from 'context/AuthContextProvider'; -import { useContext } from 'react'; +import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as HeaderImage } from '../../assets/images/header_image.svg'; From bc893d3077cd05b5225ead554602e32d0fa98e03 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Wed, 25 Sep 2024 18:36:39 +0300 Subject: [PATCH 15/33] Fix jest mocking css modules and images Signed-off-by: Zoltan Magyari --- jest.config.js | 17 ++++++++++------- tests/__fixtures__/mocks/iconsMock.js | 1 + tests/__fixtures__/mocks/stylesMock.js | 1 + 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 tests/__fixtures__/mocks/iconsMock.js create mode 100644 tests/__fixtures__/mocks/stylesMock.js diff --git a/jest.config.js b/jest.config.js index 394dafc4..62f01236 100644 --- a/jest.config.js +++ b/jest.config.js @@ -24,17 +24,20 @@ module.exports = { moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], moduleNameMapper: { - '^axios$': '/node_modules/axios/dist/node/axios.cjs' + '^axios$': '/node_modules/axios/dist/node/axios.cjs', + '\\.(jpg|jpeg|png|gif|webp|svg)$': '/tests/__fixtures__/mocks/iconsMock.js', // Map image files to iconsMock.js + '\\.module\\.css$': 'identity-obj-proxy', // CSS module files + '\\.css$': '/tests/__fixtures__/mocks/stylesMock.js', // Optional: Mock regular CSS files }, // Jest configurations - collectCoverage: true, // Enable coverage collection - coverageDirectory: 'coverage', // Output folder for coverage - collectCoverageFrom: ['./src/**'], // Specify the path from which Jest should collect coverage - coverageReporters: ['json', 'lcov', 'text', 'clover', 'json-summary'], // Add 'json-summary' to generate coverage-summary.json + collectCoverage: true, // Enable coverage collection + coverageDirectory: 'coverage', // Output folder for coverage + collectCoverageFrom: ['./src/**'], // Specify the path from which Jest should collect coverage + coverageReporters: ['json', 'lcov', 'text', 'clover', 'json-summary'], // Add 'json-summary' to generate coverage-summary.json coverageThreshold: { global: { - lines: 90 // Line coverage must be over 90% + lines: 90 // Line coverage must be over 90% } - } + }, }; diff --git a/tests/__fixtures__/mocks/iconsMock.js b/tests/__fixtures__/mocks/iconsMock.js new file mode 100644 index 00000000..bc5c9cbc --- /dev/null +++ b/tests/__fixtures__/mocks/iconsMock.js @@ -0,0 +1 @@ +module.exports = 'icons-mock'; diff --git a/tests/__fixtures__/mocks/stylesMock.js b/tests/__fixtures__/mocks/stylesMock.js new file mode 100644 index 00000000..0c28a1f8 --- /dev/null +++ b/tests/__fixtures__/mocks/stylesMock.js @@ -0,0 +1 @@ +module.exports = 'styles-mock'; From 008cdd3bed2d60620543cc6afeefb46deb99af64 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Wed, 25 Sep 2024 21:09:15 +0300 Subject: [PATCH 16/33] Fix jest mocking react-i18next module Signed-off-by: Zoltan Magyari --- jest.config.js | 1 + tests/__fixtures__/mocks/react-i18next.js | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/__fixtures__/mocks/react-i18next.js diff --git a/jest.config.js b/jest.config.js index 62f01236..a1016704 100644 --- a/jest.config.js +++ b/jest.config.js @@ -25,6 +25,7 @@ module.exports = { moduleNameMapper: { '^axios$': '/node_modules/axios/dist/node/axios.cjs', + '^react-i18next$': '/tests/__fixtures__/mocks/react-i18next.js', // Map react-i18next to the mock file '\\.(jpg|jpeg|png|gif|webp|svg)$': '/tests/__fixtures__/mocks/iconsMock.js', // Map image files to iconsMock.js '\\.module\\.css$': 'identity-obj-proxy', // CSS module files '\\.css$': '/tests/__fixtures__/mocks/stylesMock.js', // Optional: Mock regular CSS files diff --git a/tests/__fixtures__/mocks/react-i18next.js b/tests/__fixtures__/mocks/react-i18next.js new file mode 100644 index 00000000..53b128f4 --- /dev/null +++ b/tests/__fixtures__/mocks/react-i18next.js @@ -0,0 +1,10 @@ +module.exports = { + useTranslation: () => { + return { + t: (key) => key, // Return the key as the translated value + i18n: { + changeLanguage: jest.fn(), + }, + }; + }, +}; From e0218d26413c0625f27632b5f0b23e9efb19588c Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Tue, 24 Sep 2024 22:53:25 +0300 Subject: [PATCH 17/33] Increase test coverage Signed-off-by: Zoltan Magyari --- src/components/ItemCard/ItemCard.tsx | 2 +- .../resources/helpers/resourceFilterHelper.ts | 19 +- .../helpers/resourceFilterReducer.ts | 6 +- .../resources/helpers/resourcesHelper.ts | 6 +- .../resources/helpers/resourcesReducer.ts | 24 +- .../resources/hooks/useResourceFilter.ts | 1 + .../resources/hooks/useResources.ts | 20 +- src/helpers/schemasReducer.ts | 2 +- src/hooks/useSchemas.ts | 4 +- src/services/schemaApiService.ts | 7 +- ...tologies_General_HdMap_EnvironmentModel.ts | 2619 +++++++++++++++++ .../resources/ResourcesSearchPage.test.tsx | 81 + .../useResources_ResourceSearchPage.ts | 65 + ...llResources_HdMap_EnvironmentModel_x2.json | 80 + ...ceFilterState_HdMap_EnvironmentModel_x2.ts | 684 +++++ .../resources_HdMap_EnvironmentModel_x2.ts | 58 + .../helpers/resourceDataFlow.test.ts | 37 + .../helpers/resourceFilterHelper.test.ts | 692 +++++ .../helpers/resourceFilterReducer.test.ts | 60 + .../resources/helpers/resourceHelper.test.ts | 27 + .../resources/helpers/resourceReducer.test.ts | 61 + ...esourcesState_HdMap_EnvironmentModel_x2.ts | 390 +++ .../resources/hooks/useResourceFilter.test.ts | 93 + .../resources/hooks/useResources.test.ts | 100 + tests/services/schemaApiService.test.ts | 92 + tests/utils/readFile.test.ts | 63 +- 26 files changed, 5221 insertions(+), 72 deletions(-) create mode 100644 tests/__fixtures__/ontologies_General_HdMap_EnvironmentModel.ts create mode 100644 tests/components/resources/ResourcesSearchPage.test.tsx create mode 100644 tests/components/resources/__fixtures__/useResources_ResourceSearchPage.ts create mode 100644 tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json create mode 100644 tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts create mode 100644 tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts create mode 100644 tests/components/resources/helpers/resourceDataFlow.test.ts create mode 100644 tests/components/resources/helpers/resourceFilterHelper.test.ts create mode 100644 tests/components/resources/helpers/resourceFilterReducer.test.ts create mode 100644 tests/components/resources/helpers/resourceHelper.test.ts create mode 100644 tests/components/resources/helpers/resourceReducer.test.ts create mode 100644 tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts create mode 100644 tests/components/resources/hooks/useResourceFilter.test.ts create mode 100644 tests/components/resources/hooks/useResources.test.ts create mode 100644 tests/services/schemaApiService.test.ts diff --git a/src/components/ItemCard/ItemCard.tsx b/src/components/ItemCard/ItemCard.tsx index 819665fc..3c1c13b5 100644 --- a/src/components/ItemCard/ItemCard.tsx +++ b/src/components/ItemCard/ItemCard.tsx @@ -33,7 +33,7 @@ const ItemCard: FC = ({ const { t } = useTranslation(); return ( -
+
{label} {isGaiaXCompliant === undefined ? null : ( diff --git a/src/components/resources/helpers/resourceFilterHelper.ts b/src/components/resources/helpers/resourceFilterHelper.ts index e9b1dd49..8e1d66f2 100644 --- a/src/components/resources/helpers/resourceFilterHelper.ts +++ b/src/components/resources/helpers/resourceFilterHelper.ts @@ -5,9 +5,6 @@ import { Resource } from '../../../types/resources.model'; import { ResourceFilterState } from './resourceFilterReducer'; import { getPropertyValue } from './resourcesHelper'; -export const TYPE_ASSETS = 'typeAssets'; -export const FORMAT_ASSETS = 'formatAssets'; -export const VENDOR_ASSETS = 'vendorAssets'; export type AssetTypes = 'typeAssets' | 'formatAssets' | 'vendorAssets'; /** @@ -82,7 +79,7 @@ export const createFormatAssets = ( * @param resources the list of resources to look for the formats in. * @return the set of available labels. */ -const getAllFormats = (resources: Resource[]) => +export const getAllFormats = (resources: Resource[]) => new Set( resources .map(resource => resource.format) @@ -131,7 +128,7 @@ export const getResourceVendors = (resources: Resource[]) => * Represents a list of assets that are selected. It has an ALL option which means that everything is selected. No * list should be provided. */ -export type SelectedAssets = 'ALL' | string[]; +export type SelectedAssets = 'NOTHING' | string[]; /** * Returns the selected assets from the list. It has an ALL option which means that everything is selected. No list @@ -139,7 +136,7 @@ export type SelectedAssets = 'ALL' | string[]; * * An asset is considered selected when it is not disabled and its value is true. * - * If no asset is selected it is considered that everything is selected and in that case it is returned 'ALL'. + * If no asset is selected it is considered that everything is selected and in that case it is returned 'NOTHING'. * * @param assets list to be filtered for the selected one. */ @@ -150,9 +147,9 @@ export const getSelectedAssets = (assets: Asset[]): SelectedAssets => { // If type filter is selected it is considered that all enabled ones are selected if (!selectedAssets.length) { - return 'ALL' + return 'NOTHING' } - return selectedAssets; + return selectedAssets } /** @@ -176,7 +173,7 @@ export const calculateResourceFiltersAssetState = ( const resourcesWithTypeFilterApplied = resources .filter((resource) => { const selectedAssets = getSelectedAssets(filters.typeAssets) - return selectedAssets === 'ALL' || selectedAssets + return selectedAssets === 'NOTHING' || selectedAssets .some(type => resource.labels.includes(type)) }); @@ -186,7 +183,7 @@ export const calculateResourceFiltersAssetState = ( const resourcesWithFormatFilterApplied = resourcesWithTypeFilterApplied .filter(resource => { const selectedAssets = getSelectedAssets(filters.formatAssets) - return selectedAssets === 'ALL' || selectedAssets + return selectedAssets === 'NOTHING' || selectedAssets .some(format => resource.format === format) }); @@ -196,7 +193,7 @@ export const calculateResourceFiltersAssetState = ( const resourcesWithVendorFilterApplied = resourcesWithFormatFilterApplied .filter(resource => { const selectedAssets = getSelectedAssets(filters.vendorAssets) - return selectedAssets === 'ALL' || selectedAssets + return selectedAssets === 'NOTHING' || selectedAssets .some(vendor => resource.vendor === vendor) }); diff --git a/src/components/resources/helpers/resourceFilterReducer.ts b/src/components/resources/helpers/resourceFilterReducer.ts index 7bdbc675..d68aac3a 100644 --- a/src/components/resources/helpers/resourceFilterReducer.ts +++ b/src/components/resources/helpers/resourceFilterReducer.ts @@ -8,9 +8,9 @@ import { Asset, calculateResourceFiltersAssetState } from './resourceFilterHelpe //////////////////////////////////////////////////////////////////////////////// // Action types //////////////////////////////////////////////////////////////////////////////// -const SET_RESOURCE_FILTER_ASSETS = 'SET_RESOURCE_FILTER_ASSETS'; -const SET_SEARCH_TEXT = 'SET_SEARCH_TEXT'; -const UPDATE_FILTER_ASSET = 'UPDATE_FILTER_ASSET'; +export const SET_RESOURCE_FILTER_ASSETS = 'SET_RESOURCE_FILTER_ASSETS'; +export const SET_SEARCH_TEXT = 'SET_SEARCH_TEXT'; +export const UPDATE_FILTER_ASSET = 'UPDATE_FILTER_ASSET'; //////////////////////////////////////////////////////////////////////////////// // Type definitions diff --git a/src/components/resources/helpers/resourcesHelper.ts b/src/components/resources/helpers/resourcesHelper.ts index 0318b022..e315d2fe 100644 --- a/src/components/resources/helpers/resourcesHelper.ts +++ b/src/components/resources/helpers/resourcesHelper.ts @@ -12,13 +12,13 @@ export const getPropertyValue = (objectEntry: [string, any]) => String(objectEnt * This has relevance when displaying the resource list. We do not want to show the above-mentioned labels. * * @param resources the original resource list. - * @param reosurceTypes the types to be considered as resource types. + * @param resourceTypes the types to be considered as resource types. * @return returns copy of the original resources without the labels. */ -export const removeNonResourceTypeLabels = (resources: Resource[], reosurceTypes: string[]) => { +export const removeNonResourceTypeLabels = (resources: Resource[], resourceTypes: string[]) => { return resources.map(resource => ({ ...resource, - labels: resource.labels.filter(label => reosurceTypes.includes(label)) + labels: resource.labels.filter(label => resourceTypes.includes(label)) })); } diff --git a/src/components/resources/helpers/resourcesReducer.ts b/src/components/resources/helpers/resourcesReducer.ts index 3969f7e6..fca0f739 100644 --- a/src/components/resources/helpers/resourcesReducer.ts +++ b/src/components/resources/helpers/resourcesReducer.ts @@ -5,26 +5,26 @@ import { Resource } from '../../../types/resources.model'; //////////////////////////////////////////////////////////////////////////////// // Action types //////////////////////////////////////////////////////////////////////////////// -const SET_ALL_RESOURCES = 'SET_ALL_RESOURCES'; -const SET_ALL_RESOURCES_LOADING_ERROR = 'SET_ALL_RESOURCES_LOADING_ERROR'; +export const SET_ALL_RESOURCES = 'SET_ALL_RESOURCES'; +export const SET_ALL_RESOURCES_LOADING_ERROR = 'SET_ALL_RESOURCES_LOADING_ERROR'; //////////////////////////////////////////////////////////////////////////////// // Type definitions //////////////////////////////////////////////////////////////////////////////// -type AllResources = { +export type AllResources = { resources: Resource[] }; type AllResourceError = { - error: string; + error: string | Error; } type IsLoading = { isLoading: boolean; } export type AllResourcesState = (AllResources & { hasError: false } | AllResourceError & { hasError: true }) & IsLoading type AllResourcesAction = - { type: 'SET_ALL_RESOURCES', payload: AllResources } | - { type: 'SET_ALL_RESOURCES_LOADING_ERROR', payload: AllResourceError } + { type: 'SET_ALL_RESOURCES', payload: Resource[] } | + { type: 'SET_ALL_RESOURCES_LOADING_ERROR', payload: string | Error } //////////////////////////////////////////////////////////////////////////////// // Initial state @@ -38,11 +38,11 @@ export const initialResourceState: AllResourcesState = { //////////////////////////////////////////////////////////////////////////////// // Reducer //////////////////////////////////////////////////////////////////////////////// -export const resourcesReducer = (state: AllResourcesState, action: AnyAction) => { +export const resourcesReducer = (state: AllResourcesState, action: AnyAction): AllResourcesState => { switch (action.type) { case SET_ALL_RESOURCES: - return { ...action.payload, isLoading: false, hasError: false } + return { resources: action.payload, isLoading: false, hasError: false } case SET_ALL_RESOURCES_LOADING_ERROR: return { error: action.payload, isLoading: false, hasError: true } @@ -55,12 +55,12 @@ export const resourcesReducer = (state: AllResourcesState, action: AnyAction) => //////////////////////////////////////////////////////////////////////////////// // Actions //////////////////////////////////////////////////////////////////////////////// -export const resourcesLoadedAction = (payload: AllResources): AllResourcesAction => ({ +export const resourcesLoadedAction = (resources: Resource[]): AllResourcesAction => ({ type: SET_ALL_RESOURCES, - payload + payload: resources }) -export const resourcesLoadingErrorAction = (payload: AllResourceError): AllResourcesAction => ({ +export const resourcesLoadingErrorAction = (error: string | Error): AllResourcesAction => ({ type: SET_ALL_RESOURCES_LOADING_ERROR, - payload + payload: error }) diff --git a/src/components/resources/hooks/useResourceFilter.ts b/src/components/resources/hooks/useResourceFilter.ts index 413ec40f..eb221525 100644 --- a/src/components/resources/hooks/useResourceFilter.ts +++ b/src/components/resources/hooks/useResourceFilter.ts @@ -18,6 +18,7 @@ export const useResourceFilter = (ontologies: Ontology[], resources: Resource[]) dispatch(setResourceFilterAssetsAction(ontologies, resources)); }, [ontologies, resources]); + // Remove the "searchText" property from the "filters" const { searchText, ...resourceFilterAssetSate } = filters; return { ...resourceFilterAssetSate, diff --git a/src/components/resources/hooks/useResources.ts b/src/components/resources/hooks/useResources.ts index 7f03e0a1..20a1c3e2 100644 --- a/src/components/resources/hooks/useResources.ts +++ b/src/components/resources/hooks/useResources.ts @@ -1,12 +1,10 @@ -import { Reducer, useEffect, useMemo, useReducer } from 'react'; -import { AnyAction } from 'redux'; +import { useEffect, useMemo, useReducer } from 'react'; import { useSchemas } from '../../../hooks/useSchemas'; import { getResourceTypes } from '../../../services/ontologyService.utils'; import { loadResources } from '../helpers/resourceDataFlow'; import { removeNonResourceTypeLabels } from '../helpers/resourcesHelper'; import { - AllResourcesState, initialResourceState, resourcesLoadedAction, resourcesLoadingErrorAction, @@ -23,7 +21,7 @@ export const useResources = () => { !schemas.isLoading && !schemas.hasError ? schemas.ontologies : [], [schemas.isLoading]); - const [state, dispatch] = useReducer>(resourcesReducer, initialResourceState); + const [state, dispatch] = useReducer(resourcesReducer, initialResourceState); const { isLoading, resources } = useMemo(() => ({ isLoading: state.isLoading, resources: !state.isLoading && !state.hasError ? state.resources : [] @@ -39,11 +37,15 @@ export const useResources = () => { } = useResourceFilter(ontologies, resources); useEffect(() => { - if (!schemas.isLoading && !schemas.hasError) { - const resourceTypes = Array.from(getResourceTypes(schemas.ontologies)); - loadResources(resourceTypes) - .then(resources => dispatch(resourcesLoadedAction({ resources }))) - .catch(error => dispatch(resourcesLoadingErrorAction(error))) + if (!schemas.isLoading) { + if (!schemas.hasError) { + const resourceTypes = Array.from(getResourceTypes(schemas.ontologies)); + loadResources(resourceTypes) + .then(resources => dispatch(resourcesLoadedAction(resources))) + .catch(error => dispatch(resourcesLoadingErrorAction(error))) + } else { + dispatch(resourcesLoadingErrorAction(schemas.error)) + } } }, [schemas.isLoading]); diff --git a/src/helpers/schemasReducer.ts b/src/helpers/schemasReducer.ts index ce6acab7..a3e884f2 100644 --- a/src/helpers/schemasReducer.ts +++ b/src/helpers/schemasReducer.ts @@ -20,7 +20,7 @@ type AllSchemas = { } type AllSchemasError = { - error: string; + error: string | Error; } // TODO: Extend the AnyAction type diff --git a/src/hooks/useSchemas.ts b/src/hooks/useSchemas.ts index 35699e2b..6e6987ab 100644 --- a/src/hooks/useSchemas.ts +++ b/src/hooks/useSchemas.ts @@ -4,7 +4,7 @@ import { loadSchemas } from '../helpers/schemasDataFlow'; import { AllSchemasState, schemasReducer } from '../helpers/schemasReducer'; import { useThunkReducer } from '../reducers/useThunkReducer'; -export const initialState: AllSchemasState = { +export const initialSchemaState: AllSchemasState = { isLoading: true, hasError: false, shapes: [], @@ -12,7 +12,7 @@ export const initialState: AllSchemasState = { } export const useSchemas = (): AllSchemasState => { - const [schemas, dispatch] = useThunkReducer(schemasReducer, initialState); + const [schemas, dispatch] = useThunkReducer(schemasReducer, initialSchemaState); useEffect( () => dispatch(loadSchemas), diff --git a/src/services/schemaApiService.ts b/src/services/schemaApiService.ts index 22832e02..72edef85 100644 --- a/src/services/schemaApiService.ts +++ b/src/services/schemaApiService.ts @@ -12,7 +12,7 @@ export const fetchAllSchemas = async (): Promise => { return response.data; } catch (error) { console.error(error); - return { ontologies: [], shapes: [], vocabularies: [] } + return { ontologies: [], shapes: [], vocabularies: [] }; } }; @@ -25,9 +25,14 @@ export const getSchemaById = async (id: string) => { return response.data; } catch (error) { console.error('Error:', error); + throw error; } }; +/** + * + * @param id + */ export const getConvertedFile = async (id: string) => { try { const textContent = await getSchemaById(id); diff --git a/tests/__fixtures__/ontologies_General_HdMap_EnvironmentModel.ts b/tests/__fixtures__/ontologies_General_HdMap_EnvironmentModel.ts new file mode 100644 index 00000000..3c3aca4a --- /dev/null +++ b/tests/__fixtures__/ontologies_General_HdMap_EnvironmentModel.ts @@ -0,0 +1,2619 @@ +import { Ontology } from '../../src/types/ontologies.model'; + +export const ontologies_General_HdMap_EnvironmentModel = [ + { + subject: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/', + contributors: [ + 'Mirco Nierenz (TG)' + ], + description: 'ontology definition for General', + version: '0.1', + nodes: [ + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/', + label: '"ontology definition for General"@en', + type: 'http://www.w3.org/2002/07/owl#Ontology' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/General', + label: '"Class definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Description', + label: '"Description definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Data', + label: '"Data definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/BundleData', + label: '"BundleData definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Links', + label: '"Links definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Link', + label: '"Link definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Range2D', + label: '"Range2D definition for General"', + type: 'http://www.w3.org/2002/07/owl#Class' + } + ], + links: [], + relatedShapes: [ + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/GeneralShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/description', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/DescriptionShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/description' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/data', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/DataShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/data' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/links', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinksShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/links' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/bundleData', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/BundleDataShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '4' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/bundleData' + } + ] + } + ], + nodes: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/DescriptionShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/DataShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinksShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/BundleDataShape' + ], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/General' + ] + }, + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/DescriptionShape', + properties: [ + { + propertyId: 'https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#name', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'name' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'A human readable name of the entity.' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '3D Model in Grafing' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#name' + } + ] + }, + { + propertyId: 'https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#description', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'description' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'A free text description of the entity.' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'town district, with traffic signs' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#description' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Description' + ] + }, + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/DataShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/size', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'size' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Size of the file to be downloaded in MB.' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '5.8' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/size' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/contractId', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'contractId' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Contract information in regards to the data exchange component.' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'contract_zcdkr7kqd47y0w5b4tg91w1etw' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/contractId' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/recordingTime', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'recordingTime' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Time of data acquisition used to generate the asset, if partial measurement: oldest date' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '2022-04-01 00:00:00' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#dateTime' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of recordingTime failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/recordingTime' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Data' + ] + }, + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/BundleDataShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/requiredData', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'requiredData' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Reference to required assets' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'for scenario, link to required hd map' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/requiredData' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/relatedData', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'relatedData' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Reference to optional related assets' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'at hd map, link to optional surface map' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/relatedData' + } + ] + } + ], + nodes: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape' + ], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/BundleData' + ] + }, + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinksShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/media', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'media' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Reference to media data' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'link to bundle data, screenshot, video, routing, 3d preview' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of media failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/media' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/data', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'data' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Reference to the data asset as url/uri of the EDC' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'link to data asset, e.g. hd map' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of data failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/data' + } + ] + } + ], + nodes: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape' + ], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Links' + ] + }, + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/LinkShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/type', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'type' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Choose type of link.' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'Document', + 'Image', + 'Model', + 'Routing', + 'Video', + '3DPreview', + 'Asset' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of type failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/type' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/url', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'url' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Enter link as URL or DID.' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#anyURI' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of url failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/url' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Link' + ] + }, + { + shaclShapeId: '8c6a9177cc0141095c1d65d10963359bb5338f9dd8ceb314073ce0a3c3497b59', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Range2DShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/max', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'max' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of max failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/max' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/min', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'min' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of min failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/min' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Range2D' + ] + } + ] + }, + { + subject: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/', + contributors: [ + 'Sebastian Tuttas (3DMS)' + ], + description: 'ontology definition for hdmap', + version: '0.1', + nodes: [ + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/', + label: '"ontology definition for hdmap"@en', + type: 'http://www.w3.org/2002/07/owl#Ontology' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/HdMap', + label: '"class definition for hdmap"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Content', + label: '"class definition for Content"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/DataSource', + label: '"class definition for DataSource"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Format', + label: '"class definition for Format"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Quality', + label: '"class definition for Quality"', + type: 'http://www.w3.org/2002/07/owl#Class' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Quantity', + label: '"class definition for Quantity"', + type: 'http://www.w3.org/2002/07/owl#Class' + } + ], + links: [ + { + source: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/HdMap', + target: 'https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#DataResource' + } + ], + relatedShapes: [ + { + shaclShapeId: '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/HdMapShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/general', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/GeneralShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/general' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/format', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/FormatShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/format' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/content', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/ContentShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/content' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/quantity', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/QuantityShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '4' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/quantity' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/quality', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/QualityShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '5' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/quality' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/dataSource', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/DataSourceShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '6' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/dataSource' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/georeference', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/georeference/GeoreferenceShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '7' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/georeference' + } + ] + } + ], + nodes: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/GeneralShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/FormatShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/ContentShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/QuantityShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/QualityShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/DataSourceShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/georeference/GeoreferenceShape' + ], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/HdMap' + ] + }, + { + shaclShapeId: '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/ContentShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/roadTypes', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'roadTypes' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Covered/used road types, defined over ODR element t_road_type, see ODR spec section 8.3' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '[Motorway, Rural]' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'Bicycle', + 'LowSpeed', + 'Motorway', + 'Pedestrian', + 'Rural', + 'Town', + 'TownArterial', + 'TownCollector', + 'TownExpressway', + 'TownLocal', + 'TownPlayStreet', + 'TownPrivate', + 'Unknown' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of roadTypes failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/roadTypes' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/laneTypes', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'laneTypes' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Covered lane types, see ODR spec section 9.5.3.' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'shoulder, curb, ...' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'biking', + 'border', + 'connectingRamp', + 'curb', + 'driving', + 'entry', + 'exit', + 'median', + 'none', + 'offRamp', + 'onRamp', + 'parking', + 'restricted', + 'shoulder', + 'slipLane', + 'stop', + 'walking' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of laneTypes failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/laneTypes' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/levelOfDetail', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'levelOfDetail' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Covered object classes, see ODR spec section 11' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'trees, street lamps, road patches...' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'barrier', + 'bike', + 'building', + 'bus', + 'car', + 'crosswalk', + 'gantry', + 'motorbike' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of levelOfDetail failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/levelOfDetail' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/trafficDirection', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'trafficDirection' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Traffic direction, i.e. right-hand or left-hand traffic' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'right-hand traffic' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'left-hand', + 'right-hand' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of trafficDirection failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/trafficDirection' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Content' + ] + }, + { + shaclShapeId: '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/DataSourceShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/measurementSystem', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'measurementSystem' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Main acquisition device' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '3DMS system, Trimble xyz, Riegl xyz' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of measurementSystem failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/measurementSystem' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/usedDataSources', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'usedDataSources' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Basic data for the creation of the map' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'scanner, camera, osm network, aerial images, ...' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of usedDataSources failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/usedDataSources' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/DataSource' + ] + }, + { + shaclShapeId: '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/FormatShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/version', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'version' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Version of data format' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '1.5' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of version failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/version' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/formatType', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'type' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Format type definition' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'ASAM OpenDRIVE Road5 Lanelet road2sim roadXML Shape' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'ASAM OpenDRIVE', + 'Lanelet', + 'Road5', + 'Shape', + 'road2sim', + 'roadXML' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of type failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/formatType' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Format' + ] + }, + { + shaclShapeId: '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/QualityShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracySignals', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'accuracySignals' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Accuracy of traffic relevant objects, signs and signals' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0.1' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of accuracySignals failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracySignals' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracyObjects', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'accuracyObjects' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Accuracy of objects in the traffic space, which do not directly affect the traffic' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0.1' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of accuracyObjects failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '4' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracyObjects' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracyLaneModelHeight', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'accuracyLaneModelHeight' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Accuracy lane modell height' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0.1' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of accuracyLaneModelHeight failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracyLaneModelHeight' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/precision', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'precision' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Precision of measured road network (relative accuracy)' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0.01' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of precision failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/precision' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracyLaneModel2d', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'accuracyLaneModel2d' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Accuracy of lane modell 2d' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0.1' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of accuracyLaneModel2d failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/accuracyLaneModel2d' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Quality' + ] + }, + { + shaclShapeId: '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/QuantityShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberIntersections', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'numberIntersections' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Sum of all junctions defined in the map, see ODR spec section 10' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '5' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#unsignedInt' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of numberIntersections failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberIntersections' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberTrafficLights', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'numberTrafficLights' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Sum of all traffic lights defined in the map, see ODR spec section 12' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#unsignedInt' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of numberTrafficLights failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberTrafficLights' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/rangeOfModeling', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'rangeOfModeling' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'How wide is the area beyond the traffic space modeled' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '20' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of rangeOfModeling failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '8' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/rangeOfModeling' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberOutlines', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'numberOutlines' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Sum of all objects outlines in the map, see ODR spec section 11.2' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '100' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#unsignedInt' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of numberOutlines failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '6' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberOutlines' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/speedLimit', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'speedLimit' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Range of speed limits defined in the map, see ODR spec section 9.5.5. ' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '[10,50] km/h' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of speedLimit failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Range2DShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '7' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/speedLimit' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/length', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'length' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Road network length in km, sum over road length; see ODR spec section 8' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '40.0' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of length failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/length' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/elevationRange', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'elevationRange' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Difference of max and mit elevation, extraction from openDrive Element t_road_elevationprofile_elevation, see section 8.4' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '2.22' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of elevationRange failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/elevationRange' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberObjects', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'numberObjects' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Sum of all objects in the map, see ODR spec section 11' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '200' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#unsignedInt' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of numberObjects failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '5' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberObjects' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberTrafficSigns', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'numberTrafficSigns' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Sum of all traffic signs in the map, see ODR spec section 12' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '155' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#unsignedInt' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of numberTrafficSigns failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '4' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/numberTrafficSigns' + } + ] + } + ], + nodes: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/Range2DShape' + ], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/hdmap/Quantity' + ] + } + ] + }, + { + subject: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/', + contributors: [ + 'Mirco Nierenz (TG)' + ], + description: 'ontology definition for environment-model', + version: '0.1', + nodes: [ + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/', + label: '"ontology definition for environment-model"@en', + type: 'http://www.w3.org/2002/07/owl#Ontology' + }, + { + id: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/EnvironmentModel', + label: '"class definition for environment-model"', + type: 'http://www.w3.org/2002/07/owl#Class' + } + ], + links: [ + { + source: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/EnvironmentModel', + target: 'https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#DataResource' + } + ], + relatedShapes: [ + { + shaclShapeId: '9ff53e73d6e55bb1c9838240d1eb758dcf56d62ced1b0c1fcc4cf6aa022f996c', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/EnvironmentModelShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/general', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/GeneralShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/general' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/quantity', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/QuantityShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/quantity' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/quality', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/QualityShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/quality' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/project', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/ProjectShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '4' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/project' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/format', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/FormatShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '5' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/format' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/georeference', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#node', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/georeference/GeoreferenceShape' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '6' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/georeference' + } + ] + } + ], + nodes: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/general/GeneralShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/QuantityShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/QualityShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/ProjectShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/FormatShape', + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/georeference/GeoreferenceShape' + ], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/EnvironmentModel' + ] + }, + { + shaclShapeId: '9ff53e73d6e55bb1c9838240d1eb758dcf56d62ced1b0c1fcc4cf6aa022f996c', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/FormatShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/formatType', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'type' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Data type definition' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'Unreal DataSmith, Autodesk FBX, OpenSceneGraph, GLTF' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'Autodesk FBX', + 'GLTF', + 'OpenSceneGraph', + 'Unreal DataSmith' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of type failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/formatType' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/version', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'version' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Version of data format' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'SDK 4.25' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of version failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/version' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/Format' + ] + }, + { + shaclShapeId: '9ff53e73d6e55bb1c9838240d1eb758dcf56d62ced1b0c1fcc4cf6aa022f996c', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/ProjectShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/creationVersion', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'creationVersion' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Tool for the creation of the data' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '7.7' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of creationVersion failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '4' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/creationVersion' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/creationSource', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'creationSource' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Tool for the creation of the data' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'Trian3DBuilder' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of creationSource failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '3' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/creationSource' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/softwareName', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'softwareName' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Name of the graphics engine' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'Unreal' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of softwareName failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/softwareName' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/softwareVendor', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'softwareVendor' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Name of software vendor' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'Epic Games' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of softwareVendor failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/softwareVendor' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/softwareVersion', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'version' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Version of graphics engine' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '4.27' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of version failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/softwareVersion' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/Project' + ] + }, + { + shaclShapeId: '9ff53e73d6e55bb1c9838240d1eb758dcf56d62ced1b0c1fcc4cf6aa022f996c', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/QualityShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/features', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'features' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Description of quality features' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'PBR' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of features failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/features' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/detailLevel', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'detailLevel' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Category of the level of detail (High - highest level of detail with additional object enrichment, Medium - directly from data sources, with environment, Low - topological representation).' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: 'high' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#string' + }, + { + type: 'http://www.w3.org/ns/shacl#in', + value: [ + 'High', + 'Medium', + 'Low' + ] + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of detailLevel failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/detailLevel' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/textureResolution', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'textureResolution' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Real texture resolution in meter (max?)' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '0.1 m' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#float' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of textureResolution failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#minCount', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/textureResolution' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/Quality' + ] + }, + { + shaclShapeId: '9ff53e73d6e55bb1c9838240d1eb758dcf56d62ced1b0c1fcc4cf6aa022f996c', + shaclShapeName: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/QuantityShape', + properties: [ + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/geometryCount', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'geometryCount' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Total number of all geoemtries(all triangles with a material assignment), instances are considered only once' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '12000' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#int' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of geometryCount failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '2' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/geometryCount' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/triangleCount', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'triangleCount' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Total number of all triangles, instances are considered only once' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '16000000' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#int' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of triangleCount failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/triangleCount' + } + ] + }, + { + propertyId: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/textureMaterialCount', + propertyValues: [ + { + type: 'http://www.w3.org/ns/shacl#name', + value: 'textureMaterialCount' + }, + { + type: 'http://www.w3.org/ns/shacl#description', + value: 'Number of textures' + }, + { + type: 'http://www.w3.org/2004/02/skos/core#example', + value: '179' + }, + { + type: 'http://www.w3.org/ns/shacl#datatype', + value: 'http://www.w3.org/2001/XMLSchema#unsignedInt' + }, + { + type: 'http://www.w3.org/ns/shacl#maxCount', + value: '1' + }, + { + type: 'http://www.w3.org/ns/shacl#message', + value: 'Validation of textureMaterialCount failed!' + }, + { + type: 'http://www.w3.org/ns/shacl#order', + value: '0' + }, + { + type: 'http://www.w3.org/ns/shacl#path', + value: 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/textureMaterialCount' + } + ] + } + ], + nodes: [], + targetClasses: [ + 'https://github.com/GAIA-X4PLC-AAD/ontology-management-base/tree/main/environment-model/Quantity' + ] + } + ] + } +] as Ontology[]; diff --git a/tests/components/resources/ResourcesSearchPage.test.tsx b/tests/components/resources/ResourcesSearchPage.test.tsx new file mode 100644 index 00000000..904abf0b --- /dev/null +++ b/tests/components/resources/ResourcesSearchPage.test.tsx @@ -0,0 +1,81 @@ +import { render, within } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import React, { ReactNode } from 'react'; +import { MemoryRouter } from 'react-router'; + +import ResourceSearchPage from '../../../src/components/resources/ResourceSearchPage'; + +import { normal_render } from './__fixtures__/useResources_ResourceSearchPage'; + +// Mock: useResources +const useResources = jest.fn(); +jest.mock('../../../src/components/resources/hooks/useResources', () => ({ + useResources: () => useResources() +})) +const withRouter = (component: ReactNode) => (<> + + {component} + +); + +describe('ResourcesSearchPage', () => { + it('renders all resources and filter assets correctly', () => { + useResources.mockReturnValue(normal_render); + + // Text in the top header bar + const { getByRole, getByTestId, } = render(withRouter()); + expect(getByRole('heading', { name: /left-menu.resources \(2 dashboard.results\)/i })).toBeInTheDocument; + + // HdMap Card + const hdMapCard = getByTestId(/Card:.*:HdMap/); + + const hdMapCardLabel = within(hdMapCard).getByRole('heading', { name: /^HdMap$/i }); + expect(hdMapCardLabel).toBeInTheDocument + expect(hdMapCardLabel.textContent).toEqual('HdMap'); + + const hdMapCardDetailButton = within(hdMapCard).getByRole('button', { name: /details.more-details/i }); + expect(hdMapCardDetailButton).toBeInTheDocument; + + // EnvironmentModel Card + const environmentModelCard = getByTestId(/Card:.*:EnvironmentModel/); + + const environmentModelCardLabel = within(environmentModelCard).getByRole('heading', { name: /^EnvironmentModel$/i }); + expect(environmentModelCardLabel).toBeInTheDocument + expect(environmentModelCardLabel.textContent).toEqual('EnvironmentModel'); + + const environmentModelCardDetailButton = within(environmentModelCard).getByRole('button', { name: /details.more-details/i }); + expect(environmentModelCardDetailButton).toBeInTheDocument; + + // Type filter section + const typeFilterSection = getByRole('heading', { name: /Type/i }); + expect(typeFilterSection).toBeInTheDocument; + + const hdMapTypeFilterCheckbox = within(typeFilterSection.parentElement).getByRole('checkbox', { name: /HdMap/i }); + expect(hdMapTypeFilterCheckbox).toBeInTheDocument + expect(hdMapTypeFilterCheckbox).toHaveAttribute('checked') + expect(hdMapTypeFilterCheckbox).not.toHaveAttribute('disabled') + + const environmentModelTypeFilterCheckbox = within(typeFilterSection.parentElement).getByRole('checkbox', { name: /EnvironmentModel/i }); + expect(environmentModelTypeFilterCheckbox).toBeInTheDocument + expect(environmentModelTypeFilterCheckbox).not.toHaveAttribute('checked') + expect(environmentModelTypeFilterCheckbox).toHaveAttribute('disabled') + + // Format filter section + const formatFilterSection = getByRole('heading', { name: /Format/i }); + expect(formatFilterSection).toBeInTheDocument; + + const asamOpenDriveFormatFilterCheckbox = within(formatFilterSection.parentElement).getByRole('checkbox', { name: /ASAM OpenDRIVE/i }); + expect(asamOpenDriveFormatFilterCheckbox).toBeInTheDocument + expect(asamOpenDriveFormatFilterCheckbox).toHaveAttribute('checked') + expect(asamOpenDriveFormatFilterCheckbox).not.toHaveAttribute('disabled') + + // Vendor filter section + const vendorFilterSection = getByRole('heading', { name: /Vendor/i }); + expect(vendorFilterSection).toBeInTheDocument; + + const msgSystemsAgVendorFilterCheckbox = within(vendorFilterSection.parentElement).getByRole('checkbox', { name: /msg systems ag/i }); + expect(msgSystemsAgVendorFilterCheckbox).toBeInTheDocument + expect(msgSystemsAgVendorFilterCheckbox).not.toHaveAttribute('checked') + expect(msgSystemsAgVendorFilterCheckbox).not.toHaveAttribute('disabled') + }) +}) diff --git a/tests/components/resources/__fixtures__/useResources_ResourceSearchPage.ts b/tests/components/resources/__fixtures__/useResources_ResourceSearchPage.ts new file mode 100644 index 00000000..45e9c0bf --- /dev/null +++ b/tests/components/resources/__fixtures__/useResources_ResourceSearchPage.ts @@ -0,0 +1,65 @@ +import { Asset } from '../../../../src/components/resources/helpers/resourceFilterHelper'; +import { ResourcesSearchPageContentType } from '../../../../src/components/resources/hooks/useResources'; +import { Resource } from '../../../../src/types/resources.model'; + +export const normal_render = { + resources: [ + { + uri: 'did:resource-HdMap', + name: 'HdMap', + format: 'ASAM OpenDRIVE', + vendor: 'msg systems ag', + labels: ['HdMap'], + description: 'HdMap description', + claimsGraphUri: ['https://resources.gx/HdMap'] + }, + { + uri: 'did:resource-EnvironmentModel', + name: 'EnvironmentModel', + format: null, + vendor: null, + labels: ['EnvironmentModel'], + description: 'EnvironmentModel description', + claimsGraphUri: ['https://resources.gx/EnvironmentModel'] + } + ] as Resource[], + viewContentType: 'SHOW_RESOURCES' as ResourcesSearchPageContentType, + typeAssets: [ + { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: true, + disabled: false + }, + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: false, + disabled: true + } + ] as Asset[], + formatAssets: [ + { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: true, + disabled: false + } + ] as Asset[], + vendorAssets: [ + { + id: 'msg systems ag', + type: 'vendorAssets', + label: 'msg systems ag', + value: false, + disabled: false + } + ] as Asset[], + updateSearchText: jest.fn(() => { + }), + updateFilterAsset: jest.fn(() => { + }) +}; diff --git a/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json b/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json new file mode 100644 index 00000000..3b52311d --- /dev/null +++ b/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json @@ -0,0 +1,80 @@ +{ + "totalCount": 3, + "items": [ + { + "vendor": "msg systems ag", + "format": "ASAM OpenDRIVE", + "properties": { + "license": "Apache-2.0", + "expirationDateTime": "2025-05-23T07:23:25", + "copyrightOwnedBy": "https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json", + "claimsGraphUri": [ + "https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114", + "did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8" + ], + "test": "Wird das zusammengemergt?", + "containsPII": "false", + "name": "Generated Data Resource", + "description": "Generated description.", + "obsoleteDateTime": "2025-05-23T07:23:25", + "uri": "did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8", + "policy": "package access_control default allow = false allow { input.method == \"GET\" input.path == \"/public\" } allow { input.method == \"POST\" input.path == \"/private\" input.user.role == \"admin\" }" + }, + "labels": [ + "Resource", + "DataResource", + "HdMap" + ] + }, + { + "vendor": "msg systems ag", + "format": null, + "properties": { + "license": "Apache-2.0", + "expirationDateTime": "2025-06-17T11:37:14", + "copyrightOwnedBy": "https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json", + "claimsGraphUri": [ + "https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a" + ], + "containsPII": "false", + "name": "Generated Data Resource", + "description": "Generated description.", + "obsoleteDateTime": "2025-06-17T11:37:14", + "uri": "https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a", + "policy": "package access_control default allow = false allow { input.method == \"GET\" input.path == \"/public\" } allow { input.method == \"POST\" input.path == \"/private\" input.user.role == \"admin\" }" + }, + "labels": [ + "Resource", + "EnvironmentModel", + "DataResource" + ] + }, + { + "vendor": "msg systems ag", + "format": null, + "properties": { + "license": "Apache-2.0", + "expirationDateTime": "2025-04-08T14:25:58", + "copyrightOwnedBy": "https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json", + "claimsGraphUri": [ + "https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f" + ], + "containsPII": "false", + "name": "Generated Data Resource", + "description": "Generated description.", + "obsoleteDateTime": "2025-04-08T14:25:58", + "uri": "https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "policy": "package access_control default allow = false allow { input.method == \"GET\" input.path == \"/public\" } allow { input.method == \"POST\" input.path == \"/private\" input.user.role == \"admin\" }" + }, + "labels": [ + "Resource", + "EnvironmentModel", + "DataResource", + "General" + ] + } + ] +} diff --git a/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts b/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts new file mode 100644 index 00000000..75a4bb9a --- /dev/null +++ b/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts @@ -0,0 +1,684 @@ +import { ResourceFilterState } from '../../../../../src/components/resources/helpers/resourceFilterReducer'; + +export const initiallyLoaded_ResourceFilterState = { + filteredResources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'Resource', + 'DataResource', + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + }, + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-06-17T11:37:14', + format: null, + labels: [ + 'Resource', + 'EnvironmentModel', + 'DataResource' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-06-17T11:37:14', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', + vendor: 'msg systems ag' + }, + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-04-08T14:25:58', + format: null, + labels: [ + 'Resource', + 'EnvironmentModel', + 'DataResource', + 'General' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-04-08T14:25:58', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + vendor: 'msg systems ag' + } + ], + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + searchText: '', + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: false + } + ] +} as ResourceFilterState; + +export const filteredBy_searchText_HdMap_ResourceFilterState = { + filteredResources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'Resource', + 'DataResource', + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + } + ], + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + searchText: 'HdMap', + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: false + } + ] +} as ResourceFilterState; + +export const filteredBy_typeFilter_HdMap_ResourceFilterState = { + filteredResources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'Resource', + 'DataResource', + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + } + ], + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + searchText: '', + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: true + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: false + } + ] +} as ResourceFilterState; + +export const filteredBy_formatFilter_ASAMOpenDrive_ResourceFilterState = { + filteredResources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'Resource', + 'DataResource', + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + } + ], + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: true + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + searchText: '', + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: false + } + ] +} as ResourceFilterState; + +export const filteredBy_vendorFilter_MsgSystemsAG_ResourceFilterState = { + filteredResources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'Resource', + 'DataResource', + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + } + ], + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + searchText: '', + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: true + }, + { + disabled: false, + id: 'other', + label: 'other', + type: 'vendorAssets', + value: false + } + ] +} as ResourceFilterState; diff --git a/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts b/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts new file mode 100644 index 00000000..49511fa8 --- /dev/null +++ b/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts @@ -0,0 +1,58 @@ +export const resources_HdMap_EnvironmentModel_x2 = [ + { + vendor: 'msg systems ag', + format: 'ASAM OpenDRIVE', + labels: ['Resource', 'DataResource', 'HdMap'], + license: 'Apache-2.0', + expirationDateTime: '2025-05-23T07:23:25', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + test: 'Wird das zusammengemergt?', + containsPII: 'false', + name: 'Generated Data Resource', + description: 'Generated description.', + obsoleteDateTime: '2025-05-23T07:23:25', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }' + }, + { + vendor: 'msg systems ag', + format: null, + labels: ['Resource', 'EnvironmentModel', 'DataResource'], + license: 'Apache-2.0', + expirationDateTime: '2025-06-17T11:37:14', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a', + ], + containsPII: 'false', + name: 'Generated Data Resource', + description: 'Generated description.', + obsoleteDateTime: '2025-06-17T11:37:14', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }' + }, + { + vendor: 'msg systems ag', + format: null, + labels: ['Resource', 'EnvironmentModel', 'DataResource', 'General'], + license: 'Apache-2.0', + expirationDateTime: '2025-04-08T14:25:58', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' + ], + containsPII: 'false', + name: 'Generated Data Resource', + description: 'Generated description.', + obsoleteDateTime: '2025-04-08T14:25:58', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }' + } +]; diff --git a/tests/components/resources/helpers/resourceDataFlow.test.ts b/tests/components/resources/helpers/resourceDataFlow.test.ts new file mode 100644 index 00000000..f32935e6 --- /dev/null +++ b/tests/components/resources/helpers/resourceDataFlow.test.ts @@ -0,0 +1,37 @@ +import { loadResources } from '../../../../src/components/resources/helpers/resourceDataFlow'; + +import resources from './__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json'; +import { + resources_HdMap_EnvironmentModel_x2 as expectedResources +} from './__fixtures__/resources_HdMap_EnvironmentModel_x2'; + +const errorLog = jest.fn(); +const getAllResources = jest.fn(); + +jest.mock('../../../../src/services/cypherQueryApiService', () => ({ + CypherQueryApiService: { + getAllResources: (resourceTypes: string[]) => getAllResources(resourceTypes), + } +})) + +describe('loadResources', () => { + console.error = errorLog + console.debug = () => jest.fn(); // Disable debug logging + + const resourceTypes = ['Georeference', 'HdMap', 'EnvironmentModel', 'OSITrace']; + + it('the backend Data will be transformed to a Resource array', async () => { + getAllResources.mockResolvedValueOnce(resources); + + const result = await loadResources(resourceTypes); + expect(result).toEqual(expectedResources); + }) + + it('logs and throws further an error', async () => { + const error = new Error('Some Backend Error'); + getAllResources.mockRejectedValueOnce(error); + + await expect(() => loadResources(resourceTypes)).rejects.toThrow('Some Backend Error'); + expect(errorLog).toBeCalledWith('Error fetching resources:', error); + }) +}) diff --git a/tests/components/resources/helpers/resourceFilterHelper.test.ts b/tests/components/resources/helpers/resourceFilterHelper.test.ts new file mode 100644 index 00000000..d32f1c4c --- /dev/null +++ b/tests/components/resources/helpers/resourceFilterHelper.test.ts @@ -0,0 +1,692 @@ +import { + Asset, + calculateResourceFiltersAssetState, + createFormatAssets, + createTypeAssets, + createVendorAssets, + getAllFormats, + getAllLabels, + getResourceVendors, + getSelectedAssets +} from '../../../../src/components/resources/helpers/resourceFilterHelper'; +import { + initialResourceFilterState, + resourceFilterReducer, + ResourceFilterState, + setResourceFilterAssetsAction, + setSearchTextAction, + updateFilterAssetAction +} from '../../../../src/components/resources/helpers/resourceFilterReducer'; +import { + ontologies_General_HdMap_EnvironmentModel +} from '../../../__fixtures__/ontologies_General_HdMap_EnvironmentModel'; + +import { + filteredBy_formatFilter_ASAMOpenDrive_ResourceFilterState, + filteredBy_searchText_HdMap_ResourceFilterState, + filteredBy_typeFilter_HdMap_ResourceFilterState, + filteredBy_vendorFilter_MsgSystemsAG_ResourceFilterState, + initiallyLoaded_ResourceFilterState +} from './__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2'; +import { resources_HdMap_EnvironmentModel_x2 } from './__fixtures__/resources_HdMap_EnvironmentModel_x2'; + +describe('Reducer', () => { + it('generates the "initiallyLoadedResourceFilterState" when "setResourceFilterAssetsAction" created from ' + + '"ontologies_General_HdMap_EnvironmentModel" and "resources_HdMap_EnvironmentModel_x2" ' + + 'and is executed on "initialResourceFilterStatus"', () => { + const action = setResourceFilterAssetsAction( + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + ); + const nextState = resourceFilterReducer(initialResourceFilterState, action); + + expect(nextState.filteredResources.length).toEqual(3); + expect(nextState).toEqual(initiallyLoaded_ResourceFilterState); + }) + + it('generates the "filteredBy_searchText_HdMap_ResourceFilterState" when "setSearchTextAction" created from ' + + '"ontologies_General_HdMap_EnvironmentModel" and "resources_HdMap_EnvironmentModel_x2" ' + + 'and is executed on "initialResourceFilterStatus"', () => { + const searchText = 'HdMap'; + const action = setSearchTextAction( + searchText, + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + ); + const nextState = resourceFilterReducer(initialResourceFilterState, action); + + expect(nextState.filteredResources.length).toEqual(1); + expect(nextState).toEqual(filteredBy_searchText_HdMap_ResourceFilterState); + }) + + it('generates the "filteredBy_typeAssets_HdMap_ResourceFilterState" when "updateFilterAssetAction" created from ' + + 'selected type asset for which the filtering is desired ' + + 'and "ontologies_General_HdMap_EnvironmentModel" and "resources_HdMap_EnvironmentModel_x2" ' + + 'and is executed on "initiallyLoaded_ResourceFilterState"', () => { + const hdMapTypeAsset = { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: true, + disabled: false + } as Asset; + const action = updateFilterAssetAction( + hdMapTypeAsset, + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + ); + const nextState = resourceFilterReducer(initiallyLoaded_ResourceFilterState, action); + + expect(nextState.filteredResources.length).toEqual(1); + expect(nextState).toEqual(filteredBy_typeFilter_HdMap_ResourceFilterState); + }) + + it('generates the "filteredBy_formatAssets_HdMap_ResourceFilterState" when "updateFilterAssetAction" created from ' + + 'selected format asset for which the filtering is desired ' + + 'and "ontologies_General_HdMap_EnvironmentModel" and "resources_HdMap_EnvironmentModel_x2" ' + + 'and is executed on "initiallyLoaded_ResourceFilterState"', () => { + const asamOpenDriveFormatAsset = { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: true, + disabled: false + } as Asset; + const action = updateFilterAssetAction( + asamOpenDriveFormatAsset, + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + ); + const nextState = resourceFilterReducer(initiallyLoaded_ResourceFilterState, action); + + expect(nextState.filteredResources.length).toEqual(1); + expect(nextState).toEqual(filteredBy_formatFilter_ASAMOpenDrive_ResourceFilterState); + }) + + it('generates the "filteredBy_vendorAssets_MsgSystemsAG_ResourceFilterState" when "updateFilterAssetAction" created' + + ' from selected format asset for which the filtering is desired ' + + 'and "ontologies_General_HdMap_EnvironmentModel" and "resources_HdMap_EnvironmentModel_x2" ' + + 'and is executed on "initiallyLoaded_ResourceFilterState"', () => { + const msgSystemsAGVendorAsset = { + id: 'msg systems ag', + type: 'vendorAssets', + label: 'msg systems ag', + value: true, + disabled: false + } as Asset; + const resources_msgSystemsAG_x1_vendor = resources_HdMap_EnvironmentModel_x2 + .map((resource, index) => !index ? resource : { ...resource, vendor: 'other' }) + const action = updateFilterAssetAction( + msgSystemsAGVendorAsset, + ontologies_General_HdMap_EnvironmentModel, + resources_msgSystemsAG_x1_vendor + ); + const nextState = resourceFilterReducer(initiallyLoaded_ResourceFilterState, action); + + expect(nextState.filteredResources.length).toEqual(1); + expect(nextState).toEqual(filteredBy_vendorFilter_MsgSystemsAG_ResourceFilterState); + }) + + it('returns "initialResourceFilterState" if an unknown action is passed in', () => { + const action = { type: 'UNKNOWN_ACTION' }; + const nextState = resourceFilterReducer(initialResourceFilterState, action); + + expect(nextState).toEqual(initialResourceFilterState); + }) +}) + +describe('createTypeAssets', () => { + it('Creates a list of types from a list of type ids, marks disabled if not present in any of the resources' + + ' passed in', () => { + const result = createTypeAssets( + ['HdMap', 'EnvironmentModel'], + [] + ); + + expect(result.length).toEqual(2); + expect(result).toEqual(expect.arrayContaining([ + expect.objectContaining({ + id: 'HdMap', + value: false, + disabled: true + }), + expect.objectContaining({ + id: 'EnvironmentModel', + value: false, + disabled: true + }), + ])) + }) + + it('Marks enabled if it is present in the resources', () => { + const result = createTypeAssets( + ['HdMap', 'EnvironmentModel', 'Other'], + resources_HdMap_EnvironmentModel_x2 + ); + + expect(result.length).toEqual(3); + expect(result).toEqual([ + expect.objectContaining({ + id: 'HdMap', + value: false, + disabled: false + }), + expect.objectContaining({ + id: 'EnvironmentModel', + value: false, + disabled: false + }), + expect.objectContaining({ + id: 'Other', + value: false, + disabled: true + }) + ]) + }) +}) + +describe('getAllLabels', () => { + it('returns all available resource types present in the resources list', () => { + const result = getAllLabels(resources_HdMap_EnvironmentModel_x2); + expect(result).toEqual(new Set(['DataResource', 'EnvironmentModel', 'General', 'HdMap', 'Resource'])); + }) +}) + +describe('createFormatAssets', () => { + it('Creates a list of formats from a list of format ids, marks disabled if not present in any of the resources' + + ' passed in, marks unselected if it is not selected also in the "prevFormatAssets"', () => { + const result = createFormatAssets( + ['Autodesk FBX', 'GLTF', 'OpenSceneGraph', 'Unreal DataSmith', 'ASAM OSI GroundTruth', + 'ASAM OSI SensorView', 'ASAM OSI SensorData', 'ASAM OpenDRIVE', 'Lanelet', 'Road5', 'Shape', + 'road2sim', 'roadXML'], + [], + [] + ); + + expect(result.length).toEqual(13); + expect(result).toEqual(expect.arrayContaining([ + expect.objectContaining({ + id: 'ASAM OpenDRIVE', + value: false, + disabled: true + }), + expect.objectContaining({ + id: 'Autodesk FBX', + value: false, + disabled: true + }), + ])) + }) + + it('Marks enabled if it is present in the resources', () => { + const result = createFormatAssets( + ['Autodesk FBX', 'GLTF', 'OpenSceneGraph', 'Unreal DataSmith', 'ASAM OSI GroundTruth', + 'ASAM OSI SensorView', 'ASAM OSI SensorData', 'ASAM OpenDRIVE', 'Lanelet', 'Road5', 'Shape', + 'road2sim', 'roadXML'], + [], + resources_HdMap_EnvironmentModel_x2 + ); + + expect(result.length).toEqual(13); + expect(result).toEqual(expect.arrayContaining([ + expect.objectContaining({ + id: 'ASAM OpenDRIVE', + value: false, + disabled: false + }), + expect.objectContaining({ + id: 'Autodesk FBX', + value: false, + disabled: true + }), + ])) + }) + + it('Marks selected if it was selected also in the "prevFormatAssets"', () => { + const result = createFormatAssets( + ['Autodesk FBX', 'GLTF', 'OpenSceneGraph', 'Unreal DataSmith', 'ASAM OSI GroundTruth', + 'ASAM OSI SensorView', 'ASAM OSI SensorData', 'ASAM OpenDRIVE', 'Lanelet', 'Road5', 'Shape', + 'road2sim', 'roadXML'], + [ + { + id: 'ASAM OpenDRIVE', + value: true + } + ] as Asset[], + []); + + expect(result.length).toEqual(13); + expect(result).toEqual(expect.arrayContaining([ + expect.objectContaining({ + id: 'ASAM OpenDRIVE', + value: true, + disabled: true + }), + expect.objectContaining({ + id: 'Autodesk FBX', + value: false, + disabled: true + }), + ])) + }) +}) + +describe('getAllFormats', () => { + it('returns all available formats present in the resources list', () => { + const result = getAllFormats(resources_HdMap_EnvironmentModel_x2); + + expect(result).toEqual(new Set(['ASAM OpenDRIVE'])); + }) +}) + +describe('createVendorAssets', () => { + it('Creates a list of vendors from a list of vendor ids, marks disabled if not present in any of the resources' + + ' passed in, marks unselected if it is not selected also in the "prevVendorAssets"', () => { + const result = createVendorAssets(['msg systems ag', 'other'], [], []); + expect(result).toEqual([ + expect.objectContaining({ + id: 'msg systems ag', + value: false, + disabled: true + }), + expect.objectContaining({ + id: 'other', + value: false, + disabled: true + }), + ]) + }) + + it('Marks enabled if it is present in the resources', () => { + const result = createVendorAssets(['msg systems ag', 'other'], [], resources_HdMap_EnvironmentModel_x2); + expect(result).toEqual([ + expect.objectContaining({ + id: 'msg systems ag', + value: false, + disabled: false + }), + expect.objectContaining({ + id: 'other', + value: false, + disabled: true + }), + ]) + }) + + it('Marks selected if it was selected also in the "prevVendorAssets"', () => { + const result = createVendorAssets(['msg systems ag', 'other'], [ + { + id: 'msg systems ag', + value: true + } + ] as Asset[], []); + + expect(result).toEqual([ + expect.objectContaining({ + id: 'msg systems ag', + value: true, + disabled: true + }), + expect.objectContaining({ + id: 'other', + value: false, + disabled: true + }), + ]) + }) +}) + +describe('getResourceVendors', () => { + it('returns the ids of all vendors present in the resources', () => { + const vendors = getResourceVendors(resources_HdMap_EnvironmentModel_x2 + .map((resource, index) => index === 0 + ? { ...resource, vendor: 'msg systems ag' } + : { ...resource, vendor: 'other' })) + expect(vendors).toEqual(new Set(['msg systems ag', 'other'])); + }) +}) + +describe('getSelectedAssets', () => { + console.debug = jest.fn(); // Disable debug logging + + it('Only assets which are not disabled and with value equal true are selected', () => { + const assets = [ + { + id: 'General', + disabled: false, + value: false, + }, + { + id: 'EnvironmentModel', + disabled: true, + value: true + }, + { + id: 'HdMap', + disabled: false, + value: true + } + ] as Asset[]; + + const result = getSelectedAssets(assets); + expect(result).toEqual(['HdMap']) + }) + + it('returns "NOTHING" if nothing is selected and not empty list.', () => { + const assets = [ + { + id: 'General', + disabled: false, + value: false, + }, + { + id: 'EnvironmentModel', + disabled: true, + value: true + }, + { + id: 'HdMap', + disabled: true, + value: true + } + ] as Asset[]; + + const result = getSelectedAssets(assets); + expect(result).toEqual('NOTHING'); + }) +}) + +describe('calculateResourceFiltersAssetState', () => { + + it('With no selected filter passed in, the resource list will not be filtered,' + + 'the assets are created from ontologies.', () => { + const result = calculateResourceFiltersAssetState( + ontologies_General_HdMap_EnvironmentModel, + [...resources_HdMap_EnvironmentModel_x2], + initialResourceFilterState + ) + + expect(result.filteredResources).toEqual(resources_HdMap_EnvironmentModel_x2); + + expect(result.typeAssets).toEqual([ + { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: false, + disabled: false + }, + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: false, + disabled: false + } + ]); + + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets).toEqual(expect.arrayContaining([ + { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: false, + disabled: false + }, + ])); + + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) + expect(result.vendorAssets).toEqual([ + expect.objectContaining({ id: 'msg systems ag', disabled: false }) + ]); + }) + + it('Pass in "HdMap" as previously select, will not affect the disabled state of the other asset types,' + + 'it will also filter the resources list', () => { + const result = calculateResourceFiltersAssetState( + ontologies_General_HdMap_EnvironmentModel, + [...resources_HdMap_EnvironmentModel_x2], + { + filteredResources: [], + typeAssets: [ + { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: true, + disabled: false + }, + ] as Asset[], + formatAssets: [], + vendorAssets: [], + } as ResourceFilterState + ) + + expect(result.filteredResources.length).toEqual(1); + expect(result.filteredResources).toEqual([ + expect.objectContaining({ + labels: ['Resource', 'DataResource', 'HdMap'] + }) + ]); + + expect(result.typeAssets.filter(asset => !asset.value).length).toEqual(1); + expect(result.typeAssets).toEqual(expect.arrayContaining([ + { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: true, + disabled: false + } + ])); + + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets).toEqual(expect.arrayContaining([ + { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: false, + disabled: false + }, + ])); + + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) + expect(result.vendorAssets).toEqual([ + expect.objectContaining({ id: 'msg systems ag', disabled: false }) + ]); + }) + + it('Pass in "EnvironmentModel" as previously select, will affect the disabled state of the other asset types,' + + 'it will also filter the resources list', () => { + const result = calculateResourceFiltersAssetState( + ontologies_General_HdMap_EnvironmentModel, + [...resources_HdMap_EnvironmentModel_x2], + { + filteredResources: [], + typeAssets: [ + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: true, + disabled: false + }, + ] as Asset[], + formatAssets: [], + vendorAssets: [], + } as ResourceFilterState + ) + + expect(result.filteredResources.length).toEqual(2); + expect(result.filteredResources).toEqual([ + expect.objectContaining({ + labels: expect.arrayContaining(['EnvironmentModel']) + }), + expect.objectContaining({ + labels: expect.arrayContaining(['EnvironmentModel']) + }) + ]); + + expect(result.typeAssets.filter(asset => !asset.value).length).toEqual(1); + expect(result.typeAssets).toEqual(expect.arrayContaining([ + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: true, + disabled: false + } + ])); + + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(0); + + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) + expect(result.vendorAssets).toEqual([ + expect.objectContaining({ id: 'msg systems ag', disabled: false }) + ]); + }) + + it('Pass in "EnvironmentModel" type and "ASAM OpenDRIVE" format filters as previously select, will affect the' + + ' disabled state of the other asset types, it will also filter the resources list', () => { + const result = calculateResourceFiltersAssetState( + ontologies_General_HdMap_EnvironmentModel, + [...resources_HdMap_EnvironmentModel_x2], + { + filteredResources: [], + typeAssets: [ + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: true, + disabled: false + }, + ] as Asset[], + formatAssets: [ + { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: true, + disabled: false + }, + ], + vendorAssets: [], + } as ResourceFilterState + ) + + expect(result.filteredResources.length).toEqual(0); + + expect(result.typeAssets.filter(asset => !asset.value).length).toEqual(1); + expect(result.typeAssets).toEqual(expect.arrayContaining([ + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: true, + disabled: false + } + ])); + + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(0); + + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(0) + }) + + it('Pass in "vendor filter" as previously selected it will filter the resources list', () => { + const result = calculateResourceFiltersAssetState( + ontologies_General_HdMap_EnvironmentModel, + [ + ...resources_HdMap_EnvironmentModel_x2 + .map((resource, index) => index === 0 + ? { ...resource, vendor: 'msg systems ag' } + : { ...resource, vendor: 'other' }) + ], + { + filteredResources: [], + typeAssets: [], + formatAssets: [], + vendorAssets: [ + { + id: 'msg systems ag', + type: 'vendorAssets', + label: 'msg systems ag', + value: true, + disabled: false + }, + ], + } as ResourceFilterState + ) + + expect(result.filteredResources.length).toEqual(1); + + expect(result.typeAssets.filter(asset => !asset.value).length).toEqual(2); + + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets).toEqual(expect.arrayContaining([ + { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: false, + disabled: false + }, + ])); + + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(2) + expect(result.vendorAssets).toEqual([ + expect.objectContaining({ id: 'msg systems ag', value: true, disabled: false }), + expect.objectContaining({ id: 'other', value: false, disabled: false }) + ]); + }) + + it('returns a filtered resource list if searchText is set, but does not effect the filter type assets', () => { + const result = calculateResourceFiltersAssetState( + ontologies_General_HdMap_EnvironmentModel, + [...resources_HdMap_EnvironmentModel_x2], + { + filteredResources: [], + typeAssets: [], + formatAssets: [], + vendorAssets: [], + searchText: '72-' + } as ResourceFilterState + ) + + expect(result.filteredResources.length).toEqual(1); + expect(result.typeAssets).toEqual([ + { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: false, + disabled: false + }, + { + id: 'EnvironmentModel', + type: 'typeAssets', + label: 'EnvironmentModel', + value: false, + disabled: false + } + ]); + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets).toEqual(expect.arrayContaining([ + { + id: 'ASAM OpenDRIVE', + type: 'formatAssets', + label: 'ASAM OpenDRIVE', + value: false, + disabled: false + }, + ])); + + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) + expect(result.vendorAssets).toEqual([ + expect.objectContaining({ id: 'msg systems ag', disabled: false }) + ]); + }) + +}) diff --git a/tests/components/resources/helpers/resourceFilterReducer.test.ts b/tests/components/resources/helpers/resourceFilterReducer.test.ts new file mode 100644 index 00000000..c5ba9e7c --- /dev/null +++ b/tests/components/resources/helpers/resourceFilterReducer.test.ts @@ -0,0 +1,60 @@ +import { Asset } from '../../../../src/components/resources/helpers/resourceFilterHelper'; +import { + SET_RESOURCE_FILTER_ASSETS, + SET_SEARCH_TEXT, + setResourceFilterAssetsAction, + setSearchTextAction, + UPDATE_FILTER_ASSET, + updateFilterAssetAction +} from '../../../../src/components/resources/helpers/resourceFilterReducer'; +import { Ontology } from '../../../../src/types/ontologies.model'; +import { Resource } from '../../../../src/types/resources.model'; + +const getSchemaById = jest.fn(); +jest.mock('../../../../src/services/schemaApiService', () => ({ + getSchemaById: () => getSchemaById(), +})); + +// describe('Reducer', () => { +// +// it('', () => { +// +// // const nextState = resourceFilterReducer(initialResourceFilterState, setResourceFilterAssetsAction(ontologiesWithRelatedShapes)) +// }) +// }) + +describe('Actions', () => { + const ontologies = [{}, {}] as Ontology[] + const resources = [{}, {}, {}] as Resource[] + + test('setResourceFilterAssetsAction', () => { + const result = setResourceFilterAssetsAction(ontologies, resources); + + expect(result).toEqual({ + type: SET_RESOURCE_FILTER_ASSETS, + payload: { ontologies, resources } + }) + }) + + test('setSearchTextAction', () => { + const searchText = 'SEARCH_TEXT'; + + const result = setSearchTextAction(searchText, ontologies, resources); + + expect(result).toEqual({ + type: SET_SEARCH_TEXT, + payload: { searchText, ontologies, resources } + }) + }) + + test('updateFilterAssetAction', () => { + const asset = {} as Asset; + + const result = updateFilterAssetAction(asset, ontologies, resources); + + expect(result).toEqual({ + type: UPDATE_FILTER_ASSET, + payload: { asset, ontologies, resources } + }) + }) +}) diff --git a/tests/components/resources/helpers/resourceHelper.test.ts b/tests/components/resources/helpers/resourceHelper.test.ts new file mode 100644 index 00000000..2ea84dfa --- /dev/null +++ b/tests/components/resources/helpers/resourceHelper.test.ts @@ -0,0 +1,27 @@ +import { getAllLabels } from '../../../../src/components/resources/helpers/resourceFilterHelper'; +import { + getPropertyValue, + removeNonResourceTypeLabels +} from '../../../../src/components/resources/helpers/resourcesHelper'; + +import { resources_HdMap_EnvironmentModel_x2 } from './__fixtures__/resources_HdMap_EnvironmentModel_x2'; + +describe('removeNonResourceTypeLabels', () => { + it('returns the value of a given property entry', () => { + const obj = { + property1: 'first property value', + property2: 'second property value' + } + const entries = Object.entries(obj); + expect(getPropertyValue(entries[0])).toEqual('first property value'); + expect(getPropertyValue(entries[1])).toEqual('second property value'); + }) + + it('removes all labels which not contained by the "resourceTypes" input parameter', () => { + const resourceTypes = ['HdMap', 'EnvironmentModel']; + const result = removeNonResourceTypeLabels(resources_HdMap_EnvironmentModel_x2, resourceTypes); + + expect(getAllLabels(resources_HdMap_EnvironmentModel_x2).size).toBeGreaterThan(resourceTypes.length); + expect(getAllLabels(result)).toEqual(new Set(resourceTypes)); + }) +}) diff --git a/tests/components/resources/helpers/resourceReducer.test.ts b/tests/components/resources/helpers/resourceReducer.test.ts new file mode 100644 index 00000000..3040c25a --- /dev/null +++ b/tests/components/resources/helpers/resourceReducer.test.ts @@ -0,0 +1,61 @@ +import { + initialResourceState, + resourcesLoadedAction, + resourcesLoadingErrorAction, + resourcesReducer, + SET_ALL_RESOURCES, + SET_ALL_RESOURCES_LOADING_ERROR +} from '../../../../src/components/resources/helpers/resourcesReducer'; +import { Resource } from '../../../../src/types/resources.model'; + +import { resources_HdMap_EnvironmentModel_x2 } from './__fixtures__/resources_HdMap_EnvironmentModel_x2'; + +describe('Reducer', () => { + it('sets the resources to the value of the actions payload and returns it in the next state,' + + 'the "isLoading" property becomes false ' + + 'and the "hasError" property becomes also false', () => { + const allResources = [{}, {}] as Resource[]; + const nextState = resourcesReducer(initialResourceState, resourcesLoadedAction(allResources)); + + expect(nextState.resources).toEqual(allResources); + expect(nextState.isLoading).toBe(false); + expect(nextState.hasError).toBe(false); + }) + + it('sets the error to the value of the actions payload and returns it in the next state,' + + 'the "isLoading" property becomes false ' + + 'and the "hasError" property becomes also false', () => { + const error = 'error message'; + const nextState = resourcesReducer(initialResourceState, resourcesLoadingErrorAction(error)); + + expect(nextState.error).toEqual(error); + expect(nextState.isLoading).toBe(false); + expect(nextState.hasError).toBe(true); + }) + + it('returns the initial state if unknown action is passed in', () => { + const nextState = resourcesReducer(initialResourceState, { type: 'UNKNOWN_ACTION' }); + expect(nextState).toEqual(initialResourceState); + }) +}) + +describe('Actions', () => { + test('resourcesLoadedAction', () => { + const result = resourcesLoadedAction(resources_HdMap_EnvironmentModel_x2); + + expect(result).toEqual({ + type: SET_ALL_RESOURCES, + payload: resources_HdMap_EnvironmentModel_x2 + }) + }) + + test('resourcesLoadingErrorAction', () => { + const error = { error: 'error message' }; + const result = resourcesLoadingErrorAction(error); + + expect(result).toEqual({ + type: SET_ALL_RESOURCES_LOADING_ERROR, + payload: error + }) + }) +}) diff --git a/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts b/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts new file mode 100644 index 00000000..cec3317f --- /dev/null +++ b/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts @@ -0,0 +1,390 @@ +export const initiallyLoaded_ResourcesState = { + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + resources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + }, + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-06-17T11:37:14', + format: null, + labels: [ + 'EnvironmentModel' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-06-17T11:37:14', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', + vendor: 'msg systems ag' + }, + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-04-08T14:25:58', + format: null, + labels: [ + 'EnvironmentModel' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-04-08T14:25:58', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + vendor: 'msg systems ag' + } + ], + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: false + } + ], + viewContentType: 'SHOW_RESOURCES' +} + +export const filteredBy_searchText_HdMap_ResourcesState = { + formatAssets: [ + { + disabled: false, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + resources: [ + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + containsPII: 'false', + copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', + description: 'Generated description.', + expirationDateTime: '2025-05-23T07:23:25', + format: 'ASAM OpenDRIVE', + labels: [ + 'HdMap' + ], + license: 'Apache-2.0', + name: 'Generated Data Resource', + obsoleteDateTime: '2025-05-23T07:23:25', + policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', + test: 'Wird das zusammengemergt?', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + vendor: 'msg systems ag' + } + ], + typeAssets: [ + { + disabled: false, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: false, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [ + { + disabled: false, + id: 'msg systems ag', + label: 'msg systems ag', + type: 'vendorAssets', + value: false + } + ], + viewContentType: 'SHOW_RESOURCES' +} + +export const error_loadResources_ResourceState = { + formatAssets: [ + { + disabled: true, + id: 'ASAM OpenDRIVE', + label: 'ASAM OpenDRIVE', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Lanelet', + label: 'Lanelet', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Road5', + label: 'Road5', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Shape', + label: 'Shape', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'road2sim', + label: 'road2sim', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'roadXML', + label: 'roadXML', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Autodesk FBX', + label: 'Autodesk FBX', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'GLTF', + label: 'GLTF', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'OpenSceneGraph', + label: 'OpenSceneGraph', + type: 'formatAssets', + value: false + }, + { + disabled: true, + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false + } + ], + resources: [], + typeAssets: [ + { + disabled: true, + id: 'HdMap', + label: 'HdMap', + type: 'typeAssets', + value: false + }, + { + disabled: true, + id: 'EnvironmentModel', + label: 'EnvironmentModel', + type: 'typeAssets', + value: false + } + ], + vendorAssets: [], + viewContentType: 'SHOW_NO_RESULTS' +} + +export const error_useSchema_ResourceState = { + formatAssets: [], + resources: [], + typeAssets: [], + vendorAssets: [], + viewContentType: 'SHOW_NO_RESULTS' +} diff --git a/tests/components/resources/hooks/useResourceFilter.test.ts b/tests/components/resources/hooks/useResourceFilter.test.ts new file mode 100644 index 00000000..2e0cdce4 --- /dev/null +++ b/tests/components/resources/hooks/useResourceFilter.test.ts @@ -0,0 +1,93 @@ +import { act, renderHook, waitFor } from '@testing-library/react'; + +import { Asset } from '../../../../src/components/resources/helpers/resourceFilterHelper'; +import { ResourceFilterState } from '../../../../src/components/resources/helpers/resourceFilterReducer'; +import { useResourceFilter } from '../../../../src/components/resources/hooks/useResourceFilter'; +import { + ontologies_General_HdMap_EnvironmentModel +} from '../../../__fixtures__/ontologies_General_HdMap_EnvironmentModel'; +import { + filteredBy_searchText_HdMap_ResourceFilterState, + filteredBy_typeFilter_HdMap_ResourceFilterState, + initiallyLoaded_ResourceFilterState +} from '../helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2'; +import { resources_HdMap_EnvironmentModel_x2 } from '../helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2'; + +describe('useResourceFilter', () => { + it('renders correctly the initial values', async () => { + const { result } = renderHook(() => useResourceFilter( + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + )); + + // Remove the searchText from the "initiallyLoaded_ResourceFilterState" + const { searchText, ...initiallyLoadedState } = initiallyLoaded_ResourceFilterState; + + // Wait for the useEffect to be executed + await waitFor(() => expect(result.current).toEqual( + expect.objectContaining(initiallyLoadedState)) + ); + }) + + it('it filters resources if searchText is updated', async () => { + + const { result } = renderHook(() => useResourceFilter( + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + )); + + const initiallyLoadedState = removeSearchText(initiallyLoaded_ResourceFilterState) + + // Wait for the useEffect to be executed + await waitFor(() => expect(result.current).toEqual( + expect.objectContaining(initiallyLoadedState)) + ); + + // Call the "updateSearchText" returned by the hook + act(() => result.current.updateSearchText('HdMap')); + + const filteredResources = removeSearchText(filteredBy_searchText_HdMap_ResourceFilterState); + expect(result.current.filteredResources.length).toEqual(1); + expect(result.current).toEqual( + expect.objectContaining(filteredResources) + ); + }) + + it('it filters resources if filter asset is updated', async () => { + + const { result } = renderHook(() => useResourceFilter( + ontologies_General_HdMap_EnvironmentModel, + resources_HdMap_EnvironmentModel_x2 + )); + + const initiallyLoadedState = removeSearchText(initiallyLoaded_ResourceFilterState) + + // Wait for the useEffect to be executed + await waitFor(() => expect(result.current).toEqual( + expect.objectContaining(initiallyLoadedState)) + ); + + const asset = { + id: 'HdMap', + type: 'typeAssets', + label: 'HdMap', + value: true, + disabled: false + } as Asset; + + // Call the "updateSearchText" returned by the hook + act(() => result.current.updateFilterAsset(asset)); + + const filteredResources = removeSearchText(filteredBy_typeFilter_HdMap_ResourceFilterState); + expect(result.current.filteredResources.length).toEqual(1); + expect(result.current).toEqual( + expect.objectContaining(filteredResources) + ); + }) +}) + +const removeSearchText = (resourceFilterState: ResourceFilterState) => { + // Remove the "searchText" property from the "resourceFilterState" + const { searchText, ...returnValue } = resourceFilterState; + return returnValue; +} diff --git a/tests/components/resources/hooks/useResources.test.ts b/tests/components/resources/hooks/useResources.test.ts new file mode 100644 index 00000000..2c58e3f4 --- /dev/null +++ b/tests/components/resources/hooks/useResources.test.ts @@ -0,0 +1,100 @@ +import { act, renderHook, waitFor } from '@testing-library/react'; + +import { removeNonResourceTypeLabels } from '../../../../src/components/resources/helpers/resourcesHelper'; +import { useResources } from '../../../../src/components/resources/hooks/useResources'; +import { AllSchemasState } from '../../../../src/helpers/schemasReducer'; +import { + ontologies_General_HdMap_EnvironmentModel +} from '../../../__fixtures__/ontologies_General_HdMap_EnvironmentModel'; +import { resources_HdMap_EnvironmentModel_x2 } from '../helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2'; + +import { + error_loadResources_ResourceState, + error_useSchema_ResourceState, + filteredBy_searchText_HdMap_ResourcesState, + initiallyLoaded_ResourcesState +} from './__fixtures__/resourcesState_HdMap_EnvironmentModel_x2'; + +// Mock: useSchemas +const useSchemas = jest.fn(); +jest.mock('../../../../src/hooks/useSchemas', () => ({ + useSchemas: () => useSchemas() +})); + +// Mock: loadResources +const loadResources = jest.fn(); +jest.mock('../../../../src/components/resources/helpers/resourceDataFlow', () => ({ + loadResources: () => loadResources() +})); + +describe('useResources', () => { + beforeEach(() => { + loadResources.mockReset(); + useSchemas.mockReset() + .mockReturnValue({ + isLoading: false, + hasError: false, + ontologies: ontologies_General_HdMap_EnvironmentModel, + } as AllSchemasState) + }) + + it('renders correctly initial values', async () => { + loadResources.mockResolvedValueOnce(resources_HdMap_EnvironmentModel_x2); + const { result } = renderHook(() => useResources()); + + // Wait for the useEffect to be executed + const resourcesState = { + ...initiallyLoaded_ResourcesState, + resources: removeNonResourceTypeLabels( + resources_HdMap_EnvironmentModel_x2, + ['HdMap', 'EnvironmentModel'] + ) + } + await waitFor(() => expect(result.current.viewContentType).toEqual('SHOW_RESOURCES')); + expect(result.current).toEqual( + expect.objectContaining(resourcesState) + ) + }) + + it('filters "resources" if "searchText" is updated', async () => { + loadResources.mockResolvedValueOnce(resources_HdMap_EnvironmentModel_x2); + const { result } = renderHook(() => useResources()); + + // Wait for the useEffect to be executed + await waitFor(() => expect(result.current).toEqual( + expect.objectContaining(initiallyLoaded_ResourcesState)) + ); + + // Call the "updateSearchText" returned by the hook + act(() => result.current.updateSearchText('HdMap')); + + expect(result.current.resources.length).toEqual(1); + expect(result.current).toEqual( + expect.objectContaining(filteredBy_searchText_HdMap_ResourcesState) + ); + }) + + it('set "viewContentType" to "SHOW_NO_RESULT" if error occurs "loadResources"', async () => { + loadResources.mockRejectedValueOnce(new Error('error message')); + const { result } = renderHook(() => useResources()); + + // Wait for the useEffect to be executed + await waitFor(() => expect(result.current.viewContentType).toEqual('SHOW_NO_RESULTS')); + expect(result.current).toEqual(expect.objectContaining(error_loadResources_ResourceState)); + }) + + it('set "viewContentType" to "SHOW_NO_RESULT" if error occurs "useSchemas"', async () => { + useSchemas.mockReset() + .mockReturnValue({ + isLoading: false, + hasError: true, + error: new Error('error message') + } as AllSchemasState); + loadResources.mockResolvedValueOnce(resources_HdMap_EnvironmentModel_x2); + const { result } = renderHook(() => useResources()); + + // Wait for the useEffect to be executed + await waitFor(() => expect(result.current.viewContentType).toEqual('SHOW_NO_RESULTS')); + expect(result.current).toEqual(expect.objectContaining(error_useSchema_ResourceState)); + }) +}) diff --git a/tests/services/schemaApiService.test.ts b/tests/services/schemaApiService.test.ts new file mode 100644 index 00000000..bc09934b --- /dev/null +++ b/tests/services/schemaApiService.test.ts @@ -0,0 +1,92 @@ +import axios from 'axios'; + +import { fetchAllSchemas, getConvertedFile, getSchemaById } from '../../src/services/schemaApiService'; +import { readFile } from '../../src/utils/readFile'; + +const SERVER_BASE_URL: string = 'https://fc-server.gxfs.gx4fm.org'; +const CONVERT_SERVER_BASE_URL: string = 'https://sd-creation-wizard-api.gxfs.gx4fm.org/convertFile'; +const SHACL_SHAPE_ID = '700f40c0030d83b0ca6ed147144037891b27f4fa73fe596d0092c25b07c9d98b'; +const hdmap_shacl_ttl = readFile('tests/__fixtures__/hdmap_shacl.ttl'); + +const post = jest.spyOn(axios, 'post'); +const get = jest.spyOn(axios, 'get'); + +describe('getConvertedFile', () => { + beforeEach(() => { + get.mockReset(); + post.mockReset(); + }); + + it('calls the endpoint for conversion with the schema fetched from "getSchemaById"', async () => { + get.mockResolvedValueOnce({ data: await hdmap_shacl_ttl }); // called by getSchemaById + post.mockResolvedValueOnce({ data: 'converted data' }); + + const result = await getConvertedFile(SHACL_SHAPE_ID); + expect(get).toBeCalledWith(SERVER_BASE_URL + '/schemas/' + SHACL_SHAPE_ID); + + const blob = new Blob([await hdmap_shacl_ttl], { type: 'text/plain' }); + const formData = new FormData(); + formData.append('file', blob, 'shaclFile.shacl'); + + const headers = { headers: { 'Content-Type': 'multipart/form-data' } }; + expect(post).toBeCalledWith(CONVERT_SERVER_BASE_URL, formData, headers); + expect(result).toEqual('converted data'); + }); + + it('throw error if axios.post encounters an error', async () => { + const error = new Error('axios error'); + + get.mockResolvedValueOnce({ data: await hdmap_shacl_ttl }); // called by getSchemaById + post.mockRejectedValueOnce(error); + + await expect(() => getConvertedFile(SHACL_SHAPE_ID)).rejects.toThrow(error); + + }); +}); + +describe('getSchemaById', () => { + beforeEach(() => { + get.mockReset(); + post.mockReset(); + }); + + it('fetches and returns data from the "SERVER_BASE_URL"', async () => { + const responseData = await hdmap_shacl_ttl; + get.mockResolvedValueOnce({ data: responseData }); + + const result = await getSchemaById(SHACL_SHAPE_ID); + expect(result).toEqual(responseData); + expect(get).toHaveBeenCalledWith(SERVER_BASE_URL + '/schemas/' + SHACL_SHAPE_ID); + }); + + it('throws error if axios.get encounters an error', async () => { + const error = new Error('axios get error'); + get.mockRejectedValueOnce(error); + + await expect(() => getSchemaById(SHACL_SHAPE_ID)).rejects.toThrow(error); + }); +}); + +describe('fetchAllSchemas', () => { + beforeEach(() => { + get.mockReset(); + post.mockReset(); + }); + + it('fetches data from the "SERVER_BASE_URL"', async () => { + const responseData = { ontologies: [], shapes: [], vocabularies: [] }; + get.mockResolvedValueOnce({ data: responseData }); + + const result = await fetchAllSchemas(); + expect(result).toEqual(responseData); + expect(get).toHaveBeenCalledWith(SERVER_BASE_URL + '/schemas'); + }); + + it('returns default values if axios.get encounters an error', async () => { + const error = new Error('axios get error'); + get.mockRejectedValueOnce(error); + + const result = await fetchAllSchemas(); + expect(result).toEqual({ ontologies: [], shapes: [], vocabularies: [] }); + }); +}); diff --git a/tests/utils/readFile.test.ts b/tests/utils/readFile.test.ts index f6cbfbe1..1b3e82c6 100644 --- a/tests/utils/readFile.test.ts +++ b/tests/utils/readFile.test.ts @@ -2,36 +2,41 @@ import { describe, expect, it } from '@jest/globals'; import { readFile } from '../../src/utils/readFile'; -describe('ReadFile', () => { - it('_ read file', async () => { - // Given +console.error = jest.fn(); // Disable error log + +describe('readFile', () => { + it('reads content', async () => { const filePath = 'tests/utils/__fixtures__/test-shapes-short.ttl'; - const expectedString = getExpectedString(); - // When const result = await readFile(filePath); - // Then - expect(result).toEqual(expectedString); + expect(result).toEqual(expectedContent); + }); + + it('throws error', async () => { + const filePath = 'non/existing/path'; + await expect(() => readFile(filePath)).rejects.toThrow(''); + }); }); -const getExpectedString = () => { - return '@prefix dcat: .\n' + - '@prefix dct: .\n' + - '@prefix example: .\n' + - '@prefix foaf: .\n' + - '@prefix gax-core: .\n' + - '@prefix gax-trust-framework: .\n' + - '@prefix gax-validation: .\n' + - '@prefix gaxtrustframework: .\n' + - '@prefix openlabel: .\n' + - '@prefix plc: .\n' + - '@prefix rdf: .\n' + - '@prefix sh: .\n' + - '@prefix skos: .\n' + - '@prefix surveyonto: .\n' + - '@prefix vcard: .\n' + - '@prefix xsd: .\n' + - '\n' + - 'gax-validation:WalletShape\n' + - ' rdf:type sh:NodeShape;\n' + - ' sh:targetClass gax-trust-framework:Wallet .\n'; -} + +const expectedContent = + `@prefix dcat: . +@prefix dct: . +@prefix example: . +@prefix foaf: . +@prefix gax-core: . +@prefix gax-trust-framework: . +@prefix gax-validation: . +@prefix gaxtrustframework: . +@prefix openlabel: . +@prefix plc: . +@prefix rdf: . +@prefix sh: . +@prefix skos: . +@prefix surveyonto: . +@prefix vcard: . +@prefix xsd: . + +gax-validation:WalletShape + rdf:type sh:NodeShape; + sh:targetClass gax-trust-framework:Wallet . +`; From 1f3823baaa7d0acfc6762d66bcd439ea408755e9 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 13:04:26 +0300 Subject: [PATCH 18/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 43 +++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index 8b7df05b..c2c2a66a 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -32,8 +32,6 @@ jobs: # Step 4: Run Jest tests - name: Run Jest tests - # TODO: Adapt to run coverage on changed files only. - # run: npm test -- --coverage # $(git diff --name-only origin/main...HEAD | grep '\.[jt]sx\?$' | grep -v '\ .test\.') run: npm test -- --coverage env: CI: true # Ensures Jest runs in CI mode @@ -47,14 +45,33 @@ jobs: retention-days: 7 # Step 6: Fail the job if there are uncovered files (js, ts, jsx, tsx) - # TODO: It needs to be implemented. - - # Step 7: Fail the job if the test coverage is below a threshold (optional) - # TODO: This should be removed because it is solved within 'jest.config.js' by setting the 'coverageThreshold'. - # - name: Check coverage threshold - # run: | - # COVERAGE=$(grep -o '"total": {.*}' coverage/coverage-summary.json | grep -o '"lines":{.*}$' | grep -o '"pct":[0-9]*' | grep -m 1 '"pct":[0-9]*' | grep -o '[0-9]*') - # if [ "$COVERAGE" -lt 90 ]; then - # echo "Test coverage below 90%. Coverage: $COVERAGE%" - # exit 1 - # fi + - name: Check uncovered files + run: | + # Step 1: Get the list of changed JS, TS, JSX and TSX files in the src directory + CHANGED_FILES=$(git diff --name-only origin/main...HEAD | grep '^src/.*\.[jt]sx\?$' | grep -v '\ .test\.') + + # Initialize an empty array to hold files without tests + MISSING_TEST_FILES=() + + # Step 2: Loop through each changed file and check if it has a corresponding test file + for FILE in $CHANGED_FILES; do + # Extract the file path and replace "src/" with "tests/" and add ".test" postfix + TEST_FILE=$(echo "$FILE" | sed 's|^src/|tests/|' | sed 's|\.[jt]sx\?$|.test&|') + + # Check if the corresponding test file exists + if [[ ! -f "$TEST_FILE" ]]; then + MISSING_TEST_FILES+=("$FILE") # Add to missing test files array if test is not found + fi + done + + # Step 3: Report and fail if there are any missing test files + if [ ${#MISSING_TEST_FILES[@]} -ne 0 ]; then + echo "The following source files do not have corresponding test files:" + for MISSING_FILE in "${MISSING_TEST_FILES[@]}"; do + echo "$MISSING_FILE" + done + exit 1 # Fail the workflow + else + echo "All changed files have corresponding test files." + exit 0 # Success + fi From 9fd6319a5022b013ae34f20435bbe984d36c3f0d Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 13:12:21 +0300 Subject: [PATCH 19/33] Add missing dev dependency to dotenv in order to run jest tests. Signed-off-by: Zoltan Magyari --- jest.setup.js | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/jest.setup.js b/jest.setup.js index e1d9e108..84282021 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1,4 +1,5 @@ const { TextEncoder, TextDecoder } = require('util'); +require('dotenv').config(); global.TextEncoder = TextEncoder; global.TextDecoder = TextDecoder; diff --git a/package.json b/package.json index a2d68704..22afb60e 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "@types/jest": "^29.5.13", "@types/n3": "^1.16.4", "customize-cra": "^1.0.0", + "dotenv": "^16.4.5", "eslint-plugin-import": "^2.29.1", "eslint-plugin-react": "^7.29.4", "jest": "^29.6.2", From 9af9c96256e3094b3600015c6b9c17da7ad13778 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 13:23:43 +0300 Subject: [PATCH 20/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index c2c2a66a..2530e1f5 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -48,7 +48,7 @@ jobs: - name: Check uncovered files run: | # Step 1: Get the list of changed JS, TS, JSX and TSX files in the src directory - CHANGED_FILES=$(git diff --name-only origin/main...HEAD | grep '^src/.*\.[jt]sx\?$' | grep -v '\ .test\.') + CHANGED_FILES=$(git diff --name-only origin/main...HEAD | grep '^src/.*\.[jt]sx\?$') # Initialize an empty array to hold files without tests MISSING_TEST_FILES=() From c2829ccef5e7eef45814ef690dff5a404795b17c Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 13:36:20 +0300 Subject: [PATCH 21/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index 2530e1f5..53cd5136 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -48,7 +48,7 @@ jobs: - name: Check uncovered files run: | # Step 1: Get the list of changed JS, TS, JSX and TSX files in the src directory - CHANGED_FILES=$(git diff --name-only origin/main...HEAD | grep '^src/.*\.[jt]sx\?$') + CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx' || true) # Initialize an empty array to hold files without tests MISSING_TEST_FILES=() From b404d5621c2c41ca189e1f9fe6a54777722c1e84 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 13:47:12 +0300 Subject: [PATCH 22/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index 53cd5136..6f5df662 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -47,13 +47,16 @@ jobs: # Step 6: Fail the job if there are uncovered files (js, ts, jsx, tsx) - name: Check uncovered files run: | - # Step 1: Get the list of changed JS, TS, JSX and TSX files in the src directory - CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx' || true) + # Step 1: Fetch the origin/main branch to compare the HEAD with + git fetch origin main + + # Step 2: Get the list of changed JS, TS, JSX and TSX files in the src directory + CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx') # Initialize an empty array to hold files without tests MISSING_TEST_FILES=() - # Step 2: Loop through each changed file and check if it has a corresponding test file + # Step 3: Loop through each changed file and check if it has a corresponding test file for FILE in $CHANGED_FILES; do # Extract the file path and replace "src/" with "tests/" and add ".test" postfix TEST_FILE=$(echo "$FILE" | sed 's|^src/|tests/|' | sed 's|\.[jt]sx\?$|.test&|') @@ -64,7 +67,7 @@ jobs: fi done - # Step 3: Report and fail if there are any missing test files + # Step 4: Report and fail if there are any missing test files if [ ${#MISSING_TEST_FILES[@]} -ne 0 ]; then echo "The following source files do not have corresponding test files:" for MISSING_FILE in "${MISSING_TEST_FILES[@]}"; do From 00e95bb5bce7c20f9d3da515db10b4c71e297500 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 13:57:35 +0300 Subject: [PATCH 23/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index 6f5df662..e255bf8b 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -48,10 +48,10 @@ jobs: - name: Check uncovered files run: | # Step 1: Fetch the origin/main branch to compare the HEAD with - git fetch origin main + git fetch main # Step 2: Get the list of changed JS, TS, JSX and TSX files in the src directory - CHANGED_FILES=$(git diff --name-only origin/main...HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx') + CHANGED_FILES=$(git diff --name-only origin/main..HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx') # Initialize an empty array to hold files without tests MISSING_TEST_FILES=() From 6ad30f9fe3054693a5ca444c4487da8fca480478 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 14:06:54 +0300 Subject: [PATCH 24/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 33 +----------------------------- check-missing-tests.sh | 31 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 check-missing-tests.sh diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index e255bf8b..17509347 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -46,35 +46,4 @@ jobs: # Step 6: Fail the job if there are uncovered files (js, ts, jsx, tsx) - name: Check uncovered files - run: | - # Step 1: Fetch the origin/main branch to compare the HEAD with - git fetch main - - # Step 2: Get the list of changed JS, TS, JSX and TSX files in the src directory - CHANGED_FILES=$(git diff --name-only origin/main..HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx') - - # Initialize an empty array to hold files without tests - MISSING_TEST_FILES=() - - # Step 3: Loop through each changed file and check if it has a corresponding test file - for FILE in $CHANGED_FILES; do - # Extract the file path and replace "src/" with "tests/" and add ".test" postfix - TEST_FILE=$(echo "$FILE" | sed 's|^src/|tests/|' | sed 's|\.[jt]sx\?$|.test&|') - - # Check if the corresponding test file exists - if [[ ! -f "$TEST_FILE" ]]; then - MISSING_TEST_FILES+=("$FILE") # Add to missing test files array if test is not found - fi - done - - # Step 4: Report and fail if there are any missing test files - if [ ${#MISSING_TEST_FILES[@]} -ne 0 ]; then - echo "The following source files do not have corresponding test files:" - for MISSING_FILE in "${MISSING_TEST_FILES[@]}"; do - echo "$MISSING_FILE" - done - exit 1 # Fail the workflow - else - echo "All changed files have corresponding test files." - exit 0 # Success - fi + run: ./check-missing-tests.sh diff --git a/check-missing-tests.sh b/check-missing-tests.sh new file mode 100644 index 00000000..4eda90f6 --- /dev/null +++ b/check-missing-tests.sh @@ -0,0 +1,31 @@ +#!/bin/bash +git fetch origin main + +# Step 1: Get the list of changed JS, TS, JSX and TSX files in the src directory +CHANGED_FILES=$(git diff --name-only origin/main..HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx') + +# Initialize an empty array to hold files without tests +MISSING_TEST_FILES=() + +# Step 2: Loop through each changed file and check if it has a corresponding test file +for FILE in $CHANGED_FILES; do + # Extract the file path and replace "src/" with "tests/" and add ".test" postfix + TEST_FILE=$(echo "$FILE" | sed 's|^src/|tests/|' | sed 's|\.[jt]sx\?$|.test&|') + + # Check if the corresponding test file exists + if [[ ! -f "$TEST_FILE" ]]; then + MISSING_TEST_FILES+=("$FILE") # Add to missing test files array if test is not found + fi +done + +# Step 3: Report and fail if there are any missing test files +if [ ${#MISSING_TEST_FILES[@]} -ne 0 ]; then + echo "The following source files do not have corresponding test files:" + for MISSING_FILE in "${MISSING_TEST_FILES[@]}"; do + echo "$MISSING_FILE" + done + exit 1 # Fail the workflow +else + echo "All changed files have corresponding test files." + exit 0 # Success +fi From 7d25197c8eeb2b3a3d8cf9e9cbe423c36785c80e Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 14:34:44 +0300 Subject: [PATCH 25/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index 17509347..e3c62221 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -44,6 +44,10 @@ jobs: path: coverage/lcov-report/ # Path to the HTML coverage report retention-days: 7 - # Step 6: Fail the job if there are uncovered files (js, ts, jsx, tsx) + # Step 6: Make check-missing-tests.sh executable + - name: Make script 'check-missing-tests.sh' executable + run: chmod +x ./check-missing-tests.sh + + # Step 7: Fail the job if there are uncovered files (js, ts, jsx, tsx) - name: Check uncovered files run: ./check-missing-tests.sh From 8d479c592f9839bf166f30e18ba7f7b0191db42c Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 14:36:37 +0300 Subject: [PATCH 26/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index e3c62221..df780fe5 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -44,7 +44,7 @@ jobs: path: coverage/lcov-report/ # Path to the HTML coverage report retention-days: 7 - # Step 6: Make check-missing-tests.sh executable + # Step 6: Make 'check-missing-tests.sh' executable - name: Make script 'check-missing-tests.sh' executable run: chmod +x ./check-missing-tests.sh From 048361fb7081e64406934475ee8073ecb4a7007a Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 14:45:18 +0300 Subject: [PATCH 27/33] Change from eslint error to warning remove unnecessary quotes from props Signed-off-by: Zoltan Magyari --- .eslintrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index d8fc530d..76a5db3a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,7 +20,7 @@ ], "rules": { "quote-props": [ - "error", + "warn", "as-needed" ], "no-const-assign": "warn", From b4c3f3aeab0486f898e2df187387becf62efb77a Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 14:50:11 +0300 Subject: [PATCH 28/33] Change from eslint error to warning remove unnecessary quotes from props Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index df780fe5..9fda64c1 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -49,5 +49,5 @@ jobs: run: chmod +x ./check-missing-tests.sh # Step 7: Fail the job if there are uncovered files (js, ts, jsx, tsx) - - name: Check uncovered files + - name: Check missing tests run: ./check-missing-tests.sh From 04a7e5e070c2d6ded4d1e26d392d39eb1ce14739 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 14:54:15 +0300 Subject: [PATCH 29/33] Fix eslint error: remove unnecessary quotes from props Signed-off-by: Zoltan Magyari --- src/common/auth.js | 28 +++++++++---------- src/components/dashboard/dashboard_view.js | 2 +- src/components/dashboard/lcm/LcmFinal.js | 2 +- src/components/dashboard/plot_view.js | 2 +- .../dashboard/side_sections_view.js | 4 +-- src/components/discovery/DiscoveryItem.js | 6 ++-- .../tabs/description/DescriptionTab.js | 2 +- .../tabs/screenshots/ScreenshotsTabView.js | 10 +++---- src/components/expandable/down.js | 4 +-- src/components/onboarding/finish_provider.js | 2 +- src/components/onboarding/vc_customer.js | 2 +- src/components/onboarding/vc_provider.js | 2 +- .../SolutionPackagingView.js | 8 +++--- 13 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/common/auth.js b/src/common/auth.js index 60e2e63d..c5b76085 100644 --- a/src/common/auth.js +++ b/src/common/auth.js @@ -13,25 +13,25 @@ export function userData() { return { user: { - 'first_name': dToken.given_name, - 'family_name': dToken.family_name, - 'email': dToken.email, - 'user_role': retrieveRole(dToken), - 'organization_url': dToken.prWeb, - 'organization_name': dToken.prName, - 'organization_realm': dToken.prRealm + first_name: dToken.given_name, + family_name: dToken.family_name, + email: dToken.email, + user_role: retrieveRole(dToken), + organization_url: dToken.prWeb, + organization_name: dToken.prName, + organization_realm: dToken.prRealm } } } else { return { user: { - 'first_name': null, - 'family_name': null, - 'email': null, - 'user_role': VR_ROLE, - 'organization_url': null, - 'organization_name': null, - 'organization_realm': null + first_name: null, + family_name: null, + email: null, + user_role: VR_ROLE, + organization_url: null, + organization_name: null, + organization_realm: null } } } diff --git a/src/components/dashboard/dashboard_view.js b/src/components/dashboard/dashboard_view.js index 8706136a..aaa1292a 100644 --- a/src/components/dashboard/dashboard_view.js +++ b/src/components/dashboard/dashboard_view.js @@ -110,7 +110,7 @@ const ServicesLoadingListView = ({ url, title, type }) => { ) diff --git a/src/components/dashboard/lcm/LcmFinal.js b/src/components/dashboard/lcm/LcmFinal.js index c2f06775..fb464b4a 100644 --- a/src/components/dashboard/lcm/LcmFinal.js +++ b/src/components/dashboard/lcm/LcmFinal.js @@ -163,7 +163,7 @@ class LcmFinal extends Component { _getServicesRequest() { const request = { - 'services': [ + services: [ ] } diff --git a/src/components/dashboard/plot_view.js b/src/components/dashboard/plot_view.js index cf053447..91f03bf9 100644 --- a/src/components/dashboard/plot_view.js +++ b/src/components/dashboard/plot_view.js @@ -82,7 +82,7 @@ const PlotLoadingView = ({ url, title, }) => { return } diff --git a/src/components/dashboard/side_sections_view.js b/src/components/dashboard/side_sections_view.js index c0ce0973..f8c569c1 100644 --- a/src/components/dashboard/side_sections_view.js +++ b/src/components/dashboard/side_sections_view.js @@ -113,12 +113,12 @@ const SideSectionsView = () => { ) diff --git a/src/components/discovery/DiscoveryItem.js b/src/components/discovery/DiscoveryItem.js index cd794a38..6b27d957 100644 --- a/src/components/discovery/DiscoveryItem.js +++ b/src/components/discovery/DiscoveryItem.js @@ -5,9 +5,9 @@ import TileFactory from './TileFactory'; const DiscoveryItem = ({ type }) => { const id = useParams(); - const dataItem = { 'type': 'data','logo': '/images/logos/placeholder.png', 'ppr_url': 'URL to PPR', 'name': 'data name','ppr_name': 'PPR name', 'id': 'data id', 'short_description': 'String', 'location': 'String' }; - const pprItem = { 'type': 'ppr','logo': '/images/logos/placeholder.png', 'ppr_url': 'URL to PPR', 'name': 'PPR name','id': 'PPR id','sustainability': 'String','availability': 'String', 'location': 'String' }; - const serviceItem = { 'type': 'service','logo': '/images/logos/placeholder.png','name': 'Service name','id': 'service id','ppr_name': 'Provider name','ppr_url': 'URL to PPR','stack': 'String','security': 'String','location': 'String' }; + const dataItem = { type: 'data',logo: '/images/logos/placeholder.png', ppr_url: 'URL to PPR', name: 'data name',ppr_name: 'PPR name', id: 'data id', short_description: 'String', location: 'String' }; + const pprItem = { type: 'ppr',logo: '/images/logos/placeholder.png', ppr_url: 'URL to PPR', name: 'PPR name',id: 'PPR id',sustainability: 'String',availability: 'String', location: 'String' }; + const serviceItem = { type: 'service',logo: '/images/logos/placeholder.png',name: 'Service name',id: 'service id',ppr_name: 'Provider name',ppr_url: 'URL to PPR',stack: 'String',security: 'String',location: 'String' }; switch (type) { case 'data': return TileFactory ({ data: dataItem, id }); diff --git a/src/components/discovery/tabs/description/DescriptionTab.js b/src/components/discovery/tabs/description/DescriptionTab.js index b0f90b25..bf1d776d 100644 --- a/src/components/discovery/tabs/description/DescriptionTab.js +++ b/src/components/discovery/tabs/description/DescriptionTab.js @@ -26,7 +26,7 @@ const DescriptionTab = ({ id, type }) => { return ( ) diff --git a/src/components/discovery/tabs/screenshots/ScreenshotsTabView.js b/src/components/discovery/tabs/screenshots/ScreenshotsTabView.js index 7720cd8e..4d5cff30 100644 --- a/src/components/discovery/tabs/screenshots/ScreenshotsTabView.js +++ b/src/components/discovery/tabs/screenshots/ScreenshotsTabView.js @@ -18,12 +18,12 @@ const ScreenshotsTabView = (props,) => { var _images = (slideImages && slideImages.map((p, index) => { return { - 'original': p['url'], - 'originalHeight': '500px', - 'originalWidth': '100%', - 'thumbnail': p['url'], + original: p['url'], + originalHeight: '500px', + originalWidth: '100%', + thumbnail: p['url'], // 'thumbnailHeight': '128px', - 'thumbnailWidth': '128px' + thumbnailWidth: '128px' } })) || [] diff --git a/src/components/expandable/down.js b/src/components/expandable/down.js index bed93759..68d8089d 100644 --- a/src/components/expandable/down.js +++ b/src/components/expandable/down.js @@ -8,12 +8,12 @@ const Down = ({ isOpen, paddingRight, arrowColor }) => { return ( diff --git a/src/components/onboarding/finish_provider.js b/src/components/onboarding/finish_provider.js index 083e5ee4..be036ce3 100644 --- a/src/components/onboarding/finish_provider.js +++ b/src/components/onboarding/finish_provider.js @@ -22,7 +22,7 @@ const FinishProvider = () => { URL, undefined, { - headers: { 'Authorization': 'Bearer ' + retrieveAndRemoveOnboardingJWT() } + headers: { Authorization: 'Bearer ' + retrieveAndRemoveOnboardingJWT() } } ).then(() => { navigate('/'); diff --git a/src/components/onboarding/vc_customer.js b/src/components/onboarding/vc_customer.js index 54f1d3a6..a63062b0 100644 --- a/src/components/onboarding/vc_customer.js +++ b/src/components/onboarding/vc_customer.js @@ -112,7 +112,7 @@ const VCCustomer = ({ nextStage }) => { } const headerAuth = { - 'Authorization': 'Bearer ' + retrieveAndRemoveOnboardingJWT() + Authorization: 'Bearer ' + retrieveAndRemoveOnboardingJWT() } return diff --git a/src/components/onboarding/vc_provider.js b/src/components/onboarding/vc_provider.js index be06ce08..bc2a7349 100644 --- a/src/components/onboarding/vc_provider.js +++ b/src/components/onboarding/vc_provider.js @@ -96,7 +96,7 @@ const VCProvider = ({ nextStage }) => { } const headerAuth = { - 'Authorization': 'Bearer ' + retrieveOnboardingJWT() + Authorization: 'Bearer ' + retrieveOnboardingJWT() } return diff --git a/src/components/solutionPackaging/SolutionPackagingView.js b/src/components/solutionPackaging/SolutionPackagingView.js index 4989af1d..f13f62fe 100644 --- a/src/components/solutionPackaging/SolutionPackagingView.js +++ b/src/components/solutionPackaging/SolutionPackagingView.js @@ -60,10 +60,10 @@ const SolutionPackagingView = () => { } }).filter((service)=> service !== undefined); let saveData = { - 'name': name, - 'service_id': id, - 'action': action, - 'selected_items': selected } + name: name, + service_id: id, + action: action, + selected_items: selected } axios.post(SAVE_URL, saveData).then((response) => { navigate('/dashboard'); From 4922554d82c15853227da56eafc41a8053083ae2 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Fri, 27 Sep 2024 15:18:57 +0300 Subject: [PATCH 30/33] Git workflow for running jest test (Review comments) Signed-off-by: Zoltan Magyari --- .github/workflows/branch-push.yaml | 8 -------- check-missing-tests.sh | 31 ------------------------------ 2 files changed, 39 deletions(-) delete mode 100644 check-missing-tests.sh diff --git a/.github/workflows/branch-push.yaml b/.github/workflows/branch-push.yaml index 9fda64c1..822bc791 100644 --- a/.github/workflows/branch-push.yaml +++ b/.github/workflows/branch-push.yaml @@ -43,11 +43,3 @@ jobs: name: coverage-report path: coverage/lcov-report/ # Path to the HTML coverage report retention-days: 7 - - # Step 6: Make 'check-missing-tests.sh' executable - - name: Make script 'check-missing-tests.sh' executable - run: chmod +x ./check-missing-tests.sh - - # Step 7: Fail the job if there are uncovered files (js, ts, jsx, tsx) - - name: Check missing tests - run: ./check-missing-tests.sh diff --git a/check-missing-tests.sh b/check-missing-tests.sh deleted file mode 100644 index 4eda90f6..00000000 --- a/check-missing-tests.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -git fetch origin main - -# Step 1: Get the list of changed JS, TS, JSX and TSX files in the src directory -CHANGED_FILES=$(git diff --name-only origin/main..HEAD -- 'src/*.[jt]s' 'src/*.[jt]sx') - -# Initialize an empty array to hold files without tests -MISSING_TEST_FILES=() - -# Step 2: Loop through each changed file and check if it has a corresponding test file -for FILE in $CHANGED_FILES; do - # Extract the file path and replace "src/" with "tests/" and add ".test" postfix - TEST_FILE=$(echo "$FILE" | sed 's|^src/|tests/|' | sed 's|\.[jt]sx\?$|.test&|') - - # Check if the corresponding test file exists - if [[ ! -f "$TEST_FILE" ]]; then - MISSING_TEST_FILES+=("$FILE") # Add to missing test files array if test is not found - fi -done - -# Step 3: Report and fail if there are any missing test files -if [ ${#MISSING_TEST_FILES[@]} -ne 0 ]; then - echo "The following source files do not have corresponding test files:" - for MISSING_FILE in "${MISSING_TEST_FILES[@]}"; do - echo "$MISSING_FILE" - done - exit 1 # Fail the workflow -else - echo "All changed files have corresponding test files." - exit 0 # Success -fi From 1edafa8c98fe9b84c041d5b4310719776b5a9e32 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Mon, 30 Sep 2024 10:17:42 +0300 Subject: [PATCH 31/33] Fix failing ItemCard rendering Signed-off-by: Zoltan Magyari --- src/components/ItemCard/ItemCard.tsx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/ItemCard/ItemCard.tsx b/src/components/ItemCard/ItemCard.tsx index 3c1c13b5..fc36b330 100644 --- a/src/components/ItemCard/ItemCard.tsx +++ b/src/components/ItemCard/ItemCard.tsx @@ -33,7 +33,7 @@ const ItemCard: FC = ({ const { t } = useTranslation(); return ( -
+
{label} {isGaiaXCompliant === undefined ? null : ( @@ -62,3 +62,21 @@ const ItemCard: FC = ({ } export default ItemCard; + +const getTestId = ({ ontology, shape, service, resource }: + { + ontology?: Ontology, + shape?: Shape, + service?: ServiceOffering, + resource?: Resource + }) => ( + ontology + ? 'Card:' + ontology.subject + : shape + ? 'Card:' + shape.shaclShapeName + : service + ? 'Card:' + service.uri + ':' + service.name + : resource + ? 'Card:' + resource.uri + ':' + resource.name + : '' +) From 818e7403427eb0bb4c6f535cb572ad08a5ee6431 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Sun, 6 Oct 2024 19:09:28 +0300 Subject: [PATCH 32/33] Data mapper removed By refactoring the cypher query there is no more need for data mapper. Signed-off-by: Zoltan Magyari --- .../resources/helpers/resourceDataFlow.ts | 3 - src/services/cypherQueryApiService.ts | 66 ++++++++++++------- src/utils/dataMapper.ts | 25 +------ 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/components/resources/helpers/resourceDataFlow.ts b/src/components/resources/helpers/resourceDataFlow.ts index ccf9c6d5..7d7f7b46 100644 --- a/src/components/resources/helpers/resourceDataFlow.ts +++ b/src/components/resources/helpers/resourceDataFlow.ts @@ -1,12 +1,10 @@ import { CypherQueryApiService as cypherQuery } from '../../../services/cypherQueryApiService'; import { Resource } from '../../../types/resources.model'; -import { mapResources } from '../../../utils/dataMapper'; /** * Loads resources for which the following criteria are met: * - the node labels should contain at least one of the selected filters passed in as `typeFilter` param * - the node labels should contain the DataResource label too - * - only main nodes (for which the uri does not start with `pnode://`) are returned as result * * @param resourceTypes only resources with this label will be loaded * @return the list of resources @@ -14,7 +12,6 @@ import { mapResources } from '../../../utils/dataMapper'; export const loadResources = async (resourceTypes: string[]): Promise => cypherQuery .getAllResources(resourceTypes) - .then((resourceInput) => mapResources(resourceInput)) .catch(error => { console.error('Error fetching resources:', error); throw error; diff --git a/src/services/cypherQueryApiService.ts b/src/services/cypherQueryApiService.ts index 1d915c22..853bf9c7 100644 --- a/src/services/cypherQueryApiService.ts +++ b/src/services/cypherQueryApiService.ts @@ -1,6 +1,7 @@ import axios from 'axios'; +import { Resource } from 'types/resources.model'; -import { ISelfDescription, ResourceInput, ServiceOfferingInput } from '../utils/dataMapper'; +import { CypherQueryResult, ServiceOfferingInput } from '../utils/dataMapper'; const getHeaders = () => { return { @@ -18,7 +19,7 @@ function getEndpoint() { * * @param requestBody graph db query request */ -const cypherQuery = async (requestBody: { statement: string }): Promise => { +const cypherQuery = async (requestBody: { statement: string }): Promise => { const endpoint = getEndpoint(); const headers = getHeaders(); @@ -31,7 +32,7 @@ const cypherQuery = async (requestBody: { statement: string }): Promise => return response.data; }) .catch(error => { - console.error(error) + console.error('An error occurred when executing this cypher query:', requestBody.statement, 'Error:', error); throw error }) } @@ -52,7 +53,7 @@ export const CypherQueryApiService = { * * @param claimsGraphUri the id of the resource to be queried */ - async getOneSelfDescriptions(claimsGraphUri: string): Promise { + async getOneSelfDescriptions(claimsGraphUri: string): Promise { const uri = claimsGraphUri.replace(/'/g, '\\\''); return cypherQuery({ statement: `MATCH (n:HDMap) WHERE '${uri}' IN n.claimsGraphUri RETURN properties(n), labels(n) LIMIT 1`, @@ -64,39 +65,56 @@ export const CypherQueryApiService = { * * @param types the list of requested resource types */ - async getAllResources(types: string[]): Promise { + async getAllResources(types: string[]): Promise { if (!types.length) { - return { items: [] }; + return []; } const typeLabels = types.join('\', \''); return cypherQuery({ statement: ` - MATCH (resource) - WHERE ANY (label IN labels(resource) WHERE label IN [ '${typeLabels}']) + MATCH (resource) + WHERE ANY (label IN labels(resource) WHERE label IN ['${typeLabels}']) AND 'DataResource' IN labels(resource) - AND NOT resource.uri STARTS WITH 'bnode://' - - OPTIONAL MATCH(formatProperty) - WHERE resource.uri IN formatProperty.claimsGraphUri - AND ANY(label IN labels(formatProperty) WHERE label CONTAINS 'Format') - - OPTIONAL MATCH(copyrightOwner) - WHERE copyrightOwner.uri = resource.copyrightOwnedBy - - RETURN - properties(resource) AS properties, - labels(resource) AS labels, - properties(formatProperty).type AS format, - properties(copyrightOwner).legalName AS vendor`, - }) + WITH COUNT(resource) AS totalCount, resource + + OPTIONAL MATCH (resource)-[relation]-(nodeProperty) + WITH + properties(resource) AS properties, + labels(resource) AS labels, + COLLECT({ + name: type(relation), + labels: labels(nodeProperty), + properties: properties(nodeProperty) + }) AS nodeProperties, + totalCount + + WITH labels, properties, nodeProperties, + [property IN nodeProperties WHERE property.name = 'format'] AS formatNodeProperty, + [property IN nodeProperties WHERE property.name = 'producedBy'] AS producedByNodeProperty, + totalCount + + RETURN + COALESCE( + HEAD(formatNodeProperty).properties.type, + HEAD(formatNodeProperty).properties.formatType + ) AS format, + HEAD(producedByNodeProperty).properties.legalName AS vendor, + labels, + properties.name AS name, + properties.description AS description, + properties.uri AS uri, + properties.claimsGraphUri AS claimsGraphUri + ORDER BY name, uri + `, + }).then(queryResult => queryResult.items); }, /** * Returns all entries from the cypher db. This method is used for development purposes only, in cases when * available data has to be analysed. */ - async getEverything(): Promise { + async getEverything(): Promise { return cypherQuery({ statement: 'MATCH (n) RETURN properties(n) AS properties, labels(n) AS labels LIMIT 1000', }) diff --git a/src/utils/dataMapper.ts b/src/utils/dataMapper.ts index b77e7e67..395b9163 100644 --- a/src/utils/dataMapper.ts +++ b/src/utils/dataMapper.ts @@ -1,9 +1,10 @@ // This Interface is termporary, due to how we recieve data at the moment. // Interfaces and Mappers for Service Offerings -import { Resource } from '../types/resources.model'; import { ServiceOffering } from '../types/serviceOfferings.model'; +export type CypherQueryResult = { items: T[] } + // TODO: Refactor. See ResourceInput. export interface ServiceOfferingInput { items: Array<{ @@ -34,27 +35,7 @@ export function mapServiceOfferings(selfDescriptions: ServiceOfferingInput): Ser })); } -type ResourceInputProperties = Exclude -export interface ResourceInput { - items: { - vendor: string, - format: string, - labels: string[], - properties: ResourceInputProperties; - }[]; -} - -export function mapResources(selfDescriptions: ResourceInput): Resource[] { - const resources = selfDescriptions - .items.map((selfDescriptionItem) => { - const { properties, ...resource } = selfDescriptionItem; - return { ...resource, ...properties } - }); - console.debug('resources', resources) - return resources; -} - -export interface ISelfDescription { +export interface ISelfDescription extends CypherQueryResult { name: string; description: string; items: Array<{ From 229df5314929549755a3a593fd742cee0320d940 Mon Sep 17 00:00:00 2001 From: Zoltan Magyari Date: Sun, 6 Oct 2024 19:48:57 +0300 Subject: [PATCH 33/33] Fix filter asset asset error and tests - select format asset (Unreal DataSmith) - select type asset that disables the format asset (HdMap) - deselect the same type asset (HdMap) - the resources selected by the (Unreal DataSmith) won't appear even though the filter is selected Signed-off-by: Zoltan Magyari --- .../resources/helpers/resourceFilterHelper.ts | 6 +- ...llResources_HdMap_EnvironmentModel_x2.json | 85 ++++++--------- ...ceFilterState_HdMap_EnvironmentModel_x2.ts | 100 +++++------------- .../resources_HdMap_EnvironmentModel_x2.ts | 70 ++++++------ .../helpers/resourceDataFlow.test.ts | 2 +- .../helpers/resourceFilterHelper.test.ts | 57 ++++++++-- ...esourcesState_HdMap_EnvironmentModel_x2.ts | 58 +++------- tests/services/schemaApiService.test.ts | 2 + tests/utils/readFile.test.ts | 1 + 9 files changed, 159 insertions(+), 222 deletions(-) diff --git a/src/components/resources/helpers/resourceFilterHelper.ts b/src/components/resources/helpers/resourceFilterHelper.ts index 8e1d66f2..1724c4af 100644 --- a/src/components/resources/helpers/resourceFilterHelper.ts +++ b/src/components/resources/helpers/resourceFilterHelper.ts @@ -172,7 +172,7 @@ export const calculateResourceFiltersAssetState = ( const resourcesWithTypeFilterApplied = resources .filter((resource) => { - const selectedAssets = getSelectedAssets(filters.typeAssets) + const selectedAssets = getSelectedAssets(typeAssets) return selectedAssets === 'NOTHING' || selectedAssets .some(type => resource.labels.includes(type)) }); @@ -182,7 +182,7 @@ export const calculateResourceFiltersAssetState = ( const resourcesWithFormatFilterApplied = resourcesWithTypeFilterApplied .filter(resource => { - const selectedAssets = getSelectedAssets(filters.formatAssets) + const selectedAssets = getSelectedAssets(formatAssets) return selectedAssets === 'NOTHING' || selectedAssets .some(format => resource.format === format) }); @@ -192,7 +192,7 @@ export const calculateResourceFiltersAssetState = ( const resourcesWithVendorFilterApplied = resourcesWithFormatFilterApplied .filter(resource => { - const selectedAssets = getSelectedAssets(filters.vendorAssets) + const selectedAssets = getSelectedAssets(vendorAssets) return selectedAssets === 'NOTHING' || selectedAssets .some(vendor => resource.vendor === vendor) }); diff --git a/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json b/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json index 3b52311d..ef0770b1 100644 --- a/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json +++ b/tests/components/resources/helpers/__fixtures__/cypherQuery_getAllResources_HdMap_EnvironmentModel_x2.json @@ -1,79 +1,54 @@ { - "totalCount": 3, + "totalCount": 1, "items": [ { + "claimsGraphUri": [ + "https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a" + ], "vendor": "msg systems ag", - "format": "ASAM OpenDRIVE", - "properties": { - "license": "Apache-2.0", - "expirationDateTime": "2025-05-23T07:23:25", - "copyrightOwnedBy": "https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json", - "claimsGraphUri": [ - "https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114", - "did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8" - ], - "test": "Wird das zusammengemergt?", - "containsPII": "false", - "name": "Generated Data Resource", - "description": "Generated description.", - "obsoleteDateTime": "2025-05-23T07:23:25", - "uri": "did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8", - "policy": "package access_control default allow = false allow { input.method == \"GET\" input.path == \"/public\" } allow { input.method == \"POST\" input.path == \"/private\" input.user.role == \"admin\" }" - }, + "format": "Unreal DataSmith", + "name": "Generated Data Resource", + "description": "Generated description.", + "uri": "https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a", "labels": [ "Resource", - "DataResource", - "HdMap" + "EnvironmentModel", + "DataResource" ] }, { + "claimsGraphUri": [ + "https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", + "https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f" + ], "vendor": "msg systems ag", "format": null, - "properties": { - "license": "Apache-2.0", - "expirationDateTime": "2025-06-17T11:37:14", - "copyrightOwnedBy": "https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json", - "claimsGraphUri": [ - "https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a" - ], - "containsPII": "false", - "name": "Generated Data Resource", - "description": "Generated description.", - "obsoleteDateTime": "2025-06-17T11:37:14", - "uri": "https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a", - "policy": "package access_control default allow = false allow { input.method == \"GET\" input.path == \"/public\" } allow { input.method == \"POST\" input.path == \"/private\" input.user.role == \"admin\" }" - }, + "name": "Generated Data Resource", + "description": "Generated description.", + "uri": "https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", "labels": [ "Resource", "EnvironmentModel", - "DataResource" + "DataResource", + "General" ] }, { + "claimsGraphUri": [ + "https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114", + "did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8" + ], "vendor": "msg systems ag", - "format": null, - "properties": { - "license": "Apache-2.0", - "expirationDateTime": "2025-04-08T14:25:58", - "copyrightOwnedBy": "https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json", - "claimsGraphUri": [ - "https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", - "https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", - "https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", - "https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f" - ], - "containsPII": "false", - "name": "Generated Data Resource", - "description": "Generated description.", - "obsoleteDateTime": "2025-04-08T14:25:58", - "uri": "https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f", - "policy": "package access_control default allow = false allow { input.method == \"GET\" input.path == \"/public\" } allow { input.method == \"POST\" input.path == \"/private\" input.user.role == \"admin\" }" - }, + "format": "ASAM OpenDRIVE", + "name": "Generated Data Resource", + "description": "Generated description.", + "uri": "did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8", "labels": [ "Resource", - "EnvironmentModel", "DataResource", - "General" + "HdMap" ] } ] diff --git a/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts b/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts index 75a4bb9a..18ab77dd 100644 --- a/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts +++ b/tests/components/resources/helpers/__fixtures__/resourceFilterState_HdMap_EnvironmentModel_x2.ts @@ -4,71 +4,52 @@ export const initiallyLoaded_ResourceFilterState = { filteredResources: [ { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', - 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', - format: 'ASAM OpenDRIVE', + format: 'Unreal DataSmith', labels: [ 'Resource', - 'DataResource', - 'HdMap' + 'EnvironmentModel', + 'DataResource' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', - uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', vendor: 'msg systems ag' }, { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' + 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-06-17T11:37:14', format: null, labels: [ 'Resource', 'EnvironmentModel', - 'DataResource' + 'DataResource', + 'General' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-06-17T11:37:14', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', vendor: 'msg systems ag' }, { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-04-08T14:25:58', - format: null, + format: 'ASAM OpenDRIVE', labels: [ 'Resource', - 'EnvironmentModel', 'DataResource', - 'General' + 'HdMap' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-04-08T14:25:58', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', vendor: 'msg systems ag' } ], @@ -137,7 +118,7 @@ export const initiallyLoaded_ResourceFilterState = { value: false }, { - disabled: true, + disabled: false, id: 'Unreal DataSmith', label: 'Unreal DataSmith', type: 'formatAssets', @@ -179,21 +160,14 @@ export const filteredBy_searchText_HdMap_ResourceFilterState = { 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', format: 'ASAM OpenDRIVE', labels: [ 'Resource', 'DataResource', 'HdMap' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', vendor: 'msg systems ag' } @@ -263,7 +237,7 @@ export const filteredBy_searchText_HdMap_ResourceFilterState = { value: false }, { - disabled: true, + disabled: false, id: 'Unreal DataSmith', label: 'Unreal DataSmith', type: 'formatAssets', @@ -305,21 +279,14 @@ export const filteredBy_typeFilter_HdMap_ResourceFilterState = { 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', format: 'ASAM OpenDRIVE', labels: [ 'Resource', 'DataResource', 'HdMap' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', vendor: 'msg systems ag' } @@ -431,21 +398,14 @@ export const filteredBy_formatFilter_ASAMOpenDrive_ResourceFilterState = { 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', format: 'ASAM OpenDRIVE', labels: [ 'Resource', 'DataResource', 'HdMap' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', vendor: 'msg systems ag' } @@ -515,7 +475,7 @@ export const filteredBy_formatFilter_ASAMOpenDrive_ResourceFilterState = { value: false }, { - disabled: true, + disabled: false, id: 'Unreal DataSmith', label: 'Unreal DataSmith', type: 'formatAssets', @@ -554,25 +514,17 @@ export const filteredBy_vendorFilter_MsgSystemsAG_ResourceFilterState = { filteredResources: [ { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', - 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', - format: 'ASAM OpenDRIVE', + format: 'Unreal DataSmith', labels: [ 'Resource', - 'DataResource', - 'HdMap' + 'EnvironmentModel', + 'DataResource' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', - uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', vendor: 'msg systems ag' } ], @@ -641,7 +593,7 @@ export const filteredBy_vendorFilter_MsgSystemsAG_ResourceFilterState = { value: false }, { - disabled: true, + disabled: false, id: 'Unreal DataSmith', label: 'Unreal DataSmith', type: 'formatAssets', diff --git a/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts b/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts index 49511fa8..2e2b9259 100644 --- a/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts +++ b/tests/components/resources/helpers/__fixtures__/resources_HdMap_EnvironmentModel_x2.ts @@ -1,58 +1,52 @@ export const resources_HdMap_EnvironmentModel_x2 = [ { - vendor: 'msg systems ag', - format: 'ASAM OpenDRIVE', - labels: ['Resource', 'DataResource', 'HdMap'], - license: 'Apache-2.0', - expirationDateTime: '2025-05-23T07:23:25', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', - 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' ], - test: 'Wird das zusammengemergt?', - containsPII: 'false', - name: 'Generated Data Resource', - description: 'Generated description.', - obsoleteDateTime: '2025-05-23T07:23:25', - uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }' - }, - { vendor: 'msg systems ag', - format: null, - labels: ['Resource', 'EnvironmentModel', 'DataResource'], - license: 'Apache-2.0', - expirationDateTime: '2025-06-17T11:37:14', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', - claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a', - ], - containsPII: 'false', + format: 'Unreal DataSmith', name: 'Generated Data Resource', description: 'Generated description.', - obsoleteDateTime: '2025-06-17T11:37:14', uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }' + labels: [ + 'Resource', + 'EnvironmentModel', + 'DataResource' + ] }, { - vendor: 'msg systems ag', - format: null, - labels: ['Resource', 'EnvironmentModel', 'DataResource', 'General'], - license: 'Apache-2.0', - expirationDateTime: '2025-04-08T14:25:58', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', claimsGraphUri: [ 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' ], - containsPII: 'false', + vendor: 'msg systems ag', + format: null, name: 'Generated Data Resource', description: 'Generated description.', - obsoleteDateTime: '2025-04-08T14:25:58', uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }' + labels: [ + 'Resource', + 'EnvironmentModel', + 'DataResource', + 'General' + ] + }, + { + claimsGraphUri: [ + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + ], + vendor: 'msg systems ag', + format: 'ASAM OpenDRIVE', + name: 'Generated Data Resource', + description: 'Generated description.', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + labels: [ + 'Resource', + 'DataResource', + 'HdMap' + ] } ]; diff --git a/tests/components/resources/helpers/resourceDataFlow.test.ts b/tests/components/resources/helpers/resourceDataFlow.test.ts index f32935e6..98e5e030 100644 --- a/tests/components/resources/helpers/resourceDataFlow.test.ts +++ b/tests/components/resources/helpers/resourceDataFlow.test.ts @@ -21,7 +21,7 @@ describe('loadResources', () => { const resourceTypes = ['Georeference', 'HdMap', 'EnvironmentModel', 'OSITrace']; it('the backend Data will be transformed to a Resource array', async () => { - getAllResources.mockResolvedValueOnce(resources); + getAllResources.mockResolvedValueOnce(resources.items); const result = await loadResources(resourceTypes); expect(result).toEqual(expectedResources); diff --git a/tests/components/resources/helpers/resourceFilterHelper.test.ts b/tests/components/resources/helpers/resourceFilterHelper.test.ts index d32f1c4c..9353a3a3 100644 --- a/tests/components/resources/helpers/resourceFilterHelper.test.ts +++ b/tests/components/resources/helpers/resourceFilterHelper.test.ts @@ -275,7 +275,7 @@ describe('getAllFormats', () => { it('returns all available formats present in the resources list', () => { const result = getAllFormats(resources_HdMap_EnvironmentModel_x2); - expect(result).toEqual(new Set(['ASAM OpenDRIVE'])); + expect(result).toEqual(new Set(['ASAM OpenDRIVE', 'Unreal DataSmith'])); }) }) @@ -398,7 +398,7 @@ describe('getSelectedAssets', () => { describe('calculateResourceFiltersAssetState', () => { - it('With no selected filter passed in, the resource list will not be filtered,' + + it('With no selected filter passed in, the resource list will not be filtered' + 'the assets are created from ontologies.', () => { const result = calculateResourceFiltersAssetState( ontologies_General_HdMap_EnvironmentModel, @@ -425,7 +425,7 @@ describe('calculateResourceFiltersAssetState', () => { } ]); - expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(2); expect(result.formatAssets).toEqual(expect.arrayContaining([ { id: 'ASAM OpenDRIVE', @@ -434,6 +434,13 @@ describe('calculateResourceFiltersAssetState', () => { value: false, disabled: false }, + { + id: 'Unreal DataSmith', + type: 'formatAssets', + label: 'Unreal DataSmith', + value: false, + disabled: false + } ])); expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) @@ -540,7 +547,16 @@ describe('calculateResourceFiltersAssetState', () => { } ])); - expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(0); + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets).toEqual(expect.arrayContaining([ + { + id: 'Unreal DataSmith', + type: 'formatAssets', + label: 'Unreal DataSmith', + value: false, + disabled: false + } + ])); expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) expect(result.vendorAssets).toEqual([ @@ -577,7 +593,7 @@ describe('calculateResourceFiltersAssetState', () => { } as ResourceFilterState ) - expect(result.filteredResources.length).toEqual(0); + expect(result.filteredResources.length).toEqual(2); expect(result.typeAssets.filter(asset => !asset.value).length).toEqual(1); expect(result.typeAssets).toEqual(expect.arrayContaining([ @@ -590,9 +606,18 @@ describe('calculateResourceFiltersAssetState', () => { } ])); - expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(0); + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets).toEqual(expect.arrayContaining([ + { + id: 'Unreal DataSmith', + type: 'formatAssets', + label: 'Unreal DataSmith', + value: false, + disabled: false + } + ])); - expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(0) + expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1); }) it('Pass in "vendor filter" as previously selected it will filter the resources list', () => { @@ -624,7 +649,7 @@ describe('calculateResourceFiltersAssetState', () => { expect(result.typeAssets.filter(asset => !asset.value).length).toEqual(2); - expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(2); expect(result.formatAssets).toEqual(expect.arrayContaining([ { id: 'ASAM OpenDRIVE', @@ -633,6 +658,13 @@ describe('calculateResourceFiltersAssetState', () => { value: false, disabled: false }, + { + id: 'Unreal DataSmith', + type: 'formatAssets', + label: 'Unreal DataSmith', + value: false, + disabled: false, + } ])); expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(2) @@ -672,7 +704,7 @@ describe('calculateResourceFiltersAssetState', () => { disabled: false } ]); - expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(1); + expect(result.formatAssets.filter(asset => !asset.disabled).length).toEqual(2); expect(result.formatAssets).toEqual(expect.arrayContaining([ { id: 'ASAM OpenDRIVE', @@ -681,6 +713,13 @@ describe('calculateResourceFiltersAssetState', () => { value: false, disabled: false }, + { + id: 'Unreal DataSmith', + label: 'Unreal DataSmith', + type: 'formatAssets', + value: false, + disabled: false, + } ])); expect(result.vendorAssets.filter(asset => !asset.disabled).length).toEqual(1) diff --git a/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts b/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts index cec3317f..7d9730fb 100644 --- a/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts +++ b/tests/components/resources/hooks/__fixtures__/resourcesState_HdMap_EnvironmentModel_x2.ts @@ -64,7 +64,7 @@ export const initiallyLoaded_ResourcesState = { value: false }, { - disabled: true, + disabled: false, id: 'Unreal DataSmith', label: 'Unreal DataSmith', type: 'formatAssets', @@ -74,64 +74,45 @@ export const initiallyLoaded_ResourcesState = { resources: [ { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', - 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' + 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', - format: 'ASAM OpenDRIVE', + format: 'Unreal DataSmith', labels: [ - 'HdMap' + 'EnvironmentModel' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', - uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', vendor: 'msg systems ag' }, { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/physical-resource/57232ba1-7310-4f79-b64c-6793b378d76a' + 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-06-17T11:37:14', format: null, labels: [ 'EnvironmentModel' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-06-17T11:37:14', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/57232ba1-7310-4f79-b64c-6793b378d76a', + uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', vendor: 'msg systems ag' }, { claimsGraphUri: [ - 'https://www.gaia-x4plcaad.info/claims/service-access-point/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/virtual-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', - 'https://www.gaia-x4plcaad.info/claims/physical-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f' + 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', + 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-04-08T14:25:58', - format: null, + format: 'ASAM OpenDRIVE', labels: [ - 'EnvironmentModel' + 'HdMap' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-04-08T14:25:58', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - uri: 'https://www.gaia-x4plcaad.info/claims/data-resource/fe9f0d7f-3a80-48ef-9630-a7c9c3c1e78f', + uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', vendor: 'msg systems ag' } ], @@ -229,7 +210,7 @@ export const filteredBy_searchText_HdMap_ResourcesState = { value: false }, { - disabled: true, + disabled: false, id: 'Unreal DataSmith', label: 'Unreal DataSmith', type: 'formatAssets', @@ -242,19 +223,12 @@ export const filteredBy_searchText_HdMap_ResourcesState = { 'https://www.gaia-x4plcaad.info/claims/physical-resource/01a9590e-e872-470f-b400-aaa513499114', 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8' ], - containsPII: 'false', - copyrightOwnedBy: 'https://participant.gxfs.gx4fm.org/msg-systems-ag/legalParticipant.json', description: 'Generated description.', - expirationDateTime: '2025-05-23T07:23:25', format: 'ASAM OpenDRIVE', labels: [ 'HdMap' ], - license: 'Apache-2.0', name: 'Generated Data Resource', - obsoleteDateTime: '2025-05-23T07:23:25', - policy: 'package access_control default allow = false allow { input.method == "GET" input.path == "/public" } allow { input.method == "POST" input.path == "/private" input.user.role == "admin" }', - test: 'Wird das zusammengemergt?', uri: 'did:web:registry.gaia-x.eu:HdMap:wDgNY3gZAxMe3LjhdAZ9TbPiYnQ-yybNhCu8', vendor: 'msg systems ag' } diff --git a/tests/services/schemaApiService.test.ts b/tests/services/schemaApiService.test.ts index bc09934b..da26844a 100644 --- a/tests/services/schemaApiService.test.ts +++ b/tests/services/schemaApiService.test.ts @@ -11,6 +11,8 @@ const hdmap_shacl_ttl = readFile('tests/__fixtures__/hdmap_shacl.ttl'); const post = jest.spyOn(axios, 'post'); const get = jest.spyOn(axios, 'get'); +console.error = jest.fn() // Disable error log + describe('getConvertedFile', () => { beforeEach(() => { get.mockReset(); diff --git a/tests/utils/readFile.test.ts b/tests/utils/readFile.test.ts index 1b3e82c6..b739694e 100644 --- a/tests/utils/readFile.test.ts +++ b/tests/utils/readFile.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from '@jest/globals'; import { readFile } from '../../src/utils/readFile'; console.error = jest.fn(); // Disable error log +console.log = jest.fn(); // Disable console log describe('readFile', () => { it('reads content', async () => {