iterative/vscode-dvc

View on GitHub
webview/src/plots/components/comparisonTable/ComparisonTable.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
A
97%
import { ComparisonPlots, Revision } from 'dvc/src/plots/webview/contract'
import { reorderObjectList } from 'dvc/src/util/array'
import React, { useState, useRef, useEffect, useCallback } from 'react'
import { useSelector } from 'react-redux'
import {
  ComparisonTableColumn,
  ComparisonTableHead
} from './ComparisonTableHead'
import { ComparisonTableRows } from './ComparisonTableRows'
import plotsStyles from '../styles.module.scss'
import { withScale, withVariant } from '../../../util/styles'
import { PlotsState } from '../../store'
import { EmptyState } from '../../../shared/components/emptyState/EmptyState'
import { reorderComparisonPlots } from '../../util/messages'
import { WaitForPlotsInfo } from '../emptyState/WaitForPlotsInfo'
import { TooManyPlots } from '../TooManyPlots'

export const ComparisonTable: React.FC = () => {
  const { revisions, plots, width, shouldShowTooManyPlotsMessage } =
    useSelector((state: PlotsState) => state.comparison)

  const pinnedColumn = useRef('')
  const [columns, setColumns] = useState<ComparisonTableColumn[]>([])
  const [comparisonPlots, setComparisonPlots] = useState<ComparisonPlots>([])

  const isPinned = (column: ComparisonTableColumn): boolean =>
    column.id === pinnedColumn.current

  const getPinnedColumnRevision = useCallback(
    () => revisions?.find(isPinned) || null,
    [revisions]
  )

  useEffect(
    () =>
      setColumns(() => {
        const acc: Revision[] = []

        for (const column of revisions || []) {
          if (isPinned(column)) {
            continue
          }
          acc.push(column)
        }

        return [getPinnedColumnRevision(), ...acc].filter(
          Boolean
        ) as ComparisonTableColumn[]
      }),
    [revisions, getPinnedColumnRevision]
  )

  useEffect(() => {
    setComparisonPlots(plots)
  }, [plots])

  if (!plots || plots.length === 0) {
    return (
      <EmptyState isFullScreen={false}>
        No Images to Compare
        <WaitForPlotsInfo />
      </EmptyState>
    )
  }

  const setColumnsOrder = (order: string[]) => {
    const newOrder = reorderObjectList<Revision>(order, columns, 'id')
    setColumns(newOrder)
    reorderComparisonPlots(newOrder)
  }

  const changePinnedColumn = (column: string) => {
    pinnedColumn.current = pinnedColumn.current === column ? '' : column

    setColumnsOrder(
      (
        [
          getPinnedColumnRevision(),
          ...columns.filter(column => !isPinned(column))
        ].filter(Boolean) as ComparisonTableColumn[]
      ).map(({ id }) => id)
    )
  }

  return (
    <>
      <table
        className={plotsStyles.comparisonTable}
        style={{ ...withScale(columns.length), ...withVariant(width) }}
      >
        <ComparisonTableHead
          columns={columns}
          pinnedColumn={pinnedColumn.current}
          setColumnsOrder={setColumnsOrder}
          setPinnedColumn={changePinnedColumn}
        />
        <ComparisonTableRows
          plots={comparisonPlots}
          columns={columns}
          pinnedColumn={pinnedColumn.current}
        />
      </table>
      {shouldShowTooManyPlotsMessage && <TooManyPlots />}
    </>
  )
}