go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/frontend/ui/src/components/clusters_table/hooks.tsx (about)

     1  // Copyright 2023 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import {
    16    ParamKeyValuePair,
    17    useSearchParams,
    18  } from 'react-router-dom';
    19  
    20  import { TimeInterval } from '@/hooks/use_fetch_clusters';
    21  import { ProjectMetric } from '@/proto/go.chromium.org/luci/analysis/proto/v1/metrics.pb';
    22  import { MetricId } from '@/types/metric_id';
    23  
    24  export interface OrderBy {
    25    metric: MetricId,
    26    isAscending: boolean,
    27  }
    28  
    29  export function useFilterParam(): [string, (failureFilter: string, replace?: boolean) => void] {
    30    const [searchParams, setSearchParams] = useSearchParams();
    31    const failureFilter = searchParams.get('q') || '';
    32  
    33    function updateFailureFilterParam(failureFilter: string, replace = false) {
    34      const params: ParamKeyValuePair[] = [];
    35  
    36      for (const [k, v] of searchParams.entries()) {
    37        if (k !== 'q') {
    38          params.push([k, v]);
    39        }
    40      }
    41  
    42      if (failureFilter !== '') {
    43        params.push(['q', failureFilter]);
    44      }
    45      setSearchParams(params, {
    46        replace,
    47      });
    48    }
    49  
    50    return [failureFilter, updateFailureFilterParam];
    51  }
    52  
    53  export function useIntervalParam(intervals: TimeInterval[]): [TimeInterval | undefined, (selectedInterval: TimeInterval, replace?: boolean) => void] {
    54    const [searchParams, setSearchParams] = useSearchParams();
    55    const intervalParam = searchParams.get('interval') || '';
    56    let interval: TimeInterval | undefined = undefined;
    57    if (intervalParam) {
    58      interval = intervals.find((option) => option.id === intervalParam);
    59    }
    60  
    61    function updateIntervalParam(selectedInterval: TimeInterval, replace = false) {
    62      const params: ParamKeyValuePair[] = [];
    63  
    64      for (const [k, v] of searchParams.entries()) {
    65        if (k !== 'interval') {
    66          params.push([k, v]);
    67        }
    68      }
    69  
    70      params.push(['interval', selectedInterval.id]);
    71  
    72      setSearchParams(params, {
    73        replace,
    74      });
    75    }
    76  
    77    return [interval, updateIntervalParam];
    78  }
    79  
    80  export function useOrderByParam(metrics: ProjectMetric[]): [OrderBy | undefined, (orderBy: OrderBy, replace?: boolean) => void] {
    81    const [searchParams, setSearchParams] = useSearchParams();
    82    const orderByParam = searchParams.get('orderBy') || '';
    83    const orderDir = searchParams.get('orderDir') || '';
    84  
    85    let orderBy: OrderBy | undefined = undefined;
    86  
    87    if (orderByParam) {
    88      // Ensure the metric we are being asked to order by
    89      // is one of the metrics we are querying.
    90      if (metrics.some((metric) => metric.metricId == orderByParam)) {
    91        orderBy = {
    92          metric: orderByParam,
    93          isAscending: orderDir === 'asc',
    94        };
    95      }
    96    }
    97  
    98    function updateOrderByParams(orderBy: OrderBy, replace = false) {
    99      const params: ParamKeyValuePair[] = [];
   100  
   101      for (const [k, v] of searchParams.entries()) {
   102        if (k !== 'orderBy' && k !== 'orderDir') {
   103          params.push([k, v]);
   104        }
   105      }
   106      if (orderBy) {
   107        params.push(['orderBy', orderBy.metric]);
   108        if (orderBy.isAscending) {
   109          params.push(['orderDir', 'asc']);
   110        }
   111      }
   112      setSearchParams(params, {
   113        replace,
   114      });
   115    }
   116  
   117    return [orderBy, updateOrderByParams];
   118  }
   119  
   120  export function useSelectedMetricsParam(metrics: ProjectMetric[]): [ProjectMetric[], (selectedMetrics: ProjectMetric[], replace?: boolean) => void] {
   121    const [searchParams, setSearchParams] = useSearchParams();
   122    const selectedMetricsParam = searchParams.get('selectedMetrics') || '';
   123    const selectedMetricsIds = selectedMetricsParam.split(',');
   124  
   125    const selectedMetrics = metrics.filter((metric) => selectedMetricsIds.indexOf(metric.metricId) > -1);
   126  
   127    function updateSelectedMetricsParam(selectedMetrics: ProjectMetric[], replace = false) {
   128      const params: ParamKeyValuePair[] = [];
   129  
   130      const selectedMetricsIds = selectedMetrics.map((metric) => metric.metricId).join(',');
   131      params.push(['selectedMetrics', selectedMetricsIds]);
   132  
   133      const orderByParam = searchParams.get('orderBy');
   134      let addedOrderBy = false;
   135      if (selectedMetrics.findIndex((m) => m.metricId === orderByParam) < 0) {
   136        let orderByValue = '';
   137        if (selectedMetrics.length > 0) {
   138          let highestMetric = selectedMetrics[0];
   139          selectedMetrics.forEach((m) => {
   140            if (m.sortPriority > highestMetric.sortPriority) {
   141              highestMetric = m;
   142            }
   143          });
   144          orderByValue = highestMetric.metricId;
   145        }
   146        params.push(['orderBy', orderByValue]);
   147        params.push(['orderDir', 'desc']);
   148        addedOrderBy = true;
   149      }
   150  
   151      for (const [k, v] of searchParams.entries()) {
   152        if (((k === 'orderBy' || k === 'orderDir') && addedOrderBy) ||
   153          k === 'selectedMetrics') {
   154          continue;
   155        }
   156        params.push([k, v]);
   157      }
   158      setSearchParams(params, {
   159        replace,
   160      });
   161    }
   162  
   163    return [selectedMetrics, updateSelectedMetricsParam];
   164  }