Skip to content

Commit 99d3cd0

Browse files
committed
Move settings to separate UI and logic components.
1 parent 08141c5 commit 99d3cd0

File tree

4 files changed

+317
-159
lines changed

4 files changed

+317
-159
lines changed

src/app.ts

Lines changed: 37 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,25 @@
44

55
import { LitElement, html, css } from "lit";
66
import { customElement, state } from "lit/decorators.js";
7-
import { ExceptionListEntry, BugMetaMap } from "./types";
7+
import { ExceptionListEntry, BugMetaMap, FirefoxChannel, FirefoxVersions } from "./types";
88
import { getRSEndpoint, RSEnvironment, isRSEnvValid } from "../scripts/rs-config.js";
99
import "./exceptions-table/exceptions-table";
1010
import "./exceptions-table/top-exceptions-table";
1111
import "./github-corner";
12+
import "./settings-ui.js";
1213

1314
import { versionNumberMatchesFilterExpression } from "./filter-expression/filter-expression.js";
15+
import settings from "./settings.js";
1416

1517
const GITHUB_URL = "https://github.com/mozilla/url-classifier-exceptions-ui";
1618

17-
// Query parameter which can be used to override the RS environment.
18-
const QUERY_PARAM_RS_ENV = "rs_env";
19-
const QUERY_PARAM_RS_USE_PREVIEW = "rs_preview";
20-
21-
/**
22-
* Get the RS environment from URL parameters, falling back to the defaults if
23-
* not specified.
24-
* @returns The RS environment key
25-
*/
26-
function getRsEnv(): { env: RSEnvironment; usePreview: boolean } {
27-
// Check if the environment is specified in the URL.
28-
const params = new URLSearchParams(window.location.search);
29-
const env = params.get(QUERY_PARAM_RS_ENV);
30-
const usePreview = params.get(QUERY_PARAM_RS_USE_PREVIEW) === "true";
31-
if (isRSEnvValid(env)) {
32-
return { env: env as RSEnvironment, usePreview };
33-
}
34-
35-
// Fall back to build-time environment variable.
36-
let viteEnv = import.meta.env.VITE_RS_ENVIRONMENT;
37-
if (isRSEnvValid(viteEnv)) {
38-
return { env: viteEnv as RSEnvironment, usePreview: false };
39-
}
40-
41-
// Otherwise default to prod, non preview.
42-
return { env: "prod", usePreview: false };
43-
}
44-
45-
/**
46-
* Get the URL for the records endpoint for a given Remote Settings environment.
47-
* @param rsUrl The URL of the Remote Settings environment.
48-
* @returns The URL for the records endpoint.
49-
*/
50-
function getRecordsUrl(rsUrl: string): string {
51-
// Allow ENV to override the URL for testing.
52-
if (import.meta.env.VITE_RS_RECORDS_URL) {
53-
return import.meta.env.VITE_RS_RECORDS_URL;
54-
}
55-
return rsUrl;
56-
}
57-
5819
/**
5920
* Fetch the records from the Remote Settings environment.
6021
* @param rsUrl The URL of the Remote Settings environment.
6122
* @returns The records.
6223
*/
6324
async function fetchRecords(rsUrl: string): Promise<ExceptionListEntry[]> {
64-
const response = await fetch(getRecordsUrl(rsUrl));
25+
const response = await fetch(settings.getRecordsUrl(rsUrl));
6526
if (!response.ok) {
6627
throw new Error(`Failed to fetch records: ${response.statusText}`);
6728
}
@@ -126,11 +87,7 @@ async function fetchBugMetadata(bugIds: Set<string>): Promise<BugMetaMap> {
12687
* Fetch the versions for each Firefox release channel.
12788
* @returns The versions for each release channel.
12889
*/
129-
async function fetchVersionsPerChannel(): Promise<{
130-
nightly: string;
131-
beta: string;
132-
release: string;
133-
}> {
90+
async function fetchVersionsPerChannel(): Promise<FirefoxVersions> {
13491
let [nightly, beta, release] = await Promise.all([
13592
fetchVersionNumber("nightly"),
13693
fetchVersionNumber("beta"),
@@ -191,16 +148,15 @@ export class App extends LitElement {
191148
@state()
192149
error: string | null = null;
193150

194-
// Holds the version numbers for each Firefox release channel.
151+
// Holds the version numbers for each Firefox release channel. This
152+
// information is fetched via API on init.
195153
@state()
196-
firefoxVersions: {
197-
nightly: string;
198-
beta: string;
199-
release: string;
200-
} | null = null;
154+
firefoxVersions: FirefoxVersions | null = null;
201155

156+
// The selected Firefox channel to filter entries by. If set to null, entries
157+
// matching all Firefox versions are displayed.
202158
@state()
203-
filterFirefoxChannel: "nightly" | "beta" | "release" | null = null;
159+
filterFirefoxChannel: FirefoxChannel | null = null;
204160

205161
static styles = css`
206162
/* Sticky headings. */
@@ -240,44 +196,6 @@ export class App extends LitElement {
240196
font-size: 0.8rem;
241197
color: var(--text-secondary);
242198
}
243-
244-
/* Settings section */
245-
#settings-content {
246-
padding: 1.5rem 2rem;
247-
background: var(--bg-secondary, #232323);
248-
border-radius: 10px;
249-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
250-
display: grid;
251-
grid-template-columns: max-content 1fr;
252-
gap: 1rem 1.5rem;
253-
align-items: center;
254-
max-width: 480px;
255-
}
256-
#settings-content label {
257-
justify-self: end;
258-
margin-right: 0.5rem;
259-
font-weight: 500;
260-
}
261-
#settings-content select,
262-
#settings-content input[type="checkbox"] {
263-
margin-left: 0.5rem;
264-
font-size: 1rem;
265-
}
266-
#settings-content input[type="checkbox"] {
267-
transform: scale(1.2);
268-
margin-right: 0.5rem;
269-
}
270-
@media (max-width: 600px) {
271-
#settings-content {
272-
grid-template-columns: 1fr;
273-
padding: 1rem;
274-
max-width: 100%;
275-
}
276-
#settings-content label {
277-
justify-self: start;
278-
margin-right: 0;
279-
}
280-
}
281199
`;
282200

283201
/**
@@ -287,9 +205,10 @@ export class App extends LitElement {
287205
super.connectedCallback();
288206

289207
// Set the initial RS environment and preview setting.
290-
let { env, usePreview } = getRsEnv();
208+
let { env, usePreview } = settings.getRsEnv();
291209
this.rsEnv = env;
292210
this.rsEnvUsePreview = usePreview;
211+
this.filterFirefoxChannel = settings.getFirefoxChannelFilter();
293212

294213
this.init();
295214
}
@@ -303,11 +222,10 @@ export class App extends LitElement {
303222

304223
await this.updateVersionInfo();
305224

306-
// If we successfully fetched the version info, set the default filter to
307-
// the latest release channel. We need to do this before calling
308-
// this.updateRecords so that the initial display is correctly filtered.
309-
if (this.firefoxVersions) {
310-
this.filterFirefoxChannel = "release";
225+
// If we failed to fetch version info, disable the filter.
226+
// Version info is required to evaluate the RS filter expression.
227+
if (!this.firefoxVersions) {
228+
this.filterFirefoxChannel = null;
311229
}
312230

313231
// Fetch the records.
@@ -328,7 +246,6 @@ export class App extends LitElement {
328246
// Fetch the versions for each release channel.
329247
try {
330248
this.firefoxVersions = await fetchVersionsPerChannel();
331-
console.debug("versions", this.firefoxVersions);
332249
} catch (error) {
333250
console.error("Failed to fetch Firefox versions", error);
334251
}
@@ -413,25 +330,14 @@ export class App extends LitElement {
413330
}
414331

415332
/**
416-
* Handle changes to RS environment settings via the UI.
417-
* @param event The change event either the dropdown or the checkbox.
333+
* Handle changes to RS environment settings via the settings component.
334+
* @param event The RS environment change event.
418335
*/
419-
private async handleRSEnvChange(event: Event) {
420-
const target = event.target as HTMLSelectElement | HTMLInputElement;
421-
422-
if (target.id === "rs-env") {
423-
this.rsEnv = (target as HTMLSelectElement).value as RSEnvironment;
424-
// Reset preview setting when environment changes.
425-
this.rsEnvUsePreview = false;
426-
} else if (target.id === "rs-env-preview") {
427-
this.rsEnvUsePreview = (target as HTMLInputElement).checked;
428-
}
336+
private async handleRSEnvChange(event: CustomEvent) {
337+
this.rsEnv = event.detail.rsEnv;
338+
this.rsEnvUsePreview = event.detail.rsEnvUsePreview;
429339

430-
// Update URL parameters to reflect current settings
431-
const url = new URL(window.location.href);
432-
url.searchParams.set(QUERY_PARAM_RS_ENV, this.rsEnv);
433-
url.searchParams.set(QUERY_PARAM_RS_USE_PREVIEW, this.rsEnvUsePreview.toString());
434-
window.history.pushState({}, "", url);
340+
settings.setRsEnv(this.rsEnv, this.rsEnvUsePreview);
435341

436342
// Fetch the records again with the new settings
437343
try {
@@ -448,13 +354,12 @@ export class App extends LitElement {
448354
}
449355

450356
/**
451-
* Handle changes to the Firefox version filter via the UI.
452-
* @param event The change event.
357+
* Handle changes to the Firefox channel filter via the settings component.
358+
* @param event The Firefox channel filter change event.
453359
*/
454-
private async handleFirefoxVersionFilterChange(event: Event) {
455-
const target = event.target as HTMLSelectElement;
456-
457-
this.filterFirefoxChannel = target.value as keyof typeof this.firefoxVersions;
360+
private async handleFirefoxChannelFilterChange(event: CustomEvent) {
361+
this.filterFirefoxChannel = event.detail.filterFirefoxChannel;
362+
settings.setFirefoxChannelFilter(this.filterFirefoxChannel);
458363

459364
// Update the filtered records based on the selected Firefox version.
460365
// This does not require a full re-fetch of the records.
@@ -599,49 +504,22 @@ export class App extends LitElement {
599504
>
600505
for more information.
601506
</p>
602-
<details>
603-
<summary>UI Settings</summary>
604-
<div id="settings-content">
605-
<label for="rs-env">Remote Settings Environment:</label>
606-
<select id="rs-env" @change=${this.handleRSEnvChange}>
607-
<option value="prod" ?selected=${this.rsEnv === "prod"}>Prod</option>
608-
<option value="stage" ?selected=${this.rsEnv === "stage"}>Stage</option>
609-
<option value="dev" ?selected=${this.rsEnv === "dev"}>Dev</option>
610-
</select>
611-
<label for="fx-version">Firefox Version:</label>
612-
<select
613-
id="fx-version"
614-
@change=${this.handleFirefoxVersionFilterChange}
615-
?disabled=${!this.firefoxVersions}
616-
>
617-
<option value="" ?selected=${this.filterFirefoxChannel === null}>All</option>
618-
<option value="nightly" ?selected=${this.filterFirefoxChannel === "nightly"}
619-
>Nightly ${this.firefoxVersions?.nightly}</option
620-
>
621-
<option value="beta" ?selected=${this.filterFirefoxChannel === "beta"}
622-
>Beta ${this.firefoxVersions?.beta}</option
623-
>
624-
<option value="release" ?selected=${this.filterFirefoxChannel === "release"}
625-
>Release ${this.firefoxVersions?.release}</option
626-
>
627-
</select>
628-
<label for="rs-env-preview">Include changes pending review:</label>
629-
<input
630-
id="rs-env-preview"
631-
type="checkbox"
632-
?checked=${this.rsEnvUsePreview}
633-
@change=${this.handleRSEnvChange}
634-
/>
635-
</div>
636-
</details>
507+
<settings-ui
508+
.rsEnv=${this.rsEnv}
509+
.rsEnvUsePreview=${this.rsEnvUsePreview}
510+
.firefoxVersions=${this.firefoxVersions}
511+
.filterFirefoxChannel=${this.filterFirefoxChannel}
512+
@rs-env-change=${this.handleRSEnvChange}
513+
@firefox-channel-filter-change=${this.handleFirefoxChannelFilterChange}
514+
></settings-ui>
637515
638516
${this.renderMainContent()}
639517
640518
<footer>
641519
<p>
642520
Data source:
643521
${(() => {
644-
const recordsUrl = getRecordsUrl(
522+
const recordsUrl = settings.getRecordsUrl(
645523
getRSEndpoint(this.rsEnv, this.rsEnvUsePreview).toString(),
646524
);
647525
return html`<a href="${recordsUrl}">${recordsUrl}</a>`;

0 commit comments

Comments
 (0)