4
4
5
5
import { LitElement , html , css } from "lit" ;
6
6
import { customElement , state } from "lit/decorators.js" ;
7
- import { ExceptionListEntry , BugMetaMap } from "./types" ;
7
+ import { ExceptionListEntry , BugMetaMap , FirefoxChannel , FirefoxVersions } from "./types" ;
8
8
import { getRSEndpoint , RSEnvironment , isRSEnvValid } from "../scripts/rs-config.js" ;
9
9
import "./exceptions-table/exceptions-table" ;
10
10
import "./exceptions-table/top-exceptions-table" ;
11
11
import "./github-corner" ;
12
+ import "./settings-ui.js" ;
12
13
13
14
import { versionNumberMatchesFilterExpression } from "./filter-expression/filter-expression.js" ;
15
+ import settings from "./settings.js" ;
14
16
15
17
const GITHUB_URL = "https://github.com/mozilla/url-classifier-exceptions-ui" ;
16
18
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
-
58
19
/**
59
20
* Fetch the records from the Remote Settings environment.
60
21
* @param rsUrl The URL of the Remote Settings environment.
61
22
* @returns The records.
62
23
*/
63
24
async function fetchRecords ( rsUrl : string ) : Promise < ExceptionListEntry [ ] > {
64
- const response = await fetch ( getRecordsUrl ( rsUrl ) ) ;
25
+ const response = await fetch ( settings . getRecordsUrl ( rsUrl ) ) ;
65
26
if ( ! response . ok ) {
66
27
throw new Error ( `Failed to fetch records: ${ response . statusText } ` ) ;
67
28
}
@@ -126,11 +87,7 @@ async function fetchBugMetadata(bugIds: Set<string>): Promise<BugMetaMap> {
126
87
* Fetch the versions for each Firefox release channel.
127
88
* @returns The versions for each release channel.
128
89
*/
129
- async function fetchVersionsPerChannel ( ) : Promise < {
130
- nightly : string ;
131
- beta : string ;
132
- release : string ;
133
- } > {
90
+ async function fetchVersionsPerChannel ( ) : Promise < FirefoxVersions > {
134
91
let [ nightly , beta , release ] = await Promise . all ( [
135
92
fetchVersionNumber ( "nightly" ) ,
136
93
fetchVersionNumber ( "beta" ) ,
@@ -191,16 +148,15 @@ export class App extends LitElement {
191
148
@state ( )
192
149
error : string | null = null ;
193
150
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.
195
153
@state ( )
196
- firefoxVersions : {
197
- nightly : string ;
198
- beta : string ;
199
- release : string ;
200
- } | null = null ;
154
+ firefoxVersions : FirefoxVersions | null = null ;
201
155
156
+ // The selected Firefox channel to filter entries by. If set to null, entries
157
+ // matching all Firefox versions are displayed.
202
158
@state ( )
203
- filterFirefoxChannel : "nightly" | "beta" | "release" | null = null ;
159
+ filterFirefoxChannel : FirefoxChannel | null = null ;
204
160
205
161
static styles = css `
206
162
/* Sticky headings. */
@@ -240,44 +196,6 @@ export class App extends LitElement {
240
196
font-size: 0.8rem;
241
197
color: var(--text-secondary);
242
198
}
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
- }
281
199
` ;
282
200
283
201
/**
@@ -287,9 +205,10 @@ export class App extends LitElement {
287
205
super . connectedCallback ( ) ;
288
206
289
207
// Set the initial RS environment and preview setting.
290
- let { env, usePreview } = getRsEnv ( ) ;
208
+ let { env, usePreview } = settings . getRsEnv ( ) ;
291
209
this . rsEnv = env ;
292
210
this . rsEnvUsePreview = usePreview ;
211
+ this . filterFirefoxChannel = settings . getFirefoxChannelFilter ( ) ;
293
212
294
213
this . init ( ) ;
295
214
}
@@ -303,11 +222,10 @@ export class App extends LitElement {
303
222
304
223
await this . updateVersionInfo ( ) ;
305
224
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 ;
311
229
}
312
230
313
231
// Fetch the records.
@@ -328,7 +246,6 @@ export class App extends LitElement {
328
246
// Fetch the versions for each release channel.
329
247
try {
330
248
this . firefoxVersions = await fetchVersionsPerChannel ( ) ;
331
- console . debug ( "versions" , this . firefoxVersions ) ;
332
249
} catch ( error ) {
333
250
console . error ( "Failed to fetch Firefox versions" , error ) ;
334
251
}
@@ -413,25 +330,14 @@ export class App extends LitElement {
413
330
}
414
331
415
332
/**
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 .
418
335
*/
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 ;
429
339
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 ) ;
435
341
436
342
// Fetch the records again with the new settings
437
343
try {
@@ -448,13 +354,12 @@ export class App extends LitElement {
448
354
}
449
355
450
356
/**
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.
453
359
*/
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 ) ;
458
363
459
364
// Update the filtered records based on the selected Firefox version.
460
365
// This does not require a full re-fetch of the records.
@@ -599,49 +504,22 @@ export class App extends LitElement {
599
504
>
600
505
for more information.
601
506
</ 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 >
637
515
638
516
${ this . renderMainContent ( ) }
639
517
640
518
< footer >
641
519
< p >
642
520
Data source:
643
521
${ ( ( ) => {
644
- const recordsUrl = getRecordsUrl (
522
+ const recordsUrl = settings . getRecordsUrl (
645
523
getRSEndpoint ( this . rsEnv , this . rsEnvUsePreview ) . toString ( ) ,
646
524
) ;
647
525
return html `< a href ="${ recordsUrl } "> ${ recordsUrl } </ a > ` ;
0 commit comments