diff --git a/webview/src/experiments/components/table/Table.tsx b/webview/src/experiments/components/table/Table.tsx index 4dca3cec4b..f788d317e2 100644 --- a/webview/src/experiments/components/table/Table.tsx +++ b/webview/src/experiments/components/table/Table.tsx @@ -21,6 +21,7 @@ export const Table: React.FC = ({ instance }) => { const { clearSelectedRows, batchSelection, lastSelectedRow } = React.useContext(RowSelectionContext) const [expColumnNeedsShadow, setExpColumnNeedsShadow] = useState(false) + const [tableHeadHeight, setTableHeadHeight] = useState(55) const tableRef = useRef(null) @@ -81,9 +82,12 @@ export const Table: React.FC = ({ instance }) => { instance={instance} root={tableRef.current} setExpColumnNeedsShadow={setExpColumnNeedsShadow} + setTableHeadHeight={setTableHeadHeight} /> {rows.map(row => ( = ({ - row, - instance, - contextMenuDisabled, - projectHasCheckpoints, - hasRunningExperiment, - batchRowSelection -}) => { - instance.prepareRow(row) +const WorkspaceRowGroupWrapper: React.FC< + { + children: React.ReactNode + root: HTMLElement | null + tableHeaderHeight: number + } & InstanceProp +> = ({ children, instance, root, tableHeaderHeight }) => { + const [ref, needsShadow] = useInView({ + root, + rootMargin: `-${tableHeaderHeight + 15}px 0px 0px 0px`, + threshold: 1 + }) + return (
+ {children} +
+ ) +} +export const TableBody: React.FC< + RowProp & + InstanceProp & + BatchSelectionProp & { root: HTMLElement | null; tableHeaderHeight: number } +> = ({ + row, + instance, + contextMenuDisabled, + projectHasCheckpoints, + hasRunningExperiment, + batchRowSelection, + root, + tableHeaderHeight +}) => { + instance.prepareRow(row) + + const content = ( + <> ))} + + ) + return row.values.id === 'workspace' ? ( + + {content} + + ) : ( +
+ {content}
) } diff --git a/webview/src/experiments/components/table/TableHead.tsx b/webview/src/experiments/components/table/TableHead.tsx index 0926fb3c1d..9033d47e73 100644 --- a/webview/src/experiments/components/table/TableHead.tsx +++ b/webview/src/experiments/components/table/TableHead.tsx @@ -1,10 +1,8 @@ import { Experiment } from 'dvc/src/experiments/webview/contract' -import cx from 'classnames' -import React, { DragEvent, useRef } from 'react' +import React, { DragEvent, useRef, useEffect } from 'react' import { useSelector } from 'react-redux' import { HeaderGroup, TableInstance } from 'react-table' import { MessageFromWebviewType } from 'dvc/src/webview/contract' -import { useInView } from 'react-intersection-observer' import styles from './styles.module.scss' import { MergedHeaderGroups } from './MergeHeaderGroups' import { Indicators } from './Indicators' @@ -18,6 +16,7 @@ interface TableHeadProps { instance: TableInstance root: HTMLElement | null setExpColumnNeedsShadow: (needsShadow: boolean) => void + setTableHeadHeight: (height: number) => void } export const TableHead = ({ @@ -29,7 +28,8 @@ export const TableHead = ({ rows }, root, - setExpColumnNeedsShadow + setExpColumnNeedsShadow, + setTableHeadHeight }: TableHeadProps) => { const columns = useSelector( (state: ExperimentsState) => state.tableData.columns @@ -42,6 +42,14 @@ export const TableHead = ({ const fullColumnOrder = useRef() const draggingIds = useRef() + const wrapper = useRef(null) + + useEffect(() => { + const wrapperHeight = wrapper.current?.getBoundingClientRect().height + if (wrapperHeight) { + setTableHeadHeight(wrapperHeight) + } + }, [setTableHeadHeight]) const onDragStart: DragFunction = ({ currentTarget }) => { const displacerHeader = allHeaders.find( @@ -86,21 +94,13 @@ export const TableHead = ({ type: MessageFromWebviewType.REORDER_COLUMNS }) } - const [ref, needsShadow] = useInView({ - root, - rootMargin: '-15px 0px 0px 0px', - threshold: 1 - }) const selectedForPlotsCount = getSelectedForPlotsCount(rows) const firstExpColumnCellId = headerGroups[0].headers[0].id return ( -
+
{headerGroups.map(headerGroup => ( // eslint-disable-next-line react/jsx-key diff --git a/webview/src/experiments/components/table/styles.module.scss b/webview/src/experiments/components/table/styles.module.scss index b393048ffe..c97c1c6fec 100644 --- a/webview/src/experiments/components/table/styles.module.scss +++ b/webview/src/experiments/components/table/styles.module.scss @@ -17,7 +17,8 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; left: 0; display: inline-block; position: absolute; - border: 2px solid $fg-color; + border: 2px solid $watermark-color; + opacity: 0.5; border-top: unset; border-left: unset; transition: transform 0.2s, right 0.2s, bottom 0.2s; @@ -128,10 +129,6 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; background-color: $bg-color; } - .unselectedExperiment.oddRow & { - background-color: $row-bg-alt-color; - } - .workspaceWithChanges.unselectedExperiment & { border: 1px solid $changed-color; } @@ -150,18 +147,11 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; animation: spin 1s cubic-bezier(0.53, 0.21, 0.29, 0.67) infinite; background-color: $bg-color; } - .runningExperiment.oddRow & { - background-color: $row-bg-alt-color; - } + .workspaceWithChanges.runningExperiment & { border-right-color: $changed-color; border-top-color: $changed-color; } - - .runningExperiment.oddRow > .experimentCell & { - border-left: 1.5px solid $row-bg-alt-color; - border-bottom: 1.5px solid $row-bg-alt-color; - } } } @@ -181,7 +171,6 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; transform: rotate(45deg); right: 1px; bottom: 2px; - border-color: $fg-color; } .contractedRowArrow { @@ -264,6 +253,16 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; .tr { position: relative; + &:hover:not(.rowSelected) { + .td { + background-color: $row-hover-background-color; + + &:hover { + background-color: $cell-hover-background-color; + } + } + } + &:not(.rowSelected) { & > *:first-child { position: sticky; @@ -280,10 +279,6 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; transition: box-shadow 0.25s; } } - - &.oddRow > *:first-child { - background-color: $row-bg-alt-color; - } } &.rowSelected { @@ -293,11 +288,13 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; .table.withExpColumnShadow { .tr:not(.rowSelected) > *:first-child:after { - box-shadow: 3px 0px 3px var(--vscode-widget-shadow); + box-shadow: 3px 0px 3px $shadow; } } .bodyRow { + border-bottom: $row-border; + &:not(.rowSelected) { & > *:first-child { background-color: $row-bg-color; @@ -327,7 +324,7 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; } &:not(.rowSelected) > *:first-child:after { - right: -2px; + right: -1px; } &:last-child, @@ -370,44 +367,15 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; } } - .rowGroup { - margin: 0.5rem 0; - } - .normalRowGroup { - border-top: $row-border; - border-bottom: $row-border; - .oddRow { - background-color: $row-bg-alt-color; - } - .td { - &:first-child { - border-left: $row-border; - } - - &:last-child { - border-right: $row-border; - } - } - } .workspaceRowGroup { border: none; + position: sticky; + top: var(--table-head-height); + z-index: 4; + background-color: $row-bg-color; - .td { - &:first-child { - padding-left: $workspace-row-edge-margin; - .innerCell { - padding-left: $cell-padding; - border-left: $row-border; - } - } - - &:last-child { - padding-right: $workspace-row-edge-margin; - .innerCell { - padding-right: $cell-padding; - border-right: $row-border; - } - } + &.withShadow { + box-shadow: 0 5px 8px -2px $shadow; } .innerCell { @@ -421,8 +389,6 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; height: 100%; width: 100%; background-color: none; - border-top: $row-border; - border-bottom: $row-border; } } @@ -439,12 +405,14 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; } .th { height: auto; + background-color: $header-bg-color; } .td { height: auto; font-size: 0.8rem; line-height: 2rem; align-items: center; + &:first-child { .innerCell { padding-left: $edge-padding; @@ -461,6 +429,7 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; display: flex; flex-flow: row nowrap; text-align: left; + .innerCell { justify-content: flex-start; @@ -511,14 +480,14 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; .placeholderHeaderCell { background-color: $header-bg-color; - border-right: 2px solid $header-border-color; + border-right: 1px solid $header-border-color; } .headerCell { @extend .placeholderHeaderCell; color: $header-fg-color; text-align: center; - border-bottom: 2px solid $header-border-color; + border-bottom: 1px solid $header-border-color; padding: 0.31rem $cell-padding; &.leafHeader { @@ -570,7 +539,7 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; } .columnResizer { - right: -5px; + right: -4px; width: 10px; height: 500%; position: absolute; @@ -680,10 +649,6 @@ $workspace-row-edge-margin: $edge-padding - $cell-padding; position: sticky; top: 0; z-index: 4; - - &.headWithShadow { - box-shadow: 0 5px 8px -2px var(--vscode-widget-shadow); - } } .tableIndicators { diff --git a/webview/src/plots/components/ribbon/styles.module.scss b/webview/src/plots/components/ribbon/styles.module.scss index 573289e3fa..1bd59ec8b2 100644 --- a/webview/src/plots/components/ribbon/styles.module.scss +++ b/webview/src/plots/components/ribbon/styles.module.scss @@ -10,7 +10,7 @@ .block { border-left-style: solid; border-left-width: 3px; - background-color: $header-bg-color; + background-color: $plot-block-bg-color; color: $fg-color; display: inline-flex; justify-content: space-between; diff --git a/webview/src/shared/variables.scss b/webview/src/shared/variables.scss index 8425558a32..9781fdb36e 100644 --- a/webview/src/shared/variables.scss +++ b/webview/src/shared/variables.scss @@ -3,7 +3,7 @@ $bg-color: var(--vscode-editor-background); $bullet-size: 9px; $watermark-color: var(--vscode-descriptionForeground); -$border-color: var(--vscode-dropdown-border); +$border-color: var(--checkbox-border); $metrics-color: var(--vscode-dvc-metrics); $params-color: var(--vscode-dvc-params); $deps-color: var(--vscode-dvc-deps); @@ -15,12 +15,19 @@ $header-fg-color: $fg-color; $row-bg-alt-color: var(--vscode-sideBar-background); $row-bg-selected-color: var(--vscode-list-activeSelectionBackground); $row-border-selected-color: var(--vscode-list-focusOutline); -$header-bg-color: var(--vscode-dropdown-background); -$header-border-color: var(--vscode-tree-tableColumnsBorder); +$header-bg-color: $bg-color; +$header-border-color: $border-color; $meta-cell-color: var(--vscode-descriptionForeground); $hover-background-color: var(--vscode-list-hoverBackground); +$row-hover-background-color: var(--vscode-list-hoverBackground); +$cell-hover-background-color: var(--vscode-dropdown-background); + $accent-color: var(--button-primary-background); $indicator-badge-foreground: var(--vscode-activityBarBadge-foreground); $indicator-badge-background: var(--vscode-activityBarBadge-background); + +$shadow: var(--vscode-widget-shadow); + +$plot-block-bg-color: var(--vscode-dropdown-background);