mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
Merge pull request #579 from MBombeck/release/v1.31.8
chore: release v1.31.8
This commit is contained in:
8 files changed
+65
-14
No files matched your search
@@ -2,9 +2,16 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.31.8] — 2026-07-21
|
||||
|
||||
- **MCP search cursors keep lab results stable across pages.** Distinct analyte
|
||||
names are ordered before offset pagination, preventing repeated or skipped
|
||||
lab entries when a client follows `nextCursor`.
|
||||
- **Opening the medication wizard no longer risks clearing entered fields.**
|
||||
The one-shot URL flag is removed without starting a second page navigation,
|
||||
so slower browsers keep the active wizard instance and its form state.
|
||||
|
||||
No migrations. No breaking changes.
|
||||
|
||||
## [1.31.7] — 2026-07-20
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: HealthLog API
|
||||
version: 1.31.7
|
||||
version: 1.31.8
|
||||
description: >-
|
||||
Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest.
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@ import { STORAGE_STATE_PATH } from "./setup/global-setup";
|
||||
/**
|
||||
* v1.5.4 — Medication wizard end-to-end — daily cadence.
|
||||
*
|
||||
* Walks the 7-step daily path through the modal dialog. The dialog
|
||||
* mounts when `/medications/new` redirects to `/medications?new=1`.
|
||||
* Walks the 7-step daily path through the modal dialog. The shared helper
|
||||
* opens `/medications?new=1` directly so cadence coverage is independent of
|
||||
* the legacy `/medications/new` redirect.
|
||||
* The DE label surface (the maintainer's primary locale) is the assertion
|
||||
* surface — "Schritt N von 7" tracks the visible counter.
|
||||
*/
|
||||
|
||||
@@ -120,8 +120,9 @@ export async function stubDashboardAnalytics(page: Page): Promise<void> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the wizard dialog by hitting `/medications/new` (which
|
||||
* redirects to `/medications?new=1` and opens the create dialog).
|
||||
* Open the wizard directly on `/medications?new=1`. The redirect from the
|
||||
* legacy `/medications/new` route is a separate concern; these cadence specs
|
||||
* exercise the wizard without racing that server navigation.
|
||||
*/
|
||||
export async function openCreateWizard(page: Page): Promise<void> {
|
||||
// Pin the German locale for the wizard flow. The app default locale is
|
||||
@@ -141,7 +142,11 @@ export async function openCreateWizard(page: Page): Promise<void> {
|
||||
: "http://localhost:3000",
|
||||
},
|
||||
]);
|
||||
await page.goto("/medications/new", { waitUntil: "domcontentloaded" });
|
||||
await page.goto("/medications?new=1", { waitUntil: "load" });
|
||||
await page.waitForURL(
|
||||
(url) => url.pathname === "/medications" && !url.searchParams.has("new"),
|
||||
{ timeout: 10_000 },
|
||||
);
|
||||
await expect(
|
||||
page.locator('[data-slot="medication-wizard-dialog"]'),
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
@@ -33,6 +33,29 @@ import { STORAGE_STATE_PATH } from "./setup/global-setup";
|
||||
test.describe("medication wizard — one-shot", () => {
|
||||
test.use({ storageState: STORAGE_STATE_PATH });
|
||||
|
||||
test("does not replay the one-shot URL flag after history traversal", async ({
|
||||
page,
|
||||
}) => {
|
||||
await stubDashboardAnalytics(page);
|
||||
await openCreateWizard(page);
|
||||
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(
|
||||
page.locator('[data-slot="medication-wizard-dialog"]'),
|
||||
).toHaveCount(0);
|
||||
|
||||
await page.locator('a[href="/"]:visible').first().click();
|
||||
await page.waitForURL((url) => url.pathname === "/");
|
||||
await page.goBack();
|
||||
await page.waitForURL(
|
||||
(url) => url.pathname === "/medications" && !url.searchParams.has("new"),
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.locator('[data-slot="medication-wizard-dialog"]'),
|
||||
).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("creates a single-dose medication end-to-end", async ({ page }) => {
|
||||
test.slow();
|
||||
await stubDashboardAnalytics(page);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "healthlog",
|
||||
"version": "1.31.7",
|
||||
"version": "1.31.8",
|
||||
"description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.",
|
||||
"license": "PolyForm-Noncommercial-1.0.0",
|
||||
"homepage": "https://healthlog.dev",
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ try {
|
||||
// v1.4.38.4 → v1.4.42. Do not hand-edit; bump `package.json` and rebuild.
|
||||
const CACHE_VERSION =
|
||||
(typeof self !== "undefined" && self.__APP_VERSION__) ||
|
||||
/* @sw-version-fallback */ "v1.31.7";
|
||||
/* @sw-version-fallback */ "v1.31.8";
|
||||
const STATIC_CACHE = `healthlog-static-${CACHE_VERSION}`;
|
||||
const PAGE_CACHE = `healthlog-pages-${CACHE_VERSION}`;
|
||||
// v1.18.6 — read-only data cache for a curated allowlist of safe GET `/api/*`
|
||||
|
||||
@@ -198,12 +198,27 @@ export default function MedicationsPageClient() {
|
||||
const { layout, isLayoutLoading } = useMedicationListLayout(isAuthenticated);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldOpenFromUrl) {
|
||||
// Drop the query param so a refresh after closing the dialog
|
||||
// doesn't keep reopening it.
|
||||
router.replace("/medications");
|
||||
}
|
||||
}, [shouldOpenFromUrl, router]);
|
||||
if (!shouldOpenFromUrl) return;
|
||||
|
||||
// Child effects may run before the App Router installs its native-history
|
||||
// integration, while the responsive sheet also settles its first client
|
||||
// layout. Wait until the following painted frame so replaceState preserves
|
||||
// Next's internals and synchronizes useSearchParams without starting a
|
||||
// router navigation that can remount the open wizard and discard fields.
|
||||
let cleanupFrame: number | undefined;
|
||||
const layoutFrame = window.requestAnimationFrame(() => {
|
||||
cleanupFrame = window.requestAnimationFrame(() => {
|
||||
window.history.replaceState(null, "", "/medications");
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
window.cancelAnimationFrame(layoutFrame);
|
||||
if (cleanupFrame !== undefined) {
|
||||
window.cancelAnimationFrame(cleanupFrame);
|
||||
}
|
||||
};
|
||||
}, [shouldOpenFromUrl]);
|
||||
|
||||
const {
|
||||
data: medications,
|
||||
|
||||
Reference in new issue
Block a user