Skip to content

Commit

Permalink
[Canvas] Simplified aero state (#32980) (#33345)
Browse files Browse the repository at this point in the history
* Chore: Remove disused shapeAdditions

* Refactor: Move configuration into the scene

* Chore: Remove disused dispatch

* Refactor: move out DOM helper not coupled with layout functions

* Chore: make node id generation idempotent

* Refactor: Remove selectReduce

* Refactor: code alignment with data flow (selector hierarchy)

* Refactor: reduced API surface area

* Refactor: trivially split state.js

* Refactor: simplify `select`

* Refactor: extract out workpadPage components

* Refactor: rename dag_start

* Chore: make todo more salient

* Fix: remove chance of collision (two subsequent large random integers may equal)

* Chore: split the two captured variables to their own `let`
  • Loading branch information
monfera authored Mar 15, 2019
1 parent ddc0187 commit 4188d6c
Show file tree
Hide file tree
Showing 19 changed files with 302 additions and 292 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const AlignmentGuide = ({ transformMatrix, width, height }) => {
const newStyle = {
Expand All @@ -16,7 +16,7 @@ export const AlignmentGuide = ({ transformMatrix, width, height }) => {
marginTop: -height / 2,
background: 'magenta',
position: 'absolute',
transform: toCSS(transformMatrix),
transform: matrixToCSS(transformMatrix),
};
return (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const BorderConnection = ({ transformMatrix, width, height }) => {
const newStyle = {
Expand All @@ -15,7 +15,7 @@ export const BorderConnection = ({ transformMatrix, width, height }) => {
marginLeft: -width / 2,
marginTop: -height / 2,
position: 'absolute',
transform: toCSS(transformMatrix),
transform: matrixToCSS(transformMatrix),
};
return <div className="canvasBorder--connection canvasLayoutAnnotation" style={newStyle} />;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const BorderResizeHandle = ({ transformMatrix }) => (
<div
className="canvasBorderResizeHandle canvasLayoutAnnotation"
style={{ transform: toCSS(transformMatrix) }}
style={{ transform: matrixToCSS(transformMatrix) }}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const HoverAnnotation = ({ transformMatrix, width, height }) => {
const newStyle = {
width,
height,
marginLeft: -width / 2,
marginTop: -height / 2,
transform: toCSS(transformMatrix),
transform: matrixToCSS(transformMatrix),
};
return <div className="canvasHoverAnnotation canvasLayoutAnnotation" style={newStyle} />;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const Positionable = ({ children, transformMatrix, width, height }) => {
// Throw if there is more than one child
Expand All @@ -19,7 +19,7 @@ export const Positionable = ({ children, transformMatrix, width, height }) => {
marginLeft: -width / 2,
marginTop: -height / 2,
position: 'absolute',
transform: toCSS(transformMatrix.map((n, i) => (i < 12 ? n : Math.round(n)))),
transform: matrixToCSS(transformMatrix.map((n, i) => (i < 12 ? n : Math.round(n)))),
};

const stepChild = React.cloneElement(child, { size: { width, height } });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const RotationHandle = ({ transformMatrix }) => (
<div
className="canvasRotationHandle canvasRotationHandle--connector canvasLayoutAnnotation"
style={{ transform: toCSS(transformMatrix) }}
style={{ transform: matrixToCSS(transformMatrix) }}
>
<div className="canvasRotationHandle--handle" />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

import React from 'react';
import PropTypes from 'prop-types';
import { toCSS } from '../../lib/aeroelastic';
import { matrixToCSS } from '../../lib/dom';

export const HoverAnnotation = ({ transformMatrix, text }) => {
const newStyle = {
transform: `${toCSS(transformMatrix)} translate(1em, -1em)`,
transform: `${matrixToCSS(transformMatrix)} translate(1em, -1em)`,
};
return (
<div className="tooltipAnnotation canvasLayoutAnnotation" style={newStyle}>
Expand Down
176 changes: 90 additions & 86 deletions x-pack/plugins/canvas/public/components/workpad_page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,100 +52,104 @@ const getRootElementId = (lookup, id) => {
: element.id;
};

export const WorkpadPage = compose(
connect(
mapStateToProps,
mapDispatchToProps
),
withProps(({ isSelected, animation }) => {
function getClassName() {
if (animation) {
return animation.name;
}
return isSelected ? 'canvasPage--isActive' : 'canvasPage--isInactive';
const animationProps = ({ isSelected, animation }) => {
function getClassName() {
if (animation) {
return animation.name;
}
return isSelected ? 'canvasPage--isActive' : 'canvasPage--isInactive';
}

function getAnimationStyle() {
if (!animation) {
return {};
}
return {
animationDirection: animation.direction,
// TODO: Make this configurable
animationDuration: '1s',
};
function getAnimationStyle() {
if (!animation) {
return {};
}

return {
className: getClassName(),
animationStyle: getAnimationStyle(),
};
}),
withState('updateCount', 'setUpdateCount', 0), // TODO: remove this, see setUpdateCount below
withProps(({ updateCount, setUpdateCount, page, elements: pageElements }) => {
const { shapes, selectedPrimaryShapes = [], cursor } = aeroelastic.getStore(
page.id
).currentScene;
const elementLookup = new Map(pageElements.map(element => [element.id, element]));
const recurseGroupTree = shapeId => {
return [
shapeId,
...flatten(
shapes
.filter(s => s.parent === shapeId && s.type !== 'annotation')
.map(s => s.id)
.map(recurseGroupTree)
),
];
animationDirection: animation.direction,
// TODO: Make this configurable
animationDuration: '1s',
};
}

return {
className: getClassName(),
animationStyle: getAnimationStyle(),
};
};

const layoutProps = ({ updateCount, setUpdateCount, page, elements: pageElements }) => {
const { shapes, selectedPrimaryShapes = [], cursor } = aeroelastic.getStore(page.id).currentScene;
const elementLookup = new Map(pageElements.map(element => [element.id, element]));
const recurseGroupTree = shapeId => {
return [
shapeId,
...flatten(
shapes
.filter(s => s.parent === shapeId && s.type !== 'annotation')
.map(s => s.id)
.map(recurseGroupTree)
),
];
};

const selectedPrimaryShapeObjects = selectedPrimaryShapes
.map(id => shapes.find(s => s.id === id))
.filter(shape => shape);
const selectedPrimaryShapeObjects = selectedPrimaryShapes
.map(id => shapes.find(s => s.id === id))
.filter(shape => shape);

const selectedPersistentPrimaryShapes = flatten(
selectedPrimaryShapeObjects.map(shape =>
shape.subtype === 'adHocGroup'
? shapes.filter(s => s.parent === shape.id && s.type !== 'annotation').map(s => s.id)
: [shape.id]
)
);
const selectedElementIds = flatten(selectedPersistentPrimaryShapes.map(recurseGroupTree));
const selectedElements = [];
const elements = shapes.map(shape => {
let element = null;
if (elementLookup.has(shape.id)) {
element = elementLookup.get(shape.id);
if (selectedElementIds.indexOf(shape.id) > -1) {
selectedElements.push({ ...element, id: shape.id });
}
const selectedPersistentPrimaryShapes = flatten(
selectedPrimaryShapeObjects.map(shape =>
shape.subtype === 'adHocGroup'
? shapes.filter(s => s.parent === shape.id && s.type !== 'annotation').map(s => s.id)
: [shape.id]
)
);
const selectedElementIds = flatten(selectedPersistentPrimaryShapes.map(recurseGroupTree));
const selectedElements = [];
const elements = shapes.map(shape => {
let element = null;
if (elementLookup.has(shape.id)) {
element = elementLookup.get(shape.id);
if (selectedElementIds.indexOf(shape.id) > -1) {
selectedElements.push({ ...element, id: shape.id });
}
// instead of just combining `element` with `shape`, we make property transfer explicit
return element ? { ...shape, filter: element.filter } : shape;
});
return {
elements,
cursor,
selectedElementIds,
selectedElements,
selectedPrimaryShapes,
commit: (...args) => {
aeroelastic.commit(page.id, ...args);
// TODO: remove this, it's a hack to force react to rerender
setUpdateCount(updateCount + 1);
},
};
}), // Updates states; needs to have both local and global
withHandlers({
groupElements: ({ commit }) => () =>
commit('actionEvent', {
event: 'group',
}),
ungroupElements: ({ commit }) => () =>
commit('actionEvent', {
event: 'ungroup',
}),
}),
}
// instead of just combining `element` with `shape`, we make property transfer explicit
return element ? { ...shape, filter: element.filter } : shape;
});
return {
elements,
cursor,
selectedElementIds,
selectedElements,
selectedPrimaryShapes,
commit: (...args) => {
aeroelastic.commit(page.id, ...args);
// TODO: remove this, it's a hack to force react to rerender
setUpdateCount(updateCount + 1);
},
};
};

const groupHandlerCreators = {
groupElements: ({ commit }) => () =>
commit('actionEvent', {
event: 'group',
}),
ungroupElements: ({ commit }) => () =>
commit('actionEvent', {
event: 'ungroup',
}),
};

export const WorkpadPage = compose(
connect(
mapStateToProps,
mapDispatchToProps
),
withProps(animationProps),
withState('updateCount', 'setUpdateCount', 0), // TODO: remove this, see setUpdateCount below
withProps(layoutProps), // Updates states; needs to have both local and global
withHandlers(groupHandlerCreators),
withHandlers(eventHandlers) // Captures user intent, needs to have reconciled state
)(Component);

Expand Down
17 changes: 17 additions & 0 deletions x-pack/plugins/canvas/public/lib/aeroelastic/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { select } from './select';

// serves as reminder that we start with the state
// todo remove it as we add TS annotations (State)
const state = d => d;

const getScene = state => state.currentScene;
export const scene = select(getScene)(state);

const getPrimaryUpdate = state => state.primaryUpdate;
export const primaryUpdate = select(getPrimaryUpdate)(state);
Loading

0 comments on commit 4188d6c

Please sign in to comment.