diff --git a/client/components/admin/admin-logging.vue b/client/components/admin/admin-logging.vue
index 9b4fd95b..5bc0fc09 100644
--- a/client/components/admin/admin-logging.vue
+++ b/client/components/admin/admin-logging.vue
@@ -5,29 +5,86 @@
.subheading.grey--text Configure the system logger(s)
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
v-tab(key='settings'): v-icon settings
- v-tab(v-for='svc in activeServices', :key='svc.key') {{ svc.title }}
+ v-tab(v-for='logger in activeLoggers', :key='logger.key') {{ logger.title }}
v-tab-item(key='settings', :transition='false', :reverse-transition='false')
v-card.pa-3(flat, tile)
- .body-2.pb-2 Select which logging service to enable:
+ .body-2.grey--text.text--darken-1 Select which logging service to enable:
+ .caption.grey--text.pb-2 Some loggers require additional configuration in their dedicated tab (when selected).
v-form
- v-checkbox(
- v-for='(svc, n) in services',
- v-model='selectedServices',
- :key='svc.key',
- :label='svc.title',
- :value='svc.key',
- color='primary',
- :disabled='svc.key === `console`'
+ v-checkbox.my-1(
+ v-for='(logger, n) in loggers'
+ v-model='logger.isEnabled'
+ :key='logger.key'
+ :label='logger.title'
+ color='primary'
hide-details
)
- v-tab-item(v-for='(svc, n) in activeServices', :key='svc.key', :transition='false', :reverse-transition='false')
+ v-tab-item(v-for='(logger, n) in activeLoggers', :key='logger.key', :transition='false', :reverse-transition='false')
v-card.pa-3(flat, tile)
v-form
- v-subheader Service Configuration
- .body-1(v-if='!svc.props || svc.props.length < 1') This logging service has no configuration options you can modify.
- v-text-field(v-else, v-for='prop in svc.props', :key='prop', :label='prop', prepend-icon='mode_edit')
+ .loggerlogo
+ img(:src='logger.logo', :alt='logger.title')
+ v-subheader.pl-0 {{logger.title}}
+ .caption {{logger.description}}
+ .caption: a(:href='logger.website') {{logger.website}}
+ v-divider.mt-3
+ v-subheader.pl-0 Logger Configuration
+ .body-1.ml-3(v-if='!logger.config || logger.config.length < 1') This logger has no configuration options you can modify.
+ template(v-else, v-for='cfg in logger.config')
+ v-select(
+ v-if='cfg.value.type === "string" && cfg.value.enum'
+ outline
+ background-color='grey lighten-2'
+ :items='cfg.value.enum'
+ :key='cfg.key'
+ :label='cfg.value.title'
+ v-model='cfg.value.value'
+ prepend-icon='settings_applications'
+ :hint='cfg.value.hint ? cfg.value.hint : ""'
+ persistent-hint
+ :class='cfg.value.hint ? "mb-2" : ""'
+ )
+ v-switch(
+ v-else-if='cfg.value.type === "boolean"'
+ :key='cfg.key'
+ :label='cfg.value.title'
+ v-model='cfg.value.value'
+ color='primary'
+ prepend-icon='settings_applications'
+ :hint='cfg.value.hint ? cfg.value.hint : ""'
+ persistent-hint
+ )
+ v-text-field(
+ v-else
+ outline
+ background-color='grey lighten-2'
+ :key='cfg.key'
+ :label='cfg.value.title'
+ v-model='cfg.value.value'
+ prepend-icon='settings_applications'
+ :hint='cfg.value.hint ? cfg.value.hint : ""'
+ persistent-hint
+ :class='cfg.value.hint ? "mb-2" : ""'
+ )
+ v-divider.mt-3
+ v-subheader.pl-0 Log Level
+ .body-1.ml-3 Select the minimum error level that will be reported to this logger.
+ v-layout(row)
+ v-flex(xs12, md6, lg4)
+ .pt-3
+ v-select(
+ single-line
+ outline
+ background-color='grey lighten-2'
+ :items='levels'
+ label='Level'
+ v-model='logger.level'
+ prepend-icon='graphic_eq'
+ hint='Default: warn'
+ persistent-hint
+ )
v-card-chin
v-btn(color='primary', @click='save')
@@ -51,6 +108,9 @@ import _ from 'lodash'
import LoggingConsole from './admin-logging-console.vue'
+import loggersQuery from 'gql/admin/logging/logging-query-loggers.gql'
+import loggersSaveMutation from 'gql/admin/logging/logging-mutation-save-loggers.gql'
+
export default {
components: {
LoggingConsole
@@ -58,34 +118,72 @@ export default {
data() {
return {
showConsole: false,
- services: [],
- selectedServices: ['console'],
- refreshCompleted: false
+ loggers: [],
+ levels: ['error', 'warn', 'info', 'debug', 'verbose']
}
},
computed: {
- activeServices() {
- return _.filter(this.services, 'isEnabled')
+ activeLoggers() {
+ return _.filter(this.loggers, 'isEnabled')
}
},
- // apollo: {
- // services: {
- // query: CONSTANTS.GRAPH.AUTHENTICATION.QUERY_PROVIDERS,
- // update: (data) => data.authentication.providers
- // }
- // },
methods: {
async refresh() {
- await this.$apollo.queries.services.refetch()
- this.refreshCompleted = true
+ await this.$apollo.queries.loggers.refetch()
+ this.$store.commit('showNotification', {
+ message: 'List of loggers has been refreshed.',
+ style: 'success',
+ icon: 'cached'
+ })
},
- toggleConsole () {
- this.showConsole = !this.showConsole
+ async save() {
+ this.$store.commit(`loadingStart`, 'admin-logging-saveloggers')
+ await this.$apollo.mutate({
+ mutation: loggersSaveMutation,
+ variables: {
+ loggers: this.loggers.map(tgt => _.pick(tgt, [
+ 'isEnabled',
+ 'key',
+ 'config',
+ 'level'
+ ])).map(str => ({...str, config: str.config.map(cfg => ({...cfg, value: cfg.value.value}))}))
+ }
+ })
+ this.$store.commit('showNotification', {
+ message: 'Logging configuration saved successfully.',
+ style: 'success',
+ icon: 'check'
+ })
+ this.$store.commit(`loadingStop`, 'admin-logging-saveloggers')
+ }
+ },
+ apollo: {
+ loggers: {
+ query: loggersQuery,
+ fetchPolicy: 'network-only',
+ update: (data) => _.cloneDeep(data.logging.loggers).map(str => ({...str, config: str.config.map(cfg => ({...cfg, value: JSON.parse(cfg.value)}))})),
+ watchLoading (isLoading) {
+ this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-logging-refresh')
+ }
}
}
}
-
diff --git a/client/components/admin/admin-search.vue b/client/components/admin/admin-search.vue
index df6a2062..b4c6d023 100644
--- a/client/components/admin/admin-search.vue
+++ b/client/components/admin/admin-search.vue
@@ -5,26 +5,70 @@
.subheading.grey--text Configure the search capabilities of your wiki
v-tabs(:color='$vuetify.dark ? "primary" : "grey lighten-4"', fixed-tabs, :slider-color='$vuetify.dark ? "white" : "primary"', show-arrows)
v-tab(key='settings'): v-icon settings
- v-tab(key='db') Database
- v-tab(key='algolia') Algolia
- v-tab(key='elasticsearch') Elasticsearch
- v-tab(key='solr') Solr
+ v-tab(v-for='engine in activeEngines', :key='engine.key') {{ engine.title }}
- v-tab-item(key='settings')
+ v-tab-item(key='settings', :transition='false', :reverse-transition='false')
v-card.pa-3(flat, tile)
+ .body-2.grey--text.text--darken-1 Select which search engine to enable:
+ .caption.grey--text.pb-2 Some search engines require additional configuration in their dedicated tab (when selected).
v-form
- .body-2.grey--text.text--darken-1 Select the search engine to use:
- .caption.grey--text.pb-2 Some engines require additional configuration in their dedicated tab (when selected).
v-radio-group(v-model='selectedEngine')
- v-radio(v-for='(engine, n) in engines', :key='n', :label='engine.text', :value='engine.value', color='primary')
- v-tab-item(key='db')
- v-card.pa-3 TODO
- v-tab-item(key='algolia')
- v-card.pa-3 TODO
- v-tab-item(key='elasticsearch')
- v-card.pa-3 TODO
- v-tab-item(key='solr')
- v-card.pa-3 TODO
+ v-radio.my-1(
+ v-for='(engine, n) in engines'
+ :key='engine.key'
+ :label='engine.title'
+ :value='engine.key'
+ color='primary'
+ hide-details
+ )
+
+ v-tab-item(v-for='(engine, n) in activeEngines', :key='engine.key', :transition='false', :reverse-transition='false')
+ v-card.pa-3(flat, tile)
+ v-form
+ .enginelogo
+ img(:src='engine.logo', :alt='engine.title')
+ v-subheader.pl-0 {{engine.title}}
+ .caption {{engine.description}}
+ .caption: a(:href='engine.website') {{engine.website}}
+ v-divider.mt-3
+ v-subheader.pl-0 Engine Configuration
+ .body-1.ml-3(v-if='!engine.config || engine.config.length < 1') This engine has no configuration options you can modify.
+ template(v-else, v-for='cfg in logger.config')
+ v-select(
+ v-if='cfg.value.type === "string" && cfg.value.enum'
+ outline
+ background-color='grey lighten-2'
+ :items='cfg.value.enum'
+ :key='cfg.key'
+ :label='cfg.value.title'
+ v-model='cfg.value.value'
+ prepend-icon='settings_applications'
+ :hint='cfg.value.hint ? cfg.value.hint : ""'
+ persistent-hint
+ :class='cfg.value.hint ? "mb-2" : ""'
+ )
+ v-switch(
+ v-else-if='cfg.value.type === "boolean"'
+ :key='cfg.key'
+ :label='cfg.value.title'
+ v-model='cfg.value.value'
+ color='primary'
+ prepend-icon='settings_applications'
+ :hint='cfg.value.hint ? cfg.value.hint : ""'
+ persistent-hint
+ )
+ v-text-field(
+ v-else
+ outline
+ background-color='grey lighten-2'
+ :key='cfg.key'
+ :label='cfg.value.title'
+ v-model='cfg.value.value'
+ prepend-icon='settings_applications'
+ :hint='cfg.value.hint ? cfg.value.hint : ""'
+ persistent-hint
+ :class='cfg.value.hint ? "mb-2" : ""'
+ )
v-card-chin
v-btn(color='primary', @click='save')
@@ -40,23 +84,90 @@
-
diff --git a/client/graph/admin/logging/logging-mutation-save-loggers.gql b/client/graph/admin/logging/logging-mutation-save-loggers.gql
new file mode 100644
index 00000000..2d86ba14
--- /dev/null
+++ b/client/graph/admin/logging/logging-mutation-save-loggers.gql
@@ -0,0 +1,12 @@
+mutation($loggers: [LoggerInput]) {
+ logging {
+ updateLoggers(loggers: $loggers) {
+ responseResult {
+ succeeded
+ errorCode
+ slug
+ message
+ }
+ }
+ }
+}
diff --git a/client/graph/admin/logging/logging-query-loggers.gql b/client/graph/admin/logging/logging-query-loggers.gql
new file mode 100644
index 00000000..3c244c32
--- /dev/null
+++ b/client/graph/admin/logging/logging-query-loggers.gql
@@ -0,0 +1,17 @@
+query {
+ logging {
+ loggers(orderBy: "title ASC") {
+ isEnabled
+ key
+ title
+ description
+ logo
+ website
+ level
+ config {
+ key
+ value
+ }
+ }
+ }
+}
diff --git a/client/graph/admin/search/search-mutation-save-engines.gql b/client/graph/admin/search/search-mutation-save-engines.gql
new file mode 100644
index 00000000..dee48537
--- /dev/null
+++ b/client/graph/admin/search/search-mutation-save-engines.gql
@@ -0,0 +1,12 @@
+mutation($searchEngines: [SearchEngineInput]) {
+ search {
+ updateSearchEngines(searchEngines: $searchEngines) {
+ responseResult {
+ succeeded
+ errorCode
+ slug
+ message
+ }
+ }
+ }
+}
diff --git a/client/graph/admin/search/search-query-engines.gql b/client/graph/admin/search/search-query-engines.gql
new file mode 100644
index 00000000..4c70de41
--- /dev/null
+++ b/client/graph/admin/search/search-query-engines.gql
@@ -0,0 +1,16 @@
+query {
+ search {
+ searchEngines(orderBy: "title ASC") {
+ isEnabled
+ key
+ title
+ description
+ logo
+ website
+ config {
+ key
+ value
+ }
+ }
+ }
+}
diff --git a/server/graph/resolvers/logging.js b/server/graph/resolvers/logging.js
new file mode 100644
index 00000000..b0b1fc88
--- /dev/null
+++ b/server/graph/resolvers/logging.js
@@ -0,0 +1,59 @@
+const _ = require('lodash')
+const graphHelper = require('../../helpers/graph')
+
+/* global WIKI */
+
+module.exports = {
+ Query: {
+ async logging() { return {} }
+ },
+ Mutation: {
+ async logging() { return {} }
+ },
+ LoggingQuery: {
+ async loggers(obj, args, context, info) {
+ let loggers = await WIKI.models.loggers.getLoggers()
+ loggers = loggers.map(logger => {
+ const loggerInfo = _.find(WIKI.data.loggers, ['key', logger.key]) || {}
+ return {
+ ...loggerInfo,
+ ...logger,
+ config: _.sortBy(_.transform(logger.config, (res, value, key) => {
+ const configData = _.get(loggerInfo.props, key, {})
+ res.push({
+ key,
+ value: JSON.stringify({
+ ...configData,
+ value
+ })
+ })
+ }, []), 'key')
+ }
+ })
+ if (args.filter) { loggers = graphHelper.filter(loggers, args.filter) }
+ if (args.orderBy) { loggers = graphHelper.orderBy(loggers, args.orderBy) }
+ return loggers
+ }
+ },
+ LoggingMutation: {
+ async updateLoggers(obj, args, context) {
+ try {
+ for (let logger of args.loggers) {
+ await WIKI.models.loggers.query().patch({
+ isEnabled: logger.isEnabled,
+ level: logger.level,
+ config: _.reduce(logger.config, (result, value, key) => {
+ _.set(result, `${value.key}`, value.value)
+ return result
+ }, {})
+ }).where('key', logger.key)
+ }
+ return {
+ responseResult: graphHelper.generateSuccess('Loggers updated successfully')
+ }
+ } catch (err) {
+ return graphHelper.generateError(err)
+ }
+ }
+ }
+}
diff --git a/server/graph/resolvers/search.js b/server/graph/resolvers/search.js
new file mode 100644
index 00000000..5449938f
--- /dev/null
+++ b/server/graph/resolvers/search.js
@@ -0,0 +1,58 @@
+const _ = require('lodash')
+const graphHelper = require('../../helpers/graph')
+
+/* global WIKI */
+
+module.exports = {
+ Query: {
+ async search() { return {} }
+ },
+ Mutation: {
+ async search() { return {} }
+ },
+ SearchQuery: {
+ async searchEngines(obj, args, context, info) {
+ let searchEngines = await WIKI.models.searchEngines.getSearchEngines()
+ searchEngines = searchEngines.map(searchEngine => {
+ const searchEngineInfo = _.find(WIKI.data.searchEngines, ['key', searchEngine.key]) || {}
+ return {
+ ...searchEngineInfo,
+ ...searchEngine,
+ config: _.sortBy(_.transform(searchEngine.config, (res, value, key) => {
+ const configData = _.get(searchEngineInfo.props, key, {})
+ res.push({
+ key,
+ value: JSON.stringify({
+ ...configData,
+ value
+ })
+ })
+ }, []), 'key')
+ }
+ })
+ if (args.filter) { searchEngines = graphHelper.filter(searchEngines, args.filter) }
+ if (args.orderBy) { searchEngines = graphHelper.orderBy(searchEngines, args.orderBy) }
+ return searchEngines
+ }
+ },
+ SearchMutation: {
+ async updateSearchEngines(obj, args, context) {
+ try {
+ for (let searchEngine of args.searchEngines) {
+ await WIKI.models.searchEngines.query().patch({
+ isEnabled: searchEngine.isEnabled,
+ config: _.reduce(searchEngine.config, (result, value, key) => {
+ _.set(result, `${value.key}`, value.value)
+ return result
+ }, {})
+ }).where('key', searchEngine.key)
+ }
+ return {
+ responseResult: graphHelper.generateSuccess('Search Engines updated successfully')
+ }
+ } catch (err) {
+ return graphHelper.generateError(err)
+ }
+ }
+ }
+}
diff --git a/server/graph/schemas/common.graphql b/server/graph/schemas/common.graphql
index 49771821..701c7d13 100644
--- a/server/graph/schemas/common.graphql
+++ b/server/graph/schemas/common.graphql
@@ -92,12 +92,6 @@ type Right {
group: Group!
}
-type SearchResult {
- path: String
- title: String
- tags: [String]
-}
-
type Setting {
id: Int!
createdAt: Date
@@ -133,7 +127,6 @@ type Query {
files(id: Int): [File]
folders(id: Int, name: String): [Folder]
rights(id: Int): [Right]
- search(q: String, tags: [String]): [SearchResult]
settings(key: String): [Setting]
tags(key: String): [Tag]
translations(locale: String!, namespace: String!): [Translation]
diff --git a/server/graph/schemas/logging.graphql b/server/graph/schemas/logging.graphql
new file mode 100644
index 00000000..37d8cebb
--- /dev/null
+++ b/server/graph/schemas/logging.graphql
@@ -0,0 +1,54 @@
+# ===============================================
+# LOGGING
+# ===============================================
+
+extend type Query {
+ logging: LoggingQuery
+}
+
+extend type Mutation {
+ logging: LoggingMutation
+}
+
+# -----------------------------------------------
+# QUERIES
+# -----------------------------------------------
+
+type LoggingQuery {
+ loggers(
+ filter: String
+ orderBy: String
+ ): [Logger]
+}
+
+# -----------------------------------------------
+# MUTATIONS
+# -----------------------------------------------
+
+type LoggingMutation {
+ updateLoggers(
+ loggers: [LoggerInput]
+ ): DefaultResponse
+}
+
+# -----------------------------------------------
+# TYPES
+# -----------------------------------------------
+
+type Logger {
+ isEnabled: Boolean!
+ key: String!
+ title: String!
+ description: String
+ logo: String
+ website: String
+ level: String
+ config: [KeyValuePair]
+}
+
+input LoggerInput {
+ isEnabled: Boolean!
+ key: String!
+ level: String!
+ config: [KeyValuePairInput]
+}
diff --git a/server/graph/schemas/search.graphql b/server/graph/schemas/search.graphql
new file mode 100644
index 00000000..28cc9195
--- /dev/null
+++ b/server/graph/schemas/search.graphql
@@ -0,0 +1,52 @@
+# ===============================================
+# SEARCH
+# ===============================================
+
+extend type Query {
+ search: SearchQuery
+}
+
+extend type Mutation {
+ search: SearchMutation
+}
+
+# -----------------------------------------------
+# QUERIES
+# -----------------------------------------------
+
+type SearchQuery {
+ searchEngines(
+ filter: String
+ orderBy: String
+ ): [SearchEngine]
+}
+
+# -----------------------------------------------
+# MUTATIONS
+# -----------------------------------------------
+
+type SearchMutation {
+ updateSearchEngines(
+ searchEngines: [SearchEngineInput]
+ ): DefaultResponse
+}
+
+# -----------------------------------------------
+# TYPES
+# -----------------------------------------------
+
+type SearchEngine {
+ isEnabled: Boolean!
+ key: String!
+ title: String!
+ description: String
+ logo: String
+ website: String
+ config: [KeyValuePair]
+}
+
+input SearchEngineInput {
+ isEnabled: Boolean!
+ key: String!
+ config: [KeyValuePairInput]
+}
diff --git a/server/modules/logging/eventlog/definition.yml b/server/modules/logging/eventlog/definition.yml
index 73b62e23..4f405973 100644
--- a/server/modules/logging/eventlog/definition.yml
+++ b/server/modules/logging/eventlog/definition.yml
@@ -2,7 +2,7 @@ key: eventlog
title: Windows Event Log
description: Report logs to the Windows Event Log
author: requarks.io
-logo: https://static.requarks.io/logo/windows.svg
+logo: https://static.requarks.io/logo/windows-server.svg
website: https://wiki.js.org
defaultLevel: warn
props: {}
diff --git a/server/modules/search/aws/definition.yml b/server/modules/search/aws/definition.yml
index b82980d4..34199e05 100644
--- a/server/modules/search/aws/definition.yml
+++ b/server/modules/search/aws/definition.yml
@@ -2,6 +2,6 @@ key: aws
title: AWS CloudSearch
description: Amazon CloudSearch is a managed service in the AWS Cloud that makes it simple and cost-effective to set up, manage, and scale a search solution for your website or application.
author: requarks.io
-logo: https://static.requarks.io/logo/aws.svg
+logo: https://static.requarks.io/logo/aws-cloudsearch.svg
website: https://aws.amazon.com/cloudsearch/
props: {}
diff --git a/server/modules/search/db/definition.yml b/server/modules/search/db/definition.yml
index 73041ed7..05e5e75e 100644
--- a/server/modules/search/db/definition.yml
+++ b/server/modules/search/db/definition.yml
@@ -2,6 +2,6 @@ key: db
title: Database (built-in)
description: Default database-based search engine.
author: requarks.io
-logo: https://static.requarks.io/logo/db.svg
+logo: https://static.requarks.io/logo/database.svg
website: https://www.requarks.io/
props: {}
diff --git a/server/setup.js b/server/setup.js
index dbdf6cff..09919d8d 100644
--- a/server/setup.js
+++ b/server/setup.js
@@ -21,8 +21,7 @@ module.exports = () => {
const favicon = require('serve-favicon')
const http = require('http')
const Promise = require('bluebird')
- const fs = Promise.promisifyAll(require('fs-extra'))
- const yaml = require('js-yaml')
+ const fs = require('fs-extra')
const _ = require('lodash')
const cfgHelper = require('./helpers/config')
const crypto = Promise.promisifyAll(require('crypto'))