Skip to content

Commit 77beece

Browse files
committed
fix: Improve crawler channel and proxy render performance (#2955)
- Improves fetch performance for crawler proxies and channels, fixing `crawler-channels` being called twice wherever channel selector is rendered - Fixes empty space when only single channel is available - Hides `(Exact Crawler Version)` text when version is not available
1 parent 26c100d commit 77beece

File tree

10 files changed

+223
-203
lines changed

10 files changed

+223
-203
lines changed

frontend/src/components/ui/config-details.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export class ConfigDetails extends BtrixElement {
257257
crawlConfig?.browserWindows ? `${crawlConfig.browserWindows}` : "",
258258
)}
259259
${this.renderSetting(
260-
msg("Crawler Channel (Exact Crawler Version)"),
260+
`${msg("Crawler Channel")} ${crawlConfig?.image ? msg("(Exact Crawler Version)") : ""}`.trim(),
261261
capitalize(
262262
crawlConfig?.crawlerChannel || CrawlerChannelImage.Default,
263263
) + (crawlConfig?.image ? ` (${crawlConfig.image})` : ""),

frontend/src/components/ui/select-crawler.ts

Lines changed: 41 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import { consume } from "@lit/context";
12
import { localized, msg } from "@lit/localize";
23
import { type SlSelect } from "@shoelace-style/shoelace";
3-
import { html, type PropertyValues } from "lit";
4-
import { customElement, property, state } from "lit/decorators.js";
4+
import { html, nothing } from "lit";
5+
import { customElement, property } from "lit/decorators.js";
56
import { ifDefined } from "lit/directives/if-defined.js";
67
import capitalize from "lodash/fp/capitalize";
78

9+
import {
10+
orgCrawlerChannelsContext,
11+
type OrgCrawlerChannelsContext,
12+
} from "@/context/org-crawler-channels";
813
import { CrawlerChannelImage, type CrawlerChannel } from "@/pages/org/types";
914
import LiteElement from "@/utils/LiteElement";
1015

@@ -20,167 +25,96 @@ type SelectCrawlerUpdateDetail = {
2025

2126
export type SelectCrawlerUpdateEvent = CustomEvent<SelectCrawlerUpdateDetail>;
2227

23-
type CrawlerChannelsAPIResponse = {
24-
channels: CrawlerChannel[];
25-
};
26-
2728
/**
2829
* Crawler channel select dropdown
2930
*
31+
* @TODO Convert to form control
32+
*
3033
* Usage example:
3134
* ```ts
3235
* <btrix-select-crawler
3336
* on-change=${({value}) => selectedCrawler = value}
3437
* ></btrix-select-crawler>
3538
* ```
3639
*
37-
* @event on-change
40+
* @fires on-change
3841
*/
3942
@customElement("btrix-select-crawler")
4043
@localized()
4144
export class SelectCrawler extends LiteElement {
45+
@consume({ context: orgCrawlerChannelsContext, subscribe: true })
46+
private readonly crawlerChannels?: OrgCrawlerChannelsContext;
47+
4248
@property({ type: String })
4349
size?: SlSelect["size"];
4450

4551
@property({ type: String })
46-
crawlerChannel?: string;
47-
48-
@state()
49-
private selectedCrawler?: CrawlerChannel;
50-
51-
@state()
52-
private crawlerChannels?: CrawlerChannel[];
53-
54-
willUpdate(changedProperties: PropertyValues<this>) {
55-
if (changedProperties.has("crawlerChannel")) {
56-
void this.updateSelectedCrawlerChannel();
57-
}
58-
}
59-
60-
protected firstUpdated() {
61-
void this.updateSelectedCrawlerChannel();
62-
}
52+
crawlerChannel?: CrawlerChannel["id"];
6353

6454
render() {
65-
if (this.crawlerChannels && this.crawlerChannels.length < 2) {
66-
return html``;
67-
}
55+
const selectedCrawler = this.getSelectedChannel();
6856

6957
return html`
7058
<sl-select
7159
name="crawlerChannel"
7260
label=${msg("Crawler Release Channel")}
73-
value=${this.selectedCrawler?.id || ""}
61+
value=${selectedCrawler?.id || ""}
7462
placeholder=${msg("Latest")}
7563
size=${ifDefined(this.size)}
7664
hoist
7765
@sl-change=${this.onChange}
78-
@sl-focus=${() => {
79-
// Refetch to keep list up to date
80-
void this.fetchCrawlerChannels();
81-
}}
8266
@sl-hide=${this.stopProp}
8367
@sl-after-hide=${this.stopProp}
68+
?disabled=${!this.crawlerChannels || this.crawlerChannels.length === 1}
8469
>
8570
${this.crawlerChannels?.map(
8671
(crawler) =>
8772
html` <sl-option value=${crawler.id}>
8873
${capitalize(crawler.id)}
8974
</sl-option>`,
9075
)}
91-
${this.selectedCrawler
92-
? html`
93-
<div slot="help-text">
94-
${msg("Version:")}
95-
<span class="font-monospace"
96-
>${this.selectedCrawler.image}</span
97-
>
98-
</div>
99-
`
100-
: ``}
76+
<div slot="help-text">
77+
${msg("Version:")}
78+
${selectedCrawler
79+
? html`
80+
<span class="font-monospace">${selectedCrawler.image}</span>
81+
`
82+
: nothing}
83+
</div>
10184
</sl-select>
10285
`;
10386
}
10487

105-
private onChange(e: Event) {
106-
this.stopProp(e);
88+
private getSelectedChannel() {
89+
if (!this.crawlerChannels || !this.crawlerChannel) return null;
10790

108-
this.selectedCrawler = this.crawlerChannels?.find(
109-
({ id }) => id === (e.target as SlSelect).value,
110-
);
91+
if (this.crawlerChannel) {
92+
return this.crawlerChannels.find(({ id }) => id === this.crawlerChannel);
93+
}
11194

112-
this.dispatchEvent(
113-
new CustomEvent<SelectCrawlerChangeDetail>("on-change", {
114-
detail: {
115-
value: this.selectedCrawler?.id,
116-
},
117-
}),
95+
return (
96+
this.crawlerChannels.find(
97+
({ id }) => id === CrawlerChannelImage.Default,
98+
) ?? null
11899
);
119100
}
120101

121-
private async updateSelectedCrawlerChannel() {
122-
await this.fetchCrawlerChannels();
123-
await this.updateComplete;
124-
125-
if (!this.crawlerChannels) return;
126-
127-
if (this.crawlerChannel && !this.selectedCrawler) {
128-
this.selectedCrawler = this.crawlerChannels.find(
129-
({ id }) => id === this.crawlerChannel,
130-
);
131-
}
132-
133-
if (!this.selectedCrawler) {
134-
this.crawlerChannel = CrawlerChannelImage.Default;
135-
this.dispatchEvent(
136-
new CustomEvent("on-change", {
137-
detail: {
138-
value: CrawlerChannelImage.Default,
139-
},
140-
}),
141-
);
142-
this.selectedCrawler = this.crawlerChannels.find(
143-
({ id }) => id === this.crawlerChannel,
144-
);
145-
}
102+
private onChange(e: Event) {
103+
this.stopProp(e);
146104

147-
await this.updateComplete;
105+
const selectedCrawler = this.crawlerChannels?.find(
106+
({ id }) => id === (e.target as SlSelect).value,
107+
);
148108

149109
this.dispatchEvent(
150-
new CustomEvent<SelectCrawlerUpdateDetail>("on-update", {
110+
new CustomEvent<SelectCrawlerChangeDetail>("on-change", {
151111
detail: {
152-
show: this.crawlerChannels.length > 1,
112+
value: selectedCrawler?.id,
153113
},
154114
}),
155115
);
156116
}
157117

158-
/**
159-
* Fetch crawler channels and update internal state
160-
*/
161-
private async fetchCrawlerChannels(): Promise<void> {
162-
try {
163-
const channels = await this.getCrawlerChannels();
164-
this.crawlerChannels = channels;
165-
} catch (e) {
166-
this.notify({
167-
message: msg("Sorry, couldn't retrieve crawler channels at this time."),
168-
variant: "danger",
169-
icon: "exclamation-octagon",
170-
id: "crawler-channel-retrieve-error",
171-
});
172-
}
173-
}
174-
175-
private async getCrawlerChannels(): Promise<CrawlerChannel[]> {
176-
const data: CrawlerChannelsAPIResponse =
177-
await this.apiFetch<CrawlerChannelsAPIResponse>(
178-
`/orgs/${this.orgId}/crawlconfigs/crawler-channels`,
179-
);
180-
181-
return data.channels;
182-
}
183-
184118
/**
185119
* Stop propgation of sl-select events.
186120
* Prevents bug where sl-dialog closes when dropdown closes
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createContext } from "@lit/context";
2+
3+
import type { CrawlerChannel } from "@/types/crawler";
4+
5+
export type OrgCrawlerChannelsContext = CrawlerChannel[] | null;
6+
7+
export const orgCrawlerChannelsContext =
8+
createContext<OrgCrawlerChannelsContext>("org-crawler-channels");
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createContext } from "@lit/context";
2+
3+
import type { ProxiesAPIResponse } from "@/types/crawler";
4+
5+
export type OrgProxiesContext = ProxiesAPIResponse | null;
6+
7+
export const orgProxiesContext =
8+
createContext<OrgProxiesContext>("org-proxies");

frontend/src/context/org.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

frontend/src/features/browser-profiles/new-browser-profile-dialog.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import { BtrixElement } from "@/classes/BtrixElement";
1515
import type { Dialog } from "@/components/ui/dialog";
1616
import { type SelectCrawlerChangeEvent } from "@/components/ui/select-crawler";
1717
import { type SelectCrawlerProxyChangeEvent } from "@/components/ui/select-crawler-proxy";
18-
import { CrawlerChannelImage, type Proxy } from "@/types/crawler";
18+
import {
19+
CrawlerChannelImage,
20+
type CrawlerChannel,
21+
type Proxy,
22+
} from "@/types/crawler";
1923

2024
@customElement("btrix-new-browser-profile-dialog")
2125
@localized()
@@ -29,14 +33,17 @@ export class NewBrowserProfileDialog extends BtrixElement {
2933
@property({ type: Array })
3034
proxyServers?: Proxy[];
3135

36+
@property({ type: Array })
37+
crawlerChannels?: CrawlerChannel[];
38+
3239
@property({ type: Boolean })
3340
open = false;
3441

3542
@state()
3643
private isSubmitting = false;
3744

3845
@state()
39-
private crawlerChannel: string = CrawlerChannelImage.Default;
46+
private crawlerChannel: CrawlerChannel["id"] = CrawlerChannelImage.Default;
4047

4148
@state()
4249
private proxyId: string | null = null;
@@ -57,7 +64,7 @@ export class NewBrowserProfileDialog extends BtrixElement {
5764
this.defaultCrawlerChannel
5865
) {
5966
this.crawlerChannel =
60-
(this.crawlerChannel !== (CrawlerChannelImage.Default as string) &&
67+
(this.crawlerChannel !== CrawlerChannelImage.Default &&
6168
this.crawlerChannel) ||
6269
this.defaultCrawlerChannel;
6370
}
@@ -91,13 +98,15 @@ export class NewBrowserProfileDialog extends BtrixElement {
9198
>
9299
</btrix-url-input>
93100
94-
<div class="mt-4">
95-
<btrix-select-crawler
96-
.crawlerChannel=${this.crawlerChannel}
97-
@on-change=${(e: SelectCrawlerChangeEvent) =>
98-
(this.crawlerChannel = e.detail.value!)}
99-
></btrix-select-crawler>
100-
</div>
101+
${this.crawlerChannels && this.crawlerChannels.length > 1
102+
? html`<div class="mt-4">
103+
<btrix-select-crawler
104+
.crawlerChannel=${this.crawlerChannel}
105+
@on-change=${(e: SelectCrawlerChangeEvent) =>
106+
(this.crawlerChannel = e.detail.value!)}
107+
></btrix-select-crawler>
108+
</div>`
109+
: nothing}
101110
${this.proxyServers?.length
102111
? html`
103112
<div class="mt-4">

0 commit comments

Comments
 (0)