Skip to content

Commit

Permalink
feat(composer): auto query for indicator and overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
sheilaXu authored and TheEvilDev committed Aug 14, 2023
1 parent cdf1caa commit b597c6f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useStore } from '../../../store';
import { dataBindingValuesProvider } from '../../../utils/dataBindingUtils';
import { replaceBindingVariables } from '../../../utils/dataBindingVariableUtils';
import { ReactMarkdownWrapper } from '../../wrappers/ReactMarkdownWrapper';
import useBindingData from '../../../hooks/useBindingData';

import { tmAnnotationRow } from './styles';

Expand All @@ -27,26 +28,26 @@ export const DataOverlayDataRow = ({
const dataBindingTemplate = useStore(sceneComposerId)((state) => state.dataBindingTemplate);
const isEditing = useStore(sceneComposerId)((state) => state.isEditing());
const isAnnotation = overlayType === Component.DataOverlaySubType.TextAnnotation;
const bindings = useMemo(() => valueDataBindings.map((b) => b.valueDataBinding ?? {}), [valueDataBindings]);
const bindingData = useBindingData(bindings);

const [stringContent, setStringContent] = useState<string>('');

const bindingValuesMap: Record<string, string> = useMemo(() => {
const result = {};
valueDataBindings.forEach((binding) => {
valueDataBindings.forEach((binding, index) => {
if (!binding.valueDataBinding) {
return;
}
const values: Record<string, Primitive> = dataBindingValuesProvider(
dataInput,
binding.valueDataBinding,
dataBindingTemplate,
);
const values: Record<string, Primitive> =
bindingData.data?.at(index) ??
dataBindingValuesProvider(dataInput, binding.valueDataBinding, dataBindingTemplate);
result[binding.bindingName] =
values[(binding.valueDataBinding.dataBindingContext as ITwinMakerEntityDataBindingContext).propertyName];
});

return result;
}, [valueDataBindings, dataInput, dataBindingTemplate]);
}, [valueDataBindings, dataInput, dataBindingTemplate, bindingData]);

const updateContentWithBindingVariables = useCallback(
(content: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { DataOverlayDataRow } from '../DataOverlayDataRow';
import { useStore } from '../../../../store';
import { IDataInput } from '../../../../interfaces';

jest.mock('../../../../hooks/useBindingData', () => jest.fn().mockReturnValue({ data: [{ 'prop-1': 'ACTIVE' }] }));

jest.mock('../../../wrappers/ReactMarkdownWrapper', () => ({
ReactMarkdownWrapper: (...props: unknown[]) => <div data-testid='ReactMarkdownWrapper'>{JSON.stringify(props)}</div>,
}));
Expand All @@ -23,6 +25,10 @@ describe('DataOverlayDataRow', () => {
},
},
];
const randomBinding = {
valueDataBinding: { dataBindingContext: { entityId: 'eid', propertyName: 'test' } },
bindingName: 'binding-b',
};
const mockDataInput: IDataInput = {
dataFrames: [
{
Expand Down Expand Up @@ -96,7 +102,7 @@ describe('DataOverlayDataRow', () => {
<DataOverlayDataRow
rowData={row}
overlayType={Component.DataOverlaySubType.TextAnnotation}
valueDataBindings={valueDataBindings}
valueDataBindings={[...valueDataBindings, randomBinding]}
/>,
);
expect(container).toMatchSnapshot();
Expand All @@ -113,10 +119,27 @@ describe('DataOverlayDataRow', () => {
<DataOverlayDataRow
rowData={row}
overlayType={Component.DataOverlaySubType.TextAnnotation}
valueDataBindings={valueDataBindings}
valueDataBindings={[randomBinding, ...valueDataBindings]}
/>,
);
expect(container).toMatchSnapshot();
});
});

it('should render markdown row with data binding variable correctly in viewing mode from useBindingData', () => {
const row: Component.DataOverlayMarkdownRow = {
rowType: Component.DataOverlayRowType.Markdown,
content: '# content ${binding-a}',
};
isEditingMock.mockReturnValue(false);

const { container } = render(
<DataOverlayDataRow
rowData={row}
overlayType={Component.DataOverlaySubType.TextAnnotation}
valueDataBindings={[...valueDataBindings, randomBinding]}
/>,
);
expect(container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,13 @@ exports[`DataOverlayDataRow Markdown should render markdown row with data bindin
</div>
</div>
`;

exports[`DataOverlayDataRow should render markdown row with data binding variable correctly in viewing mode from useBindingData 1`] = `
<div>
<div
data-testid="ReactMarkdownWrapper"
>
[{"style":{"whiteSpace":"nowrap"},"content":"# content ACTIVE"},{}]
</div>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { getComponentGroupName } from '../../../utils/objectThreeUtils';
import { Component } from '../../../models/SceneModels';
import { dataBindingValuesProvider, ruleEvaluator } from '../../../utils/dataBindingUtils';
import { getSceneResourceInfo, parseColorWithAlpha } from '../../../utils/sceneResourceUtils';
import { KnownComponentType, SceneResourceType } from '../../../interfaces';
import { IValueDataBinding, KnownComponentType, SceneResourceType } from '../../../interfaces';
import useBindingData from '../../../hooks/useBindingData';

import { LinearPlaneMotionIndicator } from './LinearPlaneMotionIndicator';
import { LinearCylinderMotionIndicator } from './LinearCylinderMotionIndicator';
Expand Down Expand Up @@ -45,23 +46,38 @@ const MotionIndicatorComponent: React.FC<IMotionIndicatorComponentProps> = ({
),
);

const orderedBindingNames = useMemo(() => Object.keys(component.valueDataBindings), [component.valueDataBindings]);
const orderedBindings: IValueDataBinding[] = useMemo(
() => orderedBindingNames.map((name) => component.valueDataBindings[name].valueDataBinding),
[orderedBindingNames, component.valueDataBindings],
);
const orderedBindingData = useBindingData(orderedBindings);

const speed = useMemo(() => {
if (
component.config.defaultSpeed !== undefined &&
!component.valueDataBindings[Component.MotionIndicatorDataBindingName.Speed]?.ruleBasedMapId
) {
return component.config.defaultSpeed;
}
const values: Record<string, Primitive> = dataBindingValuesProvider(
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.Speed]?.valueDataBinding,
dataBindingTemplate,
);

const bindingIndex = orderedBindingNames.indexOf(Component.MotionIndicatorDataBindingName.Speed);
const bindingData = orderedBindingData.data?.at(bindingIndex);

const values: Record<string, Primitive> =
bindingData ??
dataBindingValuesProvider(
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.Speed]?.valueDataBinding,
dataBindingTemplate,
);

const result = ruleEvaluator(0, values, speedRule) as number;
return result >= 0 ? result : 0;
}, [
speedRule,
orderedBindingData,
orderedBindingNames,
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.Speed]?.valueDataBinding,
component.config.defaultSpeed,
Expand All @@ -77,11 +93,16 @@ const MotionIndicatorComponent: React.FC<IMotionIndicatorComponentProps> = ({
return new Color(defaultColor);
}

const values: Record<string, Primitive> = dataBindingValuesProvider(
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.ForegroundColor]?.valueDataBinding,
dataBindingTemplate,
);
const bindingIndex = orderedBindingNames.indexOf(Component.MotionIndicatorDataBindingName.ForegroundColor);
const bindingData = orderedBindingData.data?.at(bindingIndex);

const values: Record<string, Primitive> =
bindingData ??
dataBindingValuesProvider(
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.ForegroundColor]?.valueDataBinding,
dataBindingTemplate,
);
const result = ruleEvaluator('', values, foregroundColorRule);
const ruleTargetInfo = getSceneResourceInfo(result as string);

Expand All @@ -92,6 +113,8 @@ const MotionIndicatorComponent: React.FC<IMotionIndicatorComponentProps> = ({
: undefined;
}, [
foregroundColorRule,
orderedBindingData,
orderedBindingNames,
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.ForegroundColor]?.valueDataBinding,
component.config.defaultForegroundColor,
Expand All @@ -106,11 +129,16 @@ const MotionIndicatorComponent: React.FC<IMotionIndicatorComponentProps> = ({
return new Color(defaultColor);
}

const values: Record<string, Primitive> = dataBindingValuesProvider(
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.BackgroundColor]?.valueDataBinding,
dataBindingTemplate,
);
const bindingIndex = orderedBindingNames.indexOf(Component.MotionIndicatorDataBindingName.BackgroundColor);
const bindingData = orderedBindingData.data?.at(bindingIndex);

const values: Record<string, Primitive> =
bindingData ??
dataBindingValuesProvider(
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.BackgroundColor]?.valueDataBinding,
dataBindingTemplate,
);
const result = ruleEvaluator('', values, backgroundColorRule);
const ruleTargetInfo = getSceneResourceInfo(result as string);

Expand All @@ -121,6 +149,8 @@ const MotionIndicatorComponent: React.FC<IMotionIndicatorComponentProps> = ({
: undefined;
}, [
backgroundColorRule,
orderedBindingData,
orderedBindingNames,
dataInput,
component.valueDataBindings[Component.MotionIndicatorDataBindingName.BackgroundColor]?.valueDataBinding,
component.config.defaultBackgroundColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Component } from '../../../../models/SceneModels';
import { getSceneResourceInfo } from '../../../../utils/sceneResourceUtils';
import { dataBindingValuesProvider, ruleEvaluator } from '../../../../utils/dataBindingUtils';

jest.mock('../../../../hooks/useBindingData', () => jest.fn().mockReturnValue({ data: [{ alarm_status: 'ACTIVE' }] }));

jest.mock('../LinearPlaneMotionIndicator', () => ({
LinearPlaneMotionIndicator: (...props: any[]) => <div data-testid='linear-plane'>{JSON.stringify(props)}</div>,
}));
Expand Down Expand Up @@ -69,18 +71,25 @@ describe('MotionIndicatorComponent', () => {
};

beforeEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();

mockGetSceneResourceInfo.mockReturnValue({ type: SceneResourceType.Color, value: 'black' });
mockDataBindingValuesProvider.mockReturnValue({});
mockRuleEvaluator.mockReturnValue(3);
mockGetSceneRuleMapById.mockImplementation((id) => id);
});

it('should render with correct speed and values from rule evaluating', async () => {
useStore('default').setState(baseState);

const { container } = render(<MotionIndicatorComponent node={mockNode} component={mockComponent} />);

expect(container).toMatchSnapshot();
expect(mockRuleEvaluator).toBeCalledTimes(3);
expect(mockRuleEvaluator).toHaveBeenNthCalledWith(1, 0, { alarm_status: 'ACTIVE' }, 40);
expect(mockRuleEvaluator).toHaveBeenNthCalledWith(2, '', {}, 41);
expect(mockRuleEvaluator).toHaveBeenNthCalledWith(3, '', {}, 42);
expect(mockDataBindingValuesProvider).toBeCalledTimes(2);
});

it('should render with correct default values from config when dataBinding not set', async () => {
Expand All @@ -91,5 +100,7 @@ describe('MotionIndicatorComponent', () => {
<MotionIndicatorComponent node={mockNode} component={{ ...mockComponent, valueDataBindings: {} }} />,
);
expect(container).toMatchSnapshot();
expect(mockRuleEvaluator).not.toBeCalled();
expect(mockDataBindingValuesProvider).not.toBeCalled();
});
});

0 comments on commit b597c6f

Please sign in to comment.