Add UI for timeline

Summary:
Add a GUI for the timeline of a Component based off MarkerTimeline.

It enables selecting points on the timeline, which will display their properties (arbitrary KVS). A button allows the user to select the current point of the timeline for the tree. This triggers unselection of the tree as per D24254002.

Solving re-selection isn't trivial, which is why the tree collapses on redraw too, and I believe we can live with this UX for this v1.

Reviewed By: astreet

Differential Revision: D23865369

fbshipit-source-id: 026562e71aa04b4e5e1e7cf1392d8ef140cdf43c
This commit is contained in:
Paco Estevez Garcia
2020-10-19 05:58:02 -07:00
committed by Facebook GitHub Bot
parent e9dc645423
commit 678e12974d
2 changed files with 104 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ import React, {KeyboardEvent} from 'react';
import Glyph from '../Glyph';
import {HighlightContext} from '../Highlight';
import Select from '../Select';
import TimelineDataDescription from './TimelineDataDescription';
const NullValue = styled.span({
color: 'rgb(128, 128, 128)',
@@ -567,6 +568,24 @@ class DataDescriptionContainer extends PureComponent<{
const highlighter = this.context;
switch (type) {
case 'timeline': {
return (
<>
<TimelineDataDescription
timeline={JSON.parse(val)}
onClick={(id) => {
this.props.commit({
value: id,
keep: true,
clear: false,
set: true,
});
}}
/>
</>
);
}
case 'number':
return <NumberValue>{+val}</NumberValue>;

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import ManagedDataInspector from './ManagedDataInspector';
import {Component, ReactNode} from 'react';
import {colors} from '../colors';
import React from 'react';
import MarkerTimeline from '../MarkerTimeline';
import Button from '../Button';
type TimePoint = {
moment: number;
display: string;
color: string;
key: string;
properties: {[key: string]: string};
};
type Timeline = {
time: TimePoint[];
current: string;
};
type Props = {
timeline: Timeline;
onClick: (selected: string) => void;
};
type State = {
selected: string;
};
export default class TimelineDataDescription extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {selected: props.timeline.current};
}
render(): ReactNode {
const moments = Object.values(this.props.timeline.time);
const firstMoment = moments[0].moment;
const points = moments.map((value) => ({
label: value.display,
time: value.moment - firstMoment,
color:
Object.entries(colors).find(([k, _]) => k === value.color)?.[1] ??
value.color,
key: value.key,
}));
return (
<>
<div>
<Button
onClick={() => this.props.onClick(this.state.selected)}
disabled={this.state.selected === this.props.timeline.current}>
Set as current
</Button>
</div>
<div>
<MarkerTimeline
points={points}
onClick={(ids) => this.setState({selected: ids[0]})}
maxGap={50}
selected={this.state.selected}
/>
</div>
<div>
<ManagedDataInspector
data={
this.props.timeline.time.find(
(value) => value.key === this.state.selected,
)?.properties ?? {}
}
/>
</div>
</>
);
}
}