-
Notifications
You must be signed in to change notification settings - Fork 0
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
Implement Table Actions pattern and default columns #998
Conversation
@@ -11,11 +12,10 @@ import { | |||
} from '@/types/gqlTypes'; | |||
import { generateSafePath } from '@/utils/pathEncoding'; | |||
|
|||
const columns: ColumnDef<ServiceTypeConfigFieldsFragment>[] = [ | |||
const COLUMNS: ColumnDef<ServiceTypeConfigFieldsFragment>[] = [ |
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 had briefly discussed storing all column definitions centrally, in a code-version of the beautiful column spreadsheet. In the end I didn't decide to do that in this PR, because I was worried it would be too much code churn for now. But I'm still somewhat interested in the idea -- you can see in this PR that we have a mix of approaches, some columns defined inline, some defined and exported and used by other components, and some defined in a util file.
I did try to standardize around only using useMemo/useCallback
for columns and table actions when they have dependencies in the component props/state, and otherwise defining them in the same file but outside the component, like here. Let me know if you think this is a good approach.
record.enrollment.client.id, | ||
record.enrollment.id | ||
), | ||
state: { backToLabel: project.projectName }, |
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.
Moving this into the table action enables removal of the rowLinkState
prop on GenericTable
src/modules/projects/components/tables/ProjectClientEnrollmentsTable.tsx
Show resolved
Hide resolved
[] | ||
); | ||
|
||
const getTableRowActions = useCallback( |
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.
Changing this table is out of scope of the ticket (not in the spreadsheet), but it was an especially easy example to update to the new pattern since it already used an Action Button column, so I pulled it in.
header: 'Name', | ||
key: 'name', | ||
render: (client) => <ClientName client={asClient(client)} linkToProfile />, | ||
}, | ||
linkedNameNewTab: { |
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 removed those that weren't used anymore, but there are still a few here (like linkedNameNewTab
) that are used in out-of-scope table that I didn't update.
@@ -6,24 +6,31 @@ import { parseAndFormatDate, serviceDetails } from '@/modules/hmis/hmisUtil'; | |||
import { |
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 this file should be renamed to util.ts
?
@@ -65,18 +65,6 @@ export const generateAssessmentPath = ( | |||
}); | |||
}; | |||
|
|||
export const assessmentRowLinkTo = ( |
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 removed this in favor of keeping the assessment link consistent. I think this means that now, any table column that links to an assessment will open it in a household context if applicable. I'm not 100% confident in this change, maybe there was a good reason for the Client assessments page to link to the individual assessment view? I'm torn about whether it seems better to be consistent or maintain the previous behavior, let me know what you think.
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 was a design decision so lets review with design before reverting 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.
I see, thanks. Let's keep the behavior. I think we can still simplify the code by using generateAssessmentPath
's individualViewOnly
. Existing behavior that this PR replicates per 004ea99:
- Household Assessments (qa example -> Household toggle) opens the assessment in household context if applicable
- Enrollment Assessments (qa example) opens the assessment in household context if applicable
- Client Assessments (qa example) always opens the assessment in individual context
- Project Assessments (qa example) always opens the assessment in individual context
secondaryActions?.map((s) => { | ||
return { | ||
...s, | ||
ariaLabel: s.ariaLabel || `${s.title}, ${recordName}`, |
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 to support multiple ways of specifying the aria label? I wonder if we should just make it required on the primary/secondary action definitions, to simplify the logic. (Instead of inferring them based on recordName
and title
)
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.
Hm yeah I agree that it's not worth the extra code complexity. But I also don't necessarily think we should make ariaLabel
required on CommonMenuItem
. In general, adding additional aria labels that express something beyond what the button text itself says should be optional.
I'm proposing this middle ground where the primary action's default aria label is set using title
and recordName
, if not provided in props, while secondary actions can "fend for themselves" in terms of aria labels. I think it's an ok balance. Let me know what you think, though, I'm happy to reconfigure it.
This comment was marked as outdated.
This comment was marked as outdated.
@@ -247,7 +243,12 @@ const GenericTable = <T extends { id: string }>({ | |||
width: def.width, | |||
}} | |||
> | |||
<strong>{def.header}</strong> | |||
{def.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.
Continuing the thread from here:
{def.key || def.someOtherFieldThatsRequiredIfHeaderIsMissing}
If you agree, I was thinking that based on the comment here,
unique key for element. if not provided, header is used
We probably don't really need to add an extra someOtherFieldThatsRequiredIfHeaderIsMissing
, because key
should serve exactly that purpose.
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 -- sounds good, I see that with the union types you achieved that required-ness of header
or key
. Looks good!
@@ -54,7 +56,7 @@ const RelativeDateDisplay = ({ | |||
<Tooltip | |||
title={ | |||
<Typography component='span' variant='inherit'> | |||
{formattedDate} | |||
{formattedDate} {tooltipSuffixText} |
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.
Moved over from other PR #989 (comment)
secondaryActionConfigs={[ | ||
{ | ||
...getViewEnrollmentMenuItem(row.enrollment, { | ||
id: clientId, |
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 is the use case for #989 (comment)
) => { | ||
return { | ||
title: 'View Enrollment', | ||
key: 'enrollment', | ||
ariaLabel: `View Enrollment, ${clientBriefName(client)} ${entryExitRange(enrollment)}`, | ||
ariaLabel: `View Enrollment, ${client.hasOwnProperty('firstName') ? clientBriefName(client as ClientNameFragment) : ''} ${entryExitRange(enrollment)}`, |
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.
Type cast shouldn't be needed / I don't think Pick<ClientNameFragment, 'id'>
should be permitted -- I think this is same as other comment on the household 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.
Hm, yes it's the same comment; I moved this change over from the other PR, where it wasn't relevant. But I agree with you that it's a bit messy and could be improved. It fixes the typescript issue arising in ClientServicesPage
, where we don't have a client fragment to pass, only client ID - see #998 (comment). The Client Services Page overrides the aria label that calls for the client ID anyhow, so it's purely a typescript issue.
A couple alternative ideas:
- Just avoid
getViewEnrollmentMenuItem
onClientServicesPage
- ok, but leads to some duplication - Use
client
from dashboard context - seems like a bit of a hassle to keep Typescript happy, but maybe ok? - edit: or the
getViewEnrollmentMenuItem
function could accept bothclientId
(required, for url) andclient
(optional; if provided, then used in aria label)? Or it could require one or the other?
What do you prefer?
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 I see, thanks. I didn't realize there really was a called that only passed id
. I think the approach you added with eee782f is fine but we should not need the cast as ClientNameFragment
@martha either way is fine (using existing branch name or new branch name)! Lets just make sure that we update the backend test branch greenriver/hmis-warehouse#5012 to have the same branch name, and that shouldn't get merged until the frontend branch is merged. |
* Update Project Enrollment tables * fix a11y * More accessibility fixes * Simplify and resolve todos * Add storybook story * Remove errant comment * Add comments * Update api of TableRowActions * Fix issue with fulColSpan * Right-align table row actions Co-authored-by: Gig <[email protected]> * Remove comment * Replace overrideTableBody with more understandable API * Implement PR suggestion of moving table row to column def * Cleanup and add comments * Port over relevant changes from other PR * Refactor to use renderCellContents * Revert out-of-scope change * Add todo * Remove circular dependency * Clean up * Centralize action column base attrs * PR feedback * Fix typescript problems * Implement Table Actions pattern and default columns (#998) * Implement Table Actions pattern and default columns * Add random comment * Add storybook for table actions and fix cde story * Implement PR suggestion of moving table row to column def * add todo * Finish refactor to use column def instead of getTableAction * Fix bulk services loading * Provide a visually hidden header when header isnt provided * Keep existing behavior of individual/household assessment viewing * Fix typescript * Add accessible text for RelativeDateDisplay * implement one possible approach for client ID typescript * Remove unnecessary cast --------- Co-authored-by: Gig Ashton <[email protected]>
Description
GH issue: https://github.com/open-path/Green-River/issues/6761
I opened this PR against #989, it should be retargeted to the base branch when that is merged. Both PRs should ideally go out in the same release.
Summary of changes:
DateWithRelativeTooltip
, kind of like the inverse ofRelativeDateDisplay
.TableRowActions
api to enable the Bulk Services use case.loading
prop passed from the generic tableOther todos:
Depends on hmis-warehouse PR: (to do)
Type of change
Checklist before requesting review