GraphQL UI and Navigation (#335)

* chore(http): check for custom endpoint for caching

Signed-off-by: --global <--global>

* fix(ui) - typo

* fix(migration): template file variable values

* fix(install): minio download path

Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>

* chore(nginx): precedence x-forward-for ip for geo location tagging

Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>

* chore(kafka): change retention to 4 days

Signed-off-by: rjshrjndrn <rjshrjndrn@gmail.com>

* feat(ui) - graphql ui and navigation

Co-authored-by: --global <--global>
Co-authored-by: Mehdi Osman <estradino@users.noreply.github.com>
Co-authored-by: rjshrjndrn <rjshrjndrn@gmail.com>
This commit is contained in:
Shekar Siri 2022-02-16 17:06:08 +01:00 committed by GitHub
parent 4eaee22d30
commit e8a330c053
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 122 additions and 52 deletions

View file

@ -127,10 +127,6 @@ export default class Fetch extends React.PureComponent {
<BottomBlock.Header>
<h4 className="text-lg">Fetch</h4>
<div className="flex items-center">
{/* <div className="flex items-center mr-3 text-sm uppercase">
<div className="p-2 cursor-pointer" onClick={this.goToPrevError}>Prev</div>
<div className="p-2 cursor-pointer" onClick={this.goToNextError}>Next</div>
</div> */}
<Input
className="input-small"
placeholder="Filter"

View file

@ -1,4 +1,4 @@
import { JSONTree } from 'UI'
import { JSONTree, Button } from 'UI'
import cn from 'classnames';
export default class GQLDetails extends React.PureComponent {
@ -7,7 +7,14 @@ export default class GQLDetails extends React.PureComponent {
gql: {
variables,
response,
duration,
operationKind,
operationName,
},
nextClick,
prevClick,
first = false,
last = false,
} = this.props;
let jsonVars = undefined;
@ -19,28 +26,52 @@ export default class GQLDetails extends React.PureComponent {
jsonResponse = JSON.parse(response);
} catch (e) {}
return (
<div className="ph-20" >
<div className="divider"/>
{ variables && variables !== "{}" &&
<div>
<div className="mt-6">
<h5>{ 'Variables'}</h5>
{ jsonVars === undefined
? <div className="ml-3"> { variables } </div>
: <JSONTree src={ jsonVars } />
}
<div className="px-4 pb-16">
<h5 className="mb-2">{ 'Operation Name'}</h5>
<div className={ cn('p-2 bg-gray-lightest rounded color-gray-darkest')}>{ operationName }</div>
<div className="flex items-center mt-4">
<div className="w-4/12">
<div className="font-medium mb-2">Operation Kind</div>
<div>{operationKind}</div>
</div>
<div className="w-4/12">
<div className="font-medium mb-2">Duration</div>
<div>{parseInt(duration)} ms</div>
</div>
</div>
<div className="flex justify-between items-start mt-6">
<h5 className="mt-1 mr-1">{ 'Response' }</h5>
</div>
<div style={{ height: 'calc(100vh - 314px)', overflowY: 'auto' }}>
{ variables && variables !== "{}" &&
<div>
<div className="mt-2">
<h5>{ 'Variables'}</h5>
{ jsonVars === undefined
? <div className="ml-3"> { variables } </div>
: <JSONTree src={ jsonVars } />
}
</div>
<div className="divider"/>
</div>
<div className="divider"/>
</div>
}
<div className="mt-6">
<div className="flex justify-between items-start">
<h5 className="mt-1 mr-1">{ 'Response' }</h5>
</div>
{ jsonResponse === undefined
? <div className="ml-3"> { response } </div>
: <JSONTree src={ jsonResponse } />
}
<div className="mt-3">
{ jsonResponse === undefined
? <div className="ml-3"> { response } </div>
: <JSONTree src={ jsonResponse } />
}
</div>
</div>
<div className="flex justify-between absolute bottom-0 left-0 right-0 p-3 border-t bg-white">
<Button primary plain onClick={prevClick} disabled={first}>
Prev
</Button>
<Button primary plain onClick={nextClick} disabled={last}>
Next
</Button>
</div>
</div>
);

View file

@ -1,8 +1,6 @@
//import cn from 'classnames';
import { Icon, NoContent, Input, SlideModal } from 'UI';
import { Label, Icon, NoContent, Input, SlideModal, CloseButton } from 'UI';
import { getRE } from 'App/utils';
import { connectPlayer } from 'Player';
import Autoscroll from '../Autoscroll';
import { connectPlayer, pause, jump } from 'Player';
import BottomBlock from '../BottomBlock';
import TimeTable from '../TimeTable';
import GQLDetails from './GQLDetails';
@ -10,60 +8,105 @@ import GQLDetails from './GQLDetails';
function renderDefaultStatus() {
return "2xx-3xx";
}
@connectPlayer(state => ({
list: state.graphqlListNow,
livePlay: state.livePlay,
}))
export default class GraphQL extends React.PureComponent {
state = {
filter: "",
filter: "",
filteredList: this.props.list,
current: null,
currentIndex: 0,
showFetchDetails: false,
hasNextError: false,
hasPreviousError: false,
}
onFilterChange = (e, { value }) => this.setState({ filter: value })
setCurrent = (item) => {
this.setState({ current: item });
onFilterChange = (e, { value }) => {
const { list } = this.props;
const filterRE = getRE(value, 'i');
const filtered = list
.filter((r) => filterRE.test(r.name) || filterRE.test(r.url) || filterRE.test(r.method) || filterRE.test(r.status));
this.setState({ filter: value, filteredList: value ? filtered : list, currentIndex: 0 });
}
setCurrent = (item, index) => {
if (!this.props.livePlay) {
pause();
jump(item.time)
}
this.setState({ current: item, currentIndex: index });
}
closeModal = () => this.setState({ current: null, showFetchDetails: false });
static getDerivedStateFromProps(nextProps, prevState) {
const { filteredList } = prevState;
if (nextProps.timelinePointer) {
let activeItem = filteredList.find((r) => r.time >= nextProps.timelinePointer.time);
activeItem = activeItem || filteredList[filteredList.length - 1];
return {
current: activeItem,
currentIndex: filteredList.indexOf(activeItem),
};
}
}
closeModal = () => this.setState({ current: null})
render() {
const { list } = this.props;
const { filter, current } = this.state;
const filterRE = getRE(filter, 'i');
const filtered = list
.filter(({ operationName = "", operationKind = "" }) => filterRE.test(operationName) || filterRE.test(operationKind));
const { current, currentIndex, filteredList } = this.state;
return (
<React.Fragment>
<SlideModal
size="middle"
title={ current && <span><i className="color-gray-medium">{current.operationKind}</i> {current.operationName}</span> }
right
title = {
<div className="flex justify-between">
<h1>GraphQL</h1>
<div className="flex items-center">
<CloseButton onClick={ this.closeModal } size="18" className="ml-2" />
</div>
</div>
}
isDisplayed={ current != null }
content={ current &&
<GQLDetails gql={ current }/>
<GQLDetails
gql={ current }
nextClick={this.nextClickHander}
prevClick={this.prevClickHander}
first={currentIndex === 0}
last={currentIndex === filteredList.length - 1}
/>
}
onClose={ this.closeModal }
/>
<BottomBlock>
<BottomBlock.Header>
<Input
className="input-small"
placeholder="Filter by Name or Type"
icon="search"
iconPosition="left"
name="filter"
onChange={ this.onFilterChange }
/>
<h4 className="text-lg">GraphQL</h4>
<div className="flex items-center">
<Input
className="input-small"
placeholder="Filter by Name or Type"
icon="search"
iconPosition="left"
name="filter"
onChange={ this.onFilterChange }
/>
</div>
</BottomBlock.Header>
<BottomBlock.Content>
<NoContent
size="small"
show={ filtered.length === 0}
show={ filteredList.length === 0}
>
<TimeTable
rows={ filtered }
rows={ filteredList }
onRowClick={ this.setCurrent }
hoverable
navigation
activeIndex={currentIndex}
>
{[
{