Skip to content

Open dashboard action on the card model, with storage changes #74

Open

Description

@1t5j0y

As a phone app developer, I need the card model to carry the Open dashboard action and its target, so that the phone can open the right dashboard.

Motivation — plain

The phone keeps cards in its own database. Without a place for the target dashboard, the action reaches the phone and is lost. The target is kept as a plain reference to the dashboard. On a fresh phone, cards arrive before dashboards, so a stored link to the dashboard itself would be empty.

Acceptance Criteria — plain

  • A card synced with Open dashboard is stored with its action and the target dashboard's reference, on a fresh install and on an upgraded one.
  • On a fresh install, the target is present even though cards sync before dashboards.
  • A card with any other action stores no target.
  • Upgrading a phone with existing cards keeps them and their actions unchanged.
  • A new avni-models version is released carrying this change.

Tech Approach — technical

Verified on avni-models origin/18.3 @ 6bb6ac8, version 1.33.86.

  • src/ReportCard.js:
    • actionTypes (:22-26): add OpenDashboard: "OpenDashboard".
    • Schema (:38-64): add actionDetailDashboardUUID: {type: "string", optional: true}. A string, not an object reference. Reference data syncs from the end of EntityMetaData.model() backwards (src/EntityMetaData.js:495), so reportCard syncs before dashboard (:503). A Dashboard resolved in fromResource is null on a fresh phone.
    • Getter and setter beside actionDetailVisitType (:319).
    • fromResource (:203-237): inside the resource.actionDetail block, reportCard.actionDetailDashboardUUID = resource.actionDetail.dashboardUUID || null.
    • isActionOpenDashboard() beside isActionMarkAttendance() (:347).
  • src/Schema.js: bump schemaVersion from 220 (:281) to 221, with a comment-only step if (oldDB.schemaVersion < 221), following < 213 (:1075).
  • Release, then bump openchs-models in avni-client packages/openchs-android/package.json:106 and avni-webapp package.json:43. Both pin 1.33.86 today.
  • SQLite on the phone is handled in avni-client (story Open a dashboard from a tile, carrying filters over and restoring the one underneath avni-client#2220). This story only changes the model.

Testing Gotchas — plain

  • Test a fresh install, not only an upgrade. A fresh install is where cards arrive before dashboards.
  • Upgrade a phone that holds cards with Do visit and Mark attendance. Their visit types and attendance types must survive.

Out of Scope — plain

Related — plain


Epic: avniproject/avni-product#1915

Activity

  1. moved this from New Issues to Ready in Avni Producton Oct 29, 2026
  2. moved this from Ready to In Progress in Avni Producton Oct 29, 2026
  3. added 2 commits that reference this issue on Oct 29, 2026
  4. adamsanadi6 commented on Oct 29, 2026

    @adamsanadi6
    Contributor

    Pushed to 18.3 as 6bb6ac8..88d9b71 and released as openchs-models 1.33.88. 1.33.87, released first, misses acceptance criterion 3 in one case, and 1.33.88 fixes it. All five criteria hold in the model and on a real phone database. The web app takes 1.33.88 on 18.3 and runs on it locally, though it does not show the new action yet. The phone app waits for avniproject/avni-client#2220, which should take 1.33.88 together with its migration.

    Two changes from the card as written:

    • The upgrade step makes every phone fetch its cards again, where the Tech Approach asked for a step that changes no data. A phone that synced an Open dashboard card on an older app kept the action but dropped the target, and sync fetches only what changed. Without the fetch again, those tiles would stay without a target.
    • A card switched from Open dashboard to View subject profile, or to no action, arrives with no action details, and the phone saves only the fields a card carries. In 1.33.87 such a card kept its old target. The fix gives every card that arrives without action details an empty target, so the old one is overwritten. The line the Tech Approach names stays where it puts it.

    Review on 30 Oct, before any testing: three reviewers checked each criterion against the code. Criterion 3 failed in the case above, and nothing else did. Two reviewers then checked the fix, and the wording of one comment was corrected.

    Tested on 30 Oct, all passing:

    • Unit tests, 15 for this card and the full suite of 483, with the fix. Each new test fails when the fix is taken out.
    • Before and after on both real phone databases. 1.33.87 keeps the old target after the switch, and the fix clears it. Every case from the earlier round still passes.
    • Against the server. The server's own test of the card sync passed, and its real output was fed to the model. An old phone stores the card without its target, upgrades, gets the target on the next sync, and loses it when the card is switched.
    • Upgrades from the previous version and from one seven months old. An upgrade cut off partway is completed by the next start. An older app refuses the newer database without losing data.
    • Volume: 1,000 cards in one sync, and an upgrade of a phone holding 1,000 cards.
    • Malformed input: 2,000 generated cards never crash the model. Only a target that is not text is refused when saving, and the server always sends text.
    • The phone app's own tests with the fix: 2,315 unit and 432 integration tests, with the same results as today.

    Before the 1.33.88 release, the unit suite, the real-database checks and the package check ran again on the fix, and three reviewer agents found nothing that blocks it. The published 1.33.88 passes the same package checks.

    Checked again from the beginning after the release, on 30 Oct:

    • Code review of the whole card by three reviewer agents, each checking every criterion afresh. None found anything that needs a change or a further release, and all five criteria hold.
    • Every test again on the released 1.33.88, all passing: the unit suite, the published package, the before-and-after runs on both phone databases, the upgrade matrix, an interrupted upgrade, a downgrade, volume, malformed input, the old-phone story on the server's real output, and 21 deliberate code changes. The runs on 1.33.87 still show its gap, as they should.
    • The phone app's and the web app's own tests on the package npm serves: 2,315 unit and 432 integration tests in the phone app, and 526 in the web app, with the same results as on 1.33.86.

    Tested again later on 30 Oct, after one more review confirmed the fix commit, all passing:

    • Upgrades from every database version the phone app shipped since v15.2, eleven in all, to the fixed model. Every card keeps what its release stored, and the card list is fetched again.
    • Generated sets of sync markers, 5,000 in all, including names that differ from the card's by one letter or a space. Only the card's marker moves.
    • A card taken through Open dashboard, Do visit, Mark attendance, View subject profile, no action and back to Open dashboard. This ran through the phone app's own save code on the newer database and through the older one, on the server's real output for every action. The target is there only when the card opens a dashboard.
    • The package that would be published as 1.33.88. It holds the same files as 1.33.87, and only the fixed file and the version differ.
    • 21 deliberate changes to the new code. Each one makes a test fail.
    • The web app's own 526 tests with the fix, with the same results as today.

    Tested on a local server and web app built from 18.3, on 30 Oct, with a test card that opens a test dashboard, all passing:

    • The web app on 1.33.88 opens the card list, the test card's details page and editor, a standard card's details page and the dashboard list.
    • The server's real card sync, read by 1.33.88, gives the test card its target. Switched to View subject profile on the server, the card arrives with an empty target, and switched back, it gets the target again.

    Screenshots, numbered as the files:

    1. The card list, with the test card.
    2. The test card's details page, which names its action View subject profile.
    3. The test card in the editor, with the Action field empty.
    4. The editor after Save, with the message that a dashboard is required. The card is not changed.
    5. A standard card's details page, as before.
    6. The dashboard list, with the test dashboard.

    Gaps and issues:

    • 1.33.87 as published still misses criterion 3 for switched cards, so apps should take 1.33.88. No app pins 1.33.87, so no phone holds a stale target.
    • Not run on a phone yet. That needs #2220 to take 1.33.88. Manual tests are below.
    • The web app does not know the new action yet. Its card details page names an Open dashboard card's action View subject profile, and its editor shows the Action field empty. Card editor: Open dashboard action avni-webapp#1830 adds the action to the editor, but the details page is not on that card. Until then, saving such a card in the web app is refused with a message, and the card keeps its action and target.
    • With the fix, every card carries the new field, so a phone app build without the newer database's migration fails on every card. Noted on Preset on the phone: hidden steps, seeding and clear avni-client#2222 and #2220. Both should take 1.33.88.
    • If #2220's migration stops partway, every later start fails. Noted on #2220.
    • An upgrade from the oldest field version, v15.0 to v15.1.4, could not be run. Its database format predates the database library the tests use.
    • For up to 12 hours after an update, a background sync only uploads. So an upgraded phone's tile has no target until a sync downloads. That belongs in #2220's manual tests.
    • An older gap, outside this card: when a Do visit or Mark attendance card's programme, subject type, encounter type or attendance type is cleared on the server, the phone keeps the old value. It is recorded here, and no card is filed for it.

    Testing notes:

    • Run the manual tests below once #2220 is built on 1.33.88.
    • The test scripts can be rerun on any laptop with the repositories checked out side by side. The tech details say where they are.
    Manual tests (technical)

    Setup. A server built from 18.3 (it carries avniproject/avni-server#1101), the phone app built from avniproject/avni-client#2220 on openchs-models 1.33.88, with migration 0009, an emulator, and one organisation whose user's group sees dashboard A, plus a second dashboard B. On a dashboard the user sees, four cards: the test card, Open dashboard with target A, created as in avni-server#1101's manual test 1; a Do visit card; a Mark attendance card; and a View subject profile card.

    1. Upgrade on the older database (AC 1, AC 4, Gotcha 2). Install today's app (models 1.33.86), log in and sync. Install the #2220 build over it without uninstalling, open it and sync.
    Expected: the app opens with its data. After the sync the test card opens dashboard A, and the other three cards do what they did before.

    2. Upgrade on the newer database (AC 1, AC 4). Repeat 1 with a user whose phone is already on the newer database.
    Expected: as in 1, and the app starts without a database error.

    3. Fresh install (AC 2, Gotcha 1). Uninstall, install the #2220 build, log in and sync.
    Expected: the test card opens dashboard A, though dashboards download after cards.

    4. Switch to Do visit (AC 3). Change the test card to Do visit on the server (avni-server#1101's manual test 6, with Do visit details) and sync.
    Expected: the test card acts as a Do visit card, and no dashboard opens.

    5. Switch to View subject profile (AC 3). Change the test card to View subject profile and sync.
    Expected: the test card opens subjects as before, and its old target is gone.

    6. Back to Open dashboard (AC 1). Change the test card to Open dashboard with target B and sync.
    Expected: the test card opens dashboard B.

    7. Rerun the evidence, any time. From avni-product-ops, run each .sh in analysis/dashboard-navigation-and-filter-presets/dev-testing/avni-models-74-evidence/, with avni-models and avni-client checked out beside it.
    Expected: each log ends with RESULT: every check passed.

    Tech details
    • 23a99a4: ReportCard gains actionTypes.OpenDashboard, actionDetailDashboardUUID (optional string) and isActionOpenDashboard(). fromResource maps actionDetail.dashboardUUID inside the actionDetail block (src/ReportCard.js:225-240).
    • 17170c8: schema 221. The < 221 step moves the ReportCard sync marker to 1900-01-01 (src/Schema.js:1145-1162), the same loop as the 208 step.
    • 0e0b566: v1.33.87. Publish run 40954094562 passed; npm gitHead is 0e0b566, tarball sha1 f89d0171.
    • 417a3b6: an else in fromResource sets actionDetailDashboardUUID to null when resource.actionDetail is absent (src/ReportCard.js:240-244). In test/ReportCardTest.js, isUndefined becomes isNull, and a new test, "clears the target when a card arrives with no action details", covers View subject profile and no action.
    • 88d9b71: v1.33.88. Publish run 41021885467 passed; npm gitHead is 88d9b71, tarball sha1 4d72332d. published-1.33.88-check passes 13 of 13 on the npm tarball.
    • avni-webapp a9f07542a on 18.3: openchs-models 1.33.86 to 1.33.88 in package.json:43 and its one lockfile entry, the step the Tech Approach names. A frozen install accepts the lockfile, and the web app's 537 tests and production build pass.
    • The full re-check on 1.33.88: full-recheck-1.33.88-summary.log and the *-v1.33.88.log files in the evidence folder, with realm-corner-cases-v1.33.87.log and sqlite-after-0009-v1.33.87.log as the controls; consumer-avni-client-18.3.log and consumer-avni-webapp-18.3.log ran the npm tarball.
    • Unit, on 417a3b6 with Node 20.18.1: the file passes 15 of 15 and the suite 483, with 1 skipped. The build compiles 158 files, and all 97 schemas are valid at 221.
    • Evidence scripts and logs in avni-product-ops analysis/dashboard-navigation-and-filter-presets/dev-testing/avni-models-74-evidence/, run on Node 24.11.1 unless noted:
      • realm-corner-cases (27 checks) and sqlite-after-0009 (14). Their -0e0b566 logs show the defect in the release.
      • realm-upgrade-220-to-221 (30), realm-upgrade-from-old (45), realm-fault-injection (16), realm-downgrade (15), realm-volume (7), model-fuzz (9, seed 20261030) and realm-old-phone-story (12).
      • sqlite-pin-without-0009 (12) and published-1.33.87-check (10).
      • server-sync-capture: avni-server 694572fc6 ReportCardControllerIntegrationTest 9 of 9, JDK 21.0.12.1, Gradle 8.10.2, offline, from a throwaway worktree. It also holds the two sync bodies.
      • consumer-avni-client-18.3: avni-client a527c117a on Node 20.18.1. Unit 2,315 and integration 432 passed, both with 1.33.86 and with the fix.
      • Third round on 417a3b6: realm-upgrade-matrix (99 checks; release schemas 204 to 220, with 203 refused by Realm 12.14.2), migration-properties (5 checks over 5,000 stand-in sets and 30 real files), switch-chains (33 checks through avni-client's SqliteProxy.bulkCreate and EntityHydrator.flatten and through RealmProxy, on server-sync-do-visit.json, server-sync-mark-attendance.json and server-sync-chain-*.json), release-candidate-1.33.88-check (13 checks; same 176 files as 1.33.87, only dist/ReportCard.js and package.json differ), local-mutation-analysis (21 of 21 killed; StrykerJS would be downloaded and run through npx, which the session's safety check refused) and consumer-avni-webapp-18.3 (avni-webapp c519dfad2, 526 passed with both).
    • How the database runs work: Realm 12.14.2 through its Node binding, with cards saved by the models' RealmProxy in the app's update mode. The newer database is built from avni-client a527c117a's migrations 0000 to 0008 plus the planned 0009.
    • Downgrade: 1.33.86 refuses the file with "Provided schema version 220 is less than last set version 221."
    • Volume: for 1,000 cards, fromResource takes 41.8 ms and one write 25.4 ms. A 220 file holding 1,000 cards and 300 markers opens in 37.1 ms, migration included.
    • The server side: ReportCardControllerIntegrationTest reads _embedded.card[].actionDetail.dashboardUUID from the real sync endpoint. This card reads resource.actionDetail.dashboardUUID (src/ReportCard.js:239). After the switch, the sync sends "actionDetail": null.
    • Web app run on 30 Oct: avni-webapp a9f07542a with 1.33.88 installed, on Vite's dev server, against a local avni-server built from 694572fc6, in the HCO Test organisation, with test card 100 and target dashboard 18. src/formDesigner/components/ReportCard/ReportCardShow.jsx:216-221 names every action other than Do visit "View subject profile". The editor's Action options (CreateEditReportCard.jsx:521-531) have no Open dashboard, and its save reaches the server as Open dashboard with no target, which CardService.java:329 refuses with 400 "Dashboard is required when action is OpenDashboard". The editor shows that message (CreateEditReportCard.jsx:953-956), and the card is unchanged.
    • live-server-contract (3 checks): the server's /v2/card/search/lastModified body for card 100, read by the installed 1.33.88 ReportCard.fromResource: the target as created, null after PUT /web/reportCard/100 to View subject profile ("actionDetail": null), and back after a switch back. Card 100 ends as created. The screenshots are in the evidence folder's webapp-1.33.88/.
  5. added 2 commits that reference this issue on Oct 30, 2026
  6. moved this from In Progress to Code Review Ready in Avni Producton Oct 30, 2026
  7. moved this from Code Review Ready to QA Ready in Avni Producton Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions