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

     1  import React, { useMemo } from 'react';
     2  import { format, parseISO } from 'date-fns';
     3  
     4  import { Maybe } from '@webapp/util/fp';
     5  import { AllProfiles } from '@webapp/models/adhoc';
     6  import TableUI, { useTableSort, BodyRow } from '@webapp/ui/Table';
     7  import CheckIcon from './CheckIcon';
     8  import styles from './FileList.module.scss';
     9  
    10  const dateModifiedColName = 'updatedAt';
    11  const fileNameColName = 'name';
    12  const headRow = [
    13    { name: fileNameColName, label: 'Filename', sortable: 1 },
    14    {
    15      name: dateModifiedColName,
    16      label: 'Date Modified',
    17      sortable: 1,
    18      default: true,
    19    },
    20  ];
    21  
    22  const getBodyRows = (
    23    sortedProfilesIds: AllProfiles[0][],
    24    onProfileSelected: (id: string) => void,
    25    selectedProfileId: Maybe<string>
    26  ): BodyRow[] => {
    27    return sortedProfilesIds.reduce((acc, profile) => {
    28      const isRowSelected = selectedProfileId.mapOr(
    29        false,
    30        (profId) => profId === profile.id
    31      );
    32  
    33      const date = parseISO(profile.updatedAt);
    34      const timeString = `${format(date, 'MMM d, yyyy')} at ${format(
    35        date,
    36        'h:mm a'
    37      )}`;
    38  
    39      acc.push({
    40        cells: [
    41          {
    42            value: (
    43              <div className={styles.profileName}>
    44                <span title={profile.name}>{profile.name}</span>
    45                {isRowSelected && <CheckIcon className={styles.checkIcon} />}
    46              </div>
    47            ),
    48          },
    49          { value: timeString },
    50        ],
    51        onClick: () => {
    52          // Optimize to not reload the same one
    53          if (
    54            selectedProfileId.isJust &&
    55            selectedProfileId.value === profile.id
    56          ) {
    57            return;
    58          }
    59          onProfileSelected(profile.id);
    60        },
    61        isRowSelected,
    62      });
    63  
    64      return acc;
    65    }, [] as BodyRow[]);
    66  };
    67  
    68  interface FileListProps {
    69    className?: string;
    70    profilesList: AllProfiles;
    71    onProfileSelected: (id: string) => void;
    72    selectedProfileId: Maybe<string>;
    73  }
    74  
    75  function FileList(props: FileListProps) {
    76    const {
    77      profilesList: profiles,
    78      onProfileSelected,
    79      className,
    80      selectedProfileId,
    81    } = props;
    82  
    83    const { sortBy, sortByDirection, ...rest } = useTableSort(headRow);
    84    const sortedProfilesIds = useMemo(() => {
    85      const m = sortByDirection === 'asc' ? 1 : -1;
    86  
    87      let sorted: AllProfiles[number][] = [];
    88  
    89      if (profiles) {
    90        const filesInfo = Object.values(profiles);
    91  
    92        switch (sortBy) {
    93          case fileNameColName:
    94            sorted = filesInfo.sort(
    95              (a, b) => m * a[sortBy].localeCompare(b[sortBy])
    96            );
    97            break;
    98          case dateModifiedColName:
    99            sorted = filesInfo.sort(
   100              (a, b) =>
   101                m *
   102                (new Date(a[sortBy]).getTime() - new Date(b[sortBy]).getTime())
   103            );
   104            break;
   105          default:
   106            sorted = filesInfo;
   107        }
   108      }
   109  
   110      return sorted;
   111    }, [profiles, sortBy, sortByDirection]);
   112  
   113    const tableBodyProps = profiles
   114      ? {
   115          type: 'filled' as const,
   116          bodyRows: getBodyRows(
   117            sortedProfilesIds,
   118            onProfileSelected,
   119            selectedProfileId
   120          ),
   121        }
   122      : { type: 'not-filled' as const, value: '' };
   123  
   124    return (
   125      <>
   126        <div className={`${styles.tableContainer} ${className}`}>
   127          <TableUI
   128            /* eslint-disable-next-line react/jsx-props-no-spreading */
   129            {...rest}
   130            sortBy={sortBy}
   131            sortByDirection={sortByDirection}
   132            table={{ headRow, ...tableBodyProps }}
   133          />
   134        </div>
   135      </>
   136    );
   137  }
   138  
   139  export default FileList;