Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 51 additions & 34 deletions frontend/src/components/layout/app-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ import {
} from "@/types/localization";
import { ORG_NAME_MAX_LENGTH } from "@/types/org";
import { type UserOrg } from "@/types/user";
import { type ViewState } from "@/utils/APIRouter";
import { type RouteName, type ViewState } from "@/utils/APIRouter";
import { urlForName } from "@/utils/router";
import { AppStateService } from "@/utils/state";
import { tw } from "@/utils/tailwind";
import brandLockupColor from "~assets/brand/browsertrix-lockup-color.svg";

// TODO Validate against mkdocs paths
const mapToUserGuide: Partial<Record<RouteName, string>> = {
home: "",
org: "#quick-links",
join: "signup#set-up-your-personal-account",
};

@customElement("btrix-app-bar")
@localized()
export class AppBar extends BtrixElement {
Expand Down Expand Up @@ -139,18 +146,20 @@ export class AppBar extends BtrixElement {
</sl-menu>
</btrix-popover-menu>`
: html`
${this.viewState?.route !== "login"
? html`
<sl-button
size="small"
variant="primary"
href="/log-in"
@click=${this.navigate.link}
>
${msg("Sign In")}
</sl-button>
`
: nothing}
${this.viewState?.route === "join"
? this.renderUserGuideButton()
: this.viewState?.route !== "login"
? html`
<sl-button
size="small"
variant="primary"
href="/log-in"
@click=${this.navigate.link}
>
${msg("Sign In")}
</sl-button>
`
: nothing}
${(translatedLocales as unknown as string[]).length > 2
? html`
<btrix-user-language-select
Expand Down Expand Up @@ -251,28 +260,9 @@ export class AppBar extends BtrixElement {
}

private renderOrgUserActions() {
const showUserGuide = () => {
this.dispatchEvent(
new CustomEvent<BtrixUserGuideShowEvent["detail"]>(
"btrix-user-guide-show",
{
detail: { path: "" },
bubbles: true,
composed: true,
},
),
);
};

return html`<btrix-popover-menu>
${this.renderNavButton({
slot: "trigger",
content: msg("User Guide"),
iconName: "book",
mobileIconOnly: true,
click: showUserGuide,
})}
<sl-menu @sl-select=${showUserGuide}>
${this.renderUserGuideButton()}
<sl-menu @sl-select=${this.showUserGuide}>
<sl-menu-item>
${msg("Open to Side")}
<sl-icon slot="suffix" name="layout-sidebar-inset-reverse"></sl-icon>
Expand All @@ -285,6 +275,33 @@ export class AppBar extends BtrixElement {
</btrix-popover-menu>`;
}

private renderUserGuideButton() {
return this.renderNavButton({
slot: "trigger",
content: msg("User Guide"),
iconName: "book",
mobileIconOnly: true,
click: this.showUserGuide,
});
}

private readonly showUserGuide = () => {
this.dispatchEvent(
new CustomEvent<BtrixUserGuideShowEvent["detail"]>(
"btrix-user-guide-show",
{
detail: {
path:
(this.viewState?.route && mapToUserGuide[this.viewState.route]) ??
"",
},
bubbles: true,
composed: true,
},
),
);
};

private renderOrgs() {
const orgs = this.userInfo?.orgs;
if (!orgs) return;
Expand Down
33 changes: 20 additions & 13 deletions frontend/src/features/admin/super-admin-banner.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { localized, msg } from "@lit/localize";
import clsx from "clsx";
import { html } from "lit";
import { customElement, state } from "lit/decorators.js";

import { TailwindElement } from "@/classes/TailwindElement";
import { BtrixElement } from "@/classes/BtrixElement";
import { tw } from "@/utils/tailwind";

@customElement("btrix-super-admin-banner")
@localized()
export class SuperAdminBanner extends TailwindElement {
export class SuperAdminBanner extends BtrixElement {
@state()
hide = false;

render() {
if (this.hide) {
return html` <div class="absolute bottom-0 right-2 top-0 pt-[3.45rem]">
return html` <div
class=${clsx(
tw`absolute bottom-0 right-2 top-0`,
this.appState.userGuideOpen ? tw`pr-16` : tw`pt-[3.45rem]`,
)}
>
<sl-tooltip
placement="left"
class="[--max-width:500px] [--show-delay:0] part-[base__arrow]:bg-warning-700 part-[body]:bg-warning-700 part-[body]:text-xs"
Expand Down Expand Up @@ -46,20 +53,20 @@ export class SuperAdminBanner extends TailwindElement {
<div
class="mx-auto box-border flex w-full items-center gap-2 px-3 xl:pl-6"
>
<sl-icon
name="exclamation-diamond-fill"
class="size-4"
></sl-icon>
<sl-icon name="exclamation-diamond-fill" class="size-4"></sl-icon>
<span>
<strong>${msg("You are logged in as a superadmin")}</strong> –
${msg("please be careful.")}
</span>
<button type="button"
class="ml-auto flex"
@click=${() => {
this.hide = true;
}}>
<sl-icon name="x-circle" class="size-4"></sl-icon>
<button
type="button"
class="ml-auto flex"
@click=${() => {
this.hide = true;
}}
>
<sl-icon name="x-circle" class="size-4"></sl-icon>
</button>
</div>
</div>`;
}
Expand Down
103 changes: 53 additions & 50 deletions frontend/src/pages/invite/join.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe("btrix-join", () => {

await el.updateComplete;

expect(el).lightDom.to.contain("btrix-sign-up-form");
expect(el.shadowRoot!.querySelector("btrix-sign-up-form")).to.exist;
});

it("renders org rename form when registered", async () => {
Expand All @@ -84,7 +84,7 @@ describe("btrix-join", () => {

await el.updateComplete;

expect(el).lightDom.to.contain("btrix-org-form");
expect(el.shadowRoot!.querySelector("btrix-org-form")).to.exist;
});

it("renders org rename form with the correct attributes", async () => {
Expand All @@ -104,7 +104,7 @@ describe("btrix-join", () => {

await el.updateComplete;

const orgFormEl = el.querySelector<OrgForm>("btrix-org-form");
const orgFormEl = el.shadowRoot!.querySelector<OrgForm>("btrix-org-form");

expect(orgFormEl).attribute("newOrgId", "fake_oid");
expect(orgFormEl).attribute("name", "Fake Org Name 2");
Expand All @@ -118,7 +118,7 @@ describe("btrix-join", () => {
email="my_fake_email@example.com"
></btrix-join>`,
);
stub(el, "navTo");
stub(el.navigate, "to");
stub(el, "_isLoggedIn").get(() => true);
el._firstAdminOrgInfo = {
id: mockInviteInfo.oid,
Expand All @@ -128,7 +128,8 @@ describe("btrix-join", () => {

await el.updateComplete;

const orgFormEl = el.querySelector<OrgForm>("btrix-org-form")!;
const orgFormEl =
el.shadowRoot!.querySelector<OrgForm>("btrix-org-form")!;

setTimeout(() => {
orgFormEl.dispatchEvent(
Expand All @@ -145,54 +146,56 @@ describe("btrix-join", () => {

await oneEvent(orgFormEl, "btrix-org-updated");

expect(el.navTo).to.have.been.calledWith(
expect(el.navigate.to).to.have.been.calledWith(
"/orgs/fake-org-slug-2/dashboard",
);
});
});

describe("when inviting a non-first admin", () => {
beforeEach(() => {
stub(Join.prototype, "_getInviteInfo").callsFake(async () =>
Promise.resolve({
...mockInviteInfo,
firstOrgAdmin: false,
}),
);
});

it("renders user registration form", async () => {
const el = await fixture<Join>(
html`<btrix-join
token="my_fake_invite_token"
email="my_fake_email@example.com"
></btrix-join>`,
);

await el.updateComplete;

expect(el).lightDom.to.contain("btrix-sign-up-form");
});

it("redirects to org dashboard when registered", async () => {
const el = await fixture<Join>(
html`<btrix-join
token="my_fake_invite_token"
email="my_fake_email@example.com"
></btrix-join>`,
);
stub(el, "navTo");
el._onSignUpSuccess(
new CustomEvent("fake--success", {
detail: {},
}),
);
el._onAuthenticated(new CustomEvent("fake--authenticated"));
stub(el, "_isLoggedIn").get(() => true);

await el.updateComplete;

expect(el.navTo).to.have.been.calledWith("/orgs/fake-org-name/dashboard");
});
});
// describe("when inviting a non-first admin", () => {
// beforeEach(() => {
// stub(Join.prototype, "_getInviteInfo").callsFake(async () =>
// Promise.resolve({
// ...mockInviteInfo,
// firstOrgAdmin: false,
// }),
// );
// });

// it("renders user registration form", async () => {
// const el = await fixture<Join>(
// html`<btrix-join
// token="my_fake_invite_token"
// email="my_fake_email@example.com"
// ></btrix-join>`,
// );

// await el.updateComplete;

// expect(el).lightDom.to.contain("btrix-sign-up-form");
// });

// it("redirects to org dashboard when registered", async () => {
// const el = await fixture<Join>(
// html`<btrix-join
// token="my_fake_invite_token"
// email="my_fake_email@example.com"
// ></btrix-join>`,
// );
// stub(el.navigate, "to");
// el._onSignUpSuccess(
// new CustomEvent("fake--success", {
// detail: {},
// }),
// );
// el._onAuthenticated(new CustomEvent("fake--authenticated"));
// stub(el, "_isLoggedIn").get(() => true);

// await el.updateComplete;

// expect(el.navigate.to).to.have.been.calledWith(
// "/orgs/fake-org-name/dashboard",
// );
// });
// });
});
Loading
Loading