Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react-components): fdm support in rule based core #4706

Merged
merged 39 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1bf19c7
add a hook to get all instances from all direct connections and merge…
danpriori Aug 2, 2024
2a4a932
move direct connection with properties hook and adapt the initial fun…
danpriori Aug 7, 2024
4178c29
adapting styling groups accross components to support fdm styling gro…
danpriori Aug 8, 2024
072ddbc
insert fdm types for rule type definitions
danpriori Aug 9, 2024
062d32a
refactoring expression types
danpriori Aug 9, 2024
cc21e37
add datetime and boolean expressions statements
danpriori Aug 11, 2024
6c064fb
refactoring and add property trigger for numeric expression supportin…
danpriori Aug 11, 2024
0c00b6b
add optional parameters for the fdm typing type
danpriori Aug 12, 2024
9652578
fix property types
danpriori Aug 13, 2024
94990d4
fix date statement and fdm externalid for styling list
danpriori Aug 14, 2024
c761767
fix datetime limit type for between and notbetween
danpriori Aug 14, 2024
01b96bc
add expression safeguards
danpriori Aug 14, 2024
79e8b04
refactoring and remove duplicated timeserie ids when traversing expre…
danpriori Aug 15, 2024
eacfd1e
update and export fdm types and some cleanup
danpriori Aug 15, 2024
84e41d4
add fdm new conditions
danpriori Aug 15, 2024
547b33a
stories cleanup
danpriori Aug 15, 2024
bc5759e
cleanup fdmsdk log
danpriori Aug 15, 2024
7c3023d
Merge branch 'master' into danpriori/BND3D-4440-fdm-support-in-rule-b…
danpriori Aug 16, 2024
cb5a96b
use isLoading flag for the spinner accuracy and some refactoring on l…
danpriori Aug 16, 2024
c01a542
reduce complexity a bit
danpriori Aug 17, 2024
52e3dc3
refactoring for some small optimizations
danpriori Aug 17, 2024
e2f3a47
lint fix
danpriori Aug 17, 2024
6dcaf86
export fdm types for rule based
danpriori Aug 23, 2024
b431279
refactoring some rule type definitions to support correct typing data
danpriori Aug 24, 2024
bae8c30
fix datetimecondition definition
danpriori Aug 24, 2024
d92aefc
fix boolean condition types and export unique types list for numeric …
danpriori Aug 26, 2024
38609cc
add into index
danpriori Aug 26, 2024
df1d9c4
dont request assetids from ts if it is empty
danpriori Aug 27, 2024
de9d55a
changes from cr
danpriori Aug 28, 2024
d49a527
Merge branch 'master' into danpriori/BND3D-4440-fdm-support-in-rule-b…
danpriori Aug 28, 2024
96e4e6f
Merge branch 'danpriori/BND3D-4440-fdm-support-in-rule-based-core' of…
danpriori Aug 28, 2024
38b69a9
lint fix
danpriori Aug 28, 2024
349a1cd
Merge branch 'master' into danpriori/BND3D-4440-fdm-support-in-rule-b…
danpriori Aug 28, 2024
cca35f4
Merge remote-tracking branch 'origin/master' into danpriori/BND3D-444…
danpriori Aug 28, 2024
9137322
Merge branch 'danpriori/BND3D-4440-fdm-support-in-rule-based-core' of…
danpriori Aug 28, 2024
8678ff5
Merge branch 'master' into danpriori/BND3D-4440-fdm-support-in-rule-b…
danpriori Aug 28, 2024
84b9713
use createFdmKey - cr
danpriori Aug 28, 2024
9a85ccf
Merge branch 'danpriori/BND3D-4440-fdm-support-in-rule-based-core' of…
danpriori Aug 28, 2024
2b9a892
add createFdmKey for uniqBy
danpriori Aug 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import { Button, Dropdown, Menu, Tooltip as CogsTooltip } from '@cognite/cogs.js
import { RuleBasedOutputsSelector } from '../RuleBasedOutputs/RuleBasedOutputsSelector';
import {
type EmptyRuleForSelection,
type AssetStylingGroupAndStyleIndex,
type RuleAndEnabled
type RuleAndEnabled,
type AllMappingStylingGroupAndStyleIndex,
type AllRuleBasedStylingGroups
} from '../RuleBasedOutputs/types';
import { useTranslation } from '../i18n/I18n';
import { useFetchRuleInstances } from '../RuleBasedOutputs/hooks/useFetchRuleInstances';
import { use3dModels } from '../../hooks/use3dModels';
import { type AssetStylingGroup } from '../..';
import { type CadModelOptions } from '../Reveal3DResources/types';
import { useAssetMappedNodesForRevisions } from '../CacheProvider/AssetMappingAndNode3DCacheProvider';
import { RuleBasedSelectionItem } from '../RuleBasedOutputs/components/RuleBasedSelectionItem';
import { generateEmptyRuleForSelection, getRuleBasedById } from '../RuleBasedOutputs/utils';
import { useReveal3DResourcesStylingLoading } from '../Reveal3DResources/Reveal3DResourcesInfoContext';

type RuleBasedOutputsButtonProps = {
onRuleSetStylingChanged?: (stylings: AssetStylingGroup[] | undefined) => void;
onRuleSetStylingChanged?: (stylings: AllRuleBasedStylingGroups | undefined) => void;
onRuleSetSelectedChanged?: (ruleSet: RuleAndEnabled | undefined) => void;
};
export const RuleBasedOutputsButton = ({
Expand All @@ -36,7 +36,7 @@ export const RuleBasedOutputsButton = ({
const [currentRuleSetEnabled, setCurrentRuleSetEnabled] = useState<RuleAndEnabled>();
const [emptyRuleSelected, setEmptyRuleSelected] = useState<EmptyRuleForSelection>();
const [currentStylingGroups, setCurrentStylingGroups] = useState<
AssetStylingGroupAndStyleIndex[] | undefined
AllMappingStylingGroupAndStyleIndex[] | undefined
>();
const [ruleInstances, setRuleInstances] = useState<RuleAndEnabled[] | undefined>();

Expand All @@ -47,6 +47,8 @@ export const RuleBasedOutputsButton = ({
const [newRuleSetEnabled, setNewRuleSetEnabled] = useState<RuleAndEnabled>();
const isRuleLoadingFromContext = useReveal3DResourcesStylingLoading();

const [isAllMappingsFetched, setIsAllMappingsFetched] = useState(false);

const { data: ruleInstancesResult } = useFetchRuleInstances();

useEffect(() => {
Expand All @@ -64,11 +66,13 @@ export const RuleBasedOutputsButton = ({

useEffect(() => {
const hasRuleLoading =
currentStylingGroups !== undefined &&
currentStylingGroups.length > 0 &&
isRuleLoadingFromContext;
(currentStylingGroups !== undefined &&
currentStylingGroups.length > 0 &&
isRuleLoadingFromContext) ||
!isAllMappingsFetched;

setIsRuleLoading(hasRuleLoading);
}, [isRuleLoadingFromContext, currentStylingGroups]);
}, [isAllMappingsFetched, currentStylingGroups, isRuleLoadingFromContext, newRuleSetEnabled]);

const onChange = useCallback(
(data: string | undefined): void => {
Expand All @@ -89,19 +93,28 @@ export const RuleBasedOutputsButton = ({
emptySelection.isEnabled = true;
if (onRuleSetStylingChanged !== undefined) onRuleSetStylingChanged(undefined);
}

setEmptyRuleSelected(emptySelection);
setNewRuleSetEnabled(selectedRule);
},
[ruleInstances, onRuleSetStylingChanged, onRuleSetSelectedChanged]
[ruleInstances, emptyRuleSelected, onRuleSetStylingChanged, onRuleSetSelectedChanged]
);

const ruleSetStylingChanged = (
stylingGroups: AssetStylingGroupAndStyleIndex[] | undefined
stylingGroups: AllMappingStylingGroupAndStyleIndex[] | undefined
): void => {
setCurrentStylingGroups(stylingGroups);
const assetStylingGroups = stylingGroups?.map((group) => group.assetStylingGroup);
if (onRuleSetStylingChanged !== undefined) onRuleSetStylingChanged(assetStylingGroups);
const assetStylingGroups = stylingGroups?.map(
(group) => group.assetMappingsStylingGroupAndIndex.assetStylingGroup
);
const fdmStylingGroups = stylingGroups?.map(
(group) => group.fdmStylingGroupAndStyleIndex.fdmStylingGroup
);
const allStylingGroups: AllRuleBasedStylingGroups = {
assetStylingGroup: assetStylingGroups ?? [],
fdmStylingGroup: fdmStylingGroups ?? []
};

if (onRuleSetStylingChanged !== undefined) onRuleSetStylingChanged(allStylingGroups);
};

if (ruleInstances === undefined || ruleInstances.length === 0) {
Expand Down Expand Up @@ -158,6 +171,7 @@ export const RuleBasedOutputsButton = ({
{ruleInstances !== undefined && ruleInstances?.length > 0 && (
<RuleBasedOutputsSelector
onRuleSetChanged={ruleSetStylingChanged}
onAllMappingsFetched={setIsAllMappingsFetched}
ruleSet={currentRuleSetEnabled?.rule.properties}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
/*!
* Copyright 2024 Cognite AS
*/
import { useEffect, type ReactElement, useState } from 'react';
import { useEffect, type ReactElement, useState, useMemo } from 'react';

import { CogniteCadModel } from '@cognite/reveal';
import { type RuleOutputSet, type AssetStylingGroupAndStyleIndex } from './types';
import {
type RuleOutputSet,
type AllMappingStylingGroupAndStyleIndex,
type FdmInstanceNodeWithConnectionAndProperties
} from './types';
import { generateRuleBasedOutputs } from './utils';
import { use3dModels } from '../../hooks/use3dModels';
import { type Datapoints, type Asset, type AssetMapping3D } from '@cognite/sdk';
Expand All @@ -18,17 +22,21 @@ import { useCreateAssetMappingsMapPerModel } from '../../hooks/useCreateAssetMap
import { useExtractUniqueAssetIdsFromMapped } from './hooks/useExtractUniqueAssetIdsFromMapped';
import { useConvertAssetMetadatasToLowerCase } from './hooks/useConvertAssetMetadatasToLowerCase';
import { useExtractTimeseriesIdsFromRuleSet } from './hooks/useExtractTimeseriesIdsFromRuleSet';
import { useMappedEdgesForRevisions } from '../CacheProvider/NodeCacheProvider';
import { useAll3dDirectConnectionsWithProperties } from '../../query/useAll3dDirectConnectionsWithProperties';

const ruleSetStylingCache = new Map<string, AllMappingStylingGroupAndStyleIndex[]>();

export type ColorOverlayProps = {
ruleSet: RuleOutputSet | undefined;
onRuleSetChanged?: (currentStylings: AssetStylingGroupAndStyleIndex[] | undefined) => void;
onRuleSetChanged?: (currentStylings: AllMappingStylingGroupAndStyleIndex[] | undefined) => void;
onAllMappingsFetched: (value: boolean) => void;
};

const ruleSetStylingCache = new Map<string, AssetStylingGroupAndStyleIndex[]>();

export function RuleBasedOutputsSelector({
ruleSet,
onRuleSetChanged
onRuleSetChanged,
onAllMappingsFetched
}: ColorOverlayProps): ReactElement | undefined {
if (ruleSet === undefined) return;

Expand All @@ -42,17 +50,44 @@ export function RuleBasedOutputsSelector({
return { type: 'cad', modelId: model.modelId, revisionId: model.revisionId };
});

const { data: assetMappings } = useAssetMappedNodesForRevisions(cadModels);
const { data: assetMappings, isLoading: isAssetMappingsLoading } =
useAssetMappedNodesForRevisions(cadModels);

const assetIdsFromMapped = useExtractUniqueAssetIdsFromMapped(assetMappings);

const { data: mappedAssets, isFetched } = useAssetsByIdsQuery(assetIdsFromMapped);
const {
data: mappedAssets,
isLoading: isAssetMappedLoading,
isFetched: isAssetMappingsFetched
} = useAssetsByIdsQuery(assetIdsFromMapped);

const { data: fdmMappedEquipmentEdges, isLoading: isFdmMappingsEdgesLoading } =
useMappedEdgesForRevisions(cadModels, true);

const fdmConnectionWithNodeAndViewList = useMemo(() => {
return fdmMappedEquipmentEdges !== undefined
? Array.from(fdmMappedEquipmentEdges.values()).flat()
: [];
}, [fdmMappedEquipmentEdges]);

const { data: fdmMappings, isLoading: isFdmMappingsLoading } =
useAll3dDirectConnectionsWithProperties(fdmConnectionWithNodeAndViewList);

const allMappingsLoaded =
!isAssetMappingsLoading &&
!isAssetMappedLoading &&
!isFdmMappingsEdgesLoading &&
!isFdmMappingsLoading;

useEffect(() => {
if (isFetched) {
if (isAssetMappingsFetched) {
setAllContextualizedAssets(mappedAssets);
}
}, [mappedAssets, isFetched]);
}, [mappedAssets, isAssetMappingsFetched]);

useEffect(() => {
onAllMappingsFetched(allMappingsLoaded);
}, [allMappingsLoaded]);

const contextualizedAssetNodes = useConvertAssetMetadatasToLowerCase(allContextualizedAssets);

Expand All @@ -67,9 +102,10 @@ export function RuleBasedOutputsSelector({
const flatAssetsMappingsListPerModel = useCreateAssetMappingsMapPerModel(models, assetMappings);

useEffect(() => {
if (assetMappings === undefined || models === undefined || !isFetched) return;
if ((assetMappings === undefined && fdmMappings === undefined) || models === undefined) return;
if (timeseriesExternalIds.length > 0 && isLoadingAssetIdsAndTimeseriesData) return;
if (ruleSet === undefined) return;
if (!allMappingsLoaded) return;

const ruleBasedInitilization = async (): Promise<void> => {
const allStylings = await Promise.all(
Expand All @@ -81,50 +117,63 @@ export function RuleBasedOutputsSelector({
const flatAssetsMappingsList = flatAssetsMappingsListPerModel.get(model) ?? [];

if (flatAssetsMappingsList.length === 0) return [];
const stylings = await initializeRuleBasedOutputs({
assetMappings: flatAssetsMappingsList,

const mappingsStylings = await initializeRuleBasedOutputs({
assetMappings: flatAssetsMappingsList ?? [],
fdmMappings: fdmMappings ?? [],
contextualizedAssetNodes,
ruleSet,
assetIdsAndTimeseries: assetIdsWithTimeseriesData?.assetIdsWithTimeseries ?? [],
timeseriesDatapoints: assetIdsWithTimeseriesData?.timeseriesDatapoints ?? []
});
const filteredStylings = stylings.flat().filter(isDefined);
return filteredStylings;

return mappingsStylings;
})
);
const filteredStylings = allStylings.flat().filter(isDefined).flat();
ruleSetStylingCache.set(ruleSet.id, filteredStylings);

ruleSetStylingCache.set(ruleSet.id, filteredStylings);
if (onRuleSetChanged !== undefined) {
onRuleSetChanged(filteredStylings);
}
};
if (!ruleSetStylingCache.has(ruleSet.id)) {
void ruleBasedInitilization();
} else {
onAllMappingsFetched(true);
if (onRuleSetChanged !== undefined) onRuleSetChanged(ruleSetStylingCache.get(ruleSet.id));
}
}, [isLoadingAssetIdsAndTimeseriesData, ruleSet, assetMappings, allContextualizedAssets]);
}, [
ruleSet,
assetMappings,
fdmMappings,
contextualizedAssetNodes,
assetIdsWithTimeseriesData,
models
]);

return <></>;
}

async function initializeRuleBasedOutputs({
assetMappings,
fdmMappings,
contextualizedAssetNodes,
ruleSet,
assetIdsAndTimeseries,
timeseriesDatapoints
}: {
assetMappings: AssetMapping3D[];
fdmMappings: FdmInstanceNodeWithConnectionAndProperties[];
contextualizedAssetNodes: Asset[];
ruleSet: RuleOutputSet;
assetIdsAndTimeseries: AssetIdsAndTimeseries[];
timeseriesDatapoints: Datapoints[] | undefined;
}): Promise<AssetStylingGroupAndStyleIndex[]> {
}): Promise<AllMappingStylingGroupAndStyleIndex[]> {
const collectionStylings = await generateRuleBasedOutputs({
contextualizedAssetNodes,
assetMappings,
fdmMappings,
ruleSet,
assetIdsAndTimeseries,
timeseriesDatapoints
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*!
* Copyright 2024 Cognite AS
*/

import { type FdmPropertyType } from '../../Reveal3DResources/types';
import { type Expression, type TriggerTypeData } from '../types';
import { getFdmPropertyTrigger } from '../utils';

export const checkBooleanExpressionStatement = (
triggerTypeData: TriggerTypeData[],
expression: Expression
): boolean | undefined => {
const condition = expression.type === 'booleanExpression' ? expression.condition : undefined;
const trigger = expression.type === 'booleanExpression' ? expression.trigger : undefined;

let expressionResult: boolean | undefined = false;

if (condition === undefined || trigger === undefined) return;

const currentTriggerData = triggerTypeData.find(
(triggerType) => triggerType.type === trigger?.type
);

const isFdmTrigger = trigger?.type === 'fdm' && currentTriggerData?.type === 'fdm';

if (isFdmTrigger && currentTriggerData.instanceNode.items.length === 0) return;

const fdmItemsTrigger =
isFdmTrigger && currentTriggerData.instanceNode.items[0] !== undefined
? currentTriggerData.instanceNode.items[0]
: undefined;

const fdmPropertyTrigger = isFdmTrigger
? (fdmItemsTrigger?.properties as FdmPropertyType<unknown>)
: undefined;

const propertyTrigger = getFdmPropertyTrigger<boolean>(fdmPropertyTrigger, trigger);

switch (condition.type) {
case 'equals': {
expressionResult = propertyTrigger === true;
break;
}
case 'notEquals': {
expressionResult = propertyTrigger === false;
break;
}
}
return expressionResult;
};
Loading
Loading