feat: extensions check + resolver
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
v-expansion-panel-header(disable-icon-rotate)
|
||||
span {{ext.title}}
|
||||
template(v-slot:actions)
|
||||
v-chip(label, color='success', small, v-if='ext.installed') Installed
|
||||
v-chip(label, color='success', small, v-if='ext.isInstalled') Installed
|
||||
v-chip(label, color='warning', small, v-else) Not Installed
|
||||
v-expansion-panel-content.pa-0
|
||||
v-card(flat, :class='$vuetify.theme.dark ? `grey darken-3` : `grey lighten-5`', tile)
|
||||
@@ -25,18 +25,15 @@
|
||||
.body-2 {{ext.description}}
|
||||
v-divider.my-4
|
||||
.body-2
|
||||
strong.mr-3 Supported Platforms:
|
||||
v-chip.mr-1(label, small, :color='ext.platforms[`linux-amd64`] ? `success` : `error`') Linux (x64)
|
||||
v-chip.mr-1(label, small, :color='ext.platforms[`linux-arm64`] ? `success` : `error`') Linux (arm64)
|
||||
v-chip.mr-1(label, small, :color='ext.platforms[`linux-armv7`] ? `success` : `error`') Linux (armv7)
|
||||
v-chip.mr-1(label, small, :color='ext.platforms.macos ? `success` : `error`') MacOS
|
||||
v-chip.mr-1(label, small, :color='ext.platforms.windows ? `success` : `error`') Windows
|
||||
strong.mr-2 This extensions is
|
||||
v-chip.mr-2(v-if='ext.isCompatible', label, outlined, small, color='success') compatible
|
||||
v-chip.mr-2(v-else, label, small, color='error') not compatible
|
||||
strong with your host.
|
||||
v-card-chin
|
||||
v-spacer
|
||||
v-btn(disabled)
|
||||
v-icon(left) mdi-plus
|
||||
span Install
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -46,122 +43,70 @@ import gql from 'graphql-tag'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
config: {},
|
||||
extensions: [
|
||||
{
|
||||
key: 'git',
|
||||
title: 'Git',
|
||||
description: 'Distributed version control system. Required for the Git storage module.',
|
||||
platforms: {
|
||||
'linux-amd64': true,
|
||||
'linux-arm64': true,
|
||||
'linux-armv7': true,
|
||||
'macos': true,
|
||||
'windows': true
|
||||
},
|
||||
installed: true
|
||||
},
|
||||
{
|
||||
key: 'pandoc',
|
||||
title: 'Pandoc',
|
||||
description: 'Convert between markup formats. Required for converting from other formats such as MediaWiki, AsciiDoc, Textile and other wikis.',
|
||||
platforms: {
|
||||
'linux-amd64': true,
|
||||
'linux-arm64': false,
|
||||
'linux-armv7': false,
|
||||
'macos': true,
|
||||
'windows': true
|
||||
},
|
||||
installed: false
|
||||
},
|
||||
{
|
||||
key: 'puppeteer',
|
||||
title: 'Puppeteer',
|
||||
description: 'Headless chromium browser for server-side rendering. Required for generating PDF versions of pages and render content elements on the server (e.g. Mermaid diagrams)',
|
||||
platforms: {
|
||||
'linux-amd64': true,
|
||||
'linux-arm64': false,
|
||||
'linux-armv7': false,
|
||||
'macos': true,
|
||||
'windows': true
|
||||
},
|
||||
installed: false
|
||||
},
|
||||
{
|
||||
key: 'sharp',
|
||||
title: 'Sharp',
|
||||
description: 'Process and transform images. Required to generate thumbnails of uploaded images and perform transformations.',
|
||||
platforms: {
|
||||
'linux-amd64': true,
|
||||
'linux-arm64': false,
|
||||
'linux-armv7': false,
|
||||
'macos': true,
|
||||
'windows': true
|
||||
},
|
||||
installed: false
|
||||
}
|
||||
]
|
||||
extensions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
async save () {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation (
|
||||
$host: String!
|
||||
) {
|
||||
site {
|
||||
updateConfig(
|
||||
host: $host
|
||||
) {
|
||||
responseResult {
|
||||
succeeded
|
||||
errorCode
|
||||
slug
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
// try {
|
||||
// await this.$apollo.mutate({
|
||||
// mutation: gql`
|
||||
// mutation (
|
||||
// $host: String!
|
||||
// ) {
|
||||
// site {
|
||||
// updateConfig(
|
||||
// host: $host
|
||||
// ) {
|
||||
// responseResult {
|
||||
// succeeded
|
||||
// errorCode
|
||||
// slug
|
||||
// message
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// `,
|
||||
// variables: {
|
||||
// host: _.get(this.config, 'host', '')
|
||||
// },
|
||||
// watchLoading (isLoading) {
|
||||
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-extensions-update')
|
||||
// }
|
||||
// })
|
||||
// this.$store.commit('showNotification', {
|
||||
// style: 'success',
|
||||
// message: 'Configuration saved successfully.',
|
||||
// icon: 'check'
|
||||
// })
|
||||
// } catch (err) {
|
||||
// this.$store.commit('pushGraphError', err)
|
||||
// }
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
extensions: {
|
||||
query: gql`
|
||||
{
|
||||
system {
|
||||
extensions {
|
||||
key
|
||||
title
|
||||
description
|
||||
isInstalled
|
||||
isCompatible
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
host: _.get(this.config, 'host', '')
|
||||
},
|
||||
watchLoading (isLoading) {
|
||||
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update')
|
||||
}
|
||||
})
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'success',
|
||||
message: 'Configuration saved successfully.',
|
||||
icon: 'check'
|
||||
})
|
||||
} catch (err) {
|
||||
this.$store.commit('pushGraphError', err)
|
||||
}
|
||||
`,
|
||||
fetchPolicy: 'network-only',
|
||||
update: (data) => _.cloneDeep(data.system.extensions),
|
||||
watchLoading (isLoading) {
|
||||
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-extensions-refresh')
|
||||
}
|
||||
}
|
||||
}
|
||||
// apollo: {
|
||||
// config: {
|
||||
// query: gql`
|
||||
// {
|
||||
// site {
|
||||
// config {
|
||||
// host
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// `,
|
||||
// fetchPolicy: 'network-only',
|
||||
// update: (data) => _.cloneDeep(data.site.config),
|
||||
// watchLoading (isLoading) {
|
||||
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-refresh')
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ const state = {
|
||||
view: false,
|
||||
post: false,
|
||||
manage: false
|
||||
}
|
||||
},
|
||||
commentsCount: 0
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -103,10 +103,10 @@
|
||||
dark
|
||||
style='min-width: 50px; justify-content: center;'
|
||||
)
|
||||
span 334
|
||||
span {{commentsCount}}
|
||||
.d-flex
|
||||
v-btn.text-none(
|
||||
@click='goToComments'
|
||||
@click='goToComments()'
|
||||
:color='$vuetify.theme.dark ? `pink` : `pink darken-3`'
|
||||
outlined
|
||||
style='flex: 1 1 100%;'
|
||||
@@ -441,6 +441,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
isAuthenticated: get('user/authenticated'),
|
||||
commentsCount: get('page/commentsCount'),
|
||||
rating: {
|
||||
get () {
|
||||
return 3.5
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"cheerio": "1.0.0-rc.3",
|
||||
"chokidar": "3.4.0",
|
||||
"clean-css": "4.2.3",
|
||||
"command-exists": "1.2.9",
|
||||
"compression": "1.7.4",
|
||||
"connect-session-knex": "1.6.0",
|
||||
"cookie-parser": "1.4.5",
|
||||
@@ -162,7 +163,6 @@
|
||||
"scim-query-filter-parser": "2.0.4",
|
||||
"semver": "7.3.2",
|
||||
"serve-favicon": "2.5.0",
|
||||
"sharp": "0.25.2",
|
||||
"simple-git": "2.4.0",
|
||||
"solr-node": "1.2.1",
|
||||
"sqlite3": "4.2.0",
|
||||
|
||||
21
server/core/extensions.js
Normal file
21
server/core/extensions.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
|
||||
/* global WIKI */
|
||||
|
||||
module.exports = {
|
||||
ext: {},
|
||||
async init () {
|
||||
const extDirs = await fs.readdir(path.join(WIKI.SERVERPATH, 'modules/extensions'))
|
||||
WIKI.logger.info(`Checking for installed optional extensions...`)
|
||||
for (let dir of extDirs) {
|
||||
WIKI.extensions.ext[dir] = require(path.join(WIKI.SERVERPATH, 'modules/extensions', dir, 'ext.js'))
|
||||
const isInstalled = await WIKI.extensions.ext[dir].check()
|
||||
if (isInstalled) {
|
||||
WIKI.logger.info(`Optional extension ${dir} is installed. [ OK ]`)
|
||||
} else {
|
||||
WIKI.logger.info(`Optional extension ${dir} was not found on this system. [ SKIPPED ]`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ module.exports = {
|
||||
inbound: new EventEmitter(),
|
||||
outbound: new EventEmitter()
|
||||
}
|
||||
WIKI.extensions = require('./extensions')
|
||||
} catch (err) {
|
||||
WIKI.logger.error(err)
|
||||
process.exit(1)
|
||||
@@ -76,6 +77,8 @@ module.exports = {
|
||||
await WIKI.models.searchEngines.refreshSearchEnginesFromDisk()
|
||||
await WIKI.models.storage.refreshTargetsFromDisk()
|
||||
|
||||
await WIKI.extensions.init()
|
||||
|
||||
await WIKI.auth.activateStrategies()
|
||||
await WIKI.models.commentProviders.initProvider()
|
||||
await WIKI.models.searchEngines.initEngine()
|
||||
|
||||
@@ -34,7 +34,14 @@ module.exports = {
|
||||
result.push({ key, value })
|
||||
}, [])
|
||||
},
|
||||
async info() { return {} }
|
||||
async info () { return {} },
|
||||
async extensions () {
|
||||
const exts = Object.values(WIKI.extensions.ext).map(ext => _.pick(ext, ['key', 'title', 'description', 'isInstalled']))
|
||||
for (let ext of exts) {
|
||||
ext.isCompatible = await WIKI.extensions.ext[ext.key].isCompatible()
|
||||
}
|
||||
return exts
|
||||
}
|
||||
},
|
||||
SystemMutation: {
|
||||
async updateFlags (obj, args, context) {
|
||||
|
||||
@@ -17,6 +17,7 @@ extend type Mutation {
|
||||
type SystemQuery {
|
||||
flags: [SystemFlag] @auth(requires: ["manage:system"])
|
||||
info: SystemInfo
|
||||
extensions: [SystemExtension]! @auth(requires: ["manage:system"])
|
||||
}
|
||||
|
||||
# -----------------------------------------------
|
||||
@@ -112,3 +113,11 @@ type SystemImportUsersResponseFailed {
|
||||
email: String
|
||||
error: String
|
||||
}
|
||||
|
||||
type SystemExtension {
|
||||
key: String!
|
||||
title: String!
|
||||
description: String!
|
||||
isInstalled: Boolean!
|
||||
isCompatible: Boolean!
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ module.exports = class CommentProvider extends Model {
|
||||
const dbProviders = await WIKI.models.commentProviders.query()
|
||||
|
||||
// -> Fetch definitions from disk
|
||||
const authDirs = await fs.readdir(path.join(WIKI.SERVERPATH, 'modules/comments'))
|
||||
const commentDirs = await fs.readdir(path.join(WIKI.SERVERPATH, 'modules/comments'))
|
||||
let diskProviders = []
|
||||
for (let dir of authDirs) {
|
||||
for (let dir of commentDirs) {
|
||||
const def = await fs.readFile(path.join(WIKI.SERVERPATH, 'modules/comments', dir, 'definition.yml'), 'utf8')
|
||||
diskProviders.push(yaml.safeLoad(def))
|
||||
}
|
||||
|
||||
20
server/modules/extensions/git/ext.js
Normal file
20
server/modules/extensions/git/ext.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const cmdExists = require('command-exists')
|
||||
|
||||
module.exports = {
|
||||
key: 'git',
|
||||
title: 'Git',
|
||||
description: 'Distributed version control system. Required for the Git storage module.',
|
||||
isInstalled: false,
|
||||
async isCompatible () {
|
||||
return true
|
||||
},
|
||||
async check () {
|
||||
try {
|
||||
await cmdExists('git')
|
||||
this.isInstalled = true
|
||||
} catch (err) {
|
||||
this.isInstalled = false
|
||||
}
|
||||
return this.isInstalled
|
||||
}
|
||||
}
|
||||
21
server/modules/extensions/pandoc/ext.js
Normal file
21
server/modules/extensions/pandoc/ext.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const cmdExists = require('command-exists')
|
||||
const os = require('os')
|
||||
|
||||
module.exports = {
|
||||
key: 'pandoc',
|
||||
title: 'Pandoc',
|
||||
description: 'Convert between markup formats. Required for converting from other formats such as MediaWiki, AsciiDoc, Textile and other wikis.',
|
||||
async isCompatible () {
|
||||
return os.arch() === 'x64'
|
||||
},
|
||||
isInstalled: false,
|
||||
async check () {
|
||||
try {
|
||||
await cmdExists('pandoc')
|
||||
this.isInstalled = true
|
||||
} catch (err) {
|
||||
this.isInstalled = false
|
||||
}
|
||||
return this.isInstalled
|
||||
}
|
||||
}
|
||||
21
server/modules/extensions/puppeteer/ext.js
Normal file
21
server/modules/extensions/puppeteer/ext.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const cmdExists = require('command-exists')
|
||||
const os = require('os')
|
||||
|
||||
module.exports = {
|
||||
key: 'puppeteer',
|
||||
title: 'Puppeteer',
|
||||
description: 'Headless chromium browser for server-side rendering. Required for generating PDF versions of pages and render content elements on the server (e.g. Mermaid diagrams)',
|
||||
async isCompatible () {
|
||||
return os.arch() === 'x64'
|
||||
},
|
||||
isInstalled: false,
|
||||
async check () {
|
||||
try {
|
||||
await cmdExists('pandoc')
|
||||
this.isInstalled = true
|
||||
} catch (err) {
|
||||
this.isInstalled = false
|
||||
}
|
||||
return this.isInstalled
|
||||
}
|
||||
}
|
||||
19
server/modules/extensions/sharp/ext.js
Normal file
19
server/modules/extensions/sharp/ext.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const fs = require('fs-extra')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
|
||||
/* global WIKI */
|
||||
|
||||
module.exports = {
|
||||
key: 'sharp',
|
||||
title: 'Sharp',
|
||||
description: 'Process and transform images. Required to generate thumbnails of uploaded images and perform transformations.',
|
||||
async isCompatible () {
|
||||
return os.arch() === 'x64'
|
||||
},
|
||||
isInstalled: false,
|
||||
async check () {
|
||||
this.isInstalled = await fs.pathExists(path.join(WIKI.ROOTPATH, 'node_modules/sharp'))
|
||||
return this.isInstalled
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user