Tweaks (#24484)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s

* fix long press on mobile in face and classification

the listener was on the image only, so long pressing on any overlaid div/text area would cause iOS to select the text instead of adding the blue outline

* improve navigation to and from explore

when viewing a tracked object in explore from a classification card, triggers, or the detail stream, explore would open and show a single tracked object. on mobile (noted especially on iOS with frigate in HA), there is no obvious way to navigate back, so add a back button in its usual spot.

also, when going back to the classification view from explore, it may not be obvious which thumbnail you were last viewing, so add a temporary blue outline around the card like review and explore already does

* test tweaks
This commit is contained in:
Josh Hawkins
2026-09-27 07:45:32 -06:00
committed by GitHub
parent 3941355051
commit 4e196516dd
8 changed files with 196 additions and 66 deletions
+70 -31
View File
@@ -30,40 +30,51 @@ function groupedFacesMock() {
});
}
async function installGroupedFaces(app: FrigateApp) {
const GROUPED_EVENT = {
id: GROUPED_EVENT_ID,
label: "person",
sub_label: null,
camera: "front_door",
start_time: 1775487131.3863528,
end_time: 1775487161.3863528,
false_positive: false,
zones: ["front_yard"],
thumbnail: null,
has_clip: true,
has_snapshot: true,
retain_indefinitely: false,
plus_id: null,
model_hash: "abc123",
detector_type: "cpu",
model_type: "ssd",
data: {
top_score: 0.92,
score: 0.92,
region: [0.1, 0.1, 0.5, 0.8],
box: [0.2, 0.15, 0.45, 0.75],
area: 0.18,
ratio: 0.6,
type: "object",
path_data: [],
},
};
async function installGroupedFaces(
app: FrigateApp,
opts: { withEventIds?: boolean } = {},
) {
await app.api.install({
events: [
{
id: GROUPED_EVENT_ID,
label: "person",
sub_label: null,
camera: "front_door",
start_time: 1775487131.3863528,
end_time: 1775487161.3863528,
false_positive: false,
zones: ["front_yard"],
thumbnail: null,
has_clip: true,
has_snapshot: true,
retain_indefinitely: false,
plus_id: null,
model_hash: "abc123",
detector_type: "cpu",
model_type: "ssd",
data: {
top_score: 0.92,
score: 0.92,
region: [0.1, 0.1, 0.5, 0.8],
box: [0.2, 0.15, 0.45, 0.75],
area: 0.18,
ratio: 0.6,
type: "object",
path_data: [],
},
},
],
events: [GROUPED_EVENT],
faces: groupedFacesMock(),
});
// api-mocker does not cover /api/event_ids, which the card needs to link to
// Explore. Registered after install so it takes precedence.
if (opts.withEventIds) {
await app.page.route("**/api/event_ids**", (route) =>
route.fulfill({ json: [GROUPED_EVENT] }),
);
}
}
async function openGroupedFaceDialog(app: FrigateApp): Promise<Locator> {
@@ -512,6 +523,34 @@ test.describe("FaceSelectionDialog @high", () => {
});
});
test.describe("Face Library: return from Explore @high", () => {
test("Explore back button returns to an outlined collection", async ({
frigateApp,
}) => {
await installGroupedFaces(frigateApp, { withEventIds: true });
await frigateApp.goto("/faces");
// Mobile opens the collection as a MobilePage, which has no dialog role
const card = frigateApp.page
.locator('img[src*="clips/faces/train/"]')
.first()
.locator("xpath=..");
await card.click();
await frigateApp.page.getByLabel("View in Explore").click();
await expect(frigateApp.page).toHaveURL(
new RegExp(`/explore\\?event_id=${GROUPED_EVENT_ID}`),
);
const back = frigateApp.page.getByRole("button", { name: "Go back" });
await expect(back).toBeVisible({ timeout: 5_000 });
await back.click();
await expect(frigateApp.page).toHaveURL(/\/faces/);
await expect(card).toHaveClass(/outline-selected/, { timeout: 5_000 });
await expect(card).not.toHaveClass(/outline-selected/, { timeout: 5_000 });
});
});
test.describe("Face Library — mobile @high @mobile", () => {
test.skip(({ frigateApp }) => !frigateApp.isMobile, "Mobile-only");