diff --git a/src/components/displays/pagination/PaginationOtherFiltersDropdown.vue b/src/components/displays/pagination/PaginationOtherFiltersDropdown.vue
index c90d1726..18230cfc 100644
--- a/src/components/displays/pagination/PaginationOtherFiltersDropdown.vue
+++ b/src/components/displays/pagination/PaginationOtherFiltersDropdown.vue
@@ -134,7 +134,7 @@ onBeforeUnmount(() => {
padding: 0 0.3rem;
pointer-events: none;
position: absolute;
- right: -0.35rem;
+ right: -0.55rem;
top: -0.25rem;
z-index: 1;
}
diff --git a/src/components/displays/pagination/models/SuperUserDashboard/SubusersPagination.vue b/src/components/displays/pagination/models/SuperUserDashboard/SubusersPagination.vue
index ec185e23..d3375b8a 100644
--- a/src/components/displays/pagination/models/SuperUserDashboard/SubusersPagination.vue
+++ b/src/components/displays/pagination/models/SuperUserDashboard/SubusersPagination.vue
@@ -27,6 +27,7 @@ const props = defineProps({
default: null,
},
});
+const emit = defineEmits(["mutated"]);
const paginatedList = usePaginatedList();
provide(PaginatedListKey, paginatedList);
@@ -52,6 +53,10 @@ if (props.hideSearch) {
if (props.autoLoad) {
loadList();
}
+
+const onTableMutated = () => {
+ emit("mutated");
+};
@@ -64,6 +69,7 @@ if (props.autoLoad) {
:objects="list"
:show-customer="showCustomer"
:user-scoped-user-id="userScopedUserId"
+ @mutated="onTableMutated"
/>
diff --git a/src/components/displays/superuser/tables/SubusersTable.vue b/src/components/displays/superuser/tables/SubusersTable.vue
index 772774d4..16d3affd 100644
--- a/src/components/displays/superuser/tables/SubusersTable.vue
+++ b/src/components/displays/superuser/tables/SubusersTable.vue
@@ -1,5 +1,6 @@
-
+
-
+
diff --git a/src/i18n/generated/da-v2.json b/src/i18n/generated/da-v2.json
index 5e1e8601..7e504deb 100644
--- a/src/i18n/generated/da-v2.json
+++ b/src/i18n/generated/da-v2.json
@@ -4679,6 +4679,7 @@
},
"pagination": {
"archive": "Arkiv",
+ "clear_all": "Ryd alle",
"ascending": "Stigende (Ældste @:{'words.generated.først'})",
"booking_status": "Bogføringsstatus",
"bookings_overview": "@:{'templates.generated.compat.objects.bookings.description'}",
diff --git a/src/i18n/generated/no-v2.json b/src/i18n/generated/no-v2.json
index 6757c021..c525172e 100644
--- a/src/i18n/generated/no-v2.json
+++ b/src/i18n/generated/no-v2.json
@@ -4793,6 +4793,7 @@
},
"pagination": {
"archive": "Arkiv",
+ "clear_all": "Tøm alle",
"ascending": "Stigende (eldst @:{'words.generated.først'})",
"booking_status": "Bestillingsstatus",
"bookings_overview": "Bestillingsoversikt",
diff --git a/src/i18n/source/da/phrases/compat/pagination/index.json b/src/i18n/source/da/phrases/compat/pagination/index.json
index 502ed00a..08aaf845 100644
--- a/src/i18n/source/da/phrases/compat/pagination/index.json
+++ b/src/i18n/source/da/phrases/compat/pagination/index.json
@@ -2,6 +2,7 @@
"compat": {
"pagination": {
"archive": "Arkiv",
+ "clear_all": "Ryd alle",
"ascending": "Stigende (Ældste @:{'terms.glossary.først'})",
"booking_status": "Bogføringsstatus",
"bookings_overview": "@:{'phrases.compat.objects.bookings.description'}",
diff --git a/src/i18n/source/no/phrases/compat/pagination/index.json b/src/i18n/source/no/phrases/compat/pagination/index.json
index a7718c28..eddb18c7 100644
--- a/src/i18n/source/no/phrases/compat/pagination/index.json
+++ b/src/i18n/source/no/phrases/compat/pagination/index.json
@@ -2,6 +2,7 @@
"compat": {
"pagination": {
"archive": "Arkiv",
+ "clear_all": "Tøm alle",
"ascending": "Stigende (eldst @:{'terms.glossary.først'})",
"booking_status": "Bestillingsstatus",
"bookings_overview": "Bestillingsoversikt",
diff --git a/src/views/dashboards/superUserDashboard/user/UserSubusers.vue b/src/views/dashboards/superUserDashboard/user/UserSubusers.vue
index 58dda9ea..4a9592a0 100644
--- a/src/views/dashboards/superUserDashboard/user/UserSubusers.vue
+++ b/src/views/dashboards/superUserDashboard/user/UserSubusers.vue
@@ -171,6 +171,7 @@ watch(
:endpoint="endpoint"
:user-scoped-user-id="routeUserId"
auto-load="true"
+ @mutated="loadSummary"
/>
diff --git a/tests/e2e/subuser-management.spec.ts b/tests/e2e/subuser-management.spec.ts
index 712b3e28..7b1abcad 100644
--- a/tests/e2e/subuser-management.spec.ts
+++ b/tests/e2e/subuser-management.spec.ts
@@ -886,8 +886,10 @@ test("customer user with own-subuser permissions can invite and manage grant acc
await page.getByTestId("subuser-dognvask-tooltip-3").hover();
await expect(page.locator(".tooltip-content:visible")).toContainText("Kundeadgangen er deaktiveret");
await page.mouse.move(0, 0);
- await page.getByTestId("subuser-remove-2").hover();
- await expect(page.locator(".tooltip-content", { hasText: "Deaktiverer chaufførens kundeadgang" })).toBeVisible();
+ await page.locator(".b-tooltip", { has: page.getByTestId("subuser-remove-2") }).hover();
+ await expect(
+ page.locator(".tooltip-content:visible", { hasText: "Deaktiverer chaufførens kundeadgang" }).first()
+ ).toContainText("Deaktiverer chaufførens kundeadgang");
await page.getByRole("button", { name: /Invit.*chauff/i }).click();
await page.fill("#subuser-form-name", "Invited Driver");
@@ -901,16 +903,17 @@ test("customer user with own-subuser permissions can invite and manage grant acc
await expect(page.getByTestId("subuser-phone-100")).toHaveText("+45 44444444");
await expect(page.getByTestId("subuser-plate-100")).toHaveText("-");
- await page.getByTestId("subuser-plate-edit-100").click();
- await page.selectOption("#subuser-assigned-vehicle", "104");
- await page.getByRole("button", { name: "Gem" }).click();
- await expect(page.getByTestId("subuser-plate-100")).toHaveText("NY44444");
-
let actions = await openSubuserActions(page, 100);
await expect(actions.getByTestId("subuser-section-account-100")).toHaveCount(0);
await expect(actions.getByTestId("subuser-section-vehicle-100")).toBeVisible();
await expect(actions.getByTestId("subuser-section-grant-100")).toBeVisible();
await expect(actions.getByTestId("subuser-section-details-100")).toBeVisible();
+ await actions.getByTestId("subuser-assign-vehicle-100").click();
+ await page.selectOption("#subuser-assigned-vehicle", "104");
+ await page.getByRole("button", { name: "Gem" }).click();
+ await expect(page.getByTestId("subuser-plate-100")).toHaveText("NY44444");
+
+ actions = await openSubuserActions(page, 100);
await actions.getByTestId("subuser-permissions-100").click();
await expect(page.getByText("Adgangsprofil for Invited Driver")).toBeVisible();
await expect(page.getByTestId("permission-template-driver")).toBeVisible();
@@ -985,14 +988,19 @@ test("superusers can list and invite chauffeurs across customers", async ({ page
await expect(actions.getByTestId("subuser-section-details-51-510")).toBeVisible();
await expect(actions).toContainText("12345678 - Nordic Transport");
await expect(actions.getByTestId("subuser-resend-51-510")).toBeVisible();
+ await expect(page.getByTestId("subuser-name-edit-51-510")).toHaveCount(0);
+ await expect(page.getByTestId("subuser-phone-edit-51-510")).toHaveCount(0);
+ await expect(page.getByTestId("subuser-plate-edit-51-510")).toHaveCount(0);
+ await expect(page.getByTestId("subuser-dognvask-51-511")).toBeVisible();
- await page.getByTestId("subuser-name-edit-51-510").click();
+ await actions.getByTestId("subuser-edit-name-51-510").click();
await page.fill(".swal2-input", "Renamed Super Driver");
await page.getByRole("button", { name: "Gem" }).click();
await expect(page.getByTestId("subuser-name-51-510")).toContainText("Renamed Super Driver");
expect(profilePayloads).toContainEqual({ id: 51, payload: { name: "Renamed Super Driver" } });
- await page.getByTestId("subuser-phone-edit-51-510").click();
+ actions = await openSubuserActions(page, "51-510");
+ await actions.getByTestId("subuser-edit-contact-51-510").click();
await page.fill("#subuser-admin-email", "renamed@example.com");
await page.fill("#subuser-admin-phone-country-code", "46");
await page.fill("#subuser-admin-phone", "12312312");
@@ -1007,7 +1015,8 @@ test("superusers can list and invite chauffeurs across customers", async ({ page
},
});
- await page.getByTestId("subuser-plate-edit-51-510").click();
+ actions = await openSubuserActions(page, "51-510");
+ await actions.getByTestId("subuser-assign-vehicle-51-510").click();
await page.selectOption("#subuser-assigned-vehicle", "5102");
await page.getByRole("button", { name: "Gem" }).click();
await expect(page.getByTestId("subuser-plate-51-510")).toHaveText("NT24680");
diff --git a/tests/e2e/superuser-orders-date-filters.spec.ts b/tests/e2e/superuser-orders-date-filters.spec.ts
index 832627f8..b294df51 100644
--- a/tests/e2e/superuser-orders-date-filters.spec.ts
+++ b/tests/e2e/superuser-orders-date-filters.spec.ts
@@ -88,6 +88,7 @@ test.describe("superuser order date filters", () => {
await expect(otherFiltersButton).toBeVisible();
await expect(otherFiltersButton).not.toHaveClass(/is-small/);
const otherFiltersCount = page.getByTestId("invoice-orders-other-filters-count");
+ const clearOtherFiltersButton = page.getByTestId("invoice-orders-other-filters-clear");
await expect(otherFiltersCount).toHaveText("3");
await expect(anytimeDateShortcut).toBeVisible();
await expect(todayDateShortcut).toBeVisible();
@@ -107,8 +108,8 @@ test.describe("superuser order date filters", () => {
const shortcutCenterY = shortcutBox.y + shortcutBox.height / 2;
const otherToAnytimeGap = shortcutBox.x - (buttonBox.x + buttonBox.width);
const dateShortcutGap = todayShortcutBox.x - (shortcutBox.x + shortcutBox.width);
- const doesCountProtrudeFromTopRight =
- countBox.y < buttonBox.y && countBox.x + countBox.width > buttonBox.x + buttonBox.width;
+ const countRightProtrusion = countBox.x + countBox.width - (buttonBox.x + buttonBox.width);
+ const doesCountProtrudeFromTopRight = countBox.y < buttonBox.y && countRightProtrusion >= 8;
const hasCountTopClearance = countBox.y >= shortcutActionsBox.y + 2;
return (
@@ -120,35 +121,29 @@ test.describe("superuser order date filters", () => {
);
})
.toBe(true);
- await expect(otherFiltersMenu).toBeHidden();
-
- await otherFiltersButton.click();
- await expect(otherFiltersMenu).toBeVisible();
- for (const label of [
- "Rækkefølge",
- "Bogføringsstatus",
- "Betalingsprocessor",
- "Fuldført",
- "Faktura valg",
- "Specialaftale",
- "Vaskeabonnement",
- ]) {
- await expect(otherFiltersLabel(label)).toBeVisible();
+ const verifiedButtonBox = await otherFiltersButton.boundingBox();
+ const verifiedCountBox = await otherFiltersCount.boundingBox();
+ const verifiedShortcutBox = await anytimeDateShortcut.boundingBox();
+ if (!verifiedButtonBox || !verifiedCountBox || !verifiedShortcutBox) {
+ throw new Error("Unable to capture verified other filters badge screenshot");
}
-
- await page.getByTestId("invoice-orders-other-filter-processor").selectOption("2");
- await expect(otherFiltersCount).toHaveText("4");
- await expect.poll(() => orderRequests.some((request) => request.filters.includes("processor:2"))).toBeTruthy();
-
- await page.keyboard.press("Escape");
+ const verifiedTop = Math.min(verifiedButtonBox.y, verifiedCountBox.y);
+ const verifiedBottom = Math.max(
+ verifiedButtonBox.y + verifiedButtonBox.height,
+ verifiedCountBox.y + verifiedCountBox.height,
+ verifiedShortcutBox.y + verifiedShortcutBox.height
+ );
+ await page.screenshot({
+ path: "output/playwright/manual/invoice-orders-other-filters-badge-right-protrusion.png",
+ clip: {
+ x: Math.max(0, verifiedButtonBox.x - 28),
+ y: Math.max(0, verifiedTop - 24),
+ width: Math.ceil(verifiedShortcutBox.x + verifiedShortcutBox.width - verifiedButtonBox.x + 56),
+ height: Math.ceil(verifiedBottom - verifiedTop + 48),
+ },
+ });
await expect(otherFiltersMenu).toBeHidden();
- await expect
- .poll(() =>
- orderRequests.some((request) => request.limit === 1000 && !request.filters.includes("created_at-date_"))
- )
- .toBeTruthy();
-
const fromField = page.getByTestId("invoice-orders-date-from");
const fromInput = fromField.locator("input").first();
const toInput = page.getByTestId("invoice-orders-date-to").locator("input").first();
@@ -177,6 +172,80 @@ test.describe("superuser order date filters", () => {
.poll(() => orderRequests.some((request) => request.filters.includes("created_at-date_from:2026-07-02")))
.toBeTruthy();
+ await otherFiltersButton.click();
+ await expect(otherFiltersMenu).toBeVisible();
+ for (const label of [
+ "Rækkefølge",
+ "Bogføringsstatus",
+ "Betalingsprocessor",
+ "Fuldført",
+ "Faktura valg",
+ "Specialaftale",
+ "Vaskeabonnement",
+ ]) {
+ await expect(otherFiltersLabel(label)).toBeVisible();
+ }
+ await expect(clearOtherFiltersButton).toBeVisible();
+ await expect(clearOtherFiltersButton).toHaveText("Ryd alle");
+ await expect
+ .poll(async () => {
+ const menuBox = await otherFiltersMenu.boundingBox();
+ const clearBox = await clearOtherFiltersButton.boundingBox();
+ const lastSelectBox = await page.getByTestId("invoice-orders-other-filter-wash-subscription").boundingBox();
+
+ if (!menuBox || !clearBox || !lastSelectBox) {
+ return false;
+ }
+
+ return (
+ clearBox.y > lastSelectBox.y + lastSelectBox.height &&
+ clearBox.y + clearBox.height <= menuBox.y + menuBox.height
+ );
+ })
+ .toBe(true);
+
+ await page.getByTestId("invoice-orders-other-filter-processor").selectOption("2");
+ await expect(otherFiltersCount).toHaveText("4");
+ await expect.poll(() => orderRequests.some((request) => request.filters.includes("processor:2"))).toBeTruthy();
+
+ const requestCountBeforeClear = orderRequests.length;
+ await clearOtherFiltersButton.click();
+
+ await expect.poll(() => orderRequests.length > requestCountBeforeClear).toBeTruthy();
+ await expect(page.getByTestId("invoice-orders-other-filters-count")).toHaveCount(0);
+ await expect(page.getByTestId("invoice-orders-other-filter-order-direction")).toHaveValue("desc");
+ for (const filterTestId of [
+ "invoice-orders-other-filter-booked-invoice-id",
+ "invoice-orders-other-filter-processor",
+ "invoice-orders-other-filter-completed-at",
+ "invoice-orders-other-filter-invoice-selection",
+ "invoice-orders-other-filter-special-agreement",
+ "invoice-orders-other-filter-wash-subscription",
+ ]) {
+ await expect(page.getByTestId(filterTestId)).toHaveValue("*");
+ }
+ await expect(fromInput).toHaveValue("02.07.2026");
+ await expect(toInput).toHaveValue("");
+ await expect
+ .poll(() => {
+ const latestTableRequest = [...orderRequests].reverse().find((request) => request.limit !== 1000);
+
+ return Boolean(
+ latestTableRequest?.filters.includes("created_at-date_from:2026-07-02") &&
+ !latestTableRequest.filters.includes("processor:2")
+ );
+ })
+ .toBeTruthy();
+
+ await page.keyboard.press("Escape");
+ await expect(otherFiltersMenu).toBeHidden();
+
+ await expect
+ .poll(() =>
+ orderRequests.some((request) => request.limit === 1000 && !request.filters.includes("created_at-date_"))
+ )
+ .toBeTruthy();
+
await fromField.locator(".icon.is-right").click();
await expect(fromInput).toHaveValue("");
diff --git a/tests/e2e/superuser-security.spec.ts b/tests/e2e/superuser-security.spec.ts
index e2fb59bb..d0a518d3 100644
--- a/tests/e2e/superuser-security.spec.ts
+++ b/tests/e2e/superuser-security.spec.ts
@@ -210,6 +210,9 @@ test.describe("Superuser system security", () => {
await page.goto("/superuser/system/security/overview");
await expect(page.getByTestId("superuser-security-page")).toBeVisible();
+ const desktopNavigation = page.getByTestId("desktop-buefy-navigation");
+ await expect(desktopNavigation.getByText("System", { exact: true })).toBeVisible();
+ await expect(desktopNavigation.getByText("Security", { exact: true })).toBeVisible();
await expect(page.getByText("Security overview")).toBeVisible();
await expect(page.getByRole("link", { name: "Open incidents" })).toBeVisible();
await expect(page.getByText("Block firewall rule matched: ip 203.0.113.9")).toBeVisible();
diff --git a/tests/unit/date-period-selector.spec.js b/tests/unit/date-period-selector.spec.js
index 2b2e7afd..89fe4ac6 100644
--- a/tests/unit/date-period-selector.spec.js
+++ b/tests/unit/date-period-selector.spec.js
@@ -433,6 +433,7 @@ describe("DatePeriodSelector month warning", () => {
showUpdateButton: false,
showStartDate: false,
showEndDate: false,
+ showToLabel: false,
showSelectionValidity: false,
showMonthSelector: false,
showYearSelector: false,
@@ -450,6 +451,8 @@ describe("DatePeriodSelector month warning", () => {
expect(anytimeButton.classes()).toContain("is-info");
expect(todayButton.classes()).not.toContain("is-info");
+ expect(wrapper.find(".level").exists()).toBe(false);
+ expect(wrapper.get("[data-testid='date-period-shortcut-anytime']").exists()).toBe(true);
});
it("hides empty range controls unless the selector is optional", () => {
diff --git a/tests/unit/navigation-menu-items-admin-contract.spec.js b/tests/unit/navigation-menu-items-admin-contract.spec.js
index 39992a18..4d61c272 100644
--- a/tests/unit/navigation-menu-items-admin-contract.spec.js
+++ b/tests/unit/navigation-menu-items-admin-contract.spec.js
@@ -67,7 +67,7 @@ describe("NavigationMenuItemsAdmin contract", () => {
expect(superuserSource).not.toContain('to: "/superuser/system/replication"');
expect(superuserLeftMenuSource).toContain('t("security.nav", "Security")');
- expect(superuserLeftMenuSource).toContain("value: '/system/security/overview'");
+ expect(superuserLeftMenuSource).toContain('value: "/system/security/overview"');
expect(superuserLeftMenuSource).toContain('t("cron.system_nav", "System")');
});
});