add dialog

This commit is contained in:
sua yoo 2024-05-07 15:08:43 -07:00
parent ebb9dc826a
commit 13b6a5b15f
No known key found for this signature in database
GPG Key ID: 5AD1B4C02D4F0567
2 changed files with 139 additions and 25 deletions

View File

@ -1,16 +1,19 @@
import { localized, msg, str } from "@lit/localize"; import { localized, msg, str } from "@lit/localize";
import type { SlInput } from "@shoelace-style/shoelace"; import type { SlInput } from "@shoelace-style/shoelace";
import { type TemplateResult } from "lit"; import { html, type TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, query } from "lit/decorators.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
import { TailwindElement } from "@/classes/TailwindElement";
import type { Dialog } from "@/components/ui/dialog";
import { APIController } from "@/controllers/api";
import { NavigateController } from "@/controllers/navigate";
import type { CurrentUser, UserOrg } from "@/types/user"; import type { CurrentUser, UserOrg } from "@/types/user";
import LiteElement, { html } from "@/utils/LiteElement";
import type { OrgData } from "@/utils/orgs"; import type { OrgData } from "@/utils/orgs";
@localized() @localized()
@customElement("btrix-orgs-list") @customElement("btrix-orgs-list")
export class OrgsList extends LiteElement { export class OrgsList extends TailwindElement {
@property({ type: Object }) @property({ type: Object })
userInfo?: CurrentUser; userInfo?: CurrentUser;
@ -23,6 +26,15 @@ export class OrgsList extends LiteElement {
@property({ type: Object }) @property({ type: Object })
currOrg?: OrgData | null = null; currOrg?: OrgData | null = null;
@query("#orgDeleteDialog")
orgDeleteDialog?: Dialog | null;
@query("#orgQuotaDialog")
orgQuotaDialog?: Dialog | null;
private readonly api = new APIController(this);
private readonly navigate = new NavigateController(this);
render() { render() {
if (this.skeleton) { if (this.skeleton) {
return this.renderSkeleton(); return this.renderSkeleton();
@ -33,17 +45,108 @@ export class OrgsList extends LiteElement {
return html` return html`
<ul class="overflow-hidden rounded-lg border"> <ul class="overflow-hidden rounded-lg border">
${this.orgList?.map(this.renderOrg(defaultOrg))} ${this.orgList?.map(this.renderOrg(defaultOrg))}
${this.renderOrgDelete()}
${this.renderOrgQuotas()} ${this.renderOrgQuotas()}
</ul> </ul>
`; `;
} }
private renderOrgDelete() {
return html`
<btrix-dialog
class="[--width:36rem]"
id="orgDeleteDialog"
.label=${msg(str`Confirm Org Deletion: ${this.currOrg?.name || ""}`)}
@sl-after-hide=${() => (this.currOrg = null)}
>
${when(this.currOrg, (org) => {
const confirmationStr = msg(str`Delete ${org.name}`);
return html`
<p class="mb-3">
${msg(
html`Are you sure you want to delete
<a
class="font-semibold text-primary"
href="/orgs/${org.slug}"
target="_blank"
>
${org.name}
<sl-icon
name="box-arrow-up-right"
label=${msg("Open in new window")}
></sl-icon> </a
>? This cannot be undone.`,
)}
</p>
<ul class="mb-3 text-neutral-600">
<li>${msg(str`Slug: ${org.slug}`)}</li>
<li>
${msg(
str`Members: ${Object.keys(org.users || {}).length.toLocaleString()}`,
)}
</li>
</ul>
<p class="mb-3">
${msg(
html`Deleting an org will delete all
<strong class="font-semibold">
<sl-format-bytes value=${org.bytesStored}></sl-format-bytes>
</strong>
of data associated with the org.`,
)}
</p>
<ul class="mb-3 text-neutral-600">
<li>
${msg(
html`Crawls:
<sl-format-bytes
value=${org.bytesStoredCrawls}
></sl-format-bytes>`,
)}
</li>
<li>
${msg(
html`Uploads:
<sl-format-bytes
value=${org.bytesStoredUploads}
></sl-format-bytes>`,
)}
</li>
<li>
${msg(
html`Profiles:
<sl-format-bytes
value=${org.bytesStoredProfiles}
></sl-format-bytes>`,
)}
</li>
</ul>
<sl-divider></sl-divider>
<sl-input placeholder=${confirmationStr}>
<strong slot="label" class="font-semibold">
${msg(str`Type "${confirmationStr}" to confirm`)}
</strong>
</sl-input>
`;
})}
<div slot="footer" class="flex justify-end">
<sl-button
size="small"
@click="${this.onSubmitQuotas}"
variant="danger"
>${msg("Delete Org")}
</sl-button>
</div>
</btrix-dialog>
`;
}
private renderOrgQuotas() { private renderOrgQuotas() {
return html` return html`
<btrix-dialog <btrix-dialog
id="orgQuotaDialog"
.label=${msg(str`Quotas for: ${this.currOrg?.name || ""}`)} .label=${msg(str`Quotas for: ${this.currOrg?.name || ""}`)}
.open=${!!this.currOrg} @sl-after-hide=${() => (this.currOrg = null)}
@sl-request-close=${() => (this.currOrg = null)}
> >
${when(this.currOrg?.quotas, (quotas) => ${when(this.currOrg?.quotas, (quotas) =>
Object.entries(quotas).map(([key, value]) => { Object.entries(quotas).map(([key, value]) => {
@ -72,6 +175,7 @@ export class OrgsList extends LiteElement {
label = msg("Unlabeled"); label = msg("Unlabeled");
} }
return html` <sl-input return html` <sl-input
class="mb-3 last:mb-0"
name=${key} name=${key}
label=${label} label=${label}
value=${value} value=${value}
@ -110,18 +214,6 @@ export class OrgsList extends LiteElement {
new CustomEvent("update-quotas", { detail: this.currOrg }), new CustomEvent("update-quotas", { detail: this.currOrg }),
); );
} }
this.currOrg = null;
}
private showQuotas(org: OrgData) {
const stop = (e: Event) => {
e.preventDefault();
e.stopPropagation();
this.currOrg = org;
return false;
};
return stop;
} }
private readonly renderOrg = (defaultOrg?: UserOrg) => (org: OrgData) => { private readonly renderOrg = (defaultOrg?: UserOrg) => (org: OrgData) => {
@ -158,12 +250,31 @@ export class OrgsList extends LiteElement {
? msg(`1 member`) ? msg(`1 member`)
: msg(str`${memberCount} members`)} : msg(str`${memberCount} members`)}
</div> </div>
<sl-icon-button <btrix-overflow-dropdown
name="gear" @click=${(e: MouseEvent) => e.stopPropagation()}
slot="prefix" >
label=${msg("Edit org quotas")} <sl-menu>
@click="${this.showQuotas(org)}" <sl-menu-item
></sl-icon-button> @click=${() => {
this.currOrg = org;
void this.orgQuotaDialog?.show();
}}
>
<sl-icon slot="prefix" name="gear"></sl-icon>
${msg("Edit Quotas")}
</sl-menu-item>
<sl-menu-item
style="--sl-color-neutral-700: var(--danger)"
@click=${() => {
this.currOrg = org;
void this.orgDeleteDialog?.show();
}}
>
<sl-icon slot="prefix" name="trash3"></sl-icon>
${msg("Delete Org")}
</sl-menu-item>
</sl-menu>
</btrix-overflow-dropdown>
</div> </div>
</li> </li>
`; `;
@ -180,7 +291,7 @@ export class OrgsList extends LiteElement {
} }
private makeOnOrgClick(org: OrgData) { private makeOnOrgClick(org: OrgData) {
const navigate = () => this.navTo(`/orgs/${org.slug}`); const navigate = () => this.navigate.to(`/orgs/${org.slug}`);
if (typeof window.getSelection !== "undefined") { if (typeof window.getSelection !== "undefined") {
return () => { return () => {

View File

@ -19,6 +19,9 @@ export type OrgData = {
slug: string; slug: string;
quotas?: Record<string, number>; quotas?: Record<string, number>;
bytesStored: number; bytesStored: number;
bytesStoredCrawls: number;
bytesStoredUploads: number;
bytesStoredProfiles: number;
usage: { [key: YearMonth]: number } | null; usage: { [key: YearMonth]: number } | null;
crawlExecSeconds?: { [key: YearMonth]: number }; crawlExecSeconds?: { [key: YearMonth]: number };
monthlyExecSeconds?: { [key: YearMonth]: number }; monthlyExecSeconds?: { [key: YearMonth]: number };