Forráskód Böngészése

feat: check for updates dialog

NGPixel 2 éve
szülő
commit
bb4a1e6b15

+ 1 - 1
server/core/config.mjs

@@ -109,7 +109,7 @@ export default {
    */
   async saveToDb(keys, propagate = true) {
     try {
-      for (let key of keys) {
+      for (const key of keys) {
         let value = get(WIKI.config, key, null)
         if (!isPlainObject(value)) {
           value = { v: value }

+ 22 - 3
server/graph/resolvers/system.mjs

@@ -98,6 +98,25 @@ export default {
         return generateError(err)
       }
     },
+    async checkForUpdates (obj, args, context) {
+      try {
+        const renderJob = await WIKI.scheduler.addJob({
+          task: 'checkVersion',
+          maxRetries: 0,
+          promise: true
+        })
+        await renderJob.promise
+        return {
+          operation: generateSuccess('Checked for latest version successfully.'),
+          current: WIKI.version,
+          latest: WIKI.config.update.version,
+          latestDate: WIKI.config.update.versionDate
+        }
+      } catch (err) {
+        WIKI.logger.warn(err)
+        return generateError(err)
+      }
+    },
     async disconnectWS (obj, args, context) {
       WIKI.servers.ws.disconnectSockets(true)
       WIKI.logger.info('All active websocket connections have been terminated.')
@@ -205,13 +224,13 @@ export default {
       return _.toSafeInteger(results?.total) === 0
     },
     latestVersion () {
-      return WIKI.system.updates.version
+      return WIKI.config.update.version
     },
     latestVersionReleaseDate () {
-      return DateTime.fromISO(WIKI.system.updates.releaseDate).toJSDate()
+      return DateTime.fromISO(WIKI.config.update.versionDate).toJSDate()
     },
     nodeVersion () {
-      return process.version.substr(1)
+      return process.version.substring(1)
     },
     async operatingSystem () {
       let osLabel = `${os.type()} (${os.platform()}) ${os.release()} ${os.arch()}`

+ 9 - 0
server/graph/schemas/system.graphql

@@ -20,6 +20,8 @@ extend type Mutation {
     id: UUID!
   ): DefaultResponse
 
+  checkForUpdates: SystemCheckUpdateResponse
+
   disconnectWS: DefaultResponse
 
   installExtension(
@@ -204,3 +206,10 @@ enum SystemJobState {
   FAILED
   INTERRUPTED
 }
+
+type SystemCheckUpdateResponse {
+  operation: Operation
+  current: String
+  latest: String
+  latestDate: String
+}

+ 3 - 0
server/locales/en.json

@@ -770,17 +770,20 @@
   "admin.system.databaseHostHint": "The hostname used to access the database.",
   "admin.system.dbPartialSupport": "Your database version is not fully supported. Some functionality may be limited or not work as expected.",
   "admin.system.engines": "Server Engines",
+  "admin.system.fetchingLatestVersionInfo": "Fetching latest version info...",
   "admin.system.hostInfo": "Server Host Information",
   "admin.system.hostname": "Hostname",
   "admin.system.hostnameHint": "The hostname of the server / container.",
   "admin.system.latestVersion": "Latest Version",
   "admin.system.latestVersionHint": "The latest version available to install.",
+  "admin.system.newVersionAvailable": "A new version is available.",
   "admin.system.nodejsHint": "The version of Node.js installed.",
   "admin.system.os": "Operating System",
   "admin.system.osHint": "The OS Wiki.js is running on.",
   "admin.system.published": "Published",
   "admin.system.ramUsage": "RAM Usage: {used} / {total}",
   "admin.system.refreshSuccess": "System Info has been refreshed.",
+  "admin.system.runningLatestVersion": "You're running the latest version.",
   "admin.system.subtitle": "Information about your server / client",
   "admin.system.title": "System Info",
   "admin.system.totalRAM": "Total RAM",

+ 7 - 7
server/tasks/simple/check-version.mjs

@@ -3,14 +3,14 @@ export async function task (payload) {
 
   try {
     const resp = await fetch('https://api.github.com/repos/requarks/wiki/releases/latest').then(r => r.json())
+    const strictVersion = resp.tag_name.indexOf('v') === 0 ? resp.tag_name.substring(1) : resp.tag_name
     WIKI.logger.info(`Latest version is ${resp.tag_name}.`)
-    await WIKI.db.knex('settings').where('key', 'update').update({
-      value: {
-        lastCheckedAt: (new Date).toISOString(),
-        version: resp.tag_name,
-        versionDate: resp.published_at
-      }
-    })
+    WIKI.config.update = {
+      lastCheckedAt: (new Date).toISOString(),
+      version: strictVersion,
+      versionDate: resp.published_at
+    }
+    await WIKI.config.saveToDb(['update'])
 
     WIKI.logger.info('Checked for latest version: [ COMPLETED ]')
   } catch (err) {

+ 50 - 23
ux/src/components/CheckUpdateDialog.vue

@@ -7,17 +7,25 @@ q-dialog(ref='dialogRef', @hide='onDialogHide')
     q-card-section
       .q-pa-md.text-center
         img(src='/_assets/illustrations/undraw_going_up.svg', style='width: 150px;')
-      q-linear-progress(
-        indeterminate
-        size='lg'
-        rounded
-        )
-      .q-mt-sm.text-center.text-caption Fetching latest version info...
+      template(v-if='state.isLoading')
+        q-linear-progress(
+          indeterminate
+          size='lg'
+          rounded
+          )
+        .q-mt-sm.text-center.text-caption {{ $t('admin.system.fetchingLatestVersionInfo') }}
+      template(v-else)
+        .text-center
+          strong.text-positive(v-if='isLatest') {{ $t('admin.system.runningLatestVersion') }}
+          strong.text-pink(v-else) {{ $t('admin.system.newVersionAvailable') }}
+          .text-body2.q-mt-md Current: #[strong {{ state.current }}]
+          .text-body2 Latest: #[strong {{ state.latest }}]
+          .text-body2 Release Date: #[strong {{ state.latestDate }}]
     q-card-actions.card-actions
       q-space
       q-btn.acrylic-btn(
         flat
-        :label='t(`common.actions.cancel`)'
+        :label='state.isLoading ? t(`common.actions.cancel`) : t(`common.actions.close`)'
         color='grey'
         padding='xs md'
         @click='onDialogCancel'
@@ -37,7 +45,10 @@ q-dialog(ref='dialogRef', @hide='onDialogHide')
 import gql from 'graphql-tag'
 import { useI18n } from 'vue-i18n'
 import { useDialogPluginComponent, useQuasar } from 'quasar'
-import { reactive } from 'vue'
+import { computed, onMounted, reactive } from 'vue'
+import { DateTime } from 'luxon'
+
+import { useUserStore } from 'src/stores/user'
 
 // EMITS
 
@@ -50,6 +61,10 @@ defineEmits([
 const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
 const $q = useQuasar()
 
+// STORES
+
+const userStore = useUserStore()
+
 // I18N
 
 const { t } = useI18n()
@@ -58,44 +73,56 @@ const { t } = useI18n()
 
 const state = reactive({
   isLoading: false,
-  canUpgrade: false
+  canUpgrade: false,
+  current: '',
+  latest: '',
+  latestDate: ''
+})
+
+const isLatest = computed(() => {
+  return true
 })
 
 // METHODS
 
-async function upgrade () {
+async function check () {
   state.isLoading = true
   try {
     const resp = await APOLLO_CLIENT.mutate({
       mutation: gql`
-        mutation deleteHook ($id: UUID!) {
-          deleteHook(id: $id) {
+        mutation checkForUpdates {
+          checkForUpdates {
             operation {
               succeeded
               message
             }
+            current
+            latest
+            latestDate
           }
         }
-      `,
-      variables: {
-        id: 0
-      }
+      `
     })
-    if (resp?.data?.deleteHook?.operation?.succeeded) {
-      $q.notify({
-        type: 'positive',
-        message: t('admin.webhooks.deleteSuccess')
-      })
-      onDialogOK()
+    if (resp?.data?.checkForUpdates?.operation?.succeeded) {
+      state.current = resp?.data?.checkForUpdates?.current
+      state.latest = resp?.data?.checkForUpdates?.latest
+      state.latestDate = DateTime.fromISO(resp?.data?.checkForUpdates?.latestDate).toFormat(userStore.preferredDateFormat)
     } else {
-      throw new Error(resp?.data?.deleteHook?.operation?.message || 'An unexpected error occured.')
+      throw new Error(resp?.data?.checkForUpdates?.operation?.message || 'An unexpected error occured.')
     }
   } catch (err) {
     $q.notify({
       type: 'negative',
       message: err.message
     })
+    onDialogCancel()
   }
   state.isLoading = false
 }
+
+// MOUNTED
+
+onMounted(() => {
+  check()
+})
 </script>

+ 0 - 22
ux/src/pages/AdminLocale.vue

@@ -107,28 +107,6 @@ q-page.admin-locale
       .q-pa-md.text-center
         img(src='/_assets/illustrations/undraw_world.svg', style='width: 80%;')
 
-        //- q-separator.q-my-sm(inset)
-        //- q-item
-        //-   blueprint-icon(icon='test-passed')
-        //-   q-item-section
-        //-     q-item-label {{t(`admin.locale.activeNamespaces.label`)}}
-        //-     q-item-label(caption) {{t(`admin.locale.activeNamespaces.hint`)}}
-        //-   q-item-section
-        //-     q-select(
-        //-       outlined
-        //-       :disable='!namespacing'
-        //-       v-model='namespaces'
-        //-       :options='installedLocales'
-        //-       multiple
-        //-       use-chips
-        //-       option-value='code'
-        //-       option-label='name'
-        //-       emit-value
-        //-       map-options
-        //-       dense
-        //-       :aria-label='t(`admin.locale.activeNamespaces.label`)'
-        //-       )
-
 </template>
 
 <script setup>

+ 3 - 83
ux/src/pages/AdminSystem.vue

@@ -60,7 +60,7 @@ q-page.admin-system
           q-item-section
             .row.q-col-gutter-sm
               .col
-                .dark-value(caption) {{ state.info.latestVersion }}
+                .text-caption.dark-value {{ state.info.latestVersion }}
               .col-auto
                 q-btn.acrylic-btn(
                   flat
@@ -200,43 +200,6 @@ q-page.admin-system
             q-item-label(caption) {{t('admin.system.configFileHint')}}
           q-item-section
             q-item-label.dark-value(caption) {{ state.info.configFile }}
-
-  //-                 v-list-item-action-text {{ t('admin.system.published') }} {{ state.info.latestVersionReleaseDate | moment('from') }}
-  //-           v-card-actions(v-if='info.upgradeCapable && !isLatestVersion && info.platform === `docker`', :class='$vuetify.theme.dark ? `grey darken-3-d5` : `indigo lighten-5`')
-  //-             .caption.indigo--text.pl-3(:class='$vuetify.theme.dark ? `text--lighten-4` : ``') Wiki.js can perform the upgrade to the latest version for you.
-  //-             v-spacer
-  //-             v-btn.px-3(
-  //-               color='indigo'
-  //-               dark
-  //-               @click='performUpgrade'
-  //-               )
-  //-               v-icon(left) mdi-upload
-  //-               span Perform Upgrade
-
-  //- v-dialog(
-  //-   v-model='isUpgrading'
-  //-   persistent
-  //-   width='450'
-  //-   )
-  //-   v-card.blue.darken-5(dark)
-  //-     v-card-text.text-center.pa-10
-  //-       self-building-square-spinner(
-  //-         :animation-duration='4000'
-  //-         :size='40'
-  //-         color='#FFF'
-  //-         style='margin: 0 auto;'
-  //-         )
-  //-       .body-2.mt-5.blue--text.text--lighten-4 Your Wiki.js container is being upgraded...
-  //-       .caption.blue--text.text--lighten-2 Please wait
-  //-       v-progress-linear.mt-5(
-  //-         color='blue lighten-2'
-  //-         :value='upgradeProgress'
-  //-         :buffer-value='upgradeProgress'
-  //-         rounded
-  //-         :stream='isUpgradingStarted'
-  //-         query
-  //-         :indeterminate='!isUpgradingStarted'
-  //-       )
 </template>
 
 <script setup>
@@ -309,9 +272,6 @@ const platformLogo = computed(() => {
       return 'washing-machine'
   }
 })
-const isLatestVersion = computed(() => {
-  return state.info.currentVersion === state.info.latestVersion
-})
 const clientBrowser = computed(() => {
   return !import.meta.env.SSR ? navigator.userAgent : ''
 })
@@ -364,51 +324,11 @@ async function load () {
 function checkForUpdates () {
   $q.dialog({
     component: CheckUpdateDialog
+  }).onDismiss(() => {
+    load()
   })
 }
 
-// async function performUpgrade () {
-//   state.isUpgrading = true
-//   state.isUpgradingStarted = false
-//   state.upgradeProgress = 0
-//   this.$store.commit('loadingStart', 'admin-system-upgrade')
-//   try {
-//     const respRaw = await APOLLO_CLIENT.mutate({
-//       mutation: gql`
-//         mutation performUpdate {
-//           system {
-//             performUpgrade {
-//               responseResult {
-//                 succeeded
-//                 errorCode
-//                 slug
-//                 message
-//               }
-//             }
-//           }
-//         }
-//       `
-//     })
-//     const resp = _get(respRaw, 'data.system.performUpgrade.responseResult', {})
-//     if (resp.succeeded) {
-//       this.isUpgradingStarted = true
-//       const progressInterval = setInterval(() => {
-//         this.upgradeProgress += 0.83
-//       }, 500)
-//       setTimeout(() => {
-//         clearInterval(progressInterval)
-//         window.location.reload(true)
-//       }, 60000)
-//     } else {
-//       throw new Error(resp.message)
-//     }
-//   } catch (err) {
-//     this.$store.commit('pushGraphError', err)
-//     this.$store.commit('loadingStop', 'admin-system-upgrade')
-//     this.isUpgrading = false
-//   }
-// }
-
 // MOUNTED
 
 onMounted(() => {