Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize filter management mechanisms #6499

Closed
Tracked by #6120
asteriscos opened this issue Mar 12, 2024 · 6 comments · Fixed by #6534
Closed
Tracked by #6120

Standardize filter management mechanisms #6499

asteriscos opened this issue Mar 12, 2024 · 6 comments · Fixed by #6534
Assignees
Labels
level/task Task issue type/enhancement Enhancement issue

Comments

@asteriscos
Copy link
Member

asteriscos commented Mar 12, 2024

Description

We need to refactor and standardize the filtering mechanisms so all the embeddable dashboards and reports can make use of the filter state without using any of the legacy methods. This is a step forward towards deprecating the Discover legacy, AngularJS, and also integrating the new embeddable dashboards with the PDF reports.

Functional requirements

  • The filter system must consider the search bar filters
  • The filter system must consider the hideManager alerts configuration
  • The filter system must consider if an agent is pinned
  • The filter system must consider the allowed agents by RBAC
  • The filter system must consider the selected cluster
@Machi3mfl
Copy link
Member

Machi3mfl commented Mar 13, 2024

Scope

The aim is to generate a standard solution that allows each system module (such as vulnerabilities) to manage its own data source.
It is important that the solution is standard and allows:

  • Retrieving filters (getFilters)
  • Fetching data (fetchData)

The goal is for each module to be able to manage its own data source, to be able to decouple, decentralize, and give responsibility to each module for its own data source.

Problematic

Currently, the state of the current filters comes from different sources:

  • FilterManager (OSD Filter Manager)
  • Session Storage (Browser)

Every module has specific default filters, and need to preserve and merge them with the user filters if are inside the module.

Use Case

  • When we navigate to specific modules, exists a filter that is applied by default. Also, we need to check the OSD filter manager to see if the filters correspond with the current module.

Plan

Screen.Recording.2024-04-03.at.14.17.47.mov

@Machi3mfl
Copy link
Member

Machi3mfl commented Mar 19, 2024

Create a generic solution design

Data source filter manager

Is a class that is responsible for managing the filters of a data source (Important: the filters are not managed by the data source itself, it's managed by the filter manager). This allows the filters to be managed in a centralized way but at the same time makes it responsive to the data source to define its filters.

Use cases

  • The data source filter manager receives a data source and the filters from the filter manager or another source. The filters have the type Filter.

  • When the data source filter manager receives the filters:

    • Filter the filters received and only keep the filters that was added by the user.
      Condition: When the filter not have the property meta.controlledBy, $state.isImplicit and the meta.index is not the same as the data source index pattern.
  • Then is able to:

    • Retrieve the filters applied by the user and the data source filters (For instance: the vulnerabilities module). Every module has the responsibility to manage its own filters.
    • Fetch the data from the data source using the filters and add extra filters that are not visible to the user.
      For instance: hide manager, pinned agent, allowed agents, etc.

Solution

export type tDataSource = {
    id: string;
    title: string;
    select(): Promise<void>;
    getFilters: () => Promise<tFilter[]> | tFilter[];
    setFilters: (filters: tFilter[]) => Promise<void> | void;
    getFields: () => Promise<any[]> | any[];
    getFixedFilters: () => tFilter[];
    getFetchFilters: () => tFilter[];
    fetch: (params: tSearchParams) => Promise<any>;
    toJSON(): object;
}

export interface IDataSourceFactoryConstructor<T extends tDataSource> {
    new(id: T['id'], title: T['title']): T;
}

export type tDataSourceFactory<T extends object, K extends tDataSource> = {
    create: (DataSourceType: IDataSourceFactoryConstructor<K>, data: T) => Promise<K>;
    createAll: (DataSourceType: IDataSourceFactoryConstructor<K>, data: T[]) => Promise<K[]>;
}

export type tDataSourceFilterManager = {
    fetch: () => Promise<any>;
    setFilters: (filters: tFilter[]) => void;
    getFilters: () => tFilter[];
    getFixedFilters: () => tFilter[];
    getFetchFilters: () => tFilter[];
}

export type tDataSourceRepository<T extends object> = {
    get(id: string): Promise<T>;
    getAll(): Promise<T[]>;
    setDefault(dataSourceData: T): Promise<void> | void;
    getDefault(): Promise<T | null> | T | null;
}

export type tDataSourceSelector<T extends tDataSource> = {
    existsDataSource: (id: string) => Promise<boolean>;
    getFirstValidDataSource: () => Promise<T>;
    getAllDataSources: () => Promise<T[]>;
    getDataSource: (id: string) => Promise<T>;
    getSelectedDataSource: () => Promise<T>;
    selectDataSource: (id: string) => Promise<void>;
}

export type tFilter = Filter & {
    meta?: {
        removable?: boolean;
    }
};

export type tSearchParams = {
    filters?: tFilter[];
    query?: any;
    pagination?: {
        pageIndex?: number;
        pageSize?: number;
    };
    fields?: string[],
    sorting?: {
        columns: {
            id: string;
            direction: 'asc' | 'desc';
        }[];
    };
    dateRange?: {
        from: string;
        to: string;
    };
}

Unit tests

Screenshot 2024-03-31 at 15 08 24

@Machi3mfl Machi3mfl linked a pull request Mar 19, 2024 that will close this issue
6 tasks
@Machi3mfl
Copy link
Member

Machi3mfl commented Mar 20, 2024

Create a generic solution design

Data source hook

Create a react hook that:

  • simplifies the use of data sources, related filters, fetching data
  • reduce the boilerplate
type tUseDataSourceProps<T extends object, K extends PatternDataSource> = {
    DataSource: IDataSourceFactoryConstructor<K>;
    repository: tDataSourceRepository<T>;
    factory?: PatternDataSourceFactory;
    filterManager?: tFilterManager;
    filters?: tFilter[];
}

type tUseDataSourceLoadedReturns<K> = {
    isLoading: boolean;
    dataSource: K;
    filters: tFilter[];
    fetchFilters: tFilter[];
    fixedFilters: tFilter[];
    fetchData: (params: Omit<tSearchParams, 'filters'>) => Promise<any>;
    setFilters: (filters: tFilter[]) => void;
    filterManager: PatternDataSourceFilterManager;
}

type tUseDataSourceNotLoadedReturns = {
    isLoading: boolean;
    dataSource: undefined;
    filters: [];
    fetchFilters: [];
    fixedFilters: [];
    fetchData: (params: Omit<tSearchParams, 'filters'>) => Promise<any>;
    setFilters: (filters: tFilter[]) => void;
    filterManager: null;
}

Unit tests

Screenshot 2024-03-31 at 15 08 32

@Machi3mfl
Copy link
Member

Machi3mfl commented Mar 26, 2024

Implemented on Vulnerability Detection Module

Screen.Recording.2024-03-27.at.16.55.26.mov

This solution uses the new:

  • Data Source solution
  • useDataSource hook
  • Wazuh discover with useDataSource hook added

@Machi3mfl
Copy link
Member

Add unit tests to the final solution

Screenshot 2024-03-31 at 15 08 54 Screenshot 2024-03-31 at 15 08 48 Screenshot 2024-03-31 at 15 08 40 Screenshot 2024-03-31 at 15 08 32 Screenshot 2024-03-31 at 15 08 24

@Machi3mfl
Copy link
Member

How to use the new data source solution

(Coming soon ⏳)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
level/task Task issue type/enhancement Enhancement issue
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants