fix: Superadmin active crawl count inaccuracies (#2706)

- Fixes superadmin active crawl count not showing on first log in
- Fixes `/all/crawls` endpoint running when auth is not available or not
superadmin
This commit is contained in:
sua yoo 2025-07-07 10:13:57 -07:00 committed by GitHub
parent 8152223750
commit 9cfed7c6fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 63 additions and 51 deletions

View File

@ -0,0 +1,60 @@
import { localized } from "@lit/localize";
import { Task } from "@lit/task";
import { html } from "lit";
import { customElement } from "lit/decorators.js";
import queryString from "query-string";
import { BtrixElement } from "@/classes/BtrixElement";
import type { APIPaginatedList } from "@/types/api";
import type { Crawl } from "@/types/crawler";
const POLL_INTERVAL_SECONDS = 30;
@customElement("btrix-active-crawls-badge")
@localized()
export class ActiveCrawlsBadge extends BtrixElement {
private readonly activeCrawlsTotalTask = new Task(this, {
task: async () => {
return await this.getActiveCrawlsTotal();
},
args: () => [] as const,
});
private readonly pollTask = new Task(this, {
task: async () => {
window.clearTimeout(this.pollTask.value);
return window.setTimeout(() => {
void this.activeCrawlsTotalTask.run();
}, POLL_INTERVAL_SECONDS * 1000);
},
args: () => [this.activeCrawlsTotalTask.value] as const,
});
disconnectedCallback(): void {
super.disconnectedCallback();
window.clearTimeout(this.pollTask.value);
}
render() {
if (this.activeCrawlsTotalTask.value) {
const { total } = this.activeCrawlsTotalTask.value;
return html`<btrix-badge variant=${total > 0 ? "primary" : "blue"}>
${this.localize.number(total)}
</btrix-badge>`;
}
}
private async getActiveCrawlsTotal() {
const query = queryString.stringify({
pageSize: 1,
});
const data = await this.api.fetch<APIPaginatedList<Crawl>>(
`/orgs/all/crawls?${query}`,
);
return data;
}
}

View File

@ -1,2 +1,3 @@
import "./active-crawls-badge";
import "./stats"; import "./stats";
import "./super-admin-banner"; import "./super-admin-banner";

View File

@ -3,7 +3,6 @@ import "./global";
import { provide } from "@lit/context"; import { provide } from "@lit/context";
import { localized, msg, str } from "@lit/localize"; import { localized, msg, str } from "@lit/localize";
import { Task } from "@lit/task";
import type { import type {
SlDialog, SlDialog,
SlDrawer, SlDrawer,
@ -15,7 +14,6 @@ import { ifDefined } from "lit/directives/if-defined.js";
import { until } from "lit/directives/until.js"; import { until } from "lit/directives/until.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
import isEqual from "lodash/fp/isEqual"; import isEqual from "lodash/fp/isEqual";
import queryString from "query-string";
import "./components"; import "./components";
import "./features"; import "./features";
@ -35,9 +33,7 @@ import AuthService, {
import { BtrixElement } from "@/classes/BtrixElement"; import { BtrixElement } from "@/classes/BtrixElement";
import type { NavigateEventDetail } from "@/controllers/navigate"; import type { NavigateEventDetail } from "@/controllers/navigate";
import type { NotifyEventDetail } from "@/controllers/notify"; import type { NotifyEventDetail } from "@/controllers/notify";
import type { APIPaginatedList } from "@/types/api";
import { type Auth } from "@/types/auth"; import { type Auth } from "@/types/auth";
import type { Crawl } from "@/types/crawler";
import { import {
translatedLocales, translatedLocales,
type TranslatedLocaleEnum, type TranslatedLocaleEnum,
@ -70,8 +66,6 @@ export interface UserGuideEventMap {
"btrix-user-guide-show": CustomEvent<{ path?: string }>; "btrix-user-guide-show": CustomEvent<{ path?: string }>;
} }
const POLL_INTERVAL_SECONDS = 30;
@customElement("browsertrix-app") @customElement("browsertrix-app")
@localized() @localized()
export class App extends BtrixElement { export class App extends BtrixElement {
@ -114,24 +108,6 @@ export class App extends BtrixElement {
@query("#userGuideDrawer") @query("#userGuideDrawer")
private readonly userGuideDrawer!: SlDrawer; 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() { get orgSlugInPath() {
return this.viewState.params.slug || ""; return this.viewState.params.slug || "";
} }
@ -188,12 +164,6 @@ export class App extends BtrixElement {
this.startSyncBrowserTabs(); this.startSyncBrowserTabs();
} }
disconnectedCallback(): void {
super.disconnectedCallback();
window.clearTimeout(this.pollTask.value);
}
private attachUserGuideListeners() { private attachUserGuideListeners() {
this.addEventListener( this.addEventListener(
"btrix-user-guide-show", "btrix-user-guide-show",
@ -479,7 +449,7 @@ export class App extends BtrixElement {
} }
private renderNavBar() { private renderNavBar() {
const isSuperAdmin = this.userInfo?.isSuperAdmin; const isSuperAdmin = this.authState && this.userInfo?.isSuperAdmin;
const showFullLogo = const showFullLogo =
this.viewState.route === "login" || !this.authService.authState; this.viewState.route === "login" || !this.authService.authState;
@ -629,14 +599,7 @@ export class App extends BtrixElement {
@click=${this.navigate.link} @click=${this.navigate.link}
> >
${msg("Active Crawls")} ${msg("Active Crawls")}
${when( <btrix-active-crawls-badge></btrix-active-crawls-badge>
this.activeCrawlsTotalTask.value,
(total) => html`
<btrix-badge variant=${total > 0 ? "primary" : "blue"}>
${this.localize.number(total)}
</btrix-badge>
`,
)}
</a> </a>
</div> </div>
` `
@ -1183,16 +1146,4 @@ export class App extends BtrixElement {
private clearSelectedOrg() { private clearSelectedOrg() {
AppStateService.updateOrgSlug(null); 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;
}
} }