AdminTerminal.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <template lang='pug'>
  2. q-page.admin-terminal
  3. .row.q-pa-md.items-center
  4. .col-auto
  5. img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-linux-terminal-animated.svg')
  6. .col.q-pl-md
  7. .text-h5.text-primary.animated.fadeInLeft {{ t('admin.terminal.title') }}
  8. .text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ t('admin.terminal.subtitle') }}
  9. .col-auto.flex
  10. q-btn.acrylic-btn.q-mr-sm(
  11. v-if='!state.connected || state.connecting'
  12. flat
  13. icon='las la-link'
  14. :label='t(`admin.terminal.connect`)'
  15. color='positive'
  16. @click='connect'
  17. :loading='state.connecting'
  18. :disabled='state.connecting'
  19. )
  20. q-btn.acrylic-btn.q-mr-sm(
  21. v-else
  22. flat
  23. icon='las la-unlink'
  24. :label='t(`admin.terminal.disconnect`)'
  25. color='negative'
  26. @click='disconnect'
  27. )
  28. q-btn.acrylic-btn.q-mr-md(
  29. flat
  30. icon='las la-ban'
  31. :label='t(`admin.terminal.clear`)'
  32. color='primary'
  33. @click='clearTerminal'
  34. )
  35. q-separator.q-mr-md(vertical)
  36. q-btn.q-mr-sm.acrylic-btn(
  37. icon='las la-question-circle'
  38. flat
  39. color='grey'
  40. :href='siteStore.docsBase + `/admin/terminal`'
  41. target='_blank'
  42. type='a'
  43. )
  44. q-separator(inset)
  45. .q-pa-md.q-gutter-md
  46. q-card
  47. .admin-terminal-term(ref='termDiv')
  48. </template>
  49. <script setup>
  50. import { onBeforeUnmount, onMounted, reactive, ref } from 'vue'
  51. import { useMeta, useQuasar } from 'quasar'
  52. import { useI18n } from 'vue-i18n'
  53. import { io } from 'socket.io-client'
  54. import { Terminal } from 'xterm'
  55. import 'xterm/css/xterm.css'
  56. import { useSiteStore } from 'src/stores/site'
  57. // QUASAR
  58. const $q = useQuasar()
  59. // STORES
  60. const siteStore = useSiteStore()
  61. // I18N
  62. const { t } = useI18n()
  63. // META
  64. useMeta({
  65. title: t('admin.terminal.title')
  66. })
  67. // DATA
  68. const state = reactive({
  69. displayMode: 'logs',
  70. connected: false,
  71. connecting: false
  72. })
  73. let socket = null
  74. let term = null
  75. // REFS
  76. const termDiv = ref(null)
  77. // METHODS
  78. function clearTerminal () {
  79. term.clear()
  80. term.focus()
  81. }
  82. function connect () {
  83. state.connecting = true
  84. socket.connect()
  85. }
  86. function disconnect () {
  87. socket.disconnect()
  88. }
  89. // MOUNTED
  90. onMounted(() => {
  91. term = new Terminal({
  92. cursorBlink: true,
  93. cols: 128
  94. })
  95. term.open(termDiv.value)
  96. term.writeln(`> ${t('admin.terminal.connecting')}`)
  97. state.connecting = true
  98. // socket = io(window.location.host, {
  99. socket = io(window.location.host, {
  100. path: '/_ws/',
  101. auth: {
  102. token: 'TEST' // TODO: Use active token
  103. },
  104. autoConnect: false
  105. })
  106. socket.on('connect', () => {
  107. term.writeln(`> ${t('admin.terminal.connected')}`)
  108. state.connected = true
  109. state.connecting = false
  110. socket.emit('server:logs')
  111. })
  112. socket.on('disconnect', () => {
  113. term.writeln(`> ${t('admin.terminal.disconnected')}`)
  114. state.connected = false
  115. })
  116. socket.on('connect_error', (err) => {
  117. console.warn(err)
  118. term.writeln(`!> ${t('admin.terminal.connectError')} ${err.message}`)
  119. })
  120. socket.on('server:log', (msg) => {
  121. term.writeln(msg)
  122. term.focus()
  123. })
  124. socket.connect()
  125. })
  126. // BEFORE UNMOUNT
  127. onBeforeUnmount(() => {
  128. if (socket?.connected) {
  129. socket.disconnect()
  130. }
  131. })
  132. </script>
  133. <style lang='scss'>
  134. .admin-terminal {
  135. &-term {
  136. width: 100%;
  137. background-color: #000;
  138. border-radius: 5px;
  139. overflow: hidden;
  140. padding: 10px;
  141. }
  142. }
  143. </style>