-
Notifications
You must be signed in to change notification settings - Fork 91
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
#7 Permissions #9
Conversation
}); | ||
return { groupedPermissions, loaded: true }; | ||
}) | ||
.then(data => this.setState({ ...data })) |
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 can we not use .then(data => this.setState)
?
return { groupedPermissions, loaded: true }; | ||
}) | ||
.then(data => this.setState({ ...data })) | ||
.catch(console.log); |
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.
Let's console.error that?
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.
Maybe we could route it through winston and have logger.error
here instead?
https://www.npmjs.com/package/winston
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.
Should we create a quick ticket to track this? For me ideally we write the data one day back to Drupal
.eslintrc.json
Outdated
{ | ||
"extends": [ | ||
"eslint-config-airbnb", | ||
"plugin:prettier/recommended" |
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.
Nice!
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.
🤓
<Fragment key={`fragment-${permissionGroupName}`}> | ||
<tr key={`permissionGroup-${permissionGroupName}`}> | ||
<td>{permissionGroupName}</td> | ||
</tr> |
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 just love how prettier ensures things aren't too dense, honestly!
Is this still a problem? |
When you access the user roles they will each have a list of permissions they have
Do you think this is super useful? I can't really think of a usecase for that.
Yes! See my comment in the PR |
loaded: false, | ||
}; | ||
componentDidMount() { | ||
fetch(`${drupalOrigin}/permissions?_format=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.
I think we should group the permissions when we render. Otherwise live filtering permissions would be a bit more pain. Thoughts?
.eslintignore
Outdated
@@ -0,0 +1 @@ | |||
build/**/*.js |
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.
.eslintrc.json
Outdated
{ | ||
"extends": [ | ||
"eslint-config-airbnb", | ||
"plugin:prettier/recommended" |
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.
🤓
.eslintrc.json
Outdated
"rules": { | ||
"no-param-reassign": [0], | ||
"no-underscore-dangle": [0], | ||
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }] |
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's the advantage of doing this?
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 put JSX in .js files.
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.
Should we stick with one way? At work we use JS, because well, that's what is in there :)
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 fine with that, but I think all this stuff needs moving over to a separate issue to discuss how/where we deviate from CRA
.prettierrc.json
Outdated
"printWidth": 80, | ||
"semi": true, | ||
"singleQuote": true, | ||
"trailingComma": "all" |
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.
💃
package.json
Outdated
@@ -9,9 +9,19 @@ | |||
"react-router-dom": "^4.2.2" | |||
}, | |||
"devDependencies": { | |||
"eslint": "^4.9.0", |
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.
Aren't these already included with CRA?
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.
Eslint is included with CRA, but none of the other deps we need for airbnb or prettier 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.
CRA uses eslint:recommended instead (see facebook/create-react-app#3540 (comment)), but I think we can avoid this when we bump to react-scripts 2.0 (if we do want airbnb here).
Can we split this eslint/prettier stuff into a separate PR so we can continue there and not hold things up here.
src/App.jsx
Outdated
@@ -20,7 +16,7 @@ class NoMatch extends Component { | |||
render() { | |||
return null; | |||
} | |||
}; |
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.
Was this a prettier fix?
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?
<p>This will be the permissions page.</p> | ||
</div> | ||
); | ||
const drupalOrigin = 'http://localhost:9998'; |
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.
let's add this in with dotenv (already included in CRA)
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 a bit of a pane involved with CRE here. Environment variables aren't passed along unless they are prefixed with react. I had this problem when working on my config experiment, see https://github.com/jsdrupal/drupal-admin-ui/compare/config-experiment-2#diff-01454d5c4c96a618ac33dd690eb3c20bR128
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 hope we can workaround that though :)
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.
oh yeah, I forgot about that. I think prefixing with REACT_ is totally fine 👍
return { groupedPermissions, loaded: true }; | ||
}) | ||
.then(data => this.setState({ ...data })) | ||
.catch(console.log); |
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.
Maybe we could route it through winston and have logger.error
here instead?
https://www.npmjs.com/package/winston
return ( | ||
<Fragment> | ||
{!this.state.loaded ? ( | ||
<p>loading...</p> |
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.
s/.../… 🤓
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 wondering whether there is a better thing to show
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.
a party parrot, obviously
render() { | ||
return ( | ||
<Fragment> | ||
{!this.state.loaded ? ( |
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.
Here is a generic question. Is there a reason why you do the condition inside the fragment and not outside of it?
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 we're just returning the <table />
here we probably don't even need the fragment at all.
loaded: false, | ||
}; | ||
componentDidMount() { | ||
Promise.all([ |
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.
Also a general question. Don't we need some handling for the case that the component is not longer active but the promise resolves? (ideally we would cancel the promise as part of componentDidUnmount
or something like that.
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, we could set the promise up in the constructor and just execute when the component mounts, and cancel it later.
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.
Let's keep that up as a todo, I guess?
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'll just get these wrapped up today. :)
componentWillUnmount() { | ||
this.cancelFetch(); | ||
} | ||
fetchData = () => |
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 can drop this now :)
`${process.env.REACT_APP_DRUPAL_BASE_URL}/jsonapi/user_role/user_role`, | ||
).then(res => res.json()), | ||
]); | ||
groupPermissions = permissions => |
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.
Nice code!
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.
One thing we will need to figure out, is how to handle polyfills. Since this uses entries
we will want to figure that out.
([permissionGroupName, permissions]) => | ||
permissions.length && ( | ||
<Fragment key={`fragment-${permissionGroupName}`}> | ||
<tr key={`permissionGroup-${permissionGroupName}`}> |
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.
Do we need key
on both levels?
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.
Yep. Which is strange, but each element within the loop needs a key.
permission.id | ||
}`} | ||
> | ||
{attributes.is_admin && |
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.
Nice level of detail!
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.
👍
src/components/UI/table.js
Outdated
zebra: false, | ||
}; | ||
|
||
const TBODY = ({ children, ...props }) => <tbody {...props}>{children}</tbody>; |
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.
Oh default HTML elements don't offer proptypes?
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 I wanted to provide these wrappers so if we want to provide styling/functionality for basic DOM elements, we can do it all in one place and those changes will be reflected everywhere.
], | ||
})), | ||
]) | ||
.reduce((a, b) => a.concat(b), [])} |
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.
Note: You can use [].concat(...a)
instead of the reduce.
src/components/Helpers/Loading.js
Outdated
|
||
const Loading = () => ( | ||
<div className={spinner}> | ||
<div className="bounce1" /> |
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've had some really Bad Times(tm) with using class names this way when the project starts to grow. The best way we've found is to have an object called styles and then do className={styles.spinner}
, className={styles.bounce1}
etc
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.
Yep, this totally makes sense.
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 resolved this?
@@ -108,7 +100,7 @@ const Permissions = class Permissions extends Component { | |||
) : ( | |||
<input | |||
type="checkbox" | |||
onChange={e => | |||
onChange={() => |
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 wondering: Is there a way to avoid creating new functions for each rendered checkbox?
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.
@dawehner Let me investigate that.
Co-authored-by: Michael Herchel <[email protected]>
src/components/Helpers/Loading.js
Outdated
peace: css` | ||
::before { | ||
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.
✌️
src/components/Helpers/Loading.js
Outdated
<span className={styles.peace} /> | ||
<span className={styles.right} /> | ||
<span className={styles.peace} role="img" aria-label="Peace Sign"> | ||
✌️ |
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.
✌️
src/components/Helpers/Loading.js
Outdated
transform-origin: bottom; | ||
font-size: 50px; | ||
animation-name: rotate; | ||
@keyframes rotate { |
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.
Does this actually work? I've done keyframes in emotion according to https://github.com/emotion-js/emotion/blob/master/docs/keyframes.md
const rotate = keyframes`
//...
`
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.
✌️
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 PR is amazing
src/components/UI/table.js
Outdated
<tbody> | ||
{rows.map(({ colspan, tds, key }) => ( | ||
<TR key={key}> | ||
{generateIDs(tds).map(({ id, value }) => ( |
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's the advantage of doing this over using the array 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.
React gets sad if you use the index as part of the key.
src/components/UI/index.js
Outdated
@@ -0,0 +1,9 @@ | |||
import { TR, TD, TABLE, TBODY, THEAD } from './table'; | |||
|
|||
export { |
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 do we do this instead of directly importing from a table file?
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 did this so if we ever have any other components, they are all importable from a single file.
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.
Personally I think we should come back at some point and have a look at the bigger picture to understand how we can make the entire app more readable and not just single bits and pieces.
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 had a look at some other libraries and the lodash method seems to be popular where you pull in the thing you need like import { td, tr } from 'ui/table'
, but yeah we can address this in a follow up, doesn't need to block this PR
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.
@justafish @dawehner We can pretty easily switch up the exports here. Probably better to set a good initial pattern.
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.
@mattgrill cool cool, let's do away with index.js then. Not sure what we should have the exports as exactly? My preference would be:TD
, TR
, Table
, TBody
, and THead
fetch( | ||
`${ | ||
process.env.REACT_APP_DRUPAL_BASE_URL | ||
}/jsonapi/user_role/user_role`, |
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 probably want to add the Accept: application/vnd.api+json
header. This will enable 404/403 errors in JSON format (if any). Otherwise they'll come back as HTML errors.
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.
👍
); | ||
|
||
createTableRows = (groupedPermissions, roles) => | ||
[].concat( |
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 [].concat()
instead of array spreads? It seems you prefer spreads elsewhere.
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.
For clarity, I'm not after any change here, I'm genuinely curious.
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.
@e0ipso It's a bit subtle, but this is the easiest way to flatten the two-dimensional array that's created from constructing the table rows.
Pretty awesome. I almost followed most of it. |
Based on the conversation, perhaps we can merge this today? |
A small highlight of the current permissions page work. |
Evaluator improvements
Setup
Permissions