#133: Added first part of example and body parser

This commit is contained in:
frikky
2020-12-07 16:05:30 +01:00
parent b13c3f3765
commit 6ae79cc87d
2 changed files with 215 additions and 17 deletions
+72 -4
View File
@@ -845,7 +845,7 @@ const AngularWorkflow = (props) => {
return response.json() return response.json()
}) })
.then((responseJson) => { .then((responseJson) => {
// FIXME - handle versions on left bar // FIXME - handle versions on left bar
//handleAppVersioning(responseJson) //handleAppVersioning(responseJson)
//var tmpapps = [] //var tmpapps = []
@@ -2872,8 +2872,64 @@ const AngularWorkflow = (props) => {
placeholder = data.example 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 = var datafield =
<TextField <TextField
disabled={disabled}
style={{backgroundColor: inputColor, borderRadius: borderRadius,}} style={{backgroundColor: inputColor, borderRadius: borderRadius,}}
InputProps={{ InputProps={{
style:{ style:{
@@ -2901,7 +2957,7 @@ const AngularWorkflow = (props) => {
}} }}
fullWidth fullWidth
multiline={multiline} multiline={multiline}
rows="5" rows={rows}
color="primary" color="primary"
defaultValue={data.value} defaultValue={data.value}
type={placeholder.includes("***") ? "password" : "text"} type={placeholder.includes("***") ? "password" : "text"}
@@ -2909,6 +2965,13 @@ const AngularWorkflow = (props) => {
onChange={(event) => { onChange={(event) => {
changeActionParameter(event, count) changeActionParameter(event, count)
}} }}
helperText={selectedApp.generated && selectedApp.activated && data.name === "body" ?
<span style={{color:"white", marginBottom: 5,}}>
{openApiHelperText}
</span>
:
null
}
onBlur={(event) => { onBlur={(event) => {
// Super basic check // Super basic check
//if (event.target.value.startsWith("{")) { //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={{width: 17, height: 17, borderRadius: 17 / 2, backgroundColor: itemColor, marginRight: 10}}/>
} }
<div style={{flex: "10"}}> <div style={{flex: "10"}}>
<b>{data.name} </b> <b>{data.name.charAt(0).toUpperCase()+data.name.substring(1)} </b>
</div> </div>
{selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0 ? null : {selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0 ? null :
@@ -3685,7 +3748,7 @@ const AngularWorkflow = (props) => {
{selectedAction.description} {selectedAction.description}
</div> : null} </div> : null}
<div style={{marginTop: "10px", borderColor: "white", borderWidth: "2px", marginBottom: 200}}> <div style={{marginTop: "10px", borderColor: "white", borderWidth: "2px", marginBottom: 200}}>
<AppActionArguments key={selectedAction.id} selectedAction={selectedAction} /> <AppActionArguments key={selectedAction.id} selectedAction={selectedAction} />
</div> </div>
<div style={{}}> <div style={{}}>
@@ -6253,6 +6316,11 @@ const AngularWorkflow = (props) => {
getAppAuthentication() getAppAuthentication()
setUpdate(authenticationOption.id) setUpdate(authenticationOption.id)
/*
{selectedAction.authentication.map(data => (
<MenuItem key={data.id} style={{backgroundColor: inputColor, color: "white"}} value={data}>
*/
} }
return ( return (
+143 -13
View File
@@ -4,6 +4,7 @@ import {BrowserView, MobileView} from "react-device-detect";
import {Link} from 'react-router-dom'; import {Link} from 'react-router-dom';
import Paper from '@material-ui/core/Paper'; import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider'; import Divider from '@material-ui/core/Divider';
@@ -218,6 +219,7 @@ const AppCreator = (props) => {
const [actions, setActions] = useState([]) const [actions, setActions] = useState([])
const [errorCode, setErrorCode] = useState("") const [errorCode, setErrorCode] = useState("")
const [appBuilding, setAppBuilding] = useState(false) const [appBuilding, setAppBuilding] = useState(false)
const [extraBodyFields, setExtraBodyFields] = useState([])
//const [actions, setActions] = useState([{ //const [actions, setActions] = useState([{
// "name": "Get workflows", // "name": "Get workflows",
@@ -253,6 +255,7 @@ const AppCreator = (props) => {
"queries": [], "queries": [],
"body": "", "body": "",
"errors": [], "errors": [],
"example_response": "",
"method": actionNonBodyRequest[0], "method": actionNonBodyRequest[0],
}); });
@@ -262,7 +265,7 @@ const AppCreator = (props) => {
if (firstrequest) { if (firstrequest) {
setFirstrequest(false) setFirstrequest(false)
if (window.location.pathname.includes("apps/edit")) { if (window.location.pathname.includes("apps/edit")) {
setIsEditing(true) setIsEditing(true)
handleEditApp() handleEditApp()
} else { } else {
checkQuery() checkQuery()
@@ -433,6 +436,22 @@ const AppCreator = (props) => {
"paths": [], "paths": [],
"body": "", "body": "",
"errors": [], "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) { for (var key in methodvalue.parameters) {
@@ -469,6 +488,7 @@ const AppCreator = (props) => {
} }
} }
if (newaction.name === "" || newaction.name === undefined) { if (newaction.name === "" || newaction.name === undefined) {
// Find a unique part of the string // Find a unique part of the string
// FIXME: Looks for length between /, find the one where they differ // FIXME: Looks for length between /, find the one where they differ
@@ -668,7 +688,14 @@ const AppCreator = (props) => {
"responses": { "responses": {
"default": { "default": {
"description": "default", "description": "default",
"schema": {} "content": {
"text/plain": {
"schema": {
"type": "string",
"example": "",
},
},
},
} }
}, },
"summary": item.name, "summary": item.name,
@@ -679,6 +706,35 @@ const AppCreator = (props) => {
//console.log("ACTION: ", item) //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) { if (item.queries.length > 0) {
for (var querykey in item.queries) { for (var querykey in item.queries) {
const queryitem = item.queries[querykey] const queryitem = item.queries[querykey]
@@ -761,7 +817,7 @@ const AppCreator = (props) => {
"type": "string", "type": "string",
}, },
} }
// FIXME - add application/json if JSON example? // FIXME - add application/json if JSON example?
data.paths[item.url][item.method.toLowerCase()]["requestBody"] = { data.paths[item.url][item.method.toLowerCase()]["requestBody"] = {
"description": "Generated by Shuffler.io", "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) data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem)
} }
@@ -782,7 +850,6 @@ const AppCreator = (props) => {
const headersSplit = item.headers.split("\n") const headersSplit = item.headers.split("\n")
for (var key in headersSplit) { for (var key in headersSplit) {
const header = headersSplit[key] const header = headersSplit[key]
console.log("HEADER: ", header)
var key = "" var key = ""
var value = "" var value = ""
if (header.length > 0 && header.includes("= ")) { if (header.length > 0 && header.includes("= ")) {
@@ -1137,12 +1204,15 @@ const AppCreator = (props) => {
setUrlPathQueries(data.queries) setUrlPathQueries(data.queries)
setUrlPath(data.url) setUrlPath(data.url)
setActionsModalOpen(true) setActionsModalOpen(true)
if (data["body"] !== undefined && data["body"] !== null && data["body"].length > 0) {
findBodyParams(data["body"])
}
}}> }}>
<div style={{display: "flex"}}> <div style={{display: "flex"}}>
<Chip <Chip
style={{backgroundColor: bgColor, color: "white", borderRadius: 5, minWidth: 80, marginRight: 10, marginTop: 2, cursor: "pointer", fontSize: 14,}} style={{backgroundColor: bgColor, color: "white", borderRadius: 5, minWidth: 80, marginRight: 10, marginTop: 2, cursor: "pointer", fontSize: 14,}}
label={data.method} label={data.method}
variant="contained"
/> />
<span style={{fontSize: 16, marginTop: "auto", marginBottom: "auto",}}> <span style={{fontSize: 16, marginTop: "auto", marginBottom: "auto",}}>
{url} - {data.name} {url} - {data.name}
@@ -1177,24 +1247,52 @@ const AppCreator = (props) => {
const setActionField = (field, value) => { const setActionField = (field, value) => {
currentAction[field] = value currentAction[field] = value
setCurrentAction(currentAction) setCurrentAction(currentAction)
//setUrlPathQueries(currentAction.queries) //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) ? const bodyInfo = actionBodyRequest.includes(currentActionMethod) ?
<div> <div style={{marginTop: 10}}>
Body - used as example in action argument <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 <TextField
required required
style={{flex: "1", marginRight: "15px", backgroundColor: inputColor}} style={{flex: "1", marginRight: "15px", backgroundColor: inputColor}}
fullWidth={true} 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" margin="normal"
variant="outlined" variant="outlined"
multiline multiline
rows="5" rows="5"
defaultValue={currentAction["body"]} defaultValue={currentAction["body"]}
onChange={e => setActionField("body", e.target.value)} onChange={e => {
setActionField("body", e.target.value)
findBodyParams(e.target.value)
}}
key={currentAction} key={currentAction}
helperText={
<span style={{color:"white", marginBottom: "2px",}}>
Shows an example body to the user. ${} creates variables.
</span>
}
InputProps={{ InputProps={{
classes: { classes: {
notchedOutline: classes.notchedOutline, notchedOutline: classes.notchedOutline,
@@ -1205,9 +1303,40 @@ const AppCreator = (props) => {
}} }}
/> />
<div>
</div>
</div> </div>
: null : 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) => { const addActionToView = (errors) => {
currentAction.errors = errors currentAction.errors = errors
currentAction.queries = urlPathQueries currentAction.queries = urlPathQueries
@@ -1361,7 +1490,6 @@ const AppCreator = (props) => {
open={actionsModalOpen} open={actionsModalOpen}
fullWidth fullWidth
onClose={() => { onClose={() => {
console.log("CLOSED?")
setUrlPath("") setUrlPath("")
setCurrentAction({ setCurrentAction({
"name": "", "name": "",
@@ -1564,7 +1692,7 @@ const AppCreator = (props) => {
addPathQuery() addPathQuery()
}}>New query</Button> }}>New query</Button>
<div/> <div/>
Headers - static for the action <b>Headers</b>: static for the action
<TextField <TextField
required required
style={{flex: "1", marginRight: "15px", marginTop: "5px", backgroundColor: inputColor}} style={{flex: "1", marginRight: "15px", marginTop: "5px", backgroundColor: inputColor}}
@@ -1575,7 +1703,7 @@ const AppCreator = (props) => {
id="standard-required" id="standard-required"
defaultValue={currentAction["headers"]} defaultValue={currentAction["headers"]}
multiline multiline
rows="5" rows="2"
onChange={e => setActionField("headers", e.target.value)} onChange={e => setActionField("headers", e.target.value)}
helperText={<span style={{color:"white", marginBottom: "2px",}}>Headers that are part of the request. Default: EMPTY</span>} helperText={<span style={{color:"white", marginBottom: "2px",}}>Headers that are part of the request. Default: EMPTY</span>}
InputProps={{ InputProps={{
@@ -1588,6 +1716,8 @@ const AppCreator = (props) => {
}} }}
/> />
{bodyInfo} {bodyInfo}
<Divider style={{backgroundColor: "rgba(255,255,255,0.5)", marginTop: 15, marginBottom: 15}} />
{exampleResponse}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button style={{borderRadius: "0px"}} onClick={() => { <Button style={{borderRadius: "0px"}} onClick={() => {
@@ -1597,7 +1727,7 @@ const AppCreator = (props) => {
<Button color="primary" variant="outlined" style={{borderRadius: "0px"}} onClick={() => { <Button color="primary" variant="outlined" style={{borderRadius: "0px"}} onClick={() => {
console.log(urlPathQueries) console.log(urlPathQueries)
console.log(urlPath) console.log(urlPath)
// value={urlPath} console.log(currentAction)
const errors = getActionErrors() const errors = getActionErrors()
addActionToView(errors) addActionToView(errors)
setActionsModalOpen(false) setActionsModalOpen(false)