Skip to content

Commit

Permalink
Feature: Added a feature to show raw query responses (ToolJet#2562)
Browse files Browse the repository at this point in the history
* Implemented json/raw preview modes

* Added dark theme

* Changed some bg colors

* made text copiable

Co-authored-by: Sherfin Shamsudeen <sherfin94@gmail.com>
  • Loading branch information
shah21 and sherfin94 authored Mar 31, 2022
1 parent 4429cde commit a56c272
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 43 deletions.
71 changes: 71 additions & 0 deletions frontend/src/Editor/QueryManager/Preview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useEffect } from 'react';
import { JSONTree } from 'react-json-tree';
import { Tab, ListGroup, Row } from 'react-bootstrap';

const Preview = ({ previewPanelRef, previewLoading, queryPreviewData, theme, darkMode }) => {
const [key, setKey] = React.useState('raw');
const [isJson, setIsJson] = React.useState(false);
const tabs = ['Json', 'Raw'];

useEffect(() => {
if (typeof queryPreviewData === 'object') {
setKey('json');
} else {
setKey('raw');
}
setIsJson(typeof queryPreviewData === 'object');
}, [queryPreviewData]);

const renderRawData = () => {
if (queryPreviewData) {
return isJson ? JSON.stringify(queryPreviewData).toString() : queryPreviewData.toString();
}
return '';
};

return (
<div>
<div className="row preview-header border-top" ref={previewPanelRef}>
<div className="py-2" style={{ fontWeight: 600 }}>
Preview
</div>
</div>
<Tab.Container activeKey={key} onSelect={(k) => setKey(k)} defaultActiveKey="raw">
<Row>
<div className="keys">
<ListGroup className={`query-preview-list-group ${darkMode ? 'dark' : ''}`} variant="flush">
{tabs.map((tab) => (
<ListGroup.Item key={tab} eventKey={tab.toLowerCase()}>
<span>{tab}</span>
</ListGroup.Item>
))}
</ListGroup>
</div>
{previewLoading && (
<center>
<div className="spinner-border text-azure mt-5" role="status"></div>
</center>
)}
<div className="col" style={{ userSelect: 'text' }}>
<Tab.Content>
<Tab.Pane eventKey="json" transition={false}>
<div className="mb-3 mt-2">
{previewLoading === false && isJson && (
<div>
<JSONTree theme={theme} data={queryPreviewData} invertTheme={!darkMode} collectionLimit={100} />
</div>
)}
</div>
</Tab.Pane>
<Tab.Pane eventKey="raw" transition={false}>
<div className={`mb-3 mt-2 raw-container ${darkMode ? 'dark' : ''}`}>{renderRawData()}</div>
</Tab.Pane>
</Tab.Content>
</div>
</Row>
</Tab.Container>
</div>
);
};

export default Preview;
41 changes: 9 additions & 32 deletions frontend/src/Editor/QueryManager/QueryManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { previewQuery } from '@/_helpers/appUtils';
import { EventManager } from '../Inspector/EventManager';
import { CodeHinter } from '../CodeBuilder/CodeHinter';
import { DataSourceTypes } from '../DataSourceManager/SourceComponents';
import RunjsIcon from '../Icons/runjs.svg';
import Preview from './Preview';
import DataSourceLister from './DataSourceLister';
import { JSONTree } from 'react-json-tree';
import { allSvgs } from '@tooljet/plugins/client';
import RunjsIcon from '../Icons/runjs.svg';

const queryNameRegex = new RegExp('^[A-Za-z0-9_-]*$');

Expand Down Expand Up @@ -123,11 +123,6 @@ let QueryManager = class QueryManager extends React.Component {
this.setStateFromProps(this.props);
}

isJson = (maybeJson) => {
if (typeof maybeJson === 'object') return true;
return false;
};

handleBackButton = () => {
this.setState({
isSourceSelected: true,
Expand Down Expand Up @@ -483,31 +478,13 @@ let QueryManager = class QueryManager extends React.Component {
</div>
</div>
)}
<div className="row preview-header border-top" ref={this.previewPanelRef}>
<div className="py-2" style={{ fontWeight: 600 }}>
Preview
</div>
</div>
<div className="mb-3 mt-2">
{previewLoading && (
<center>
<div className="spinner-border text-azure mt-5" role="status"></div>
</center>
)}
{previewLoading === false &&
(this.isJson(queryPreviewData) ? (
<div>
<JSONTree
theme={this.state.theme}
data={queryPreviewData}
invertTheme={!this.props.darkMode}
collectionLimit={100}
/>
</div>
) : (
<div>{queryPreviewData}</div>
))}
</div>
<Preview
previewPanelRef={this.previewPanelRef}
previewLoading={previewLoading}
queryPreviewData={queryPreviewData}
theme={this.state.theme}
darkMode={this.props.darkMode}
/>
</div>
)}
</div>
Expand Down
65 changes: 56 additions & 9 deletions frontend/src/_styles/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4441,6 +4441,62 @@ input[type="text"] {
}
}

.query-preview-list-group {
width: 100%;
display: flex;
flex-direction: row;
gap: 5px;
margin-top: 10px;
.list-group-item {
border: none !important;
cursor: pointer;
font-weight: 600;
font-size: 12px;
padding: 5px 10px !important;
color: #737373;
border-radius: 5px;

span {
display: flex;
justify-content: left;
}

&:hover {
color: #000;
}
}

.list-group-item + .list-group-item.active {
margin-top: 0;
}

.list-group-item.active {
background-color: #f5f7f9 !important;
color: $black;
z-index: inherit !important;
}
}

.query-preview-list-group.dark {
.list-group-item {
color: $disabled !important;

&:hover {
color: #ffffff !important;
}
}
.list-group-item.active {
color: $white !important;
background-color: #333c48 !important;
}
}

.raw-container.dark {
background: #272822;
padding: 5px;
}


// **Alert component**
.alert-component {
border: 1px solid rgba(101, 109, 119, 0.16) !important;
Expand Down Expand Up @@ -4631,19 +4687,10 @@ div#driver-page-overlay {
color: $light-gray;
}

.multi-select {
div::-webkit-scrollbar {
display: none; /* for Chrome, Safari, and Opera */
}
}

#transformation-popover-container {
margin-left: 80px !important;
margin-bottom: -2px !important;
// top: -10px !important;
// left: 100px !important;
// background-color: #0565ff;
}
.rmsc .dropdown-heading {
height: 25px;
}
12 changes: 10 additions & 2 deletions plugins/packages/restapi/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ export default class RestapiQueryService implements QueryService {
return Object.fromEntries(urlParams);
}

isJson(str: string) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}

async run(sourceOptions: any, queryOptions: any, dataSourceId: string): Promise<RestAPIResult> {
/* REST API queries can be adhoc or associated with a REST API datasource */
const hasDataSource = dataSourceId !== undefined;
Expand Down Expand Up @@ -121,8 +130,7 @@ export default class RestapiQueryService implements QueryService {
},
json,
});

result = JSON.parse(response.body);
result = this.isJson(response.body) ? JSON.parse(response.body) : response.body;
requestObject = {
requestUrl: response.request.requestUrl,
method: response.request.options.method,
Expand Down

0 comments on commit a56c272

Please sign in to comment.