go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/frontend/ui/src/views/bug/bug_page/bug_page.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 { useQuery } from 'react-query';
    16  import {
    17    useNavigate,
    18    useParams,
    19  } from 'react-router-dom';
    20  
    21  import Alert from '@mui/material/Alert';
    22  import AlertTitle from '@mui/material/AlertTitle';
    23  import Container from '@mui/material/Container';
    24  import Grid from '@mui/material/Grid';
    25  import LinearProgress from '@mui/material/LinearProgress';
    26  import Link from '@mui/material/Link';
    27  import Paper from '@mui/material/Paper';
    28  
    29  import MultiRulesFound from '@/components/bugs/multi_rules_found/multi_rules_found';
    30  import ErrorAlert from '@/components/error_alert/error_alert';
    31  import LoadErrorAlert from '@/components/load_error_alert/load_error_alert';
    32  import { LookupBugRequest } from '@/proto/go.chromium.org/luci/analysis/proto/v1/rules.pb';
    33  import { getRulesService } from '@/services/services';
    34  import { prpcRetrier } from '@/tools/prpc_retrier';
    35  import { parseRuleName } from '@/tools/rules';
    36  import {
    37    linkToRule,
    38    loginLink,
    39  } from '@/tools/urlHandling/links';
    40  
    41  const BugPage = () => {
    42    const { bugTracker, id } = useParams();
    43    const navigate = useNavigate();
    44  
    45    let bugSystem = '';
    46    let bugId: string | undefined = '';
    47  
    48    if (!bugTracker) {
    49      bugSystem = 'buganizer';
    50      bugId = id;
    51    } else {
    52      bugSystem = 'monorail';
    53      bugId = bugTracker + '/' + id;
    54    }
    55  
    56    const {
    57      isLoading,
    58      error,
    59      isSuccess,
    60      data,
    61    } = useQuery(['bug', bugSystem, bugId], async () => {
    62      const service = getRulesService();
    63      const request: LookupBugRequest = {
    64        system: bugSystem,
    65        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    66        id: bugId!,
    67      };
    68      return await service.lookupBug(request);
    69    }, {
    70      enabled: !!(bugSystem && bugId),
    71      retry: prpcRetrier,
    72    });
    73  
    74    if (!bugId) {
    75      return (
    76        <ErrorAlert
    77          errorTitle="Bug ID not specified"
    78          errorText="Bug ID not found in the URL, please check the URL and try again"
    79          showError
    80        />
    81      );
    82    }
    83  
    84    if (isSuccess &&
    85      data &&
    86      data.rules &&
    87      data.rules.length === 1) {
    88      const ruleKey = parseRuleName(data.rules[0]);
    89      const link = linkToRule(ruleKey.project, ruleKey.ruleId);
    90      // For automatic redirects, replace the history entry in the browser
    91      // so that if the user clicks 'back', they are not redirected forward
    92      // again.
    93      navigate(link, { replace: true });
    94    }
    95  
    96    return (
    97      <Container>
    98        <Paper elevation={3} sx={{
    99          pt: 1,
   100          pb: 4,
   101          px: 2,
   102          mt: 1,
   103          mx: 2,
   104        }}>
   105          {isLoading && (
   106            <LinearProgress />
   107          )}
   108          {
   109            error && (
   110              <LoadErrorAlert
   111                entityName="rule"
   112                error={error}
   113              />
   114            )
   115          }
   116          {
   117            isSuccess && data && (
   118              <Grid container>
   119                {
   120                  data.rules ? (
   121                    <MultiRulesFound
   122                      bugSystem={bugSystem}
   123                      bugId={bugId}
   124                      rules={data.rules}
   125                    />
   126                  ) : (
   127                    <Grid item xs={12}>
   128                      <Alert
   129                        severity="info"
   130                        sx={{ mb: 2 }}>
   131                        <AlertTitle>Could not find a rule for this bug (or you may not have permission to see it)</AlertTitle>
   132                        {
   133                            window.isAnonymous ? (
   134                              // Because of the design of the RPC, it cannot tell us if there are
   135                              // rules we do not have access to. If the user is not logged in,
   136                              // assume a rule exists and prompt the user to log in.
   137                              <>
   138                                Please <Link data-testid="error_login_link" href={loginLink(location.pathname + location.search + location.hash)}>log in</Link> to view this information.
   139                              </>
   140                            ) : (
   141                              <>
   142                                <strong>If you came here from a bug, please check if the bug has been duplicated into another bug and use that bug instead.</strong>&nbsp;
   143                                It is also possible a rule exists, but you do not have permission to view it.
   144                              </>
   145                            )
   146                        }
   147                      </Alert>
   148                    </Grid>
   149                  )
   150                }
   151              </Grid>
   152            )
   153          }
   154        </Paper>
   155      </Container>
   156    );
   157  };
   158  
   159  export default BugPage;