-
Notifications
You must be signed in to change notification settings - Fork 49
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
Bug fixes and Plugin Versions content #231
Conversation
@jennydaman After this is merged, the master branch can be deployed. |
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 noticed that the screens for "plugin meta" (/plugin/pl-name
) v.s. "plugin" (/p/14
) are the same. This is okay for now but we will need to make them distinct in the future.
I think I said this before, the "Install to ChRIS" url should be something from the backend API's data. It should not be built from string concatenation/template. On top of that, the template you are using is not correct for /p/<N>
routes.
Also note that all backend API handles must end in trailing slashes. However, you shouldn't have to worry about this if you are using the client correctly, that is, avoid concatenating URLs and instead use the URLs as they are returned by the backend. |
The URL was only being built for the |
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 finally got around to understanding how this all works, and a few notes.
The <Switch>
in Plugins.jsx
is nested under the component exported by Router.jsx
right? Having a nested router which manipulates routes at the same level (here, both are manipulating top-level routes) is highly prone to errors. I suggest refactoring such that the application only has one top-level <Switch>
.
Regarding <Plugin>
: optional props are okay, and here pluginData
is optional. But self-fulfilling optional parameters is poor design. When arguments are not given to an object (component), the object should either show a default or do nothing (component is blank), it should not try and fulfill its own arguments (props). This is especially true in the world of React because you're blurring the line between props and state, where props are not mutable by the component itself.
On top of the "self-fulfilling parameter" the if-else of componentDidMount causes further branching of logic leading to high code complexity.
In OOP there is a concept "inversion of dependency," where it is the client's responsibility to coerce data to the object's interface. In React speak, the parent component in Plugins.jsx
(more specifically, whichever Switch > Route
is the parent to <Plugin>
) should be responsible for wrangling its data to match the expected props for <Plugin>
. In effect, you should move the complicated network requests and data (pluginData
) coercion code within the execution tree of Plugin.componentDidMount
(so also consider fetchPluginVersions
and fetchPluginData
) to its parent (which in your implementation, the parent is defined in Plugins.jsx
). The goal would be for Plugin.jsx
to define a stateless component which does nothing more than display the data its given, without trying to modify nor create data in any way. It would be the sole responsibility of Plugins.jsx
to provide the correct data. This responsibility of "providing the correct data" should happen in one place and one place only. If you want to support the /plugins
to /plugin/pl-name
data saving feature, and you want <Plugin>
to be nested under <Plugins>
, then <Plugins>
should be responsible for providing the correct data to <Plugin>
in all cases, and <Plugin>
should be a "dumb" stateless component which operates with what it is given and does nothing else.
@jennydaman Okay so to understand better
I think if one component was to do all the data coersion it would first mean that that component would be too big and certain methods in that component would only be used when children are rendered, not when it's own content is rendered. So that would probably go against separation of concerns. |
Here is the reason I would argue it is convoluted (not ideal): The
When there is one
Let's start on common ground and agree that having only one What about when we have two Switches, which listen on the same resource, and affect the same resource?
In this situation, complexity is increased because This is a simplification of our situation because in reality, you have The ChRIS_store_ui and the ChRIS_store are relatively simple applications and it's preferable to not have to make these kind of software design decisions and tradeoffs if we can avoid them. |
If you weren't given a certain piece of data as a prop, you shouldn't be trying to find the data yourself and then storing it as a state. If a category of data is being represented by a prop, then the component should consider that piece of data immutable. This is a design choice that you must go all-or-nothing: do you want A) Hint: if you are interested in the feature where data from |
You are trying to use the code for showing details about a plugin for both showing plugin details or plugin meta details, where plugin != plugin meta. So we've already bit the bullet (bitten? bullet has been bit?) |
The most ideal but time-consuming way forward would be to develop two separate screens for plugin vs plugin meta details. If you don't want to/don't have time for that. then we have to do some sort of data cohesion somewhere, and we are debating where is best for this code to be. My argument is that the code for data cohesion should not exist in the |
It's not a big deal, I am just pointing out this I would prefer it if the if/else can be moved outside of |
The nested
Their behavior is now predictable. |
Fixes: #199
Fixes: #230
Versions Content
Add list of versions to content section and add choice of which version to install in the install button.