-
Notifications
You must be signed in to change notification settings - Fork 13
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
EZP-28841: Content On the Fly v2 #55
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's quite a lof of things to change.
import './css/content.creator.component.css'; | ||
|
||
export default class ContentCreatorComponent extends Component { | ||
constructor(props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're not using props to initialize state, then you can omit the props
variable in the constructor
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can but I don't think you should.
Class components should always call the base constructor with props.
from React doc: https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is recommendation, right. We can follow this rule. It's especially useful when you're extending your own component classes. In this case, when you extend base component class it's not that relevant. Because any kind of props won't affect the way the base class works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it will not cause any problems when extending React.Component
for now, but if they have this in their doc they may require this at some point in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let's keep it then. From the currect perspective, it brings no value now, but it's a recommended by React doc.
handleIframeLoad() { | ||
const locationId = this._iframe.contentWindow.document.querySelector('meta[name="LocationID"]'); | ||
|
||
if (this._iframe.contentWindow.location.pathname !== this.generateIframeUrl() && !locationId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this.generateIframeUrl()
be cached?
} else { | ||
this.setState(state => Object.assign({}, state, { iframeLoading: false })); | ||
|
||
this._iframe.contentWindow.onbeforeunload = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: I would put the iframe event handlers to the second callback of this.setState
method. Do you think it's a bad approach? When moving the event handlers assignment to the callback you apply them right the state is updated (in a sync way).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question is still valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those onbeforeunload
and onunload
is not related to the setState
, I think callback for setState
should be used when its depends on the state.
} | ||
|
||
generateIframeUrl() { | ||
return window.Routing.generate('ezplatform.content.create.on_the_fly', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be initialized in the constructor
method, because you're not updating app state in case of props updates. This function will always return the same output.
In the constructor
it should be stored liked this:
this.iframeUrl = window.Routing.generate(...);
* @returns {Element} | ||
* @memberof FinderTreeLeafComponent | ||
*/ | ||
renderLoadingIcon() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renderLoadingSpinner
<div {...wrapperAttrs}> | ||
<TabContentPanelComponent {...props}> | ||
<div className="c-create-panel__first-step"> | ||
<div className="c-create-panel__step-title">1) {props.labels.contentOnTheFly.chooseLangaugeAndContentType}</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using ol > li
isn't the right way to go?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So li
would need to have inside a whole create
or finder
component? I think it's not the best structure.
languageCode, | ||
locationId | ||
}, callback) => { | ||
const endpoint = window.Routing.generate('ezplatform.content.create.on_the_fly.has_access', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to duplicate the names: window.Routing.generate('ezplatform.content.create.on_the_fly.has_access', { languageCode, contentTypeIdentifier, locationId })
const request = new Request(endpoint, { | ||
method: 'GET', | ||
headers: {'X-CSRF-Token': token}, | ||
mode: 'cors', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We decided to switch to proper mode: same-origin
this.onContentTypeSelected = this.onContentTypeSelected.bind(this); | ||
this.handlePublish = this.handlePublish.bind(this); | ||
|
||
if (props.forcedLanguageCOTF) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it should be renamed to something like: cotfForcedLanguage
or maybe it can be done differently. Because, here youre hardcoding a kind-of-dependency to the COTF which might not exist on a specific instalation.
Do you really need this information here, in UDW module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
COTF is part of a UDW module and the configuration must be set on the UDW and then pass to the COTF.
Because, here youre hardcoding a kind-of-dependency to the COTF which might not exist on a specific instalation.
- that's why it has a default value ''
which will prevent from breaking in customers instalations
this.setState(state => Object.assign({}, state, {isCheckingPermission: false})); | ||
|
||
if (this.state.hasPermission !== response.access) { | ||
this.setState(state => Object.assign({}, state, {hasPermission: response.access})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should set state once, not twice in the same scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how this could be in one. We want to change isCheckingPermission
every time when the request is finished but change the permission state only when have to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about it?
this.setState(state => Object.assign({}, state, {
isCheckingPermission: false,
hasPermission: state.hasPermission !== response.access ? response.access : state.hasPermission
}));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can try but as far as I know thanks to immutable
with Object.assign
this will make rerender of react component and this is what I wanted to avoid in this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're already doing it, so why doing it twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React will compare boolean values (I assume they are boolean). If there's any change then it will cause re-rendering of any related piece of code.
ping @sunpietro |
} | ||
|
||
handlePublish() { | ||
this._iframe.contentWindow.onbeforeunload = () => {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With ReactJS we abandoned the rule of adding underscores into protected variables. These will not be exposed in the React code anyway.
} else { | ||
this.setState(state => Object.assign({}, state, { iframeLoading: false })); | ||
|
||
this._iframe.contentWindow.onbeforeunload = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question is still valid.
.replace('{contentType}', selectedContentType.name) | ||
.replace('{language}', selectedLanguage.name); | ||
const iframeUrl = this.generateIframeUrl(); | ||
const contentClass = this.state.iframeLoading ? "m-ud__content is-loading" : "m-ud__content"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CS: Single quotes, please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not: m-ud__content--is-loading
?
} | ||
|
||
updateFilterQuery(event) { | ||
const value = event.target.value.toLowerCase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you thought about naming it as filterQuery
?
}, 200); | ||
} | ||
|
||
renderItem(item, index) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question is still valid.
background-color: #e1f5ff; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CS: Remove extra empty line here.
<div {...wrapperAttrs}> | ||
<TabContentPanelComponent {...props}> | ||
<div className="c-create-panel__first-step"> | ||
<div className="c-create-panel__step-title">1) {props.labels.contentOnTheFly.chooseLangaugeAndContentType}</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm?
|
||
fetch(request) | ||
.then(handleRequestResponse) | ||
.then(json => callback(json)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.then(callback)
|
||
fetch(request) | ||
.then(handleRequestResponse) | ||
.then(json => callback(json)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.then(callback)
if (this.props.onlyContentOnTheFly) { | ||
return ( | ||
<div className="m-ud__panels"> | ||
{this.renderSinglePanel(createPanelConfig)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking about moving these configs into some kidn of array. But maybe in other PR.
|
||
window.clearTimeout(this._filterTimeout); | ||
|
||
this._filterTimeout = window.setTimeout(() => { | ||
this.setState(state => Object.assign({}, state, {filterQuery: value})); | ||
this.setState(state => Object.assign({}, state, {filterQuery: filterQuery})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ filterQuery }
@@ -21,14 +21,14 @@ export default class ChooseLanguageComponent extends Component { | |||
|
|||
this.props.onLanguageSelected(selectedLanguage); | |||
|
|||
this.setState(state => Object.assign({}, state, {selected: selectedLanguage})); | |||
this.setState(state => Object.assign({}, state, {selectedLanguage: selectedLanguage})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ selectedLanguage }
</div> | ||
); | ||
} | ||
const CreateComponent = (props) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can drop import of React component in the first line: import React from 'react';
Jira ticket: https://jira.ez.no/browse/EZP-28841
Requires: ezsystems/ezplatform-admin-ui#366
TODO