-
Notifications
You must be signed in to change notification settings - Fork 1.6k
MM-69625 MM-69633: Collapse-all and task filtering on playbook run checklists #9928
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,10 +10,12 @@ import Button from '@components/button'; | |
| import CompassIcon from '@components/compass_icon'; | ||
| import {useServerUrl} from '@context/server'; | ||
| import {useTheme} from '@context/theme'; | ||
| import useDidUpdate from '@hooks/did_update'; | ||
| import {renameChecklist, addChecklistItem} from '@playbooks/actions/remote/checklist'; | ||
| import ProgressBar from '@playbooks/components/progress_bar'; | ||
| import {goToRenameChecklist, goToAddChecklistItem} from '@playbooks/screens/navigation'; | ||
| import {getChecklistProgress} from '@playbooks/utils/progress'; | ||
| import {isItemVisible, itemMatchesFilters, type TaskFilters} from '@playbooks/utils/task_filters'; | ||
| import {getFullErrorMessage} from '@utils/errors'; | ||
| import {logError} from '@utils/log'; | ||
| import {showPlaybookErrorSnackbar} from '@utils/snack_bar'; | ||
|
|
@@ -114,6 +116,10 @@ type Props = { | |
| isFinished: boolean; | ||
| isParticipant: boolean; | ||
| checklistProgress: ReturnType<typeof getChecklistProgress>; | ||
| filters: TaskFilters; | ||
| currentUserId: string; | ||
| collapseAll: boolean; | ||
| collapseAllEpoch: number; | ||
| } | ||
|
|
||
| const Checklist = ({ | ||
|
|
@@ -131,6 +137,10 @@ const Checklist = ({ | |
| totalNumber, | ||
| progress, | ||
| }, | ||
| filters, | ||
| currentUserId, | ||
| collapseAll, | ||
| collapseAllEpoch, | ||
| }: Props) => { | ||
| const [expanded, setExpanded] = useState(true); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Newly-mounted checklists ignore the current
🔧 Proposed fix: seed initial state from the current prop- const [expanded, setExpanded] = useState(true);
+ const [expanded, setExpanded] = useState(() => !collapseAll);Self-recovers on the next collapse/expand-all press, so impact is limited to a transient visual inconsistency. Also applies to: 153-156 🤖 Prompt for AI Agents |
||
| const intl = useIntl(); | ||
|
|
@@ -140,10 +150,24 @@ const Checklist = ({ | |
| const height = useSharedValue(0); | ||
| const windowDimensions = useWindowDimensions(); | ||
|
|
||
| // Follow the run-level collapse/expand control whenever the user triggers it. | ||
| useDidUpdate(() => { | ||
| setExpanded(!collapseAll); | ||
| }, [collapseAll, collapseAllEpoch]); | ||
|
|
||
| const toggleExpanded = useCallback(() => { | ||
| setExpanded((prev) => !prev); | ||
| }, []); | ||
|
|
||
| // `items` holds every item in the checklist's canonical order, so an item's position here is the | ||
| // index the server expects. Pair each item with that index before filtering, otherwise hiding an | ||
| // item would shift the indices sent to the server for the items after it. | ||
| // Not memoized: WatermelonDB mutates model instances in place, so a memo keyed on the array | ||
| // identity would keep serving a stale result after an item's state or assignee changes. | ||
| const visibleItems = items. | ||
| map((item, itemNumber) => ({item, itemNumber})). | ||
| filter(({item}) => isItemVisible(item) && itemMatchesFilters(item, filters, currentUserId)); | ||
|
|
||
| const handleRename = useCallback(async (newTitle: string) => { | ||
| const res = await renameChecklist(serverUrl, playbookRunId, checklistNumber, checklist.id, newTitle); | ||
| if ('error' in res && res.error) { | ||
|
|
@@ -234,13 +258,13 @@ const Checklist = ({ | |
| style={[styles.checklistItemsContainer, animatedStyle]} | ||
| testID='checklist-items-container' | ||
| > | ||
| {items.map((item, index) => ( | ||
| {visibleItems.map(({item, itemNumber}) => ( | ||
| <ChecklistItem | ||
| key={item.id} | ||
| item={item} | ||
| channelId={channelId} | ||
| checklistNumber={checklistNumber} | ||
| itemNumber={index} | ||
| itemNumber={itemNumber} | ||
| playbookRunId={playbookRunId} | ||
| isDisabled={isFinished || !isParticipant} | ||
| /> | ||
|
|
@@ -262,13 +286,13 @@ const Checklist = ({ | |
| style={calculatorStyle} | ||
| onLayout={calculatorOnLayout} | ||
| > | ||
| {items.map((item, index) => ( | ||
| {visibleItems.map(({item, itemNumber}) => ( | ||
| <ChecklistItem | ||
| key={`calc-${item.id}`} | ||
| item={item} | ||
| channelId={channelId} | ||
| checklistNumber={checklistNumber} | ||
| itemNumber={index} | ||
| itemNumber={itemNumber} | ||
| playbookRunId={playbookRunId} | ||
| isDisabled={isFinished || !isParticipant} | ||
| /> | ||
|
|
||
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.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Filter tests only check absence, not full result set.
These four tests use
.not.toContain(...)without checking length or the full expected array, unlike the adjacent tests at lines 500 and 546 that assert the complete array. As per coding guidelines, "In tests, check array lengths in addition to individual items to ensure no extra elements exist."✅ Proposed fix: assert the full expected set
(similarly for the
showSkipped,showAssignedToMe, andshowAssignedToOtherstests)🤖 Prompt for AI Agents
Source: Coding guidelines