未验证 提交 89fadd59 编写于 作者: P Peter Pan 提交者: GitHub

fix: confusion of column order in hyper-parameters page (#966)

上级 03f31128
...@@ -109,28 +109,35 @@ const StyledScaleMethodSelect = styled(ScaleMethodSelect)` ...@@ -109,28 +109,35 @@ const StyledScaleMethodSelect = styled(ScaleMethodSelect)`
position: relative; position: relative;
`; `;
const sortIndicators = (indicators: Indicator[], order?: string[]) =>
order ? indicators.sort(({name: nameA}, {name: nameB}) => order.indexOf(nameA) - order.indexOf(nameB)) : indicators;
type ParallelCoordinatesProps = ViewData & { type ParallelCoordinatesProps = ViewData & {
colors: string[]; colors: string[];
order?: string[];
onHover?: (index: number | null) => unknown; onHover?: (index: number | null) => unknown;
onSelect?: (index: number | null) => unknown; onSelect?: (index: number | null) => unknown;
onChangeOrder?: (order: string[]) => unknown;
}; };
const ParallelCoordinates: FunctionComponent<ParallelCoordinatesProps & WithStyled> = ({ const ParallelCoordinates: FunctionComponent<ParallelCoordinatesProps & WithStyled> = ({
indicators, indicators,
data, data,
colors, colors,
order,
onHover, onHover,
onSelect, onSelect,
onChangeOrder,
className className
}) => { }) => {
const container = useRef<HTMLDivElement>(null); const container = useRef<HTMLDivElement>(null);
const graph = useRef<Graph>(); const graph = useRef<Graph>();
const [columnWidth, setColumnWidth] = useState(0); const [columnWidth, setColumnWidth] = useState(0);
const [indicatorsOrder, setIndicatorsOrder] = useState(indicators.map(({name}) => name)); const [indicatorsOrder, setIndicatorsOrder] = useState(sortIndicators(indicators, order).map(({name}) => name));
useEffect(() => { useEffect(() => {
setIndicatorsOrder(indicators.map(({name}) => name)); setIndicatorsOrder(sortIndicators(indicators, order).map(({name}) => name));
}, [indicators]); }, [indicators, order]);
const orderedIndicators = useMemo( const orderedIndicators = useMemo(
() => () =>
...@@ -176,7 +183,18 @@ const ParallelCoordinates: FunctionComponent<ParallelCoordinatesProps & WithStyl ...@@ -176,7 +183,18 @@ const ParallelCoordinates: FunctionComponent<ParallelCoordinatesProps & WithStyl
setIndicatorsOrder(order); setIndicatorsOrder(order);
}); });
return () => graph.current?.dispose(); return () => graph.current?.dispose();
}, []); }, [onChangeOrder]);
const changeOrder = useCallback((order: string[]) => onChangeOrder?.(order), [onChangeOrder]);
useEffect(() => {
const g = graph.current;
if (g) {
g.on('dragged', changeOrder);
return () => {
g.off('dragged', changeOrder);
};
}
}, [changeOrder]);
useEffect(() => { useEffect(() => {
const c = container.current; const c = container.current;
...@@ -215,9 +233,10 @@ const ParallelCoordinates: FunctionComponent<ParallelCoordinatesProps & WithStyl ...@@ -215,9 +233,10 @@ const ParallelCoordinates: FunctionComponent<ParallelCoordinatesProps & WithStyl
}, [colors]); }, [colors]);
useEffect(() => { useEffect(() => {
graph.current?.render(indicators, data); const orderedIndicators = sortIndicators(indicators, order);
graph.current?.render(orderedIndicators, data);
setColumnWidth(graph.current?.columnWidth ?? 0); setColumnWidth(graph.current?.columnWidth ?? 0);
}, [indicators, data]); }, [indicators, data, order]);
return ( return (
<Container className={className}> <Container className={className}>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
import React, {FunctionComponent, useState} from 'react'; import React, {FunctionComponent, useState} from 'react';
import {useGraph, useIndicatorOrder} from '~/resource/hyper-parameter';
import ColorMap from '~/components/HyperParameterPage/ColorMap'; import ColorMap from '~/components/HyperParameterPage/ColorMap';
import ParallelCoordinatesGraph from './ParallelCoordinatesGraph'; import ParallelCoordinatesGraph from './ParallelCoordinatesGraph';
...@@ -23,7 +24,6 @@ import View from '~/components/HyperParameterPage/View'; ...@@ -23,7 +24,6 @@ import View from '~/components/HyperParameterPage/View';
import type {ViewData} from '~/resource/hyper-parameter'; import type {ViewData} from '~/resource/hyper-parameter';
import {rem} from '~/utils/style'; import {rem} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {useGraph} from '~/resource/hyper-parameter';
const ParallelCoordinatesContainer = styled.div` const ParallelCoordinatesContainer = styled.div`
width: 100%; width: 100%;
...@@ -41,6 +41,8 @@ const ParallelCoordinatesContainer = styled.div` ...@@ -41,6 +41,8 @@ const ParallelCoordinatesContainer = styled.div`
} }
`; `;
const COLUMN_ORDER_STORAGE_KEY = 'hyper-parameter-parallel-coordinates-view-column-order';
type ParallelCoordinatesViewProps = ViewData; type ParallelCoordinatesViewProps = ViewData;
const ParallelCoordinatesView: FunctionComponent<ParallelCoordinatesViewProps> = ({indicators, list, data}) => { const ParallelCoordinatesView: FunctionComponent<ParallelCoordinatesViewProps> = ({indicators, list, data}) => {
...@@ -48,6 +50,8 @@ const ParallelCoordinatesView: FunctionComponent<ParallelCoordinatesViewProps> = ...@@ -48,6 +50,8 @@ const ParallelCoordinatesView: FunctionComponent<ParallelCoordinatesViewProps> =
const [colors, setColors] = useState<string[]>([]); const [colors, setColors] = useState<string[]>([]);
const [order, setOrder] = useIndicatorOrder(COLUMN_ORDER_STORAGE_KEY, indicators);
return ( return (
<> <>
<View> <View>
...@@ -58,8 +62,10 @@ const ParallelCoordinatesView: FunctionComponent<ParallelCoordinatesViewProps> = ...@@ -58,8 +62,10 @@ const ParallelCoordinatesView: FunctionComponent<ParallelCoordinatesViewProps> =
list={list} list={list}
data={data} data={data}
colors={colors} colors={colors}
order={order}
onHover={onHover} onHover={onHover}
onSelect={onSelect} onSelect={onSelect}
onChangeOrder={setOrder}
/> />
<ColorMap className="color-map" indicators={indicators} data={data} onChange={setColors} /> <ColorMap className="color-map" indicators={indicators} data={data} onChange={setColors} />
</ParallelCoordinatesContainer> </ParallelCoordinatesContainer>
......
...@@ -95,7 +95,7 @@ const TableViewTable: FunctionComponent<TableViewTableProps> = ({ ...@@ -95,7 +95,7 @@ const TableViewTable: FunctionComponent<TableViewTableProps> = ({
setColumnOrder, setColumnOrder,
state, state,
totalColumnsWidth, totalColumnsWidth,
columns: tableColumns, visibleColumns,
allColumns allColumns
} = useTable( } = useTable(
{ {
...@@ -131,10 +131,7 @@ const TableViewTable: FunctionComponent<TableViewTableProps> = ({ ...@@ -131,10 +131,7 @@ const TableViewTable: FunctionComponent<TableViewTableProps> = ({
const startDrag = useCallback((id: string) => setDraggingColumnId(id), []); const startDrag = useCallback((id: string) => setDraggingColumnId(id), []);
const stopDrag = useCallback(() => setDraggingColumnId(null), []); const stopDrag = useCallback(() => setDraggingColumnId(null), []);
const changeDropSide = useCallback((id: string, side: 'before' | 'after') => setDroppableColumn([id, side]), []); const changeDropSide = useCallback((id: string, side: 'before' | 'after') => setDroppableColumn([id, side]), []);
const orderedColumnIds = useMemo( const orderedColumnIds = useMemo(() => visibleColumns.map(c => c.id), [visibleColumns]);
() => (state.columnOrder.length ? state.columnOrder : tableColumns.map(c => c.id)),
[state.columnOrder, tableColumns]
);
useEffect(() => { useEffect(() => {
onOrderChange?.(orderedColumnIds.filter(id => id !== 'name')); onOrderChange?.(orderedColumnIds.filter(id => id !== 'name'));
}, [onOrderChange, orderedColumnIds]); }, [onOrderChange, orderedColumnIds]);
......
...@@ -14,19 +14,18 @@ ...@@ -14,19 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
import {DEFAULT_ORDER_INDICATOR, OrderDirection} from '~/resource/hyper-parameter'; import {DEFAULT_ORDER_INDICATOR, OrderDirection, useIndicatorOrder} from '~/resource/hyper-parameter';
import React, {FunctionComponent, useCallback, useMemo, useState} from 'react'; import React, {FunctionComponent, useMemo, useState} from 'react';
import Select from '~/components/Select'; import Select from '~/components/Select';
import Table from './Table'; import Table from './Table';
import View from '~/components/HyperParameterPage/View'; import View from '~/components/HyperParameterPage/View';
import type {ViewData} from '~/resource/hyper-parameter'; import type {ViewData} from '~/resource/hyper-parameter';
import {rem} from '~/utils/style'; import {rem} from '~/utils/style';
import {safeSplit} from '~/utils';
import styled from 'styled-components'; import styled from 'styled-components';
import {useTranslation} from 'react-i18next'; import {useTranslation} from 'react-i18next';
const TABLE_ORDER_STORAGE_KEY = 'hyper-parameter-table-view-table-order'; const COLUMN_ORDER_STORAGE_KEY = 'hyper-parameter-table-view-column-order';
const Wrapper = styled(View)` const Wrapper = styled(View)`
display: flex; display: flex;
...@@ -67,14 +66,14 @@ const TableView: FunctionComponent<TableViewProps> = ({indicators, list, data}) ...@@ -67,14 +66,14 @@ const TableView: FunctionComponent<TableViewProps> = ({indicators, list, data})
const indicatorNameList = useMemo(() => indicators.map(({name}) => name), [indicators]); const indicatorNameList = useMemo(() => indicators.map(({name}) => name), [indicators]);
const indicatorOrderList = useMemo( const columnOrderList = useMemo(
() => [ () => [
{value: DEFAULT_ORDER_INDICATOR, label: t('hyper-parameter.order-default')}, {value: DEFAULT_ORDER_INDICATOR, label: t('hyper-parameter.order-default')},
...indicatorNameList.map(value => ({value, label: value})) ...indicatorNameList.map(value => ({value, label: value}))
], ],
[indicatorNameList, t] [indicatorNameList, t]
); );
const [indicatorOrder, setIndicatorOrder] = useState<string | symbol>(DEFAULT_ORDER_INDICATOR); const [columnOrder, setColumnOrder] = useState<string | symbol>(DEFAULT_ORDER_INDICATOR);
const orderDirectionList = useMemo( const orderDirectionList = useMemo(
() => () =>
...@@ -88,35 +87,20 @@ const TableView: FunctionComponent<TableViewProps> = ({indicators, list, data}) ...@@ -88,35 +87,20 @@ const TableView: FunctionComponent<TableViewProps> = ({indicators, list, data})
const sortBy = useMemo( const sortBy = useMemo(
() => () =>
indicatorOrder === DEFAULT_ORDER_INDICATOR columnOrder === DEFAULT_ORDER_INDICATOR
? [] ? []
: [{id: indicatorOrder as string, desc: orderDirection === OrderDirection.DESCENDING}], : [{id: columnOrder as string, desc: orderDirection === OrderDirection.DESCENDING}],
[orderDirection, indicatorOrder] [orderDirection, columnOrder]
); );
const [columnOrder, setColumnOrder] = useState<string[]>( const [indicatorOrder, setIndicatorOrder] = useIndicatorOrder(COLUMN_ORDER_STORAGE_KEY, indicators);
safeSplit(window.sessionStorage.getItem(TABLE_ORDER_STORAGE_KEY) ?? '', ',')
);
const changeOrder = useCallback(
(order: string[]) => {
const filterOrder = order.filter(o => indicatorNameList.includes(o));
setColumnOrder(filterOrder);
window.sessionStorage.setItem(TABLE_ORDER_STORAGE_KEY, filterOrder.join(','));
},
[indicatorNameList]
);
return ( return (
<Wrapper> <Wrapper>
<OrderSection> <OrderSection>
<span>{t('hyper-parameter:order-by')}</span> <span>{t('hyper-parameter:order-by')}</span>
<Select <Select className="order-select" list={columnOrderList} value={columnOrder} onChange={setColumnOrder} />
className="order-select" {columnOrder !== DEFAULT_ORDER_INDICATOR ? (
list={indicatorOrderList}
value={indicatorOrder}
onChange={setIndicatorOrder}
/>
{indicatorOrder !== DEFAULT_ORDER_INDICATOR ? (
<> <>
<span>{t('hyper-parameter:order-direction')}</span> <span>{t('hyper-parameter:order-direction')}</span>
<Select <Select
...@@ -135,8 +119,8 @@ const TableView: FunctionComponent<TableViewProps> = ({indicators, list, data}) ...@@ -135,8 +119,8 @@ const TableView: FunctionComponent<TableViewProps> = ({indicators, list, data})
data={data} data={data}
sortBy={sortBy} sortBy={sortBy}
expand expand
columnOrder={columnOrder} columnOrder={indicatorOrder}
onOrderChange={changeOrder} onOrderChange={setIndicatorOrder}
/> />
</TableSection> </TableSection>
</Wrapper> </Wrapper>
......
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {useCallback, useMemo, useState} from 'react';
import type {Indicator} from '../types';
import {safeSplit} from '~/utils';
export default function useIndicatorOrder(key: string, indicators: Indicator[]) {
const indicatorNameList = useMemo(() => indicators.map(i => i.name), [indicators]);
const [order, setOrder] = useState<string[]>(safeSplit(window.sessionStorage.getItem(key) ?? '', ','));
const changeOrder = useCallback(
(order: string[]) => {
const filterOrder = order.filter(o => indicatorNameList.includes(o));
setOrder(filterOrder);
window.sessionStorage.setItem(key, filterOrder.join(','));
},
[indicatorNameList, key]
);
return [order, changeOrder] as const;
}
...@@ -37,6 +37,7 @@ export {format, formatIndicators, getColorScale, COLOR_MAP} from './format'; ...@@ -37,6 +37,7 @@ export {format, formatIndicators, getColorScale, COLOR_MAP} from './format';
export {filter} from './filter'; export {filter} from './filter';
export {calculateRelativeTime, chartData} from './metric'; export {calculateRelativeTime, chartData} from './metric';
export {default as useGraph} from './hooks/useGraph'; export {default as useGraph} from './hooks/useGraph';
export {default as useIndicatorOrder} from './hooks/useIndicatorOrder';
export const DEFAULT_ORDER_INDICATOR = Symbol('DEFAULT_ORDER_INDICATOR'); export const DEFAULT_ORDER_INDICATOR = Symbol('DEFAULT_ORDER_INDICATOR');
export const DND_TYPE = Symbol('DND_TYPE'); export const DND_TYPE = Symbol('DND_TYPE');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册