feat: locales availability + IE display mode
This commit is contained in:
57
.babelrc
57
.babelrc
@@ -16,13 +16,66 @@
|
|||||||
"@babel/plugin-proposal-function-sent",
|
"@babel/plugin-proposal-function-sent",
|
||||||
"@babel/plugin-proposal-export-namespace-from",
|
"@babel/plugin-proposal-export-namespace-from",
|
||||||
"@babel/plugin-proposal-numeric-separator",
|
"@babel/plugin-proposal-numeric-separator",
|
||||||
"@babel/plugin-proposal-throw-expressions"
|
"@babel/plugin-proposal-throw-expressions",
|
||||||
|
[
|
||||||
|
"prismjs", {
|
||||||
|
"languages": [
|
||||||
|
"markup",
|
||||||
|
"css",
|
||||||
|
"clike",
|
||||||
|
"javascript",
|
||||||
|
"c",
|
||||||
|
"bash",
|
||||||
|
"basic",
|
||||||
|
"cpp",
|
||||||
|
"csharp",
|
||||||
|
"arduino",
|
||||||
|
"ruby",
|
||||||
|
"elixir",
|
||||||
|
"fsharp",
|
||||||
|
"go",
|
||||||
|
"graphql",
|
||||||
|
"handlebars",
|
||||||
|
"haskell",
|
||||||
|
"ini",
|
||||||
|
"java",
|
||||||
|
"json",
|
||||||
|
"kotlin",
|
||||||
|
"latex",
|
||||||
|
"less",
|
||||||
|
"makefile",
|
||||||
|
"markdown",
|
||||||
|
"matlab",
|
||||||
|
"nginx",
|
||||||
|
"objectivec",
|
||||||
|
"perl",
|
||||||
|
"php",
|
||||||
|
"powershell",
|
||||||
|
"pug",
|
||||||
|
"python",
|
||||||
|
"typescript",
|
||||||
|
"rust",
|
||||||
|
"scss",
|
||||||
|
"scala",
|
||||||
|
"smalltalk",
|
||||||
|
"sql",
|
||||||
|
"stylus",
|
||||||
|
"swift",
|
||||||
|
"vbnet",
|
||||||
|
"yaml"
|
||||||
|
],
|
||||||
|
"plugins": ["line-numbers"],
|
||||||
|
"theme": "dark",
|
||||||
|
"css": true
|
||||||
|
}
|
||||||
|
]
|
||||||
],
|
],
|
||||||
"presets": [
|
"presets": [
|
||||||
[
|
[
|
||||||
"@babel/preset-env", {
|
"@babel/preset-env", {
|
||||||
"useBuiltIns": "entry",
|
"useBuiltIns": "entry",
|
||||||
"corejs": 3
|
"corejs": 3,
|
||||||
|
"debug": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,6 +19,7 @@ npm-debug.log*
|
|||||||
# Generated assets
|
# Generated assets
|
||||||
/assets
|
/assets
|
||||||
server/views/master.pug
|
server/views/master.pug
|
||||||
|
server/views/legacy.pug
|
||||||
server/views/setup.pug
|
server/views/setup.pug
|
||||||
|
|
||||||
# Webpack
|
# Webpack
|
||||||
|
|||||||
@@ -52,8 +52,6 @@
|
|||||||
v-toolbar(color='primary', dark, dense, flat)
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
.subheading {{ $t('admin:locale.namespacing') }}
|
.subheading {{ $t('admin:locale.namespacing') }}
|
||||||
v-spacer
|
|
||||||
v-chip(label, color='white', small).primary--text coming soon
|
|
||||||
v-card-text
|
v-card-text
|
||||||
v-switch(
|
v-switch(
|
||||||
v-model='namespacing'
|
v-model='namespacing'
|
||||||
@@ -102,28 +100,35 @@
|
|||||||
v-card.animated.fadeInUp.wait-p4s
|
v-card.animated.fadeInUp.wait-p4s
|
||||||
v-toolbar(color='teal', dark, dense, flat)
|
v-toolbar(color='teal', dark, dense, flat)
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
.subheading {{ $t('admin:locale.download') }}
|
.subheading {{ $t('admin:locale.downloadTitle') }}
|
||||||
v-list(two-line, dense)
|
v-data-table(
|
||||||
template(v-for='(lc, idx) in locales')
|
:headers='headers',
|
||||||
v-list-tile(:key='lc.code')
|
:items='locales',
|
||||||
v-list-tile-avatar
|
hide-actions,
|
||||||
v-avatar.teal.white--text(size='40') {{lc.code.toUpperCase()}}
|
item-key='code',
|
||||||
v-list-tile-content
|
:rows-per-page-items='[-1]'
|
||||||
v-list-tile-title(v-html='lc.name')
|
)
|
||||||
v-list-tile-sub-title(v-html='lc.nativeName')
|
template(v-slot:items='lc')
|
||||||
v-list-tile-action(v-if='lc.isRTL')
|
td
|
||||||
v-chip(label, small, :class='$vuetify.dark ? `text--lighten-5` : `text--darken-2`').caption.grey--text RTL
|
v-chip.white--text(label, color='teal', small) {{lc.item.code}}
|
||||||
v-list-tile-action(v-if='lc.isInstalled && lc.installDate < lc.updatedAt')
|
td
|
||||||
v-btn(icon, @click='download(lc)')
|
strong {{lc.item.name}}
|
||||||
v-icon.blue--text cached
|
td
|
||||||
v-list-tile-action(v-else-if='lc.isInstalled')
|
span {{ lc.item.nativeName }}
|
||||||
|
td.text-xs-center
|
||||||
|
v-icon(v-if='lc.item.isRTL') check
|
||||||
|
td
|
||||||
|
.d-flex.align-center.pl-4
|
||||||
|
.caption.mr-2(:class='lc.item.availability <= 33 ? `red--text` : (lc.item.availability <= 66) ? `orange--text` : `green--text`') {{lc.item.availability}}%
|
||||||
|
v-progress-circular(:value='lc.item.availability', width='2', size='20', :color='lc.item.availability <= 33 ? `red` : (lc.item.availability <= 66) ? `orange` : `green`')
|
||||||
|
td.text-xs-center
|
||||||
|
v-progress-circular(v-if='lc.item.isDownloading', indeterminate, color='blue', size='20', :width='2')
|
||||||
|
v-btn(v-else-if='lc.item.isInstalled && lc.item.installDate < lc.item.updatedAt', icon, @click='download(lc.item)')
|
||||||
|
v-icon.blue--text cached
|
||||||
|
v-btn(v-else-if='lc.item.isInstalled', icon, @click='download(lc.item)')
|
||||||
v-icon.green--text check
|
v-icon.green--text check
|
||||||
v-list-tile-action(v-else-if='lc.isDownloading')
|
v-btn(v-else, icon, @click='download(lc.item)')
|
||||||
v-progress-circular(indeterminate, color='blue', size='20', :width='3')
|
v-icon.grey--text cloud_download
|
||||||
v-list-tile-action(v-else)
|
|
||||||
v-btn(icon, @click='download(lc)')
|
|
||||||
v-icon.grey--text cloud_download
|
|
||||||
v-divider.my-0(inset, v-if='idx < locales.length - 1')
|
|
||||||
v-card.wiki-form.mt-3.animated.fadeInUp.wait-p5s
|
v-card.wiki-form.mt-3.animated.fadeInUp.wait-p5s
|
||||||
v-toolbar(color='teal', dark, dense, flat)
|
v-toolbar(color='teal', dark, dense, flat)
|
||||||
v-toolbar-title
|
v-toolbar-title
|
||||||
@@ -158,6 +163,46 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
installedLocales() {
|
installedLocales() {
|
||||||
return _.filter(this.locales, ['isInstalled', true])
|
return _.filter(this.locales, ['isInstalled', true])
|
||||||
|
},
|
||||||
|
headers() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: this.$t('admin:locale.code'),
|
||||||
|
align: 'left',
|
||||||
|
value: 'code',
|
||||||
|
width: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$t('admin:locale.name'),
|
||||||
|
align: 'left',
|
||||||
|
value: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$t('admin:locale.nativeName'),
|
||||||
|
align: 'left',
|
||||||
|
value: 'nativeName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$t('admin:locale.rtl'),
|
||||||
|
align: 'center',
|
||||||
|
value: 'isRTL',
|
||||||
|
sortable: false,
|
||||||
|
width: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$t('admin:locale.availability'),
|
||||||
|
align: 'center',
|
||||||
|
value: 'availability',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$t('admin:locale.download'),
|
||||||
|
align: 'center',
|
||||||
|
value: 'code',
|
||||||
|
sortable: false,
|
||||||
|
width: 100
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -173,6 +218,8 @@ export default {
|
|||||||
if (resp.succeeded) {
|
if (resp.succeeded) {
|
||||||
lc.isDownloading = false
|
lc.isDownloading = false
|
||||||
lc.isInstalled = true
|
lc.isInstalled = true
|
||||||
|
lc.updatedAt = new Date().toISOString()
|
||||||
|
lc.installDate = lc.updatedAt
|
||||||
this.$store.commit('showNotification', {
|
this.$store.commit('showNotification', {
|
||||||
message: `Locale ${lc.name} has been installed successfully.`,
|
message: `Locale ${lc.name} has been installed successfully.`,
|
||||||
style: 'success',
|
style: 'success',
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
v-toolbar(flat, color='primary', dark, dense)
|
v-toolbar(flat, color='primary', dark, dense)
|
||||||
.subheading {{ $t('admin:utilities.authTitle') }}
|
.subheading {{ $t('admin:utilities.authTitle') }}
|
||||||
v-card-text
|
v-card-text
|
||||||
v-subheader.pl-0 Generate New Authentication Public / Private Key Certificates
|
v-subheader.pl-0.primary--text Generate New Authentication Public / Private Key Certificates
|
||||||
.body-1 This will invalidate all current session tokens and cause all users to be logged out.
|
.body-1 This will invalidate all current session tokens and cause all users to be logged out.
|
||||||
.body-1.red--text You will need to log back in after the operation.
|
.body-1.red--text You will need to log back in after the operation.
|
||||||
v-btn(outline, color='primary', @click='regenCerts', :disabled='loading').ml-0.mt-3
|
v-btn(outline, color='primary', @click='regenCerts', :disabled='loading').ml-0.mt-3
|
||||||
v-icon(left) build
|
v-icon(left) build
|
||||||
span Proceed
|
span Proceed
|
||||||
v-divider.my-3
|
v-divider.my-3
|
||||||
v-subheader.pl-0 Reset Guest User
|
v-subheader.pl-0.primary--text Reset Guest User
|
||||||
.body-1 This will reset the guest user to its default parameters and permissions.
|
.body-1 This will reset the guest user to its default parameters and permissions.
|
||||||
v-btn(outline, color='primary', @click='resetGuest', :disabled='loading').ml-0.mt-3
|
v-btn(outline, color='primary', @click='resetGuest', :disabled='loading').ml-0.mt-3
|
||||||
v-icon(left) build
|
v-icon(left) build
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
v-toolbar(flat, color='primary', dark, dense)
|
v-toolbar(flat, color='primary', dark, dense)
|
||||||
.subheading {{ $t('admin:utilities.cacheTitle') }}
|
.subheading {{ $t('admin:utilities.cacheTitle') }}
|
||||||
v-card-text
|
v-card-text
|
||||||
v-subheader.pl-0 Flush Pages and Assets Cache
|
v-subheader.pl-0.primary--text Flush Pages and Assets Cache
|
||||||
.body-1 Pages and Assets are cached to disk for better performance. You can flush the cache to force all content to be fetched from the DB again.
|
.body-1 Pages and Assets are cached to disk for better performance. You can flush the cache to force all content to be fetched from the DB again.
|
||||||
v-btn(outline, color='primary', @click='flushCache', :disabled='loading').ml-0.mt-3
|
v-btn(outline, color='primary', @click='flushCache', :disabled='loading').ml-0.mt-3
|
||||||
v-icon(left) build
|
v-icon(left) build
|
||||||
span Proceed
|
span Proceed
|
||||||
v-divider.my-3
|
v-divider.my-3
|
||||||
v-subheader.pl-0 Flush Temporary Uploads
|
v-subheader.pl-0.primary--text Flush Temporary Uploads
|
||||||
.body-1 New uploads are temporarily saved to disk while they are being processed. They are automatically deleted after processing, but you can force an immediate cleanup using this tool.
|
.body-1 New uploads are temporarily saved to disk while they are being processed. They are automatically deleted after processing, but you can force an immediate cleanup using this tool.
|
||||||
.body-1.red--text Note that performing this action while an upload is in progress can result in a failed upload.
|
.body-1.red--text Note that performing this action while an upload is in progress can result in a failed upload.
|
||||||
v-btn(outline, color='primary', @click='flushUploads', :disabled='loading').ml-0.mt-3
|
v-btn(outline, color='primary', @click='flushUploads', :disabled='loading').ml-0.mt-3
|
||||||
|
|||||||
68
client/components/admin/admin-utilities-content.vue
Normal file
68
client/components/admin/admin-utilities-content.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<template lang='pug'>
|
||||||
|
v-card
|
||||||
|
v-toolbar(flat, color='primary', dark, dense)
|
||||||
|
.subheading {{ $t('admin:utilities.contentTitle') }}
|
||||||
|
v-card-text
|
||||||
|
v-subheader.pl-0.primary--text Migrate all pages to base language
|
||||||
|
.body-1 If you created content before selecting a different locale and activating the namespacing capabilities, you may want to transfer all content to the base locale.
|
||||||
|
.body-1.red--text: strong This operation is destructive and cannot be reversed! Make sure you have proper backups!
|
||||||
|
.body-1.mt-3 Based on your current configuration, all pages will be migrated to the locale #[v-chip(label, small): strong {{currentLocale.toUpperCase()}}]
|
||||||
|
.body-1.mt-3 Pages that are already in the target locale will not be touched. If a page already exists at the target, the source page will not be modified as it would create a conflict. If you want to overwrite the target content, you must first delete that page.
|
||||||
|
v-btn(outline, color='primary', @click='migrateToLocale', :disabled='loading').ml-0.mt-3
|
||||||
|
v-icon(left) build
|
||||||
|
span Proceed
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import utilityContentMigrateLocaleMutation from 'gql/admin/utilities/utilities-mutation-content-migratelocale.gql'
|
||||||
|
|
||||||
|
/* global siteLang */
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentLocale() {
|
||||||
|
return siteConfig.lang
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async migrateToLocale() {
|
||||||
|
this.loading = true
|
||||||
|
this.$store.commit(`loadingStart`, 'admin-utilities-content-migratelocale')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const respRaw = await this.$apollo.mutate({
|
||||||
|
mutation: utilityContentMigrateLocaleMutation,
|
||||||
|
variables: {
|
||||||
|
targetLocale: siteConfig.lang
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const resp = _.get(respRaw, 'data.pages.migrateToLocale.responseResult', {})
|
||||||
|
if (resp.succeeded) {
|
||||||
|
this.$store.commit('showNotification', {
|
||||||
|
message: 'Migrated all content to target locale successfully.',
|
||||||
|
style: 'success',
|
||||||
|
icon: 'check'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(resp.message)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.$store.commit('pushGraphError', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.commit(`loadingStop`, 'admin-utilities-content-migratelocale')
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang='scss'>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
UtilityAuth: () => import(/* webpackChunkName: "admin" */ './admin-utilities-auth.vue'),
|
UtilityAuth: () => import(/* webpackChunkName: "admin" */ './admin-utilities-auth.vue'),
|
||||||
|
UtilityContent: () => import(/* webpackChunkName: "admin" */ './admin-utilities-content.vue'),
|
||||||
UtilityCache: () => import(/* webpackChunkName: "admin" */ './admin-utilities-cache.vue'),
|
UtilityCache: () => import(/* webpackChunkName: "admin" */ './admin-utilities-cache.vue'),
|
||||||
UtilityImportv1: () => import(/* webpackChunkName: "admin" */ './admin-utilities-importv1.vue'),
|
UtilityImportv1: () => import(/* webpackChunkName: "admin" */ './admin-utilities-importv1.vue'),
|
||||||
UtilityTelemetry: () => import(/* webpackChunkName: "admin" */ './admin-utilities-telemetry.vue')
|
UtilityTelemetry: () => import(/* webpackChunkName: "admin" */ './admin-utilities-telemetry.vue')
|
||||||
@@ -49,6 +50,12 @@ export default {
|
|||||||
i18nKey: 'auth',
|
i18nKey: 'auth',
|
||||||
isAvailable: true
|
isAvailable: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'UtilityContent',
|
||||||
|
icon: 'insert_drive_file',
|
||||||
|
i18nKey: 'content',
|
||||||
|
isAvailable: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'UtilityCache',
|
key: 'UtilityCache',
|
||||||
icon: 'invert_colors',
|
icon: 'invert_colors',
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export default {
|
|||||||
return this.response.suggestions ? this.response.suggestions : []
|
return this.response.suggestions ? this.response.suggestions : []
|
||||||
},
|
},
|
||||||
paginationLength() {
|
paginationLength() {
|
||||||
return this.response.totalHits > 0 ? 0 : Math.ceil(this.response.totalHits / 10)
|
return (this.response.totalHits > 0) ? 0 : Math.ceil(this.response.totalHits / 10)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -107,7 +107,7 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$root.$on('searchMove', (dir) => {
|
this.$root.$on('searchMove', (dir) => {
|
||||||
this.cursor += (dir === 'up' ? -1 : 1)
|
this.cursor += ((dir === 'up') ? -1 : 1)
|
||||||
if (this.cursor < -1) {
|
if (this.cursor < -1) {
|
||||||
this.cursor = -1
|
this.cursor = -1
|
||||||
} else if (this.cursor > this.results.length + this.suggestions.length - 1) {
|
} else if (this.cursor > this.results.length + this.suggestions.length - 1) {
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ import mdMark from 'markdown-it-mark'
|
|||||||
import mdImsize from 'markdown-it-imsize'
|
import mdImsize from 'markdown-it-imsize'
|
||||||
|
|
||||||
// Prism (Syntax Highlighting)
|
// Prism (Syntax Highlighting)
|
||||||
import Prism from '@/libs/prism/prism.js'
|
import Prism from 'prismjs'
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// INIT
|
// INIT
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
localization {
|
localization {
|
||||||
locales {
|
locales {
|
||||||
|
availability
|
||||||
code
|
code
|
||||||
createdAt
|
createdAt
|
||||||
isInstalled
|
isInstalled
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
mutation {
|
||||||
|
pages {
|
||||||
|
migrateToLocale {
|
||||||
|
responseResult {
|
||||||
|
succeeded
|
||||||
|
errorCode
|
||||||
|
slug
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
client/index-legacy.js
Normal file
3
client/index-legacy.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
require('./scss/legacy.scss')
|
||||||
|
|
||||||
|
window.WIKI = null
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
require('@babel/polyfill')
|
require('core-js/stable')
|
||||||
|
require('regenerator-runtime/runtime')
|
||||||
|
|
||||||
require('vuetify/src/stylus/main.styl')
|
require('vuetify/src/stylus/main.styl')
|
||||||
require('./scss/app.scss')
|
require('./scss/app.scss')
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
@import 'layout/md2';
|
@import 'layout/md2';
|
||||||
|
|
||||||
// @import '../libs/twemoji/twemoji-awesome';
|
// @import '../libs/twemoji/twemoji-awesome';
|
||||||
@import '../libs/prism/prism.css';
|
// @import '../libs/prism/prism.css';
|
||||||
@import '~vue-tour/dist/vue-tour.css';
|
@import '~vue-tour/dist/vue-tour.css';
|
||||||
@import '~vue-status-indicator/styles.css';
|
@import '~vue-status-indicator/styles.css';
|
||||||
@import '~xterm/dist/xterm.css';
|
@import '~xterm/dist/xterm.css';
|
||||||
|
|||||||
218
client/scss/legacy.scss
Normal file
218
client/scss/legacy.scss
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
@import "global";
|
||||||
|
|
||||||
|
@import "./base/fonts.scss";
|
||||||
|
@import "./base/icons.scss";
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: mc('grey', '50');
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Roboto",sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background-color: #000;
|
||||||
|
color: #FFF;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: .02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-deprecated {
|
||||||
|
color: mc('red', '100');
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: mc('pink', '400');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-login {
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #FFF;
|
||||||
|
transition: color .3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: mc('blue', '500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
min-height: calc(100vh - 64px);
|
||||||
|
height: 50vh;
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 300px;
|
||||||
|
background-color: mc('blue', '700');
|
||||||
|
color: #FFF;
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
|
.sidebar-link {
|
||||||
|
height: 40px;
|
||||||
|
font-size: 13px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 16px;
|
||||||
|
transition: background .3s cubic-bezier(.25,.8,.5,1);
|
||||||
|
font-weight: 400;
|
||||||
|
color: #FFF;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: hsla(0,0%,100%,.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i.material-icons {
|
||||||
|
width: 56px;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-divider {
|
||||||
|
border-top: 1px solid hsla(0,0%,100%,.12);
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-title {
|
||||||
|
font-size: 13px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 16px 0 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: hsla(0,0%,100%,.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
background-color: mc('grey', '100');
|
||||||
|
padding: 0 24px;
|
||||||
|
height: 90px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid mc('grey', '200');
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 32px;
|
||||||
|
color: mc('grey', '800');
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: mc('grey', '600');
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-left {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-right {
|
||||||
|
flex: 0 0 324px;
|
||||||
|
padding-left: 16px;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
color: mc('grey', '500');
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
&-author {
|
||||||
|
color: mc('grey', '800');
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
&-updated {
|
||||||
|
color: mc('grey', '600');
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-contents {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc {
|
||||||
|
flex: 0 0 348px;
|
||||||
|
background-color: mc('grey', '200');
|
||||||
|
padding: 4px 0;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
font-size: 13px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
color: mc('blue', '600');
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-tile {
|
||||||
|
text-decoration: none;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
font-size: 13px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 16px;
|
||||||
|
color: mc('grey', '800');
|
||||||
|
transition: background-color .3s ease;
|
||||||
|
|
||||||
|
&.inset {
|
||||||
|
padding-left: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-divider {
|
||||||
|
border-top: 1px solid rgba(0,0,0,.12);
|
||||||
|
margin: 0 0 0 24px;
|
||||||
|
|
||||||
|
&.inset {
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "../themes/default/scss/app.scss";
|
||||||
|
|
||||||
|
.contents {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { StatusIndicator } from 'vue-status-indicator'
|
import { StatusIndicator } from 'vue-status-indicator'
|
||||||
import Prism from '@/libs/prism/prism.js'
|
import Prism from 'prismjs'
|
||||||
import { get } from 'vuex-pathify'
|
import { get } from 'vuex-pathify'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
|||||||
127
dev/templates/legacy.pug
Normal file
127
dev/templates/legacy.pug
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
doctype html
|
||||||
|
html
|
||||||
|
head
|
||||||
|
meta(http-equiv='X-UA-Compatible', content='IE=edge')
|
||||||
|
meta(charset='UTF-8')
|
||||||
|
meta(name='viewport', content='user-scalable=yes, width=device-width, initial-scale=1, maximum-scale=5')
|
||||||
|
meta(name='theme-color', content='#333333')
|
||||||
|
meta(name='msapplication-TileColor', content='#333333')
|
||||||
|
meta(name='msapplication-TileImage', content='/favicons/ms-icon-144x144.png')
|
||||||
|
|
||||||
|
title= pageMeta.title + ' | ' + config.title
|
||||||
|
|
||||||
|
//- SEO / OpenGraph
|
||||||
|
meta(name='description', content=pageMeta.description)
|
||||||
|
meta(property='og:title', content=pageMeta.title)
|
||||||
|
meta(property='og:type', content='website')
|
||||||
|
meta(property='og:description', content=pageMeta.description)
|
||||||
|
meta(property='og:image', content=pageMeta.image)
|
||||||
|
meta(property='og:url', content=pageMeta.url)
|
||||||
|
meta(property='og:site_name', content=config.title)
|
||||||
|
|
||||||
|
//- Favicon
|
||||||
|
each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
|
||||||
|
link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href='/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
|
||||||
|
link(rel='icon', type='image/png', sizes='192x192', href='/favicons/android-icon-192x192.png')
|
||||||
|
each favsize in [32, 96, 16]
|
||||||
|
link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
|
||||||
|
link(rel='manifest', href='/manifest.json')
|
||||||
|
|
||||||
|
//- CSS
|
||||||
|
<% for (var index in htmlWebpackPlugin.files.css) { %>
|
||||||
|
<% if (htmlWebpackPlugin.files.cssIntegrity) { %>
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='<%= htmlWebpackPlugin.files.css[index] %>'
|
||||||
|
integrity='<%= htmlWebpackPlugin.files.cssIntegrity[index] %>'
|
||||||
|
crossorigin='<%= webpackConfig.output.crossOriginLoading %>'
|
||||||
|
)
|
||||||
|
<% } else { %>
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='<%= htmlWebpackPlugin.files.css[index] %>'
|
||||||
|
)
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
script(
|
||||||
|
crossorigin='anonymous'
|
||||||
|
src='https://polyfill.io/v3/polyfill.min.js?features=EventSource'
|
||||||
|
)
|
||||||
|
|
||||||
|
//- JS
|
||||||
|
<% for (var index in htmlWebpackPlugin.files.js) { %>
|
||||||
|
<% if (htmlWebpackPlugin.files.cssIntegrity) { %>
|
||||||
|
script(
|
||||||
|
type='text/javascript'
|
||||||
|
src='<%= htmlWebpackPlugin.files.js[index] %>'
|
||||||
|
integrity='<%= htmlWebpackPlugin.files.jsIntegrity[index] %>'
|
||||||
|
crossorigin='<%= webpackConfig.output.crossOriginLoading %>'
|
||||||
|
)
|
||||||
|
<% } else { %>
|
||||||
|
script(
|
||||||
|
type='text/javascript'
|
||||||
|
src='<%= htmlWebpackPlugin.files.js[index] %>'
|
||||||
|
)
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
!= analyticsCode.head
|
||||||
|
|
||||||
|
if injectCode.css
|
||||||
|
style(type='text/css')!= injectCode.css
|
||||||
|
if injectCode.head
|
||||||
|
!= injectCode.head
|
||||||
|
|
||||||
|
body
|
||||||
|
!= analyticsCode.bodyStart
|
||||||
|
#root
|
||||||
|
.header
|
||||||
|
span.header-title= siteConfig.title
|
||||||
|
span.header-deprecated Your browser is outdated. Upgrade to a #[a(href='https://bestvpn.org/outdatedbrowser/en', rel='nofollow') modern browser].
|
||||||
|
span.header-login
|
||||||
|
a(href='/login')
|
||||||
|
i.material-icons account_circle
|
||||||
|
.main
|
||||||
|
.sidebar
|
||||||
|
each navItem in sidebar
|
||||||
|
if navItem.kind === 'link'
|
||||||
|
a.sidebar-link(href=navItem.target)
|
||||||
|
i.material-icons= navItem.icon
|
||||||
|
span= navItem.label
|
||||||
|
else if navItem.kind === 'divider'
|
||||||
|
.sidebar-divider
|
||||||
|
else if navItem.kind === 'header'
|
||||||
|
.sidebar-title= navItem.label
|
||||||
|
.main-container
|
||||||
|
.page-header
|
||||||
|
.page-header-left
|
||||||
|
h1= page.title
|
||||||
|
h2= page.description
|
||||||
|
.page-header-right
|
||||||
|
.page-header-right-title Last edited by
|
||||||
|
.page-header-right-author= page.authorName
|
||||||
|
.page-header-right-updated= page.updatedAt
|
||||||
|
.page-contents
|
||||||
|
.contents
|
||||||
|
div!= page.render
|
||||||
|
if page.toc.length
|
||||||
|
.toc
|
||||||
|
.toc-title Table of Contents
|
||||||
|
each tocItem, tocIdx in page.toc
|
||||||
|
a.toc-tile(href='#' + tocItem.anchor)
|
||||||
|
i.material-icons arrow_right
|
||||||
|
span= tocItem.title
|
||||||
|
if tocIdx < page.toc.length - 1 || tocItem.children.length
|
||||||
|
.toc-divider
|
||||||
|
each tocSubItem in tocItem.children
|
||||||
|
a.toc-tile.inset(href='#' + tocSubItem.anchor)
|
||||||
|
i.material-icons arrow_right
|
||||||
|
span= tocSubItem.title
|
||||||
|
if tocIdx < page.toc.length - 1
|
||||||
|
.toc-divider.inset
|
||||||
|
if injectCode.body
|
||||||
|
!= injectCode.body
|
||||||
|
!= analyticsCode.bodyEnd
|
||||||
@@ -24,6 +24,7 @@ module.exports = {
|
|||||||
mode: 'development',
|
mode: 'development',
|
||||||
entry: {
|
entry: {
|
||||||
app: ['./client/index-app.js', 'webpack-hot-middleware/client'],
|
app: ['./client/index-app.js', 'webpack-hot-middleware/client'],
|
||||||
|
legacy: ['./client/index-legacy.js', 'webpack-hot-middleware/client'],
|
||||||
setup: ['./client/index-setup.js', 'webpack-hot-middleware/client']
|
setup: ['./client/index-setup.js', 'webpack-hot-middleware/client']
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
@@ -194,14 +195,21 @@ module.exports = {
|
|||||||
filename: '../server/views/master.pug',
|
filename: '../server/views/master.pug',
|
||||||
hash: false,
|
hash: false,
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['setup']
|
excludeChunks: ['setup', 'legacy']
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: 'dev/templates/legacy.pug',
|
||||||
|
filename: '../server/views/legacy.pug',
|
||||||
|
hash: false,
|
||||||
|
inject: false,
|
||||||
|
excludeChunks: ['setup', 'app']
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: 'dev/templates/setup.pug',
|
template: 'dev/templates/setup.pug',
|
||||||
filename: '../server/views/setup.pug',
|
filename: '../server/views/setup.pug',
|
||||||
hash: false,
|
hash: false,
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['app']
|
excludeChunks: ['app', 'legacy']
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPugPlugin(),
|
new HtmlWebpackPugPlugin(),
|
||||||
new SriWebpackPlugin({
|
new SriWebpackPlugin({
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ module.exports = {
|
|||||||
mode: 'production',
|
mode: 'production',
|
||||||
entry: {
|
entry: {
|
||||||
app: './client/index-app.js',
|
app: './client/index-app.js',
|
||||||
|
legacy: './client/index-legacy.js',
|
||||||
setup: './client/index-setup.js'
|
setup: './client/index-setup.js'
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
@@ -204,14 +205,21 @@ module.exports = {
|
|||||||
filename: '../server/views/master.pug',
|
filename: '../server/views/master.pug',
|
||||||
hash: false,
|
hash: false,
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['setup']
|
excludeChunks: ['setup', 'legacy']
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: 'dev/templates/legacy.pug',
|
||||||
|
filename: '../server/views/legacy.pug',
|
||||||
|
hash: false,
|
||||||
|
inject: false,
|
||||||
|
excludeChunks: ['setup', 'app']
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: 'dev/templates/setup.pug',
|
template: 'dev/templates/setup.pug',
|
||||||
filename: '../server/views/setup.pug',
|
filename: '../server/views/setup.pug',
|
||||||
hash: false,
|
hash: false,
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['app']
|
excludeChunks: ['app', 'legacy']
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPugPlugin(),
|
new HtmlWebpackPugPlugin(),
|
||||||
new ScriptExtHtmlWebpackPlugin({
|
new ScriptExtHtmlWebpackPlugin({
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -180,6 +180,7 @@
|
|||||||
"@babel/polyfill": "^7.4.4",
|
"@babel/polyfill": "^7.4.4",
|
||||||
"@babel/preset-env": "^7.4.5",
|
"@babel/preset-env": "^7.4.5",
|
||||||
"@panter/vue-i18next": "0.15.1",
|
"@panter/vue-i18next": "0.15.1",
|
||||||
|
"@vue/babel-preset-app": "3.9.2",
|
||||||
"animate-sass": "0.8.2",
|
"animate-sass": "0.8.2",
|
||||||
"animated-number-vue": "0.1.5",
|
"animated-number-vue": "0.1.5",
|
||||||
"apollo-cache-inmemory": "1.6.2",
|
"apollo-cache-inmemory": "1.6.2",
|
||||||
@@ -197,6 +198,7 @@
|
|||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-graphql-tag": "2.4.0",
|
"babel-plugin-graphql-tag": "2.4.0",
|
||||||
"babel-plugin-lodash": "3.3.4",
|
"babel-plugin-lodash": "3.3.4",
|
||||||
|
"babel-plugin-prismjs": "1.0.2",
|
||||||
"babel-plugin-transform-imports": "1.5.1",
|
"babel-plugin-transform-imports": "1.5.1",
|
||||||
"brace": "0.11.1",
|
"brace": "0.11.1",
|
||||||
"cache-loader": "4.0.0",
|
"cache-loader": "4.0.0",
|
||||||
@@ -243,6 +245,7 @@
|
|||||||
"postcss-loader": "3.0.0",
|
"postcss-loader": "3.0.0",
|
||||||
"postcss-preset-env": "6.6.0",
|
"postcss-preset-env": "6.6.0",
|
||||||
"postcss-selector-parser": "6.0.2",
|
"postcss-selector-parser": "6.0.2",
|
||||||
|
"prismjs": "1.16.0",
|
||||||
"pug-lint": "2.5.0",
|
"pug-lint": "2.5.0",
|
||||||
"pug-loader": "2.4.0",
|
"pug-loader": "2.4.0",
|
||||||
"pug-plain-loader": "1.0.0",
|
"pug-plain-loader": "1.0.0",
|
||||||
@@ -299,9 +302,12 @@
|
|||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 major versions",
|
||||||
"Firefox ESR",
|
"Firefox ESR",
|
||||||
"not ie < 11"
|
"not ie > 0",
|
||||||
|
"not ie_mob > 0",
|
||||||
|
"not android > 0",
|
||||||
|
"not dead"
|
||||||
],
|
],
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"plugins": {
|
"plugins": {
|
||||||
|
|||||||
@@ -195,7 +195,15 @@ router.get('/*', async (req, res, next) => {
|
|||||||
head: WIKI.config.theming.injectHead,
|
head: WIKI.config.theming.injectHead,
|
||||||
body: WIKI.config.theming.injectBody
|
body: WIKI.config.theming.injectBody
|
||||||
}
|
}
|
||||||
res.render('page', { page, sidebar, injectCode })
|
|
||||||
|
if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
|
||||||
|
if (_.isString(page.toc)) {
|
||||||
|
page.toc = JSON.parse(page.toc)
|
||||||
|
}
|
||||||
|
res.render('legacy', { page, sidebar, injectCode })
|
||||||
|
} else {
|
||||||
|
res.render('page', { page, sidebar, injectCode })
|
||||||
|
}
|
||||||
} else if (pageArgs.path === 'home') {
|
} else if (pageArgs.path === 'home') {
|
||||||
_.set(res.locals, 'pageMeta.title', 'Welcome')
|
_.set(res.locals, 'pageMeta.title', 'Welcome')
|
||||||
res.render('welcome')
|
res.render('welcome')
|
||||||
|
|||||||
13
server/db/migrations-sqlite/2.0.0-beta.217.js
Normal file
13
server/db/migrations-sqlite/2.0.0-beta.217.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
exports.up = knex => {
|
||||||
|
return knex.schema
|
||||||
|
.table('locales', table => {
|
||||||
|
table.integer('availability').notNullable().defaultTo(0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = knex => {
|
||||||
|
return knex.schema
|
||||||
|
.table('locales', table => {
|
||||||
|
table.dropColumn('availability')
|
||||||
|
})
|
||||||
|
}
|
||||||
13
server/db/migrations/2.0.0-beta.217.js
Normal file
13
server/db/migrations/2.0.0-beta.217.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
exports.up = knex => {
|
||||||
|
return knex.schema
|
||||||
|
.table('locales', table => {
|
||||||
|
table.integer('availability').notNullable().defaultTo(0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = knex => {
|
||||||
|
return knex.schema
|
||||||
|
.table('locales', table => {
|
||||||
|
table.dropColumn('availability')
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ module.exports = {
|
|||||||
LocalizationQuery: {
|
LocalizationQuery: {
|
||||||
async locales(obj, args, context, info) {
|
async locales(obj, args, context, info) {
|
||||||
let remoteLocales = await WIKI.cache.get('locales')
|
let remoteLocales = await WIKI.cache.get('locales')
|
||||||
let localLocales = await WIKI.models.locales.query().select('code', 'isRTL', 'name', 'nativeName', 'createdAt', 'updatedAt')
|
let localLocales = await WIKI.models.locales.query().select('code', 'isRTL', 'name', 'nativeName', 'createdAt', 'updatedAt', 'availability')
|
||||||
remoteLocales = remoteLocales || localLocales
|
remoteLocales = remoteLocales || localLocales
|
||||||
return _.map(remoteLocales, rl => {
|
return _.map(remoteLocales, rl => {
|
||||||
let isInstalled = _.some(localLocales, ['code', rl.code])
|
let isInstalled = _.some(localLocales, ['code', rl.code])
|
||||||
|
|||||||
@@ -95,6 +95,16 @@ module.exports = {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
return graphHelper.generateError(err)
|
return graphHelper.generateError(err)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async migrateToLocale(obj, args, context) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
return {
|
||||||
|
responseResult: graphHelper.generateSuccess('Migrated all content to target locale successfully.')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return graphHelper.generateError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Page: {
|
Page: {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type LocalizationMutation {
|
|||||||
# -----------------------------------------------
|
# -----------------------------------------------
|
||||||
|
|
||||||
type LocalizationLocale {
|
type LocalizationLocale {
|
||||||
|
availability: Int!
|
||||||
code: String!
|
code: String!
|
||||||
createdAt: Date!
|
createdAt: Date!
|
||||||
installDate: Date
|
installDate: Date
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ type PageMutation {
|
|||||||
): DefaultResponse @auth(requires: ["delete:pages", "manage:system"])
|
): DefaultResponse @auth(requires: ["delete:pages", "manage:system"])
|
||||||
|
|
||||||
flushCache: DefaultResponse @auth(requires: ["manage:system"])
|
flushCache: DefaultResponse @auth(requires: ["manage:system"])
|
||||||
|
|
||||||
|
migrateToLocale: DefaultResponse @auth(requires: ["manage:system"])
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------
|
# -----------------------------------------------
|
||||||
|
|||||||
@@ -28,21 +28,30 @@ module.exports = async (localeCode) => {
|
|||||||
let lcObj = {}
|
let lcObj = {}
|
||||||
_.forEach(strings, row => {
|
_.forEach(strings, row => {
|
||||||
if (_.includes(row.key, '::')) { return }
|
if (_.includes(row.key, '::')) { return }
|
||||||
if (_.isEmpty(row.value)) { row.value = row.key }
|
if (_.isEmpty(row.value)) {
|
||||||
|
row.value = row.key
|
||||||
|
}
|
||||||
_.set(lcObj, row.key.replace(':', '.'), row.value)
|
_.set(lcObj, row.key.replace(':', '.'), row.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
const locales = await WIKI.cache.get('locales')
|
const locales = await WIKI.cache.get('locales')
|
||||||
if (locales) {
|
if (locales) {
|
||||||
const currentLocale = _.find(locales, ['code', localeCode]) || {}
|
const currentLocale = _.find(locales, ['code', localeCode]) || {}
|
||||||
await WIKI.models.locales.query().delete().where('code', localeCode)
|
const existingLocale = await WIKI.models.locales.query().where('code', localeCode)
|
||||||
await WIKI.models.locales.query().insert({
|
if (existingLocale) {
|
||||||
code: localeCode,
|
await WIKI.models.locales.query().patch({
|
||||||
strings: lcObj,
|
strings: lcObj
|
||||||
isRTL: currentLocale.isRTL,
|
}).where('code', localeCode)
|
||||||
name: currentLocale.name,
|
} else {
|
||||||
nativeName: currentLocale.nativeName
|
await WIKI.models.locales.query().insert({
|
||||||
})
|
code: localeCode,
|
||||||
|
strings: lcObj,
|
||||||
|
isRTL: currentLocale.isRTL,
|
||||||
|
name: currentLocale.name,
|
||||||
|
nativeName: currentLocale.nativeName,
|
||||||
|
availability: currentLocale.availability
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Failed to fetch cached locales list! Restart server to resolve this issue.')
|
throw new Error('Failed to fetch cached locales list! Restart server to resolve this issue.')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ module.exports = async () => {
|
|||||||
query: `{
|
query: `{
|
||||||
localization {
|
localization {
|
||||||
locales {
|
locales {
|
||||||
|
availability
|
||||||
code
|
code
|
||||||
name
|
name
|
||||||
nativeName
|
nativeName
|
||||||
@@ -54,7 +55,9 @@ module.exports = async () => {
|
|||||||
let lcObj = {}
|
let lcObj = {}
|
||||||
_.forEach(strings, row => {
|
_.forEach(strings, row => {
|
||||||
if (_.includes(row.key, '::')) { return }
|
if (_.includes(row.key, '::')) { return }
|
||||||
if (_.isEmpty(row.value)) { row.value = row.key }
|
if (_.isEmpty(row.value)) {
|
||||||
|
row.value = row.key
|
||||||
|
}
|
||||||
_.set(lcObj, row.key.replace(':', '.'), row.value)
|
_.set(lcObj, row.key.replace(':', '.'), row.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -63,7 +66,8 @@ module.exports = async () => {
|
|||||||
strings: lcObj,
|
strings: lcObj,
|
||||||
isRTL: localeInfo.isRTL,
|
isRTL: localeInfo.isRTL,
|
||||||
name: localeInfo.name,
|
name: localeInfo.name,
|
||||||
nativeName: localeInfo.nativeName
|
nativeName: localeInfo.nativeName,
|
||||||
|
availability: localeInfo.availability
|
||||||
}).where('code', currentLocale)
|
}).where('code', currentLocale)
|
||||||
|
|
||||||
WIKI.logger.info(`Pulled latest locale updates for ${localeInfo.name} from Graph endpoint: [ COMPLETED ]`)
|
WIKI.logger.info(`Pulled latest locale updates for ${localeInfo.name} from Graph endpoint: [ COMPLETED ]`)
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ module.exports = class Locale extends Model {
|
|||||||
name: {type: 'string'},
|
name: {type: 'string'},
|
||||||
nativeName: {type: 'string'},
|
nativeName: {type: 'string'},
|
||||||
createdAt: {type: 'string'},
|
createdAt: {type: 'string'},
|
||||||
updatedAt: {type: 'string'}
|
updatedAt: {type: 'string'},
|
||||||
|
availability: {type: 'integer'}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user