diff --git a/frontend/playwright/data/dashboard/check-nitrate-sso-authorized.json b/frontend/playwright/data/dashboard/check-nitrate-sso-authorized.json new file mode 100644 index 0000000000..0d710478b5 --- /dev/null +++ b/frontend/playwright/data/dashboard/check-nitrate-sso-authorized.json @@ -0,0 +1 @@ +{ "~:authorized": true } diff --git a/frontend/playwright/data/dashboard/get-environment-data-empty.json b/frontend/playwright/data/dashboard/get-environment-data-empty.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/frontend/playwright/data/dashboard/get-environment-data-empty.json @@ -0,0 +1 @@ +{} diff --git a/frontend/playwright/data/dashboard/get-teams-organization.json b/frontend/playwright/data/dashboard/get-teams-organization.json new file mode 100644 index 0000000000..4219dfa4d4 --- /dev/null +++ b/frontend/playwright/data/dashboard/get-teams-organization.json @@ -0,0 +1,78 @@ +[ + { + "~:features": { + "~#set": [ + "layout/grid", + "styles/v2", + "fdata/pointer-map", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true + }, + "~:name": "Default", + "~:modified-at": "~m1713533116375", + "~:id": "~uc7ce0794-0992-8105-8004-38e630f40f6d", + "~:created-at": "~m1713533116375", + "~:is-default": true + }, + { + "~:features": { + "~#set": [ + "layout/grid", + "styles/v2", + "fdata/pointer-map", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true + }, + "~:name": "Second team", + "~:modified-at": "~m1701164272671", + "~:id": "~udd33ff88-f4e5-8033-8003-8096cc07bdf3", + "~:created-at": "~m1701164272671", + "~:is-default": false + }, + { + "~:features": { + "~#set": [ + "layout/grid", + "styles/v2", + "fdata/pointer-map", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true + }, + "~:name": "Acme default", + "~:modified-at": "~m1713533116375", + "~:id": "~u11111111-1111-1111-1111-111111111111", + "~:created-at": "~m1713533116375", + "~:is-default": true, + "~:organization": { + "~:id": "~u22222222-2222-2222-2222-222222222222", + "~:name": "Acme", + "~:owner-id": "~u33333333-3333-3333-3333-333333333333", + "~:permissions": { "~:create-teams": "any" } + }, + "~:organization-id": "~u22222222-2222-2222-2222-222222222222" + } +] diff --git a/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js b/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js index e53180e4dc..94985dfeee 100644 --- a/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js +++ b/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js @@ -1064,3 +1064,42 @@ test.describe("Download report", () => { await expect(page.getByText("Send", { exact: true })).toBeVisible(); }); }); + +test.describe("Team settings organization", () => { + test("Shows the Add to an organization link", async ({ page }) => { + const shot = { maxDiffPixelRatio: 0, threshold: 0 }; + // Organizations need the admin console flag, a team the user owns that + // is in no organization, and an organization the user belongs to. + await DashboardPage.mockConfigFlags(page, [ + "disable-onboarding", + "enable-admin-console", + ]); + const dashboardPage = new DashboardPage(page); + await dashboardPage.setupDashboardFull(); + await dashboardPage.mockRPC( + "get-teams", + "dashboard/get-teams-organization.json", + ); + await dashboardPage.mockRPC( + /check-nitrate-sso/, + "dashboard/check-nitrate-sso-authorized.json", + ); + await dashboardPage.mockRPC( + /get-environment-data/, + "dashboard/get-environment-data-empty.json", + ); + await dashboardPage.mockRPC( + "get-team-stats?team-id=*", + "dashboard/get-team-stats.json", + ); + await dashboardPage.goToSecondTeamSettingsSection(); + + const add = page.getByText("Add to an organization", { exact: true }); + await expect(add).toBeVisible(); + await page.mouse.move(10, 700); + await expect(add).toHaveScreenshot(shot); + + await add.hover(); + await expect(add).toHaveScreenshot(shot); + }); +}); diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 5629337572..081b204af2 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -1721,7 +1721,10 @@ (when can-add-to-organization? [:div {:class (stl/css :block-content)} [:span {:class (stl/css :block-text)} - [:a {:on-click on-add-team-to-organization} (tr "dashboard.team-organization.add")]]])]))]) + [:button {:type "button" + :class (stl/css :add-to-organization) + :on-click on-add-team-to-organization} + (tr "dashboard.team-organization.add")]]])]))]) [:div {:class (stl/css :block)} [:div {:class (stl/css :block-label)} diff --git a/frontend/src/app/main/ui/dashboard/team.scss b/frontend/src/app/main/ui/dashboard/team.scss index 4966b8ab87..f878618f8e 100644 --- a/frontend/src/app/main/ui/dashboard/team.scss +++ b/frontend/src/app/main/ui/dashboard/team.scss @@ -56,6 +56,26 @@ text-wrap: nowrap; } +// Opens the add to organization modal, so it is a button that keeps the +// look of a text link. +.add-to-organization { + font: inherit; + font-weight: 500; + + // A button is a block in its line: the normal line height keeps the box of + // the inline link it replaces. + line-height: normal; + color: var(--color-accent-primary); + background: none; + border: none; + padding: 0; + cursor: pointer; + + &:hover { + text-decoration: underline; + } +} + .block-content { display: grid; grid-template-columns: var(--sp-xxxl) 1fr;