Upgrade.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <script setup lang="ts">
  2. import {useGettext} from 'vue3-gettext'
  3. import upgrade from '@/api/upgrade'
  4. import {computed, ref} from 'vue'
  5. import version from '@/version.json'
  6. import dayjs from 'dayjs'
  7. import {marked} from 'marked'
  8. import websocket from '@/lib/websocket'
  9. import {message} from 'ant-design-vue'
  10. const {$gettext} = useGettext()
  11. const data: any = ref({})
  12. const last_check = ref('')
  13. const loading = ref(false)
  14. const progressStrokeColor = {
  15. from: '#108ee9',
  16. to: '#87d068'
  17. }
  18. const modalVisible = ref(false)
  19. const progressPercent: any = ref(0)
  20. const progressStatus = ref('active')
  21. const modalClosable = ref(false)
  22. const get_release_error = ref(false)
  23. const progressPercentComputed = computed(() => {
  24. return parseFloat(progressPercent.value.toFixed(1))
  25. })
  26. function get_latest_release() {
  27. loading.value = true
  28. upgrade.get_latest_release().then(r => {
  29. data.value = r
  30. last_check.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
  31. }).catch(e => {
  32. get_release_error.value = e?.message
  33. message.error(e?.message ?? $gettext('Server error'))
  34. }).finally(() => {
  35. setTimeout(() => {
  36. loading.value = false
  37. }, 2000)
  38. })
  39. }
  40. get_latest_release()
  41. const is_latest_ver = computed(() => {
  42. return data.value.name === `v${version.version}`
  43. })
  44. const logContainer = ref(null)
  45. function log(msg: string) {
  46. const para = document.createElement('p')
  47. para.appendChild(document.createTextNode($gettext(msg)));
  48. (logContainer.value as any as Node).appendChild(para);
  49. (logContainer.value as any as Element).scroll({top: 320, left: 0, behavior: 'smooth'})
  50. }
  51. async function perform_upgrade() {
  52. progressStatus.value = 'active'
  53. modalClosable.value = false
  54. modalVisible.value = true
  55. progressPercent.value = 0;
  56. (logContainer.value as any as Element).innerHTML = ''
  57. log($gettext('Upgrading Nginx UI, please wait...'))
  58. const ws = websocket('/api/upgrade/perform', false)
  59. let last = 0
  60. ws.onmessage = async m => {
  61. const r = JSON.parse(m.data)
  62. if (r.message) log(r.message)
  63. console.log(r.status)
  64. switch (r.status) {
  65. case 'info':
  66. progressPercent.value += 10
  67. break
  68. case 'progress':
  69. progressPercent.value += (r.progress - last) / 2
  70. last = r.progress
  71. break
  72. case 'error':
  73. progressStatus.value = 'exception'
  74. modalClosable.value = true
  75. break
  76. default:
  77. modalClosable.value = true
  78. break
  79. }
  80. }
  81. ws.onclose = () => {
  82. const t = setInterval(() => {
  83. upgrade.current_version().then(() => {
  84. clearInterval(t)
  85. progressStatus.value = 'success'
  86. progressPercent.value = 100
  87. modalClosable.value = true
  88. log('Upgraded successfully')
  89. setInterval(() => {
  90. location.reload()
  91. }, 1000)
  92. })
  93. }, 2000)
  94. }
  95. }
  96. </script>
  97. <template>
  98. <a-card :title="$gettext('Upgrade')">
  99. <a-modal
  100. :title="$gettext('Core Upgrade')"
  101. v-model:visible="modalVisible"
  102. :mask-closable="false"
  103. :footer="null" :closable="modalClosable" force-render>
  104. <a-progress
  105. :stroke-color="progressStrokeColor"
  106. :percent="progressPercentComputed"
  107. :status="progressStatus"
  108. />
  109. <div class="core-upgrade-log-container" ref="logContainer"/>
  110. </a-modal>
  111. <div class="upgrade-container">
  112. <p>{{ $gettext('You can check Nginx UI upgrade at this page.') }}</p>
  113. <h3>{{ $gettext('Current Version') }}: v{{ version.version }}</h3>
  114. <template v-if="get_release_error">
  115. <a-alert type="error"
  116. :title="$gettext('Get release information error')"
  117. :message="get_release_error"
  118. banner
  119. />
  120. </template>
  121. <template v-else>
  122. <p>{{ $gettext('OS') }}: {{ data.os }}</p>
  123. <p>{{ $gettext('Arch') }}: {{ data.arch }}</p>
  124. <p>{{ $gettext('Executable Path') }}: {{ data.ex_path }}</p>
  125. <p>{{ $gettext('Last checked at') }}: {{ last_check }}
  126. <a-button type="link" @click="get_latest_release" :loading="loading">
  127. {{ $gettext('Check again') }}
  128. </a-button>
  129. </p>
  130. <a-alert type="success" v-if="is_latest_ver"
  131. :message="$gettext('You are using the latest version')"
  132. banner
  133. />
  134. <a-alert type="info" v-else
  135. :message="$gettext('New version released')"
  136. banner
  137. />
  138. <div class="control-btn">
  139. <a-space>
  140. <a-button type="primary" @click="perform_upgrade"
  141. ghost v-if="is_latest_ver">{{ $gettext('Reinstall') }}
  142. </a-button>
  143. <a-button type="primary" @click="perform_upgrade"
  144. ghost v-else>{{ $gettext('Upgrade') }}
  145. </a-button>
  146. </a-space>
  147. </div>
  148. </template>
  149. <template v-if="data.body">
  150. <h2>{{ $gettext('Release Note') }}</h2>
  151. <div v-html="marked.parse(data.body)"></div>
  152. </template>
  153. </div>
  154. </a-card>
  155. </template>
  156. <style lang="less">
  157. .dark {
  158. .core-upgrade-log-container {
  159. background-color: rgba(0, 0, 0, 0.84);
  160. }
  161. }
  162. .core-upgrade-log-container {
  163. height: 320px;
  164. overflow: scroll;
  165. background-color: #f3f3f3;
  166. border-radius: 4px;
  167. margin-top: 15px;
  168. padding: 10px;
  169. p {
  170. font-size: 12px;
  171. line-height: 1.3;
  172. }
  173. }
  174. </style>
  175. <style lang="less" scoped>
  176. .upgrade-container {
  177. width: 100%;
  178. max-width: 600px;
  179. margin: 0 auto;
  180. padding: 0 10px;
  181. }
  182. .control-btn {
  183. margin: 15px 0;
  184. }
  185. </style>