admin-locale.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <template lang='pug'>
  2. v-container(fluid, grid-list-lg)
  3. v-layout(row, wrap)
  4. v-flex(xs12)
  5. .admin-header
  6. img.animated.fadeInUp(src='/svg/icon-globe-earth.svg', alt='Locale', style='width: 80px;')
  7. .admin-header-title
  8. .headline.primary--text.animated.fadeInLeft {{ $t('admin:locale.title') }}
  9. .subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{ $t('admin:locale.subtitle') }}
  10. v-spacer
  11. v-btn.animated.fadeInDown(color='success', depressed, @click='save', large, :loading='loading')
  12. v-icon(left) mdi-check
  13. span {{$t('common:actions.apply')}}
  14. v-form.pt-3
  15. v-layout(row wrap)
  16. v-flex(lg6 xs12)
  17. v-card.wiki-form.animated.fadeInUp
  18. v-toolbar(color='primary', dark, dense, flat)
  19. v-toolbar-title.subtitle-1 {{ $t('admin:locale.settings') }}
  20. v-card-text
  21. v-select(
  22. outlined
  23. :items='installedLocales'
  24. prepend-icon='mdi-web'
  25. v-model='selectedLocale'
  26. item-value='code'
  27. item-text='nativeName'
  28. :label='namespacing ? $t("admin:locale.base.labelWithNS") : $t("admin:locale.base.label")'
  29. persistent-hint
  30. :hint='$t("admin:locale.base.hint")'
  31. )
  32. template(slot='item', slot-scope='data')
  33. template(v-if='typeof data.item !== "object"')
  34. v-list-item-content(v-text='data.item')
  35. template(v-else)
  36. v-list-item-avatar
  37. v-avatar.blue.white--text(tile, size='40', v-html='data.item.code.toUpperCase()')
  38. v-list-item-content
  39. v-list-item-title(v-html='data.item.name')
  40. v-list-item-sub-title(v-html='data.item.nativeName')
  41. v-divider.mt-3
  42. v-switch(
  43. v-model='autoUpdate'
  44. :label='$t("admin:locale.autoUpdate.label")'
  45. color='primary'
  46. persistent-hint
  47. :hint='namespacing ? $t("admin:locale.autoUpdate.hintWithNS") : $t("admin:locale.autoUpdate.hint")'
  48. )
  49. v-card.wiki-form.mt-3.animated.fadeInUp.wait-p2s
  50. v-toolbar(color='primary', dark, dense, flat)
  51. v-toolbar-title.subtitle-1 {{ $t('admin:locale.namespacing') }}
  52. v-card-text
  53. v-switch(
  54. v-model='namespacing'
  55. :label='$t("admin:locale.namespaces.label")'
  56. color='primary'
  57. persistent-hint
  58. :hint='$t("admin:locale.namespaces.hint")'
  59. )
  60. v-alert.mt-3(
  61. outlined
  62. color='orange'
  63. :value='true'
  64. icon='mdi-alert'
  65. )
  66. span {{ $t('admin:locale.namespacingPrefixWarning.title', { langCode: selectedLocale }) }}
  67. .caption.grey--text {{ $t('admin:locale.namespacingPrefixWarning.subtitle') }}
  68. v-divider.mt-3.mb-4
  69. v-select(
  70. outlined
  71. :disabled='!namespacing'
  72. :items='installedLocales'
  73. prepend-icon='mdi-web'
  74. multiple
  75. chips
  76. deletable-chips
  77. v-model='namespaces'
  78. item-value='code'
  79. item-text='name'
  80. :label='$t("admin:locale.activeNamespaces.label")'
  81. persistent-hint
  82. small-chips
  83. :hint='$t("admin:locale.activeNamespaces.hint")'
  84. )
  85. template(slot='item', slot-scope='data')
  86. template(v-if='typeof data.item !== "object"')
  87. v-list-item-content(v-text='data.item')
  88. template(v-else)
  89. v-list-item-avatar
  90. v-avatar.blue.white--text(tile, size='40', v-html='data.item.code.toUpperCase()')
  91. v-list-item-content
  92. v-list-item-title(v-html='data.item.name')
  93. v-list-item-sub-title(v-html='data.item.nativeName')
  94. v-list-item-action
  95. v-checkbox(:input-value='data.tile.props.value', color='primary', value)
  96. v-flex(lg6 xs12)
  97. v-card.animated.fadeInUp.wait-p4s
  98. v-toolbar(color='teal', dark, dense, flat)
  99. v-toolbar-title.subtitle-1 {{ $t('admin:locale.downloadTitle') }}
  100. v-data-table(
  101. :headers='headers',
  102. :items='locales',
  103. hide-default-footer,
  104. item-key='code',
  105. :items-per-page='1000'
  106. )
  107. template(v-slot:item.code='{ item }')
  108. v-chip.white--text(label, color='teal', small) {{item.code}}
  109. template(v-slot:item.name='{ item }')
  110. strong {{item.name}}
  111. template(v-slot:item.isRTL='{ item }')
  112. v-icon(v-if='item.isRTL') mdi-check
  113. template(v-slot:item.availability='{ item }')
  114. .d-flex.align-center.pl-4
  115. v-progress-circular(:value='item.availability', width='2', size='20', :color='item.availability <= 33 ? `red` : (item.availability <= 66) ? `orange` : `green`')
  116. .caption.ml-2(:class='item.availability <= 33 ? `red--text` : (item.availability <= 66) ? `orange--text` : `green--text`') {{item.availability}}%
  117. template(v-slot:item.isInstalled='{ item }')
  118. v-progress-circular(v-if='item.isDownloading', indeterminate, color='blue', size='20', :width='2')
  119. v-btn(v-else-if='item.isInstalled && item.installDate < item.updatedAt', icon, small, @click='download(item)')
  120. v-icon.blue--text mdi-cached
  121. v-btn(v-else-if='item.isInstalled', icon, small, @click='download(item)')
  122. v-icon.green--text mdi-check
  123. v-btn(v-else, icon, small, @click='download(item)')
  124. v-icon.grey--text mdi-cloud-download
  125. v-card.wiki-form.mt-3.animated.fadeInUp.wait-p5s
  126. v-toolbar(color='teal', dark, dense, flat)
  127. v-toolbar-title.subtitle-1 {{ $t('admin:locale.sideload') }}
  128. v-spacer
  129. v-chip(label, color='white', small).teal--text coming soon
  130. v-card-text
  131. div {{ $t('admin:locale.sideloadHelp') }}
  132. v-btn.ml-0.mt-3(color='teal', disabled) {{ $t('common:actions.browse') }}
  133. </template>
  134. <script>
  135. import _ from 'lodash'
  136. /* global WIKI */
  137. import localesQuery from 'gql/admin/locale/locale-query-list.gql'
  138. import localesDownloadMutation from 'gql/admin/locale/locale-mutation-download.gql'
  139. import localesSaveMutation from 'gql/admin/locale/locale-mutation-save.gql'
  140. export default {
  141. data() {
  142. return {
  143. loading: false,
  144. locales: [],
  145. selectedLocale: 'en',
  146. autoUpdate: false,
  147. namespacing: false,
  148. namespaces: []
  149. }
  150. },
  151. computed: {
  152. installedLocales() {
  153. return _.filter(this.locales, ['isInstalled', true])
  154. },
  155. headers() {
  156. return [
  157. {
  158. text: this.$t('admin:locale.code'),
  159. align: 'left',
  160. value: 'code',
  161. width: 90
  162. },
  163. {
  164. text: this.$t('admin:locale.name'),
  165. align: 'left',
  166. value: 'name'
  167. },
  168. {
  169. text: this.$t('admin:locale.nativeName'),
  170. align: 'left',
  171. value: 'nativeName'
  172. },
  173. {
  174. text: this.$t('admin:locale.rtl'),
  175. align: 'center',
  176. value: 'isRTL',
  177. sortable: false,
  178. width: 10
  179. },
  180. {
  181. text: this.$t('admin:locale.availability'),
  182. align: 'center',
  183. value: 'availability',
  184. sortable: false,
  185. width: 100
  186. },
  187. {
  188. text: this.$t('admin:locale.download'),
  189. align: 'center',
  190. value: 'isInstalled',
  191. sortable: false,
  192. width: 100
  193. }
  194. ]
  195. }
  196. },
  197. methods: {
  198. async download(lc) {
  199. lc.isDownloading = true
  200. const respRaw = await this.$apollo.mutate({
  201. mutation: localesDownloadMutation,
  202. variables: {
  203. locale: lc.code
  204. }
  205. })
  206. const resp = _.get(respRaw, 'data.localization.downloadLocale.responseResult', {})
  207. if (resp.succeeded) {
  208. lc.isDownloading = false
  209. lc.isInstalled = true
  210. lc.updatedAt = new Date().toISOString()
  211. lc.installDate = lc.updatedAt
  212. this.$store.commit('showNotification', {
  213. message: `Locale ${lc.name} has been installed successfully.`,
  214. style: 'success',
  215. icon: 'get_app'
  216. })
  217. } else {
  218. this.$store.commit('showNotification', {
  219. message: `Error: ${resp.message}`,
  220. style: 'error',
  221. icon: 'warning'
  222. })
  223. }
  224. this.isDownloading = false
  225. },
  226. async save() {
  227. this.loading = true
  228. const respRaw = await this.$apollo.mutate({
  229. mutation: localesSaveMutation,
  230. variables: {
  231. locale: this.selectedLocale,
  232. autoUpdate: this.autoUpdate,
  233. namespacing: this.namespacing,
  234. namespaces: this.namespaces
  235. }
  236. })
  237. const resp = _.get(respRaw, 'data.localization.updateLocale.responseResult', {})
  238. if (resp.succeeded) {
  239. // Change UI language
  240. WIKI.$i18n.i18next.changeLanguage(this.selectedLocale)
  241. WIKI.$moment.locale(this.selectedLocale)
  242. // Check for RTL
  243. const curLocale = _.find(this.locales, ['code', this.selectedLocale])
  244. this.$vuetify.rtl = curLocale && curLocale.isRTL
  245. this.$store.commit('showNotification', {
  246. message: 'Locale settings updated successfully.',
  247. style: 'success',
  248. icon: 'check'
  249. })
  250. } else {
  251. this.$store.commit('showNotification', {
  252. message: `Error: ${resp.message}`,
  253. style: 'error',
  254. icon: 'warning'
  255. })
  256. }
  257. this.loading = false
  258. }
  259. },
  260. apollo: {
  261. locales: {
  262. query: localesQuery,
  263. fetchPolicy: 'network-only',
  264. update: (data) => data.localization.locales.map(lc => ({ ...lc, isDownloading: false })),
  265. watchLoading (isLoading) {
  266. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-locale-refresh')
  267. }
  268. },
  269. selectedLocale: {
  270. query: localesQuery,
  271. update: (data) => data.localization.config.locale
  272. },
  273. autoUpdate: {
  274. query: localesQuery,
  275. update: (data) => data.localization.config.autoUpdate
  276. },
  277. namespacing: {
  278. query: localesQuery,
  279. update: (data) => data.localization.config.namespacing
  280. },
  281. namespaces: {
  282. query: localesQuery,
  283. update: (data) => data.localization.config.namespaces
  284. }
  285. }
  286. }
  287. </script>