Compare commits

...
Author SHA1 Message Date
Claude 58745543f3 Correct system and diagnostics API types in the frontend
Compare the system health, log, repairs and related data modules with
the handlers that produce them, and fix the mismatches.

The system health failure detail was read from a key that does not
exist, so a failed check rendered blank. Repairs issues carry several
always-present nullable fields and no active flag. Saving the core
config and ignoring a repair return nothing, and the icon types were
missing a nesting level.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK
2026-09-21 05:38:07 +00:00
15 changed files with 57 additions and 49 deletions
+2 -1
View File
@@ -10,6 +10,7 @@ export interface AnalyticsPreferences {
export interface Analytics {
preferences: AnalyticsPreferences;
onboarded: boolean;
}
export const getAnalyticsDetails = (hass: HomeAssistant) =>
@@ -21,7 +22,7 @@ export const setAnalyticsPreferences = (
hass: HomeAssistant,
preferences: AnalyticsPreferences
) =>
hass.callWS<AnalyticsPreferences>({
hass.callWS<{ preferences: AnalyticsPreferences }>({
type: "analytics/preferences",
preferences,
});
+2 -2
View File
@@ -1,4 +1,3 @@
import type { HassConfig } from "home-assistant-js-websocket";
import type { HomeAssistant } from "../types";
export interface ConfigUpdateValues {
@@ -14,6 +13,7 @@ export interface ConfigUpdateValues {
currency?: string | null;
country?: string | null;
language?: string | null;
update_units?: boolean;
}
export interface CheckConfigResult {
@@ -26,7 +26,7 @@ export const saveCoreConfig = (
hass: HomeAssistant,
values: Partial<ConfigUpdateValues>
) =>
hass.callWS<HassConfig>({
hass.callWS<undefined>({
type: "config/core/update",
...values,
});
+3 -1
View File
@@ -16,7 +16,8 @@ export interface HttpConfig {
}
// The slot the running HTTP server was actually started with.
export type ActiveConfigType = "stable" | "pending" | "default";
export type ActiveConfigType =
"stable" | "pending" | "default" | "default_legacy_port";
// A stored config slot carries metadata alongside the editable fields:
// - created_at: when the slot was staged
@@ -25,6 +26,7 @@ export type ActiveConfigType = "stable" | "pending" | "default";
export interface HttpConfigWithMeta extends HttpConfig {
created_at?: string;
error?: string | null;
error_message?: string | null;
}
export interface HttpConfigState {
+17 -14
View File
@@ -193,19 +193,22 @@ interface IconResources<
type PlatformIcons = Record<
string,
{
state: Record<string, string>;
range?: Record<string, string>;
state_attributes: Record<
string,
{
state: Record<string, string>;
range?: Record<string, string>;
default: string;
}
>;
default: string;
}
Record<
string,
{
state?: Record<string, string>;
range?: Record<string, string>;
state_attributes?: Record<
string,
{
state?: Record<string, string>;
range?: Record<string, string>;
default?: string;
}
>;
default?: string;
}
>
>;
export type ComponentIcons = Record<
@@ -216,7 +219,7 @@ export type ComponentIcons = Record<
state_attributes?: Record<
string,
{
state: Record<string, string>;
state?: Record<string, string>;
range?: Record<string, string>;
default: string;
}
+3 -3
View File
@@ -9,9 +9,9 @@ export interface LabPreviewFeature {
domain: string;
enabled: boolean;
is_built_in: boolean;
feedback_url?: string;
learn_more_url?: string;
report_issue_url?: string;
feedback_url: string | null;
learn_more_url: string | null;
report_issue_url: string | null;
}
export interface LabPreviewFeaturesResponse {
+8 -9
View File
@@ -7,18 +7,17 @@ import type { DataEntryFlowStep } from "./data_entry_flow";
export interface RepairsIssue {
domain: string;
issue_domain?: string;
issue_domain: string | null;
issue_id: string;
active: boolean;
is_fixable: boolean;
severity: "error" | "warning" | "critical";
breaks_in_ha_version?: string;
breaks_in_ha_version: string | null;
ignored: boolean;
created: string;
dismissed_version?: string;
learn_more_url?: string;
translation_key?: string;
translation_placeholders?: Record<string, string>;
dismissed_version: string | null;
learn_more_url: string | null;
translation_key: string | null;
translation_placeholders: Record<string, string> | null;
}
export const severitySort = {
@@ -37,7 +36,7 @@ export const fetchRepairsIssueData = (
domain: string,
issue_id: string
) =>
conn.sendMessagePromise<{ issue_data: { string: any } }>({
conn.sendMessagePromise<{ issue_data: Record<string, any> | null }>({
type: "repairs/get_issue_data",
domain,
issue_id,
@@ -48,7 +47,7 @@ export const ignoreRepairsIssue = async (
issue: RepairsIssue,
ignore: boolean
) =>
hass.callWS<string>({
hass.callWS<undefined>({
type: "repairs/ignore_issue",
issue_id: issue.issue_id,
domain: issue.domain,
+5
View File
@@ -7,8 +7,11 @@ export interface RelatedResult {
config_entry?: string[];
device?: string[];
entity?: string[];
floor?: string[];
group?: string[];
integration?: string[];
label?: string[];
person?: string[];
scene?: string[];
script?: string[];
script_blueprint?: string[];
@@ -29,7 +32,9 @@ export type ItemType =
| "entity"
| "floor"
| "group"
| "integration"
| "label"
| "person"
| "scene"
| "script"
| "automation_blueprint"
+5 -10
View File
@@ -21,7 +21,7 @@ export type SystemCheckValueObject =
| SystemCheckValuePendingObject;
export type SystemCheckValue =
string | number | boolean | SystemCheckValueObject;
string | number | boolean | null | SystemCheckValueObject;
export type SystemHealthInfo = Partial<{
homeassistant: {
@@ -31,8 +31,8 @@ export type SystemHealthInfo = Partial<{
dev: boolean;
hassio: boolean;
docker: boolean;
container_arch: string;
user: string;
container_arch: string | null;
user: string | null;
virtualenv: boolean;
python_version: string;
os_name: string;
@@ -65,9 +65,7 @@ interface SystemHealthEventUpdateError {
success: false;
domain: string;
key: string;
error: {
msg: string;
};
error: SystemCheckValueErrorObject;
}
interface SystemHealthEventFinish {
@@ -107,10 +105,7 @@ export const subscribeSystemHealthInfo = (
...data[updateEvent.domain].info,
[updateEvent.key]: updateEvent.success
? updateEvent.data
: {
error: true,
value: updateEvent.error.msg,
},
: updateEvent.error,
},
},
};
+1 -1
View File
@@ -5,7 +5,7 @@ export type SystemLogLevel =
export interface LoggedError {
name: string;
message: [string];
message: string[];
level: SystemLogLevel;
source: [string, number];
exception: string;
+1 -1
View File
@@ -24,7 +24,7 @@ interface TemplatePreviewState {
state: string;
attributes: Record<string, any>;
listeners: TemplateListeners;
domain?: string;
domain: string;
}
interface TemplatePreviewError {
+1 -1
View File
@@ -18,7 +18,7 @@ export type Theme = ThemeVars & {
export interface Themes {
default_theme: string;
default_dark_theme: string | null;
default_dark_theme?: string | null;
themes: Record<string, Theme>;
// Currently effective dark mode. Will never be undefined. If user selected "auto"
// in theme picker, this property will still contain either true or false based on
@@ -19,7 +19,9 @@ import "./dialog-repairs-issue-subtitle";
const mergePlaceholders = (issue: RepairsIssue, step: DataEntryFlowStep) =>
step.description_placeholders && issue.translation_placeholders
? { ...issue.translation_placeholders, ...step.description_placeholders }
: step.description_placeholders || issue.translation_placeholders;
: step.description_placeholders ||
issue.translation_placeholders ||
undefined;
const renderIssueDescription = (hass: HomeAssistant, issue: RepairsIssue) =>
issue.breaks_in_ha_version
@@ -102,7 +102,7 @@ class DialogRepairsIssue extends LitElement {
`component.${this._issue.domain}.issues.${
this._issue.translation_key || this._issue.issue_id
}.description`,
this._issue.translation_placeholders
this._issue.translation_placeholders ?? undefined
) ||
`${this._issue.domain}: ${this._issue.translation_key || this._issue.issue_id}`
}
@@ -144,7 +144,7 @@ class HaConfigRepairs extends LitElement {
issue.domain,
issue.issue_id
);
if ("flow_id" in data.issue_data) {
if (data.issue_data && "flow_id" in data.issue_data) {
showConfigFlowDialog(this, {
continueFlowId: data.issue_data.flow_id as string,
});
@@ -159,6 +159,7 @@ class HaConfigRepairs extends LitElement {
issue.issue_id
);
if (
data.issue_data &&
"entity_id" in data.issue_data &&
typeof data.issue_data.entity_id === "string"
) {
@@ -177,7 +178,7 @@ class HaConfigRepairs extends LitElement {
issue.domain,
issue.issue_id
);
if ("issue_type" in data.issue_data) {
if (data.issue_data && "issue_type" in data.issue_data) {
await fixStatisticsIssue(this, {
type: data.issue_data
.issue_type as StatisticsValidationResult["type"],
@@ -38,9 +38,9 @@ export class HuiRepairsCard
subscribeRepairsIssueRegistry(
this.hass!.connection,
(repairs: { issues: RepairsIssue[] }) => {
// Filter to only active and non-ignored issues
// Filter to only non-ignored issues
this._repairsIssues = repairs.issues.filter(
(issue) => issue.active !== false && !issue.ignored
(issue) => !issue.ignored
);
}
),