feat: Minor improvements to superadmin view (#1971)
Resolves https://github.com/webrecorder/browsertrix/issues/1951 ### Changes - Shows date org was created in superadmin org list - Visually differentiates unnamed org ID - Adds "Admin" badge to app header to make current login more apparent - Fixes logic to show "create org" dialog if there are no orgs in an instance - Refactors `btrix-home` to remove unused references to non-superadmin org list --------- Co-authored-by: Henry Wilkinson <henry@wilkinson.graphics>
This commit is contained in:
parent
94e985ae13
commit
daeb7448f5
@ -16,7 +16,7 @@ import { NavigateController } from "@/controllers/navigate";
|
|||||||
import { NotifyController } from "@/controllers/notify";
|
import { NotifyController } from "@/controllers/notify";
|
||||||
import type { CurrentUser } from "@/types/user";
|
import type { CurrentUser } from "@/types/user";
|
||||||
import type { AuthState } from "@/utils/AuthService";
|
import type { AuthState } from "@/utils/AuthService";
|
||||||
import { formatNumber } from "@/utils/localization";
|
import { formatNumber, getLocale } from "@/utils/localization";
|
||||||
import type { OrgData } from "@/utils/orgs";
|
import type { OrgData } from "@/utils/orgs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,7 +27,7 @@ import type { OrgData } from "@/utils/orgs";
|
|||||||
export class OrgsList extends TailwindElement {
|
export class OrgsList extends TailwindElement {
|
||||||
static styles = css`
|
static styles = css`
|
||||||
btrix-table {
|
btrix-table {
|
||||||
grid-template-columns: min-content [clickable-start] 50ch auto auto [clickable-end] min-content;
|
grid-template-columns: min-content [clickable-start] 50ch auto auto auto [clickable-end] min-content;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -76,6 +76,9 @@ export class OrgsList extends TailwindElement {
|
|||||||
<btrix-table-header-cell class="px-2">
|
<btrix-table-header-cell class="px-2">
|
||||||
${msg("Name")}
|
${msg("Name")}
|
||||||
</btrix-table-header-cell>
|
</btrix-table-header-cell>
|
||||||
|
<btrix-table-header-cell class="px-2">
|
||||||
|
${msg("Created")}
|
||||||
|
</btrix-table-header-cell>
|
||||||
<btrix-table-header-cell class="px-2">
|
<btrix-table-header-cell class="px-2">
|
||||||
${msg("Members")}
|
${msg("Members")}
|
||||||
</btrix-table-header-cell>
|
</btrix-table-header-cell>
|
||||||
@ -500,7 +503,7 @@ export class OrgsList extends TailwindElement {
|
|||||||
</btrix-table-cell>
|
</btrix-table-cell>
|
||||||
<btrix-table-cell class="p-2" rowClickTarget="a">
|
<btrix-table-cell class="p-2" rowClickTarget="a">
|
||||||
<a
|
<a
|
||||||
class=${org.readOnly ? "text-neutral-400" : "text-neutral-900"}
|
class=${org.readOnly ? "text-neutral-500" : "text-neutral-900"}
|
||||||
href="/orgs/${org.slug}"
|
href="/orgs/${org.slug}"
|
||||||
@click=${this.navigate.link}
|
@click=${this.navigate.link}
|
||||||
aria-disabled="${!isUserOrg}"
|
aria-disabled="${!isUserOrg}"
|
||||||
@ -508,9 +511,22 @@ export class OrgsList extends TailwindElement {
|
|||||||
${org.default
|
${org.default
|
||||||
? html`<btrix-tag class="mr-1">${msg("Default")}</btrix-tag>`
|
? html`<btrix-tag class="mr-1">${msg("Default")}</btrix-tag>`
|
||||||
: nothing}
|
: nothing}
|
||||||
${org.name}
|
${org.name === org.id
|
||||||
|
? html`<code class="text-neutral-400">${org.id}</code>`
|
||||||
|
: org.name}
|
||||||
</a>
|
</a>
|
||||||
</btrix-table-cell>
|
</btrix-table-cell>
|
||||||
|
|
||||||
|
<btrix-table-cell class="p-2">
|
||||||
|
<sl-format-date
|
||||||
|
lang=${getLocale()}
|
||||||
|
class="truncate"
|
||||||
|
date=${`${org.created}Z`}
|
||||||
|
month="2-digit"
|
||||||
|
day="2-digit"
|
||||||
|
year="2-digit"
|
||||||
|
></sl-format-date>
|
||||||
|
</btrix-table-cell>
|
||||||
<btrix-table-cell class="p-2">
|
<btrix-table-cell class="p-2">
|
||||||
${memberCount ? formatNumber(memberCount) : none}
|
${memberCount ? formatNumber(memberCount) : none}
|
||||||
</btrix-table-cell>
|
</btrix-table-cell>
|
||||||
|
@ -292,6 +292,7 @@ export class App extends LiteElement {
|
|||||||
class="mx-auto box-border flex h-12 items-center justify-between px-3 xl:pl-6"
|
class="mx-auto box-border flex h-12 items-center justify-between px-3 xl:pl-6"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
class="items-between flex gap-2"
|
||||||
aria-label="home"
|
aria-label="home"
|
||||||
href=${homeHref}
|
href=${homeHref}
|
||||||
@click=${(e: MouseEvent) => {
|
@click=${(e: MouseEvent) => {
|
||||||
@ -302,6 +303,9 @@ export class App extends LiteElement {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img class="h-6" alt="Browsertrix logo" src=${brandLockupColor} />
|
<img class="h-6" alt="Browsertrix logo" src=${brandLockupColor} />
|
||||||
|
${isSuperAdmin
|
||||||
|
? html`<btrix-tag>${msg("Admin")}</btrix-tag>`
|
||||||
|
: nothing}
|
||||||
</a>
|
</a>
|
||||||
${isSuperAdmin
|
${isSuperAdmin
|
||||||
? html`
|
? html`
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { localized, msg, str } from "@lit/localize";
|
import { localized, msg, str } from "@lit/localize";
|
||||||
import type { SlInput, SlInputEvent } from "@shoelace-style/shoelace";
|
import type { SlInput, SlInputEvent } from "@shoelace-style/shoelace";
|
||||||
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
|
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
|
||||||
import { type PropertyValues, type TemplateResult } from "lit";
|
import { type PropertyValues } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators.js";
|
import { customElement, property, state } from "lit/decorators.js";
|
||||||
|
|
||||||
import type { InviteSuccessDetail } from "@/features/accounts/invite-form";
|
import type { InviteSuccessDetail } from "@/features/accounts/invite-form";
|
||||||
@ -15,6 +15,11 @@ import type { OrgData } from "@/utils/orgs";
|
|||||||
import slugifyStrict from "@/utils/slugify";
|
import slugifyStrict from "@/utils/slugify";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Home page when org is not selected.
|
||||||
|
* Currently, only visible to superadmins--redirects to user's org, otherwise
|
||||||
|
*
|
||||||
|
* TODO Refactor out superadmin UI
|
||||||
|
*
|
||||||
* @fires btrix-update-user-info
|
* @fires btrix-update-user-info
|
||||||
*/
|
*/
|
||||||
@localized()
|
@localized()
|
||||||
@ -62,27 +67,24 @@ export class Home extends LiteElement {
|
|||||||
this.navTo(`/orgs/${this.slug}`);
|
this.navTo(`/orgs/${this.slug}`);
|
||||||
} else if (changedProperties.has("userInfo") && this.userInfo) {
|
} else if (changedProperties.has("userInfo") && this.userInfo) {
|
||||||
if (this.userInfo.isSuperAdmin) {
|
if (this.userInfo.isSuperAdmin) {
|
||||||
|
if (this.userInfo.orgs.length) {
|
||||||
void this.fetchOrgs();
|
void this.fetchOrgs();
|
||||||
|
} else {
|
||||||
|
this.isAddingOrg = true;
|
||||||
|
this.isAddOrgFormVisible = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.navTo(`/account/settings`);
|
this.navTo(`/account/settings`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updated(
|
render() {
|
||||||
changedProperties: PropertyValues<this> & Map<string, unknown>,
|
if (!this.userInfo || !this.userInfo.isSuperAdmin) {
|
||||||
) {
|
return;
|
||||||
const orgListUpdated = changedProperties.has("orgList") && this.orgList;
|
|
||||||
const userInfoUpdated = changedProperties.has("userInfo") && this.userInfo;
|
|
||||||
if (orgListUpdated || userInfoUpdated) {
|
|
||||||
if (this.userInfo?.isSuperAdmin && this.orgList && !this.orgList.length) {
|
|
||||||
this.isAddingOrg = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
if (this.userInfo.orgs.length && !this.orgList) {
|
||||||
if (!this.userInfo || !this.orgList) {
|
|
||||||
return html`
|
return html`
|
||||||
<div class="my-24 flex items-center justify-center text-3xl">
|
<div class="my-24 flex items-center justify-center text-3xl">
|
||||||
<sl-spinner></sl-spinner>
|
<sl-spinner></sl-spinner>
|
||||||
@ -90,29 +92,19 @@ export class Home extends LiteElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let title: string | undefined;
|
|
||||||
let content: TemplateResult<1> | undefined;
|
|
||||||
|
|
||||||
if (this.userInfo.isSuperAdmin) {
|
|
||||||
title = msg("Welcome");
|
|
||||||
content = this.renderAdminOrgs();
|
|
||||||
} else {
|
|
||||||
title = msg("Organizations");
|
|
||||||
content = this.renderLoggedInNonAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="bg-white">
|
<div class="bg-white">
|
||||||
<header
|
<header
|
||||||
class="mx-auto box-border w-full max-w-screen-desktop px-3 py-4 md:py-8"
|
class="mx-auto box-border w-full max-w-screen-desktop px-3 py-4 md:py-8"
|
||||||
>
|
>
|
||||||
<h1 class="text-xl font-medium">${title}</h1>
|
<h1 class="text-xl font-medium">${msg("Welcome")}</h1>
|
||||||
</header>
|
</header>
|
||||||
<hr />
|
<hr />
|
||||||
</div>
|
</div>
|
||||||
<main class="mx-auto box-border w-full max-w-screen-desktop px-3 py-4">
|
<main class="mx-auto box-border w-full max-w-screen-desktop px-3 py-4">
|
||||||
${content}
|
${this.renderAdminOrgs()}
|
||||||
</main>
|
</main>
|
||||||
|
${this.renderAddOrgDialog()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,8 +174,6 @@ export class Home extends LiteElement {
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.renderAddOrgDialog()}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,24 +267,6 @@ export class Home extends LiteElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderLoggedInNonAdmin() {
|
|
||||||
if (this.orgList && !this.orgList.length) {
|
|
||||||
return html`<div class="rounded-lg border bg-white p-4 md:p-8">
|
|
||||||
<p class="text-center text-neutral-400">
|
|
||||||
${msg("You don't have any organizations.")}
|
|
||||||
</p>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<btrix-orgs-list
|
|
||||||
.userInfo=${this.userInfo}
|
|
||||||
.orgList=${this.orgList}
|
|
||||||
?skeleton=${!this.orgList}
|
|
||||||
></btrix-orgs-list>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderInvite() {
|
private renderInvite() {
|
||||||
return html`
|
return html`
|
||||||
<btrix-invite-form
|
<btrix-invite-form
|
||||||
@ -384,9 +356,6 @@ export class Home extends LiteElement {
|
|||||||
// Update user info since orgs are checked against userInfo.orgs
|
// Update user info since orgs are checked against userInfo.orgs
|
||||||
this.dispatchEvent(new CustomEvent("btrix-update-user-info"));
|
this.dispatchEvent(new CustomEvent("btrix-update-user-info"));
|
||||||
|
|
||||||
await this.updateComplete;
|
|
||||||
void this.fetchOrgs();
|
|
||||||
|
|
||||||
this.notify({
|
this.notify({
|
||||||
message: msg(str`Created new org named "${params.name}".`),
|
message: msg(str`Created new org named "${params.name}".`),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
|
@ -31,6 +31,7 @@ export type OrgQuotas = {
|
|||||||
export type OrgData = {
|
export type OrgData = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
created: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
default: boolean;
|
default: boolean;
|
||||||
quotas: OrgQuotas;
|
quotas: OrgQuotas;
|
||||||
|
Loading…
Reference in New Issue
Block a user