Fixes allowed actions for viewers and crawlers throughout the app (#1326)
Closes #1294 ### Changes - `crawl-list` component - Adds a check if there are any items in the actions menu. If not, skip rendering the actions menu. - This allows us to give the component no actions! Currently required to remove them for viewers! - Collection Details - Hides "Remove from Collection" option for viewers - Crawls List - Removes the single "View Crawl Details" option from archived items for viewers - All the other actions were already set up correctly to be used by all roles! - Dashboard - Hides org settings gear icon button unless the user is an admin - Hides "Create New" dropdown for viewers - Workflow Details - Hides workflow edit icon button for viewers - Hides the "Delete Crawl" option in archived items for viewers - Hides the "Run Crawl" option for viewers - Workflow List - Hides all edit-related options for viewers, the only option now is copying tags - Removes the deactivate / delete options (were only visible when running a crawl) in the workflow list actions --------- Co-authored-by: Ilya Kreymer <ikreymer@gmail.com> Co-authored-by: sua yoo <sua@suayoo.com>
This commit is contained in:
parent
1218d6e767
commit
f507f1d2ec
@ -833,7 +833,7 @@ def init_crawls_api(app, user_dep, *args):
|
||||
crawl_id: str,
|
||||
pageSize: int = DEFAULT_PAGE_SIZE,
|
||||
page: int = 1,
|
||||
org: Organization = Depends(org_crawl_dep),
|
||||
org: Organization = Depends(org_viewer_dep),
|
||||
):
|
||||
crawl_raw = await ops.get_crawl_raw(crawl_id, org)
|
||||
crawl = Crawl.from_dict(crawl_raw)
|
||||
|
@ -207,6 +207,9 @@ export class CrawlListItem extends LitElement {
|
||||
@state()
|
||||
private dropdownIsOpen?: boolean;
|
||||
|
||||
@state()
|
||||
private hasMenuItems?: boolean;
|
||||
|
||||
// TODO localize
|
||||
private numberFormatter = new Intl.NumberFormat(undefined, {
|
||||
notation: "compact",
|
||||
@ -357,35 +360,7 @@ export class CrawlListItem extends LitElement {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col action">
|
||||
<sl-icon-button
|
||||
class="dropdownTrigger"
|
||||
label=${msg("Actions")}
|
||||
name="three-dots-vertical"
|
||||
@click=${(e: MouseEvent) => {
|
||||
// Prevent anchor link default behavior
|
||||
e.preventDefault();
|
||||
// Stop prop to anchor link
|
||||
e.stopPropagation();
|
||||
this.dropdownIsOpen = !this.dropdownIsOpen;
|
||||
}}
|
||||
@focusout=${(e: FocusEvent) => {
|
||||
const relatedTarget = e.relatedTarget as HTMLElement;
|
||||
if (relatedTarget) {
|
||||
if (this.menuArr[0]?.contains(relatedTarget)) {
|
||||
// Keep dropdown open if moving to menu selection
|
||||
return;
|
||||
}
|
||||
if (this.row?.isEqualNode(relatedTarget)) {
|
||||
// Handle with click event
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.dropdownIsOpen = false;
|
||||
}}
|
||||
>
|
||||
</sl-icon-button>
|
||||
</div>
|
||||
${this.renderActions()}
|
||||
</a>`;
|
||||
}
|
||||
|
||||
@ -406,6 +381,7 @@ export class CrawlListItem extends LitElement {
|
||||
>
|
||||
<slot
|
||||
name="menu"
|
||||
@slotchange=${() => (this.hasMenuItems = this.menuArr.length > 0)}
|
||||
@sl-select=${() => (this.dropdownIsOpen = false)}
|
||||
></slot>
|
||||
</div> `;
|
||||
@ -440,6 +416,42 @@ export class CrawlListItem extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private renderActions() {
|
||||
if (!this.hasMenuItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
return html` <div class="col action">
|
||||
<sl-icon-button
|
||||
class="dropdownTrigger"
|
||||
label=${msg("Actions")}
|
||||
name="three-dots-vertical"
|
||||
@click=${(e: MouseEvent) => {
|
||||
// Prevent anchor link default behavior
|
||||
e.preventDefault();
|
||||
// Stop prop to anchor link
|
||||
e.stopPropagation();
|
||||
this.dropdownIsOpen = !this.dropdownIsOpen;
|
||||
}}
|
||||
@focusout=${(e: FocusEvent) => {
|
||||
const relatedTarget = e.relatedTarget as HTMLElement;
|
||||
if (relatedTarget) {
|
||||
if (this.menuArr[0]?.contains(relatedTarget)) {
|
||||
// Keep dropdown open if moving to menu selection
|
||||
return;
|
||||
}
|
||||
if (this.row?.isEqualNode(relatedTarget)) {
|
||||
// Handle with click event
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.dropdownIsOpen = false;
|
||||
}}
|
||||
>
|
||||
</sl-icon-button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
private repositionDropdown() {
|
||||
const { x, y } = this.dropdownTrigger.getBoundingClientRect();
|
||||
this.dropdown.style.left = `${x + window.scrollX}px`;
|
||||
|
@ -623,15 +623,19 @@ export class CollectionDetail extends LiteElement {
|
||||
orgSlug=${this.appState.orgSlug || ""}
|
||||
.crawl=${item}
|
||||
>
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--warning)"
|
||||
@click=${() => this.removeArchivedItem(item.id, idx)}
|
||||
>
|
||||
<sl-icon name="folder-minus" slot="prefix"></sl-icon>
|
||||
${msg("Remove from Collection")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
${when(
|
||||
this.isCrawler,
|
||||
() =>
|
||||
html` <sl-menu slot="menu">
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--warning)"
|
||||
@click=${() => this.removeArchivedItem(item.id, idx)}
|
||||
>
|
||||
<sl-icon name="folder-minus" slot="prefix"></sl-icon>
|
||||
${msg("Remove from Collection")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>`
|
||||
)}
|
||||
</btrix-crawl-list-item>
|
||||
`;
|
||||
|
||||
|
@ -447,28 +447,11 @@ export class CrawlsList extends LiteElement {
|
||||
orgSlug=${this.appState.orgSlug || ""}
|
||||
.crawl=${item}
|
||||
>
|
||||
<sl-menu slot="menu">
|
||||
${when(
|
||||
this.isCrawler,
|
||||
this.crawlerMenuItemsRenderer(item),
|
||||
() => html`
|
||||
<sl-menu-item
|
||||
@click=${() =>
|
||||
this.navTo(
|
||||
`${this.orgBasePath}/items/${
|
||||
item.type === "upload" ? "upload" : "crawl"
|
||||
}/${item.id}`
|
||||
)}
|
||||
>
|
||||
${msg("View Crawl Details")}
|
||||
</sl-menu-item>
|
||||
`
|
||||
)}
|
||||
</sl-menu>
|
||||
<sl-menu slot="menu"> ${this.crawlerMenuItemsRenderer(item)} </sl-menu>
|
||||
</btrix-crawl-list-item>
|
||||
`;
|
||||
|
||||
private crawlerMenuItemsRenderer = (item: Crawl) => () =>
|
||||
private crawlerMenuItemsRenderer = (item: Crawl) =>
|
||||
// HACK shoelace doesn't current have a way to override non-hover
|
||||
// color without resetting the --sl-color-neutral-700 variable
|
||||
html`
|
||||
|
@ -36,6 +36,12 @@ export class Dashboard extends LiteElement {
|
||||
@property({ type: Object })
|
||||
authState!: AuthState;
|
||||
|
||||
@property({ type: Boolean })
|
||||
isCrawler?: boolean;
|
||||
|
||||
@property({ type: Boolean })
|
||||
isAdmin?: boolean;
|
||||
|
||||
@property({ type: String })
|
||||
orgId!: string;
|
||||
|
||||
@ -96,48 +102,55 @@ export class Dashboard extends LiteElement {
|
||||
<h1 class="min-w-0 text-xl font-semibold leading-8 mr-auto">
|
||||
${this.org?.name}
|
||||
</h1>
|
||||
<sl-icon-button
|
||||
href=${`${this.orgBasePath}/settings`}
|
||||
class="text-lg"
|
||||
name="gear"
|
||||
label="Edit org settings"
|
||||
@click=${this.navLink}
|
||||
></sl-icon-button>
|
||||
<sl-dropdown
|
||||
distance="4"
|
||||
placement="bottom-end"
|
||||
@sl-select=${(e: SlSelectEvent) => {
|
||||
this.dispatchEvent(
|
||||
<SelectNewDialogEvent>new CustomEvent("select-new-dialog", {
|
||||
detail: e.detail.item.value,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<sl-button slot="trigger" size="small" caret>
|
||||
<sl-icon slot="prefix" name="plus-lg"></sl-icon>
|
||||
${msg("Create New...")}
|
||||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="workflow"
|
||||
>${msg("Crawl Workflow")}</sl-menu-item
|
||||
>
|
||||
<sl-menu-item
|
||||
value="upload"
|
||||
?disabled=${!this.metrics || quotaReached}
|
||||
>${msg("Upload")}</sl-menu-item
|
||||
>
|
||||
<sl-menu-item value="collection">
|
||||
${msg("Collection")}
|
||||
</sl-menu-item>
|
||||
<sl-menu-item
|
||||
value="browser-profile"
|
||||
?disabled=${!this.metrics || quotaReached}
|
||||
>
|
||||
${msg("Browser Profile")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
${when(
|
||||
this.isAdmin,
|
||||
() =>
|
||||
html` <sl-icon-button
|
||||
href=${`${this.orgBasePath}/settings`}
|
||||
class="text-lg"
|
||||
name="gear"
|
||||
label="Edit org settings"
|
||||
@click=${this.navLink}
|
||||
></sl-icon-button>`
|
||||
)}
|
||||
${when(
|
||||
this.isCrawler,
|
||||
() => html` <sl-dropdown
|
||||
distance="4"
|
||||
placement="bottom-end"
|
||||
@sl-select=${(e: SlSelectEvent) => {
|
||||
this.dispatchEvent(
|
||||
<SelectNewDialogEvent>new CustomEvent("select-new-dialog", {
|
||||
detail: e.detail.item.value,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<sl-button slot="trigger" size="small" caret>
|
||||
<sl-icon slot="prefix" name="plus-lg"></sl-icon>
|
||||
${msg("Create New...")}
|
||||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="workflow"
|
||||
>${msg("Crawl Workflow")}</sl-menu-item
|
||||
>
|
||||
<sl-menu-item
|
||||
value="upload"
|
||||
?disabled=${!this.metrics || quotaReached}
|
||||
>${msg("Upload")}</sl-menu-item
|
||||
>
|
||||
<sl-menu-item value="collection">
|
||||
${msg("Collection")}
|
||||
</sl-menu-item>
|
||||
<sl-menu-item
|
||||
value="browser-profile"
|
||||
?disabled=${!this.metrics || quotaReached}
|
||||
>
|
||||
${msg("Browser Profile")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>`
|
||||
)}
|
||||
</header>
|
||||
<main>
|
||||
<div class="flex flex-col md:flex-row gap-6">
|
||||
|
@ -455,6 +455,8 @@ export class Org extends LiteElement {
|
||||
.authState=${this.authState!}
|
||||
orgId=${this.orgId}
|
||||
.org=${this.org || null}
|
||||
?isCrawler=${this.isCrawler}
|
||||
?isAdmin=${this.isAdmin}
|
||||
@select-new-dialog=${this.onSelectNewDialog}
|
||||
></btrix-dashboard>
|
||||
`;
|
||||
|
@ -448,7 +448,7 @@ export class WorkflowDetail extends LiteElement {
|
||||
)}
|
||||
</h3>`;
|
||||
}
|
||||
if (this.activePanel === "settings") {
|
||||
if (this.activePanel === "settings" && this.isCrawler == true) {
|
||||
return html` <h3>${this.tabLabels[this.activePanel]}</h3>
|
||||
<sl-icon-button
|
||||
name="gear"
|
||||
@ -460,7 +460,7 @@ export class WorkflowDetail extends LiteElement {
|
||||
>
|
||||
</sl-icon-button>`;
|
||||
}
|
||||
if (this.activePanel === "watch") {
|
||||
if (this.activePanel === "watch" && this.isCrawler == true) {
|
||||
return html` <h3>${this.tabLabels[this.activePanel]}</h3>
|
||||
<sl-button
|
||||
size="small"
|
||||
@ -836,21 +836,22 @@ export class WorkflowDetail extends LiteElement {
|
||||
this.crawls,
|
||||
() =>
|
||||
this.crawls!.items.map(
|
||||
(crawl: Crawl) => html`
|
||||
<btrix-crawl-list-item
|
||||
orgSlug=${this.appState.orgSlug || ""}
|
||||
.crawl=${crawl}
|
||||
>
|
||||
<sl-format-date
|
||||
slot="id"
|
||||
date=${`${crawl.started}Z`}
|
||||
month="2-digit"
|
||||
day="2-digit"
|
||||
year="2-digit"
|
||||
hour="2-digit"
|
||||
minute="2-digit"
|
||||
></sl-format-date>
|
||||
<sl-menu slot="menu">
|
||||
(crawl: Crawl) => html` <btrix-crawl-list-item
|
||||
orgSlug=${this.appState.orgSlug || ""}
|
||||
.crawl=${crawl}
|
||||
>
|
||||
<sl-format-date
|
||||
slot="id"
|
||||
date=${`${crawl.started}Z`}
|
||||
month="2-digit"
|
||||
day="2-digit"
|
||||
year="2-digit"
|
||||
hour="2-digit"
|
||||
minute="2-digit"
|
||||
></sl-format-date>
|
||||
${when(
|
||||
this.isCrawler,
|
||||
() => html` <sl-menu slot="menu">
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--danger)"
|
||||
@click=${() => this.deleteCrawl(crawl)}
|
||||
@ -858,9 +859,9 @@ export class WorkflowDetail extends LiteElement {
|
||||
<sl-icon name="trash3" slot="prefix"></sl-icon>
|
||||
${msg("Delete Crawl")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</btrix-crawl-list-item>
|
||||
`
|
||||
</sl-menu>`
|
||||
)}</btrix-crawl-list-item
|
||||
>`
|
||||
),
|
||||
() => html`<div
|
||||
class="w-full flex items-center justify-center my-24 text-3xl"
|
||||
@ -1037,24 +1038,26 @@ export class WorkflowDetail extends LiteElement {
|
||||
>
|
||||
`
|
||||
)}
|
||||
|
||||
<sl-tooltip
|
||||
content=${msg(
|
||||
"Org Storage Full or Monthly Execution Minutes Reached"
|
||||
)}
|
||||
?disabled=${!this.orgStorageQuotaReached &&
|
||||
!this.orgExecutionMinutesQuotaReached}
|
||||
>
|
||||
<sl-button
|
||||
size="small"
|
||||
?disabled=${this.orgStorageQuotaReached ||
|
||||
this.orgExecutionMinutesQuotaReached}
|
||||
@click=${() => this.runNow()}
|
||||
${when(
|
||||
this.isCrawler,
|
||||
() => html` <sl-tooltip
|
||||
content=${msg(
|
||||
"Org Storage Full or Monthly Execution Minutes Reached"
|
||||
)}
|
||||
?disabled=${!this.orgStorageQuotaReached &&
|
||||
!this.orgExecutionMinutesQuotaReached}
|
||||
>
|
||||
<sl-icon name="play" slot="prefix"></sl-icon>
|
||||
${msg("Run Crawl")}
|
||||
</sl-button>
|
||||
</sl-tooltip>
|
||||
<sl-button
|
||||
size="small"
|
||||
?disabled=${this.orgStorageQuotaReached ||
|
||||
this.orgExecutionMinutesQuotaReached}
|
||||
@click=${() => this.runNow()}
|
||||
>
|
||||
<sl-icon name="play" slot="prefix"></sl-icon>
|
||||
${msg("Run Crawl")}
|
||||
</sl-button>
|
||||
</sl-tooltip>`
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
@ -421,7 +421,7 @@ export class WorkflowsList extends LiteElement {
|
||||
private renderMenuItems(workflow: ListWorkflow) {
|
||||
return html`
|
||||
${when(
|
||||
workflow.isCrawlRunning,
|
||||
workflow.isCrawlRunning && this.isCrawler,
|
||||
// HACK shoelace doesn't current have a way to override non-hover
|
||||
// color without resetting the --sl-color-neutral-700 variable
|
||||
() => html`
|
||||
@ -439,7 +439,10 @@ export class WorkflowsList extends LiteElement {
|
||||
<sl-icon name="x-octagon" slot="prefix"></sl-icon>
|
||||
${msg("Cancel & Discard Crawl")}
|
||||
</sl-menu-item>
|
||||
`,
|
||||
`
|
||||
)}
|
||||
${when(
|
||||
this.isCrawler && !workflow.isCrawlRunning,
|
||||
() => html`
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--success)"
|
||||
@ -453,7 +456,7 @@ export class WorkflowsList extends LiteElement {
|
||||
`
|
||||
)}
|
||||
${when(
|
||||
workflow.isCrawlRunning,
|
||||
workflow.isCrawlRunning && this.isCrawler,
|
||||
// HACK shoelace doesn't current have a way to override non-hover
|
||||
// color without resetting the --sl-color-neutral-700 variable
|
||||
() => html`
|
||||
@ -485,14 +488,19 @@ export class WorkflowsList extends LiteElement {
|
||||
<sl-divider></sl-divider>
|
||||
`
|
||||
)}
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
@click=${() =>
|
||||
this.navTo(`${this.orgBasePath}/workflows/crawl/${workflow.id}?edit`)}
|
||||
>
|
||||
<sl-icon name="gear" slot="prefix"></sl-icon>
|
||||
${msg("Edit Workflow Settings")}
|
||||
</sl-menu-item>
|
||||
${when(
|
||||
this.isCrawler,
|
||||
() => html` <sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
@click=${() =>
|
||||
this.navTo(
|
||||
`${this.orgBasePath}/workflows/crawl/${workflow.id}?edit`
|
||||
)}
|
||||
>
|
||||
<sl-icon name="gear" slot="prefix"></sl-icon>
|
||||
${msg("Edit Workflow Settings")}
|
||||
</sl-menu-item>`
|
||||
)}
|
||||
<sl-menu-item
|
||||
@click=${() => CopyButton.copyToClipboard(workflow.tags.join(", "))}
|
||||
?disabled=${!workflow.tags.length}
|
||||
@ -500,28 +508,15 @@ export class WorkflowsList extends LiteElement {
|
||||
<sl-icon name="tags" slot="prefix"></sl-icon>
|
||||
${msg("Copy Tags")}
|
||||
</sl-menu-item>
|
||||
<sl-menu-item @click=${() => this.duplicateConfig(workflow)}>
|
||||
<sl-icon name="files" slot="prefix"></sl-icon>
|
||||
${msg("Duplicate Workflow")}
|
||||
</sl-menu-item>
|
||||
${when(workflow.isCrawlRunning, () => {
|
||||
const shouldDeactivate = workflow.crawlCount && !workflow.inactive;
|
||||
return html`
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--danger)"
|
||||
@click=${() =>
|
||||
shouldDeactivate
|
||||
? this.deactivate(workflow)
|
||||
: this.delete(workflow)}
|
||||
>
|
||||
<sl-icon name="trash3" slot="prefix"></sl-icon>
|
||||
${shouldDeactivate
|
||||
? msg("Deactivate Workflow")
|
||||
: msg("Delete Workflow")}
|
||||
</sl-menu-item>
|
||||
`;
|
||||
})}
|
||||
${when(
|
||||
this.isCrawler,
|
||||
() => html` <sl-menu-item
|
||||
@click=${() => this.duplicateConfig(workflow)}
|
||||
>
|
||||
<sl-icon name="files" slot="prefix"></sl-icon>
|
||||
${msg("Duplicate Workflow")}
|
||||
</sl-menu-item>`
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user