Skip to content
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

Enhancement: add injector to gallery toolbar #712

Merged

Conversation

blueo
Copy link
Contributor

@blueo blueo commented Dec 16, 2017

This is prototype for adding some injection points to the gallery section so the upload/create files buttons can be customised or added to.

Currently it is tricky to separate theses buttons because they effect changes that use the router/params. To this end, I have created an adminDecorator to allow passing of the router and location, along with common url-related functions to injected components (notably handleBrowse). This avoids needing to pass these objects down the component tree.

I'd love some feedback on my approach to using the injector and the decorator concept / better ways to setup injected components.

current plans include:

  • shift more state into redux to allow cleaner separation of components
  • inject the GalleryView component

relevant issues:

@flamerohr flamerohr self-assigned this Dec 18, 2017
@blueo blueo force-pushed the pulls/add-injector-to-gallery-toolbar branch from 4e9f11b to b640840 Compare December 22, 2017 02:26
@blueo blueo force-pushed the pulls/add-injector-to-gallery-toolbar branch from b640840 to 4110b6e Compare January 8, 2018 02:11
@blueo
Copy link
Contributor Author

blueo commented Jan 8, 2018

happy new year @flamerohr :) I've removed the adminDecorator and changed GalleryToolbar so its buttons can be changed via props or new buttons can be added as 'children'. I've also moved the sorters into redux so they can be updated via the injectory (if you'd prefer this as a separate PR let me know :))

@blueo blueo force-pushed the pulls/add-injector-to-gallery-toolbar branch 2 times, most recently from 560bd9a to c3702a1 Compare January 11, 2018 00:38
@flamerohr flamerohr added this to the Recipe 4.1.0 milestone Jan 14, 2018
Copy link
Contributor

@flamerohr flamerohr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, pretty neat work done, a few comments that would be good to get addressed :)

Let me know if you don't get time to apply the changes

onCreateFolder();
}
event.preventDefault();
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could have this handleCreateFolder defined as a const in the AddFolderButton function, did you prefer the factory paradigm instead?

I can see the benefit of simpler unit tests though, perhaps that could be added for this function as well :)

handleMoveFiles,
}) {
const { parentId: itemId } = folder;
if (itemId !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we flip this and have the early return null instead


describe('render BackButton', () => {
it('should not render if parentId is not set', () => {
expect(Component({ ...props })).toBeNull();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest importing React and writing this as if a react component <Component {...props} />
Makes it clear that we are primarily treating it that way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh so turns out renderIntoDocument doesn't play well with stateless components. (see https://stackoverflow.com/questions/36682241/testing-functional-components-with-renderintodocument). The options are to 1) leave it as it is or 2) add a wrapper. I'd prefer to leave it like this unless you already have a similar setup for other components?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh...
I think we only have one or two stateless components and the rest as classes regardless of stateful-ness.
Could we convert the component is a class? (with eslint-disable if required)

I've been meaning to turn off the react/prefer-stateless-components rule for a while now.

// Button components
BackButton, // eslint-disable-line no-shadow
UploadButton, // eslint-disable-line no-shadow
AddFolderButton, // eslint-disable-line no-shadow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we give a different name to the imported components? BackButtonDefault or such?
I think the no-shadow linting rule is important to have

jest.mock('components/AssetDropzone/AssetDropzone');
jest.mock('components/BulkActions/BulkActions');
jest.mock('containers/MoveModal/MoveModal');
jest.mock('../Buttons/BackButton');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need to mock BackButton if you can override it in the props already?
Could mock all the child components in the props where possible

// set default sort
if (!sort) {
sort = `${sorters[0].field},${sorters[0].direction}`;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come this was moved from defaultProps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default sort was created from a constant but I've moved the sort info into redux so the default can't be created without the context from the store.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort wasn't stored in redux because it came from react-router url params - duplication of data.

Hmm... I didn't notice it being moved to redux.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry 'sort' does come from the router but I moved 'sorters' as otherwise it was impossible to customise the sort dropdown. But the result is that the default 'sort' needs the redux info from 'sorters'

Copy link
Contributor

@flamerohr flamerohr Jan 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, you're right!

neat, ok I can see why it's needed here now.

P.S. Perhaps have a truthy sorters[0] check, if it's customisable - someone's going to be naughty with it :D


export default compose(
inject(
['GalleryToolbar'],
GalleryToolbar => ({ GalleryToolbar }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be null for default behaviour :)

TableView.propTypes = galleryViewPropTypes;
TableView.propTypes = {
...galleryViewPropTypes,
sort: PropTypes.string.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this belonging in the galleryViewPropTypes variable more than being standalone here and not required.

I'm pretty sure it was defined in a sharedPropTypes somewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was in the shared props but I moved it for a couple of reasons:

  1. Not all the components with shared props needed it (ThumbnailView).
  2. I wanted to make the proptype check stricter on those components that did need it.

I could move it back to being an optional prop in the shared variable though if needed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I overlooked ThumbnailView not needing it now (used to be, until the sorter got move up a level)

cool, this stays then :D

Copy link
Contributor

@flamerohr flamerohr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It all looks good to me, nice work.
One minor comment to address when you rebase

Can be merged on green

const button = ReactTestUtils.renderIntoDocument(<Component {...props} />);
button.handleCreateFolder(new Event('click'));

expect(props.onCreateFolder).toBeCalledWith();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.toBeCalled() should be enough if no params are expected :)

created GalleryToolbar component
GalleryToolbar Buttons components added as default props
allowed adding extra buttons as children of GalleryToolbar
@blueo blueo force-pushed the pulls/add-injector-to-gallery-toolbar branch from c44238e to 8bd033f Compare January 18, 2018 02:55
@blueo blueo changed the title [WIP] Enhancement: add injector to gallery toolbar Enhancement: add injector to gallery toolbar Jan 18, 2018
@flamerohr flamerohr force-pushed the pulls/add-injector-to-gallery-toolbar branch from 8bd033f to 86b1188 Compare January 18, 2018 07:04
@flamerohr
Copy link
Contributor

I had amended the props handleMoveFile and handleSort which I overlooked and should've been named onMoveFile and onSort :)

handleMoveFile and handleSort are valid class method names, but props should be on prefixed instead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants