diff --git a/backend/btrixcloud/main.py b/backend/btrixcloud/main.py index 4afd8afe..e878fef6 100644 --- a/backend/btrixcloud/main.py +++ b/backend/btrixcloud/main.py @@ -67,6 +67,7 @@ def main(): os.environ.get("DEFAULT_PAGE_LOAD_TIME_SECONDS", 120) ), "maxPagesPerCrawl": int(os.environ.get("MAX_PAGES_PER_CRAWL", 0)), + "maxScale": int(os.environ.get("MAX_CRAWL_SCALE", 3)), } invites = init_invites(mdb, email) diff --git a/backend/test/test_settings.py b/backend/test/test_settings.py index 1f4515ac..a15f012e 100644 --- a/backend/test/test_settings.py +++ b/backend/test/test_settings.py @@ -14,5 +14,6 @@ def test_settings(): "jwtTokenLifetime": 86400, "defaultBehaviorTimeSeconds": 300, "maxPagesPerCrawl": 4, + "maxScale": 3, "defaultPageLoadTimeSeconds": 120, } diff --git a/frontend/src/index.ts b/frontend/src/index.ts index 7afd5ed2..278327ef 100644 --- a/frontend/src/index.ts +++ b/frontend/src/index.ts @@ -33,6 +33,7 @@ import "./assets/fonts/Inter/inter.css"; import "./assets/fonts/Recursive/recursive.css"; import "./styles.css"; import { theme } from "@/theme"; +import { DEFAULT_MAX_SCALE } from "./utils/crawler"; // Make theme CSS available in document document.adoptedStyleSheets = [theme]; @@ -79,6 +80,8 @@ export class App extends LiteElement { @state() private isRegistrationEnabled?: boolean; + private maxScale = DEFAULT_MAX_SCALE; + async connectedCallback() { let authState: AuthState = null; try { @@ -136,6 +139,7 @@ export class App extends LiteElement { if (settings) { this.isRegistrationEnabled = settings.registrationEnabled; + this.maxScale = settings.maxScale; } this.isAppSettingsLoaded = true; @@ -173,13 +177,19 @@ export class App extends LiteElement { } } - async getAppSettings(): Promise<{ registrationEnabled: boolean } | void> { + async getAppSettings(): Promise<{ + registrationEnabled: boolean; + maxScale: number; + } | void> { const resp = await fetch("/api/settings", { headers: { "Content-Type": "application/json" }, }); if (resp.status === 200) { - const body = (await resp.json()) as { registrationEnabled: boolean }; + const body = (await resp.json()) as { + registrationEnabled: boolean; + maxScale: number; + }; return body; } else { @@ -600,6 +610,7 @@ export class App extends LiteElement { .userInfo=${this.appState.userInfo ?? undefined} .viewStateData=${this.viewState.data} .params=${this.viewState.params} + .maxScale=${this.maxScale} slug=${slug} orgPath=${orgPath.split(slug)[1]} orgTab=${orgTab as OrgTab} diff --git a/frontend/src/pages/org/index.ts b/frontend/src/pages/org/index.ts index d0a6cac0..1a0c9b66 100644 --- a/frontend/src/pages/org/index.ts +++ b/frontend/src/pages/org/index.ts @@ -11,6 +11,7 @@ import type { OrgData } from "@/utils/orgs"; import { isAdmin, isCrawler } from "@/utils/orgs"; import LiteElement, { html } from "@/utils/LiteElement"; import { needLogin } from "@/utils/auth"; +import { DEFAULT_MAX_SCALE } from "@/utils/crawler"; import "./workflow-detail"; import "./workflows-list"; import "./workflows-new"; @@ -104,6 +105,9 @@ export class Org extends LiteElement { @property({ type: String }) orgTab: OrgTab = defaultTab; + @property({ type: Number }) + maxScale: number = DEFAULT_MAX_SCALE; + @state() private orgStorageQuotaReached = false; @@ -572,6 +576,7 @@ export class Org extends LiteElement { openDialogName=${this.viewStateData?.dialog} ?isEditing=${isEditing} ?isCrawler=${this.isCrawler} + .maxScale=${this.maxScale} > `; } diff --git a/frontend/src/pages/org/workflow-detail.ts b/frontend/src/pages/org/workflow-detail.ts index d047efa7..eaec62f9 100644 --- a/frontend/src/pages/org/workflow-detail.ts +++ b/frontend/src/pages/org/workflow-detail.ts @@ -19,7 +19,11 @@ import type { } from "./types"; import { humanizeSchedule } from "@/utils/cron"; import type { APIPaginatedList } from "@/types/api"; -import { inactiveCrawlStates, isActive } from "@/utils/crawler"; +import { + DEFAULT_MAX_SCALE, + inactiveCrawlStates, + isActive, +} from "@/utils/crawler"; import type { SlSelect } from "@shoelace-style/shoelace"; import type { PageChangeEvent } from "@/components/ui/pagination"; import { ExclusionEditor } from "@/features/crawl-workflows/exclusion-editor"; @@ -70,6 +74,9 @@ export class WorkflowDetail extends LiteElement { @property({ type: String }) initialActivePanel?: Tab; + @property({ type: Number }) + maxScale = DEFAULT_MAX_SCALE; + @state() private workflow?: Workflow; @@ -1261,20 +1268,13 @@ export class WorkflowDetail extends LiteElement { private renderEditScale() { if (!this.workflow) return; - const scaleOptions = [ - { - value: 1, - label: "1×", - }, - { - value: 2, - label: "2×", - }, - { - value: 3, - label: "3×", - }, - ]; + const scaleOptions = []; + for (let value = 1; value <= this.maxScale; value++) { + scaleOptions.push({ + value, + label: `${value}×`, + }); + } return html`