diff --git a/src/components/App/NotFound.js b/src/components/App/NotFound.js index 8a081ae468..94f205ee12 100644 --- a/src/components/App/NotFound.js +++ b/src/components/App/NotFound.js @@ -1,3 +1,5 @@ +// @flow + // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,13 +14,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -import PropTypes from 'prop-types'; import React from 'react'; import { Link } from 'react-router-dom'; import prefixUrl from '../../utils/prefix-url'; -export default function NotFound({ error }) { +type NotFoundProps = { + error: any, +}; + +export default function NotFound({ error }: NotFoundProps) { return (
@@ -38,7 +43,3 @@ export default function NotFound({ error }) {
); } - -NotFound.propTypes = { - error: PropTypes.object, -}; diff --git a/src/components/DependencyGraph/DAG.js b/src/components/DependencyGraph/DAG.js index 2a339f6497..37862cb5c4 100644 --- a/src/components/DependencyGraph/DAG.js +++ b/src/components/DependencyGraph/DAG.js @@ -21,17 +21,20 @@ import dagre from 'dagre'; cydagre(cytoscape, dagre); export default class DAG extends React.Component { - static get propTypes() { - return { - serviceCalls: PropTypes.arrayOf( - PropTypes.shape({ - parent: PropTypes.string, - child: PropTypes.string, - callCount: PropTypes.number, - }) - ), - }; - } + static propTypes = { + serviceCalls: PropTypes.arrayOf( + PropTypes.shape({ + parent: PropTypes.string, + child: PropTypes.string, + callCount: PropTypes.number, + }) + ), + }; + + static defaultProps = { + serviceCalls: [], + }; + componentDidMount() { const { serviceCalls } = this.props; const nodeMap = {}; diff --git a/src/components/DependencyGraph/index.js b/src/components/DependencyGraph/index.js index e7272ae488..b508e5bcf3 100644 --- a/src/components/DependencyGraph/index.js +++ b/src/components/DependencyGraph/index.js @@ -28,16 +28,22 @@ import DependencyForceGraph from './DependencyForceGraph'; import DAG from './DAG'; export default class DependencyGraphPage extends Component { - static get propTypes() { - return { - dependencies: PropTypes.any, - fetchDependencies: PropTypes.func.isRequired, - nodes: nodesPropTypes, - links: linksPropTypes, - loading: PropTypes.bool, - error: PropTypes.object, - }; - } + static propTypes = { + // eslint-disable-next-line react/forbid-prop-types + dependencies: PropTypes.any.isRequired, + fetchDependencies: PropTypes.func.isRequired, + nodes: nodesPropTypes, + links: linksPropTypes, + loading: PropTypes.bool.isRequired, + // eslint-disable-next-line react/forbid-prop-types + error: PropTypes.object, + }; + + static defaultProps = { + nodes: null, + links: null, + error: null, + }; constructor(props) { super(props); diff --git a/src/components/SearchTracePage/SearchDropdownInput.js b/src/components/SearchTracePage/SearchDropdownInput.js index 9bfe3d0c6f..c8880dec0c 100644 --- a/src/components/SearchTracePage/SearchDropdownInput.js +++ b/src/components/SearchTracePage/SearchDropdownInput.js @@ -65,6 +65,7 @@ export default class SearchDropdownInput extends Component { SearchDropdownInput.defaultProps = { maxResults: 250, + items: [], }; SearchDropdownInput.propTypes = { items: PropTypes.arrayOf( @@ -76,6 +77,6 @@ SearchDropdownInput.propTypes = { input: PropTypes.shape({ value: PropTypes.string, onChange: PropTypes.func, - }), + }).isRequired, maxResults: PropTypes.number, }; diff --git a/src/components/SearchTracePage/TraceSearchForm.js b/src/components/SearchTracePage/TraceSearchForm.js index 6bd173e579..322ee5ce52 100644 --- a/src/components/SearchTracePage/TraceSearchForm.js +++ b/src/components/SearchTracePage/TraceSearchForm.js @@ -186,7 +186,7 @@ export function TraceSearchFormComponent(props) { } TraceSearchFormComponent.propTypes = { - handleSubmit: PropTypes.func, + handleSubmit: PropTypes.func.isRequired, submitting: PropTypes.bool, services: PropTypes.arrayOf( PropTypes.shape({ @@ -200,6 +200,9 @@ TraceSearchFormComponent.propTypes = { TraceSearchFormComponent.defaultProps = { services: [], + submitting: false, + selectedService: null, + selectedLookback: null, }; export const searchSideBarFormSelector = formValueSelector('searchSideBar'); diff --git a/src/components/TracePage/ScrollManager.js b/src/components/TracePage/ScrollManager.js index d68db4b02a..df1923d0e5 100644 --- a/src/components/TracePage/ScrollManager.js +++ b/src/components/TracePage/ScrollManager.js @@ -104,6 +104,7 @@ export default class ScrollManager { const isUp = direction < 0; const position = xrs.getRowPosition(rowIndex); if (!position) { + // eslint-disable-next-line no-console console.warn('Invalid row index'); return; } diff --git a/src/components/TracePage/TracePageHeader.js b/src/components/TracePage/TracePageHeader.js index 66e4c8f069..34f70065e7 100644 --- a/src/components/TracePage/TracePageHeader.js +++ b/src/components/TracePage/TracePageHeader.js @@ -1,3 +1,5 @@ +// @flow + // Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,41 +14,65 @@ // See the License for the specific language governing permissions and // limitations under the License. -import PropTypes from 'prop-types'; -import React from 'react'; +import * as React from 'react'; import { Dropdown, Menu } from 'semantic-ui-react'; import { formatDatetime, formatDuration } from '../../utils/date'; +type TracePageHeaderProps = { + traceID: string, + name: String, + slimView: boolean, + onSlimViewClicked: () => void, + updateTextFilter: string => void, + textFilter: ?string, + // these props are used by the `HEADER_ITEMS` + // eslint-disable-next-line react/no-unused-prop-types + timestamp: number, + // eslint-disable-next-line react/no-unused-prop-types + duration: number, + // eslint-disable-next-line react/no-unused-prop-types + numServices: number, + // eslint-disable-next-line react/no-unused-prop-types + maxDepth: number, + // eslint-disable-next-line react/no-unused-prop-types + numSpans: number, +}; + export const HEADER_ITEMS = [ { key: 'timestamp', title: 'Trace Start', - renderer: props => formatDatetime(props.timestamp), + propName: null, + renderer: (props: TracePageHeaderProps) => formatDatetime(props.timestamp), }, { key: 'duration', title: 'Duration', - renderer: props => formatDuration(props.duration), + propName: null, + renderer: (props: TracePageHeaderProps) => formatDuration(props.duration), }, { key: 'service-count', title: 'Services', propName: 'numServices', + renderer: null, }, { key: 'depth', title: 'Depth', propName: 'maxDepth', + renderer: null, }, { key: 'span-count', title: 'Total Spans', propName: 'numSpans', + renderer: null, }, ]; -export default function TracePageHeader(props) { +export default function TracePageHeader(props: TracePageHeaderProps) { const { traceID, name, slimView, onSlimViewClicked, updateTextFilter, textFilter } = props; if (!traceID) { @@ -58,7 +84,7 @@ export default function TracePageHeader(props) {

- + {!slimView && (
- {HEADER_ITEMS.map(({ renderer, propName, title, key }) => ( -
- {title}: - {propName ? props[propName] : renderer(props)} -
- ))} + {HEADER_ITEMS.map(({ renderer, propName, title, key }) => { + let value: ?React.Node; + if (propName) { + value = props[propName]; + } else if (renderer) { + value = renderer(props); + } else { + throw new Error('Invalid HEADER_ITEM configuration'); + } + return ( +
+ {title}: + {value} +
+ ); + })}
)} ); } - -TracePageHeader.propTypes = { - duration: PropTypes.number, // eslint-disable-line react/no-unused-prop-types - maxDepth: PropTypes.number, // eslint-disable-line react/no-unused-prop-types - name: PropTypes.string, - numServices: PropTypes.number, // eslint-disable-line react/no-unused-prop-types - numSpans: PropTypes.number, // eslint-disable-line react/no-unused-prop-types - onSlimViewClicked: PropTypes.func, - slimView: PropTypes.bool, - textFilter: PropTypes.string, - timestamp: PropTypes.number, // eslint-disable-line react/no-unused-prop-types - traceID: PropTypes.string, - updateTextFilter: PropTypes.func.isRequired, -}; diff --git a/src/components/TracePage/TraceTimelineViewer/SpanBar.js b/src/components/TracePage/TraceTimelineViewer/SpanBar.js index aba8e8b6c1..efeb7ebd3a 100644 --- a/src/components/TracePage/TraceTimelineViewer/SpanBar.js +++ b/src/components/TracePage/TraceTimelineViewer/SpanBar.js @@ -43,7 +43,13 @@ function SpanBar(props: SpanBarProps) { const { viewEnd, viewStart, color, label, hintSide, onClick, setLongLabel, setShortLabel, rpc } = props; return ( -
+
- {data.map((row, i) => ( - // `i` is necessary in the key because row.key can repeat - // eslint-disable-next-line react/no-array-index-key - - - - - ))} + {data.map((row, i) => { + const jsonTable = ( + // eslint-disable-next-line react/no-danger +
+ ); + return ( + // `i` is necessary in the key because row.key can repeat + // eslint-disable-next-line react/no-array-index-key +
+ + + + ); + })}
{row.key} -
-
{row.key}{jsonTable}
diff --git a/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.js b/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.js index e928224324..e6ead2bcc6 100644 --- a/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.js +++ b/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.js @@ -65,7 +65,9 @@ export default class SpanDetailRow extends React.PureComponent diff --git a/src/components/TracePage/TraceTimelineViewer/SpanTreeOffset.js b/src/components/TracePage/TraceTimelineViewer/SpanTreeOffset.js index 05017555ea..11a3a5a52a 100644 --- a/src/components/TracePage/TraceTimelineViewer/SpanTreeOffset.js +++ b/src/components/TracePage/TraceTimelineViewer/SpanTreeOffset.js @@ -32,7 +32,7 @@ export default function SpanTreeOffset(props: SpanTreeOffsetProps) { ) : null; return ( - + {icon} diff --git a/src/components/TracePage/TraceTimelineViewer/TimelineRow.js b/src/components/TracePage/TraceTimelineViewer/TimelineRow.js index fb6e265eeb..8fd0aea6d2 100644 --- a/src/components/TracePage/TraceTimelineViewer/TimelineRow.js +++ b/src/components/TracePage/TraceTimelineViewer/TimelineRow.js @@ -19,12 +19,12 @@ import * as React from 'react'; import './TimelineRow.css'; type TimelineRowProps = { - children?: React.Node, + children: React.Node, className: string, }; type TimelineRowCellProps = { - children?: React.Node, + children: React.Node, className: string, width: number, style?: Object, @@ -54,6 +54,6 @@ function TimelineRowCell(props: TimelineRowCellProps) { ); } -TimelineRowCell.defaultProps = { className: '' }; +TimelineRowCell.defaultProps = { className: '', style: {} }; TimelineRow.Cell = TimelineRowCell; diff --git a/src/model/trace-viewer.js b/src/model/trace-viewer.js index 3dec53cf4c..dd0700096f 100644 --- a/src/model/trace-viewer.js +++ b/src/model/trace-viewer.js @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// eslint-disable-next-line import/prefer-default-export export function getTraceName(spans, processes) { const span = spans.find(sp => sp.spanID === sp.traceID) || spans[0]; return span ? `${processes[span.processID].serviceName}: ${span.operationName}` : ''; diff --git a/src/model/transform-trace-data.js b/src/model/transform-trace-data.js index ac248e1008..7744dabd9e 100644 --- a/src/model/transform-trace-data.js +++ b/src/model/transform-trace-data.js @@ -50,8 +50,10 @@ export default function transfromTraceData(data: TraceData & { spans: SpanWithPr // make sure span IDs are unique const idCount = spanIdCounts.get(spanID); if (idCount != null) { + // eslint-disable-next-line no-console console.warn(`Dupe spanID, ${idCount + 1} x ${spanID}`, span, spanMap.get(spanID)); if (_isEqual(span, spanMap.get(spanID))) { + // eslint-disable-next-line no-console console.warn('\t two spans with same ID have `isEqual(...) === true`'); } spanIdCounts.set(spanID, idCount + 1); diff --git a/src/selectors/dependencies.js b/src/selectors/dependencies.js index a6bbdaffb0..71c04ae443 100644 --- a/src/selectors/dependencies.js +++ b/src/selectors/dependencies.js @@ -14,6 +14,7 @@ import { createSelector } from 'reselect'; +// eslint-disable-next-line import/prefer-default-export export const formatDependenciesAsNodesAndLinks = createSelector( ({ dependencies }) => dependencies, dependencies => { diff --git a/src/selectors/trace.js b/src/selectors/trace.js index 44e5d810df..e916d9be53 100644 --- a/src/selectors/trace.js +++ b/src/selectors/trace.js @@ -275,6 +275,7 @@ export const enforceUniqueSpanIds = createSelector( const updatedSpan = { ...span, spanID }; if (spanID !== getSpanId(span)) { + // eslint-disable-next-line no-console console.warn('duplicate spanID in trace replaced', getSpanId(span), 'new:', spanID); } diff --git a/src/utils/number.js b/src/utils/number.js index 6b15b7fea5..d3ca09fa7f 100644 --- a/src/utils/number.js +++ b/src/utils/number.js @@ -26,6 +26,7 @@ * @param {number} precision * @return {number} number at new floating precision */ +// eslint-disable-next-line import/prefer-default-export export function toFloatPrecision(number, precision) { const log10Length = Math.floor(Math.log10(Math.abs(number))) + 1; const targetPrecision = precision + log10Length;