go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/test_verdict/pages/recent_regressions_page/recent_regressions.tsx (about)

     1  // Copyright 2024 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 { Box, CircularProgress } from '@mui/material';
    16  import { useQuery } from '@tanstack/react-query';
    17  import { useCallback } from 'react';
    18  
    19  import { useChangepointsClient } from '@/analysis/hooks/prpc_clients';
    20  import { useSyncedSearchParams } from '@/generic_libs/hooks/synced_search_params';
    21  import {
    22    ChangepointPredicate,
    23    QueryChangepointGroupSummariesRequest,
    24  } from '@/proto/go.chromium.org/luci/analysis/proto/v1/changepoints.pb';
    25  import { getRegressionDetailsURLPath } from '@/test_verdict/tools/url_utils';
    26  import { OutputChangepointGroupSummary } from '@/test_verdict/types';
    27  
    28  import { RegressionFilters } from './regression_filters';
    29  import { RegressionTable } from './regression_table';
    30  
    31  function getPredicate(searchParams: URLSearchParams) {
    32    const predicate = searchParams.get('cp') || '{}';
    33    return ChangepointPredicate.fromJSON(JSON.parse(predicate));
    34  }
    35  
    36  function predicateUpdater(newPredicate: ChangepointPredicate) {
    37    return (params: URLSearchParams) => {
    38      const searchParams = new URLSearchParams(params);
    39      const predicateStr = JSON.stringify(
    40        ChangepointPredicate.toJSON(newPredicate),
    41      );
    42      if (predicateStr === '{}') {
    43        searchParams.delete('cp');
    44      } else {
    45        searchParams.set('cp', predicateStr);
    46      }
    47      return searchParams;
    48    };
    49  }
    50  
    51  export interface RecentRegressionsProps {
    52    readonly project: string;
    53  }
    54  
    55  export function RecentRegressions({ project }: RecentRegressionsProps) {
    56    const [searchParams, setSearchParams] = useSyncedSearchParams();
    57    const predicate = getPredicate(searchParams);
    58  
    59    const client = useChangepointsClient();
    60    const { data, isLoading, isError, error } = useQuery(
    61      client.QueryChangepointGroupSummaries.query(
    62        QueryChangepointGroupSummariesRequest.fromPartial({
    63          project,
    64          predicate,
    65        }),
    66      ),
    67    );
    68  
    69    if (isError) {
    70      throw error;
    71    }
    72  
    73    const getDetailsUrlPath = useCallback(
    74      (group: OutputChangepointGroupSummary) =>
    75        getRegressionDetailsURLPath({
    76          canonicalChangepoint: group.canonicalChangepoint,
    77          predicate,
    78        }),
    79      [predicate],
    80    );
    81  
    82    return (
    83      <>
    84        <Box
    85          display="flex"
    86          justifyContent="center"
    87          alignItems="center"
    88          sx={{ margin: '10px 20px' }}
    89        >
    90          <RegressionFilters
    91            predicate={predicate}
    92            onPredicateUpdate={(p) => setSearchParams(predicateUpdater(p))}
    93          />
    94        </Box>
    95        {isLoading ? (
    96          <Box display="flex" justifyContent="center" alignItems="center">
    97            <CircularProgress />
    98          </Box>
    99        ) : (
   100          <RegressionTable
   101            regressions={
   102              data.groupSummaries as readonly OutputChangepointGroupSummary[]
   103            }
   104            getDetailsUrlPath={getDetailsUrlPath}
   105          />
   106        )}
   107      </>
   108    );
   109  }