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
DS integration in Webhooks Listview #10732
Conversation
Codecov Report
@@ Coverage Diff @@
## v4/ds-migration #10732 +/- ##
================================================
Coverage 57.73% 57.73%
================================================
Files 183 183
Lines 6466 6466
Branches 1343 1343
================================================
Hits 3733 3733
Misses 2263 2263
Partials 470 470
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report at Codecov.
|
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.
Overall, this looks great 😄 . I've put comments in the codebase, if something is not clear, feel free to reach out to me 😊 . Great job 👏🏻 🚀
@@ -1,4 +1,3 @@ | |||
import 'sanitize.css/sanitize.css'; |
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.
🎉 🚀 💥
title={headerProps.title.label} | ||
subtitle={headerProps.content} | ||
primaryAction={( | ||
<Button onClick={() => (canCreate ? handleGoTo('create') : {})} startIcon={<AddIcon />}> |
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 semantic HTML, a button is not a link. We should not use button to redirect to pages 😊
webhooksToDelete.length > 0 && webhooksToDelete.length < webhooks.length | ||
} | ||
value={webhooksToDelete.length === webhooks.length} | ||
onValueChange={value => handleCheckboxChange('main', 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.
I would suggest to separate the logic between checking the "main" checkbox and checking the other ones. This will reduce the complexity of the handleCheckboxChange
. Complexity, in this scenario, corresponds to the number paths existing in the "handleCheckboxChange".
And for clarity reasons, I would suggest to avoid the conditional in this function since it's arbitrary and note based on the data we have 😊
Something like:
const handleSelectAllCheckbox = () => {}
const handleSelectOneCheckbox = () => {}
<Row justifyContent="flex-end"> | ||
{canUpdate && ( | ||
<IconButton | ||
onClick={() => { | ||
handleGoTo(webhook.id); | ||
}} | ||
label="Edit" | ||
icon={<EditIcon />} | ||
noBorder | ||
/> | ||
)} | ||
{canDelete && ( | ||
<Box paddingLeft={1}> | ||
<IconButton | ||
onClick={() => handleDeleteClick(webhook.id)} | ||
label="Delete" | ||
icon={<DeleteIcon />} | ||
noBorder | ||
/> | ||
</Box> | ||
)} | ||
</Row> |
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.
Instead of doing this, in v9 (or 10) of parts, you can use:
<Stack horizontal size={1}>
<Button1/>
<Button2/>
</Stack>
and it will do the same as what you're trying to do 😊
<Header {...headerProps} /> | ||
{canRead && ( | ||
<div className="list-wrapper"> | ||
<HeaderLayout |
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 should have an h1
(<HeaderLayout as="h1" />
) on it and the page itself should have a <Main labelledBy="the-id-you-put-on-the-h1">
Hicham managed this the following way in the registration page 😊
- Concerning the Main component => https://github.com/strapi/strapi/pull/10733/files#diff-5b8fde11bf3bfe8ba7a3b27f0c5e0d3838892702ff8f1d93ab0589f7351d53abR72
- Concerning the title of the page => https://github.com/strapi/strapi/pull/10733/files#diff-5b8fde11bf3bfe8ba7a3b27f0c5e0d3838892702ff8f1d93ab0589f7351d53abR76
rowCount={webhooks.length} | ||
footer={( | ||
<TFooter onClick={() => (canCreate ? handleGoTo('create') : {})} icon={<AddIcon />}> | ||
Add another field to this collection type |
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 this should go in a translation file 😊 . You have exampelp in this file using the formatMessage
function
<Tr> | ||
<Th> | ||
<BaseCheckbox | ||
aria-label="Select all entries" |
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 also put it in a translation file 😊
/> | ||
</Th> | ||
<Th> | ||
<TableLabel>name</TableLabel> |
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.
Same concerning all the Th
content: I think they should go in a translation file 😛
<Td> | ||
<Row> | ||
<Switch | ||
onLabel="Enabled" |
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 won't comment about it anymore about it, but every string occurence of a word, in plain english, existing in this file, should go in a translation file 😊
); | ||
} | ||
|
||
export default ListView; | ||
|
||
// TO KEEP AS EXEMPLE UNTIL WE KNOW HOW TO DEAL WITH EVENTS AND FUNCTIONS DEFINED IN THIS COMPONENT |
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.
wut? 😆
@@ -267,6 +200,36 @@ function ListView() { | |||
} | |||
}; | |||
|
|||
const handleSelectAllCheckbox = () => { |
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 that function, you loop over webhooks 2 times.
The first time to extract ids. And the second time to select each webhook of the webhookIds.
I think you don't need to do that. You don't need to extract the ids of webhooks. Since you can access the state in the reducer function, you only need to create a function that select all the webhooks.
// Webhooks/ListView/index.js
const handleSelectAllCheckbox = () => {
dispatch({
type: 'SET_ALL_WEBHOOKS_TO_DELETE',
});
};
// Webhooks/ListView/reducer.js
...
case 'SET_ALL_WEBHOOKS_TO_DELETE': {
const { webhooks, webhooksToDelete } = state;
if (webhooks.length === webhooksToDelete.length) {
draftState.webhooksToDelete = initialState.webhooksToDelete;
} else {
draftState.webhooksToDelete = webhooks.map(webhook => webhook.id);
}
break;
}
...
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.
Don't forget to add some test to this reducer case 😄
import reducer, { initialState } from './reducer'; | ||
import PageTitle from '../../../components/SettingsPageTitle'; | ||
import adminPermissions from '../../../permissions'; | ||
|
||
function ListView() { |
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 will need to call the focus hook when the i18n list view will be merged.
|
||
<ContentLayout> | ||
<> | ||
{rowsCount > 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.
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 focus on it if you are already focused on the edit icon then using tab. I talked about it with Marvin, if I understood well it's because it's a button/action so you have to use tab to access 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.
Oh thanks for the button, indeed it is better with the tab. But, I still can't reach the last list row with the keyboard 😢
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.
(rows should include the header)
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 right same here, I'm not sure why though! @mfrachet do you have an idea? 🤕
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.
Fixed 🔥
{rowsCount > 0 ? ( | ||
<Table | ||
colCount={5} | ||
rowCount={webhooks.length} |
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.
rowCount is already defined on the top of the file : rowCount={rowsCount}
id: 'Settings.webhooks.list.all-entries.select', | ||
})} | ||
indeterminate={ | ||
webhooksToDelete.length > 0 && webhooksToDelete.length < webhooks.length |
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.
Same : webhooksToDelete.length > 0 && webhooksToDelete.length < rowsCount
indeterminate={ | ||
webhooksToDelete.length > 0 && webhooksToDelete.length < webhooks.length | ||
} | ||
value={webhooksToDelete.length === webhooks.length} |
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.
Same : webhooksToDelete.length === rowsCount
id={`${formatMessage({ id: 'Settings.webhooks.list.select' })} ${ | ||
webhook.id | ||
}`} | ||
name={`${formatMessage({ id: 'Settings.webhooks.list.select' })} ${ | ||
webhook.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.
The id
and name
aren't used to be understood by the user. We should use static names
and ids
not translated messages.
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 put a request for changes to investigate the a11y way to handle this page loading :)
linkText={formatMessage({ id: 'Settings.webhooks.list.empty.link' })} | ||
<Main labelledBy="webhooks"> | ||
{isLoading ? ( | ||
<LoadingIndicatorPage /> |
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.
Even when displaying the loader, I think the HeaderLayout should be on the page because else, during this tiny moment where nothing is displayed, there's nothing on the screen and the page is in an invalid state because there's not H1 on it.
Also, when loading something, you can put a aria-busy={isLoading}
on the "Main" component so that it tells people using ATs that something is happening.
Later on, when the data has been loader, I think it's a common practice to use an aria region to announce that the content has been loaded and that the content of the Table is ready to be navigated 😊
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.
Good job !!
What does it do?
Integration of DS components in Settings/Webhooks Listview 💅
Actions still work using actions logic that was already there - refacto after this PR
Old List component left in comments for future implementation of actions (as PopUpWarning)
Demo
Run this branch