[Extensions UI] Install extensions deps from the UI.

- Added `Install` button
- Added interactive output panel
This commit is contained in:
Fabio Manganiello 2023-10-17 20:11:32 +02:00
parent 033317e0a7
commit a652bd9df8
Signed by: blacklight
GPG key ID: D90FBA7F76362774
5 changed files with 171 additions and 9 deletions

View file

@ -45,5 +45,6 @@ export default {
padding: 0.5em;
font-size: 1.5em;
cursor: pointer;
z-index: 1;
}
</style>

View file

@ -1,9 +1,43 @@
<template>
<div class="install-container">
<div class="install-cmd-container">
<CopyButton :text="installCmd" />
<pre><code v-html="highlightedInstallCmd" /></pre>
</div>
<section class="top">
<header>
<h2>Dependencies</h2>
</header>
<div class="body">
<div class="container install-cmd-container">
<CopyButton :text="installCmd" />
<pre><code v-html="highlightedInstallCmd" /></pre>
</div>
<div class="buttons install-btn" v-if="installCmd?.length">
<button type="button"
class="btn btn-default"
:disabled="installRunning"
@click="installExtension">
<i class="fas fa-download" /> Install
</button>
</div>
</div>
</section>
<section class="bottom" v-if="installRunning || installOutput">
<header>
<h2>Output</h2>
</header>
<div class="body">
<div class="container install-output" ref="installOutput">
<CopyButton :text="installOutput" />
<pre><code v-text="installOutput" /><div
class="loading-container"
v-if="installRunning">
<Loading />
</div></pre>
</div>
</div>
</section>
</div>
</template>
@ -12,14 +46,18 @@ import 'highlight.js/lib/common'
import 'highlight.js/styles/stackoverflow-dark.min.css'
import hljs from "highlight.js"
import CopyButton from "@/components/elements/CopyButton"
import Loading from "@/components/Loading"
import Utils from "@/Utils"
export default {
name: "Install",
mixins: [Utils],
emit: ['install-start', 'install-end'],
components: {
CopyButton,
Loading,
},
props: {
extension: {
type: Object,
@ -27,6 +65,14 @@ export default {
},
},
data() {
return {
installRunning: false,
installOutput: null,
pendingCommands: 0,
}
},
computed: {
installCmd() {
const cmd = this.extension.deps.install_cmd.join('\n').trim()
@ -47,29 +93,142 @@ export default {
)
},
},
methods: {
wsProcess(path) {
try {
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
const url = `${protocol}://${location.host}${path}`
const ws = new WebSocket(url)
ws.onmessage = this.onMessage
ws.onerror = this.onError
ws.onclose = this.onClose
} catch (err) {
console.error('Websocket initialization error') // TODO notify
console.error(err)
return
}
},
onMessage(msg) {
if (!this.installOutput)
this.installOutput = ''
this.installOutput += msg.data
},
onClose() {
this.installRunning = false
this.$emit('install-end', this.extension)
},
onError(error) {
console.error('Websocket error') // TODO notify
console.error(error)
},
installExtension() {
this.installRunning = true
this.installOutput = ''
this.$emit('install-start', this.extension)
const cmd = (this.extension.deps.install_cmd || []).join(';\n')
this.request('shell.exec', {
cmd: cmd,
ws: true,
}).then((output) => {
this.wsProcess(output.ws_path)
}).catch((err) => {
console.error(err) // TODO notify
})
},
},
mounted() {
this.$watch('installOutput', () => {
this.$nextTick(() => {
this.$refs.installOutput.focus()
this.$refs.installOutput.scrollTop = this.$refs.installOutput.scrollHeight
})
})
},
}
</script>
<style lang="scss" scoped>
@import "common.scss";
$header-height: 3.5em;
.install-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.install-cmd-container {
section {
&.top {
height: 33.3333% !important;
}
&.bottom {
height: 66.6666% !important;
}
header {
height: $header-height;
padding-left: 0.5em;
border-top: 1px solid $border-color-1;
border-bottom: 1px solid $border-color-1;
}
.body {
height: calc(100% - #{$header-height});
display: flex;
flex-direction: column;
padding: 1em;
}
h2 {
font-size: 1.3em;
opacity: 0.9;
}
}
.container {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
flex-grow: 1;
}
pre {
height: 50%;
height: 100%;
position: relative;
border-radius: 1em;
}
.install-btn {
width: 100%;
margin-top: 1em;
display: flex;
justify-content: right;
button {
border-radius: 0.5em;
margin-right: 0.5em;
}
}
.loading-container {
width: 100%;
position: relative;
:deep(.loading) {
background: none;
}
}
}
</style>

View file

@ -3,6 +3,7 @@ pre {
margin: 0;
background: $code-dark-bg;
color: $code-dark-fg;
font-size: 0.9em;
padding: 0.5em;
overflow: auto;
}

View file

@ -166,7 +166,7 @@ $scrollbar-thumb-bg: #a5a2a2 !default;
$row-shadow: 0 0 1px 0.5px #cfcfcf !default;
//// Code blocks
$code-dark-bg: #090909 !default;
$code-dark-fg: #f0f0f0 !default;
$code-dark-bg: rgb(11, 11, 13) !default;
$code-dark-fg: rgb(243, 243, 250) !default;
$code-light-bg: #f2f0e9 !default;
$code-light-fg: #090909 !default;

View file

@ -36,6 +36,7 @@ module.exports = {
proxy: {
'^/ws/events': wsProxy,
'^/ws/requests': wsProxy,
'^/ws/shell': wsProxy,
'^/execute': httpProxy,
'^/auth': httpProxy,
'^/camera/': httpProxy,