Crawl workflow detail page improvements (#823)
Resolves #817 - Adds relevant action buttons to each Workflow detail tab header - Adds "Delete" action menu item to crawls in Crawls tab - Prevent automatically switching to "Watch" tab after running crawl from detail page - Removes "Stop" confirmation prompt and only shows "Cancel" confirmation prompt if there are one or more pages crawled - Replaces "Cancel" confirmation prompt with web component dialog (partially addresses Switch to in-page dialogue boxes #619) - Fixes hash routing to fix going back with browser back button
This commit is contained in:
parent
aae0e6590e
commit
0d23b45dac
@ -20,8 +20,9 @@ import {
|
||||
} from "lit/decorators.js";
|
||||
import { when } from "lit/directives/when.js";
|
||||
import { msg, localized, str } from "@lit/localize";
|
||||
import type { SlIconButton, SlMenu } from "@shoelace-style/shoelace";
|
||||
import type { SlMenu } from "@shoelace-style/shoelace";
|
||||
|
||||
import type { Button } from "./button";
|
||||
import { RelativeDuration } from "./relative-duration";
|
||||
import type { Crawl } from "../types/crawler";
|
||||
import { srOnly, truncate, dropdown } from "../utils/css";
|
||||
@ -190,7 +191,7 @@ export class CrawlListItem extends LitElement {
|
||||
dropdown!: HTMLElement;
|
||||
|
||||
@query(".dropdownTrigger")
|
||||
dropdownTrigger!: SlIconButton;
|
||||
dropdownTrigger!: Button;
|
||||
|
||||
@queryAssignedElements({ selector: "sl-menu", slot: "menu" })
|
||||
private menuArr!: Array<SlMenu>;
|
||||
@ -336,10 +337,10 @@ export class CrawlListItem extends LitElement {
|
||||
</div>
|
||||
<div class="col action">
|
||||
<slot name="menuTrigger">
|
||||
<sl-icon-button
|
||||
<btrix-button
|
||||
class="dropdownTrigger"
|
||||
name="three-dots-vertical"
|
||||
label=${msg("Actions")}
|
||||
icon
|
||||
@click=${(e: MouseEvent) => {
|
||||
// Prevent anchor link default behavior
|
||||
e.preventDefault();
|
||||
@ -361,7 +362,9 @@ export class CrawlListItem extends LitElement {
|
||||
}
|
||||
this.dropdownIsOpen = false;
|
||||
}}
|
||||
></sl-icon-button>
|
||||
>
|
||||
<sl-icon name="three-dots-vertical"></sl-icon>
|
||||
</btrix-button>
|
||||
</slot>
|
||||
</div>
|
||||
</a>`;
|
||||
@ -443,6 +446,11 @@ export class CrawlList extends LitElement {
|
||||
columnCss,
|
||||
hostVars,
|
||||
css`
|
||||
.listHeader, .list {
|
||||
margin-left: var(--row-offset);
|
||||
margin-right: var(--row-offset);
|
||||
}
|
||||
|
||||
.listHeader {
|
||||
line-height: 1;
|
||||
}
|
||||
@ -451,8 +459,6 @@ export class CrawlList extends LitElement {
|
||||
border: 1px solid var(--sl-panel-border-color);
|
||||
border-radius: var(--sl-border-radius-medium);
|
||||
overflow: hidden;
|
||||
margin-left: var(--row-offset);
|
||||
margin-right: var(--row-offset);
|
||||
}
|
||||
|
||||
.row {
|
||||
|
@ -253,7 +253,9 @@ export class WorkflowListItem extends LitElement {
|
||||
return html`<a
|
||||
class="item row"
|
||||
role="button"
|
||||
href=${`/orgs/${this.workflow?.oid}/workflows/crawl/${this.workflow?.id}`}
|
||||
href=${`/orgs/${this.workflow?.oid}/workflows/crawl/${
|
||||
this.workflow?.id
|
||||
}#${this.workflow?.currCrawlId ? "watch" : "artifacts"}`}
|
||||
@click=${async (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
await this.updateComplete;
|
||||
|
@ -25,7 +25,7 @@ import { DASHBOARD_ROUTE } from "../../routes";
|
||||
|
||||
const SECTIONS = ["artifacts", "watch", "settings"] as const;
|
||||
type Tab = (typeof SECTIONS)[number];
|
||||
|
||||
const DEFAULT_SECTION: Tab = "artifacts";
|
||||
const POLL_INTERVAL_SECONDS = 10;
|
||||
|
||||
/**
|
||||
@ -75,6 +75,12 @@ export class WorkflowDetail extends LiteElement {
|
||||
@state()
|
||||
private isDialogVisible: boolean = false;
|
||||
|
||||
@state()
|
||||
private isAttemptCancel: boolean = false;
|
||||
|
||||
@state()
|
||||
private isCancelingOrStoppingCrawl: boolean = false;
|
||||
|
||||
@state()
|
||||
private filterBy: Partial<Record<keyof Crawl, any>> = {};
|
||||
|
||||
@ -106,10 +112,7 @@ export class WorkflowDetail extends LiteElement {
|
||||
|
||||
connectedCallback(): void {
|
||||
// Set initial active section and dialog based on URL #hash value
|
||||
const hash = window.location.hash.slice(1);
|
||||
if (SECTIONS.includes(hash as any)) {
|
||||
this.activePanel = hash as Tab;
|
||||
}
|
||||
this.getActivePanelFromHash();
|
||||
|
||||
if (
|
||||
this.openDialogName &&
|
||||
@ -118,11 +121,13 @@ export class WorkflowDetail extends LiteElement {
|
||||
this.isDialogVisible = true;
|
||||
}
|
||||
super.connectedCallback();
|
||||
window.addEventListener("hashchange", this.getActivePanelFromHash);
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
this.stopPoll();
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("hashchange", this.getActivePanelFromHash);
|
||||
}
|
||||
|
||||
willUpdate(changedProperties: Map<string, any>) {
|
||||
@ -143,41 +148,51 @@ export class WorkflowDetail extends LiteElement {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.activePanel !== window.location.hash.slice(1)) {
|
||||
window.location.hash = `#${this.activePanel}`;
|
||||
}
|
||||
|
||||
if (this.activePanel === "artifacts") {
|
||||
this.fetchCrawls();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updated(changedProperties: Map<string, any>) {
|
||||
const prevWorkflow = changedProperties.get("workflow");
|
||||
if (
|
||||
prevWorkflow?.currCrawlId &&
|
||||
!this.workflow?.currCrawlId &&
|
||||
this.activePanel === "watch"
|
||||
) {
|
||||
this.goToTab(DEFAULT_SECTION, { replace: true });
|
||||
}
|
||||
}
|
||||
|
||||
private getActivePanelFromHash = () => {
|
||||
const hashValue = window.location.hash.slice(1);
|
||||
if (SECTIONS.includes(hashValue as any)) {
|
||||
this.activePanel = hashValue as Tab;
|
||||
} else {
|
||||
this.goToTab(DEFAULT_SECTION, { replace: true });
|
||||
}
|
||||
};
|
||||
|
||||
private goToTab(tab: Tab, { replace = false } = {}) {
|
||||
const path = `${window.location.href.split("#")[0]}#${tab}`;
|
||||
if (replace) {
|
||||
window.history.replaceState(null, "", path);
|
||||
} else {
|
||||
window.history.pushState(null, "", path);
|
||||
}
|
||||
this.activePanel = tab;
|
||||
}
|
||||
|
||||
private async fetchWorkflow() {
|
||||
this.stopPoll();
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
this.workflow = await this.getWorkflow();
|
||||
let activePanel = this.activePanel;
|
||||
|
||||
if (!this.activePanel) {
|
||||
if (this.workflow.currCrawlId) {
|
||||
activePanel = "watch";
|
||||
} else {
|
||||
activePanel = "artifacts";
|
||||
}
|
||||
if (this.workflow.currCrawlId) {
|
||||
this.fetchCurrentCrawl();
|
||||
}
|
||||
|
||||
if (activePanel === "watch") {
|
||||
if (this.workflow.currCrawlId) {
|
||||
this.fetchCurrentCrawl();
|
||||
} else {
|
||||
activePanel = "artifacts";
|
||||
}
|
||||
}
|
||||
|
||||
this.activePanel = activePanel;
|
||||
} catch (e: any) {
|
||||
this.notify({
|
||||
message:
|
||||
@ -249,6 +264,31 @@ export class WorkflowDetail extends LiteElement {
|
||||
</div>`
|
||||
)}
|
||||
</div>
|
||||
|
||||
<btrix-dialog
|
||||
label=${msg("Cancel Crawl?")}
|
||||
?open=${this.isAttemptCancel}
|
||||
@sl-request-close=${() => (this.isAttemptCancel = false)}
|
||||
>
|
||||
${msg(
|
||||
"Canceling will discard all pages crawled. Are you sure you want to discard them?"
|
||||
)}
|
||||
<div slot="footer" class="flex justify-between">
|
||||
<sl-button size="small" @click=${() => (this.isAttemptCancel = false)}
|
||||
>Keep Crawling</sl-button
|
||||
>
|
||||
<sl-button
|
||||
size="small"
|
||||
variant="primary"
|
||||
?loading=${this.isCancelingOrStoppingCrawl}
|
||||
@click=${async () => {
|
||||
await this.cancel();
|
||||
this.isAttemptCancel = false;
|
||||
}}
|
||||
>Cancel & Discard Crawl</sl-button
|
||||
>
|
||||
</div>
|
||||
</btrix-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -313,26 +353,71 @@ export class WorkflowDetail extends LiteElement {
|
||||
if (!this.activePanel) return;
|
||||
if (this.activePanel === "artifacts") {
|
||||
return html`<h3>
|
||||
${this.workflow?.crawlCount === 1
|
||||
? msg(str`${this.workflow?.crawlCount} Crawl`)
|
||||
: msg(str`${this.workflow?.crawlCount} Crawls`)}
|
||||
</h3>`;
|
||||
${this.workflow?.crawlCount === 1
|
||||
? msg(str`${this.workflow?.crawlCount} Crawl`)
|
||||
: msg(str`${this.workflow?.crawlCount} Crawls`)}
|
||||
</h3>
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => this.runNow()}
|
||||
?disabled=${this.workflow?.currCrawlId}
|
||||
>
|
||||
<sl-icon name="play" slot="prefix"></sl-icon>
|
||||
<span>${msg("Run")}</span>
|
||||
</sl-button>`;
|
||||
}
|
||||
|
||||
if (this.activePanel === "watch") {
|
||||
if (this.activePanel === "settings") {
|
||||
return html` <h3>${this.tabLabels[this.activePanel]}</h3>
|
||||
<sl-button
|
||||
size="small"
|
||||
?disabled=${this.workflow?.currCrawlState !== "running"}
|
||||
@click=${() => {
|
||||
this.openDialogName = "scale";
|
||||
this.isDialogVisible = true;
|
||||
}}
|
||||
@click=${() =>
|
||||
this.navTo(
|
||||
`/orgs/${this.workflow?.oid}/workflows/crawl/${this.workflow?.id}?edit`
|
||||
)}
|
||||
>
|
||||
<sl-icon name="plus-slash-minus" slot="prefix"></sl-icon>
|
||||
<span> ${msg("Crawler Instances")} </span>
|
||||
<sl-icon name="gear" slot="prefix"></sl-icon>
|
||||
<span>${msg("Edit")}</span>
|
||||
</sl-button>`;
|
||||
}
|
||||
if (this.activePanel === "watch") {
|
||||
return html` <h3>${this.tabLabels[this.activePanel]}</h3>
|
||||
<sl-button-group>
|
||||
<sl-button
|
||||
size="small"
|
||||
?disabled=${this.workflow?.currCrawlState !== "running"}
|
||||
@click=${() => {
|
||||
this.openDialogName = "scale";
|
||||
this.isDialogVisible = true;
|
||||
}}
|
||||
>
|
||||
<sl-icon name="plus-slash-minus" slot="prefix"></sl-icon>
|
||||
<span> ${msg("Edit Instances")} </span>
|
||||
</sl-button>
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => this.stop()}
|
||||
?disabled=${!this.workflow?.currCrawlId ||
|
||||
this.isCancelingOrStoppingCrawl ||
|
||||
this.workflow?.currCrawlState === "stopping"}
|
||||
>
|
||||
<sl-icon name="dash-circle" slot="prefix"></sl-icon>
|
||||
<span>${msg("Stop")}</span>
|
||||
</sl-button>
|
||||
<sl-button
|
||||
size="small"
|
||||
@click=${() => this.requestCancelCrawl()}
|
||||
?disabled=${!this.workflow?.currCrawlId ||
|
||||
this.isCancelingOrStoppingCrawl}
|
||||
>
|
||||
<sl-icon
|
||||
name="x-octagon"
|
||||
slot="prefix"
|
||||
class="text-danger"
|
||||
></sl-icon>
|
||||
<span class="text-danger">${msg("Cancel")}</span>
|
||||
</sl-button>
|
||||
</sl-button-group>`;
|
||||
}
|
||||
|
||||
return html`<h3>${this.tabLabels[this.activePanel]}</h3>`;
|
||||
}
|
||||
@ -346,7 +431,6 @@ export class WorkflowDetail extends LiteElement {
|
||||
class="block font-medium rounded-sm mb-2 mr-2 p-2 transition-all ${isActive
|
||||
? "text-blue-600 bg-blue-50 shadow-sm"
|
||||
: "text-neutral-600 hover:bg-neutral-50"}"
|
||||
@click=${() => (this.activePanel = tabName)}
|
||||
aria-selected=${isActive}
|
||||
>
|
||||
${this.tabLabels[tabName]}
|
||||
@ -384,7 +468,7 @@ export class WorkflowDetail extends LiteElement {
|
||||
const workflow = this.workflow;
|
||||
|
||||
return html`
|
||||
<sl-dropdown placement="bottom-end" distance="4">
|
||||
<sl-dropdown placement="bottom-end" distance="4" hoist>
|
||||
<sl-button slot="trigger" size="small" caret
|
||||
>${msg("Actions")}</sl-button
|
||||
>
|
||||
@ -396,14 +480,16 @@ export class WorkflowDetail extends LiteElement {
|
||||
() => html`
|
||||
<sl-menu-item
|
||||
@click=${() => this.stop()}
|
||||
?disabled=${workflow.currCrawlState === "stopping"}
|
||||
?disabled=${workflow.currCrawlState === "stopping" ||
|
||||
this.isCancelingOrStoppingCrawl}
|
||||
>
|
||||
<sl-icon name="dash-circle" slot="prefix"></sl-icon>
|
||||
${msg("Stop Crawl")}
|
||||
</sl-menu-item>
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--danger)"
|
||||
@click=${() => this.cancel()}
|
||||
?disabled=${this.isCancelingOrStoppingCrawl}
|
||||
@click=${() => this.requestCancelCrawl()}
|
||||
>
|
||||
<sl-icon name="x-octagon" slot="prefix"></sl-icon>
|
||||
${msg("Cancel & Discard Crawl")}
|
||||
@ -624,8 +710,15 @@ export class WorkflowDetail extends LiteElement {
|
||||
hour="2-digit"
|
||||
minute="2-digit"
|
||||
></sl-format-date>
|
||||
<!-- Hide menu trigger: -->
|
||||
<div slot="menuTrigger" role="none"></div>
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item
|
||||
style="--sl-color-neutral-700: var(--danger)"
|
||||
@click=${() => this.deleteCrawl(crawl)}
|
||||
>
|
||||
<sl-icon name="trash" slot="prefix"></sl-icon>
|
||||
${msg("Delete Crawl")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</btrix-crawl-list-item>
|
||||
`
|
||||
),
|
||||
@ -887,6 +980,15 @@ export class WorkflowDetail extends LiteElement {
|
||||
this.fetchWorkflow();
|
||||
}
|
||||
|
||||
private requestCancelCrawl() {
|
||||
const pagesDone = this.currentCrawl?.stats?.done;
|
||||
if (pagesDone && +pagesDone > 0) {
|
||||
this.isAttemptCancel = true;
|
||||
} else {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private async scale(value: Crawl["scale"]) {
|
||||
if (!this.workflow?.currCrawlId) return;
|
||||
this.isSubmittingUpdate = true;
|
||||
@ -1081,7 +1183,10 @@ export class WorkflowDetail extends LiteElement {
|
||||
|
||||
private async cancel() {
|
||||
if (!this.workflow?.currCrawlId) return;
|
||||
if (window.confirm(msg("Are you sure you want to cancel the crawl?"))) {
|
||||
|
||||
this.isCancelingOrStoppingCrawl = true;
|
||||
|
||||
try {
|
||||
const data = await this.apiFetch(
|
||||
`/orgs/${this.orgId}/crawls/${this.workflow.currCrawlId}/cancel`,
|
||||
this.authState!,
|
||||
@ -1092,18 +1197,25 @@ export class WorkflowDetail extends LiteElement {
|
||||
if (data.success === true) {
|
||||
this.fetchWorkflow();
|
||||
} else {
|
||||
this.notify({
|
||||
message: msg("Something went wrong, couldn't cancel crawl."),
|
||||
variant: "danger",
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
throw data;
|
||||
}
|
||||
} catch {
|
||||
this.notify({
|
||||
message: msg("Something went wrong, couldn't cancel crawl."),
|
||||
variant: "danger",
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
}
|
||||
|
||||
this.isCancelingOrStoppingCrawl = false;
|
||||
}
|
||||
|
||||
private async stop() {
|
||||
if (!this.workflow?.currCrawlId) return;
|
||||
if (window.confirm(msg("Are you sure you want to stop the crawl?"))) {
|
||||
|
||||
this.isCancelingOrStoppingCrawl = true;
|
||||
|
||||
try {
|
||||
const data = await this.apiFetch(
|
||||
`/orgs/${this.orgId}/crawls/${this.workflow.currCrawlId}/stop`,
|
||||
this.authState!,
|
||||
@ -1114,13 +1226,17 @@ export class WorkflowDetail extends LiteElement {
|
||||
if (data.success === true) {
|
||||
this.fetchWorkflow();
|
||||
} else {
|
||||
this.notify({
|
||||
message: msg("Something went wrong, couldn't stop crawl."),
|
||||
variant: "danger",
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
throw data;
|
||||
}
|
||||
} catch {
|
||||
this.notify({
|
||||
message: msg("Something went wrong, couldn't stop crawl."),
|
||||
variant: "danger",
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
}
|
||||
|
||||
this.isCancelingOrStoppingCrawl = false;
|
||||
}
|
||||
|
||||
private async runNow(): Promise<void> {
|
||||
@ -1132,7 +1248,6 @@ export class WorkflowDetail extends LiteElement {
|
||||
method: "POST",
|
||||
}
|
||||
);
|
||||
this.activePanel = "watch";
|
||||
this.fetchWorkflow();
|
||||
|
||||
this.notify({
|
||||
@ -1141,8 +1256,8 @@ export class WorkflowDetail extends LiteElement {
|
||||
<br />
|
||||
<a
|
||||
class="underline hover:no-underline"
|
||||
href="/orgs/${this.orgId}/workflows/crawl/${this.workflowId}"
|
||||
@click="${this.navLink.bind(this)}"
|
||||
href="/orgs/${this.orgId}/workflows/crawl/${this
|
||||
.workflowId}#watch"
|
||||
>Watch crawl</a
|
||||
>`
|
||||
),
|
||||
@ -1158,6 +1273,37 @@ export class WorkflowDetail extends LiteElement {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteCrawl(crawl: Crawl) {
|
||||
try {
|
||||
const data = await this.apiFetch(
|
||||
`/orgs/${crawl.oid}/crawls/delete`,
|
||||
this.authState!,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
crawl_ids: [crawl.id],
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
this.crawls = this.crawls!.filter((c) => c.id !== crawl.id);
|
||||
this.notify({
|
||||
message: msg(`Successfully deleted crawl`),
|
||||
variant: "success",
|
||||
icon: "check2-circle",
|
||||
});
|
||||
this.fetchCrawls();
|
||||
} catch (e: any) {
|
||||
this.notify({
|
||||
message:
|
||||
(e.isApiError && e.message) ||
|
||||
msg("Sorry, couldn't run crawl at this time."),
|
||||
variant: "danger",
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("btrix-workflow-detail", WorkflowDetail);
|
||||
|
@ -227,40 +227,40 @@ export class WorkflowsList extends LiteElement {
|
||||
|
||||
<div class="flex items-center w-full md:w-fit">
|
||||
<div class="whitespace-nowrap text-sm text-0-500 mr-2">
|
||||
${msg("Sort by:")}
|
||||
</div>
|
||||
<sl-select
|
||||
class="flex-1 md:min-w-[9.2rem]"
|
||||
size="small"
|
||||
pill
|
||||
value=${this.orderBy.field}
|
||||
@sl-select=${(e: any) => {
|
||||
const field = e.detail.item.value as SortField;
|
||||
this.orderBy = {
|
||||
field: field,
|
||||
direction:
|
||||
sortableFields[field].defaultDirection ||
|
||||
this.orderBy.direction,
|
||||
};
|
||||
}}
|
||||
>
|
||||
${Object.entries(sortableFields).map(
|
||||
([value, { label }]) => html`
|
||||
<sl-menu-item value=${value}>${label}</sl-menu-item>
|
||||
`
|
||||
)}
|
||||
</sl-select>
|
||||
<sl-icon-button
|
||||
name="arrow-down-up"
|
||||
label=${msg("Reverse sort")}
|
||||
@click=${() => {
|
||||
this.orderBy = {
|
||||
...this.orderBy,
|
||||
direction: this.orderBy.direction === "asc" ? "desc" : "asc",
|
||||
};
|
||||
}}
|
||||
></sl-icon-button>
|
||||
${msg("Sort by:")}
|
||||
</div>
|
||||
<sl-select
|
||||
class="flex-1 md:min-w-[9.2rem]"
|
||||
size="small"
|
||||
pill
|
||||
value=${this.orderBy.field}
|
||||
@sl-select=${(e: any) => {
|
||||
const field = e.detail.item.value as SortField;
|
||||
this.orderBy = {
|
||||
field: field,
|
||||
direction:
|
||||
sortableFields[field].defaultDirection ||
|
||||
this.orderBy.direction,
|
||||
};
|
||||
}}
|
||||
>
|
||||
${Object.entries(sortableFields).map(
|
||||
([value, { label }]) => html`
|
||||
<sl-menu-item value=${value}>${label}</sl-menu-item>
|
||||
`
|
||||
)}
|
||||
</sl-select>
|
||||
<sl-icon-button
|
||||
name="arrow-down-up"
|
||||
label=${msg("Reverse sort")}
|
||||
@click=${() => {
|
||||
this.orderBy = {
|
||||
...this.orderBy,
|
||||
direction: this.orderBy.direction === "asc" ? "desc" : "asc",
|
||||
};
|
||||
}}
|
||||
></sl-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-between">
|
||||
@ -298,7 +298,9 @@ export class WorkflowsList extends LiteElement {
|
||||
</div>
|
||||
<div class="flex items-center justify-end">
|
||||
<label>
|
||||
<span class="text-neutral-500 mr-1 text-xs">${msg("Show Only Mine")}</span>
|
||||
<span class="text-neutral-500 mr-1 text-xs"
|
||||
>${msg("Show Only Mine")}</span
|
||||
>
|
||||
<sl-switch
|
||||
@sl-change=${(e: CustomEvent) =>
|
||||
(this.filterByCurrentUser = (e.target as SlCheckbox).checked)}
|
||||
@ -655,7 +657,7 @@ export class WorkflowsList extends LiteElement {
|
||||
<br />
|
||||
<a
|
||||
class="underline hover:no-underline"
|
||||
href="/orgs/${this.orgId}/workflows/crawl/${workflow.id}"
|
||||
href="/orgs/${this.orgId}/workflows/crawl/${workflow.id}#watch"
|
||||
@click=${this.navLink.bind(this)}
|
||||
>Watch crawl</a
|
||||
>`
|
||||
|
Loading…
Reference in New Issue
Block a user