-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1635 from SeedCompany/engagement-datagrid-editing
- Loading branch information
Showing
16 changed files
with
227 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
src/components/EngagementDataGrid/UpdateLanguageEngagementGrid.graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
mutation UpdateLanguageEngagementGrid($input: UpdateLanguageEngagement!) { | ||
updateLanguageEngagement(input: { engagement: $input }) { | ||
engagement { | ||
...engagementDataGridRow | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './EngagementColumns'; | ||
export * from './engagementDataGridRow.graphql'; | ||
export * from './useProcessEngagementUpdate'; |
54 changes: 54 additions & 0 deletions
54
src/components/EngagementDataGrid/useProcessEngagementUpdate.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { useMutation } from '@apollo/client'; | ||
import { UpdateLanguageEngagement as UpdateLanguageEngagementInput } from '~/api/schema.graphql'; | ||
import { EngagementDataGridRowFragment } from './engagementDataGridRow.graphql'; | ||
import { UpdateLanguageEngagementGridDocument as UpdateLanguageEngagement } from './UpdateLanguageEngagementGrid.graphql'; | ||
|
||
export const useProcessEngagementUpdate = () => { | ||
const [updateLanguageEngagement] = useMutation(UpdateLanguageEngagement); | ||
|
||
return (updated: EngagementDataGridRowFragment) => { | ||
if (updated.__typename !== 'LanguageEngagement') { | ||
return updated; | ||
} | ||
|
||
const input: UpdateLanguageEngagementInput = { | ||
id: updated.id, | ||
milestoneReached: updated.milestoneReached.value, | ||
usingAIAssistedTranslation: updated.usingAIAssistedTranslation.value, | ||
}; | ||
// Don't wait for the mutation to finish/error, which allows | ||
// the grid to close the editing state immediately. | ||
// There shouldn't be any business errors from these current changes, | ||
// and network errors are handled with snackbars. | ||
// Additionally, MUI doesn't handle thrown errors either; it just gives | ||
// them straight back to us on the `onProcessRowUpdateError` callback. | ||
void updateLanguageEngagement({ | ||
variables: { input }, | ||
// Inform Apollo of these async/queued updates. | ||
// This is important because users can make multiple changes | ||
// quickly, since we don't `await` above. | ||
// These optimistic updates are layered/stacked. | ||
// So if two value changes are in flight, the value from the first | ||
// API response isn't presented as the latest value, | ||
// since there is still another optimistic update left. | ||
// Said another way: this prevents the UI from presenting the final change, | ||
// then looking like it reverted to the first change, | ||
// and then flipping back to the final change again. | ||
// This also ensures these pending updates are maintained | ||
// even if the grid is unmounted/remounted. | ||
optimisticResponse: { | ||
updateLanguageEngagement: { | ||
__typename: 'UpdateLanguageEngagementOutput', | ||
// This is an easy/cheap/hacky way to "unparse" the date scalars | ||
// before writing them to the cache. | ||
// Our read policies expect them to be ISO strings as we receive | ||
// them from the network this way. | ||
// Since our temporal objects have a toJSON, this works fine to revert that. | ||
engagement: JSON.parse(JSON.stringify(updated)), | ||
}, | ||
}, | ||
}); | ||
|
||
return updated; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { | ||
Check as CheckIcon, | ||
Close as CloseIcon, | ||
QuestionMark, | ||
} from '@mui/icons-material'; | ||
import { GridEditSingleSelectCell } from '@mui/x-data-grid-pro'; | ||
import { mapEntries } from '@seedcompany/common'; | ||
import { column, RowLike } from './definition.types'; | ||
import { enumColumn } from './enumColumn'; | ||
|
||
const labelToValue = { | ||
Unknown: null, | ||
Yes: true, | ||
No: false, | ||
} as const; | ||
|
||
const icons = { | ||
Yes: <CheckIcon color="success" sx={{ margin: 'auto' }} />, | ||
No: <CloseIcon color="error" sx={{ margin: 'auto' }} />, | ||
Unknown: <QuestionMark color="action" sx={{ margin: 'auto' }} />, | ||
}; | ||
|
||
type Formatted = keyof typeof labelToValue; | ||
const options = Object.keys(labelToValue) as Formatted[]; | ||
const labels = mapEntries(labelToValue, ([k]) => [k, k]).asRecord; | ||
const valueToLabel = mapEntries(labelToValue, ([k, v]) => [v, k]).asMap; | ||
|
||
export const booleanNullableColumn = <Row extends RowLike>() => | ||
column<Row>()({ | ||
...enumColumn<Row, Formatted>(options, labels), | ||
type: 'singleSelect', | ||
// filterOperators: [], // TODO | ||
valueFormatter: (value: boolean | null) => valueToLabel.get(value), | ||
getOptionLabel: (value: Formatted) => icons[value], | ||
display: 'flex', | ||
renderCell: ({ formattedValue }) => { | ||
const v = formattedValue as Formatted; | ||
return v !== 'Unknown' ? icons[v] : null; | ||
}, | ||
renderEditCell: (params) => { | ||
if (typeof params.value === 'string') { | ||
// Value selected, and therefore about to close, but given formatted value. | ||
// Don't bother trying to remap value just close. | ||
return null; | ||
} | ||
return ( | ||
<GridEditSingleSelectCell | ||
{...params} | ||
value={valueToLabel.get(params.value)} | ||
// Stop editing on the first value changed. | ||
// This way users' change will be sent to the server immediately after | ||
// selecting a new value without needing another interaction. | ||
onValueChange={async (event, formatted: Formatted) => { | ||
const { api, id, field } = params; | ||
const value = labelToValue[formatted]; | ||
await api.setEditCellValue({ id, field, value }, event); | ||
api.stopCellEditMode({ id, field }); | ||
}} | ||
sx={{ | ||
'.MuiSelect-select': { | ||
// center icon | ||
display: 'flex', | ||
justifyContent: 'center', | ||
// adjust to render outline within the cell | ||
// and ignore arrow padding to center horizontally | ||
px: '4px !important', | ||
}, | ||
'[data-testid="ArrowDropDownIcon"]': { display: 'none' }, | ||
}} | ||
/> | ||
); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { | ||
GridCellParams as CellParams, | ||
GridValidRowModel as RowLike, | ||
} from '@mui/x-data-grid-pro'; | ||
|
||
export const isCellEditable = <R extends RowLike>(params: CellParams<R>) => { | ||
if (params.colDef.isEditable) { | ||
return params.colDef.isEditable(params); | ||
} | ||
return true; | ||
}; | ||
|
||
declare module '@mui/x-data-grid/internals' { | ||
interface GridBaseColDef<R extends RowLike = RowLike, V = any, F = V> { | ||
/** | ||
* Is this cell editable? | ||
* Useful when it needs to be dynamic based on the row. | ||
* | ||
* Requires {@link editable} == true in addition to this. | ||
* Requires {@link isCellEditable} to be passed to the Grid. | ||
*/ | ||
isEditable?: (params: CellParams<R, V, F>) => boolean; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.