@@ -38,6 +38,8 @@ import { ActionTypes } from 'lib/stores/SchemaStore';
3838import stringCompare from 'lib/stringCompare' ;
3939import subscribeTo from 'lib/subscribeTo' ;
4040import { withRouter } from 'lib/withRouter' ;
41+ import FilterPreferencesManager from 'lib/FilterPreferencesManager' ;
42+ import { prefersServerStorage } from 'lib/StoragePreferences' ;
4143import Parse from 'parse' ;
4244import React from 'react' ;
4345import { Helmet } from 'react-helmet' ;
@@ -129,6 +131,7 @@ class Browser extends DashboardView {
129131 this . subsection = 'Browser' ;
130132 this . noteTimeout = null ;
131133 this . currentQuery = null ;
134+ this . filterPreferencesManager = null ;
132135 const limit = window . localStorage ?. getItem ( 'browserLimit' ) ;
133136
134137 this . state = {
@@ -188,6 +191,7 @@ class Browser extends DashboardView {
188191 AggregationPanelData : { } ,
189192 isLoadingInfoPanel : false ,
190193 errorAggregatedData : { } ,
194+ classFilters : { } , // Map of className -> filters array
191195 } ;
192196
193197 this . addLocation = this . addLocation . bind ( this ) ;
@@ -298,6 +302,52 @@ class Browser extends DashboardView {
298302 this . setState ( { configData : data } ) ;
299303 this . classAndCloudFuntionMap ( this . state . configData ) ;
300304 } ) ;
305+
306+ // Initialize FilterPreferencesManager
307+ if ( this . context ) {
308+ this . filterPreferencesManager = new FilterPreferencesManager ( this . context ) ;
309+ // Load all class filters if schema is already available
310+ if ( this . props . schema ?. data ?. get ( 'classes' ) ) {
311+ this . loadAllClassFilters ( ) ;
312+ }
313+ }
314+ }
315+
316+ async loadAllClassFilters ( propsToUse ) {
317+ if ( ! this . filterPreferencesManager ) {
318+ return ;
319+ }
320+
321+ // Use provided props or fall back to this.props
322+ const props = propsToUse || this . props ;
323+ const schema = props . schema ;
324+ if ( ! schema || ! schema . data ) {
325+ return ;
326+ }
327+
328+ const classFilters = { } ;
329+
330+ // Load filters for all classes
331+ const classList = schema . data . get ( 'classes' ) ;
332+ if ( classList ) {
333+ const classNames = Object . keys ( classList . toObject ( ) ) ;
334+ await Promise . all (
335+ classNames . map ( async ( className ) => {
336+ try {
337+ const filters = await this . filterPreferencesManager . getFilters (
338+ this . context . applicationId ,
339+ className
340+ ) ;
341+ classFilters [ className ] = filters || [ ] ;
342+ } catch ( error ) {
343+ console . error ( `Failed to load filters for class ${ className } :` , error ) ;
344+ classFilters [ className ] = [ ] ;
345+ }
346+ } )
347+ ) ;
348+ }
349+
350+ this . setState ( { classFilters } ) ;
301351 }
302352
303353 componentWillUnmount ( ) {
@@ -340,6 +390,15 @@ class Browser extends DashboardView {
340390 ) ;
341391 this . redirectToFirstClass ( nextProps . schema . data . get ( 'classes' ) , nextContext ) ;
342392 }
393+
394+ // Load filters when schema becomes available or changes
395+ if (
396+ nextProps . schema ?. data ?. get ( 'classes' ) &&
397+ ( ! this . props . schema ?. data ?. get ( 'classes' ) ||
398+ this . props . params . appId !== nextProps . params . appId )
399+ ) {
400+ this . loadAllClassFilters ( nextProps ) ;
401+ }
343402 }
344403
345404 setLoadingInfoPanel ( bool ) {
@@ -1294,7 +1353,7 @@ class Browser extends DashboardView {
12941353 } ) ;
12951354 }
12961355
1297- saveFilters ( filters , name , relativeDate , filterId = null ) {
1356+ async saveFilters ( filters , name , relativeDate , filterId = null ) {
12981357 const jsonFilters = filters . toJSON ( ) ;
12991358 if ( relativeDate && jsonFilters ?. length ) {
13001359 for ( let i = 0 ; i < jsonFilters . length ; i ++ ) {
@@ -1364,15 +1423,16 @@ class Browser extends DashboardView {
13641423 } ) ;
13651424 }
13661425 } else {
1367- // Check if this is updating a legacy filter (no filterId but filter content matches existing filter without ID)
1368- const existingLegacyFilterIndex = preferences . filters . findIndex ( filter =>
1369- ! filter . id && filter . name === name && filter . filter === _filters
1426+ // Check if this is updating an existing filter by name and content match
1427+ // (legacy filters get auto-assigned UUIDs when read, so we match by content)
1428+ const existingFilterIndex = preferences . filters . findIndex ( filter =>
1429+ filter . name === name && filter . filter === _filters
13701430 ) ;
13711431
1372- if ( existingLegacyFilterIndex !== - 1 ) {
1373- // Convert legacy filter to modern filter by adding an ID
1374- newFilterId = crypto . randomUUID ( ) ;
1375- preferences . filters [ existingLegacyFilterIndex ] = {
1432+ if ( existingFilterIndex !== - 1 ) {
1433+ // Update existing filter, keeping its ID
1434+ newFilterId = preferences . filters [ existingFilterIndex ] . id ;
1435+ preferences . filters [ existingFilterIndex ] = {
13761436 name,
13771437 id : newFilterId ,
13781438 filter : _filters ,
@@ -1388,19 +1448,60 @@ class Browser extends DashboardView {
13881448 }
13891449 }
13901450
1391- ClassPreferences . updatePreferences (
1392- preferences ,
1393- this . context . applicationId ,
1394- this . props . params . className
1395- ) ;
1451+ // Use FilterPreferencesManager if available, otherwise fallback to local storage
1452+ if ( this . filterPreferencesManager ) {
1453+ const filterToSave = {
1454+ id : newFilterId ,
1455+ name,
1456+ className : this . props . params . className ,
1457+ filter : _filters ,
1458+ } ;
1459+ await this . filterPreferencesManager . saveFilter (
1460+ this . context . applicationId ,
1461+ this . props . params . className ,
1462+ filterToSave ,
1463+ preferences . filters
1464+ ) ;
1465+ } else {
1466+ // Fallback to local storage
1467+ ClassPreferences . updatePreferences (
1468+ preferences ,
1469+ this . context . applicationId ,
1470+ this . props . params . className
1471+ ) ;
1472+ }
1473+
1474+ // Reload filters for this class to update the sidebar
1475+ await this . reloadClassFilters ( this . props . params . className ) ;
13961476
13971477 super . forceUpdate ( ) ;
13981478
13991479 // Return the filter ID for new filters so the caller can apply them
14001480 return newFilterId ;
14011481 }
14021482
1403- deleteFilter ( filterIdOrObject ) {
1483+ async reloadClassFilters ( className ) {
1484+ if ( ! this . filterPreferencesManager ) {
1485+ return ;
1486+ }
1487+
1488+ try {
1489+ const filters = await this . filterPreferencesManager . getFilters (
1490+ this . context . applicationId ,
1491+ className
1492+ ) ;
1493+ this . setState ( prevState => ( {
1494+ classFilters : {
1495+ ...prevState . classFilters ,
1496+ [ className ] : filters || [ ]
1497+ }
1498+ } ) ) ;
1499+ } catch ( error ) {
1500+ console . error ( `Failed to reload filters for class ${ className } :` , error ) ;
1501+ }
1502+ }
1503+
1504+ async deleteFilter ( filterIdOrObject ) {
14041505 const preferences = ClassPreferences . getPreferences (
14051506 this . context . applicationId ,
14061507 this . props . params . className
@@ -1425,13 +1526,27 @@ class Browser extends DashboardView {
14251526 }
14261527 }
14271528
1428- ClassPreferences . updatePreferences (
1429- { ...preferences , filters : updatedFilters } ,
1430- this . context . applicationId ,
1431- this . props . params . className
1432- ) ;
1529+ // Use FilterPreferencesManager if available, otherwise fallback to local storage
1530+ if ( this . filterPreferencesManager ) {
1531+ await this . filterPreferencesManager . deleteFilter (
1532+ this . context . applicationId ,
1533+ this . props . params . className ,
1534+ filterIdOrObject ,
1535+ updatedFilters
1536+ ) ;
1537+ } else {
1538+ // Fallback to local storage
1539+ ClassPreferences . updatePreferences (
1540+ { ...preferences , filters : updatedFilters } ,
1541+ this . context . applicationId ,
1542+ this . props . params . className
1543+ ) ;
1544+ }
14331545 }
14341546
1547+ // Reload filters for this class to update the sidebar
1548+ await this . reloadClassFilters ( this . props . params . className ) ;
1549+
14351550 super . forceUpdate ( ) ;
14361551 }
14371552
@@ -2263,13 +2378,24 @@ class Browser extends DashboardView {
22632378 }
22642379 const allCategories = [ ] ;
22652380 for ( const row of [ ...special , ...categories ] ) {
2266- const { filters = [ ] } = ClassPreferences . getPreferences (
2267- this . context . applicationId ,
2268- row . name
2269- ) ;
2270- // Set filters sorted alphabetically
2271- row . filters = filters . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
2272- allCategories . push ( row ) ;
2381+ let filters = this . state . classFilters [ row . name ] ;
2382+
2383+ // Fallback to local storage ONLY if not using server storage and filters not loaded yet
2384+ if ( filters === undefined &&
2385+ ( ! this . filterPreferencesManager ?. isServerConfigEnabled ( ) ||
2386+ ! prefersServerStorage ( this . context . applicationId ) ) ) {
2387+ const prefs = ClassPreferences . getPreferences ( this . context . applicationId , row . name ) ;
2388+ filters = prefs ?. filters || [ ] ;
2389+ } else if ( filters === undefined ) {
2390+ filters = [ ] ;
2391+ }
2392+
2393+ // Set filters sorted alphabetically and create a new row object to trigger re-render
2394+ const sortedFilters = filters . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
2395+ allCategories . push ( {
2396+ ...row ,
2397+ filters : sortedFilters
2398+ } ) ;
22732399 }
22742400
22752401 return (
0 commit comments