5
5
import { LitElement , html , css } from "lit" ;
6
6
import { customElement , state } from "lit/decorators.js" ;
7
7
import { ExceptionListEntry , BugMetaMap } from "./types" ;
8
+ import { getRSEndpoint , RSEnvironment , isRSEnvValid } from "../scripts/rs-config.js" ;
8
9
import "./exceptions-table/exceptions-table" ;
9
10
import "./exceptions-table/top-exceptions-table" ;
10
11
import "./github-corner" ;
@@ -13,51 +14,52 @@ const GITHUB_URL = "https://github.com/mozilla/url-classifier-exceptions-ui";
13
14
14
15
// Query parameter which can be used to override the RS environment.
15
16
const QUERY_PARAM_RS_ENV = "rs_env" ;
16
-
17
- // The available Remote Settings endpoints.
18
- const RS_ENDPOINTS = {
19
- prod : "https://firefox.settings.services.mozilla.com" ,
20
- stage : "https://firefox.settings.services.allizom.org" ,
21
- dev : "https://remote-settings-dev.allizom.org" ,
22
- } as const ;
23
-
24
- type RSEndpointKey = keyof typeof RS_ENDPOINTS ;
17
+ const QUERY_PARAM_RS_USE_PREVIEW = "rs_preview" ;
25
18
26
19
/**
27
20
* Get the RS environment from URL parameters, falling back to the defaults if
28
21
* not specified.
29
22
* @returns The RS environment key
30
23
*/
31
- function getRsEnv ( ) : RSEndpointKey {
24
+ function getRsEnv ( ) : { env : RSEnvironment ; usePreview : boolean } {
25
+ // Check if the environment is specified in the URL.
32
26
const params = new URLSearchParams ( window . location . search ) ;
33
27
const env = params . get ( QUERY_PARAM_RS_ENV ) ;
34
- if ( env && Object . keys ( RS_ENDPOINTS ) . includes ( env ) ) {
35
- return env as RSEndpointKey ;
28
+ const usePreview = params . get ( QUERY_PARAM_RS_USE_PREVIEW ) === "true" ;
29
+ if ( isRSEnvValid ( env ) ) {
30
+ return { env : env as RSEnvironment , usePreview } ;
36
31
}
37
- // Fall back to build env configuration or if env is not set, the default of "prod".
38
- return ( import . meta. env . VITE_RS_ENVIRONMENT as RSEndpointKey ) || "prod" ;
32
+
33
+ // Fall back to build-time environment variable.
34
+ let viteEnv = import . meta. env . VITE_RS_ENVIRONMENT ;
35
+ if ( isRSEnvValid ( viteEnv ) ) {
36
+ return { env : viteEnv as RSEnvironment , usePreview : false } ;
37
+ }
38
+
39
+ // Otherwise default to prod, non preview.
40
+ return { env : "prod" , usePreview : false } ;
39
41
}
40
42
41
43
/**
42
44
* Get the URL for the records endpoint for a given Remote Settings environment.
43
- * @param rsOrigin The origin of the Remote Settings environment.
45
+ * @param rsUrl The URL of the Remote Settings environment.
44
46
* @returns The URL for the records endpoint.
45
47
*/
46
- function getRecordsUrl ( rsOrigin : string ) : string {
48
+ function getRecordsUrl ( rsUrl : string ) : string {
47
49
// Allow ENV to override the URL for testing.
48
50
if ( import . meta. env . VITE_RS_RECORDS_URL ) {
49
51
return import . meta. env . VITE_RS_RECORDS_URL ;
50
52
}
51
- return ` ${ rsOrigin } /v1/buckets/main/collections/url-classifier-exceptions/records` ;
53
+ return rsUrl ;
52
54
}
53
55
54
56
/**
55
57
* Fetch the records from the Remote Settings environment.
56
- * @param rsOrigin The origin of the Remote Settings environment.
58
+ * @param rsUrl The URL of the Remote Settings environment.
57
59
* @returns The records.
58
60
*/
59
- async function fetchRecords ( rsOrigin : string ) : Promise < ExceptionListEntry [ ] > {
60
- const response = await fetch ( getRecordsUrl ( rsOrigin ) ) ;
61
+ async function fetchRecords ( rsUrl : string ) : Promise < ExceptionListEntry [ ] > {
62
+ const response = await fetch ( getRecordsUrl ( rsUrl ) ) ;
61
63
if ( ! response . ok ) {
62
64
throw new Error ( `Failed to fetch records: ${ response . statusText } ` ) ;
63
65
}
@@ -124,7 +126,13 @@ export class App extends LitElement {
124
126
// at build time. The user can change this via a dropdown. The user can also
125
127
// override the environment via a query parameter.
126
128
@state ( )
127
- rsEnv : RSEndpointKey = getRsEnv ( ) ;
129
+ rsEnv : RSEnvironment = "prod" ;
130
+
131
+ // Whether to use the preview environment. This bucket includes changes that
132
+ // are still pending review. The user can change this via a checkbox. It can
133
+ // also be overridden via a query parameter.
134
+ @state ( )
135
+ rsEnvUsePreview : boolean = false ;
128
136
129
137
// Holds all fetched records.
130
138
@state ( )
@@ -187,6 +195,12 @@ export class App extends LitElement {
187
195
*/
188
196
connectedCallback ( ) {
189
197
super . connectedCallback ( ) ;
198
+
199
+ // Set the initial RS environment and preview setting.
200
+ let { env, usePreview } = getRsEnv ( ) ;
201
+ this . rsEnv = env ;
202
+ this . rsEnvUsePreview = usePreview ;
203
+
190
204
this . init ( ) ;
191
205
}
192
206
@@ -196,7 +210,9 @@ export class App extends LitElement {
196
210
async init ( ) {
197
211
try {
198
212
this . loading = true ;
199
- this . records = await fetchRecords ( RS_ENDPOINTS [ this . rsEnv ] ) ;
213
+
214
+ const urlStr = getRSEndpoint ( this . rsEnv , this . rsEnvUsePreview ) . toString ( ) ;
215
+ this . records = await fetchRecords ( urlStr ) ;
200
216
201
217
// Spot check if the format is as expected.
202
218
if ( this . records . length && this . records [ 0 ] . bugIds == null ) {
@@ -227,6 +243,31 @@ export class App extends LitElement {
227
243
return new Set ( this . records . flatMap ( ( record ) => record . bugIds || [ ] ) ) . size ;
228
244
}
229
245
246
+ /**
247
+ * Handle changes to RS environment settings via the UI.
248
+ * @param event The change event either the dropdown or the checkbox.
249
+ */
250
+ private handleRSEnvChange ( event : Event ) {
251
+ const target = event . target as HTMLSelectElement | HTMLInputElement ;
252
+
253
+ if ( target . id === "rs-env" ) {
254
+ this . rsEnv = ( target as HTMLSelectElement ) . value as RSEnvironment ;
255
+ // Reset preview setting when environment changes.
256
+ this . rsEnvUsePreview = false ;
257
+ } else if ( target . id === "rs-env-preview" ) {
258
+ this . rsEnvUsePreview = ( target as HTMLInputElement ) . checked ;
259
+ }
260
+
261
+ // Update URL parameters to reflect current settings
262
+ const url = new URL ( window . location . href ) ;
263
+ url . searchParams . set ( QUERY_PARAM_RS_ENV , this . rsEnv ) ;
264
+ url . searchParams . set ( QUERY_PARAM_RS_USE_PREVIEW , this . rsEnvUsePreview . toString ( ) ) ;
265
+ window . history . pushState ( { } , "" , url ) ;
266
+
267
+ // Fetch the records again with the new settings
268
+ this . init ( ) ;
269
+ }
270
+
230
271
/**
231
272
* Handle anchor navigation. We need to do this via JS because native navigation
232
273
* does not traverse shadow DOM.
@@ -370,32 +411,28 @@ export class App extends LitElement {
370
411
< footer >
371
412
< p >
372
413
< label for ="rs-env "> Remote Settings Environment:</ label >
373
- < select
374
- id ="rs-env "
375
- @change =${ ( e : Event ) => {
376
- const newEnv = ( e . target as HTMLSelectElement ) . value as RSEndpointKey ;
377
- this . rsEnv = newEnv ;
378
-
379
- // When the env changes reflect the update in the URL.
380
- // Update URL parameter without reloading the page
381
- const url = new URL ( window . location . href ) ;
382
- url . searchParams . set ( QUERY_PARAM_RS_ENV , newEnv ) ;
383
- window . history . pushState ( { } , "" , url ) ;
384
-
385
- // Fetch the records again.
386
- this . init ( ) ;
387
- } }
388
- >
414
+ < select id ="rs-env " @change =${ this . handleRSEnvChange } >
389
415
< option value ="prod " ?selected =${ this . rsEnv === "prod" } > Prod</ option >
390
416
< option value ="stage " ?selected =${ this . rsEnv === "stage" } > Stage</ option >
391
417
< option value ="dev " ?selected =${ this . rsEnv === "dev" } > Dev</ option >
392
418
</ select >
419
+ < br />
420
+ < label for ="rs-env-preview "> Show changes pending review:</ label >
421
+ < input
422
+ id ="rs-env-preview "
423
+ type ="checkbox "
424
+ ?checked =${ this . rsEnvUsePreview }
425
+ @change =${ this . handleRSEnvChange }
426
+ />
393
427
</ p >
394
428
< p >
395
429
Data source:
396
- < a href ="${ getRecordsUrl ( RS_ENDPOINTS [ this . rsEnv ] ) } "
397
- > ${ getRecordsUrl ( RS_ENDPOINTS [ this . rsEnv ] ) } </ a
398
- > .
430
+ ${ ( ( ) => {
431
+ const recordsUrl = getRecordsUrl (
432
+ getRSEndpoint ( this . rsEnv , this . rsEnvUsePreview ) . toString ( ) ,
433
+ ) ;
434
+ return html `< a href ="${ recordsUrl } "> ${ recordsUrl } </ a > ` ;
435
+ } ) ( ) } .
399
436
</ p >
400
437
</ footer >
401
438
<!-- Show a link to the repository in the top right corner -->
0 commit comments