Fix Home and Phone settings states

This commit is contained in:
Gabriel Brown
2026-08-17 18:02:09 -04:00
parent 65966200fe
commit c8eb344a0b
6 changed files with 144 additions and 15 deletions
@@ -4,25 +4,38 @@ import qs.services
Item {
id: root
objectName: "home-phone-page"
property string lightQuery: searchInput.text.trim().toLowerCase()
readonly property var availableLights: HomeAssistant.catalog.filter(entity => {
if (HomePreferences.isSelected(entity.id))
if (HomeAssistant.selectedEntities.some(selected => selected.id === entity.id))
return false;
const haystack = (entity.sourceName + " " + entity.id).toLowerCase();
return root.lightQuery === "" || haystack.includes(root.lightQuery);
})
readonly property string availableEmptyText: root.availableLights.length > 0
? ""
: (root.lightQuery !== ""
? "No lights match that search"
: (HomeAssistant.catalog.length === 0
? "No lights discovered"
: "All discovered lights are already selected"))
readonly property var pageDiagnostics: ({
availableLightIds: root.availableLights.map(entity => entity.id),
availableEmptyText: root.availableEmptyText,
homeStatus: root.homeStatus()
})
function homeStatus(): string {
if (HomeAssistant.phase === "ready")
return `Connected · ${HomeAssistant.discoveredCount} lights discovered`;
if (HomeAssistant.phase === "degraded")
return "Last update unavailable · showing saved controls";
if (HomeAssistant.lastError === "authentication-required")
return "Authentication required";
if (HomeAssistant.lastError === "not-configured")
return "Home Assistant is not configured";
if (HomeAssistant.phase === "ready")
return `Connected · ${HomeAssistant.discoveredCount} lights discovered`;
if (HomeAssistant.phase === "degraded")
return "Last update unavailable · showing saved controls";
if (HomeAssistant.phase === "loading")
return "Connecting to Home Assistant";
return "Home Assistant is unavailable";
@@ -250,9 +263,7 @@ Item {
Text {
width: parent.width
visible: root.availableLights.length === 0
text: root.lightQuery === "" && HomeAssistant.catalog.length > 0
? "All discovered lights are already selected"
: "No lights match that search"
text: root.availableEmptyText
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
@@ -6,6 +6,11 @@ Rectangle {
id: root
property var hostWindow: null
readonly property var homePhoneDiagnostics: pageLoader.status === Loader.Ready
&& pageLoader.item
&& pageLoader.item.objectName === "home-phone-page"
? pageLoader.item.pageDiagnostics
: ({})
color: Theme.bg
radius: 18
@@ -6,6 +6,8 @@ import qs.services
FloatingWindow {
id: root
readonly property var homePhoneDiagnostics: settingsShell.homePhoneDiagnostics
title: "Panama Settings"
visible: ShellState.settingsOpen
implicitWidth: 1120
@@ -23,6 +25,7 @@ FloatingWindow {
}
SettingsShell {
id: settingsShell
anchors.fill: parent
hostWindow: root
}
@@ -434,7 +434,8 @@ Singleton {
}
function applyFixture(name: string): void {
if (["ready", "stale", "unavailable", "missing-selected", "action-error",
if (["ready", "available-extra", "stale", "stale-authentication", "stale-not-configured",
"unavailable", "missing-selected", "action-error",
"process-actions", "process-no-output", "process-delayed-exit",
"process-slow-actions"].indexOf(name) < 0)
return;
@@ -488,15 +489,31 @@ Singleton {
root.catalog = root.fixtureEntities();
root.fixtureFavorites = root.fixturePreferenceRecords();
if (name === "available-extra") {
root.catalog = root.catalog.concat([{
id: "light.fixture_guest",
sourceName: "Guest lamp",
state: "off",
available: true,
active: false,
dimmable: true,
brightnessPct: 0
}]);
}
if (name === "missing-selected") {
root.fixtureFavorites = root.fixtureFavorites.concat([
{ id: "light.fixture_missing", alias: "Porch" }
]);
}
root.rebuildSelection();
root.phase = name === "stale" ? "degraded" : "ready";
root.stale = name === "stale";
root.lastError = name === "stale" ? "unreachable" : "";
const isStale = ["stale", "stale-authentication", "stale-not-configured"].indexOf(name) >= 0;
root.phase = isStale ? "degraded" : "ready";
root.stale = isStale;
root.lastError = name === "stale-authentication"
? "authentication-required"
: (name === "stale-not-configured"
? "not-configured"
: (name === "stale" ? "unreachable" : ""));
if (name === "action-error") {
root.entityErrors = {
"light.fixture_kitchen": "request-failed"
+3 -2
View File
@@ -85,7 +85,7 @@ ShellRoot {
IntelligenceResult {}
ActivityPanel {}
PowerMenu {}
SettingsWindow {}
SettingsWindow { id: settingsWindow }
// Toasts are their own always-on layer; they must be able to appear
// without any overlay being open.
@@ -295,7 +295,8 @@ ShellRoot {
open: ShellState.settingsOpen,
page: ShellState.settingsPage,
discoveredCount: HomeAssistant.discoveredCount,
selectedCount: HomeAssistant.configuredCount
selectedCount: HomeAssistant.configuredCount,
homePhone: settingsWindow.homePhoneDiagnostics
});
}
}
@@ -93,6 +93,7 @@ assert_contains 'HomePreferences.add' "$home_page"
assert_contains 'HomePreferences.retrySave' "$home_page"
assert_contains 'Choose lights below to build your Control Center shelf.' "$home_page"
assert_contains 'All discovered lights are already selected' "$home_page"
assert_contains 'No lights discovered' "$home_page"
assert_contains 'No lights match that search' "$home_page"
assert_contains 'Opens BlueBubbles' "$home_page"
[[ "$(rg -Fc 'required property var modelData' "$home_page")" -ge 2 ]] \
@@ -173,9 +174,100 @@ for _ in $(seq 1 40); do
fi
sleep 0.1
done
jq -e '.open == true and .page == "home-phone" and .discoveredCount == 7 and .selectedCount == 7' \
jq -e '
.open == true and
.page == "home-phone" and
.discoveredCount == 7 and
.selectedCount == 7 and
.homePhone.availableLightIds == [] and
.homePhone.availableEmptyText == "All discovered lights are already selected"
' \
<<<"$status" >/dev/null || fail "Home & Phone diagnostics are incomplete: $status"
qs_for_test ipc call home-assistant fixture available-extra >/dev/null
available_status='{}'
for _ in $(seq 1 40); do
available_status="$(qs_for_test ipc call settings status | jq -c .)"
if jq -e '
.discoveredCount == 8 and
.selectedCount == 7 and
.homePhone.availableLightIds == ["light.fixture_guest"]
' <<<"$available_status" >/dev/null; then
break
fi
sleep 0.1
done
jq -e '
.discoveredCount == 8 and
.selectedCount == 7 and
.homePhone.availableLightIds == ["light.fixture_guest"]
' <<<"$available_status" >/dev/null \
|| fail "an unselected fixture light was not the only available row: $available_status"
qs_for_test ipc call home-assistant fixture stale-authentication >/dev/null
authentication_status='{}'
for _ in $(seq 1 40); do
authentication_status="$(qs_for_test ipc call settings status | jq -c .)"
if jq -e '
.discoveredCount == 7 and
.selectedCount == 7 and
.homePhone.homeStatus == "Authentication required"
' <<<"$authentication_status" >/dev/null; then
break
fi
sleep 0.1
done
jq -e '
.discoveredCount == 7 and
.selectedCount == 7 and
.homePhone.homeStatus == "Authentication required"
' <<<"$authentication_status" >/dev/null \
|| fail "stale authentication did not retain actionable copy: $authentication_status"
qs_for_test ipc call home-assistant fixture stale-not-configured >/dev/null
not_configured_status='{}'
for _ in $(seq 1 40); do
not_configured_status="$(qs_for_test ipc call settings status | jq -c .)"
if jq -e '
.discoveredCount == 7 and
.selectedCount == 7 and
.homePhone.homeStatus == "Home Assistant is not configured"
' <<<"$not_configured_status" >/dev/null; then
break
fi
sleep 0.1
done
jq -e '
.discoveredCount == 7 and
.selectedCount == 7 and
.homePhone.homeStatus == "Home Assistant is not configured"
' <<<"$not_configured_status" >/dev/null \
|| fail "stale not-configured state did not retain actionable copy: $not_configured_status"
qs_for_test ipc call home-assistant fixture unavailable >/dev/null
empty_status='{}'
for _ in $(seq 1 40); do
empty_status="$(qs_for_test ipc call settings status | jq -c .)"
if jq -e '
.discoveredCount == 0 and
.selectedCount == 0 and
.homePhone.homeStatus == "Home Assistant is not configured" and
.homePhone.availableLightIds == [] and
.homePhone.availableEmptyText == "No lights discovered"
' <<<"$empty_status" >/dev/null; then
break
fi
sleep 0.1
done
jq -e '
.discoveredCount == 0 and
.selectedCount == 0 and
.homePhone.homeStatus == "Home Assistant is not configured" and
.homePhone.availableLightIds == [] and
.homePhone.availableEmptyText == "No lights discovered"
' <<<"$empty_status" >/dev/null \
|| fail "an empty catalog did not render its distinct copy: $empty_status"
system_status="$(qs_for_test ipc call settings-system status | jq -c .)"
jq -e '.bluebubblesAvailable == true' <<<"$system_status" >/dev/null \
|| fail "BlueBubbles availability was not exposed: $system_status"