Files
flipper/desktop/plugins/network/ManageMockResponsePanel.tsx
bizzguy 8c3abf7450 Network Plugin - Minor UI fixes (#1864)
Summary:
Made UI fixes to Network Plugin (mostly to Route screens) to continue migration to the new design framework.  This consisted mostly of replacing FlexColumn and FlexRow with Layout.Container and Layout.Horizontal.

Also, contains some cosmetic changes to "Mock Network Response" page.

Here is the screenshot with UI changes:

![image](https://user-images.githubusercontent.com/337874/105937062-6d0e4500-601a-11eb-97ce-d9c4ae0c184f.png)

This was the old screen for comparison:

![image](https://user-images.githubusercontent.com/337874/105937028-5667ee00-601a-11eb-84a9-a2bd4bb78846.png)

## Changelog

Network Plugin - UI changes to continue migration to Sandy design framework

Pull Request resolved: https://github.com/facebook/flipper/pull/1864

Test Plan: Manual testing to ensure that all data still displayed with new UI changes (especially the Data and Headers info in the "Route Info" section)

Reviewed By: passy

Differential Revision: D26125656

Pulled By: mweststrate

fbshipit-source-id: a25104274ed25788e5c0738ac0a9609f2cead751
2021-01-29 09:02:54 -08:00

244 lines
6.3 KiB
TypeScript

/**
* 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 {
Layout,
ManagedTable,
Text,
FlexBox,
FlexRow,
Glyph,
styled,
colors,
Panel,
} from 'flipper';
import React, {useContext, useState, useMemo, useEffect} from 'react';
import {Route, Request, Response} from './types';
import {MockResponseDetails} from './MockResponseDetails';
import {NetworkRouteContext} from './index';
import {RequestId} from './types';
type Props = {
routes: {[id: string]: Route};
highlightedRows: Set<string> | null | undefined;
requests: {[id: string]: Request};
responses: {[id: string]: Response};
};
const ColumnSizes = {route: 'flex'};
const Columns = {route: {value: 'Route', resizable: false}};
const Button = styled(FlexBox)({
color: colors.blackAlpha50,
alignItems: 'center',
padding: 5,
flexShrink: 0,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
});
const TextEllipsis = styled(Text)({
overflowX: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '100%',
lineHeight: '18px',
paddingTop: 4,
display: 'block',
whiteSpace: 'nowrap',
});
const Icon = styled(Glyph)({
marginTop: 5,
marginRight: 8,
});
// return ids that have the same pair of requestUrl and method; this will return only the duplicate
function _duplicateIds(routes: {[id: string]: Route}): Array<RequestId> {
const idSet: {[id: string]: {[method: string]: boolean}} = {};
return Object.entries(routes).reduce((acc: Array<RequestId>, [id, route]) => {
if (idSet.hasOwnProperty(route.requestUrl)) {
if (idSet[route.requestUrl].hasOwnProperty(route.requestMethod)) {
return acc.concat(id);
}
idSet[route.requestUrl] = {
...idSet[route.requestUrl],
[route.requestMethod]: true,
};
return acc;
} else {
idSet[route.requestUrl] = {[route.requestMethod]: true};
return acc;
}
}, []);
}
function _buildRows(
routes: {[id: string]: Route},
duplicatedIds: Array<string>,
handleRemoveId: (id: string) => void,
) {
return Object.entries(routes).map(([id, route]) => ({
columns: {
route: {
value: (
<RouteRow
key={id}
text={route.requestUrl}
showWarning={duplicatedIds.includes(id)}
handleRemoveId={() => handleRemoveId(id)}
/>
),
},
},
key: id,
}));
}
function RouteRow(props: {
text: string;
showWarning: boolean;
handleRemoveId: () => void;
}) {
return (
<FlexRow grow={true}>
<FlexRow onClick={props.handleRemoveId}>
<Icon name="cross-circle" color={colors.red} />
</FlexRow>
<FlexRow grow={true}>
{props.showWarning && (
<Icon name="caution-triangle" color={colors.yellow} />
)}
{props.text.length === 0 ? (
<TextEllipsis style={{color: colors.blackAlpha50}}>
untitled
</TextEllipsis>
) : (
<TextEllipsis>{props.text}</TextEllipsis>
)}
</FlexRow>
</FlexRow>
);
}
function ManagedMockResponseRightPanel(props: {
id: string;
route: Route;
isDuplicated: boolean;
}) {
const {id, route, isDuplicated} = props;
return (
<Panel
grow={true}
collapsable={false}
floating={false}
heading={'Route Info'}>
<MockResponseDetails
key={id}
id={id}
route={route}
isDuplicated={isDuplicated}
/>
</Panel>
);
}
export function ManageMockResponsePanel(props: Props) {
const networkRouteManager = useContext(NetworkRouteContext);
const [selectedId, setSelectedId] = useState<RequestId | null>(null);
useEffect(() => {
setSelectedId((selectedId) => {
const keys = Object.keys(props.routes);
return keys.length === 0
? null
: selectedId === null || !keys.includes(selectedId)
? keys[keys.length - 1]
: selectedId;
});
}, [props.routes]);
const duplicatedIds = useMemo(() => _duplicateIds(props.routes), [
props.routes,
]);
return (
<Layout.Container style={{height: 550}}>
<Layout.Left>
<Layout.Container width={450} pad={10} gap={5}>
<Button
onClick={() => {
networkRouteManager.addRoute();
}}>
<Glyph
name="plus-circle"
size={16}
variant="outline"
color={colors.blackAlpha30}
/>
&nbsp;Add Route
</Button>
<Button
onClick={() => {
networkRouteManager.copyHighlightedCalls(
props.highlightedRows as Set<string>,
props.requests,
props.responses,
);
}}>
<Glyph
name="plus-circle"
size={16}
variant="outline"
color={colors.blackAlpha30}
/>
&nbsp;Copy Highlighted Calls
</Button>
<Panel
grow={true}
collapsable={false}
floating={false}
heading={'Routes'}>
<ManagedTable
hideHeader={true}
multiline={false}
columnSizes={ColumnSizes}
columns={Columns}
rows={_buildRows(props.routes, duplicatedIds, (id) => {
networkRouteManager.removeRoute(id);
setSelectedId(null);
})}
stickyBottom={true}
autoHeight={false}
floating={false}
zebra={false}
onRowHighlighted={(selectedIds) => {
const newSelectedId =
selectedIds.length === 1 ? selectedIds[0] : null;
setSelectedId(newSelectedId);
}}
highlightedRows={new Set(selectedId)}
/>
</Panel>
</Layout.Container>
<Layout.Container>
{selectedId && props.routes.hasOwnProperty(selectedId) && (
<ManagedMockResponseRightPanel
id={selectedId}
route={props.routes[selectedId]}
isDuplicated={duplicatedIds.includes(selectedId)}
/>
)}
</Layout.Container>
</Layout.Left>
</Layout.Container>
);
}