-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Add an API to add a plugin sidebar (new) #4777
Conversation
I think I said this on the last PR, but I'll say it again: nice work — I think developers will love this API. Keep in mind I can only speak for the UI and user experienceon this, so take any thoughts from me in that vein. The principles are these:
As also mentioned in a previous PR, not all of these principles have to be part of THIS PR. It's totally fine that we address these later on. But I'm explicitly stating these so we can have some agreement as to where this should end up. If we agree this is the approach to pursue and this will be possible and desirable, then I think UI wise this PR is good to go after two quick visual fixes. The plugin sidebar should look a bit more like the standard sidebar: Right now the plugin sidebar has a bigger font size in the title (should be With those tiny visual tweaks, and an agreement as to where to go next, 👍 👍 from me on the visuals and interaction! |
Another quick note I forgot to mention — the behavior for the sidebar hiding and not restoring when you resize the screen has regressed from master. We should ideally restore it like we do in master. We also need to be sure that the mobile experience is good, the modal sidebar system has regressed also: But modals on mobile need imminent polish regardless, as part of #4082, so perhaps that doesn't need to be addressed in this PR. The thing is — due to how WordPress handles fixed and sticky toolbars at various breakpoints, and due to the need to handle mobile scroll bleed (don't scroll content underneath the modal when you're swiping, and also don't lose your place when you open a modal), it's difficult to get the modals to behave well here. I know @youknowriad has a component that takes some of the vinegar out. |
edit-post/store/selectors.js
Outdated
* @return {string} Active plugin sidebar plugin | ||
*/ | ||
export function getActivePlugin( state ) { | ||
return getPreference( state, 'activeSidebarPanel', {} ).plugins; |
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.
Minor: in the state tree we save as "plugins", but the selector uses "Plugin". Should we allow more than one plugin to be active? If yes the selector should be renamed to getActivePlugins if not the property should be renamed to plugin.
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.
@jorgefilipecosta That's a good question. I think because this function is sidebar specific (using 'activeSidebarPanel' in the getPreference function), there could only be one plugin active at any given time. I'll rename the property accordingly.
export default connect( | ||
( state ) => { | ||
return { | ||
plugin: getActivePlugin( state ), |
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.
It looks like this will always return null (and we will see the 'No matching plugin sidebar found for plugin ""'), because the store being queried here is not the store that contains the active ActiveEditorPanel preference.
We can confirm that by adding console.log( 'PluginsPanel' , state ); before the return.
We can correct that by specifying the store key:
export default connect(
( state ) => {
return {
plugin: getActivePlugin( state ),
};
}, {
onClose: closeGeneralSidebar,
}, undefined,
{ storeKey: 'edit-post' }
)( withFocusReturn( PluginsPanel ) );
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.
It looks like the changes, to the mobile sidebar, hiding/persisting behavior are good, nice job in that refactoring 👍
edit-post/store/defaults.js
Outdated
publish: false, | ||
editorMode: 'visual', | ||
viewportType: 'desktop', // 'desktop' | 'mobile' | ||
activeGeneralSidebar: null, // null | 'editor' | 'plugins' |
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 here we should set activeGeneralSidebar to 'editor', otherwise, we are introducing a behavior change because when reloading the page without preferences stored in localStorage no sidebar will be active.
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.
Thank you for your work on this PR. It looks like we are pretty close to have it merged.
I think we still need to clarify how the public API should look like. I left some question regarding renderSidebar
and getSidebarSettings
methods exposed. It seems like registerSidebar
would be a better fit here. I'm wondering what's your take on this and why it has changed in this new PR.
I played with the code locally and I saw some issues:
I think @jorgefilipecosta found the reason of this issue. We need to fix it before merging this PR. The screenshot I shared reveals also the issue with the renderSidebar
method - which registers the sidebar every time it's going to be executed. This needs to be optimized.
I have a feeling that it might be possible to reuse or extract more functionality out of the existing sidebar components. This might be done in the follow-up PRs, we just should identify what would be the best way to move forward.
Another thing to think about in the future (not for this PR) is if we could handle the global settings and block settings as sidebar plugins, too. This would allow us further simplify the way we handle state because we wouldn't have to worry about two competing sidebars which want to be displayed in the same area.
Let's make sure there are no unexpected behaviors and come up with the plan how to continue work on this feature.
edit-post/api/sidebar.js
Outdated
*/ | ||
function activateSidebar( name ) { | ||
store.dispatch( openGeneralSidebar( 'plugins' ) ); | ||
store.dispatch( setGeneralSidebarActivePanel( 'plugins', name ) ); |
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.
Would be it possible to dispatch one action named after the function (activateSidebar
) to update all reducers that are involved in this state update?
Isn't meant to be dispatched directly inside the menu component in the future? What is the reason for having it outside of the component's lifecycle?
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 will be addressed in a next iteration
edit-post/api/index.js
Outdated
@@ -0,0 +1,4 @@ | |||
export { | |||
renderSidebar, | |||
getSidebarSettings, |
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 you give an example of the use case where getSidebarSettings
would be useful for plugin developers? It not used in the code as part of this API. I don't see also any comments in the PRs description. It would be nice to have a better overview on how this API might work.
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 exposure of getSidebarSettings was a remnant of some debugging. I'll remove it from the API. I cannot think of a reason to leave it exposed. When someone thinks of a use case it can be exposed again.
return null; | ||
} | ||
|
||
settings = applyFilters( 'editor.registerSidebar', settings, name ); |
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 we have the same logic in blocks.registerBlockType
. I'm afraid this needs to be further discussed. The thing is that it happens after validation process is done, so you can update all settings however you want and it won't be validated again. It seems like this should happen before the validation begins.
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 will be addressed in a next iteration
edit-post/api/index.js
Outdated
@@ -0,0 +1,4 @@ | |||
export { | |||
renderSidebar, |
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.
In the previous version, we had registerSidebar
exposed in the public API. What was the reason to use renderSidebar
instead?
edit-post/api/sidebar.js
Outdated
* | ||
* @return {void} | ||
*/ | ||
export function renderSidebar( name, settings ) { |
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.
When I call this method twice for the same name
, I see the following error on the console:
Sidebar my-plugin/my-sidebar is already registered.
This is exposed as public API. I assume this is what would be executed from the menu, so it shouldn't register the same sidebar every time a user clicks on the menu item.
/> | ||
</div> | ||
<div className="editor-plugins-panel__content"> | ||
{ render() } |
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 won't work properly in the case where render
property will contain Component class. It should follow React guidelines here: Composing Components.
<div>
<RenderComponent />
</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.
On second thought I don't think we need to change that. It is perfectly fine as long as we make it clear that you need to return WPElement
from the function, similar to what createElement produces:
class MyComponent extends Component {
render() {
return <div>My Component</div>
}
}
const render = () => <MyComponent />;
render, | ||
} = getPluginSidebar( plugin ); | ||
return ( | ||
<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.
This component is almost identical to <Sidebar /
. It would be nice to reuse it here. See:
https://github.com/WordPress/gutenberg/blob/master/edit-post/components/sidebar/index.js#L24
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.
Since <Header/>
is nested inside <Sidebar/>
, this would be something for a next iteration as well (see comment below https://github.com/WordPress/gutenberg/pull/4777/files/3cdf86f520f8f379b50eeed62872e24fb7516b76#r167880008)
tabIndex="-1"> | ||
<div className="editor-plugins-panel__header"> | ||
<h3>{ title }</h3> | ||
<IconButton |
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 is also <Header />
component which looks similar to what we have here: https://github.com/WordPress/gutenberg/blob/master/edit-post/components/sidebar/header.js#L41. For instance it contains an identical close button. Is it possible to make those components more flexible so we could use them in here, too?
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 close button is the only similarity. The header in sidebar/header.js solely consists of three buttons. The header component may be generalized to fit both headers, but that's something for a next iteration.
edit-post/components/layout/index.js
Outdated
import { closeGeneralSidebar, closePublishSidebar } from '../../store/actions'; | ||
import PluginsPanel from '../../components/plugins-panel/index.js'; | ||
|
||
function GeneralSidebar( { openedGeneralSidebar } ) { |
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 might be inlined inside the component that is consuming it. If it is going to be reused in other places it should be moved to its own file.
edit-post/components/layout/index.js
Outdated
{ publishSidebarOpen && <PostPublishPanel onClose={ onClosePublishSidebar } /> } | ||
{ | ||
openedGeneralSidebar !== null && <GeneralSidebar | ||
onCloseGeneralSidebar={ onCloseGeneralSidebar } |
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.
Both props passed down aren't propagated to the child components.
We are persisting the active plugin panel, so if when we reload because of some reason the sidebar is not available (e.g: plugin was uninstalled) we immediately enter into an error state. As an improvement when loading the preferences from localStorage we should check if the sidebar is available before showing the error. |
Thank you a lot for the work in this PR, I left some suggestions about possible improvements/bugfixes but generally, it looks like we are getting close to a merge :) |
@@ -8,7 +8,6 @@ import { registerReducer, withRehydratation, loadAndPersist } from '@wordpress/d | |||
*/ | |||
import reducer from './reducer'; | |||
import enhanceWithBrowserSize from './mobile'; | |||
import applyMiddlewares from './middlewares'; | |||
import { BREAK_MEDIUM } from './constants'; |
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 don't need ./middlewares
file anymore if we stop using it here.
@youknowriad can you confirm we can remove it completely?
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.
yes, it's a local dependency if the mobile middleware is gone we can safely remove it. but how is the mobile Middleware replaced right now? Sorry didn't review in depth?
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 need for mobile middleware was removed because of a logic was changed. As a side effect:
The sidebar is hidden when you change from desktop to mobile. However, it's not saved that it was opened before, which means it will not be reopened when switching back to desktop.
I think it is ok to remove that behavior as the reopen from mobile to desktop was not an initial requirement. And we can try to propose a solution for that if required after this PR is merged.
While I really want this to get merged in, I would object to the merger until these UI issues are fixed. Specifically:
My primary concern is that we merge this in and work on addressing the UI glitches falls through the cracks, forgotten mostly because you'd only ever see it if you also installed a plugin that took advantage of this new API, which very few would do. |
The improvements I referred in the last review are addressed, thank you for applying the fixes. |
@jasmussen My bad. I was under the impression that I had fixed those UI things when I did a CSS review and removed duplicate CSS, which wasn't the case. I've just pushed more CSS changes to address the issues you raised. @jorgefilipecosta @gziolo I'll address your feedback tomorrow. |
@@ -12,6 +12,10 @@ | |||
|
|||
h3 { | |||
margin: 0; | |||
font-weight: 400; | |||
color: inherit; |
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.
Haven't had time to check, but should the font size also be addressed? The font size should be 13px, and you get that from the $default-font-size variable here https://github.com/WordPress/gutenberg/blob/master/edit-post/assets/stylesheets/_variables.scss#L7
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 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.
Ah right, sorry, wasn't able to test. No that looks good. Though feel free to set the font weight to 600 so it's bold, like an active tab. Otherwise 👍 👍
I added a few commits to remove the sidebar state with error messages. Let's tackle it separately in a way that is less confusing for the users, but at the same time helpful for site owners so they could get proper feedback. At this moment when there is no matching sidebar registered by Redux has active plugin stored, we stop rendering sidebar. Let's iterate on this in the follow-up PR. |
There is one known issue. Steps to reproduce:
This is not likely that user will get into such flow, so I think we can fix it in a follow-up PR. @IreneStr thanks for working on this one. It looks solid and we can proceed. We agreed that it's better to merge it in the current shape and address all the comments in the smaller targeted PRs. ✨ |
Description
This adds an API that plugins can use to add sidebars.
The API looks like this:
How Has This Been Tested?
There is a PR on Yoast SEO to test this with. Yoast/wordpress-seo#8531 shows how the API can be used.
Screenshots (jpeg or gifs if applicable):
Types of changes
New API
Checklist:
Remarks
No matching plugin sidebar found for plugin [plugin name]
. When refreshing the page with the sidebar opened, the same error will appear.viewport
property in the state (it used to be based onsidebar: 'mobile'
in the state). I've removed the mobile middleware in theedit-post
folder. It would be great if someone can double check whether I didn't break anything related to that.For more comments, see #4109