feat: Clean up settings UI (#2018)
- Renames "Org Settings" -> "Settings" - Reduces gap between settings panel heading and panel - Always show "Pending Invites" section and update heading styles to match panel heading - Update "Current Plan" and "Usage History" sections to be on the same hierarchical level under "Billing" - Refactors `<btrix-org>` to move `isAdmin` and `isCrawler` helpers to app state
This commit is contained in:
parent
9a7033875b
commit
4c7f1aa3ca
@ -90,7 +90,8 @@ export class TabList extends TailwindElement {
|
||||
"header"
|
||||
"main";
|
||||
grid-template-columns: 1fr;
|
||||
grid-gap: 1.5rem;
|
||||
grid-column-gap: 1.5rem;
|
||||
grid-row-gap: 1rem;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: ${TWO_COL_SCREEN_MIN_CSS}) {
|
||||
|
@ -387,7 +387,7 @@ export class App extends LiteElement {
|
||||
<sl-menu-item
|
||||
@click=${() => this.navigate(ROUTES.accountSettings)}
|
||||
>
|
||||
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||
<sl-icon slot="prefix" name="person-gear"></sl-icon>
|
||||
${msg("Account Settings")}
|
||||
</sl-menu-item>
|
||||
${this.userInfo?.isSuperAdmin
|
||||
|
@ -34,9 +34,6 @@ export class Dashboard extends LiteElement {
|
||||
@property({ type: Boolean })
|
||||
isCrawler?: boolean;
|
||||
|
||||
@property({ type: Boolean })
|
||||
isAdmin?: boolean;
|
||||
|
||||
@state()
|
||||
private metrics?: Metrics;
|
||||
|
||||
@ -74,7 +71,7 @@ export class Dashboard extends LiteElement {
|
||||
${this.userOrg?.name}
|
||||
</h1>
|
||||
${when(
|
||||
this.isAdmin,
|
||||
this.appState.isAdmin,
|
||||
() =>
|
||||
html` <sl-icon-button
|
||||
href=${`${this.orgBasePath}/settings`}
|
||||
|
@ -22,7 +22,7 @@ import { isApiError } from "@/utils/api";
|
||||
import type { ViewState } from "@/utils/APIRouter";
|
||||
import { DEFAULT_MAX_SCALE } from "@/utils/crawler";
|
||||
import LiteElement, { html } from "@/utils/LiteElement";
|
||||
import { isAdmin, isCrawler, type OrgData } from "@/utils/orgs";
|
||||
import { type OrgData } from "@/utils/orgs";
|
||||
import { AppStateService } from "@/utils/state";
|
||||
|
||||
import "./workflow-detail";
|
||||
@ -113,18 +113,6 @@ export class Org extends LiteElement {
|
||||
@state()
|
||||
private isCreateDialogVisible = false;
|
||||
|
||||
private get isAdmin() {
|
||||
const userOrg = this.appState.userOrg;
|
||||
if (userOrg) return isAdmin(userOrg.role);
|
||||
return false;
|
||||
}
|
||||
|
||||
private get isCrawler() {
|
||||
const userOrg = this.appState.userOrg;
|
||||
if (userOrg) return isCrawler(userOrg.role);
|
||||
return false;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.addEventListener(
|
||||
@ -263,7 +251,8 @@ export class Org extends LiteElement {
|
||||
["collections", this.renderCollections],
|
||||
[
|
||||
"settings",
|
||||
() => (this.isAdmin ? this.renderOrgSettings() : html``),
|
||||
() =>
|
||||
this.appState.isAdmin ? this.renderOrgSettings() : html``,
|
||||
],
|
||||
],
|
||||
() =>
|
||||
@ -304,17 +293,17 @@ export class Org extends LiteElement {
|
||||
label: msg("Collections"),
|
||||
path: "collections",
|
||||
})}
|
||||
${when(this.isCrawler, () =>
|
||||
${when(this.appState.isCrawler, () =>
|
||||
this.renderNavTab({
|
||||
tabName: "browser-profiles",
|
||||
label: msg("Browser Profiles"),
|
||||
path: "browser-profiles",
|
||||
}),
|
||||
)}
|
||||
${when(this.isAdmin || this.userInfo?.isSuperAdmin, () =>
|
||||
${when(this.appState.isAdmin || this.userInfo?.isSuperAdmin, () =>
|
||||
this.renderNavTab({
|
||||
tabName: "settings",
|
||||
label: msg("Org Settings"),
|
||||
label: msg("Settings"),
|
||||
path: "settings",
|
||||
}),
|
||||
)}
|
||||
@ -356,7 +345,7 @@ export class Org extends LiteElement {
|
||||
}
|
||||
|
||||
private renderNewResourceDialogs() {
|
||||
if (!this.orgId || !this.isCrawler) {
|
||||
if (!this.orgId || !this.appState.isCrawler) {
|
||||
return;
|
||||
}
|
||||
if (!this.isCreateDialogVisible) {
|
||||
@ -413,8 +402,8 @@ export class Org extends LiteElement {
|
||||
private readonly renderDashboard = () => {
|
||||
return html`
|
||||
<btrix-dashboard
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isAdmin=${this.isAdmin}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
?isAdmin=${this.appState.isAdmin}
|
||||
@select-new-dialog=${this.onSelectNewDialog}
|
||||
></btrix-dashboard>
|
||||
`;
|
||||
@ -425,7 +414,7 @@ export class Org extends LiteElement {
|
||||
|
||||
if (params.itemId) {
|
||||
if (params.qaTab) {
|
||||
if (!this.isCrawler) {
|
||||
if (!this.appState.isCrawler) {
|
||||
return html`<btrix-not-found
|
||||
class="flex items-center justify-center"
|
||||
></btrix-not-found>`;
|
||||
@ -445,12 +434,12 @@ export class Org extends LiteElement {
|
||||
collectionId=${params.collectionId || ""}
|
||||
workflowId=${params.workflowId || ""}
|
||||
itemType=${params.itemType || "crawl"}
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
></btrix-archived-item-detail>`;
|
||||
}
|
||||
|
||||
return html`<btrix-archived-items
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
itemType=${ifDefined(params.itemType || undefined)}
|
||||
@select-new-dialog=${this.onSelectNewDialog}
|
||||
></btrix-archived-items>`;
|
||||
@ -470,7 +459,7 @@ export class Org extends LiteElement {
|
||||
workflowId=${workflowId}
|
||||
openDialogName=${this.viewStateData?.dialog}
|
||||
?isEditing=${isEditing}
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
.maxScale=${this.maxScale}
|
||||
></btrix-workflow-detail>
|
||||
`;
|
||||
@ -481,7 +470,7 @@ export class Org extends LiteElement {
|
||||
|
||||
return html` <btrix-workflows-new
|
||||
class="col-span-5 mt-6"
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
.initialWorkflow=${workflow}
|
||||
.initialSeeds=${seeds}
|
||||
jobType=${ifDefined(params.jobType)}
|
||||
@ -490,7 +479,6 @@ export class Org extends LiteElement {
|
||||
}
|
||||
|
||||
return html`<btrix-workflows-list
|
||||
?isCrawler=${this.isCrawler}
|
||||
@select-new-dialog=${this.onSelectNewDialog}
|
||||
></btrix-workflows-list>`;
|
||||
};
|
||||
@ -501,7 +489,7 @@ export class Org extends LiteElement {
|
||||
if (params.browserProfileId) {
|
||||
return html`<btrix-browser-profiles-detail
|
||||
profileId=${params.browserProfileId}
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
></btrix-browser-profiles-detail>`;
|
||||
}
|
||||
|
||||
@ -520,7 +508,7 @@ export class Org extends LiteElement {
|
||||
}
|
||||
|
||||
return html`<btrix-browser-profiles-list
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
@select-new-dialog=${this.onSelectNewDialog}
|
||||
></btrix-browser-profiles-list>`;
|
||||
};
|
||||
@ -533,12 +521,12 @@ export class Org extends LiteElement {
|
||||
collectionId=${params.collectionId}
|
||||
collectionTab=${(params.collectionTab as CollectionTab | undefined) ||
|
||||
"replay"}
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
></btrix-collection-detail>`;
|
||||
}
|
||||
|
||||
return html`<btrix-collections-list
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isCrawler=${this.appState.isCrawler}
|
||||
@select-new-dialog=${this.onSelectNewDialog}
|
||||
></btrix-collections-list>`;
|
||||
};
|
||||
|
@ -84,32 +84,38 @@ export class OrgSettingsBilling extends BtrixElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="rounded-lg border">
|
||||
<section class="-mt-5">
|
||||
${columns([
|
||||
[
|
||||
html`
|
||||
<h4 class="form-label text-neutral-800">
|
||||
${msg("Current Plan")}
|
||||
</h4>
|
||||
<div class="rounded border px-4 pb-4">
|
||||
${when(
|
||||
this.org,
|
||||
(org) => html`
|
||||
<div
|
||||
class="mb-3 flex items-center justify-between border-b py-2"
|
||||
>
|
||||
<div
|
||||
class="flex items-center gap-2 text-base font-semibold leading-none"
|
||||
>
|
||||
${this.renderSubscriptionDetails(org.subscription)}
|
||||
</div>
|
||||
${org.subscription
|
||||
<div class="mt-5 rounded-lg border px-4 pb-4">
|
||||
<div
|
||||
class="mb-3 flex items-center justify-between border-b py-2"
|
||||
>
|
||||
<div
|
||||
class="flex items-center gap-2 text-base font-semibold leading-none"
|
||||
>
|
||||
${when(
|
||||
this.org,
|
||||
(org) => this.renderSubscriptionDetails(org.subscription),
|
||||
() => html` <sl-skeleton></sl-skeleton> `,
|
||||
)}
|
||||
</div>
|
||||
${when(
|
||||
this.org,
|
||||
(org) =>
|
||||
org.subscription
|
||||
? this.renderPortalLink()
|
||||
: this.salesEmail
|
||||
? this.renderContactSalesLink(this.salesEmail)
|
||||
: nothing}
|
||||
</div>
|
||||
${org.subscription?.futureCancelDate
|
||||
: nothing,
|
||||
() => html` <sl-skeleton></sl-skeleton> `,
|
||||
)}
|
||||
</div>
|
||||
${when(
|
||||
this.org,
|
||||
(org) =>
|
||||
org.subscription?.futureCancelDate
|
||||
? html`
|
||||
<div
|
||||
class="mb-3 flex items-center gap-2 border-b pb-3 text-neutral-500"
|
||||
@ -134,12 +140,20 @@ export class OrgSettingsBilling extends BtrixElement {
|
||||
</span>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
<h5 class="mb-2 mt-4 text-xs leading-none text-neutral-500">
|
||||
${msg("Monthly quota")}
|
||||
</h5>
|
||||
${this.renderQuotas(org.quotas)}
|
||||
`,
|
||||
: nothing,
|
||||
() => html` <sl-skeleton></sl-skeleton> `,
|
||||
)}
|
||||
<h5 class="mb-2 mt-4 text-xs leading-none text-neutral-500">
|
||||
${msg("Monthly quota")}
|
||||
</h5>
|
||||
${when(
|
||||
this.org,
|
||||
(org) => this.renderQuotas(org.quotas),
|
||||
() =>
|
||||
html` <sl-skeleton class="mb-2"></sl-skeleton>
|
||||
<sl-skeleton class="mb-2"></sl-skeleton>
|
||||
<sl-skeleton class="mb-2"></sl-skeleton>
|
||||
<sl-skeleton class="mb-2"></sl-skeleton>`,
|
||||
)}
|
||||
</div>
|
||||
`,
|
||||
@ -182,14 +196,20 @@ export class OrgSettingsBilling extends BtrixElement {
|
||||
`,
|
||||
],
|
||||
])}
|
||||
|
||||
<div class="p-4">
|
||||
<btrix-section-heading style="--margin: var(--sl-spacing-medium)">
|
||||
<h4>${msg("Usage History")}</h4>
|
||||
</btrix-section-heading>
|
||||
<btrix-usage-history-table></btrix-usage-history-table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="mt-7">
|
||||
<header>
|
||||
<h3 class="mb-2 text-lg font-medium">${msg("Usage History")}</h3>
|
||||
</header>
|
||||
${when(
|
||||
this.org,
|
||||
() => html` <btrix-usage-history-table></btrix-usage-history-table> `,
|
||||
() =>
|
||||
html`<div class="flex justify-center rounded border p-5 text-xl">
|
||||
<sl-spinner></sl-spinner>
|
||||
</div>`,
|
||||
)}
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import type { SlInput } from "@shoelace-style/shoelace";
|
||||
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
|
||||
import { html, type PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { choose } from "lit/directives/choose.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
import { when } from "lit/directives/when.js";
|
||||
|
||||
@ -104,27 +105,33 @@ export class OrgSettings extends BtrixElement {
|
||||
</header>
|
||||
|
||||
<btrix-tab-list activePanel=${this.activePanel} hideIndicator>
|
||||
<header slot="header" class="flex h-5 items-end justify-between">
|
||||
${when(
|
||||
this.activePanel === "members",
|
||||
() => html`
|
||||
<h3>${msg("Active Members")}</h3>
|
||||
<sl-button
|
||||
href=${`${this.navigate.orgBasePath}/settings/members?invite`}
|
||||
variant="primary"
|
||||
size="small"
|
||||
@click=${this.navigate.link}
|
||||
>
|
||||
<sl-icon
|
||||
slot="prefix"
|
||||
name="person-add"
|
||||
aria-hidden="true"
|
||||
library="default"
|
||||
></sl-icon>
|
||||
${msg("Invite New Member")}
|
||||
</sl-button>
|
||||
`,
|
||||
() => html` <h3>${this.tabLabels[this.activePanel]}</h3> `,
|
||||
<header slot="header" class="flex h-7 items-end justify-between">
|
||||
${choose(
|
||||
this.activePanel,
|
||||
[
|
||||
[
|
||||
"members",
|
||||
() => html`
|
||||
<h3>${msg("Active Members")}</h3>
|
||||
<sl-button
|
||||
href=${`${this.navigate.orgBasePath}/settings/members?invite`}
|
||||
variant="primary"
|
||||
size="small"
|
||||
@click=${this.navigate.link}
|
||||
>
|
||||
<sl-icon
|
||||
slot="prefix"
|
||||
name="person-add"
|
||||
aria-hidden="true"
|
||||
library="default"
|
||||
></sl-icon>
|
||||
${msg("Invite New Member")}
|
||||
</sl-button>
|
||||
`,
|
||||
],
|
||||
["billing", () => html`<h3>${msg("Current Plan")}</h3> `],
|
||||
],
|
||||
() => html`<h3>${this.tabLabels[this.activePanel]}</h3>`,
|
||||
)}
|
||||
</header>
|
||||
${this.renderTab("information", "settings")}
|
||||
@ -167,67 +174,69 @@ export class OrgSettings extends BtrixElement {
|
||||
|
||||
return html`<div class="rounded-lg border">
|
||||
<form @submit=${this.onOrgInfoSubmit}>
|
||||
${columns([
|
||||
[
|
||||
html`
|
||||
<sl-input
|
||||
class="with-max-help-text mb-2"
|
||||
name="orgName"
|
||||
size="small"
|
||||
label=${msg("Org Name")}
|
||||
placeholder=${msg("My Organization")}
|
||||
autocomplete="off"
|
||||
value=${this.userOrg.name}
|
||||
minlength="2"
|
||||
required
|
||||
help-text=${this.validateOrgNameMax.helpText}
|
||||
@sl-input=${this.validateOrgNameMax.validate}
|
||||
></sl-input>
|
||||
`,
|
||||
msg(
|
||||
"Name of your organization that is visible to all org members.",
|
||||
),
|
||||
],
|
||||
[
|
||||
html`
|
||||
<sl-input
|
||||
class="mb-2"
|
||||
name="orgSlug"
|
||||
size="small"
|
||||
label=${msg("Custom URL Identifier")}
|
||||
placeholder="my-organization"
|
||||
autocomplete="off"
|
||||
value=${this.orgSlug || ""}
|
||||
minlength="2"
|
||||
maxlength="30"
|
||||
required
|
||||
help-text=${msg(
|
||||
str`Org home page: ${window.location.protocol}//${
|
||||
window.location.hostname
|
||||
}/orgs/${
|
||||
this.slugValue
|
||||
? slugifyStrict(this.slugValue)
|
||||
: this.orgSlug
|
||||
}`,
|
||||
)}
|
||||
@sl-input=${this.handleSlugInput}
|
||||
></sl-input>
|
||||
`,
|
||||
msg(
|
||||
"Customize your organization's web address for accessing Browsertrix.",
|
||||
),
|
||||
],
|
||||
[
|
||||
html`
|
||||
<btrix-copy-field
|
||||
class="mb-2"
|
||||
label=${msg("Org ID")}
|
||||
value=${this.orgId}
|
||||
></btrix-copy-field>
|
||||
`,
|
||||
msg("Use this ID to reference this org in the Browsertrix API."),
|
||||
],
|
||||
])}
|
||||
<div class="p-5">
|
||||
${columns([
|
||||
[
|
||||
html`
|
||||
<sl-input
|
||||
class="with-max-help-text mb-2"
|
||||
name="orgName"
|
||||
size="small"
|
||||
label=${msg("Org Name")}
|
||||
placeholder=${msg("My Organization")}
|
||||
autocomplete="off"
|
||||
value=${this.userOrg.name}
|
||||
minlength="2"
|
||||
required
|
||||
help-text=${this.validateOrgNameMax.helpText}
|
||||
@sl-input=${this.validateOrgNameMax.validate}
|
||||
></sl-input>
|
||||
`,
|
||||
msg(
|
||||
"Name of your organization that is visible to all org members.",
|
||||
),
|
||||
],
|
||||
[
|
||||
html`
|
||||
<sl-input
|
||||
class="mb-2"
|
||||
name="orgSlug"
|
||||
size="small"
|
||||
label=${msg("Custom URL Identifier")}
|
||||
placeholder="my-organization"
|
||||
autocomplete="off"
|
||||
value=${this.orgSlug || ""}
|
||||
minlength="2"
|
||||
maxlength="30"
|
||||
required
|
||||
help-text=${msg(
|
||||
str`Org home page: ${window.location.protocol}//${
|
||||
window.location.hostname
|
||||
}/orgs/${
|
||||
this.slugValue
|
||||
? slugifyStrict(this.slugValue)
|
||||
: this.orgSlug
|
||||
}`,
|
||||
)}
|
||||
@sl-input=${this.handleSlugInput}
|
||||
></sl-input>
|
||||
`,
|
||||
msg(
|
||||
"Customize your organization's web address for accessing Browsertrix.",
|
||||
),
|
||||
],
|
||||
[
|
||||
html`
|
||||
<btrix-copy-field
|
||||
class="mb-2"
|
||||
label=${msg("Org ID")}
|
||||
value=${this.orgId}
|
||||
></btrix-copy-field>
|
||||
`,
|
||||
msg("Use this ID to reference this org in the Browsertrix API."),
|
||||
],
|
||||
])}
|
||||
</div>
|
||||
<footer class="flex justify-end border-t px-4 py-3">
|
||||
<sl-button
|
||||
class="inline-control-button"
|
||||
@ -281,14 +290,13 @@ export class OrgSettings extends BtrixElement {
|
||||
</btrix-data-table>
|
||||
</section>
|
||||
|
||||
${when(
|
||||
this.pendingInvites.length,
|
||||
() => html`
|
||||
<section class="mt-7">
|
||||
<h3 class="mb-2 text-lg font-semibold">
|
||||
${msg("Pending Invites")}
|
||||
</h3>
|
||||
|
||||
<section class="mt-7">
|
||||
<header>
|
||||
<h3 class="mb-2 text-lg font-medium">${msg("Pending Invites")}</h3>
|
||||
</header>
|
||||
${when(
|
||||
this.pendingInvites.length,
|
||||
() => html`
|
||||
<btrix-data-table
|
||||
.columns=${[
|
||||
msg("Email"),
|
||||
@ -303,9 +311,16 @@ export class OrgSettings extends BtrixElement {
|
||||
.columnWidths=${columnWidths}
|
||||
>
|
||||
</btrix-data-table>
|
||||
</section>
|
||||
`,
|
||||
)}
|
||||
`,
|
||||
() => html`
|
||||
<p
|
||||
class="rounded border bg-neutral-50 p-3 text-center text-neutral-500"
|
||||
>
|
||||
${msg("No pending invites to show.")}
|
||||
</p>
|
||||
`,
|
||||
)}
|
||||
</section>
|
||||
|
||||
<btrix-dialog
|
||||
.label=${msg("Invite New Member")}
|
||||
|
@ -9,7 +9,7 @@ export function columns(
|
||||
cols: [TemplateResult<1>, TemplateResult<1> | string][],
|
||||
) {
|
||||
return html`
|
||||
<div class="grid grid-cols-5 gap-5 p-5">
|
||||
<div class="grid grid-cols-5 gap-5">
|
||||
${cols.map(
|
||||
([main, info]) => html`
|
||||
<div class=${tw`col-span-5 self-baseline md:col-span-3`}>${main}</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { localized, msg, str } from "@lit/localize";
|
||||
import type { SlCheckbox } from "@shoelace-style/shoelace";
|
||||
import { type PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
import { when } from "lit/directives/when.js";
|
||||
import queryString from "query-string";
|
||||
@ -70,9 +70,6 @@ export class WorkflowsList extends LiteElement {
|
||||
firstSeed: msg("Crawl Start URL"),
|
||||
};
|
||||
|
||||
@property({ type: Boolean })
|
||||
isCrawler!: boolean;
|
||||
|
||||
@state()
|
||||
private workflows?: APIPaginatedList<ListWorkflow>;
|
||||
|
||||
@ -190,12 +187,13 @@ export class WorkflowsList extends LiteElement {
|
||||
render() {
|
||||
return html`
|
||||
<header class="contents">
|
||||
<div class="mb-4 flex w-full justify-between">
|
||||
<h1 class="text-xl font-semibold leading-8">
|
||||
<div class="mb-4 flex w-full justify-end gap-2">
|
||||
<h1 class="mr-auto text-xl font-semibold leading-8">
|
||||
${msg("Crawl Workflows")}
|
||||
</h1>
|
||||
|
||||
${when(
|
||||
this.isCrawler,
|
||||
this.appState.isCrawler,
|
||||
() => html`
|
||||
<sl-button
|
||||
variant="primary"
|
||||
@ -413,7 +411,7 @@ export class WorkflowsList extends LiteElement {
|
||||
private renderMenuItems(workflow: ListWorkflow) {
|
||||
return html`
|
||||
${when(
|
||||
workflow.isCrawlRunning && this.isCrawler,
|
||||
workflow.isCrawlRunning && this.appState.isCrawler,
|
||||
// HACK shoelace doesn't current have a way to override non-hover
|
||||
// color without resetting the --sl-color-neutral-700 variable
|
||||
() => html`
|
||||
@ -434,7 +432,7 @@ export class WorkflowsList extends LiteElement {
|
||||
`,
|
||||
)}
|
||||
${when(
|
||||
this.isCrawler && !workflow.isCrawlRunning,
|
||||
this.appState.isCrawler && !workflow.isCrawlRunning,
|
||||
() => html`
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--success)"
|
||||
@ -447,7 +445,7 @@ export class WorkflowsList extends LiteElement {
|
||||
`,
|
||||
)}
|
||||
${when(
|
||||
workflow.isCrawlRunning && this.isCrawler,
|
||||
workflow.isCrawlRunning && this.appState.isCrawler,
|
||||
// HACK shoelace doesn't current have a way to override non-hover
|
||||
// color without resetting the --sl-color-neutral-700 variable
|
||||
() => html`
|
||||
@ -480,7 +478,7 @@ export class WorkflowsList extends LiteElement {
|
||||
`,
|
||||
)}
|
||||
${when(
|
||||
this.isCrawler,
|
||||
this.appState.isCrawler,
|
||||
() =>
|
||||
html` <sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
@ -501,7 +499,7 @@ export class WorkflowsList extends LiteElement {
|
||||
${msg("Copy Tags")}
|
||||
</sl-menu-item>
|
||||
${when(
|
||||
this.isCrawler,
|
||||
this.appState.isCrawler,
|
||||
() =>
|
||||
html` <sl-menu-item
|
||||
?disabled=${isArchivingDisabled(this.org, true)}
|
||||
|
@ -9,6 +9,7 @@ import type { AppSettings } from "@/types/app";
|
||||
import { authSchema, type Auth } from "@/types/auth";
|
||||
import type { OrgData } from "@/types/org";
|
||||
import { userInfoSchema, type UserInfo, type UserOrg } from "@/types/user";
|
||||
import { isAdmin, isCrawler } from "@/utils/orgs";
|
||||
|
||||
export { use };
|
||||
|
||||
@ -46,6 +47,18 @@ export function makeAppStateService() {
|
||||
get orgId() {
|
||||
return this.userOrg?.id || "";
|
||||
}
|
||||
|
||||
get isAdmin() {
|
||||
const userOrg = this.userOrg;
|
||||
if (userOrg) return isAdmin(userOrg.role);
|
||||
return false;
|
||||
}
|
||||
|
||||
get isCrawler() {
|
||||
const userOrg = this.userOrg;
|
||||
if (userOrg) return isCrawler(userOrg.role);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const appState = new AppState();
|
||||
|
Loading…
Reference in New Issue
Block a user