feat: locales availability + IE display mode
This commit is contained in:
@@ -52,8 +52,6 @@
|
||||
v-toolbar(color='primary', dark, dense, flat)
|
||||
v-toolbar-title
|
||||
.subheading {{ $t('admin:locale.namespacing') }}
|
||||
v-spacer
|
||||
v-chip(label, color='white', small).primary--text coming soon
|
||||
v-card-text
|
||||
v-switch(
|
||||
v-model='namespacing'
|
||||
@@ -102,28 +100,35 @@
|
||||
v-card.animated.fadeInUp.wait-p4s
|
||||
v-toolbar(color='teal', dark, dense, flat)
|
||||
v-toolbar-title
|
||||
.subheading {{ $t('admin:locale.download') }}
|
||||
v-list(two-line, dense)
|
||||
template(v-for='(lc, idx) in locales')
|
||||
v-list-tile(:key='lc.code')
|
||||
v-list-tile-avatar
|
||||
v-avatar.teal.white--text(size='40') {{lc.code.toUpperCase()}}
|
||||
v-list-tile-content
|
||||
v-list-tile-title(v-html='lc.name')
|
||||
v-list-tile-sub-title(v-html='lc.nativeName')
|
||||
v-list-tile-action(v-if='lc.isRTL')
|
||||
v-chip(label, small, :class='$vuetify.dark ? `text--lighten-5` : `text--darken-2`').caption.grey--text RTL
|
||||
v-list-tile-action(v-if='lc.isInstalled && lc.installDate < lc.updatedAt')
|
||||
v-btn(icon, @click='download(lc)')
|
||||
v-icon.blue--text cached
|
||||
v-list-tile-action(v-else-if='lc.isInstalled')
|
||||
.subheading {{ $t('admin:locale.downloadTitle') }}
|
||||
v-data-table(
|
||||
:headers='headers',
|
||||
:items='locales',
|
||||
hide-actions,
|
||||
item-key='code',
|
||||
:rows-per-page-items='[-1]'
|
||||
)
|
||||
template(v-slot:items='lc')
|
||||
td
|
||||
v-chip.white--text(label, color='teal', small) {{lc.item.code}}
|
||||
td
|
||||
strong {{lc.item.name}}
|
||||
td
|
||||
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-list-tile-action(v-else-if='lc.isDownloading')
|
||||
v-progress-circular(indeterminate, color='blue', size='20', :width='3')
|
||||
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-btn(v-else, icon, @click='download(lc.item)')
|
||||
v-icon.grey--text cloud_download
|
||||
v-card.wiki-form.mt-3.animated.fadeInUp.wait-p5s
|
||||
v-toolbar(color='teal', dark, dense, flat)
|
||||
v-toolbar-title
|
||||
@@ -158,6 +163,46 @@ export default {
|
||||
computed: {
|
||||
installedLocales() {
|
||||
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: {
|
||||
@@ -173,6 +218,8 @@ export default {
|
||||
if (resp.succeeded) {
|
||||
lc.isDownloading = false
|
||||
lc.isInstalled = true
|
||||
lc.updatedAt = new Date().toISOString()
|
||||
lc.installDate = lc.updatedAt
|
||||
this.$store.commit('showNotification', {
|
||||
message: `Locale ${lc.name} has been installed successfully.`,
|
||||
style: 'success',
|
||||
|
@@ -3,14 +3,14 @@
|
||||
v-toolbar(flat, color='primary', dark, dense)
|
||||
.subheading {{ $t('admin:utilities.authTitle') }}
|
||||
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.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-icon(left) build
|
||||
span Proceed
|
||||
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.
|
||||
v-btn(outline, color='primary', @click='resetGuest', :disabled='loading').ml-0.mt-3
|
||||
v-icon(left) build
|
||||
|
@@ -3,13 +3,13 @@
|
||||
v-toolbar(flat, color='primary', dark, dense)
|
||||
.subheading {{ $t('admin:utilities.cacheTitle') }}
|
||||
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.
|
||||
v-btn(outline, color='primary', @click='flushCache', :disabled='loading').ml-0.mt-3
|
||||
v-icon(left) build
|
||||
span Proceed
|
||||
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.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
|
||||
|
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 {
|
||||
components: {
|
||||
UtilityAuth: () => import(/* webpackChunkName: "admin" */ './admin-utilities-auth.vue'),
|
||||
UtilityContent: () => import(/* webpackChunkName: "admin" */ './admin-utilities-content.vue'),
|
||||
UtilityCache: () => import(/* webpackChunkName: "admin" */ './admin-utilities-cache.vue'),
|
||||
UtilityImportv1: () => import(/* webpackChunkName: "admin" */ './admin-utilities-importv1.vue'),
|
||||
UtilityTelemetry: () => import(/* webpackChunkName: "admin" */ './admin-utilities-telemetry.vue')
|
||||
@@ -49,6 +50,12 @@ export default {
|
||||
i18nKey: 'auth',
|
||||
isAvailable: true
|
||||
},
|
||||
{
|
||||
key: 'UtilityContent',
|
||||
icon: 'insert_drive_file',
|
||||
i18nKey: 'content',
|
||||
isAvailable: true
|
||||
},
|
||||
{
|
||||
key: 'UtilityCache',
|
||||
icon: 'invert_colors',
|
||||
|
@@ -91,7 +91,7 @@ export default {
|
||||
return this.response.suggestions ? this.response.suggestions : []
|
||||
},
|
||||
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: {
|
||||
@@ -107,7 +107,7 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.$root.$on('searchMove', (dir) => {
|
||||
this.cursor += (dir === 'up' ? -1 : 1)
|
||||
this.cursor += ((dir === 'up') ? -1 : 1)
|
||||
if (this.cursor < -1) {
|
||||
this.cursor = -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'
|
||||
|
||||
// Prism (Syntax Highlighting)
|
||||
import Prism from '@/libs/prism/prism.js'
|
||||
import Prism from 'prismjs'
|
||||
|
||||
// ========================================
|
||||
// INIT
|
||||
|
@@ -1,6 +1,7 @@
|
||||
{
|
||||
localization {
|
||||
locales {
|
||||
availability
|
||||
code
|
||||
createdAt
|
||||
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('./scss/app.scss')
|
||||
|
@@ -18,7 +18,7 @@
|
||||
@import 'layout/md2';
|
||||
|
||||
// @import '../libs/twemoji/twemoji-awesome';
|
||||
@import '../libs/prism/prism.css';
|
||||
// @import '../libs/prism/prism.css';
|
||||
@import '~vue-tour/dist/vue-tour.css';
|
||||
@import '~vue-status-indicator/styles.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>
|
||||
import { StatusIndicator } from 'vue-status-indicator'
|
||||
import Prism from '@/libs/prism/prism.js'
|
||||
import Prism from 'prismjs'
|
||||
import { get } from 'vuex-pathify'
|
||||
import _ from 'lodash'
|
||||
|
||||
|
Reference in New Issue
Block a user