github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/components/Settings/APIKeys/index.tsx (about)

     1  import React, { useEffect } from 'react';
     2  import { useHistory } from 'react-router-dom';
     3  import { formatDistance, formatRelative } from 'date-fns/fp';
     4  import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes';
     5  import { faPlus } from '@fortawesome/free-solid-svg-icons/faPlus';
     6  
     7  import Button from '@webapp/ui/Button';
     8  import Icon from '@webapp/ui/Icon';
     9  import TableUI, { BodyRow } from '@webapp/ui/Table';
    10  import type { APIKey, APIKeys } from '@webapp/models/apikeys';
    11  import { useAppDispatch, useAppSelector } from '@webapp/redux/hooks';
    12  import {
    13    reloadApiKeys,
    14    selectAPIKeys,
    15    deleteAPIKey,
    16  } from '@webapp/redux/reducers/settings';
    17  import confirmDelete from '@webapp/components/Modals/ConfirmDelete';
    18  import styles from '../SettingsTable.module.scss';
    19  
    20  const getBodyRows = (
    21    keys: APIKeys,
    22    onDelete: (k: APIKey) => void
    23  ): BodyRow[] => {
    24    const now = new Date();
    25  
    26    const handleDeleteClick = (key: APIKey) => {
    27      confirmDelete({
    28        objectType: 'key',
    29        objectName: key.name,
    30        onConfirm: () => onDelete(key),
    31      });
    32    };
    33  
    34    return keys.reduce((acc, k) => {
    35      acc.push({
    36        cells: [
    37          { value: k.id },
    38          { value: k.name },
    39          { value: k.role },
    40          { value: formatRelative(k.createdAt, now) },
    41          {
    42            value: k.expiresAt
    43              ? `in ${formatDistance(k.expiresAt, now)}`
    44              : 'never',
    45            title: k?.expiresAt?.toString(),
    46          },
    47          {
    48            value: (
    49              <Button
    50                type="submit"
    51                kind="danger"
    52                aria-label="Delete key"
    53                onClick={() => handleDeleteClick(k)}
    54              >
    55                <Icon icon={faTimes} />
    56              </Button>
    57            ),
    58            align: 'center',
    59          },
    60        ],
    61      });
    62      return acc;
    63    }, [] as BodyRow[]);
    64  };
    65  
    66  const headRow = [
    67    { name: '', label: 'Id', sortable: 0 },
    68    { name: '', label: 'Name', sortable: 0 },
    69    { name: '', label: 'Role', sortable: 0 },
    70    { name: '', label: 'Creation date', sortable: 0 },
    71    { name: '', label: 'Expiration date', sortable: 0 },
    72  ];
    73  
    74  const ApiKeys = () => {
    75    const dispatch = useAppDispatch();
    76    const apiKeys = useAppSelector(selectAPIKeys);
    77    const history = useHistory();
    78  
    79    useEffect(() => {
    80      dispatch(reloadApiKeys());
    81    }, []);
    82  
    83    const onDelete = (key: APIKey) => {
    84      dispatch(deleteAPIKey(key))
    85        .unwrap()
    86        .then(() => {
    87          dispatch(reloadApiKeys());
    88        });
    89    };
    90  
    91    const tableBodyProps = apiKeys
    92      ? { type: 'filled' as const, bodyRows: getBodyRows(apiKeys, onDelete) }
    93      : { type: 'not-filled' as const, value: '' };
    94  
    95    return (
    96      <>
    97        <h2>API keys</h2>
    98        <div>
    99          <Button
   100            type="submit"
   101            kind="secondary"
   102            icon={faPlus}
   103            onClick={() => history.push('/settings/api-keys/add')}
   104          >
   105            Add Key
   106          </Button>
   107        </div>
   108        <TableUI
   109          table={{ headRow, ...tableBodyProps }}
   110          className={styles.settingsTable}
   111        />
   112      </>
   113    );
   114  };
   115  
   116  export default ApiKeys;