feat: Update superadmin active crawls view (#2618)

- Renames "Running Crawls" -> "Active Crawls" in superadmin app bar
- Shows number of active crawls next to link
- Refreshes active crawl list every 30 seconds
- Standardizes browser title
This commit is contained in:
sua yoo 2025-05-26 12:22:38 -07:00 committed by GitHub
parent cb50c7c2c2
commit 7674672027
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 76 additions and 16 deletions

View File

@ -3,6 +3,7 @@ import "./global";
import { provide } from "@lit/context";
import { localized, msg, str } from "@lit/localize";
import { Task } from "@lit/task";
import type {
SlDialog,
SlDrawer,
@ -14,6 +15,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
import { until } from "lit/directives/until.js";
import { when } from "lit/directives/when.js";
import isEqual from "lodash/fp/isEqual";
import queryString from "query-string";
import "./components";
import "./features";
@ -33,7 +35,9 @@ import AuthService, {
import { BtrixElement } from "@/classes/BtrixElement";
import type { NavigateEventDetail } from "@/controllers/navigate";
import type { NotifyEventDetail } from "@/controllers/notify";
import type { APIPaginatedList } from "@/types/api";
import { type Auth } from "@/types/auth";
import type { Crawl } from "@/types/crawler";
import {
translatedLocales,
type TranslatedLocaleEnum,
@ -66,6 +70,8 @@ export interface UserGuideEventMap {
"btrix-user-guide-show": CustomEvent<{ path?: string }>;
}
const POLL_INTERVAL_SECONDS = 30;
@customElement("browsertrix-app")
@localized()
export class App extends BtrixElement {
@ -108,6 +114,24 @@ export class App extends BtrixElement {
@query("#userGuideDrawer")
private readonly userGuideDrawer!: SlDrawer;
private readonly activeCrawlsTotalTask = new Task(this, {
task: async () => {
return await this.getActiveCrawlsTotal();
},
args: () => [] as const,
});
private readonly pollTask = new Task(this, {
task: async ([crawls]) => {
if (!crawls) return;
return window.setTimeout(() => {
void this.activeCrawlsTotalTask.run();
}, POLL_INTERVAL_SECONDS * 1000);
},
args: () => [this.activeCrawlsTotalTask.value] as const,
});
get orgSlugInPath() {
return this.viewState.params.slug || "";
}
@ -164,6 +188,12 @@ export class App extends BtrixElement {
this.startSyncBrowserTabs();
}
disconnectedCallback(): void {
super.disconnectedCallback();
window.clearTimeout(this.pollTask.value);
}
private attachUserGuideListeners() {
this.addEventListener(
"btrix-user-guide-show",
@ -579,15 +609,22 @@ export class App extends BtrixElement {
</div>
${isSuperAdmin
? html`
<div
class="order-3 grid w-full auto-cols-max grid-flow-col items-center gap-5 md:order-2 md:w-auto"
>
<div class="order-3 w-full auto-cols-max md:order-2 md:w-auto">
<a
class="font-medium text-neutral-500 hover:text-primary"
class="inline-flex items-center gap-2 font-medium text-neutral-500 hover:text-primary"
href=${urlForName("adminCrawls")}
@click=${this.navigate.link}
>${msg("Running Crawls")}</a
>
${msg("Active Crawls")}
${when(
this.activeCrawlsTotalTask.value,
(total) => html`
<btrix-badge variant=${total > 0 ? "primary" : "blue"}>
${this.localize.number(total)}
</btrix-badge>
`,
)}
</a>
</div>
`
: nothing}
@ -1127,4 +1164,16 @@ export class App extends BtrixElement {
private clearSelectedOrg() {
AppStateService.updateOrgSlug(null);
}
private async getActiveCrawlsTotal() {
const query = queryString.stringify({
pageSize: 1,
});
const data = await this.api.fetch<APIPaginatedList<Crawl>>(
`/orgs/all/crawls?${query}`,
);
return data.total;
}
}

View File

@ -70,7 +70,7 @@ export class Admin extends BtrixElement {
if (this.userInfo.orgs.length && !this.orgList) {
return html`
<btrix-document-title
title=${msg("Admin dashboard")}
title=${msg("Dashboard Admin")}
></btrix-document-title>
<div class="my-24 flex items-center justify-center text-3xl">
@ -81,7 +81,7 @@ export class Admin extends BtrixElement {
return html`
<btrix-document-title
title=${msg("Admin dashboard")}
title=${msg("Dashboard Admin")}
></btrix-document-title>
<div class="bg-white">

View File

@ -35,6 +35,7 @@ const sortableFields: Record<
},
};
const ABORT_REASON_THROTTLE = "throttled";
const POLL_INTERVAL_SECONDS = 30;
@customElement("btrix-crawls")
@localized()
@ -66,6 +67,8 @@ export class Crawls extends BtrixElement {
state: activeCrawlStates,
};
private timerId?: number;
// Use to cancel requests
private getCrawlsController: AbortController | null = null;
@ -102,11 +105,13 @@ export class Crawls extends BtrixElement {
disconnectedCallback(): void {
this.cancelInProgressGetCrawls();
super.disconnectedCallback();
window.clearTimeout(this.timerId);
}
render() {
return html`<btrix-document-title
title=${msg("Running crawls")}
title=${msg("Active Crawls Admin")}
></btrix-document-title>
<div class="mx-auto box-border w-full max-w-screen-desktop px-3 py-4">
@ -122,9 +127,7 @@ export class Crawls extends BtrixElement {
<main>
<header class="contents">
<div class="mb-3 flex w-full justify-between border-b pb-4">
<h1 class="h-8 text-xl font-semibold">
${msg("All Running Crawls")}
</h1>
<h1 class="h-8 text-xl font-semibold">${msg("Active Crawls")}</h1>
</div>
<div
class="sticky top-2 z-10 mb-3 rounded-lg border bg-neutral-50 p-4"
@ -329,8 +332,16 @@ export class Crawls extends BtrixElement {
*/
private async fetchCrawls(params?: APIPaginationQuery): Promise<void> {
this.cancelInProgressGetCrawls();
window.clearTimeout(this.timerId);
try {
this.crawls = await this.getCrawls(params);
// TODO Refactor to poll task
// https://github.com/webrecorder/browsertrix/issues/1716
this.timerId = window.setTimeout(() => {
void this.fetchCrawls();
}, POLL_INTERVAL_SECONDS * 1000);
} catch (e) {
if ((e as Error).name === "AbortError") {
console.debug("Fetch crawls aborted to throttle");

View File

@ -294,7 +294,7 @@ export class Org extends BtrixElement {
OrgTab.Items,
() => html`
<btrix-document-title
title=${`${msg("Archived Items")} - ${userOrg.name}`}
title=${`${msg("Archived Items")} ${userOrg.name}`}
></btrix-document-title>
${this.renderArchivedItem()}
`,
@ -303,7 +303,7 @@ export class Org extends BtrixElement {
OrgTab.Workflows,
() => html`
<btrix-document-title
title=${`${msg("Crawl Workflows")} - ${userOrg.name}`}
title=${`${msg("Crawl Workflows")} ${userOrg.name}`}
></btrix-document-title>
${this.renderWorkflows()}
`,
@ -312,7 +312,7 @@ export class Org extends BtrixElement {
OrgTab.BrowserProfiles,
() => html`
<btrix-document-title
title=${`${msg("Browser Profiles")} - ${userOrg.name}`}
title=${`${msg("Browser Profiles")} ${userOrg.name}`}
></btrix-document-title>
${this.renderBrowserProfiles()}
`,
@ -321,7 +321,7 @@ export class Org extends BtrixElement {
OrgTab.Collections,
() => html`
<btrix-document-title
title=${`${msg("Collections")} - ${userOrg.name}`}
title=${`${msg("Collections")} ${userOrg.name}`}
></btrix-document-title>
${this.renderCollections()}
`,
@ -332,7 +332,7 @@ export class Org extends BtrixElement {
this.appState.isAdmin
? html`
<btrix-document-title
title=${`${msg("Org Settings")} - ${userOrg.name}`}
title=${`${msg("Org Settings")} ${userOrg.name}`}
></btrix-document-title>
${this.renderOrgSettings()}
`