desktop/plugins/public/network/request-mocking/MockResponseDetails.tsx (202 lines of code) (raw):

/** * Copyright (c) Meta Platforms, Inc. and 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 React, {useContext, useState} from 'react'; import { NetworkRouteContext, NetworkRouteManager, Route, } from './NetworkRouteManager'; import {RequestId} from '../types'; import {Button, Input, Select} from 'antd'; import {Layout, produce, Tabs, Tab, theme} from 'flipper-plugin'; import {CloseCircleOutlined, WarningOutlined} from '@ant-design/icons'; type Props = { id: RequestId; route: Route; isDuplicated: boolean; }; function HeaderInput(props: { initialValue: string; onUpdate: (newValue: string) => void; style?: React.CSSProperties; }) { const [value, setValue] = useState(props.initialValue); return ( <Input type="text" placeholder="Name" value={value} onChange={(event) => { setValue(event.target.value); props.onUpdate(event.target.value); }} style={props.style} /> ); } function ResponseHeaders({ routeId, route, networkRouteManager, }: { routeId: string; route: Route; networkRouteManager: NetworkRouteManager; }) { return ( <Layout.Container gap style={{paddingRight: theme.space.small}}> {Object.entries(route.responseHeaders).map(([id, header]) => ( <Layout.Horizontal center gap key={id}> <HeaderInput initialValue={header.key} onUpdate={(newValue: string) => { const newHeaders = produce( route.responseHeaders, (draftHeaders) => { draftHeaders[id].key = newValue; }, ); networkRouteManager.modifyRoute(routeId, { responseHeaders: newHeaders, }); }} style={{width: 300}} /> <HeaderInput initialValue={header.value} onUpdate={(newValue: string) => { const newHeaders = produce( route.responseHeaders, (draftHeaders) => { draftHeaders[id].value = newValue; }, ); networkRouteManager.modifyRoute(routeId, { responseHeaders: newHeaders, }); }} /> <Layout.Container onClick={() => { const newHeaders = produce( route.responseHeaders, (draftHeaders) => { delete draftHeaders[id]; }, ); networkRouteManager.modifyRoute(routeId, { responseHeaders: newHeaders, }); }}> <CloseCircleOutlined /> </Layout.Container> </Layout.Horizontal> ))} </Layout.Container> ); } const httpMethods = [ 'GET', 'POST', 'PATCH', 'HEAD', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'CONNECT', ].map((v) => ({value: v, label: v})); export function MockResponseDetails({id, route, isDuplicated}: Props) { const networkRouteManager = useContext(NetworkRouteContext); const [nextHeaderId, setNextHeaderId] = useState(0); const {requestUrl, requestMethod, responseData, responseStatus} = route; let formattedResponse = ''; try { formattedResponse = JSON.stringify(JSON.parse(responseData), null, 2); } catch (e) { formattedResponse = responseData; } return ( <Layout.Container gap> <Layout.Horizontal gap> <Select value={requestMethod} options={httpMethods} onChange={(text) => networkRouteManager.modifyRoute(id, {requestMethod: text}) } /> <Input type="text" placeholder="URL" value={requestUrl} onChange={(event) => networkRouteManager.modifyRoute(id, { requestUrl: event.target.value, }) } style={{flex: 1}} /> <Input type="text" placeholder="STATUS" value={responseStatus} onChange={(event) => networkRouteManager.modifyRoute(id, { responseStatus: event.target.value, }) } style={{width: 100}} /> </Layout.Horizontal> {isDuplicated && ( <Layout.Horizontal gap> <WarningOutlined /> Route is duplicated (Same URL and Method) </Layout.Horizontal> )} <Layout.Container height={500}> <Tabs grow> <Tab tab={'Data'}> <Input.TextArea wrap="soft" autoComplete="off" spellCheck={false} value={formattedResponse} onChange={(event) => networkRouteManager.modifyRoute(id, { responseData: event.target.value, }) } style={{flex: 1}} /> </Tab> <Tab tab={'Headers'}> <Layout.Top gap> <Layout.Horizontal> <Button onClick={() => { const newHeaders = { ...route.responseHeaders, [nextHeaderId.toString()]: {key: '', value: ''}, }; setNextHeaderId(nextHeaderId + 1); networkRouteManager.modifyRoute(id, { responseHeaders: newHeaders, }); }}> Add Header </Button> </Layout.Horizontal> <Layout.ScrollContainer> <ResponseHeaders routeId={id} route={route} networkRouteManager={networkRouteManager} /> </Layout.ScrollContainer> </Layout.Top> </Tab> </Tabs> </Layout.Container> </Layout.Container> ); }