Skip to content

WEB-4460 - Setup TIDE Dashboard - #1976

Open
henry-tp wants to merge 174 commits into
feat/tide-v2from
WEB-4460-setup
Open

WEB-4460 - Setup TIDE Dashboard#1976
henry-tp wants to merge 174 commits into
feat/tide-v2from
WEB-4460-setup

Conversation

@henry-tp

@henry-tp henry-tp commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@henry-tp
henry-tp changed the base branch from develop to feat/tide-v2 July 7, 2026 20:30
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (4)
  • master
  • main
  • develop
  • release.*

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f694bda0-f0ce-491f-bcd1-0c5245981c4c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

<review_stack_artifact_context>
</review_stack_artifact_context>

Walkthrough

This PR introduces a new Tide Dashboard V2 feature comprising Redux slices for dashboard/filter state, an RTK Query patient-fetching endpoint with CGM exclusion logic, filter/category UI components, table cell renderers, pagination, and localStorage-backed filter persistence. It also wires the new dashboard into clinicworkspace tabs and refactors ClinicPatients pagination/filter UI to shared components.

Changes

Tide Dashboard V2

Layer / File(s) Summary
State slices
app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js, tideDashboardFiltersSlice.js, app/redux/reducers/index.js
New tideDashboard (category, offset) and tideDashboardFilters (patientTags, clinicSites) slices with set/reset actions, registered in the root reducer.
CGM exclusion query and patients endpoint
.../CGMExclusionQuery.js, .../tideDashboardApi.js
CGMExclusionQuery builds mutually-exclusive category thresholds via rule negation; buildGetTideDashboardPatientsParams and getTideDashboardPatients RTK Query endpoint fetch /clinics/:clinicId/patients with category/tag/site/offset/limit params.
Filter hooks
.../useActiveFiltersCount.js, .../usePruneInvalidFilters.js
Computes active filter count and prunes stale tag/site IDs from filter state on mount.
Filter and category UI
.../FilterByTags.js, FilterBySites.js, FilterByCategory.js, app/pages/clinicworkspace/components/CategorySegmentedControl.js, ActiveFilterCount.js, ResetFilters.js, SitesFilterDropdown.js, TagFilterDropdown.js
New dropdown/segmented-control components dispatching tag, site, category, and offset changes, plus shared filter-count and reset-filter controls.
Table cells, header, and pagination
.../Cells.js, app/pages/clinicworkspace/components/TagListCell.js, .../TableCategoryHeader.js, .../EmptyContentNode.js, app/pages/clinicworkspace/components/PaginationControls.js, PatientCount.js, app/components/elements/Table.js
Renders patient/tag cells, category-specific header copy, empty-state messaging, and offset-based pagination/count; adds data-testid attributes to Table.
Page assembly and workspace wiring
.../TideDashboardV2.js, .../index.js, app/pages/clinicworkspace/clinicworkspace.js, app/bootstrap.js
Assembles the dashboard page from filters/table/pagination pieces, adds a dynamic useTabs hook and TideDashboardV2 tab panel, and removes unused LaunchDarkly flag defaults.
Filter persistence
app/redux/store/localStorage.js, configureStore.dev.js, configureStore.prod.js, app/redux/actions/async.js
Adds keyed local storage load/save via getTideDashboardFiltersKey, persists tideDashboardFilters per user/clinic on store changes, and loads persisted filters on clinic selection.

ClinicPatients pagination and filter UI refactor

Layer / File(s) Summary
Offset-based pagination and filter UI swap
app/pages/clinicworkspace/ClinicPatients.js, __tests__/utils/setupStore.js
Replaces page-based Pagination with offset-based PaginationControls, swaps inline filter count/reset UI for ActiveFilterCount/ResetFilters components, removes a Tide Dashboard popover block, and adds additionalReducers support to the test store helper.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TideDashboardV2
  participant Redux
  participant tideDashboardApi
  participant RTKQueryApi

  User->>TideDashboardV2: select category/tag/site filter
  TideDashboardV2->>Redux: dispatch setCategory / setPatientTagsFilter / setClinicSitesFilter / setOffset(0)
  Redux-->>TideDashboardV2: updated state
  TideDashboardV2->>tideDashboardApi: useGetTideDashboardPatientsQuery(params)
  tideDashboardApi->>RTKQueryApi: GET /clinics/:clinicId/patients
  RTKQueryApi-->>tideDashboardApi: patients + total
  tideDashboardApi-->>TideDashboardV2: table data
  TideDashboardV2->>User: render table, pagination, and empty state
Loading

Related PRs: None found.

Suggested labels: enhancement, tide-dashboard

Suggested reviewers: None determined.

🐰

   Hop by hop through filters wide,
   New tabs, new tides, side by side.
   Offsets glide where pages stood,
   Storage remembers, as it should.
   The dashboard grows — the rabbit's proud.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so the PR context is not meaningfully described. Add a brief summary of the main code changes and intent.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly reflects the main change: setting up the TIDE Dashboard.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch WEB-4460-setup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread app/pages/clinicworkspace/TideDashboardV2/CGMExclusionQuery.js Outdated
case threshold.startsWith('>='): return threshold.replace('>=', '<');
case threshold.startsWith('<='): return threshold.replace('<=', '>');
case threshold.startsWith('>'): return threshold.replace('>', '<=');
case threshold.startsWith('<'): return threshold.replace('<', '>=');
@henry-tp henry-tp mentioned this pull request Jul 7, 2026
1 task
@henry-tp henry-tp changed the title WEB-4460 - Setup WEB-4460 - Setup Dashboard Jul 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/pages/clinicworkspace/clinicworkspace.js (1)

76-86: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Stale selectedTab when tabIndices changes after mount.

tabIndices is now derived dynamically from tabs, which depends on useFlags() and clinic entitlements — both of which can resolve asynchronously after the initial render, shifting tab positions (e.g., the TIDE_DASHBOARD tab appearing once flags load). The existing useEffect (lines 82-86) only re-syncs selectedTab when the URL tab param changes, not when tabIndices itself changes, so selectedTab can point at the wrong tab index once flags resolve, and the panel rendering at lines 147-159 (which uses selectedTab === tabIndices[TAB.X]) will show/hide the wrong content. As per coding guidelines, "respect react-hooks/exhaustive-deps".

🐛 Proposed fix
   useEffect(() => {
     if (tab && tab in tabIndices && tabIndices[tab] !== selectedTab) {
       setSelectedTab(tabIndices[tab]);
     }
-  }, [tab]);
+  }, [tab, tabIndices]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/clinicworkspace.js` around lines 76 - 86, The
`selectedTab` state can become stale when `tabIndices` changes after async
flags/entitlements load, because the sync effect only watches `tab`. Update the
`useEffect` in `ClinicWorkspace` to re-derive `selectedTab` whenever
`tabIndices` changes (and keep the URL `tab` param in sync), and include the
missing hook dependencies so `react-hooks/exhaustive-deps` is satisfied. Use the
`tabs`, `tabIndices`, `selectedTab`, and `setSelectedTab` logic to locate the
fix, and ensure the rendered tab panels continue to use the current index
mapping.

Source: Coding guidelines

🧹 Nitpick comments (21)
app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js (1)

3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting CATEGORY out of a component file.

CATEGORY is imported from ./FilterByCategory, a UI component. Both this slice and tideDashboardApi.js depend on it, coupling Redux/data layers to a presentational component and creating circular-import risk if FilterByCategory ever needs slice actions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js` at line 3,
`CATEGORY` is currently being pulled from the `FilterByCategory` component,
which couples the slice to UI code and risks circular imports. Extract
`CATEGORY` into a shared non-component module (for example a constants file used
by both `tideDashboardSlice` and `tideDashboardApi`) and update the imports in
`tideDashboardSlice` and any other consumers to reference that shared symbol
instead of the component.
app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js (2)

96-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove commented-out prop wiring or implement it.

sx, onSort, order, orderBy, onClickRow are left commented out. Either wire these up now or drop the dead code to keep the component clean.

🧹 Proposed cleanup
-        // sx={tableStyle}
-        // onSort={handleSortChange}
-        // order={sort?.substring(0, 1) === '+' ? 'asc' : 'desc'}
-        // orderBy={sort?.substring(1)}
-        // onClickRow={handleClickPatient}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js` around lines 96
- 100, The TideDashboardV2 component still has dead commented-out prop wiring
for the table, which should be cleaned up or restored. In TideDashboardV2.js,
either pass the intended props through to the table/component using the existing
handlers and state like handleSortChange, sort, and handleClickPatient, or
remove the commented lines entirely if they are not needed. Keep the component
definition clean by resolving the commented `sx`, `onSort`, `order`, `orderBy`,
and `onClickRow` wiring around the table usage.

81-93: 🎯 Functional Correctness | 🔵 Trivial

Several table columns are non-functional placeholders.

Flag, Avg Glucose, % TIR, % Time in Range, % Change in TIR, GMI, CGM Use, and the trailing // More column all have an empty field and no render, so they'll always render blank cells. If this is deliberate scaffolding for a later PR in the stack, consider tracking it explicitly (e.g., TODO) so it isn't missed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js` around lines 81
- 93, The TideDashboardV2 table defines several non-functional placeholder
columns with empty field values and no renderers, so they will always display
blank cells. Update the columns in TideDashboardV2 to either wire each one to
real data/render logic using the relevant table row fields or explicitly mark
them as intentional scaffolding with a clear TODO/comment so they are not
mistaken for finished UI, including the trailing More column.
app/redux/store/configureStore.dev.js (1)

112-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract duplicated persistence logic; drop leftover dead comment.

Line 112 is a stray leftover comment from an earlier draft. Also, this entire subscribe/persist block (112-124) is duplicated almost verbatim in configureStore.prod.js (lines 68-80). Extracting both into a small shared helper (e.g. persistBlipState(store) in localStorage.js) would remove the dead comment and prevent the dev/prod persistence logic from drifting apart over time.

♻️ Proposed refactor sketch
-  // tideDashboardFilters: store.getState().blip?.tideDashboardFilters,
-
-  store.subscribe(throttle(() => {
-    const selectedClinicId = store.getState().blip?.selectedClinicId;
-    const loggedInUserId = store.getState().blip?.loggedInUserId;
-
-    saveLocalState({ selectedClinicId });
-
-    if (loggedInUserId && selectedClinicId) {
-      const tideDashboardFiltersKey = getTideDashboardFiltersKey(loggedInUserId, selectedClinicId);
-
-      saveLocalState(store.getState().blip?.tideDashboardFilters, tideDashboardFiltersKey);
-    }
-  }, 1000));
+  store.subscribe(throttle(() => persistBlipState(store), 1000));
// localStorage.js
export const persistBlipState = (store) => {
  const selectedClinicId = store.getState().blip?.selectedClinicId;
  const loggedInUserId = store.getState().blip?.loggedInUserId;

  saveLocalState({ selectedClinicId });

  if (loggedInUserId && selectedClinicId) {
    saveLocalState(
      store.getState().blip?.tideDashboardFilters,
      getTideDashboardFiltersKey(loggedInUserId, selectedClinicId)
    );
  }
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/redux/store/configureStore.dev.js` around lines 112 - 125, Remove the
stray leftover comment in configureStore.dev.js and extract the duplicated
subscribe/throttled persistence logic into a shared helper so dev and prod stay
in sync. Create a small function such as persistBlipState(store) alongside the
existing localStorage helpers, and have both configureStore.dev.js and
configureStore.prod.js call it from their store.subscribe(throttle(...)) blocks.
Keep the helper responsible for reading selectedClinicId, loggedInUserId, saving
selectedClinicId, and persisting tideDashboardFilters via
getTideDashboardFiltersKey.
app/pages/clinicworkspace/components/TagListCell.js (1)

5-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing PropTypes on TagListCell.

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/TagListCell.js` around lines 5 - 14, Add
PropTypes for TagListCell’s props to satisfy the component prop validation
guideline. Update the TagListCell component to declare the expected shape for
the patient prop, including its tags field, using the same propTypes pattern
used elsewhere in the codebase. Keep the validation рядом with TagListCell so
the prop contract is explicit and easy to maintain.

Source: Coding guidelines

app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js (2)

1-7: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Import order deviates from guideline groups.

Redux (react-redux) should precede third-party libs, and third-party (@tidepool/viz) should be grouped together, before theme-ui and local imports.

As per coding guidelines, "Group imports in the required order with blank lines between groups: React, PropTypes, Redux, third-party libraries, Lodash specific imports, theme-ui, then local imports."

♻️ Suggested import order
 import React from 'react';
-import { useTranslation } from 'react-i18next';
 import { useSelector, useDispatch } from 'react-redux';
+
+import { useTranslation } from 'react-i18next';
+import { colors as vizColors } from '`@tidepool/viz`';
+
+import { Box } from 'theme-ui';
+
 import { CategorySegmentedControl, Segment } from '../components/CategorySegmentedControl';
 import { setCategory, setOffset } from './tideDashboardSlice';
-import { colors as vizColors } from '`@tidepool/viz`';
-import { Box } from 'theme-ui';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js` around lines 1
- 7, The import block in FilterByCategory.js is out of the required grouping
order: keep React first, then Redux imports from react-redux, then third-party
libraries like `@tidepool/viz`, then theme-ui, and finally local imports such as
CategorySegmentedControl and tideDashboardSlice. Reorder the existing imports in
that file to match the project’s import grouping guideline and separate each
group with blank lines.

Source: Coding guidelines


22-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing PropTypes on Indicator.

Indicator accepts a color prop but has no PropTypes definition.

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js` around lines
22 - 28, The Indicator component currently accepts a color prop but does not
define PropTypes, so add a PropTypes declaration for Indicator’s color property
alongside the component definition in FilterByCategory.js. Use the Indicator
symbol to locate the component and ensure the prop is marked as required or
typed according to the existing component prop conventions in this file.

Source: Coding guidelines

app/pages/clinicworkspace/TideDashboardV2/Cells.js (1)

5-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing PropTypes on PatientCell.

PatientCell accepts a patient prop without PropTypes.

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/Cells.js` around lines 5 - 15,
PatientCell is missing PropTypes for its patient prop, so add prop type
validation for the component. Update PatientCell in Cells.js to define its
expected props shape using PropTypes, including the patient object and the
fields it reads (fullName, birthDate, mrn), and make sure the PropTypes are
attached to PatientCell alongside the existing component definition.

Source: Coding guidelines

app/pages/clinicworkspace/components/CategorySegmentedControl.js (2)

20-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add ARIA semantics for the interactive Segment.

Segment handles keyboard activation but has no role or aria-pressed, so assistive tech won't announce it as a toggle/tab control or expose its selected state.

♿ Suggested fix
     <Flex
       onClick={onClick}
       onKeyDown={(evt) => {
         if (evt.key === 'Enter' || evt.key === ' ') {
           onClick();
         }
       }}
       tabIndex="0"
+      role="button"
+      aria-pressed={selected}
       px={4}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/CategorySegmentedControl.js` around
lines 20 - 52, The interactive Segment component supports click and keyboard
activation but is missing accessible semantics. Update the Segment component to
expose the correct ARIA role and selected state by adding a suitable role and an
aria-pressed or equivalent selected-state attribute tied to the selected prop.
Keep the keyboard and click behavior in Segment consistent with the new
semantics so assistive technologies can announce it properly.

6-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing PropTypes on CategorySegmentedControl and Segment.

Neither component declares PropTypes for its props (children, selected, onClick).

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/CategorySegmentedControl.js` around
lines 6 - 18, Add PropTypes declarations for the components in
CategorySegmentedControl.js so all props are explicitly validated. Update
CategorySegmentedControl to declare children, and add PropTypes for Segment to
cover selected and onClick (and any other props it receives) using the component
names as anchors so the definitions stay with the exports.

Source: Coding guidelines

app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js (1)

1-8: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Import grouping deviates from guideline order.

Redux, local, and third-party imports are interleaved rather than grouped as React → Redux → third-party → theme-ui → local.

As per coding guidelines, "Group imports in the required order with blank lines between groups: React, PropTypes, Redux, third-party libraries, Lodash specific imports, theme-ui, then local imports."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js` around
lines 1 - 8, The imports in TableCategoryHeader are not grouped in the required
order, with Redux, third-party, theme-ui, and local imports mixed together.
Reorder the imports in the module so they follow the project’s grouping
convention: React first, then Redux, then third-party libraries, then theme-ui,
and finally local imports, with blank lines between each group. Use the existing
symbols like useSelector, useTranslation, Box, Text, vizColors, vizUtils, utils,
and MGDL_UNITS to keep the imports in the correct grouped sections.

Source: Coding guidelines

app/pages/clinicworkspace/components/PaginationControls.js (1)

4-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add PropTypes for component props.

♻️ Proposed fix
 import React from 'react';
+import PropTypes from 'prop-types';
 import Pagination from '../../../components/elements/Pagination';

 const PaginationControls = ({ total = 0, limit, offset, onOffsetChange }) => {
   ...
 };

+PaginationControls.propTypes = {
+  total: PropTypes.number,
+  limit: PropTypes.number.isRequired,
+  offset: PropTypes.number.isRequired,
+  onOffsetChange: PropTypes.func.isRequired,
+};

 export default PaginationControls;

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/PaginationControls.js` around lines 4 -
28, Add PropTypes for PaginationControls props to match the coding guidelines.
Define prop validation for total, limit, offset, and onOffsetChange on the
PaginationControls component so the expected types are explicit and any
missing/invalid props are caught during development.

Source: Coding guidelines

app/pages/clinicworkspace/components/ResetFilters.js (1)

6-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add PropTypes for component props.

hidden and onClick props aren't typed.

♻️ Proposed fix
 import React from 'react';
+import PropTypes from 'prop-types';
 import noop from 'lodash/noop';
 import { useTranslation } from 'react-i18next';
 import Button from '../../../components/elements/Button';

 const ResetFilters = ({ hidden = false, onClick = noop }) => {
   ...
 };

+ResetFilters.propTypes = {
+  hidden: PropTypes.bool,
+  onClick: PropTypes.func,
+};

 export default ResetFilters;

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/ResetFilters.js` around lines 6 - 24,
The ResetFilters component is missing PropTypes for its props, so add prop type
definitions for hidden and onClick in the ResetFilters component export. Use the
component name ResetFilters to locate the function, and define hidden as a
boolean and onClick as a function, matching the existing default props behavior.

Source: Coding guidelines

app/pages/clinicworkspace/components/SitesFilterDropdown.js (1)

35-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add PropTypes for component props.

Neither DropdownContent nor SitesFilterDropdown define PropTypes for their props.

As per coding guidelines, "Define PropTypes for all component props."

Also applies to: 158-161

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js` around lines 35
- 39, Add PropTypes definitions for both DropdownContent and SitesFilterDropdown
so all expected props are explicitly validated. Update the component
declarations to include prop type checks for handlers and data props such as
onClose, onChange, clinicSites, and any props accepted by SitesFilterDropdown,
using the existing component names to place the new propTypes alongside their
definitions.

Source: Coding guidelines

app/pages/clinicworkspace/components/TagFilterDropdown.js (3)

158-161: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add PropTypes for onChange/patientTags.

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/TagFilterDropdown.js` around lines 158 -
161, The TagFilterDropdown component currently defines default values for
onChange and patientTags but does not declare PropTypes for its props. Add
PropTypes for TagFilterDropdown so both onChange and patientTags are explicitly
validated, using the TagFilterDropdown function/component name to place the prop
type definitions alongside the component export.

Source: Coding guidelines


30-31: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

trackMetric/prefixPopHealthMetric are no-op stubs — analytics calls silently do nothing.

trackMetric is defined as () => noop, so every call like trackMetric(prefixPopHealthMetric('...'), {...}) (lines 136, 146, 180, 221) just returns the noop function without invoking any tracking side effect. If this is intentional scaffolding for the "Setup" PR, consider wiring these through actual tracking (e.g. as props threaded from the parent, similar to how ClinicPatients.js passes trackMetric into MoreMenu/PatientTags), otherwise this component's analytics instrumentation is effectively dead code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/TagFilterDropdown.js` around lines 30 -
31, The analytics helpers in TagFilterDropdown are currently stubs, so calls to
trackMetric(prefixPopHealthMetric(...), ...) do nothing. Replace the noop
definitions with real tracking plumbing by accepting these functions as props or
otherwise wiring them from the parent, and update TagFilterDropdown’s callers to
pass the actual metric functions so the existing trackMetric calls produce side
effects instead of silently returning noop.

33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract SPECIAL_FILTER_STATES into a shared module
TagFilterDropdown.js and SitesFilterDropdown.js both depend on ClinicPatients.js only for this constant. Moving it out of the page component keeps reusable dropdowns decoupled and avoids a future circular dependency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/TagFilterDropdown.js` at line 33,
SPECIAL_FILTER_STATES is being imported from ClinicPatients.js just to support
TagFilterDropdown, which couples reusable dropdowns to the page component. Move
SPECIAL_FILTER_STATES into a shared module and update TagFilterDropdown and
SitesFilterDropdown to import it from there instead of ClinicPatients. Keep the
constant in a standalone location that both dropdown components can reference
without depending on the page.
app/pages/clinicworkspace/components/PatientCount.js (2)

9-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant total === 0 check.

Line 9 already returns null when total === 0, so the ternary on line 11 always resolves to offset + 1.

♻️ Proposed simplification
-  const start = total === 0 ? 0 : offset + 1;
+  const start = offset + 1;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/PatientCount.js` around lines 9 - 11, In
PatientCount, remove the redundant total === 0 branch from the start calculation
because the early return already handles that case; simplify the logic so the
start value is derived directly from offset in the component’s render path,
keeping the existing null return for zero totals.

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add PropTypes for total, offset, limit.

As per coding guidelines, "Define PropTypes for all component props."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/PatientCount.js` at line 6, PatientCount
is missing PropTypes for its component props, so add prop type validation for
total, offset, and limit on the PatientCount component. Update the PatientCount
definition to include a PropTypes declaration that matches the existing default
values and optional limit prop, so the component conforms to the project’s
prop-type guidelines.

Source: Coding guidelines

app/pages/clinicworkspace/components/ActiveFilterCount.js (1)

10-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add PropTypes for count.

Component prop count has no PropTypes definition.

As per coding guidelines, "Define PropTypes for all component props."

♻️ Proposed fix
 import React from 'react';
+import PropTypes from 'prop-types';
 import { Flex, Text } from 'theme-ui';
 export default ActiveFilterCount;
+
+ActiveFilterCount.propTypes = {
+  count: PropTypes.number,
+};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/ActiveFilterCount.js` around lines 10 -
46, Add PropTypes for the ActiveFilterCount component’s count prop, since it is
currently undocumented by runtime prop validation. Update ActiveFilterCount to
declare count with an appropriate numeric PropTypes definition alongside the
existing useTranslation logic and JSX, so the component follows the project
guideline that all component props must have PropTypes.

Source: Coding guidelines

app/components/elements/Table.js (1)

230-238: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

data-testid can collide across columns with empty field.

Several dashboard table columns use field: '' (see TideDashboardV2.js column definitions), so data-testid={\${id}-row-${rowIndex}-${col.field}`}` will produce duplicate/ambiguous test ids within the same row, weakening the value of these new selectors for RTL/Jest tests.

♻️ Proposed fix using column index for uniqueness
               {map(columns, (col, index) => (
                 <TableCell
                   id={`${id}-row-${rowIndex}-${col.field}`}
                   key={`${id}-row-${rowIndex}-${col.field}`}
-                  data-testid={`${id}-row-${rowIndex}-${col.field}`}
+                  data-testid={`${id}-row-${rowIndex}-${col.field || index}`}
As per coding guidelines for `**/*.{js,jsx,ts,tsx}` files, tests should use stable/descriptive selectors, and `__tests__/**/*.js` guidelines call for `userEvent`-driven interaction testing that benefits from unambiguous test ids.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/components/elements/Table.js` around lines 230 - 238, The row cell test
ids in Table.js can collide when a column has an empty field value, so update
the Table rendering logic to make the `data-testid` for each `TableCell` unique
per column. Use the existing `map(columns, (col, index) => ...)` loop and
incorporate the column index (or another stable unique column identifier) into
the row/cell test id generation alongside `id` and `rowIndex`, so selectors
remain unambiguous even when `col.field` is empty.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js`:
- Line 33: Move SPECIAL_FILTER_STATES out of ClinicPatients.js and into a shared
constants module so SitesFilterDropdown stays independent of a page-level
import. Update SitesFilterDropdown and ClinicPatients to import the constant
from the new shared location, and make sure any other consumers such as
TideDashboardV2/FilterBySites use the same shared source to avoid circular
dependencies.

In `@app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js`:
- Line 33: Resetting filters currently leaves pagination untouched, so the
dashboard can stay on a non-zero offset after filters are cleared. Update
handleResetFilters to also reset the pagination state by setting offset back to
0 along with dispatching resetTideDashboardFilters(), using the existing
dashboard state/actions around TideDashboardV2.

In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js`:
- Around line 40-58: The TideDashboardV2 component returns null while
useGetTideDashboardPatientsQuery is still resolving because it only checks data,
which leaves a blank area on navigation. Update TideDashboardV2.js to use the
query’s loading state (for example from useGetTideDashboardPatientsQuery) and
render an appropriate skeleton/spinner until the request finishes, then fall
through to the existing tableData/total rendering once data is available.

In `@app/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.js`:
- Around line 1-4: The import ordering in usePruneInvalidFilters is incorrect
because the Lodash import for keyBy is placed after the local
tideDashboardFiltersSlice import. Reorder the imports to follow the required
grouping in this file: React, Redux, third-party, Lodash, then local, keeping
keyBy before ./tideDashboardFiltersSlice while preserving the existing
useEffect, useDispatch, useSelector, and
setPatientTagsFilter/setClinicSitesFilter references.
- Line 10: The selector in usePruneInvalidFilters is reading the wrong shape
from state, so patientTags and clinicSites become undefined and both pruning
effects never run. Update the useSelector call to select the full
tideDashboardFilters slice (or the actual arrays directly) instead of
destructuring from state.blip.tideDashboardFilters.patientTags, then verify the
existing patientTags/clinicSites effects in usePruneInvalidFilters still receive
arrays and can prune stale IDs as intended.

---

Outside diff comments:
In `@app/pages/clinicworkspace/clinicworkspace.js`:
- Around line 76-86: The `selectedTab` state can become stale when `tabIndices`
changes after async flags/entitlements load, because the sync effect only
watches `tab`. Update the `useEffect` in `ClinicWorkspace` to re-derive
`selectedTab` whenever `tabIndices` changes (and keep the URL `tab` param in
sync), and include the missing hook dependencies so
`react-hooks/exhaustive-deps` is satisfied. Use the `tabs`, `tabIndices`,
`selectedTab`, and `setSelectedTab` logic to locate the fix, and ensure the
rendered tab panels continue to use the current index mapping.

---

Nitpick comments:
In `@app/components/elements/Table.js`:
- Around line 230-238: The row cell test ids in Table.js can collide when a
column has an empty field value, so update the Table rendering logic to make the
`data-testid` for each `TableCell` unique per column. Use the existing
`map(columns, (col, index) => ...)` loop and incorporate the column index (or
another stable unique column identifier) into the row/cell test id generation
alongside `id` and `rowIndex`, so selectors remain unambiguous even when
`col.field` is empty.

In `@app/pages/clinicworkspace/components/ActiveFilterCount.js`:
- Around line 10-46: Add PropTypes for the ActiveFilterCount component’s count
prop, since it is currently undocumented by runtime prop validation. Update
ActiveFilterCount to declare count with an appropriate numeric PropTypes
definition alongside the existing useTranslation logic and JSX, so the component
follows the project guideline that all component props must have PropTypes.

In `@app/pages/clinicworkspace/components/CategorySegmentedControl.js`:
- Around line 20-52: The interactive Segment component supports click and
keyboard activation but is missing accessible semantics. Update the Segment
component to expose the correct ARIA role and selected state by adding a
suitable role and an aria-pressed or equivalent selected-state attribute tied to
the selected prop. Keep the keyboard and click behavior in Segment consistent
with the new semantics so assistive technologies can announce it properly.
- Around line 6-18: Add PropTypes declarations for the components in
CategorySegmentedControl.js so all props are explicitly validated. Update
CategorySegmentedControl to declare children, and add PropTypes for Segment to
cover selected and onClick (and any other props it receives) using the component
names as anchors so the definitions stay with the exports.

In `@app/pages/clinicworkspace/components/PaginationControls.js`:
- Around line 4-28: Add PropTypes for PaginationControls props to match the
coding guidelines. Define prop validation for total, limit, offset, and
onOffsetChange on the PaginationControls component so the expected types are
explicit and any missing/invalid props are caught during development.

In `@app/pages/clinicworkspace/components/PatientCount.js`:
- Around line 9-11: In PatientCount, remove the redundant total === 0 branch
from the start calculation because the early return already handles that case;
simplify the logic so the start value is derived directly from offset in the
component’s render path, keeping the existing null return for zero totals.
- Line 6: PatientCount is missing PropTypes for its component props, so add prop
type validation for total, offset, and limit on the PatientCount component.
Update the PatientCount definition to include a PropTypes declaration that
matches the existing default values and optional limit prop, so the component
conforms to the project’s prop-type guidelines.

In `@app/pages/clinicworkspace/components/ResetFilters.js`:
- Around line 6-24: The ResetFilters component is missing PropTypes for its
props, so add prop type definitions for hidden and onClick in the ResetFilters
component export. Use the component name ResetFilters to locate the function,
and define hidden as a boolean and onClick as a function, matching the existing
default props behavior.

In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js`:
- Around line 35-39: Add PropTypes definitions for both DropdownContent and
SitesFilterDropdown so all expected props are explicitly validated. Update the
component declarations to include prop type checks for handlers and data props
such as onClose, onChange, clinicSites, and any props accepted by
SitesFilterDropdown, using the existing component names to place the new
propTypes alongside their definitions.

In `@app/pages/clinicworkspace/components/TagFilterDropdown.js`:
- Around line 158-161: The TagFilterDropdown component currently defines default
values for onChange and patientTags but does not declare PropTypes for its
props. Add PropTypes for TagFilterDropdown so both onChange and patientTags are
explicitly validated, using the TagFilterDropdown function/component name to
place the prop type definitions alongside the component export.
- Around line 30-31: The analytics helpers in TagFilterDropdown are currently
stubs, so calls to trackMetric(prefixPopHealthMetric(...), ...) do nothing.
Replace the noop definitions with real tracking plumbing by accepting these
functions as props or otherwise wiring them from the parent, and update
TagFilterDropdown’s callers to pass the actual metric functions so the existing
trackMetric calls produce side effects instead of silently returning noop.
- Line 33: SPECIAL_FILTER_STATES is being imported from ClinicPatients.js just
to support TagFilterDropdown, which couples reusable dropdowns to the page
component. Move SPECIAL_FILTER_STATES into a shared module and update
TagFilterDropdown and SitesFilterDropdown to import it from there instead of
ClinicPatients. Keep the constant in a standalone location that both dropdown
components can reference without depending on the page.

In `@app/pages/clinicworkspace/components/TagListCell.js`:
- Around line 5-14: Add PropTypes for TagListCell’s props to satisfy the
component prop validation guideline. Update the TagListCell component to declare
the expected shape for the patient prop, including its tags field, using the
same propTypes pattern used elsewhere in the codebase. Keep the validation рядом
with TagListCell so the prop contract is explicit and easy to maintain.

In `@app/pages/clinicworkspace/TideDashboardV2/Cells.js`:
- Around line 5-15: PatientCell is missing PropTypes for its patient prop, so
add prop type validation for the component. Update PatientCell in Cells.js to
define its expected props shape using PropTypes, including the patient object
and the fields it reads (fullName, birthDate, mrn), and make sure the PropTypes
are attached to PatientCell alongside the existing component definition.

In `@app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js`:
- Around line 1-7: The import block in FilterByCategory.js is out of the
required grouping order: keep React first, then Redux imports from react-redux,
then third-party libraries like `@tidepool/viz`, then theme-ui, and finally local
imports such as CategorySegmentedControl and tideDashboardSlice. Reorder the
existing imports in that file to match the project’s import grouping guideline
and separate each group with blank lines.
- Around line 22-28: The Indicator component currently accepts a color prop but
does not define PropTypes, so add a PropTypes declaration for Indicator’s color
property alongside the component definition in FilterByCategory.js. Use the
Indicator symbol to locate the component and ensure the prop is marked as
required or typed according to the existing component prop conventions in this
file.

In `@app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js`:
- Around line 1-8: The imports in TableCategoryHeader are not grouped in the
required order, with Redux, third-party, theme-ui, and local imports mixed
together. Reorder the imports in the module so they follow the project’s
grouping convention: React first, then Redux, then third-party libraries, then
theme-ui, and finally local imports, with blank lines between each group. Use
the existing symbols like useSelector, useTranslation, Box, Text, vizColors,
vizUtils, utils, and MGDL_UNITS to keep the imports in the correct grouped
sections.

In `@app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js`:
- Line 3: `CATEGORY` is currently being pulled from the `FilterByCategory`
component, which couples the slice to UI code and risks circular imports.
Extract `CATEGORY` into a shared non-component module (for example a constants
file used by both `tideDashboardSlice` and `tideDashboardApi`) and update the
imports in `tideDashboardSlice` and any other consumers to reference that shared
symbol instead of the component.

In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js`:
- Around line 96-100: The TideDashboardV2 component still has dead commented-out
prop wiring for the table, which should be cleaned up or restored. In
TideDashboardV2.js, either pass the intended props through to the
table/component using the existing handlers and state like handleSortChange,
sort, and handleClickPatient, or remove the commented lines entirely if they are
not needed. Keep the component definition clean by resolving the commented `sx`,
`onSort`, `order`, `orderBy`, and `onClickRow` wiring around the table usage.
- Around line 81-93: The TideDashboardV2 table defines several non-functional
placeholder columns with empty field values and no renderers, so they will
always display blank cells. Update the columns in TideDashboardV2 to either wire
each one to real data/render logic using the relevant table row fields or
explicitly mark them as intentional scaffolding with a clear TODO/comment so
they are not mistaken for finished UI, including the trailing More column.

In `@app/redux/store/configureStore.dev.js`:
- Around line 112-125: Remove the stray leftover comment in
configureStore.dev.js and extract the duplicated subscribe/throttled persistence
logic into a shared helper so dev and prod stay in sync. Create a small function
such as persistBlipState(store) alongside the existing localStorage helpers, and
have both configureStore.dev.js and configureStore.prod.js call it from their
store.subscribe(throttle(...)) blocks. Keep the helper responsible for reading
selectedClinicId, loggedInUserId, saving selectedClinicId, and persisting
tideDashboardFilters via getTideDashboardFiltersKey.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f591017d-1d32-4b49-81a3-fb44c42913dd

📥 Commits

Reviewing files that changed from the base of the PR and between 5483630 and 500bbe5.

📒 Files selected for processing (32)
  • __tests__/utils/setupStore.js
  • app/bootstrap.js
  • app/components/elements/Table.js
  • app/pages/clinicworkspace/ClinicPatients.js
  • app/pages/clinicworkspace/TideDashboardV2/CGMExclusionQuery.js
  • app/pages/clinicworkspace/TideDashboardV2/Cells.js
  • app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js
  • app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js
  • app/pages/clinicworkspace/TideDashboardV2/FilterBySites.js
  • app/pages/clinicworkspace/TideDashboardV2/FilterByTags.js
  • app/pages/clinicworkspace/TideDashboardV2/TableCategoryHeader.js
  • app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js
  • app/pages/clinicworkspace/TideDashboardV2/index.js
  • app/pages/clinicworkspace/TideDashboardV2/tideDashboardApi.js
  • app/pages/clinicworkspace/TideDashboardV2/tideDashboardFiltersSlice.js
  • app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js
  • app/pages/clinicworkspace/TideDashboardV2/useActiveFiltersCount.js
  • app/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.js
  • app/pages/clinicworkspace/clinicworkspace.js
  • app/pages/clinicworkspace/components/ActiveFilterCount.js
  • app/pages/clinicworkspace/components/CategorySegmentedControl.js
  • app/pages/clinicworkspace/components/PaginationControls.js
  • app/pages/clinicworkspace/components/PatientCount.js
  • app/pages/clinicworkspace/components/ResetFilters.js
  • app/pages/clinicworkspace/components/SitesFilterDropdown.js
  • app/pages/clinicworkspace/components/TagFilterDropdown.js
  • app/pages/clinicworkspace/components/TagListCell.js
  • app/redux/actions/async.js
  • app/redux/reducers/index.js
  • app/redux/store/configureStore.dev.js
  • app/redux/store/configureStore.prod.js
  • app/redux/store/localStorage.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tidepool-org/viz (auto-detected)
💤 Files with no reviewable changes (1)
  • app/bootstrap.js

const trackMetric = () => noop;
const prefixPopHealthMetric = () => noop;

import { SPECIAL_FILTER_STATES } from '../ClinicPatients';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Move SPECIAL_FILTER_STATES out of ClinicPatients.js to avoid a shared-component → page dependency.

SitesFilterDropdown is a shared component (also consumed by TideDashboardV2/FilterBySites.js), but it imports a constant from a page-level module. This inverts the intended dependency direction and risks circular imports as more pages adopt this dropdown.

Consider extracting SPECIAL_FILTER_STATES into a shared constants module (e.g. core/clinicUtils.js) that both ClinicPatients.js and SitesFilterDropdown.js can import from.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/components/SitesFilterDropdown.js` at line 33, Move
SPECIAL_FILTER_STATES out of ClinicPatients.js and into a shared constants
module so SitesFilterDropdown stays independent of a page-level import. Update
SitesFilterDropdown and ClinicPatients to import the constant from the new
shared location, and make sure any other consumers such as
TideDashboardV2/FilterBySites use the same shared source to avoid circular
dependencies.

? t('There are no patients with the current filter(s)')
: t('There are no results to show');

const handleResetFilters = () => dispatch(resetTideDashboardFilters());

Copy link
Copy Markdown

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== EmptyContentNode ==\n'
sed -n '1,220p' app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js

printf '\n== TideDashboard filters slice ==\n'
sed -n '1,240p' app/pages/clinicworkspace/TideDashboardV2/tideDashboardFiltersSlice.js

printf '\n== TideDashboard slice ==\n'
sed -n '1,240p' app/pages/clinicworkspace/TideDashboardV2/tideDashboardSlice.js

printf '\n== Search for resetTideDashboardFilters / setOffset / offset handling ==\n'
rg -n "resetTideDashboardFilters|setOffset\\(|offset" app/pages/clinicworkspace/TideDashboardV2 -g '*.js' -g '*.jsx' -g '*.ts' -g '*.tsx'

Repository: tidepool-org/blip

Length of output: 5968


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,180p' app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js

Repository: tidepool-org/blip

Length of output: 176


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== TideDashboardV2.js (1-120) ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js

printf '\n== FilterByTags.js ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/FilterByTags.js

printf '\n== FilterBySites.js ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/FilterBySites.js

printf '\n== FilterByCategory.js ==\n'
sed -n '1,120p' app/pages/clinicworkspace/TideDashboardV2/FilterByCategory.js

Repository: tidepool-org/blip

Length of output: 176


Reset pagination when clearing filters.
handleResetFilters only dispatches resetTideDashboardFilters(), so clearing filters from a non-zero page can leave the dashboard on an empty offset even when unfiltered results exist. Reset offset to 0 here as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/EmptyContentNode.js` at line 33,
Resetting filters currently leaves pagination untouched, so the dashboard can
stay on a non-zero offset after filters are cleared. Update handleResetFilters
to also reset the pagination state by setting offset back to 0 along with
dispatching resetTideDashboardFilters(), using the existing dashboard
state/actions around TideDashboardV2.

Comment on lines +40 to +58
const { data } = useGetTideDashboardPatientsQuery(
{ clinicId: selectedClinicId, offset, category, tags: patientTags, sites: clinicSites, limit: LIMIT },
{ skip: !selectedClinicId }
);

const activeFiltersCount = useActiveFiltersCount();

// reset state on dismount
useEffect(() => {
return () => dispatch(resetTideDashboardState());
}, []);

const handleChangeOffset = (newOffset) => dispatch(setOffset(newOffset));

if (!data) return null;

const tableData = data?.data || [];

const total = data?.meta?.count || 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

No loading indicator while patients query resolves.

data starts undefined until the RTK Query resolves, and the component renders nothing (return null) during that window — no skeleton/spinner. This will show a blank page area on every navigation to the tab.

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 51-51: Avoid using the initial state variable in setState
Context: setOffset(newOffset)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js` around lines 40
- 58, The TideDashboardV2 component returns null while
useGetTideDashboardPatientsQuery is still resolving because it only checks data,
which leaves a blank area on navigation. Update TideDashboardV2.js to use the
query’s loading state (for example from useGetTideDashboardPatientsQuery) and
render an appropriate skeleton/spinner until the request finishes, then fall
through to the existing tableData/total rendering once data is available.

Comment thread app/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.js
const dispatch = useDispatch();
const selectedClinicId = useSelector(state => state.blip.selectedClinicId);
const clinic = useSelector(state => state.blip.clinics?.[selectedClinicId]);
const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters.patientTags);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Broken selector disables all pruning logic.

state.blip.tideDashboardFilters.patientTags is an array (per tideDashboardFiltersSlice's initialState: { patientTags: [], clinicSites: [] }), so destructuring { patientTags, clinicSites } off it yields undefined for both. Both effects below early-return via !patientTags?.length/!clinicSites?.length, so stale tag/site IDs are never pruned — the entire hook is a no-op.

🐛 Proposed fix
-  const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters.patientTags);
+  const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters.patientTags);
const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/pages/clinicworkspace/TideDashboardV2/usePruneInvalidFilters.js` at line
10, The selector in usePruneInvalidFilters is reading the wrong shape from
state, so patientTags and clinicSites become undefined and both pruning effects
never run. Update the useSelector call to select the full tideDashboardFilters
slice (or the actual arrays directly) instead of destructuring from
state.blip.tideDashboardFilters.patientTags, then verify the existing
patientTags/clinicSites effects in usePruneInvalidFilters still receive arrays
and can prune stale IDs as intended.

@henry-tp henry-tp changed the title WEB-4460 - Setup Dashboard WEB-4460 - Setup TIDE Dashboard Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants