#133: Added first part of example and body parser
This commit is contained in:
@@ -845,7 +845,7 @@ const AngularWorkflow = (props) => {
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((responseJson) => {
|
||||
.then((responseJson) => {
|
||||
// FIXME - handle versions on left bar
|
||||
//handleAppVersioning(responseJson)
|
||||
//var tmpapps = []
|
||||
@@ -2872,8 +2872,64 @@ const AngularWorkflow = (props) => {
|
||||
placeholder = data.example
|
||||
}
|
||||
|
||||
var disabled = false
|
||||
var rows = "5"
|
||||
var openApiHelperText = "This is an OpenAPI specific field"
|
||||
if (selectedApp.generated && selectedApp.activated && data.name === "body") {
|
||||
const regex = /\${(\w+)}/g
|
||||
const found = placeholder.match(regex)
|
||||
console.log("THERE MAY BE THINGS INSIDE THE BODY, NO: ", found)
|
||||
if (found === null) {
|
||||
//setExtraBodyFields([])
|
||||
} else {
|
||||
rows = "1"
|
||||
disabled = true
|
||||
openApiHelperText = "OpenAPI spec: fill the following fields."
|
||||
console.log("SHOULD ADD TO selectedActionParameters!: ", found, selectedActionParameters)
|
||||
var changed = false
|
||||
for (var specKey in found) {
|
||||
const tmpitem = found[specKey]
|
||||
var skip = false
|
||||
for (var innerkey in selectedActionParameters) {
|
||||
if (selectedActionParameters[innerkey].name === tmpitem) {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
console.log("SKIPPING ", tmpitem)
|
||||
continue
|
||||
}
|
||||
|
||||
changed = true
|
||||
selectedActionParameters.push({
|
||||
action_field: "",
|
||||
configuration: false,
|
||||
description: "Generated by OpenAPI body example",
|
||||
example: "",
|
||||
id: "",
|
||||
multiline: false,
|
||||
name: tmpitem,
|
||||
options: null,
|
||||
required: false,
|
||||
schema: {type: "string"},
|
||||
skip_multicheck: false,
|
||||
tags: null,
|
||||
value: "",
|
||||
variant: "STATIC_VALUE",
|
||||
})
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
setSelectedActionParameters(selectedActionParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var datafield =
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
style={{backgroundColor: inputColor, borderRadius: borderRadius,}}
|
||||
InputProps={{
|
||||
style:{
|
||||
@@ -2901,7 +2957,7 @@ const AngularWorkflow = (props) => {
|
||||
}}
|
||||
fullWidth
|
||||
multiline={multiline}
|
||||
rows="5"
|
||||
rows={rows}
|
||||
color="primary"
|
||||
defaultValue={data.value}
|
||||
type={placeholder.includes("***") ? "password" : "text"}
|
||||
@@ -2909,6 +2965,13 @@ const AngularWorkflow = (props) => {
|
||||
onChange={(event) => {
|
||||
changeActionParameter(event, count)
|
||||
}}
|
||||
helperText={selectedApp.generated && selectedApp.activated && data.name === "body" ?
|
||||
<span style={{color:"white", marginBottom: 5,}}>
|
||||
{openApiHelperText}
|
||||
</span>
|
||||
:
|
||||
null
|
||||
}
|
||||
onBlur={(event) => {
|
||||
// Super basic check
|
||||
//if (event.target.value.startsWith("{")) {
|
||||
@@ -3303,7 +3366,7 @@ const AngularWorkflow = (props) => {
|
||||
<div style={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10}}/>
|
||||
}
|
||||
<div style={{flex: "10"}}>
|
||||
<b>{data.name} </b>
|
||||
<b>{data.name.charAt(0).toUpperCase()+data.name.substring(1)} </b>
|
||||
</div>
|
||||
|
||||
{selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0 ? null :
|
||||
@@ -3685,7 +3748,7 @@ const AngularWorkflow = (props) => {
|
||||
{selectedAction.description}
|
||||
</div> : null}
|
||||
<div style={{marginTop: "10px", borderColor: "white", borderWidth: "2px", marginBottom: 200}}>
|
||||
<AppActionArguments key={selectedAction.id} selectedAction={selectedAction} />
|
||||
<AppActionArguments key={selectedAction.id} selectedAction={selectedAction} />
|
||||
|
||||
</div>
|
||||
<div style={{}}>
|
||||
@@ -6253,6 +6316,11 @@ const AngularWorkflow = (props) => {
|
||||
getAppAuthentication()
|
||||
setUpdate(authenticationOption.id)
|
||||
|
||||
/*
|
||||
{selectedAction.authentication.map(data => (
|
||||
<MenuItem key={data.id} style={{backgroundColor: inputColor, color: "white"}} value={data}>
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,6 +4,7 @@ import {BrowserView, MobileView} from "react-device-detect";
|
||||
|
||||
import {Link} from 'react-router-dom';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
@@ -218,6 +219,7 @@ const AppCreator = (props) => {
|
||||
const [actions, setActions] = useState([])
|
||||
const [errorCode, setErrorCode] = useState("")
|
||||
const [appBuilding, setAppBuilding] = useState(false)
|
||||
const [extraBodyFields, setExtraBodyFields] = useState([])
|
||||
|
||||
//const [actions, setActions] = useState([{
|
||||
// "name": "Get workflows",
|
||||
@@ -253,6 +255,7 @@ const AppCreator = (props) => {
|
||||
"queries": [],
|
||||
"body": "",
|
||||
"errors": [],
|
||||
"example_response": "",
|
||||
"method": actionNonBodyRequest[0],
|
||||
});
|
||||
|
||||
@@ -262,7 +265,7 @@ const AppCreator = (props) => {
|
||||
if (firstrequest) {
|
||||
setFirstrequest(false)
|
||||
if (window.location.pathname.includes("apps/edit")) {
|
||||
setIsEditing(true)
|
||||
setIsEditing(true)
|
||||
handleEditApp()
|
||||
} else {
|
||||
checkQuery()
|
||||
@@ -433,6 +436,22 @@ const AppCreator = (props) => {
|
||||
"paths": [],
|
||||
"body": "",
|
||||
"errors": [],
|
||||
"example_response": "",
|
||||
}
|
||||
|
||||
// HAHAHA wtf is this.
|
||||
if (methodvalue.responses !== undefined) {
|
||||
if (methodvalue.responses.default !== undefined) {
|
||||
if (methodvalue.responses.default.content !== undefined) {
|
||||
if (methodvalue.responses.default.content["text/plain"] !== undefined) {
|
||||
if (methodvalue.responses.default.content["text/plain"]["schema"] !== undefined) {
|
||||
if (methodvalue.responses.default.content["text/plain"]["schema"]["example"] !== undefined) {
|
||||
newaction.example_response = methodvalue.responses.default.content["text/plain"]["schema"]["example"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var key in methodvalue.parameters) {
|
||||
@@ -469,6 +488,7 @@ const AppCreator = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (newaction.name === "" || newaction.name === undefined) {
|
||||
// Find a unique part of the string
|
||||
// FIXME: Looks for length between /, find the one where they differ
|
||||
@@ -668,7 +688,14 @@ const AppCreator = (props) => {
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": "default",
|
||||
"schema": {}
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"example": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
"summary": item.name,
|
||||
@@ -679,6 +706,35 @@ const AppCreator = (props) => {
|
||||
|
||||
//console.log("ACTION: ", item)
|
||||
|
||||
if (item.example_response !== undefined && item.example_response.length > 0) {
|
||||
// FIXME: Shallow copy of the string
|
||||
var showResult = Object.assign("", item.example_response).trim()
|
||||
showResult = showResult.split(" None").join(" \"None\"")
|
||||
showResult = showResult.split("\'").join("\"")
|
||||
showResult = showResult.split(" False").join(" false")
|
||||
showResult = showResult.split(" True").join(" true")
|
||||
|
||||
var jsonvalid = true
|
||||
try {
|
||||
const tmp = String(JSON.parse(showResult))
|
||||
if (!showResult.includes("{") && !showResult.includes("[")) {
|
||||
jsonvalid = false
|
||||
}
|
||||
} catch (e) {
|
||||
jsonvalid = false
|
||||
}
|
||||
|
||||
data.paths[item.url][item.method.toLowerCase()].responses["default"]["content"]["text/plain"].schema.type = "string"
|
||||
if (jsonvalid) {
|
||||
// FIXME: Add a JSON parser here - don't run it as a string.
|
||||
data.paths[item.url][item.method.toLowerCase()].responses["default"]["content"]["text/plain"].schema.example = showResult
|
||||
|
||||
} else {
|
||||
data.paths[item.url][item.method.toLowerCase()].responses["default"]["content"]["text/plain"].schema.example = item.example_response
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (item.queries.length > 0) {
|
||||
for (var querykey in item.queries) {
|
||||
const queryitem = item.queries[querykey]
|
||||
@@ -761,7 +817,7 @@ const AppCreator = (props) => {
|
||||
"type": "string",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// FIXME - add application/json if JSON example?
|
||||
data.paths[item.url][item.method.toLowerCase()]["requestBody"] = {
|
||||
"description": "Generated by Shuffler.io",
|
||||
@@ -773,6 +829,18 @@ const AppCreator = (props) => {
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
data.paths[item.url][item.method.toLowerCase()]["requestBody"] = {
|
||||
"description": "Generated by Shuffler.io",
|
||||
"required": required,
|
||||
"content": {
|
||||
"example": {
|
||||
"example": item.body,
|
||||
},
|
||||
},
|
||||
}
|
||||
*/
|
||||
|
||||
data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem)
|
||||
}
|
||||
|
||||
@@ -782,7 +850,6 @@ const AppCreator = (props) => {
|
||||
const headersSplit = item.headers.split("\n")
|
||||
for (var key in headersSplit) {
|
||||
const header = headersSplit[key]
|
||||
console.log("HEADER: ", header)
|
||||
var key = ""
|
||||
var value = ""
|
||||
if (header.length > 0 && header.includes("= ")) {
|
||||
@@ -1137,12 +1204,15 @@ const AppCreator = (props) => {
|
||||
setUrlPathQueries(data.queries)
|
||||
setUrlPath(data.url)
|
||||
setActionsModalOpen(true)
|
||||
|
||||
if (data["body"] !== undefined && data["body"] !== null && data["body"].length > 0) {
|
||||
findBodyParams(data["body"])
|
||||
}
|
||||
}}>
|
||||
<div style={{display: "flex"}}>
|
||||
<Chip
|
||||
style={{backgroundColor: bgColor, color: "white", borderRadius: 5, minWidth: 80, marginRight: 10, marginTop: 2, cursor: "pointer", fontSize: 14,}}
|
||||
label={data.method}
|
||||
variant="contained"
|
||||
/>
|
||||
<span style={{fontSize: 16, marginTop: "auto", marginBottom: "auto",}}>
|
||||
{url} - {data.name}
|
||||
@@ -1177,24 +1247,52 @@ const AppCreator = (props) => {
|
||||
const setActionField = (field, value) => {
|
||||
currentAction[field] = value
|
||||
setCurrentAction(currentAction)
|
||||
|
||||
//setUrlPathQueries(currentAction.queries)
|
||||
}
|
||||
|
||||
const findBodyParams = (body) => {
|
||||
const regex = /\${(\w+)}/g
|
||||
const found = body.match(regex)
|
||||
console.log("FOUND: ", found)
|
||||
if (found === null) {
|
||||
setExtraBodyFields([])
|
||||
} else {
|
||||
setExtraBodyFields(found)
|
||||
}
|
||||
}
|
||||
|
||||
const bodyInfo = actionBodyRequest.includes(currentActionMethod) ?
|
||||
<div>
|
||||
Body - used as example in action argument
|
||||
<div style={{marginTop: 10}}>
|
||||
<b>Request Body</b>: {extraBodyFields.length > 0 ?
|
||||
<Typography style={{display: "inline-block"}}>
|
||||
Variables: {extraBodyFields.join(", ")}
|
||||
</Typography>
|
||||
:
|
||||
<Typography style={{display: "inline-block"}}>
|
||||
{`Add variables with \$\{ variable_name }`}
|
||||
</Typography>
|
||||
}
|
||||
<TextField
|
||||
required
|
||||
style={{flex: "1", marginRight: "15px", backgroundColor: inputColor}}
|
||||
fullWidth={true}
|
||||
placeholder={'{\n\t"username": "testing@test.com"\n\t"name": "test testington"\n}'}
|
||||
placeholder={'{\n\t"username": "${username}",\n\t"apikey": "${apikey}",\n\t"search": "1.2.3.5"}'}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
multiline
|
||||
rows="5"
|
||||
defaultValue={currentAction["body"]}
|
||||
onChange={e => setActionField("body", e.target.value)}
|
||||
onChange={e => {
|
||||
setActionField("body", e.target.value)
|
||||
findBodyParams(e.target.value)
|
||||
}}
|
||||
key={currentAction}
|
||||
helperText={
|
||||
<span style={{color:"white", marginBottom: "2px",}}>
|
||||
Shows an example body to the user. ${} creates variables.
|
||||
</span>
|
||||
}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
@@ -1205,9 +1303,40 @@ const AppCreator = (props) => {
|
||||
}}
|
||||
/>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
|
||||
const exampleResponse =
|
||||
<div style={{}}>
|
||||
<b>Example success response</b>
|
||||
<TextField
|
||||
required
|
||||
style={{flex: "1", marginRight: "15px", backgroundColor: inputColor}}
|
||||
fullWidth={true}
|
||||
placeholder={'{\n\t"email": "testing@test.com",\n\t"firstname": "testing"\n}'}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
multiline
|
||||
rows="2"
|
||||
defaultValue={currentAction["example_response"]}
|
||||
onChange={e => setActionField("example_response", e.target.value)}
|
||||
helperText={<span style={{color:"white", marginBottom: "2px",}}>
|
||||
Helps with autocompletion and understanding of the endpoint
|
||||
</span>}
|
||||
key={currentAction}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.notchedOutline,
|
||||
},
|
||||
style:{
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
const addActionToView = (errors) => {
|
||||
currentAction.errors = errors
|
||||
currentAction.queries = urlPathQueries
|
||||
@@ -1361,7 +1490,6 @@ const AppCreator = (props) => {
|
||||
open={actionsModalOpen}
|
||||
fullWidth
|
||||
onClose={() => {
|
||||
console.log("CLOSED?")
|
||||
setUrlPath("")
|
||||
setCurrentAction({
|
||||
"name": "",
|
||||
@@ -1564,7 +1692,7 @@ const AppCreator = (props) => {
|
||||
addPathQuery()
|
||||
}}>New query</Button>
|
||||
<div/>
|
||||
Headers - static for the action
|
||||
<b>Headers</b>: static for the action
|
||||
<TextField
|
||||
required
|
||||
style={{flex: "1", marginRight: "15px", marginTop: "5px", backgroundColor: inputColor}}
|
||||
@@ -1575,7 +1703,7 @@ const AppCreator = (props) => {
|
||||
id="standard-required"
|
||||
defaultValue={currentAction["headers"]}
|
||||
multiline
|
||||
rows="5"
|
||||
rows="2"
|
||||
onChange={e => setActionField("headers", e.target.value)}
|
||||
helperText={<span style={{color:"white", marginBottom: "2px",}}>Headers that are part of the request. Default: EMPTY</span>}
|
||||
InputProps={{
|
||||
@@ -1588,6 +1716,8 @@ const AppCreator = (props) => {
|
||||
}}
|
||||
/>
|
||||
{bodyInfo}
|
||||
<Divider style={{backgroundColor: "rgba(255,255,255,0.5)", marginTop: 15, marginBottom: 15}} />
|
||||
{exampleResponse}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button style={{borderRadius: "0px"}} onClick={() => {
|
||||
@@ -1597,7 +1727,7 @@ const AppCreator = (props) => {
|
||||
<Button color="primary" variant="outlined" style={{borderRadius: "0px"}} onClick={() => {
|
||||
console.log(urlPathQueries)
|
||||
console.log(urlPath)
|
||||
// value={urlPath}
|
||||
console.log(currentAction)
|
||||
const errors = getActionErrors()
|
||||
addActionToView(errors)
|
||||
setActionsModalOpen(false)
|
||||
|
||||
Reference in New Issue
Block a user