go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/frontend/ui/src/components/cl_list/cl_list.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 {
    16    useState,
    17    Fragment,
    18    MouseEvent,
    19  } from 'react';
    20  
    21  import { styled } from '@mui/material/styles';
    22  import ClickAwayListener from '@mui/material/ClickAwayListener';
    23  import Link from '@mui/material/Link';
    24  import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
    25  
    26  import { Changelist } from '@/proto/go.chromium.org/luci/analysis/proto/v1/sources.pb';
    27  import {
    28    clLink,
    29  } from '@/tools/urlHandling/links';
    30  
    31  interface Props {
    32    changelists: readonly Changelist[];
    33  }
    34  
    35  const LightTooltip = styled(({ className, ...props }: TooltipProps) => (
    36    <Tooltip {...props} classes={{ popper: className }} />
    37  ))(({ theme }) => ({
    38    [`& .${tooltipClasses.arrow}`]: {
    39      color: theme.palette.common.white,
    40    },
    41    [`& .${tooltipClasses.tooltip}`]: {
    42      backgroundColor: theme.palette.common.white,
    43      color: 'inherit',
    44      boxShadow: theme.shadows[1],
    45      fontSize: theme.typography.fontSize,
    46      fontWeight: theme.typography.fontWeightRegular,
    47    },
    48  }));
    49  
    50  const CLList = ({
    51    changelists,
    52  }: Props) => {
    53    const [tooltipOpen, setTooltipOpen] = useState(false);
    54  
    55    const handleTooltipClose = () => {
    56      setTooltipOpen(false);
    57    };
    58  
    59    const handleTooltipOpen = (e: MouseEvent<HTMLAnchorElement>) => {
    60      setTooltipOpen(!tooltipOpen);
    61      e.preventDefault();
    62    };
    63  
    64  
    65    if (changelists.length == 0) {
    66      return <></>;
    67    }
    68    return (
    69      <ClickAwayListener onClickAway={handleTooltipClose}>
    70        <div style={{ display: 'inline-block' }}>
    71          <Link
    72            href={clLink(changelists[0])}
    73            target="_blank"
    74          >
    75            {changelists[0].change}&nbsp;#{changelists[0].patchset}
    76          </Link>
    77          {changelists.length > 1 ? (
    78            <>
    79              {', '}
    80              <LightTooltip
    81                PopperProps={{
    82                  disablePortal: true,
    83                }}
    84                open={tooltipOpen}
    85                onClose={handleTooltipClose}
    86                disableFocusListener
    87                disableHoverListener
    88                disableTouchListener
    89                arrow
    90                title={
    91                  <>
    92                    {
    93                      changelists.slice(1).map((cl, i) => {
    94                        return (
    95                          <Fragment key={i.toString()}>
    96                            {i > 0 ? ', ' : null}
    97                            <Link
    98                              href={clLink(cl)}
    99                              target="_blank"
   100                            >
   101                              {cl.change}&nbsp;#{cl.patchset}
   102                            </Link>
   103                          </Fragment>
   104                        );
   105                      })
   106                    }
   107                  </>
   108                }>
   109                <Link href="#" onClick={handleTooltipOpen}>...</Link>
   110              </LightTooltip>
   111            </>) : null
   112          }
   113        </div>
   114      </ClickAwayListener>
   115    );
   116  };
   117  
   118  export default CLList;