forked from platypush/platypush
[Execute panel] Added cURL snippet modal.
This commit is contained in:
parent
fc21e9740b
commit
b47e729012
5 changed files with 133 additions and 60 deletions
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import Api from "@/utils/Api";
|
import Api from "@/utils/Api";
|
||||||
|
import Clipboard from "@/utils/Clipboard";
|
||||||
import Cookies from "@/utils/Cookies";
|
import Cookies from "@/utils/Cookies";
|
||||||
import DateTime from "@/utils/DateTime";
|
import DateTime from "@/utils/DateTime";
|
||||||
import Events from "@/utils/Events";
|
import Events from "@/utils/Events";
|
||||||
|
@ -10,6 +11,16 @@ import Types from "@/utils/Types";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Utils",
|
name: "Utils",
|
||||||
mixins: [Api, Cookies, Notification, Events, DateTime, Screen, Text, Types],
|
mixins: [
|
||||||
|
Api,
|
||||||
|
Clipboard,
|
||||||
|
Cookies,
|
||||||
|
DateTime,
|
||||||
|
Events,
|
||||||
|
Notification,
|
||||||
|
Screen,
|
||||||
|
Text,
|
||||||
|
Types,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
<main>
|
<main>
|
||||||
<h1>Execute Action</h1>
|
<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 -->
|
<!-- Execute panel views -->
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab :selected="structuredInput" icon-class="fas fa-list" @input="onInputTypeChange(true)">
|
<Tab :selected="structuredInput" icon-class="fas fa-list" @input="onInputTypeChange(true)">
|
||||||
|
@ -45,8 +51,16 @@
|
||||||
<!-- Action documentation container -->
|
<!-- Action documentation container -->
|
||||||
<section class="doc-container" v-if="selectedDoc">
|
<section class="doc-container" v-if="selectedDoc">
|
||||||
<h2>
|
<h2>
|
||||||
|
<div class="title">
|
||||||
<i class="fas fa-book" />
|
<i class="fas fa-book" />
|
||||||
<a :href="this.action?.doc_url">Action documentation</a>
|
<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>
|
</h2>
|
||||||
|
|
||||||
<div class="doc html">
|
<div class="doc html">
|
||||||
|
@ -129,7 +143,7 @@
|
||||||
{{ error != null ? 'Error' : 'Output' }}
|
{{ error != null ? 'Error' : 'Output' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="buttons">
|
<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" />
|
<i class="fas fa-clipboard" />
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
@ -159,7 +173,7 @@
|
||||||
<hgroup v-if="error != null || response != null">
|
<hgroup v-if="error != null || response != null">
|
||||||
<h2 v-text="error != null ? 'Error' : 'Output'" />
|
<h2 v-text="error != null ? 'Error' : 'Output'" />
|
||||||
<div class="buttons">
|
<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" />
|
<i class="fas fa-clipboard" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -207,13 +221,14 @@
|
||||||
import Argdoc from "./Argdoc"
|
import Argdoc from "./Argdoc"
|
||||||
import Autocomplete from "@/components/elements/Autocomplete"
|
import Autocomplete from "@/components/elements/Autocomplete"
|
||||||
import Loading from "@/components/Loading"
|
import Loading from "@/components/Loading"
|
||||||
|
import Modal from "@/components/Modal";
|
||||||
import Tab from "@/components/elements/Tab"
|
import Tab from "@/components/elements/Tab"
|
||||||
import Tabs from "@/components/elements/Tabs"
|
import Tabs from "@/components/elements/Tabs"
|
||||||
import Utils from "@/Utils"
|
import Utils from "@/Utils"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Execute",
|
name: "Execute",
|
||||||
components: {Argdoc, Autocomplete, Loading, Tab, Tabs},
|
components: {Argdoc, Autocomplete, Loading, Modal, Tab, Tabs},
|
||||||
mixins: [Utils],
|
mixins: [Utils],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -264,6 +279,64 @@ export default {
|
||||||
actionInput() {
|
actionInput() {
|
||||||
return this.$refs.autocomplete.$el.parentElement.querySelector('input[type=text]')
|
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: {
|
methods: {
|
||||||
|
@ -421,14 +494,6 @@ export default {
|
||||||
this.running = false
|
this.running = false
|
||||||
},
|
},
|
||||||
|
|
||||||
async copyToClipboard() {
|
|
||||||
const output = (
|
|
||||||
this.error != null ? this.error : this.response
|
|
||||||
)
|
|
||||||
|
|
||||||
await navigator.clipboard.writeText(output)
|
|
||||||
},
|
|
||||||
|
|
||||||
getPluginName(actionName) {
|
getPluginName(actionName) {
|
||||||
if (!actionName?.length)
|
if (!actionName?.length)
|
||||||
return ''
|
return ''
|
||||||
|
@ -442,37 +507,7 @@ export default {
|
||||||
|
|
||||||
this.running = true
|
this.running = true
|
||||||
if (this.structuredInput) {
|
if (this.structuredInput) {
|
||||||
const args = {
|
this.request(this.action.name, this.requestArgs).then(this.onResponse).catch(this.onError).finally(this.onDone)
|
||||||
...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)
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const request = JSON.parse(this.rawRequest)
|
const request = JSON.parse(this.rawRequest)
|
||||||
|
|
|
@ -207,7 +207,7 @@ form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.response {
|
.response, .doc-container {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
|
@ -225,22 +225,28 @@ form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.output {
|
.output {
|
||||||
background: $output-bg;
|
background: $output-bg;
|
||||||
padding: 0 0.75em;
|
padding: 0 0.75em;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
margin-top: 0.1em;
|
margin-top: 0.1em;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
box-shadow: $output-shadow;
|
box-shadow: $output-shadow;
|
||||||
|
|
||||||
&.response {
|
|
||||||
color: $response-fg;
|
color: $response-fg;
|
||||||
}
|
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
color: $error-fg;
|
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;
|
||||||
|
}
|
||||||
|
|
17
platypush/backend/http/webapp/src/utils/Clipboard.vue
Normal file
17
platypush/backend/http/webapp/src/utils/Clipboard.vue
Normal 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>
|
||||||
|
|
|
@ -12,6 +12,10 @@ export default {
|
||||||
prettify(text) {
|
prettify(text) {
|
||||||
return text.split('_').map((t) => this.capitalize(t)).join(' ')
|
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>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue