123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- <template lang='pug'>
- q-page.admin-terminal
- .row.q-pa-md.items-center
- .col-auto
- img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-linux-terminal-animated.svg')
- .col.q-pl-md
- .text-h5.text-primary.animated.fadeInLeft {{ t('admin.terminal.title') }}
- .text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ t('admin.terminal.subtitle') }}
- .col-auto.flex
- q-btn.acrylic-btn.q-mr-sm(
- v-if='!state.connected || state.connecting'
- flat
- icon='las la-link'
- :label='t(`admin.terminal.connect`)'
- color='positive'
- @click='connect'
- :loading='state.connecting'
- :disabled='state.connecting'
- )
- q-btn.acrylic-btn.q-mr-sm(
- v-else
- flat
- icon='las la-unlink'
- :label='t(`admin.terminal.disconnect`)'
- color='negative'
- @click='disconnect'
- )
- q-btn.acrylic-btn.q-mr-md(
- flat
- icon='las la-ban'
- :label='t(`admin.terminal.clear`)'
- color='primary'
- @click='clearTerminal'
- )
- q-separator.q-mr-md(vertical)
- q-btn.q-mr-sm.acrylic-btn(
- icon='las la-question-circle'
- flat
- color='grey'
- :href='siteStore.docsBase + `/admin/terminal`'
- target='_blank'
- type='a'
- )
- q-separator(inset)
- .q-pa-md.q-gutter-md
- q-card
- .admin-terminal-term(ref='termDiv')
- </template>
- <script setup>
- import { onBeforeUnmount, onMounted, reactive, ref } from 'vue'
- import { useMeta, useQuasar } from 'quasar'
- import { useI18n } from 'vue-i18n'
- import { io } from 'socket.io-client'
- import { Terminal } from 'xterm'
- import 'xterm/css/xterm.css'
- import { useSiteStore } from 'src/stores/site'
- // QUASAR
- const $q = useQuasar()
- // STORES
- const siteStore = useSiteStore()
- // I18N
- const { t } = useI18n()
- // META
- useMeta({
- title: t('admin.terminal.title')
- })
- // DATA
- const state = reactive({
- displayMode: 'logs',
- connected: false,
- connecting: false
- })
- let socket = null
- let term = null
- // REFS
- const termDiv = ref(null)
- // METHODS
- function clearTerminal () {
- term.clear()
- term.focus()
- }
- function connect () {
- state.connecting = true
- socket.connect()
- }
- function disconnect () {
- socket.disconnect()
- }
- // MOUNTED
- onMounted(() => {
- term = new Terminal({
- cursorBlink: true,
- cols: 128
- })
- term.open(termDiv.value)
- term.writeln(`> ${t('admin.terminal.connecting')}`)
- state.connecting = true
- // socket = io(window.location.host, {
- socket = io(window.location.host, {
- path: '/_ws/',
- auth: {
- token: 'TEST' // TODO: Use active token
- },
- autoConnect: false
- })
- socket.on('connect', () => {
- term.writeln(`> ${t('admin.terminal.connected')}`)
- state.connected = true
- state.connecting = false
- socket.emit('server:logs')
- })
- socket.on('disconnect', () => {
- term.writeln(`> ${t('admin.terminal.disconnected')}`)
- state.connected = false
- })
- socket.on('connect_error', (err) => {
- console.warn(err)
- term.writeln(`!> ${t('admin.terminal.connectError')} ${err.message}`)
- })
- socket.on('server:log', (msg) => {
- term.writeln(msg)
- term.focus()
- })
- socket.connect()
- })
- // BEFORE UNMOUNT
- onBeforeUnmount(() => {
- if (socket?.connected) {
- socket.disconnect()
- }
- })
- </script>
- <style lang='scss'>
- .admin-terminal {
- &-term {
- width: 100%;
- background-color: #000;
- border-radius: 5px;
- overflow: hidden;
- padding: 10px;
- }
- }
- </style>
|