From 4f0e8d9e479f891311355fa5ab378f1d75298172 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 11 Sep 2017 23:43:00 +0700 Subject: [PATCH 1/4] Provide stable keys for slot elements --- .../src/containers/StreamTabPanel.js | 31 +++++-------- client/coral-framework/services/plugins.js | 44 ++++++++++++++++--- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/client/coral-embed-stream/src/containers/StreamTabPanel.js b/client/coral-embed-stream/src/containers/StreamTabPanel.js index fde6e3be4..be37c307d 100644 --- a/client/coral-embed-stream/src/containers/StreamTabPanel.js +++ b/client/coral-embed-stream/src/containers/StreamTabPanel.js @@ -26,8 +26,8 @@ class StreamTabPanelContainer extends React.Component { // it does not result in a change of slot children. const changes = getShallowChanges(this.props, next); if (changes.length === 1 && changes[0] === 'reduxState') { - const prevUuid = this.getSlotComponents(this.props.tabSlot, this.props).map((cmp) => cmp.talkUuid); - const nextUuid = this.getSlotComponents(next.tabSlot, next).map((cmp) => cmp.talkUuid); + const prevUuid = this.getSlotElements(this.props.tabSlot, this.props).map((el) => el.type.talkUuid); + const nextUuid = this.getSlotElements(next.tabSlot, next).map((el) => el.type.talkUuid); return !isEqual(prevUuid, nextUuid); } @@ -37,42 +37,33 @@ class StreamTabPanelContainer extends React.Component { fallbackAllTab(props = this.props) { if (props.activeTab !== props.fallbackTab) { - const slotPlugins = this.getSlotComponents(props.tabSlot, props).map((c) => c.talkPluginName); + const slotPlugins = this.getSlotElements(props.tabSlot, props).map((el) => el.type.talkPluginName); if (slotPlugins.indexOf(props.activeTab) === -1) { props.setActiveTab(props.fallbackTab); } } } - getSlotComponents(slot, props = this.props) { + getSlotElements(slot, props = this.props) { const {plugins} = this.context; - return plugins.getSlotComponents(slot, props.reduxState, props.slotProps, props.queryData); + return plugins.getSlotElements(slot, props.reduxState, props.slotProps, props.queryData); } getPluginTabElements(props = this.props) { - const {plugins} = this.context; - return this.getSlotComponents(props.tabSlot).map((PluginComponent) => { - const pluginProps = plugins.getSlotComponentProps(PluginComponent, props.reduxState, props.slotProps, props.queryData); + return this.getSlotElements(props.tabSlot).map((el) => { return ( - - + + {React.cloneElement(el, {active: this.props.activeTab === el.type.talkPluginName})} ); }); } getPluginTabPaneElements(props = this.props) { - const {plugins} = this.context; - return this.getSlotComponents(props.tabPaneSlot).map((PluginComponent) => { - const pluginProps = plugins.getSlotComponentProps(PluginComponent, props.reduxState, props.slotProps, props.queryData); + return this.getSlotElements(props.tabPaneSlot).map((el) => { return ( - - + + {el} ); }); diff --git a/client/coral-framework/services/plugins.js b/client/coral-framework/services/plugins.js index 301428c12..5c4f8eb35 100644 --- a/client/coral-framework/services/plugins.js +++ b/client/coral-framework/services/plugins.js @@ -77,7 +77,7 @@ class PluginsService { addMetaDataToSlotComponents(plugins); } - getSlotComponents(slot, reduxState, props = {}, queryData = {}) { + _getSlotComponents(slot, reduxState, props = {}, queryData = {}) { const pluginConfig = reduxState.config.plugin_config || emptyConfig; return flatten(this.plugins @@ -100,7 +100,7 @@ class PluginsService { } isSlotEmpty(slot, reduxState, props = {}, queryData = {}) { - return this.getSlotComponents(slot, reduxState, props, queryData).length === 0; + return this._getSlotComponents(slot, reduxState, props, queryData).length === 0; } /** @@ -124,10 +124,42 @@ class PluginsService { * Returns React Elements for given slot. */ getSlotElements(slot, reduxState, props = {}, queryData = {}) { - return this.getSlotComponents(slot, reduxState, props, queryData) - .map((component, i) => { - return React.createElement(component, {key: i, ...this.getSlotComponentProps(component, reduxState, props, queryData)}); - }); + const pluginConfig = reduxState.config.plugin_config || emptyConfig; + + const isDisabled = (component) => { + if ( + pluginConfig && + pluginConfig[component.talkPluginName] && + pluginConfig[component.talkPluginName].disable_components + ) { + return true; + } + + // Check if component is excluded. + if(component.isExcluded) { + let resolvedProps = this.getSlotComponentProps(component, reduxState, props, queryData); + if (component.mapStateToProps) { + resolvedProps = {...resolvedProps, ...component.mapStateToProps(reduxState)}; + } + return component.isExcluded(resolvedProps); + } + + return false; + }; + + return flatten(this.plugins + .filter((o) => o.module.slots && o.module.slots[slot]) + .map((o) => o.module.slots[slot]) + ) + .map((component, i) => ({ + component, + disabled: isDisabled(component), + key: i, + })) + .filter((o) => !o.disabled) + .map(({component, key}) => + React.createElement(component, {key, ...this.getSlotComponentProps(component, reduxState, props, queryData)}) + ); } getSlotFragments(slot, part) { From ecd4267ea9843f29b8dd9a392d7e8f3ea53fa50f Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 11 Sep 2017 23:46:16 +0700 Subject: [PATCH 2/4] Remove getSlotComponents completely --- client/coral-framework/services/plugins.js | 24 +--------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/client/coral-framework/services/plugins.js b/client/coral-framework/services/plugins.js index 5c4f8eb35..ac752fa13 100644 --- a/client/coral-framework/services/plugins.js +++ b/client/coral-framework/services/plugins.js @@ -77,30 +77,8 @@ class PluginsService { addMetaDataToSlotComponents(plugins); } - _getSlotComponents(slot, reduxState, props = {}, queryData = {}) { - const pluginConfig = reduxState.config.plugin_config || emptyConfig; - return flatten(this.plugins - - // Filter out components that have slots and have been disabled in `plugin_config` - .filter((o) => o.module.slots && (!pluginConfig || !pluginConfig[o.name] || !pluginConfig[o.name].disable_components)) - - .filter((o) => o.module.slots[slot]) - .map((o) => o.module.slots[slot]) - ) - .filter((component) => { - if(!component.isExcluded) { - return true; - } - let resolvedProps = this.getSlotComponentProps(component, reduxState, props, queryData); - if (component.mapStateToProps) { - resolvedProps = {...resolvedProps, ...component.mapStateToProps(reduxState)}; - } - return !component.isExcluded(resolvedProps); - }); - } - isSlotEmpty(slot, reduxState, props = {}, queryData = {}) { - return this._getSlotComponents(slot, reduxState, props, queryData).length === 0; + return this.getSlotElements(slot, reduxState, props, queryData).length === 0; } /** From d1c30ab9821a234c51259921435193fa33fc9605 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 12 Sep 2017 15:57:40 +0700 Subject: [PATCH 3/4] Remove talkUuid and use element key instead --- client/coral-embed-stream/src/containers/StreamTabPanel.js | 6 +++--- client/coral-framework/components/Slot.js | 6 +++--- client/coral-framework/services/plugins.js | 4 ---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/client/coral-embed-stream/src/containers/StreamTabPanel.js b/client/coral-embed-stream/src/containers/StreamTabPanel.js index be37c307d..9a154512d 100644 --- a/client/coral-embed-stream/src/containers/StreamTabPanel.js +++ b/client/coral-embed-stream/src/containers/StreamTabPanel.js @@ -26,9 +26,9 @@ class StreamTabPanelContainer extends React.Component { // it does not result in a change of slot children. const changes = getShallowChanges(this.props, next); if (changes.length === 1 && changes[0] === 'reduxState') { - const prevUuid = this.getSlotElements(this.props.tabSlot, this.props).map((el) => el.type.talkUuid); - const nextUuid = this.getSlotElements(next.tabSlot, next).map((el) => el.type.talkUuid); - return !isEqual(prevUuid, nextUuid); + const prevKeys = this.getSlotElements(this.props.tabSlot, this.props).map((el) => el.key); + const nextKeys = this.getSlotElements(next.tabSlot, next).map((el) => el.key); + return !isEqual(prevKeys, nextKeys); } // Prevent Slot from rerendering when no props has shallowly changed. diff --git a/client/coral-framework/components/Slot.js b/client/coral-framework/components/Slot.js index 06f1d4cb7..0fe0d8896 100644 --- a/client/coral-framework/components/Slot.js +++ b/client/coral-framework/components/Slot.js @@ -20,9 +20,9 @@ class Slot extends React.Component { // it does not result in a change of slot children. const changes = getShallowChanges(this.props, next); if (changes.length === 1 && changes[0] === 'reduxState') { - const prevChildrenUuid = this.getChildren(this.props).map((child) => child.type.talkUuid); - const nextChildrenUuid = this.getChildren(next).map((child) => child.type.talkUuid); - return !isEqual(prevChildrenUuid, nextChildrenUuid); + const prevChildrenKeys = this.getChildren(this.props).map((child) => child.key); + const nextChildrenKeys = this.getChildren(next).map((child) => child.key); + return !isEqual(prevChildrenKeys, nextChildrenKeys); } // Prevent Slot from rerendering when no props has shallowly changed. diff --git a/client/coral-framework/services/plugins.js b/client/coral-framework/services/plugins.js index 809286eb0..c8eb737fd 100644 --- a/client/coral-framework/services/plugins.js +++ b/client/coral-framework/services/plugins.js @@ -8,7 +8,6 @@ import flatten from 'lodash/flatten'; import mapValues from 'lodash/mapValues'; import {getDisplayName} from 'coral-framework/helpers/hoc'; import camelize from '../helpers/camelize'; -import uuid from 'uuid/v4'; // This is returned for pluginConfig when it is empty. const emptyConfig = {}; @@ -63,9 +62,6 @@ function addMetaDataToSlotComponents(plugins) { // Attach plugin name to the component component.talkPluginName = plugin.name; - - // Attach uuid to the component - component.talkUuid = uuid(); }); }); }); From d8ca9dfb07ccccfde72fd53876fb1368569aa2ef Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 12 Sep 2017 20:58:33 +0700 Subject: [PATCH 4/4] Fix edit animation --- client/coral-admin/src/components/CommentAnimatedEdit.css | 4 ++++ client/coral-admin/src/components/CommentAnimatedEdit.js | 1 + 2 files changed, 5 insertions(+) diff --git a/client/coral-admin/src/components/CommentAnimatedEdit.css b/client/coral-admin/src/components/CommentAnimatedEdit.css index 83be36c11..a03f66fc5 100644 --- a/client/coral-admin/src/components/CommentAnimatedEdit.css +++ b/client/coral-admin/src/components/CommentAnimatedEdit.css @@ -1,3 +1,7 @@ +.root { + position: relative; +} + .bodyLeave { position: absolute; width: 100%; diff --git a/client/coral-admin/src/components/CommentAnimatedEdit.js b/client/coral-admin/src/components/CommentAnimatedEdit.js index 141dc12cc..2515d7d94 100644 --- a/client/coral-admin/src/components/CommentAnimatedEdit.js +++ b/client/coral-admin/src/components/CommentAnimatedEdit.js @@ -7,6 +7,7 @@ export default ({children, body}) => { return (