mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(apple-health): show a written-back type's newest reading on its row
A reading entered here goes to Apple Health as well, and the quiet verdict already counted it, but the row still showed the newest reading that arrived from the phone, so a type entered two minutes ago read one day old. The server now resolves lastSeenAt to the newer of the two for the types the app writes back, and the row and the verdict agree. Refs #1247
This commit is contained in:
1 parent
a0e725556b
commit
628f37bc62
4 files changed
+19
-8
No files matched your search
@@ -77130,7 +77130,9 @@ components:
|
||||
glucose while their entry is `bidirectional` or `writeOnly` and enabled): when the newest reading of the
|
||||
type was entered here rather than arriving from Apple Health, or null when none was. Such readings go to the
|
||||
phone and never come back as an arrival, so `stale` already counts them: the type is quiet only when both
|
||||
this and `lastSeenAt` are. Show it as the server sends it; do not recompute `stale`."
|
||||
are. Since v1.43.9 `lastSeenAt` on such a type is the newer of this and the newest reading from Apple
|
||||
Health, because a reading entered here is in Apple Health too; show both as the server sends them and do not
|
||||
recompute `stale`."
|
||||
anyOf:
|
||||
- type: string
|
||||
format: date-time
|
||||
|
||||
@@ -406,6 +406,9 @@ describe("GET /api/integrations/healthkit — sync health", () => {
|
||||
expect(entries.WEIGHT.lastEnteredHereAt).toBe(
|
||||
enteredHereAt.toISOString(),
|
||||
);
|
||||
// The reading entered here is in Apple Health too, so it is the type's
|
||||
// newest reading: the row and the verdict read the same instant.
|
||||
expect(entries.WEIGHT.lastSeenAt).toBe(enteredHereAt.toISOString());
|
||||
// A read-only type keeps its own verdict and carries no such field.
|
||||
expect(entries.PULSE.stale).toBe(true);
|
||||
expect(entries.PULSE).not.toHaveProperty("lastEnteredHereAt");
|
||||
|
||||
@@ -342,21 +342,27 @@ export function classifyMetricFreshness(
|
||||
return samples.map((sample) => {
|
||||
// A type the app writes back to the phone (#1247): what is entered here
|
||||
// goes to Apple Health and never arrives back, so a person who keeps
|
||||
// their readings here would otherwise watch the type go quiet. The newer
|
||||
// of the two is what says whether the type is still in use.
|
||||
// their readings here would otherwise watch the type go quiet. That
|
||||
// reading is in Apple Health too, so the newer of the two is the type's
|
||||
// newest reading: it is what the row shows and what the verdict reads.
|
||||
const written = enteredHere?.has(sample.type)
|
||||
? { lastEnteredHereAt: enteredHere.get(sample.type) ?? null }
|
||||
: {};
|
||||
if (verdict !== "fresh" || SPARSE_METRIC_TYPES.has(sample.type)) {
|
||||
return { ...sample, ...written, stale: false };
|
||||
}
|
||||
const seen = newest(
|
||||
toMillis(sample.lastSeenAt),
|
||||
toMillis(written.lastEnteredHereAt),
|
||||
);
|
||||
return {
|
||||
const resolved = {
|
||||
...sample,
|
||||
...written,
|
||||
lastSeenAt:
|
||||
seen != null ? new Date(seen).toISOString() : sample.lastSeenAt,
|
||||
};
|
||||
if (verdict !== "fresh" || SPARSE_METRIC_TYPES.has(sample.type)) {
|
||||
return { ...resolved, stale: false };
|
||||
}
|
||||
return {
|
||||
...resolved,
|
||||
stale: seen != null && nowMs - seen > METRIC_QUIET_AFTER_MS,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -293,7 +293,7 @@ const appleHealthMetricFreshnessEntry = metricFreshnessEntry
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
"v1.43.7 — present only on a type the app writes back to Apple Health (weight, blood pressure, blood glucose while their entry is `bidirectional` or `writeOnly` and enabled): when the newest reading of the type was entered here rather than arriving from Apple Health, or null when none was. Such readings go to the phone and never come back as an arrival, so `stale` already counts them: the type is quiet only when both this and `lastSeenAt` are. Show it as the server sends it; do not recompute `stale`.",
|
||||
"v1.43.7 — present only on a type the app writes back to Apple Health (weight, blood pressure, blood glucose while their entry is `bidirectional` or `writeOnly` and enabled): when the newest reading of the type was entered here rather than arriving from Apple Health, or null when none was. Such readings go to the phone and never come back as an arrival, so `stale` already counts them: the type is quiet only when both are. Since v1.43.9 `lastSeenAt` on such a type is the newer of this and the newest reading from Apple Health, because a reading entered here is in Apple Health too; show both as the server sends them and do not recompute `stale`.",
|
||||
),
|
||||
})
|
||||
.meta({
|
||||
|
||||
Reference in new issue
Block a user