Skip to content

Commit

Permalink
feat(scene composer): entity data binding UI changes and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
divya-sea authored and mukeshsahay committed May 25, 2023
1 parent 15fe82e commit f1f81b8
Show file tree
Hide file tree
Showing 22 changed files with 184 additions and 233 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/scene-composer/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = {
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/explicit-module-boundary-types': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'formatjs/no-offset': 'error',
'formatjs/blocklist-elements': [2, ['plural', 'selectordinal', 'select']],
Expand Down
2 changes: 1 addition & 1 deletion packages/scene-composer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
"lines": 76.97,
"statements": 76.38,
"functions": 75.51,
"branches": 61.1,
"branches": 61.09,
"branchesTrue": 100
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/scene-composer/src/components/StateManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
useViewOptionState,
} from '../store';
import { getCameraSettings } from '../utils/cameraUtils';
import { applyDataBindingTemplate, extractEntityId } from '../utils/dataBindingTemplateUtils';
import { applyDataBindingTemplate } from '../utils/dataBindingTemplateUtils';
import { combineTimeSeriesData, convertDataStreamsToDataInput } from '../utils/dataStreamUtils';
import { findComponentByType } from '../utils/nodeUtils';
import sceneDocumentSnapshotCreator from '../utils/sceneDocumentSnapshotCreator';
Expand Down Expand Up @@ -180,9 +180,9 @@ const StateManager: React.FC<SceneComposerInternalProps> = ({
// will always have only one entity data.
if (entityBindingComponent) {
additionalComponentData?.push({
dataBindingContext: !entityBindingComponent?.valueDataBindings?.[0].valueDataBinding?.dataBindingContext
dataBindingContext: !entityBindingComponent?.valueDataBinding?.dataBindingContext
? undefined
: extractEntityId(entityBindingComponent?.valueDataBindings?.[0].valueDataBinding),
: entityBindingComponent?.valueDataBinding?.dataBindingContext,
});
}
onSelectionChanged({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { render, screen, fireEvent, act } from '@testing-library/react';

import { useStore } from '../../store';
import { setFeatureConfig, setMetricRecorder } from '../../common/GlobalSettings';
import { COMPOSER_FEATURES, KnownComponentType } from '../../interfaces';
import { Component } from '../../models/SceneModels';

import { useStore } from '../../store';
import { AddComponentMenu } from './AddComponentMenu';

describe('AddComponentMenu', () => {
Expand Down Expand Up @@ -40,7 +39,7 @@ describe('AddComponentMenu', () => {
],
});

render(<AddComponentMenu />);
render(<AddComponentMenu/>);
const addOverlayButton = screen.getByTestId('add-component-overlay');

act(() => {
Expand Down Expand Up @@ -92,53 +91,41 @@ describe('AddComponentMenu', () => {
},
],
});

render(<AddComponentMenu />);
const addButton = screen.getByTestId('add-component-data-binding');

act(() => {
fireEvent.pointerUp(addButton);
});

expect(addComponentInternal).toBeCalledWith(
selectedSceneNodeRef,
expect.objectContaining({ type: KnownComponentType.DataBinding, valueDataBindings: [{}] }),
);
expect(addComponentInternal).toBeCalledWith(selectedSceneNodeRef, {
ref: expect.any(String),
type: KnownComponentType.DataBinding,
valueDataBinding: { dataBindingContext: {} },
});
expect(mockMetricRecorder.recordClick).toBeCalledTimes(1);
expect(mockMetricRecorder.recordClick).toBeCalledWith('add-component-data-binding');
});

it('should add addition binding to data binding component when clicked', () => {
it('should add no addition binding to data binding component when clicked', () => {
getSceneNodeByRef.mockReturnValue({
components: [
{
ref: expect.any(String),
type: KnownComponentType.DataBinding,
valueDataBindings: [{}],
type: KnownComponentType.Tag,
},
],
});

render(<AddComponentMenu />);
const addButton = screen.getByTestId('add-component-data-binding');

act(() => {
fireEvent.pointerUp(addButton);
});

expect(updateComponentInternal).toBeCalledWith(
selectedSceneNodeRef,
expect.objectContaining({ type: KnownComponentType.DataBinding, valueDataBindings: [{}, {}] }),
);
expect(mockMetricRecorder.recordClick).toBeCalledTimes(1);
expect(mockMetricRecorder.recordClick).toBeCalledWith('add-component-data-binding');
expect(screen.getByTestId('add-component-data-binding')).not.toBeNull;
screen.getByTestId('add-component-data-binding').click();
fireEvent.mouseOver(screen.getByTestId('add-component'));
expect(screen.getByTestId('add-component')).not.toContain('Add entity binding');
});

it('should not see add data binding item when feature is not enabled', () => {
setFeatureConfig({ [COMPOSER_FEATURES.DataBinding]: false });

render(<AddComponentMenu />);

expect(screen.queryByTestId('add-data-binding')).toBeNull();
});
});
42 changes: 22 additions & 20 deletions packages/scene-composer/src/components/panels/AddComponentMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { IconProps } from '@awsui/components-react';
import React, { useCallback, useContext, useMemo } from 'react';
import { defineMessages, MessageDescriptor, useIntl } from 'react-intl';
import { MessageDescriptor, defineMessages, useIntl } from 'react-intl';
import * as THREE from 'three';
import { IconProps } from '@awsui/components-react';

import { ToolbarItemOptionRaw, ToolbarItemOptions } from '../toolbars/common/types';
import { getGlobalSettings } from '../../common/GlobalSettings';
import { sceneComposerIdContext } from '../../common/sceneComposerIdContext';
import { IDataOverlayComponentInternal, useStore } from '../../store';
import { findComponentByType } from '../../utils/nodeUtils';
import { COMPOSER_FEATURES, KnownComponentType } from '../../interfaces';
import { ToolbarItem } from '../toolbars/common/ToolbarItem';
import { getGlobalSettings } from '../../common/GlobalSettings';
import { Component } from '../../models/SceneModels';
import { IDataOverlayComponentInternal, useStore } from '../../store';
import { IDataBindingComponentInternal } from '../../store/internalInterfaces';
import { findComponentByType } from '../../utils/nodeUtils';
import { ToolbarItem } from '../toolbars/common/ToolbarItem';
import { ToolbarItemOptionRaw, ToolbarItemOptions } from '../toolbars/common/types';

interface AddComponentMenuProps {
onSelect?: (selectedObject: ObjectTypes) => void;
Expand All @@ -31,12 +31,12 @@ type AddComponentMenuItem = ToolbarItemOptions & {
const labelStrings: { [key in ObjectTypes]: MessageDescriptor } = defineMessages({
[ObjectTypes.Component]: { defaultMessage: 'Add component', description: 'Menu Item label' },
[ObjectTypes.Overlay]: { defaultMessage: 'Overlay', description: 'Menu Item label' },
[ObjectTypes.DataBinding]: { defaultMessage: 'Data binding', description: 'Menu Item label' },
[ObjectTypes.DataBinding]: { defaultMessage: 'Add entity binding', description: 'Menu Item label' },
});

const textStrings = defineMessages({
[ObjectTypes.Overlay]: { defaultMessage: 'Add overlay', description: 'Menu Item' },
[ObjectTypes.DataBinding]: { defaultMessage: 'Add data binding', description: 'Menu Item' },
[ObjectTypes.DataBinding]: { defaultMessage: 'Add entity binding', description: 'Menu Item' },
});

export const AddComponentMenu: React.FC<AddComponentMenuProps> = ({ onSelect }) => {
Expand All @@ -51,7 +51,7 @@ export const AddComponentMenu: React.FC<AddComponentMenuProps> = ({ onSelect })

const isTagComponent = !!findComponentByType(selectedSceneNode, KnownComponentType.Tag);
const isOverlayComponent = !!findComponentByType(selectedSceneNode, KnownComponentType.DataOverlay);

const isDataBindingComponent = !!findComponentByType(selectedSceneNode, KnownComponentType.DataBinding);
const mapToMenuItem = useCallback(
(item: ToolbarItemOptionRaw): AddComponentMenuItem => {
const typeId: ObjectTypes = item.uuid as ObjectTypes;
Expand All @@ -76,13 +76,15 @@ export const AddComponentMenu: React.FC<AddComponentMenuProps> = ({ onSelect })
},
]
: [];
const addDataBindingItem = dataBindingComponentEnabled
? [
{
uuid: ObjectTypes.DataBinding,
},
]
: [];
const addDataBindingItem =
dataBindingComponentEnabled && !findComponentByType(selectedSceneNode, KnownComponentType.DataBinding)
? [
{
uuid: ObjectTypes.DataBinding,
isDisabled: isDataBindingComponent,
},
]
: [];

return [
{
Expand All @@ -92,7 +94,7 @@ export const AddComponentMenu: React.FC<AddComponentMenuProps> = ({ onSelect })
...addOverlayItem,
...addDataBindingItem,
].map(mapToMenuItem);
}, [selectedSceneNodeRef, isOverlayComponent, isTagComponent, dataBindingComponentEnabled]);
}, [selectedSceneNodeRef, selectedSceneNode, isOverlayComponent, isTagComponent, dataBindingComponentEnabled]);

const handleAddOverlay = useCallback(() => {
if (!selectedSceneNodeRef) return;
Expand Down Expand Up @@ -121,7 +123,7 @@ export const AddComponentMenu: React.FC<AddComponentMenuProps> = ({ onSelect })
if (dataBindingComponent) {
const newComponentPartial = {
...dataBindingComponent,
valueDataBindings: [...(dataBindingComponent as IDataBindingComponentInternal).valueDataBindings, {}],
valueDataBindings: [dataBindingComponent as IDataBindingComponentInternal, {}],
};
updateComponentInternal(selectedSceneNodeRef, newComponentPartial);
return;
Expand All @@ -130,7 +132,7 @@ export const AddComponentMenu: React.FC<AddComponentMenuProps> = ({ onSelect })
const component: IDataBindingComponentInternal = {
ref: THREE.MathUtils.generateUUID(),
type: KnownComponentType.DataBinding,
valueDataBindings: [{}],
valueDataBinding: { dataBindingContext: {} },
};

addComponentInternal(selectedSceneNodeRef, component);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function NumericInput(props: {
setValue: (val: number) => void;
toStr: (val: number) => string;
fromStr: (str: string) => number;
}) {
}): JSX.Element {
const [strValue, setStrValue] = useState(props.toStr(props.value));

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import wrapper from '@awsui/components-react/test-utils/dom';
import { act, fireEvent, render } from '@testing-library/react';
import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';

import { useStore } from '../../store';
import { setMetricRecorder } from '../../common/GlobalSettings';
import { KnownComponentType } from '../../interfaces';
import { Component } from '../../models/SceneModels';
import { useStore } from '../../store';

import { ComponentEditMenu } from './ComponentEditMenu';

Expand Down Expand Up @@ -33,39 +34,26 @@ describe('ComponentEditMenu', () => {
expect(container).toMatchInlineSnapshot(`<div />`);
});

it('should correctly add additional data binding to data binding component', () => {
it('should not add additional data binding to data binding component', () => {
const component = { type: KnownComponentType.DataBinding, ref: 'comp-ref', valueDataBindings: [{}] };
const { getByTestId } = render(<ComponentEditMenu nodeRef={nodeRef} currentComponent={component} />);
const addBindingButton = getByTestId('add-data-binding');

act(() => {
fireEvent.pointerUp(addBindingButton);
});

expect(getByTestId('edit-component').childNodes[2].childNodes.length).toEqual(2);
expect(updateComponentInternal).toBeCalledTimes(1);
expect(updateComponentInternal).toBeCalledWith(nodeRef, {
...component,
valueDataBindings: [{}, {}],
});
expect(mockMetricRecorder.recordClick).toBeCalledTimes(1);
expect(mockMetricRecorder.recordClick).toBeCalledWith('DataBinding-add-data-binding');
render(<ComponentEditMenu nodeRef={nodeRef} currentComponent={component} />);
expect(wrapper().getElement().innerHTML).not.toContain('Add entity binding');
});

it('should correctly remove data binding component', () => {
const component = { type: KnownComponentType.DataBinding, ref: 'comp-ref', valueDataBindings: [{}] };
const { getByTestId } = render(<ComponentEditMenu nodeRef={nodeRef} currentComponent={component} />);
const removeAllBindingButton = getByTestId('remove-all-data-binding');
const removeEntityBinding = getByTestId('remove-entity-binding');

act(() => {
fireEvent.pointerUp(removeAllBindingButton);
fireEvent.pointerUp(removeEntityBinding);
});

expect(getByTestId('edit-component').childNodes[2].childNodes.length).toEqual(2);
expect(getByTestId('edit-component').childNodes[2].childNodes.length).toEqual(1);
expect(removeComponent).toBeCalledTimes(1);
expect(removeComponent).toBeCalledWith(nodeRef, component.ref);
expect(mockMetricRecorder.recordClick).toBeCalledTimes(1);
expect(mockMetricRecorder.recordClick).toBeCalledWith('DataBinding-remove-all-data-binding');
expect(mockMetricRecorder.recordClick).toBeCalledWith('DataBinding-remove-entity-binding');
});

it('should correctly add additional data binding to overlay component', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ interface ComponentEditMenuProps {
enum ObjectTypes {
EditComponent = 'edit-component',
AddDataBinding = 'add-data-binding',
AddEntityBinding = 'add-entity-binding',
RemoveEntityBinding = 'remove-entity-binding',
RemoveAllDataBinding = 'remove-all-data-binding',
RemoveOverlay = 'remove-overlay',
}
Expand All @@ -32,13 +34,16 @@ type ComponentEditMenuItem = ToolbarItemOptions & {
const labelStrings: { [key in ObjectTypes]: MessageDescriptor } = defineMessages({
[ObjectTypes.EditComponent]: { defaultMessage: 'Edit component', description: 'Menu Item label' },
[ObjectTypes.AddDataBinding]: { defaultMessage: 'Add data binding', description: 'Menu Item label' },
[ObjectTypes.AddEntityBinding]: { defaultMessage: 'Add entity binding', description: 'Menu Item label' },
[ObjectTypes.RemoveEntityBinding]: { defaultMessage: 'Remove entity binding', description: 'Menu Item label' },
[ObjectTypes.RemoveAllDataBinding]: { defaultMessage: 'Remove all data binding', description: 'Menu Item label' },
[ObjectTypes.RemoveOverlay]: { defaultMessage: 'Remove overlay', description: 'Menu Item label' },
});

const textStrings = defineMessages({
[ObjectTypes.AddDataBinding]: { defaultMessage: 'Add data binding', description: 'Menu Item' },
[ObjectTypes.AddDataBinding]: { defaultMessage: 'Add entity binding', description: 'Menu Item' },
[ObjectTypes.RemoveAllDataBinding]: { defaultMessage: 'Remove all data binding', description: 'Menu Item' },
[ObjectTypes.RemoveEntityBinding]: { defaultMessage: 'Remove entity binding', description: 'Menu Item' },
[ObjectTypes.RemoveOverlay]: { defaultMessage: 'Remove overlay', description: 'Menu Item' },
});

Expand Down Expand Up @@ -67,10 +72,7 @@ export const ComponentEditMenu: React.FC<ComponentEditMenuProps> = ({ nodeRef, c
case KnownComponentType.DataBinding:
return [
{
uuid: ObjectTypes.AddDataBinding,
},
{
uuid: ObjectTypes.RemoveAllDataBinding,
uuid: ObjectTypes.RemoveEntityBinding,
},
];

Expand Down Expand Up @@ -109,7 +111,7 @@ export const ComponentEditMenu: React.FC<ComponentEditMenuProps> = ({ nodeRef, c
case KnownComponentType.DataBinding: {
const newComponentPartial = {
...currentComponent,
valueDataBindings: [...((currentComponent as IDataBindingComponentInternal).valueDataBindings || []), {}],
valueDataBindings: [(currentComponent as IDataBindingComponentInternal).valueDataBinding || [], {}],
};
updateComponentInternal(nodeRef, newComponentPartial);
return;
Expand Down Expand Up @@ -150,7 +152,7 @@ export const ComponentEditMenu: React.FC<ComponentEditMenuProps> = ({ nodeRef, c
case ObjectTypes.AddDataBinding:
handleAddDataBinding();
break;
case ObjectTypes.RemoveAllDataBinding:
case ObjectTypes.RemoveEntityBinding:
handleRemoveAllDataBinding();
break;
case ObjectTypes.RemoveOverlay:
Expand Down

0 comments on commit f1f81b8

Please sign in to comment.