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

     1  // Copyright 2022 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 { useState } from 'react';
    16  import { Link as RouterLink } from 'react-router-dom';
    17  
    18  import Archive from '@mui/icons-material/Archive';
    19  import Unarchive from '@mui/icons-material/Unarchive';
    20  import LoadingButton from '@mui/lab/LoadingButton';
    21  import Box from '@mui/material/Box';
    22  import Container from '@mui/material/Container';
    23  import Grid from '@mui/material/Grid';
    24  import Link from '@mui/material/Link';
    25  import Paper from '@mui/material/Paper';
    26  import PanelHeading from '@/components/headings/panel_heading/panel_heading';
    27  
    28  import ConfirmDialog from '@/components/confirm_dialog/confirm_dialog';
    29  import GridLabel from '@/components/grid_label/grid_label';
    30  import HelpTooltip from '@/components/help_tooltip/help_tooltip';
    31  import RuleEditDialog from '@/components/rule/rule_edit_dialog/rule_edit_dialog';
    32  import { useMutateRule } from '@/hooks/use_mutate_rule';
    33  import { Rule, UpdateRuleRequest } from '@/proto/go.chromium.org/luci/analysis/proto/v1/rules.pb';
    34  import { linkToCluster } from '@/tools/urlHandling/links';
    35  import RuleDefinition from '../rule_definition/rule_definition';
    36  
    37  const definitionTooltipText = 'The failures matched by this rule.';
    38  const archivedTooltipText = 'Archived failure association rules do not match failures. If a rule is no longer needed, it should be archived.';
    39  const sourceClusterTooltipText = 'The cluster this rule was originally created from.';
    40  
    41  interface Props {
    42      project: string;
    43      rule: Rule;
    44  }
    45  
    46  const RuleInfo = ({ project, rule }: Props) => {
    47    const [editDialogOpen, setEditDialogOpen] = useState(false);
    48    const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
    49  
    50    const mutateRule = useMutateRule();
    51  
    52    const toggleArchived = () => {
    53      const request: UpdateRuleRequest = UpdateRuleRequest.create({
    54        rule: {
    55          name: rule.name,
    56          isActive: !rule.isActive,
    57        },
    58        updateMask: Object.freeze(['isActive']),
    59        etag: rule.etag,
    60      });
    61      mutateRule.mutate(request);
    62    };
    63  
    64    const onArchiveConfirm = () => {
    65      setConfirmDialogOpen(false);
    66      toggleArchived();
    67    };
    68  
    69    const onArchiveCancel = () => {
    70      setConfirmDialogOpen(false);
    71    };
    72  
    73    return (
    74      <Paper data-cy="rule-info" elevation={3} sx={{ pt: 2, pb: 2, mt: 1 }} >
    75        <Container maxWidth={false}>
    76          <PanelHeading>
    77            Rule Details
    78          </PanelHeading>
    79          <Grid container rowGap={1}>
    80            <GridLabel text="Rule definition">
    81              <HelpTooltip text={definitionTooltipText} />
    82            </GridLabel>
    83            <Grid item xs={10} alignItems="center">
    84              <RuleDefinition definition={rule.ruleDefinition} onEditClicked={() => setEditDialogOpen(true)} />
    85            </Grid>
    86            <GridLabel text="Source cluster">
    87              <HelpTooltip text={sourceClusterTooltipText} />
    88            </GridLabel>
    89            <Grid item xs={10} alignItems="center">
    90              <Box sx={{ display: 'inline-block' }} paddingTop={1}>
    91                {
    92                  rule.sourceCluster?.algorithm && rule.sourceCluster?.id ? (
    93                    <Link aria-label='source cluster link' component={RouterLink} to={linkToCluster(project, rule.sourceCluster)}>
    94                      {rule.sourceCluster.algorithm}/{rule.sourceCluster.id}
    95                    </Link>
    96                  ) : (
    97                      'None'
    98                  )
    99                }
   100              </Box>
   101            </Grid>
   102            <GridLabel text="Archived">
   103              <HelpTooltip text={archivedTooltipText} />
   104            </GridLabel>
   105            <Grid item xs={10} alignItems="center" columnGap={1}>
   106              <Box data-testid="rule-archived" sx={{ display: 'inline-block' }} paddingTop={1} paddingRight={1}>
   107                {rule.isActive ? 'No' : 'Yes'}
   108              </Box>
   109              <LoadingButton
   110                data-testid="rule-archived-toggle"
   111                loading={mutateRule.isLoading}
   112                variant="outlined"
   113                startIcon={rule.isActive ? (<Archive />) : (<Unarchive />)}
   114                onClick={() => setConfirmDialogOpen(true)}>
   115                {rule.isActive ? 'Archive' : 'Restore'}
   116              </LoadingButton>
   117            </Grid>
   118          </Grid>
   119        </Container>
   120        <ConfirmDialog
   121          open={confirmDialogOpen}
   122          message={
   123            rule.isActive?
   124            'Impact and recent failures are not available for archived rules.'+
   125            ' Automatic bug priority updates and auto-closure will also cease.'+
   126            ' You can restore archived rules at any time.' :
   127            'LUCI Analysis automatically archives rules when the associated'+
   128            ' bug has been closed for 30 days. Please make sure the associated'+
   129            ' bug is no longer closed to avoid this rule being automatically'+
   130            ' re-archived.'
   131          }
   132          onConfirm={onArchiveConfirm}
   133          onCancel={onArchiveCancel}/>
   134        <RuleEditDialog
   135          open={editDialogOpen}
   136          setOpen={setEditDialogOpen}
   137          rule={rule}/>
   138      </Paper>
   139    );
   140  };
   141  
   142  export default RuleInfo;