Fix Home and Phone settings states
This commit is contained in:
@@ -4,25 +4,38 @@ import qs.services
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
objectName: "home-phone-page"
|
||||||
|
|
||||||
property string lightQuery: searchInput.text.trim().toLowerCase()
|
property string lightQuery: searchInput.text.trim().toLowerCase()
|
||||||
|
|
||||||
readonly property var availableLights: HomeAssistant.catalog.filter(entity => {
|
readonly property var availableLights: HomeAssistant.catalog.filter(entity => {
|
||||||
if (HomePreferences.isSelected(entity.id))
|
if (HomeAssistant.selectedEntities.some(selected => selected.id === entity.id))
|
||||||
return false;
|
return false;
|
||||||
const haystack = (entity.sourceName + " " + entity.id).toLowerCase();
|
const haystack = (entity.sourceName + " " + entity.id).toLowerCase();
|
||||||
return root.lightQuery === "" || haystack.includes(root.lightQuery);
|
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 {
|
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")
|
if (HomeAssistant.lastError === "authentication-required")
|
||||||
return "Authentication required";
|
return "Authentication required";
|
||||||
if (HomeAssistant.lastError === "not-configured")
|
if (HomeAssistant.lastError === "not-configured")
|
||||||
return "Home Assistant is 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")
|
if (HomeAssistant.phase === "loading")
|
||||||
return "Connecting to Home Assistant";
|
return "Connecting to Home Assistant";
|
||||||
return "Home Assistant is unavailable";
|
return "Home Assistant is unavailable";
|
||||||
@@ -250,9 +263,7 @@ Item {
|
|||||||
Text {
|
Text {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: root.availableLights.length === 0
|
visible: root.availableLights.length === 0
|
||||||
text: root.lightQuery === "" && HomeAssistant.catalog.length > 0
|
text: root.availableEmptyText
|
||||||
? "All discovered lights are already selected"
|
|
||||||
: "No lights match that search"
|
|
||||||
color: Theme.fgDim
|
color: Theme.fgDim
|
||||||
font.family: Theme.fontFamily
|
font.family: Theme.fontFamily
|
||||||
font.pixelSize: Theme.fontSize
|
font.pixelSize: Theme.fontSize
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ Rectangle {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var hostWindow: null
|
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
|
color: Theme.bg
|
||||||
radius: 18
|
radius: 18
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import qs.services
|
|||||||
FloatingWindow {
|
FloatingWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property var homePhoneDiagnostics: settingsShell.homePhoneDiagnostics
|
||||||
|
|
||||||
title: "Panama Settings"
|
title: "Panama Settings"
|
||||||
visible: ShellState.settingsOpen
|
visible: ShellState.settingsOpen
|
||||||
implicitWidth: 1120
|
implicitWidth: 1120
|
||||||
@@ -23,6 +25,7 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsShell {
|
SettingsShell {
|
||||||
|
id: settingsShell
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hostWindow: root
|
hostWindow: root
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -434,7 +434,8 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applyFixture(name: string): void {
|
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-actions", "process-no-output", "process-delayed-exit",
|
||||||
"process-slow-actions"].indexOf(name) < 0)
|
"process-slow-actions"].indexOf(name) < 0)
|
||||||
return;
|
return;
|
||||||
@@ -488,15 +489,31 @@ Singleton {
|
|||||||
|
|
||||||
root.catalog = root.fixtureEntities();
|
root.catalog = root.fixtureEntities();
|
||||||
root.fixtureFavorites = root.fixturePreferenceRecords();
|
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") {
|
if (name === "missing-selected") {
|
||||||
root.fixtureFavorites = root.fixtureFavorites.concat([
|
root.fixtureFavorites = root.fixtureFavorites.concat([
|
||||||
{ id: "light.fixture_missing", alias: "Porch" }
|
{ id: "light.fixture_missing", alias: "Porch" }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
root.rebuildSelection();
|
root.rebuildSelection();
|
||||||
root.phase = name === "stale" ? "degraded" : "ready";
|
const isStale = ["stale", "stale-authentication", "stale-not-configured"].indexOf(name) >= 0;
|
||||||
root.stale = name === "stale";
|
root.phase = isStale ? "degraded" : "ready";
|
||||||
root.lastError = name === "stale" ? "unreachable" : "";
|
root.stale = isStale;
|
||||||
|
root.lastError = name === "stale-authentication"
|
||||||
|
? "authentication-required"
|
||||||
|
: (name === "stale-not-configured"
|
||||||
|
? "not-configured"
|
||||||
|
: (name === "stale" ? "unreachable" : ""));
|
||||||
if (name === "action-error") {
|
if (name === "action-error") {
|
||||||
root.entityErrors = {
|
root.entityErrors = {
|
||||||
"light.fixture_kitchen": "request-failed"
|
"light.fixture_kitchen": "request-failed"
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ ShellRoot {
|
|||||||
IntelligenceResult {}
|
IntelligenceResult {}
|
||||||
ActivityPanel {}
|
ActivityPanel {}
|
||||||
PowerMenu {}
|
PowerMenu {}
|
||||||
SettingsWindow {}
|
SettingsWindow { id: settingsWindow }
|
||||||
|
|
||||||
// Toasts are their own always-on layer; they must be able to appear
|
// Toasts are their own always-on layer; they must be able to appear
|
||||||
// without any overlay being open.
|
// without any overlay being open.
|
||||||
@@ -295,7 +295,8 @@ ShellRoot {
|
|||||||
open: ShellState.settingsOpen,
|
open: ShellState.settingsOpen,
|
||||||
page: ShellState.settingsPage,
|
page: ShellState.settingsPage,
|
||||||
discoveredCount: HomeAssistant.discoveredCount,
|
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 'HomePreferences.retrySave' "$home_page"
|
||||||
assert_contains 'Choose lights below to build your Control Center shelf.' "$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 '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 'No lights match that search' "$home_page"
|
||||||
assert_contains 'Opens BlueBubbles' "$home_page"
|
assert_contains 'Opens BlueBubbles' "$home_page"
|
||||||
[[ "$(rg -Fc 'required property var modelData' "$home_page")" -ge 2 ]] \
|
[[ "$(rg -Fc 'required property var modelData' "$home_page")" -ge 2 ]] \
|
||||||
@@ -173,9 +174,100 @@ for _ in $(seq 1 40); do
|
|||||||
fi
|
fi
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
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"
|
<<<"$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 .)"
|
system_status="$(qs_for_test ipc call settings-system status | jq -c .)"
|
||||||
jq -e '.bluebubblesAvailable == true' <<<"$system_status" >/dev/null \
|
jq -e '.bluebubblesAvailable == true' <<<"$system_status" >/dev/null \
|
||||||
|| fail "BlueBubbles availability was not exposed: $system_status"
|
|| fail "BlueBubbles availability was not exposed: $system_status"
|
||||||
|
|||||||
Reference in New Issue
Block a user