ToolJet/frontend/src/Editor/QueryManager/QueryEditors/Stripe.jsx
Arpit 3a62ac9820
[improvement] Query panel redesign (#1947)
* query panel headers styles

* create query button style update

* create query button style update

* create query button style update: mixins

* querypanel header nav-links updated

* querypanel header buttons

* restapi: url hinter styles

* fixes querypane header width, undo prev styles applied

* querypanel header icons margin fix

* restapi: header tab

* restapi: params tab

* restapi: body tab

* base url style fixed

* added alert component to @/_ui

* adds margin top to query-panel tabs

* bumped font weight of preview

* on hover query style updated

* selected query style update and along with dark themed

* adds new searchbox component, added search queries

* fixes query panel query lists icons margin

* query selected hover bg

* back icon should not be render if callback is a function

* airtable: queries redesigned

* stripe: queries redesigned

* fixed query-pane header responsiveness

* fixes tab title typo

* undp/redo select datasource only when mode='create'

* removes comments

* refactor restapi url codehinter styles

* fixes white spaces in query pane and query pane header

* minor updates for restapi query options styles

* removes tool-tip for lens svg icon for search: query-pane header

* adds button loading spinner with primary color

* fixes hover bg color for queries

* update: query hover bg color to lighter tint

* update query list icons: trash and play svgs

* adds icons to the selection component

* fixes tabs alignments restapi

* fixes codehonter text margin: restapi url

* fixes advanced-options-container margintop

* new UI query: dynamodb

* new UI query: elasticsearch

* new UI query: firestore

* new UI query: mongodb

* new UI query: mysql

* new UI query: psql

* new UI query: typesenseapi

* new UI query: gsheet

* new UI query: sendgrid

* new UI query: twillio

* new UI query: gcs

* new UI query: minio

* new UI query: aws

* update query bg color and hover bg color

* fixes run query icon for dark theme

* fixes input query title text alignment

* update query header title

* adds search queries placeholder and add icon when search box is displayed

* updated No results query text

* undo/redo rest-api tabs: fixes whote spaces

* undo/redo: rest-api tabs conde hinter placeholder paddinleft

* adding new queries when search box component is mounted:fix

* fixes creating a new query after filtering queries

* fixes dark theme for select search components

* reverts query pane header search box with add icon

* fixes input left margin

* fixes bottom padding rest api tabs

* fixes toggle button:not selected in dark theme

* fixes typos

* fixes preview button spinner size

* undo/redo: query-trash-icon.svg for queries and trash.svg for components

* query icons badge bg update[options]

* icon badge fix

* move static styles to theme.scss

* restapi: url field height increment

* fixes query name when adding a new query with filtered querylist

* fixes alignment issues of the query header icon

* revert back to 32px code hinter height

* adds apdding to code mirror line

* updates to react-select

* remove component unmounts and mounts side effect
2022-02-02 22:29:57 +05:30

321 lines
12 KiB
JavaScript

import React from 'react';
import 'codemirror/theme/duotone-light.css';
import DOMPurify from 'dompurify';
import SelectSearch, { fuzzySearch } from 'react-select-search';
import { openapiService } from '@/_services';
import { CodeHinter } from '../../CodeBuilder/CodeHinter';
const operationColorMapping = {
get: 'azure',
post: 'green',
delete: 'red',
put: 'yellow',
};
class Stripe extends React.Component {
constructor(props) {
super(props);
this.state = {
loadingSpec: true,
};
}
componentDidMount() {
this.setState({
loadingSpec: true,
options: {
params: {
path: {},
query: {},
request: {},
},
},
});
this.fetchOpenApiSpec();
}
fetchOpenApiSpec = () => {
this.setState({ loadingSpec: true });
openapiService
.fetchSpecFromUrl('https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json')
.then((response) => {
response.text().then((text) => {
const data = JSON.parse(text);
this.setState({ specJson: data, loadingSpec: false });
});
});
};
changeOption(option, value) {
this.setState({
options: {
...this.state.options,
[option]: value,
},
});
}
changeOperation = (value) => {
const operation = value.split(',')[0];
const path = value.split(',')[1];
this.setState(
{
selectedOperation: this.state.specJson.paths[path][operation],
options: {
...this.state.options,
path,
operation,
},
},
() => {
this.props.optionsChanged(this.state.options);
}
);
};
changeParam = (paramType, paramName, value) => {
const options = this.state.options;
const newOptions = {
...options,
params: {
...options.params,
[paramType]: {
...options.params[paramType],
[paramName]: value,
},
},
};
this.setState({
options: newOptions,
});
this.props.optionsChanged(newOptions);
};
renderOperationOption = (props, option, snapshot, className) => {
return (
<button {...props} className={className} type="button">
<div className="row">
<div className="col-md-1">
<span className={`badge bg-${operationColorMapping[option.operation]}`}>{option.operation}</span>
</div>
<div className="col-md-8">
<span className="text-muted mx-2">{option.name}</span>
</div>
</div>
</button>
);
};
computeOperationSelectionOptions = (paths) => {
let options = [];
for (const path of Object.keys(paths)) {
for (const operation of Object.keys(paths[path])) {
options.push({
value: `${operation},${path}`,
name: path,
operation: operation,
});
}
}
return options;
};
render() {
const { options, selectedOperation, specJson, loadingSpec } = this.state;
let pathParams = [];
let queryParams = [];
let requestBody = [];
if (selectedOperation) {
if (selectedOperation.parameters) {
pathParams = selectedOperation.parameters.filter((param) => param.in === 'path');
queryParams = selectedOperation.parameters.filter((param) => param.in === 'query');
}
if (selectedOperation.requestBody) {
const requestType = Object.keys(selectedOperation.requestBody.content)[0];
requestBody = selectedOperation.requestBody.content[requestType];
}
}
return (
<div>
{loadingSpec && (
<div className="p-3">
<div className="spinner-border spinner-border-sm text-azure mx-2" role="status"></div>
Please wait whle we load the OpenAPI specification for Stripe.
</div>
)}
{options && !loadingSpec && (
<div className="mb-3 mt-2">
<div className="row g-2">
<div className="col-12">
<label className="form-label pt-2">Operation</label>
</div>
<div className="col stripe-operation-options" style={{ width: '90px', marginTop: 0 }}>
<SelectSearch
options={this.computeOperationSelectionOptions(specJson.paths)}
value="sv"
search={true}
onChange={(value) => this.changeOperation(value)}
filterOptions={fuzzySearch}
renderOption={this.renderOperationOption}
placeholder="Select an operation"
/>
{selectedOperation && (
<small
style={{ margintTop: '10px' }}
className="my-2"
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(selectedOperation.description) }}
/>
)}
</div>
</div>
{selectedOperation && (
<div className="row mt-2">
{pathParams.length > 0 && (
<div className="mt-2">
<h5 className="text-muted">PATH</h5>
{pathParams.map((param) => (
<div className="row input-group my-1" key={param.name}>
<div className="col-4 field field-width-268">
<input type="text" value={param.name} className="form-control" placeholder="key" />
</div>
<div className="col-6 field" style={{ width: '300px' }}>
<CodeHinter
currentState={this.props.currentState}
initialValue={this.state.options.params.path[param.name]}
mode="text"
placeholder={'value'}
theme={this.props.darkMode ? 'monokai' : 'duotone-light'}
lineNumbers={false}
onChange={(value) => this.changeParam('path', param.name, value)}
height={'36px'}
width="268px"
/>
</div>
<span className="btn-sm col-2 mt-2" role="button">
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.99931 6.97508L11.0242 12.0014L12 11.027L6.9737 6.00069L12 0.975767L11.0256 0L5.99931 5.0263L0.974388 0L0 0.975767L5.02492 6.00069L0 11.0256L0.974388 12.0014L5.99931 6.97508Z"
fill="#8092AC"
/>
</svg>
</span>
</div>
))}
</div>
)}
{queryParams.length > 0 && (
<div className="mt-2">
<h5 className="text-muted">QUERY</h5>
{queryParams.map((param) => (
<div className="row input-group my-1" key={param.name}>
<div className="col-4 field field-width-268">
<input type="text" value={param.name} className="form-control" placeholder="key" disabled />
</div>
<div className="col-6 field" style={{ width: '300px' }}>
<CodeHinter
currentState={this.props.currentState}
initialValue={this.state.options.params.query[param.name]}
mode="text"
placeholder={'value'}
theme={this.props.darkMode ? 'monokai' : 'duotone-light'}
lineNumbers={false}
onChange={(value) => this.changeParam('query', param.name, value)}
height={'36px'}
width="268px"
/>
</div>
<span className="btn-sm col-2 mt-2" role="button">
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.99931 6.97508L11.0242 12.0014L12 11.027L6.9737 6.00069L12 0.975767L11.0256 0L5.99931 5.0263L0.974388 0L0 0.975767L5.02492 6.00069L0 11.0256L0.974388 12.0014L5.99931 6.97508Z"
fill="#8092AC"
/>
</svg>
</span>
</div>
))}
</div>
)}
{requestBody.schema.properties && (
<div className="mt-2">
<h5 className="text-muted">REQUEST BODY</h5>
{Object.keys(requestBody.schema.properties).map((param) => (
<div className="row input-group my-1" key={param.name}>
<div className="col-4 field field-width-268">
<input type="text" value={param} className="form-control" placeholder="key" disabled />
</div>
<div className="col-6 field" style={{ width: '300px' }}>
<CodeHinter
currentState={this.props.currentState}
initialValue={this.state.options.params.request[param.name]}
mode="text"
placeholder={'value'}
theme={this.props.darkMode ? 'monokai' : 'duotone-light'}
lineNumbers={false}
onChange={(value) => this.changeParam('request', param.name, value)}
height={'36px'}
width="268px"
/>
</div>
<span className="btn-sm col-2 mt-2" role="button">
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.99931 6.97508L11.0242 12.0014L12 11.027L6.9737 6.00069L12 0.975767L11.0256 0L5.99931 5.0263L0.974388 0L0 0.975767L5.02492 6.00069L0 11.0256L0.974388 12.0014L5.99931 6.97508Z"
fill="#8092AC"
/>
</svg>
</span>
</div>
))}
</div>
)}
</div>
)}
</div>
)}
</div>
);
}
}
export { Stripe };