Skip to content

fix: Crawler proxy selection fixes #2280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@formatjs/intl-durationformat": "^0.6.4",
"@formatjs/intl-localematcher": "^0.5.9",
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
"@lit/context": "^1.1.3",
"@lit/localize": "^0.12.1",
"@lit/task": "^1.0.0",
"@novnc/novnc": "^1.4.0-beta",
Expand Down
115 changes: 40 additions & 75 deletions frontend/src/components/ui/select-crawler-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { localized, msg } from "@lit/localize";
import { type SlSelect } from "@shoelace-style/shoelace";
import type { SlSelect } from "@shoelace-style/shoelace";
import { html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";

import type { ProxiesAPIResponse, Proxy } from "@/pages/org/types";
import LiteElement from "@/utils/LiteElement";
import { BtrixElement } from "@/classes/BtrixElement";
import type { Proxy } from "@/pages/org/types";

type SelectCrawlerProxyChangeDetail = {
value: string | null;
Expand All @@ -26,30 +27,40 @@ export type SelectCrawlerProxyUpdateEvent =
* Usage example:
* ```ts
* <btrix-select-crawler-proxy
* orgId=${orgId}
* on-change=${({value}) => selectedcrawlerProxy = value}
* .proxyServers=${proxyServers}
* btrix-change=${({value}) => selectedcrawlerProxy = value}
* ></btrix-select-crawler-proxy>
* ```
*
* @event on-change
* @fires btrix-change
*/
@customElement("btrix-select-crawler-proxy")
@localized()
export class SelectCrawlerProxy extends LiteElement {
export class SelectCrawlerProxy extends BtrixElement {
@property({ type: String })
defaultProxyId: string | null = null;

@property({ type: Array })
proxyServers: Proxy[] = [];

@property({ type: String })
proxyId: string | null = null;

@property({ type: String })
size?: SlSelect["size"];

@state()
private selectedProxy?: Proxy;

@state()
private defaultProxy?: Proxy;

@state()
private allProxies?: Proxy[];
public get value() {
return this.selectedProxy?.id || "";
}

protected firstUpdated() {
void this.fetchOrgProxies();
void this.initProxies();
}
// credit: https://dev.to/jorik/country-code-to-flag-emoji-a21
private countryCodeToFlagEmoji(countryCode: String): String {
Expand All @@ -61,10 +72,6 @@ export class SelectCrawlerProxy extends LiteElement {
}

render() {
/*if (this.crawlerProxys && this.crawlerProxys.length < 2) {
return html``;
}*/

return html`
<sl-select
name="proxyId"
Expand All @@ -75,15 +82,12 @@ export class SelectCrawlerProxy extends LiteElement {
: msg("No Proxy")}
hoist
clearable
size=${ifDefined(this.size)}
@sl-change=${this.onChange}
@sl-focus=${() => {
// Refetch to keep list up to date
void this.fetchOrgProxies();
}}
@sl-hide=${this.stopProp}
@sl-after-hide=${this.stopProp}
>
${this.allProxies?.map(
${this.proxyServers.map(
(server) =>
html` <sl-option value=${server.id}>
${server.country_code
Expand Down Expand Up @@ -121,7 +125,7 @@ export class SelectCrawlerProxy extends LiteElement {
private onChange(e: Event) {
this.stopProp(e);

this.selectedProxy = this.allProxies?.find(
this.selectedProxy = this.proxyServers.find(
({ id }) => id === (e.target as SlSelect).value,
);

Expand All @@ -130,71 +134,32 @@ export class SelectCrawlerProxy extends LiteElement {
}

this.dispatchEvent(
new CustomEvent<SelectCrawlerProxyChangeDetail>("on-change", {
new CustomEvent<SelectCrawlerProxyChangeDetail>("btrix-change", {
detail: {
value: this.selectedProxy ? this.selectedProxy.id : null,
},
}),
);
}

/**
* Fetch crawler proxies and update internal state
*/
private async fetchOrgProxies(): Promise<void> {
try {
const data = await this.getOrgProxies();
const defaultProxyId = data.default_proxy_id;

this.allProxies = data.servers;

if (!this.defaultProxy) {
this.defaultProxy = this.allProxies.find(
({ id }) => id === defaultProxyId,
);
}

if (this.proxyId && !this.selectedProxy?.id) {
this.selectedProxy = this.allProxies.find(
({ id }) => id === this.proxyId,
);
}

if (!this.selectedProxy) {
this.proxyId = null;
this.dispatchEvent(
new CustomEvent("on-change", {
detail: {
value: null,
},
}),
);
this.selectedProxy = this.allProxies.find(
({ id }) => id === this.proxyId,
);
}

this.dispatchEvent(
new CustomEvent<SelectCrawlerProxyUpdateDetail>("on-update", {
detail: {
show: this.allProxies.length > 1,
},
}),
private async initProxies(): Promise<void> {
const defaultProxyId = this.defaultProxyId;

if (!this.defaultProxy) {
this.defaultProxy = this.proxyServers.find(
({ id }) => id === defaultProxyId,
);
} catch (e) {
this.notify({
message: msg("Sorry, couldn't retrieve proxies at this time."),
variant: "danger",
icon: "exclamation-octagon",
id: "proxy-retrieve-status",
});
}
}

private async getOrgProxies(): Promise<ProxiesAPIResponse> {
return this.apiFetch<ProxiesAPIResponse>(
`/orgs/${this.orgId}/crawlconfigs/crawler-proxies`,
);
if (this.proxyId && !this.selectedProxy) {
this.selectedProxy = this.proxyServers.find(
({ id }) => id === this.proxyId,
);
}

if (!this.selectedProxy) {
this.proxyId = null;
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/context/org.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createContext } from "@lit/context";

import type { ProxiesAPIResponse } from "@/types/crawler";

export type ProxiesContext = ProxiesAPIResponse | null;

export const proxiesContext = createContext<ProxiesContext>("proxies");
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { consume } from "@lit/context";
import { localized, msg, str } from "@lit/localize";
import { type SlInput } from "@shoelace-style/shoelace";
import { nothing } from "lit";
import {
customElement,
property,
query,
queryAsync,
state,
} from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import queryString from "query-string";

import type { Dialog } from "@/components/ui/dialog";
import { type SelectCrawlerChangeEvent } from "@/components/ui/select-crawler";
import { type SelectCrawlerProxyChangeEvent } from "@/components/ui/select-crawler-proxy";
import { proxiesContext, type ProxiesContext } from "@/context/org";
import LiteElement, { html } from "@/utils/LiteElement";

@localized()
@customElement("btrix-new-browser-profile-dialog")
export class NewBrowserProfileDialog extends LiteElement {
@consume({ context: proxiesContext, subscribe: true })
private readonly proxies?: ProxiesContext;

@property({ type: Boolean })
open = false;

Expand Down Expand Up @@ -83,14 +90,22 @@ export class NewBrowserProfileDialog extends LiteElement {
(this.crawlerChannel = e.detail.value!)}
></btrix-select-crawler>
</div>
<div class="mt-4">
<btrix-select-crawler-proxy
orgId=${this.orgId}
.proxyId="${this.proxyId || ""}"
@on-change=${(e: SelectCrawlerProxyChangeEvent) =>
(this.proxyId = e.detail.value!)}
></btrix-select-crawler-proxy>
</div>
${this.proxies?.servers.length
? html`
<div class="mt-4">
<btrix-select-crawler-proxy
defaultProxyId=${ifDefined(
this.proxies.default_proxy_id ?? undefined,
)}
.proxyServers=${this.proxies.servers}
.proxyId="${this.proxyId || ""}"
@btrix-change=${(e: SelectCrawlerProxyChangeEvent) =>
(this.proxyId = e.detail.value)}
></btrix-select-crawler-proxy>
</div>
`
: nothing}

<input class="invisible size-0" type="submit" />
</form>
<div slot="footer" class="flex justify-between">
Expand Down
34 changes: 23 additions & 11 deletions frontend/src/features/crawl-workflows/workflow-editor.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { consume } from "@lit/context";
import { localized, msg, str } from "@lit/localize";
import type {
SlChangeEvent,
Expand Down Expand Up @@ -43,6 +44,7 @@ import type { SelectCrawlerProxyChangeEvent } from "@/components/ui/select-crawl
import type { Tab } from "@/components/ui/tab-list";
import type { TagInputEvent, TagsChangeEvent } from "@/components/ui/tag-input";
import type { TimeInputChangeEvent } from "@/components/ui/time-input";
import { proxiesContext, type ProxiesContext } from "@/context/org";
import { type SelectBrowserProfileChangeEvent } from "@/features/browser-profiles/select-browser-profile";
import type { CollectionsChangeEvent } from "@/features/collections/collections-add";
import type { QueueExclusionTable } from "@/features/crawl-workflows/queue-exclusion-table";
Expand Down Expand Up @@ -188,6 +190,9 @@ type CrawlConfigResponse = {
@localized()
@customElement("btrix-workflow-editor")
export class WorkflowEditor extends BtrixElement {
@consume({ context: proxiesContext, subscribe: true })
private readonly proxies?: ProxiesContext;

@property({ type: String })
configId?: string;

Expand Down Expand Up @@ -1329,17 +1334,24 @@ https://archiveweb.page/images/${"logo.svg"}`}
></btrix-select-browser-profile>
`)}
${this.renderHelpTextCol(infoTextStrings["browserProfile"])}
${inputCol(html`
<btrix-select-crawler-proxy
orgId=${this.orgId}
.proxyId="${this.formState.proxyId || ""}"
@on-change=${(e: SelectCrawlerProxyChangeEvent) =>
this.updateFormState({
proxyId: e.detail.value,
})}
></btrix-select-crawler-proxy>
`)}
${this.renderHelpTextCol(infoTextStrings["proxyId"])}
${this.proxies?.servers.length
? [
inputCol(html`
<btrix-select-crawler-proxy
defaultProxyId=${ifDefined(
this.proxies.default_proxy_id ?? undefined,
)}
.proxyServers=${this.proxies.servers}
.proxyId="${this.formState.proxyId || ""}"
@btrix-change=${(e: SelectCrawlerProxyChangeEvent) =>
this.updateFormState({
proxyId: e.detail.value,
})}
></btrix-select-crawler-proxy>
`),
this.renderHelpTextCol(infoTextStrings["proxyId"]),
]
: nothing}
${inputCol(html`
<sl-radio-group
name="scale"
Expand Down
Loading
Loading