[Execute panel] Added cURL snippet modal.

This commit is contained in:
Fabio Manganiello 2023-10-11 16:38:38 +02:00
parent fc21e9740b
commit b47e729012
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
5 changed files with 133 additions and 60 deletions

View file

@ -1,5 +1,6 @@
<script>
import Api from "@/utils/Api";
import Clipboard from "@/utils/Clipboard";
import Cookies from "@/utils/Cookies";
import DateTime from "@/utils/DateTime";
import Events from "@/utils/Events";
@ -10,6 +11,16 @@ import Types from "@/utils/Types";
export default {
name: "Utils",
mixins: [Api, Cookies, Notification, Events, DateTime, Screen, Text, Types],
mixins: [
Api,
Clipboard,
Cookies,
DateTime,
Events,
Notification,
Screen,
Text,
Types,
],
}
</script>

View file

@ -6,6 +6,12 @@
<main>
<h1>Execute Action</h1>
<!-- cURL snippet modal -->
<Modal ref="curlModal" title="curl request" v-if="curlSnippet?.length">
<textarea class="output curl-snippet" readonly :value="curlSnippet"
@click="copyToClipboard(curlSnippet)" />
</Modal>
<!-- Execute panel views -->
<Tabs>
<Tab :selected="structuredInput" icon-class="fas fa-list" @input="onInputTypeChange(true)">
@ -45,8 +51,16 @@
<!-- Action documentation container -->
<section class="doc-container" v-if="selectedDoc">
<h2>
<div class="title">
<i class="fas fa-book" /> &nbsp;
<a :href="this.action?.doc_url">Action documentation</a>
</div>
<div class="buttons" v-if="action?.name">
<button type="button" title="cURL command" v-if="curlSnippet?.length"
@click="$refs.curlModal.show()">
<i class="fas fa-terminal" />
</button>
</div>
</h2>
<div class="doc html">
@ -129,7 +143,7 @@
{{ error != null ? 'Error' : 'Output' }}
</span>
<span class="buttons">
<button type="button" title="Copy to clipboard" @click="copyToClipboard">
<button type="button" title="Copy to clipboard" @click="copyToClipboard(response)">
<i class="fas fa-clipboard" />
</button>
</span>
@ -159,7 +173,7 @@
<hgroup v-if="error != null || response != null">
<h2 v-text="error != null ? 'Error' : 'Output'" />
<div class="buttons">
<button type="button" title="Copy to clipboard" @click="copyToClipboard">
<button type="button" title="Copy to clipboard" @click="copyToClipboard(error)">
<i class="fas fa-clipboard" />
</button>
</div>
@ -207,13 +221,14 @@
import Argdoc from "./Argdoc"
import Autocomplete from "@/components/elements/Autocomplete"
import Loading from "@/components/Loading"
import Modal from "@/components/Modal";
import Tab from "@/components/elements/Tab"
import Tabs from "@/components/elements/Tabs"
import Utils from "@/Utils"
export default {
name: "Execute",
components: {Argdoc, Autocomplete, Loading, Tab, Tabs},
components: {Argdoc, Autocomplete, Loading, Modal, Tab, Tabs},
mixins: [Utils],
data() {
@ -264,6 +279,64 @@ export default {
actionInput() {
return this.$refs.autocomplete.$el.parentElement.querySelector('input[type=text]')
},
requestArgs() {
if (!this.action.name)
return {}
return {
...Object.entries(this.action.args).reduce((args, arg) => {
if (arg[1].value != null) {
let value = arg[1].value
try {
value = JSON.parse(value)
} catch (e) {
console.debug('Not a valid JSON value')
console.debug(value)
}
args[arg[0]] = value
}
return args
}, {}),
...this.action.extraArgs.reduce((args, arg) => {
let value = args[arg.value]
try {
value = JSON.parse(value)
} catch (e) {
console.debug('Not a valid JSON value')
console.debug(value)
}
args[arg.name] = value
return args
}, {})
}
},
curlURL() {
return `${window.location.protocol}//${window.location.host}/execute`
},
curlSnippet() {
if (!this.action.name)
return ''
const request = {
type: 'request',
action: this.action.name,
args: this.requestArgs,
}
return (
'curl -XPOST -H "Content-Type: application/json" \\\n\t' +
`-H "Cookie: session_token=${this.getCookies()['session_token']}"`+
" \\\n\t -d '" +
this.indent(JSON.stringify(request, null, 2), 2).trim() + "' \\\n\t" +
`'${this.curlURL}'`
)
},
},
methods: {
@ -421,14 +494,6 @@ export default {
this.running = false
},
async copyToClipboard() {
const output = (
this.error != null ? this.error : this.response
)
await navigator.clipboard.writeText(output)
},
getPluginName(actionName) {
if (!actionName?.length)
return ''
@ -442,37 +507,7 @@ export default {
this.running = true
if (this.structuredInput) {
const args = {
...Object.entries(this.action.args).reduce((args, arg) => {
if (arg[1].value != null) {
let value = arg[1].value
try {
value = JSON.parse(value)
} catch (e) {
console.debug('Not a valid JSON value')
console.debug(value)
}
args[arg[0]] = value
}
return args
}, {}),
...this.action.extraArgs.reduce((args, arg) => {
let value = args[arg.value]
try {
value = JSON.parse(value)
} catch (e) {
console.debug('Not a valid JSON value')
console.debug(value)
}
args[arg.name] = value
return args
}, {})
}
this.request(this.action.name, args).then(this.onResponse).catch(this.onError).finally(this.onDone)
this.request(this.action.name, this.requestArgs).then(this.onResponse).catch(this.onError).finally(this.onDone)
} else {
try {
const request = JSON.parse(this.rawRequest)

View file

@ -207,7 +207,7 @@ form {
}
}
.response {
.response, .doc-container {
flex-grow: 1;
h2 {
@ -225,6 +225,7 @@ form {
}
}
}
}
.output {
background: $output-bg;
@ -233,14 +234,19 @@ form {
margin-top: 0.1em;
border-radius: 1em;
box-shadow: $output-shadow;
&.response {
color: $response-fg;
}
&.error {
color: $error-fg;
}
}
}
textarea.curl-snippet {
width: calc(100vw - 5em);
height: 100vh;
max-width: 40em;
max-height: 25em;
line-break: anywhere;
overflow: auto;
padding: 0.5em;
}

View file

@ -0,0 +1,17 @@
<script>
export default {
name: "Clipboard",
methods: {
async copyToClipboard(text) {
await navigator.clipboard.writeText(text)
this.notify({
text: 'Copied to the clipboard',
image: {
icon: 'clipboard',
},
})
},
},
}
</script>

View file

@ -12,6 +12,10 @@ export default {
prettify(text) {
return text.split('_').map((t) => this.capitalize(t)).join(' ')
},
indent(text, tabs = 1) {
return text.split('\n').map((t) => `${'\t'.repeat(tabs)}${t}`).join('\n')
},
},
}
</script>