Move Sections Plugin to OS folder
Summary: as title; we'd like to reuse this for the Litho sections plugin but not having it in OS makes setting up deps more difficult than it should be. Reviewed By: danielbuechele Differential Revision: D16052298 fbshipit-source-id: cd965688eff4fedbe57264e6676b6ca09b9deb45
This commit is contained in:
committed by
Facebook Github Bot
parent
468468a3bc
commit
353f65cd7f
@@ -7,7 +7,7 @@
|
|||||||
.*/static/.*
|
.*/static/.*
|
||||||
<PROJECT_ROOT>/src/fb/plugins/relaydevtools/relay-devtools/DevtoolsUI.js$
|
<PROJECT_ROOT>/src/fb/plugins/relaydevtools/relay-devtools/DevtoolsUI.js$
|
||||||
.*/website/.*
|
.*/website/.*
|
||||||
<PROJECT_ROOT>/src/fb/plugins/sections/d3/d3.js$
|
<PROJECT_ROOT>/src/plugins/sections/d3/d3.js$
|
||||||
|
|
||||||
[libs]
|
[libs]
|
||||||
flow-typed
|
flow-typed
|
||||||
|
|||||||
88
src/plugins/sections/DetailsPanel.js
Normal file
88
src/plugins/sections/DetailsPanel.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
import type {UpdateTreeGenerationChangesetApplicationPayload} from './Models.js';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
MarkerTimeline,
|
||||||
|
Component,
|
||||||
|
styled,
|
||||||
|
FlexBox,
|
||||||
|
ManagedDataInspector,
|
||||||
|
Panel,
|
||||||
|
colors,
|
||||||
|
} from 'flipper';
|
||||||
|
|
||||||
|
const NoContent = styled(FlexBox)({
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexGrow: 1,
|
||||||
|
fontWeight: '500',
|
||||||
|
color: colors.light30,
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = {|
|
||||||
|
changeSets: ?Array<UpdateTreeGenerationChangesetApplicationPayload>,
|
||||||
|
eventUserInfo: ?Object,
|
||||||
|
focusedChangeSet: ?UpdateTreeGenerationChangesetApplicationPayload,
|
||||||
|
onFocusChangeSet: (
|
||||||
|
focusedChangeSet: ?UpdateTreeGenerationChangesetApplicationPayload,
|
||||||
|
) => void,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export default class DetailsPanel extends Component<Props> {
|
||||||
|
render() {
|
||||||
|
const {changeSets, eventUserInfo} = this.props;
|
||||||
|
const firstChangeSet =
|
||||||
|
(changeSets || []).reduce(
|
||||||
|
(min, cs) => Math.min(min, cs.timestamp),
|
||||||
|
Infinity,
|
||||||
|
) || 0;
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{eventUserInfo && (
|
||||||
|
<Panel
|
||||||
|
collapsable={false}
|
||||||
|
floating={false}
|
||||||
|
heading={'Event User Info'}>
|
||||||
|
<ManagedDataInspector data={eventUserInfo} expandRoot={true} />
|
||||||
|
</Panel>
|
||||||
|
)}
|
||||||
|
{changeSets && changeSets.length > 0 ? (
|
||||||
|
<Panel collapsable={false} floating={false} heading={'Changesets'}>
|
||||||
|
<MarkerTimeline
|
||||||
|
points={changeSets.map(p => ({
|
||||||
|
label:
|
||||||
|
p.type === 'CHANGESET_GENERATED' ? 'Generated' : 'Rendered',
|
||||||
|
time: Math.round((p.timestamp || 0) - firstChangeSet),
|
||||||
|
color:
|
||||||
|
p.type === 'CHANGESET_GENERATED' ? colors.lemon : colors.teal,
|
||||||
|
key: p.identifier,
|
||||||
|
}))}
|
||||||
|
onClick={ids =>
|
||||||
|
this.props.onFocusChangeSet(
|
||||||
|
changeSets.find(c => c.identifier === ids[0]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
selected={this.props.focusedChangeSet?.identifier}
|
||||||
|
/>
|
||||||
|
</Panel>
|
||||||
|
) : (
|
||||||
|
<NoContent>No changes sets available</NoContent>
|
||||||
|
)}
|
||||||
|
{this.props.focusedChangeSet && (
|
||||||
|
<Panel floating={false} heading="Changeset Details">
|
||||||
|
<ManagedDataInspector
|
||||||
|
data={this.props.focusedChangeSet.changeset}
|
||||||
|
expandRoot={true}
|
||||||
|
/>
|
||||||
|
</Panel>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
249
src/plugins/sections/EventsTable.js
Normal file
249
src/plugins/sections/EventsTable.js
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {TreeGeneration} from './Models.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
FlexColumn,
|
||||||
|
FlexRow,
|
||||||
|
Component,
|
||||||
|
Tooltip,
|
||||||
|
Glyph,
|
||||||
|
styled,
|
||||||
|
colors,
|
||||||
|
} from 'flipper';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const PADDING = 15;
|
||||||
|
const WIDTH = 70;
|
||||||
|
const LABEL_WIDTH = 140;
|
||||||
|
|
||||||
|
const Container = styled(FlexRow)({
|
||||||
|
flexShrink: 0,
|
||||||
|
flexGrow: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const SurfaceContainer = styled(FlexColumn)(props => ({
|
||||||
|
position: 'relative',
|
||||||
|
'::after': {
|
||||||
|
display: props.scrolled ? 'block' : 'none',
|
||||||
|
content: '""',
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
right: -15,
|
||||||
|
width: 15,
|
||||||
|
background: `linear-gradient(90deg, ${
|
||||||
|
colors.macOSTitleBarBackgroundBlur
|
||||||
|
} 0%, transparent 100%)`,
|
||||||
|
zIndex: 3,
|
||||||
|
position: 'absolute',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TimeContainer = styled(FlexColumn)({
|
||||||
|
overflow: 'scroll',
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Row = styled(FlexRow)(props => ({
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingBottom: 3,
|
||||||
|
marginTop: 3,
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 0,
|
||||||
|
maxHeight: 75,
|
||||||
|
position: 'relative',
|
||||||
|
minWidth: '100%',
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
'::before': {
|
||||||
|
display: props.showTimeline ? 'block' : 'none',
|
||||||
|
zIndex: 1,
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
borderTop: `1px dotted ${colors.light15}`,
|
||||||
|
height: 1,
|
||||||
|
top: '50%',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Label = styled('div')({
|
||||||
|
width: LABEL_WIDTH,
|
||||||
|
paddingLeft: 10,
|
||||||
|
paddingRight: 10,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textAlign: 'right',
|
||||||
|
flexShrink: 0,
|
||||||
|
position: 'sticky',
|
||||||
|
left: 0,
|
||||||
|
zIndex: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Content = styled('div')({
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden',
|
||||||
|
fontSize: 11,
|
||||||
|
textAlign: 'center',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
fontWeight: '500',
|
||||||
|
color: colors.light50,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Record = styled('div')(({highlighted}) => ({
|
||||||
|
border: `1px solid ${colors.light15}`,
|
||||||
|
boxShadow: highlighted
|
||||||
|
? `inset 0 0 0 2px ${colors.macOSTitleBarIconSelected}`
|
||||||
|
: 'none',
|
||||||
|
borderRadius: 5,
|
||||||
|
padding: 5,
|
||||||
|
marginRight: PADDING,
|
||||||
|
backgroundColor: colors.white,
|
||||||
|
zIndex: 2,
|
||||||
|
position: 'relative',
|
||||||
|
width: WIDTH,
|
||||||
|
flexShrink: 0,
|
||||||
|
alignSelf: 'stretch',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Empty = styled('div')({
|
||||||
|
width: WIDTH,
|
||||||
|
padding: '10px 5px',
|
||||||
|
marginRight: PADDING,
|
||||||
|
flexShrink: 0,
|
||||||
|
position: 'relative',
|
||||||
|
});
|
||||||
|
|
||||||
|
const Icon = styled(Glyph)({
|
||||||
|
position: 'absolute',
|
||||||
|
right: 5,
|
||||||
|
top: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = {|
|
||||||
|
generations: Array<TreeGeneration>,
|
||||||
|
focusedGenerationId: ?string,
|
||||||
|
onClick: (id: string) => mixed,
|
||||||
|
|};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
scrolled: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class extends Component<Props, State> {
|
||||||
|
state = {
|
||||||
|
scrolled: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener('keydown', this.onKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener('keydown', this.onKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: Props) {
|
||||||
|
const {focusedGenerationId} = this.props;
|
||||||
|
if (
|
||||||
|
focusedGenerationId &&
|
||||||
|
focusedGenerationId !== prevProps.focusedGenerationId
|
||||||
|
) {
|
||||||
|
const node = document.querySelector(`[data-id="${focusedGenerationId}"]`);
|
||||||
|
if (node) {
|
||||||
|
// $FlowFixMe scrollIntoViewIfNeeded exists
|
||||||
|
node.scrollIntoViewIfNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
let nextGenerationId = null;
|
||||||
|
|
||||||
|
const index = this.props.generations.findIndex(
|
||||||
|
g => g.id === this.props.focusedGenerationId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const direction = e.key === 'ArrowRight' ? 1 : -1;
|
||||||
|
const bound = e.key === 'ArrowRight' ? this.props.generations.length : -1;
|
||||||
|
|
||||||
|
for (let i = index + direction; i !== bound; i += direction) {
|
||||||
|
if (
|
||||||
|
this.props.generations[i].surface_key ===
|
||||||
|
this.props.generations[index].surface_key
|
||||||
|
) {
|
||||||
|
nextGenerationId = this.props.generations[i].id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextGenerationId) {
|
||||||
|
this.props.onClick(nextGenerationId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onScroll = (e: SyntheticUIEvent<HTMLElement>) =>
|
||||||
|
this.setState({scrolled: e.currentTarget.scrollLeft > 0});
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const surfaces = this.props.generations.reduce(
|
||||||
|
(acc, cv) => acc.add(cv.surface_key),
|
||||||
|
new Set(),
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<SurfaceContainer scrolled={this.state.scrolled}>
|
||||||
|
{[...surfaces].map(surface => (
|
||||||
|
<Row key={surface}>
|
||||||
|
<Label title={surface}>{surface}</Label>
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
</SurfaceContainer>
|
||||||
|
<TimeContainer onScroll={this.onScroll}>
|
||||||
|
{[...surfaces].map(surface => (
|
||||||
|
<Row key={surface} showTimeline>
|
||||||
|
{this.props.generations.map((record: TreeGeneration) =>
|
||||||
|
record.surface_key === surface ? (
|
||||||
|
<Record
|
||||||
|
key={`${surface}${record.id}`}
|
||||||
|
data-id={record.id}
|
||||||
|
highlighted={record.id === this.props.focusedGenerationId}
|
||||||
|
onClick={() => this.props.onClick(record.id)}>
|
||||||
|
<Content>{record.reason}</Content>
|
||||||
|
{record.reentrant_count > 0 && (
|
||||||
|
<Tooltip
|
||||||
|
title={'Reentrant count ' + record.reentrant_count}>
|
||||||
|
<Icon
|
||||||
|
color={colors.red}
|
||||||
|
name="caution-circle"
|
||||||
|
variant="filled"
|
||||||
|
size={12}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Record>
|
||||||
|
) : (
|
||||||
|
<Empty key={`${surface}${record.id}`} />
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
</TimeContainer>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/plugins/sections/Models.js
Normal file
83
src/plugins/sections/Models.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type SectionComponentHierarchy = {|
|
||||||
|
type: string,
|
||||||
|
children: Array<SectionComponentHierarchy>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type AddEventPayload = {|
|
||||||
|
id: string,
|
||||||
|
reason: string,
|
||||||
|
stack_trace: Array<string>,
|
||||||
|
surface_key: string,
|
||||||
|
event_timestamp: number,
|
||||||
|
update_mode: number,
|
||||||
|
reentrant_count: number,
|
||||||
|
payload: ?Object,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type UpdateTreeGenerationHierarchyGenerationPayload = {|
|
||||||
|
hierarchy_generation_timestamp: number,
|
||||||
|
id: string,
|
||||||
|
reason: string,
|
||||||
|
tree?: Array<{
|
||||||
|
didTriggerStateUpdate: boolean,
|
||||||
|
identifier: string,
|
||||||
|
isDirty: boolean,
|
||||||
|
isReused: boolean,
|
||||||
|
name: string,
|
||||||
|
parent: string | 0,
|
||||||
|
}>,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type UpdateTreeGenerationChangesetGenerationPayload = {|
|
||||||
|
timestamp: number,
|
||||||
|
tree_generation_id: string,
|
||||||
|
identifier: string,
|
||||||
|
type: string,
|
||||||
|
changeset: {
|
||||||
|
inserted_items: {},
|
||||||
|
inserted_sections: {},
|
||||||
|
moved_items: {},
|
||||||
|
removed_sections: [],
|
||||||
|
updated_items: {
|
||||||
|
[key: string]: {
|
||||||
|
context: string,
|
||||||
|
model: string,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type UpdateTreeGenerationChangesetApplicationPayload = {|
|
||||||
|
changeset: {
|
||||||
|
inserted_items: {},
|
||||||
|
inserted_sections: {},
|
||||||
|
moved_items: {},
|
||||||
|
removed_sections: [],
|
||||||
|
updated_items: {
|
||||||
|
[key: string]: {
|
||||||
|
context: string,
|
||||||
|
model: string,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: string,
|
||||||
|
identifier: string,
|
||||||
|
timestamp: number,
|
||||||
|
section_component_hierarchy: SectionComponentHierarchy,
|
||||||
|
tree_generation_id: string,
|
||||||
|
payload: ?Object,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type TreeGeneration = {|
|
||||||
|
...AddEventPayload,
|
||||||
|
...$Shape<UpdateTreeGenerationHierarchyGenerationPayload>,
|
||||||
|
...$Shape<UpdateTreeGenerationChangesetGenerationPayload>,
|
||||||
|
changeSets: Array<UpdateTreeGenerationChangesetApplicationPayload>,
|
||||||
|
|};
|
||||||
47
src/plugins/sections/StackTrace.js
Normal file
47
src/plugins/sections/StackTrace.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {colors, StackTrace} from 'flipper';
|
||||||
|
|
||||||
|
const FacebookLibraries = ['Facebook'];
|
||||||
|
|
||||||
|
const REGEX = new RegExp(
|
||||||
|
'(?<library>[A-Za-z0-9]*) *(?<address>0x[A-Za-z0-9]*) (?<caller>(.*)) \\+ (?<lineNumber>[0-9]*)',
|
||||||
|
);
|
||||||
|
|
||||||
|
function isSystemLibrary(libraryName: ?string): boolean {
|
||||||
|
return !FacebookLibraries.includes(libraryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: Array<string>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<StackTrace backgroundColor={colors.white}>
|
||||||
|
{/* We need to filter out from the stack trace any reference to the plugin such that the information is more coincised and focused */}
|
||||||
|
{this.props.data
|
||||||
|
.filter(stack_trace_line => {
|
||||||
|
return !stack_trace_line.includes('FlipperKitSectionsPlugin');
|
||||||
|
})
|
||||||
|
.map(stack_trace_line => {
|
||||||
|
const trace = REGEX.exec(stack_trace_line)?.groups;
|
||||||
|
return {
|
||||||
|
bold: !isSystemLibrary(trace?.library),
|
||||||
|
library: trace?.library,
|
||||||
|
address: trace?.address,
|
||||||
|
caller: trace?.caller,
|
||||||
|
lineNumber: trace?.lineNumber,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
</StackTrace>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
236
src/plugins/sections/Tree.js
Normal file
236
src/plugins/sections/Tree.js
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {SectionComponentHierarchy} from './Models';
|
||||||
|
|
||||||
|
import {PureComponent, styled, Toolbar, Spacer, colors} from 'flipper';
|
||||||
|
import {Tree} from 'react-d3-tree';
|
||||||
|
import {Fragment} from 'react';
|
||||||
|
|
||||||
|
const Legend = styled('div')(props => ({
|
||||||
|
color: colors.dark50,
|
||||||
|
marginLeft: 20,
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
display: 'inline-block',
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
borderRadius: 6,
|
||||||
|
backgroundColor: props.color,
|
||||||
|
border: `1px solid rgba(0,0,0,0.2)`,
|
||||||
|
marginRight: 4,
|
||||||
|
marginBottom: -1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Label = styled('div')({
|
||||||
|
position: 'relative',
|
||||||
|
top: -7,
|
||||||
|
left: 7,
|
||||||
|
maxWidth: 270,
|
||||||
|
overflow: 'hidden',
|
||||||
|
fontWeight: '500',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
paddingLeft: 5,
|
||||||
|
paddingRight: 5,
|
||||||
|
background: colors.white,
|
||||||
|
display: 'inline-block',
|
||||||
|
});
|
||||||
|
|
||||||
|
const Container = styled('div')({
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
background:
|
||||||
|
'linear-gradient(-90deg,rgba(0,0,0,.02) 1px,transparent 0),linear-gradient(rgba(0,0,0,.02) 1px,transparent 0),linear-gradient(-90deg,rgba(0,0,0,.03) 1px,transparent 0),linear-gradient(rgba(0,0,0,.03) 1px,transparent 0)',
|
||||||
|
backgroundSize:
|
||||||
|
'10px 10px,10px 10px,100px 100px,100px 100px,100px 100px,100px 100px,100px 100px,100px 100px',
|
||||||
|
});
|
||||||
|
|
||||||
|
type TreeData = Array<{
|
||||||
|
identifier: string,
|
||||||
|
name: string,
|
||||||
|
parent: string | 0,
|
||||||
|
didTriggerStateUpdate: boolean,
|
||||||
|
isReused: boolean,
|
||||||
|
isDirty: boolean,
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: TreeData | SectionComponentHierarchy,
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
translate: {
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
},
|
||||||
|
tree: ?Object,
|
||||||
|
zoom: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
const NodeLabel = (props: {
|
||||||
|
nodeData: {
|
||||||
|
name: string,
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
|
const name = props?.nodeData?.name;
|
||||||
|
return <Label title={name}>{name}</Label>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class extends PureComponent<Props, State> {
|
||||||
|
treeFromFlatArray = (data: TreeData) => {
|
||||||
|
const tree = data.map(n => {
|
||||||
|
let fill = colors.blueGreyTint70;
|
||||||
|
if (n.didTriggerStateUpdate) {
|
||||||
|
fill = colors.lemon;
|
||||||
|
} else if (n.isReused) {
|
||||||
|
fill = colors.teal;
|
||||||
|
} else if (n.isDirty) {
|
||||||
|
fill = colors.grape;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: n.name,
|
||||||
|
children: [],
|
||||||
|
attributes: {...n},
|
||||||
|
nodeSvgShape: {
|
||||||
|
shapeProps: {
|
||||||
|
fill,
|
||||||
|
r: 6,
|
||||||
|
strokeWidth: 1,
|
||||||
|
stroke: 'rgba(0,0,0,0.2)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const parentMap: Map<string, Array<Object>> = tree.reduce((acc, cv) => {
|
||||||
|
const {parent} = cv.attributes;
|
||||||
|
if (typeof parent !== 'string') {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
const children = acc.get(parent);
|
||||||
|
if (children) {
|
||||||
|
return acc.set(parent, children.concat(cv));
|
||||||
|
} else {
|
||||||
|
return acc.set(parent, [cv]);
|
||||||
|
}
|
||||||
|
}, new Map());
|
||||||
|
|
||||||
|
tree.forEach(n => {
|
||||||
|
n.children = parentMap.get(n.attributes.identifier) || [];
|
||||||
|
});
|
||||||
|
|
||||||
|
// find the root node
|
||||||
|
return tree.find(node => !node.attributes.parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
treeFromHierarchy = (data: SectionComponentHierarchy): Object => {
|
||||||
|
return {
|
||||||
|
name: data.type,
|
||||||
|
children: data.children ? data.children.map(this.treeFromHierarchy) : [],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
translate: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
tree: Array.isArray(this.props.data)
|
||||||
|
? this.treeFromFlatArray(this.props.data)
|
||||||
|
: this.treeFromHierarchy(this.props.data),
|
||||||
|
zoom: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
treeContainer: any = null;
|
||||||
|
|
||||||
|
componentWillReceiveProps(props: Props) {
|
||||||
|
if (this.props.data === props.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
tree: Array.isArray(props.data)
|
||||||
|
? this.treeFromFlatArray(props.data)
|
||||||
|
: this.treeFromHierarchy(props.data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.treeContainer) {
|
||||||
|
const dimensions = this.treeContainer.getBoundingClientRect();
|
||||||
|
this.setState({
|
||||||
|
translate: {
|
||||||
|
x: 50,
|
||||||
|
y: dimensions.height / 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onZoom = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
||||||
|
this.setState({zoom: e.target.valueAsNumber});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Container
|
||||||
|
innerRef={ref => {
|
||||||
|
this.treeContainer = ref;
|
||||||
|
}}>
|
||||||
|
<style>
|
||||||
|
{'.rd3t-tree-container foreignObject {overflow: visible;}'}
|
||||||
|
</style>
|
||||||
|
{this.state.tree && (
|
||||||
|
<Tree
|
||||||
|
transitionDuration={0}
|
||||||
|
separation={{siblings: 0.5, nonSiblings: 0.5}}
|
||||||
|
data={this.state.tree}
|
||||||
|
translate={this.state.translate}
|
||||||
|
zoom={this.state.zoom}
|
||||||
|
nodeLabelComponent={{
|
||||||
|
// $FlowFixMe props are passed in by react-d3-tree
|
||||||
|
render: <NodeLabel />,
|
||||||
|
}}
|
||||||
|
allowForeignObjects
|
||||||
|
nodeSvgShape={{
|
||||||
|
shape: 'circle',
|
||||||
|
shapeProps: {
|
||||||
|
stroke: 'rgba(0,0,0,0.2)',
|
||||||
|
strokeWidth: 1,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
styles={{
|
||||||
|
links: {
|
||||||
|
stroke: '#b3b3b3',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
nodeSize={{x: 300, y: 100}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
<Toolbar position="bottom" compact>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
onChange={this.onZoom}
|
||||||
|
value={this.state.zoom}
|
||||||
|
min="0.1"
|
||||||
|
max="1"
|
||||||
|
step="0.01"
|
||||||
|
/>
|
||||||
|
<Spacer />
|
||||||
|
<Legend color={colors.lemon}>triggered state update</Legend>
|
||||||
|
<Legend color={colors.teal}>is reused</Legend>
|
||||||
|
<Legend color={colors.grape}>is dirty</Legend>
|
||||||
|
</Toolbar>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/plugins/sections/d3/LICENSE
Normal file
26
src/plugins/sections/d3/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) 2010-2016, Michael Bostock
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* The name Michael Bostock may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
9553
src/plugins/sections/d3/d3.js
vendored
Normal file
9553
src/plugins/sections/d3/d3.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
69
src/plugins/sections/d3/package.json
Normal file
69
src/plugins/sections/d3/package.json
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"name": "d3",
|
||||||
|
"version": "3.5.17",
|
||||||
|
"description": "A JavaScript visualization library for HTML and SVG.",
|
||||||
|
"bugs": {
|
||||||
|
"email": "danielbuechele@fb.com"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"dom",
|
||||||
|
"w3c",
|
||||||
|
"visualization",
|
||||||
|
"svg",
|
||||||
|
"animation",
|
||||||
|
"canvas"
|
||||||
|
],
|
||||||
|
"homepage": "http://d3js.org",
|
||||||
|
"author": {
|
||||||
|
"name": "Mike Bostock",
|
||||||
|
"url": "http://bost.ocks.org/mike"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Jason Davies",
|
||||||
|
"url": "http://jasondavies.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/mbostock/d3.git"
|
||||||
|
},
|
||||||
|
"main": "d3.js",
|
||||||
|
"browser": "d3.js",
|
||||||
|
"jspm": {
|
||||||
|
"main": "d3",
|
||||||
|
"shim": {
|
||||||
|
"d3": {
|
||||||
|
"exports": "d3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"d3.js"
|
||||||
|
],
|
||||||
|
"buildConfig": {
|
||||||
|
"uglify": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jam": {
|
||||||
|
"main": "d3.js",
|
||||||
|
"shim": {
|
||||||
|
"exports": "d3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spm": {
|
||||||
|
"main": "d3.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"jsdom": "3",
|
||||||
|
"seedrandom": "2",
|
||||||
|
"smash": "0.0",
|
||||||
|
"uglify-js": "2.6.2",
|
||||||
|
"vows": "0.8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "vows && echo",
|
||||||
|
"prepublish": "npm test && rm -f package.js src/start.js d3.js d3.min.js d3.zip && bin/start > src/start.js && bin/meteor > package.js && smash src/d3.js | uglifyjs - -b indent-level=2 -o d3.js && bin/uglify d3.js > d3.min.js && chmod a-w d3.js d3.min.js package.js && zip d3.zip LICENSE d3.js d3.min.js",
|
||||||
|
"postpublish": "VERSION=`node -e 'console.log(require(\"./package.json\").version)'`; git push && git push --tags && cp -v README.md LICENSE d3.js d3.min.js ../d3-bower && cd ../d3-bower && git add README.md LICENSE d3.js d3.min.js && git commit -m \"Release $VERSION.\" && git tag -am \"Release $VERSION.\" v${VERSION} && git push && git push --tags && cd - && cp -v d3.js ../d3.github.com/d3.v3.js && cp -v d3.min.js ../d3.github.com/d3.v3.min.js && cd ../d3.github.com && git add d3.v3.js d3.v3.min.js && git commit -m \"d3 ${VERSION}\" && git push"
|
||||||
|
},
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
}
|
||||||
266
src/plugins/sections/index.js
Normal file
266
src/plugins/sections/index.js
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
TreeGeneration,
|
||||||
|
AddEventPayload,
|
||||||
|
UpdateTreeGenerationHierarchyGenerationPayload,
|
||||||
|
UpdateTreeGenerationChangesetGenerationPayload,
|
||||||
|
UpdateTreeGenerationChangesetApplicationPayload,
|
||||||
|
} from './Models.js';
|
||||||
|
|
||||||
|
import {FlipperPlugin} from 'flipper';
|
||||||
|
import React from 'react';
|
||||||
|
import Tree from './Tree.js';
|
||||||
|
import StackTrace from './StackTrace.js';
|
||||||
|
import EventTable from './EventsTable.js';
|
||||||
|
import DetailsPanel from './DetailsPanel.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Toolbar,
|
||||||
|
Glyph,
|
||||||
|
Sidebar,
|
||||||
|
FlexBox,
|
||||||
|
styled,
|
||||||
|
Button,
|
||||||
|
Spacer,
|
||||||
|
colors,
|
||||||
|
DetailSidebar,
|
||||||
|
} from 'flipper';
|
||||||
|
|
||||||
|
const Waiting = styled(FlexBox)(props => ({
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
flexGrow: 1,
|
||||||
|
background: colors.light02,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const InfoText = styled('div')(props => ({
|
||||||
|
marginTop: 10,
|
||||||
|
marginBottom: 10,
|
||||||
|
fontWeight: '500',
|
||||||
|
color: colors.light30,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const InfoBox = styled('div')(props => ({
|
||||||
|
maxWidth: 400,
|
||||||
|
margin: 'auto',
|
||||||
|
textAlign: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
focusedChangeSet: ?UpdateTreeGenerationChangesetApplicationPayload,
|
||||||
|
userSelectedGenerationId: ?string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type PersistedState = {
|
||||||
|
generations: {
|
||||||
|
[id: string]: TreeGeneration,
|
||||||
|
},
|
||||||
|
focusedGenerationId: ?string,
|
||||||
|
recording: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class extends FlipperPlugin<State, *, PersistedState> {
|
||||||
|
static title = 'Sections';
|
||||||
|
static id = 'Sections';
|
||||||
|
static icon = 'tree';
|
||||||
|
|
||||||
|
static defaultPersistedState = {
|
||||||
|
generations: {},
|
||||||
|
focusedGenerationId: null,
|
||||||
|
recording: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static persistedStateReducer = (
|
||||||
|
persistedState: PersistedState,
|
||||||
|
method: string,
|
||||||
|
payload: Object,
|
||||||
|
): $Shape<PersistedState> => {
|
||||||
|
if (!persistedState.recording) {
|
||||||
|
return persistedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const addEvent = (data: AddEventPayload) => ({
|
||||||
|
...persistedState,
|
||||||
|
generations: {
|
||||||
|
...persistedState.generations,
|
||||||
|
[data.id]: {
|
||||||
|
...data,
|
||||||
|
changeSets: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
focusedGenerationId: persistedState.focusedGenerationId || data.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateTreeGenerationHierarchyGeneration = (
|
||||||
|
data: UpdateTreeGenerationHierarchyGenerationPayload,
|
||||||
|
) => ({
|
||||||
|
...persistedState,
|
||||||
|
generations: {
|
||||||
|
...persistedState.generations,
|
||||||
|
[data.id]: {
|
||||||
|
...persistedState.generations[data.id],
|
||||||
|
...data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateTreeGenerationChangeset = (
|
||||||
|
data:
|
||||||
|
| UpdateTreeGenerationChangesetGenerationPayload
|
||||||
|
| UpdateTreeGenerationChangesetApplicationPayload,
|
||||||
|
) => ({
|
||||||
|
...persistedState,
|
||||||
|
generations: {
|
||||||
|
...persistedState.generations,
|
||||||
|
[data.tree_generation_id]: {
|
||||||
|
...persistedState.generations[data.tree_generation_id],
|
||||||
|
changeSets: [
|
||||||
|
...persistedState.generations[data.tree_generation_id].changeSets,
|
||||||
|
data,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (method === 'addEvent') {
|
||||||
|
return addEvent(payload);
|
||||||
|
} else if (method === 'updateTreeGenerationHierarchyGeneration') {
|
||||||
|
return updateTreeGenerationHierarchyGeneration(payload);
|
||||||
|
} else if (
|
||||||
|
method === 'updateTreeGenerationChangesetApplication' ||
|
||||||
|
method === 'updateTreeGenerationChangesetGeneration'
|
||||||
|
) {
|
||||||
|
return updateTreeGenerationChangeset(payload);
|
||||||
|
} else {
|
||||||
|
return persistedState;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
focusedChangeSet: null,
|
||||||
|
userSelectedGenerationId: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
onTreeGenerationFocused = (focusedGenerationId: ?string) => {
|
||||||
|
this.setState({
|
||||||
|
focusedChangeSet: null,
|
||||||
|
userSelectedGenerationId: focusedGenerationId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onFocusChangeSet = (
|
||||||
|
focusedChangeSet: ?UpdateTreeGenerationChangesetApplicationPayload,
|
||||||
|
) => {
|
||||||
|
this.setState({
|
||||||
|
focusedChangeSet,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTreeHierarchy = (generation: ?TreeGeneration) => {
|
||||||
|
if (generation && generation.tree && generation.tree.length > 0) {
|
||||||
|
// Display component tree hierarchy, if any
|
||||||
|
return <Tree data={generation.tree} />;
|
||||||
|
} else if (
|
||||||
|
this.state.focusedChangeSet &&
|
||||||
|
this.state.focusedChangeSet.section_component_hierarchy
|
||||||
|
) {
|
||||||
|
// Display section component hierarchy for specific changeset
|
||||||
|
return (
|
||||||
|
<Tree data={this.state.focusedChangeSet.section_component_hierarchy} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return this.renderWaiting();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderWaiting = () => (
|
||||||
|
<Waiting>
|
||||||
|
<InfoBox>
|
||||||
|
<Glyph
|
||||||
|
name="face-unhappy"
|
||||||
|
variant="outline"
|
||||||
|
size={24}
|
||||||
|
color={colors.light30}
|
||||||
|
/>
|
||||||
|
<InfoText>No data available...</InfoText>
|
||||||
|
</InfoBox>
|
||||||
|
</Waiting>
|
||||||
|
);
|
||||||
|
|
||||||
|
clear = () => {
|
||||||
|
this.props.setPersistedState({
|
||||||
|
...this.constructor.defaultPersistedState,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {generations} = this.props.persistedState;
|
||||||
|
if (Object.values(this.props.persistedState.generations).length === 0) {
|
||||||
|
return this.renderWaiting();
|
||||||
|
}
|
||||||
|
|
||||||
|
const focusedGenerationId =
|
||||||
|
this.state.userSelectedGenerationId ||
|
||||||
|
this.props.persistedState.focusedGenerationId;
|
||||||
|
|
||||||
|
const focusedTreeGeneration: ?TreeGeneration = focusedGenerationId
|
||||||
|
? generations[focusedGenerationId]
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Toolbar>
|
||||||
|
<Spacer />
|
||||||
|
{this.props.persistedState.recording ? (
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
this.props.setPersistedState({
|
||||||
|
recording: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
iconVariant="filled"
|
||||||
|
icon="stop-playback">
|
||||||
|
Stop
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button onClick={this.clear} icon="trash" iconVariant="outline">
|
||||||
|
Clear
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Toolbar>
|
||||||
|
<Sidebar position="top" minHeight={80} height={80}>
|
||||||
|
<EventTable
|
||||||
|
// $FlowFixMe Object.values returns Array<mixed>: https://github.com/facebook/flow/issues/2221
|
||||||
|
generations={Object.values(generations)}
|
||||||
|
focusedGenerationId={focusedGenerationId}
|
||||||
|
onClick={this.onTreeGenerationFocused}
|
||||||
|
/>
|
||||||
|
</Sidebar>
|
||||||
|
{this.renderTreeHierarchy(focusedTreeGeneration)}
|
||||||
|
{focusedTreeGeneration && (
|
||||||
|
<Sidebar position="bottom" minHeight={100} height={250}>
|
||||||
|
<StackTrace data={focusedTreeGeneration.stack_trace} />
|
||||||
|
</Sidebar>
|
||||||
|
)}
|
||||||
|
<DetailSidebar>
|
||||||
|
<DetailsPanel
|
||||||
|
eventUserInfo={focusedTreeGeneration?.payload}
|
||||||
|
changeSets={focusedTreeGeneration?.changeSets}
|
||||||
|
onFocusChangeSet={this.onFocusChangeSet}
|
||||||
|
focusedChangeSet={this.state.focusedChangeSet}
|
||||||
|
/>
|
||||||
|
</DetailSidebar>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/plugins/sections/package.json
Normal file
18
src/plugins/sections/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "flipper-plugin-sections",
|
||||||
|
"title": "Sections",
|
||||||
|
"bugs": {
|
||||||
|
"email": "oncall+ios_componentkit@xmail.facebook.com",
|
||||||
|
"url": "https://fb.workplace.com/groups/componentkit/"
|
||||||
|
},
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"gatekeeper": "flipper_sections_plugin",
|
||||||
|
"dependencies": {
|
||||||
|
"react-d3-tree": "^1.12.1"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"react-d3-tree/d3": "file:./d3"
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/plugins/sections/yarn.lock
Normal file
100
src/plugins/sections/yarn.lock
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@babel/runtime@^7.1.2":
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f"
|
||||||
|
integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.12.0"
|
||||||
|
|
||||||
|
chain-function@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.1.tgz#c63045e5b4b663fb86f1c6e186adaf1de402a1cc"
|
||||||
|
integrity sha512-SxltgMwL9uCko5/ZCLiyG2B7R9fY4pDZUw7hJ4MhirdjBLosoDqkWABi3XMucddHdLiFJMb7PD2MZifZriuMTg==
|
||||||
|
|
||||||
|
clone@^2.1.1:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
|
||||||
|
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
|
||||||
|
|
||||||
|
d3@3.5.17, "d3@file:./d3":
|
||||||
|
version "3.5.17"
|
||||||
|
|
||||||
|
deep-equal@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||||
|
integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
|
||||||
|
|
||||||
|
dom-helpers@^3.2.0:
|
||||||
|
version "3.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
|
||||||
|
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.1.2"
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||||
|
|
||||||
|
loose-envify@^1.0.0, loose-envify@^1.3.1:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
|
object-assign@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
|
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||||
|
|
||||||
|
prop-types@^15.5.10, prop-types@^15.5.6:
|
||||||
|
version "15.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||||
|
integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.3.1"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
react-d3-tree@^1.12.1:
|
||||||
|
version "1.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-d3-tree/-/react-d3-tree-1.12.1.tgz#30ca3ff727bc6c43cf2d0f0e1796c3b0907f6a3f"
|
||||||
|
integrity sha512-4yRCXccmkTbMPHNr2gcVrYwYaYzZOWItqRqxItNFfozpKfaymWvwepC9sIm5RAdWOIGnsoK1SR+X67rB4th2Xg==
|
||||||
|
dependencies:
|
||||||
|
clone "^2.1.1"
|
||||||
|
d3 "3.5.17"
|
||||||
|
deep-equal "^1.0.1"
|
||||||
|
prop-types "^15.5.10"
|
||||||
|
react-transition-group "^1.1.3"
|
||||||
|
uuid "^3.0.1"
|
||||||
|
|
||||||
|
react-transition-group@^1.1.3:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6"
|
||||||
|
integrity sha512-CWaL3laCmgAFdxdKbhhps+c0HRGF4c+hdM4H23+FI1QBNUyx/AMeIJGWorehPNSaKnQNOAxL7PQmqMu78CDj3Q==
|
||||||
|
dependencies:
|
||||||
|
chain-function "^1.0.0"
|
||||||
|
dom-helpers "^3.2.0"
|
||||||
|
loose-envify "^1.3.1"
|
||||||
|
prop-types "^15.5.6"
|
||||||
|
warning "^3.0.0"
|
||||||
|
|
||||||
|
regenerator-runtime@^0.12.0:
|
||||||
|
version "0.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
|
||||||
|
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
|
||||||
|
|
||||||
|
uuid@^3.0.1:
|
||||||
|
version "3.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||||
|
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
||||||
|
|
||||||
|
warning@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
|
||||||
|
integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.0.0"
|
||||||
Reference in New Issue
Block a user