test: cover core flows across browser engines
This commit is contained in:
parent
692f7c9baa
commit
5b723831af
|
|
@ -17,20 +17,46 @@ export const Hooks = {
|
||||||
AidMap: {
|
AidMap: {
|
||||||
mounted() {
|
mounted() {
|
||||||
this.markers = []
|
this.markers = []
|
||||||
this.map = new maplibregl.Map({
|
|
||||||
container: this.el,
|
|
||||||
style: defaultStyle,
|
|
||||||
center: [30.5234, 50.4501],
|
|
||||||
zoom: 5
|
|
||||||
})
|
|
||||||
this.map.addControl(new maplibregl.NavigationControl(), "top-right")
|
|
||||||
this.markLoading = () => {
|
this.markLoading = () => {
|
||||||
this.el.dataset.mapReady = "false"
|
if (this.el.dataset.mapReady !== "true") {
|
||||||
|
this.el.dataset.mapReady = "false"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.markReady = () => {
|
this.markReady = () => {
|
||||||
this.el.dataset.mapReady = "true"
|
this.el.dataset.mapReady = "true"
|
||||||
}
|
}
|
||||||
|
this.showUnavailable = () => {
|
||||||
|
this.map = null
|
||||||
|
this.el.dataset.mapUnavailable = "true"
|
||||||
|
this.markReady()
|
||||||
|
|
||||||
|
const fallback = document.createElement("p")
|
||||||
|
fallback.className = "grid h-full place-items-center p-6 text-center text-sm"
|
||||||
|
fallback.dataset.mapFallback = "true"
|
||||||
|
fallback.textContent = this.el.dataset.mapUnavailableLabel
|
||||||
|
this.el.replaceChildren(fallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supportsMapCanvas()) {
|
||||||
|
this.showUnavailable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.map = new maplibregl.Map({
|
||||||
|
container: this.el,
|
||||||
|
style: defaultStyle,
|
||||||
|
center: [30.5234, 50.4501],
|
||||||
|
zoom: 5
|
||||||
|
})
|
||||||
|
} catch (_error) {
|
||||||
|
this.showUnavailable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map.addControl(new maplibregl.NavigationControl(), "top-right")
|
||||||
this.map.on("dataloading", this.markLoading)
|
this.map.on("dataloading", this.markLoading)
|
||||||
|
this.map.on("load", this.markReady)
|
||||||
this.map.on("idle", this.markReady)
|
this.map.on("idle", this.markReady)
|
||||||
this.renderMarkers()
|
this.renderMarkers()
|
||||||
},
|
},
|
||||||
|
|
@ -39,6 +65,7 @@ export const Hooks = {
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.map?.off("dataloading", this.markLoading)
|
this.map?.off("dataloading", this.markLoading)
|
||||||
|
this.map?.off("load", this.markReady)
|
||||||
this.map?.off("idle", this.markReady)
|
this.map?.off("idle", this.markReady)
|
||||||
this.map?.remove()
|
this.map?.remove()
|
||||||
},
|
},
|
||||||
|
|
@ -129,3 +156,26 @@ function escapeHtml(value) {
|
||||||
node.textContent = value || ""
|
node.textContent = value || ""
|
||||||
return node.innerHTML
|
return node.innerHTML
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function supportsMapCanvas() {
|
||||||
|
const canvas = document.createElement("canvas")
|
||||||
|
const attributes = {
|
||||||
|
alpha: true,
|
||||||
|
depth: true,
|
||||||
|
stencil: true,
|
||||||
|
premultipliedAlpha: true
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const context =
|
||||||
|
canvas.getContext("webgl2", attributes) ||
|
||||||
|
canvas.getContext("webgl", attributes)
|
||||||
|
|
||||||
|
if (!context) return false
|
||||||
|
|
||||||
|
context.getExtension("WEBGL_lose_context")?.loseContext()
|
||||||
|
return true
|
||||||
|
} catch (_error) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ export default defineConfig({
|
||||||
],
|
],
|
||||||
use: {
|
use: {
|
||||||
baseURL,
|
baseURL,
|
||||||
...devices["Desktop Chrome"],
|
|
||||||
actionTimeout: 10_000,
|
actionTimeout: 10_000,
|
||||||
navigationTimeout: 20_000,
|
navigationTimeout: 20_000,
|
||||||
trace: "retain-on-failure",
|
trace: "retain-on-failure",
|
||||||
|
|
@ -35,7 +34,19 @@ export default defineConfig({
|
||||||
{
|
{
|
||||||
name: "chromium",
|
name: "chromium",
|
||||||
use: {
|
use: {
|
||||||
browserName: "chromium",
|
...devices["Desktop Chrome"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "firefox",
|
||||||
|
use: {
|
||||||
|
...devices["Desktop Firefox"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "webkit",
|
||||||
|
use: {
|
||||||
|
...devices["Desktop Safari"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ import { expect, test } from "@playwright/test";
|
||||||
import {
|
import {
|
||||||
captureBrowserFailures,
|
captureBrowserFailures,
|
||||||
loginWithMagicLink,
|
loginWithMagicLink,
|
||||||
|
projectEmail,
|
||||||
|
projectText,
|
||||||
registerAndConfirm,
|
registerAndConfirm,
|
||||||
selectOptionContaining,
|
selectOptionContaining,
|
||||||
waitForMapReady,
|
waitForMapReady,
|
||||||
|
|
@ -10,17 +12,30 @@ import {
|
||||||
test("activity approval, privacy controls, reporting, and moderation work end to end", async ({
|
test("activity approval, privacy controls, reporting, and moderation work end to end", async ({
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
}) => {
|
}, testInfo) => {
|
||||||
|
const projectName = testInfo.project.name;
|
||||||
|
const organizerEmail = projectEmail("activity-organizer", projectName);
|
||||||
|
const participantEmail = projectEmail("activity-participant", projectName);
|
||||||
|
const activityTitle = projectText("E2E public coffee meetup", projectName);
|
||||||
|
const organizerMessageText = projectText(
|
||||||
|
"Welcome to the E2E activity group.",
|
||||||
|
projectName,
|
||||||
|
);
|
||||||
|
const reportDescription = projectText(
|
||||||
|
"E2E moderation evidence for the selected activity message.",
|
||||||
|
projectName,
|
||||||
|
);
|
||||||
|
const proposalTitle = projectText("E2E quiet board games", projectName);
|
||||||
const organizer = await registerAndConfirm(
|
const organizer = await registerAndConfirm(
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
"activity-organizer@example.invalid",
|
organizerEmail,
|
||||||
"E2E Activity Organizer",
|
"E2E Activity Organizer",
|
||||||
);
|
);
|
||||||
const participant = await registerAndConfirm(
|
const participant = await registerAndConfirm(
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
"activity-participant@example.invalid",
|
participantEmail,
|
||||||
"E2E Activity Participant",
|
"E2E Activity Participant",
|
||||||
);
|
);
|
||||||
const assertOrganizerClean = captureBrowserFailures(organizer.page);
|
const assertOrganizerClean = captureBrowserFailures(organizer.page);
|
||||||
|
|
@ -33,7 +48,7 @@ test("activity approval, privacy controls, reporting, and moderation work end to
|
||||||
await organizer.page.goto("/activities/new");
|
await organizer.page.goto("/activities/new");
|
||||||
await selectOptionContaining(organizer.page, "Activity type", "Coffee or tea");
|
await selectOptionContaining(organizer.page, "Activity type", "Coffee or tea");
|
||||||
await organizer.page.getByLabel("Preferred setting").selectOption("cafe");
|
await organizer.page.getByLabel("Preferred setting").selectOption("cafe");
|
||||||
await organizer.page.getByLabel("Short title").fill("E2E public coffee meetup");
|
await organizer.page.getByLabel("Short title").fill(activityTitle);
|
||||||
await organizer.page
|
await organizer.page
|
||||||
.getByLabel("Plan and expectations")
|
.getByLabel("Plan and expectations")
|
||||||
.fill("Meet at a public café for an hour of safe conversation.");
|
.fill("Meet at a public café for an hour of safe conversation.");
|
||||||
|
|
@ -80,13 +95,13 @@ test("activity approval, privacy controls, reporting, and moderation work end to
|
||||||
|
|
||||||
await organizer.page
|
await organizer.page
|
||||||
.getByPlaceholder("Message the approved group")
|
.getByPlaceholder("Message the approved group")
|
||||||
.fill("Welcome to the E2E activity group.");
|
.fill(organizerMessageText);
|
||||||
await organizer.page.getByRole("button", { name: "Send", exact: true }).click();
|
await organizer.page.getByRole("button", { name: "Send", exact: true }).click();
|
||||||
await expect(participant.page.getByText("Welcome to the E2E activity group.")).toBeVisible();
|
await expect(participant.page.getByText(organizerMessageText)).toBeVisible();
|
||||||
|
|
||||||
const organizerMessage = participant.page
|
const organizerMessage = participant.page
|
||||||
.locator("#activity-messages article")
|
.locator("#activity-messages article")
|
||||||
.filter({ hasText: "Welcome to the E2E activity group." });
|
.filter({ hasText: organizerMessageText });
|
||||||
await organizerMessage.getByRole("button", { name: "Report" }).click();
|
await organizerMessage.getByRole("button", { name: "Report" }).click();
|
||||||
const safetyControls = participant.page
|
const safetyControls = participant.page
|
||||||
.getByRole("heading", { name: "Safety controls" })
|
.getByRole("heading", { name: "Safety controls" })
|
||||||
|
|
@ -97,13 +112,13 @@ test("activity approval, privacy controls, reporting, and moderation work end to
|
||||||
await safetyControls.getByLabel("Reason").selectOption("harassment");
|
await safetyControls.getByLabel("Reason").selectOption("harassment");
|
||||||
await safetyControls
|
await safetyControls
|
||||||
.getByLabel("What happened?")
|
.getByLabel("What happened?")
|
||||||
.fill("E2E moderation evidence for the selected activity message.");
|
.fill(reportDescription);
|
||||||
await safetyControls.getByRole("button", { name: "Send report" }).click();
|
await safetyControls.getByRole("button", { name: "Send report" }).click();
|
||||||
await expect(participant.page.getByText("Report sent to moderators.")).toBeVisible();
|
await expect(participant.page.getByText("Report sent to moderators.")).toBeVisible();
|
||||||
|
|
||||||
await waitForMapReady(participant.page);
|
await waitForMapReady(participant.page);
|
||||||
await participant.page.goto("/categories/proposals");
|
await participant.page.goto("/categories/proposals");
|
||||||
await participant.page.getByLabel("Proposed category").fill("E2E quiet board games");
|
await participant.page.getByLabel("Proposed category").fill(proposalTitle);
|
||||||
await participant.page.getByLabel("Mode").selectOption("activity");
|
await participant.page.getByLabel("Mode").selectOption("activity");
|
||||||
await participant.page
|
await participant.page
|
||||||
.getByLabel("Why is this useful?")
|
.getByLabel("Why is this useful?")
|
||||||
|
|
@ -157,12 +172,12 @@ test("activity approval, privacy controls, reporting, and moderation work end to
|
||||||
|
|
||||||
const reportCard = admin.page
|
const reportCard = admin.page
|
||||||
.locator("article")
|
.locator("article")
|
||||||
.filter({ hasText: "E2E moderation evidence for the selected activity message." });
|
.filter({ hasText: reportDescription });
|
||||||
await reportCard.getByRole("button", { name: "View scoped evidence" }).click();
|
await reportCard.getByRole("button", { name: "View scoped evidence" }).click();
|
||||||
const evidence = admin.page
|
const evidence = admin.page
|
||||||
.getByRole("heading", { name: "Reported evidence" })
|
.getByRole("heading", { name: "Reported evidence" })
|
||||||
.locator("xpath=ancestor::section");
|
.locator("xpath=ancestor::section");
|
||||||
await expect(evidence.getByText("Welcome to the E2E activity group.")).toBeVisible();
|
await expect(evidence.getByText(organizerMessageText)).toBeVisible();
|
||||||
await evidence.getByRole("button", { name: "Close" }).click();
|
await evidence.getByRole("button", { name: "Close" }).click();
|
||||||
await reportCard.getByRole("combobox").selectOption("resolved");
|
await reportCard.getByRole("combobox").selectOption("resolved");
|
||||||
await reportCard.getByPlaceholder("Resolution note").fill("Reviewed in isolated browser E2E.");
|
await reportCard.getByPlaceholder("Resolution note").fill("Reviewed in isolated browser E2E.");
|
||||||
|
|
@ -171,14 +186,14 @@ test("activity approval, privacy controls, reporting, and moderation work end to
|
||||||
|
|
||||||
const proposalCard = admin.page
|
const proposalCard = admin.page
|
||||||
.locator("article")
|
.locator("article")
|
||||||
.filter({ hasText: "E2E quiet board games" });
|
.filter({ hasText: proposalTitle });
|
||||||
await proposalCard.getByPlaceholder("Rejection note").fill("Covered by an existing category.");
|
await proposalCard.getByPlaceholder("Rejection note").fill("Covered by an existing category.");
|
||||||
await proposalCard.getByRole("button", { name: "Reject" }).click();
|
await proposalCard.getByRole("button", { name: "Reject" }).click();
|
||||||
await expect(admin.page.getByText("Proposal rejected.")).toBeVisible();
|
await expect(admin.page.getByText("Proposal rejected.")).toBeVisible();
|
||||||
|
|
||||||
const participantRow = admin.page
|
const participantRow = admin.page
|
||||||
.locator("tbody tr")
|
.locator("tbody tr")
|
||||||
.filter({ hasText: "activity-participant@example.invalid" });
|
.filter({ hasText: participantEmail });
|
||||||
await participantRow.getByRole("combobox").first().selectOption("restricted");
|
await participantRow.getByRole("combobox").first().selectOption("restricted");
|
||||||
await participantRow.getByPlaceholder("Internal note").fill("E2E restriction boundary.");
|
await participantRow.getByPlaceholder("Internal note").fill("E2E restriction boundary.");
|
||||||
await participantRow.getByRole("button", { name: "Save" }).click();
|
await participantRow.getByRole("button", { name: "Save" }).click();
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,15 @@ export type AuthenticatedBrowser = {
|
||||||
email: string;
|
email: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function projectEmail(localPart: string, projectName: string): string {
|
||||||
|
const scope = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
||||||
|
return `${localPart}+${scope}@example.invalid`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function projectText(value: string, projectName: string): string {
|
||||||
|
return `${value} [${projectName}]`;
|
||||||
|
}
|
||||||
|
|
||||||
export async function newIsolatedContext(browser: Browser): Promise<BrowserContext> {
|
export async function newIsolatedContext(browser: Browser): Promise<BrowserContext> {
|
||||||
return browser.newContext({ serviceWorkers: "block" });
|
return browser.newContext({ serviceWorkers: "block" });
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +36,22 @@ export async function waitForMapReady(page: Page): Promise<void> {
|
||||||
const map = page.locator(".aid-map");
|
const map = page.locator(".aid-map");
|
||||||
|
|
||||||
if ((await map.count()) > 0) {
|
if ((await map.count()) > 0) {
|
||||||
await expect(map).toHaveAttribute("data-map-ready", "true", { timeout: 15_000 });
|
await expect
|
||||||
|
.poll(
|
||||||
|
async () => {
|
||||||
|
if ((await map.getAttribute("data-map-ready")) === "true") {
|
||||||
|
return "map";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((await map.locator("[data-map-fallback=true]").count()) === 1) {
|
||||||
|
return "fallback";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
{ timeout: 15_000 },
|
||||||
|
)
|
||||||
|
.not.toBeNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,8 +69,19 @@ export function captureBrowserFailures(page: Page): () => void {
|
||||||
});
|
});
|
||||||
|
|
||||||
page.on("requestfailed", (request) => {
|
page.on("requestfailed", (request) => {
|
||||||
|
const failure = request.failure()?.errorText ?? "";
|
||||||
|
|
||||||
|
if (
|
||||||
|
request.url().includes("/__e2e__/map-tile.png") &&
|
||||||
|
(failure.includes("Load request cancelled") ||
|
||||||
|
failure.includes("ERR_ABORTED") ||
|
||||||
|
failure.includes("NS_BINDING_ABORTED"))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
failures.push(
|
failures.push(
|
||||||
`requestfailed: ${request.method()} ${request.url()} ${request.failure()?.errorText}`,
|
`requestfailed: ${request.method()} ${request.url()} ${failure}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
import { newIsolatedContext, registerAndConfirm } from "./helpers";
|
import { newIsolatedContext, projectEmail, registerAndConfirm } from "./helpers";
|
||||||
|
|
||||||
test("public language selection persists across pages", async ({ browser }) => {
|
test("public language selection persists across pages", async ({ browser }) => {
|
||||||
const context = await newIsolatedContext(browser);
|
const context = await newIsolatedContext(browser);
|
||||||
|
|
@ -19,11 +19,14 @@ test("public language selection persists across pages", async ({ browser }) => {
|
||||||
await context.close();
|
await context.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("authenticated LiveView uses the selected browser language", async ({ browser, request }) => {
|
test("authenticated LiveView uses the selected browser language", async ({
|
||||||
|
browser,
|
||||||
|
request,
|
||||||
|
}, testInfo) => {
|
||||||
const user = await registerAndConfirm(
|
const user = await registerAndConfirm(
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
"localization@example.invalid",
|
projectEmail("localization", testInfo.project.name),
|
||||||
"E2E Localization",
|
"E2E Localization",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
import {
|
import {
|
||||||
captureBrowserFailures,
|
captureBrowserFailures,
|
||||||
|
projectEmail,
|
||||||
|
projectText,
|
||||||
registerAndConfirm,
|
registerAndConfirm,
|
||||||
selectOptionContaining,
|
selectOptionContaining,
|
||||||
waitForMapReady,
|
waitForMapReady,
|
||||||
|
|
@ -9,17 +11,18 @@ import {
|
||||||
test("two users complete a medicine handover with realtime chat and blind reviews", async ({
|
test("two users complete a medicine handover with realtime chat and blind reviews", async ({
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
}) => {
|
}, testInfo) => {
|
||||||
|
const requestTitle = projectText("E2E medicine pickup", testInfo.project.name);
|
||||||
const requester = await registerAndConfirm(
|
const requester = await registerAndConfirm(
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
"requester@example.invalid",
|
projectEmail("requester", testInfo.project.name),
|
||||||
"E2E Requester",
|
"E2E Requester",
|
||||||
);
|
);
|
||||||
const helper = await registerAndConfirm(
|
const helper = await registerAndConfirm(
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
"helper@example.invalid",
|
projectEmail("helper", testInfo.project.name),
|
||||||
"E2E Helper",
|
"E2E Helper",
|
||||||
);
|
);
|
||||||
const assertRequesterClean = captureBrowserFailures(requester.page);
|
const assertRequesterClean = captureBrowserFailures(requester.page);
|
||||||
|
|
@ -28,7 +31,7 @@ test("two users complete a medicine handover with realtime chat and blind review
|
||||||
await requester.page.goto("/requests/new");
|
await requester.page.goto("/requests/new");
|
||||||
await selectOptionContaining(requester.page, "Category", "Medicine pickup");
|
await selectOptionContaining(requester.page, "Category", "Medicine pickup");
|
||||||
await requester.page.getByLabel("Medicine pickup status").selectOption("reserved");
|
await requester.page.getByLabel("Medicine pickup status").selectOption("reserved");
|
||||||
await requester.page.getByLabel("Short title").fill("E2E medicine pickup");
|
await requester.page.getByLabel("Short title").fill(requestTitle);
|
||||||
await requester.page
|
await requester.page
|
||||||
.getByLabel("What help do you need?")
|
.getByLabel("What help do you need?")
|
||||||
.fill("Please collect the legal medicine that is already reserved.");
|
.fill("Please collect the legal medicine that is already reserved.");
|
||||||
|
|
@ -45,7 +48,7 @@ test("two users complete a medicine handover with realtime chat and blind review
|
||||||
await requester.page.getByRole("button", { name: "Publish request" }).click();
|
await requester.page.getByRole("button", { name: "Publish request" }).click();
|
||||||
await expect(requester.page).toHaveURL(/\/requests\/[0-9a-f-]+$/);
|
await expect(requester.page).toHaveURL(/\/requests\/[0-9a-f-]+$/);
|
||||||
const requestURL = requester.page.url();
|
const requestURL = requester.page.url();
|
||||||
await expect(requester.page.getByRole("heading", { name: "E2E medicine pickup" })).toBeVisible();
|
await expect(requester.page.getByRole("heading", { name: requestTitle })).toBeVisible();
|
||||||
|
|
||||||
await helper.page.goto(requestURL);
|
await helper.page.goto(requestURL);
|
||||||
await helper.page.getByRole("button", { name: "I can help" }).click();
|
await helper.page.getByRole("button", { name: "I can help" }).click();
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
import { registerAndConfirm } from "./helpers";
|
import { projectEmail, registerAndConfirm } from "./helpers";
|
||||||
|
|
||||||
test("a disconnected LiveView announces recovery and clears it after reconnect", async ({
|
test("a disconnected LiveView announces recovery and clears it after reconnect", async ({
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
}) => {
|
}, testInfo) => {
|
||||||
const user = await registerAndConfirm(
|
const user = await registerAndConfirm(
|
||||||
browser,
|
browser,
|
||||||
request,
|
request,
|
||||||
"resilience@example.invalid",
|
projectEmail("resilience", testInfo.project.name),
|
||||||
"E2E Resilience",
|
"E2E Resilience",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ defmodule WhoNeedHelpWeb.Endpoint do
|
||||||
from: :who_need_help,
|
from: :who_need_help,
|
||||||
gzip: not code_reloading?,
|
gzip: not code_reloading?,
|
||||||
only: WhoNeedHelpWeb.static_paths(),
|
only: WhoNeedHelpWeb.static_paths(),
|
||||||
|
only_matching: ~w(favicon manifest robots sw),
|
||||||
raise_on_missing_only: code_reloading?
|
raise_on_missing_only: code_reloading?
|
||||||
|
|
||||||
# Code reloading can be explicitly enabled under the
|
# Code reloading can be explicitly enabled under the
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,9 @@ defmodule WhoNeedHelpWeb.ActivityLive.Index do
|
||||||
phx-hook="AidMap"
|
phx-hook="AidMap"
|
||||||
phx-update="ignore"
|
phx-update="ignore"
|
||||||
data-markers={@markers}
|
data-markers={@markers}
|
||||||
|
data-map-unavailable-label={
|
||||||
|
gettext("The map is unavailable in this browser. Request details remain usable.")
|
||||||
|
}
|
||||||
class="aid-map"
|
class="aid-map"
|
||||||
/>
|
/>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,9 @@ defmodule WhoNeedHelpWeb.ActivityLive.Show do
|
||||||
phx-hook="AidMap"
|
phx-hook="AidMap"
|
||||||
phx-update="ignore"
|
phx-update="ignore"
|
||||||
data-markers={@markers}
|
data-markers={@markers}
|
||||||
|
data-map-unavailable-label={
|
||||||
|
gettext("The map is unavailable in this browser. Request details remain usable.")
|
||||||
|
}
|
||||||
class="aid-map"
|
class="aid-map"
|
||||||
/>
|
/>
|
||||||
<div class="rounded-2xl bg-base-200 p-5 text-sm">
|
<div class="rounded-2xl bg-base-200 p-5 text-sm">
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,9 @@ defmodule WhoNeedHelpWeb.RequestLive.Index do
|
||||||
phx-hook="AidMap"
|
phx-hook="AidMap"
|
||||||
phx-update="ignore"
|
phx-update="ignore"
|
||||||
data-markers={@markers}
|
data-markers={@markers}
|
||||||
|
data-map-unavailable-label={
|
||||||
|
gettext("The map is unavailable in this browser. Request details remain usable.")
|
||||||
|
}
|
||||||
class="aid-map"
|
class="aid-map"
|
||||||
/>
|
/>
|
||||||
<div class="rounded-3xl bg-base-200 p-5">
|
<div class="rounded-3xl bg-base-200 p-5">
|
||||||
|
|
|
||||||
|
|
@ -734,6 +734,9 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
|
||||||
phx-hook="AidMap"
|
phx-hook="AidMap"
|
||||||
phx-update="ignore"
|
phx-update="ignore"
|
||||||
data-markers={@markers}
|
data-markers={@markers}
|
||||||
|
data-map-unavailable-label={
|
||||||
|
gettext("The map is unavailable in this browser. Request details remain usable.")
|
||||||
|
}
|
||||||
class="aid-map"
|
class="aid-map"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user