mirror of https://github.com/requarks/wiki
parent
dfde2e10aa
commit
358ad1fdcd
@ -1,56 +0,0 @@
|
|||||||
const { SchemaDirectiveVisitor } = require('graphql-tools')
|
|
||||||
const { defaultFieldResolver } = require('graphql')
|
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
class AuthDirective extends SchemaDirectiveVisitor {
|
|
||||||
visitObject(type) {
|
|
||||||
this.ensureFieldsWrapped(type)
|
|
||||||
type._requiredAuthScopes = this.args.requires
|
|
||||||
}
|
|
||||||
// Visitor methods for nested types like fields and arguments
|
|
||||||
// also receive a details object that provides information about
|
|
||||||
// the parent and grandparent types.
|
|
||||||
visitFieldDefinition(field, details) {
|
|
||||||
this.ensureFieldsWrapped(details.objectType)
|
|
||||||
field._requiredAuthScopes = this.args.requires
|
|
||||||
}
|
|
||||||
|
|
||||||
visitArgumentDefinition(argument, details) {
|
|
||||||
this.ensureFieldsWrapped(details.objectType)
|
|
||||||
argument._requiredAuthScopes = this.args.requires
|
|
||||||
}
|
|
||||||
|
|
||||||
ensureFieldsWrapped(objectType) {
|
|
||||||
// Mark the GraphQLObjectType object to avoid re-wrapping:
|
|
||||||
if (objectType._authFieldsWrapped) return
|
|
||||||
objectType._authFieldsWrapped = true
|
|
||||||
|
|
||||||
const fields = objectType.getFields()
|
|
||||||
|
|
||||||
Object.keys(fields).forEach(fieldName => {
|
|
||||||
const field = fields[fieldName]
|
|
||||||
const { resolve = defaultFieldResolver } = field
|
|
||||||
field.resolve = async function (...args) {
|
|
||||||
// Get the required scopes from the field first, falling back
|
|
||||||
// to the objectType if no scopes is required by the field:
|
|
||||||
const requiredScopes = field._requiredAuthScopes || objectType._requiredAuthScopes
|
|
||||||
|
|
||||||
if (!requiredScopes) {
|
|
||||||
return resolve.apply(this, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
const context = args[2]
|
|
||||||
if (!context.req.user) {
|
|
||||||
throw new Error('Unauthorized')
|
|
||||||
}
|
|
||||||
if (!_.some(context.req.user.permissions, pm => _.includes(requiredScopes, pm))) {
|
|
||||||
throw new Error('Forbidden')
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve.apply(this, args)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = AuthDirective
|
|
@ -1,5 +0,0 @@
|
|||||||
const { createRateLimitDirective } = require('graphql-rate-limit-directive')
|
|
||||||
|
|
||||||
module.exports = createRateLimitDirective({
|
|
||||||
keyGenerator: (directiveArgs, source, args, context, info) => `${context.req.ip}:${info.parentType}.${info.fieldName}`
|
|
||||||
})
|
|
@ -1,28 +0,0 @@
|
|||||||
const request = require('request-promise')
|
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
/* global WIKI */
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
Query: {
|
|
||||||
async contribute() { return {} }
|
|
||||||
},
|
|
||||||
ContributeQuery: {
|
|
||||||
async contributors(obj, args, context, info) {
|
|
||||||
try {
|
|
||||||
const resp = await request({
|
|
||||||
method: 'POST',
|
|
||||||
uri: 'https://graph.requarks.io',
|
|
||||||
json: true,
|
|
||||||
body: {
|
|
||||||
query: '{\n sponsors {\n list(kind: BACKER) {\n id\n source\n name\n joined\n website\n twitter\n avatar\n }\n }\n}\n',
|
|
||||||
variables: {}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return _.get(resp, 'data.sponsors.list', [])
|
|
||||||
} catch (err) {
|
|
||||||
WIKI.logger.warn(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
// Query: {
|
|
||||||
// folders(obj, args, context, info) {
|
|
||||||
// return WIKI.models.Folder.findAll({ where: args })
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// Mutation: {
|
|
||||||
// createFolder(obj, args) {
|
|
||||||
// return WIKI.models.Folder.create(args)
|
|
||||||
// },
|
|
||||||
// deleteFolder(obj, args) {
|
|
||||||
// return WIKI.models.Folder.destroy({
|
|
||||||
// where: {
|
|
||||||
// id: args.id
|
|
||||||
// },
|
|
||||||
// limit: 1
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// renameFolder(obj, args) {
|
|
||||||
// return WIKI.models.Folder.update({
|
|
||||||
// name: args.name
|
|
||||||
// }, {
|
|
||||||
// where: { id: args.id }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// Folder: {
|
|
||||||
// files(grp) {
|
|
||||||
// return grp.getFiles()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
// Query: {
|
|
||||||
// tags(obj, args, context, info) {
|
|
||||||
// return WIKI.models.Tag.findAll({ where: args })
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// Mutation: {
|
|
||||||
// assignTagToDocument(obj, args) {
|
|
||||||
// return WIKI.models.Tag.findById(args.tagId).then(tag => {
|
|
||||||
// if (!tag) {
|
|
||||||
// throw new gql.GraphQLError('Invalid Tag ID')
|
|
||||||
// }
|
|
||||||
// return WIKI.models.Document.findById(args.documentId).then(doc => {
|
|
||||||
// if (!doc) {
|
|
||||||
// throw new gql.GraphQLError('Invalid Document ID')
|
|
||||||
// }
|
|
||||||
// return tag.addDocument(doc)
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// createTag(obj, args) {
|
|
||||||
// return WIKI.models.Tag.create(args)
|
|
||||||
// },
|
|
||||||
// deleteTag(obj, args) {
|
|
||||||
// return WIKI.models.Tag.destroy({
|
|
||||||
// where: {
|
|
||||||
// id: args.id
|
|
||||||
// },
|
|
||||||
// limit: 1
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// removeTagFromDocument(obj, args) {
|
|
||||||
// return WIKI.models.Tag.findById(args.tagId).then(tag => {
|
|
||||||
// if (!tag) {
|
|
||||||
// throw new gql.GraphQLError('Invalid Tag ID')
|
|
||||||
// }
|
|
||||||
// return WIKI.models.Document.findById(args.documentId).then(doc => {
|
|
||||||
// if (!doc) {
|
|
||||||
// throw new gql.GraphQLError('Invalid Document ID')
|
|
||||||
// }
|
|
||||||
// return tag.removeDocument(doc)
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// renameTag(obj, args) {
|
|
||||||
// return WIKI.models.Group.update({
|
|
||||||
// key: args.key
|
|
||||||
// }, {
|
|
||||||
// where: { id: args.id }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// Tag: {
|
|
||||||
// documents(tag) {
|
|
||||||
// return tag.getDocuments()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
const graphHelper = require('../../helpers/graph')
|
|
||||||
const _ = require('lodash')
|
|
||||||
const CleanCSS = require('clean-css')
|
|
||||||
|
|
||||||
/* global WIKI */
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
Query: {
|
|
||||||
async theming() { return {} }
|
|
||||||
},
|
|
||||||
Mutation: {
|
|
||||||
async theming() { return {} }
|
|
||||||
},
|
|
||||||
ThemingQuery: {
|
|
||||||
async themes(obj, args, context, info) {
|
|
||||||
return [{ // TODO
|
|
||||||
key: 'default',
|
|
||||||
title: 'Default',
|
|
||||||
author: 'requarks.io'
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
async config(obj, args, context, info) {
|
|
||||||
return {
|
|
||||||
theme: WIKI.config.theming.theme,
|
|
||||||
iconset: WIKI.config.theming.iconset,
|
|
||||||
darkMode: WIKI.config.theming.darkMode,
|
|
||||||
injectCSS: new CleanCSS({ format: 'beautify' }).minify(WIKI.config.theming.injectCSS).styles,
|
|
||||||
injectHead: WIKI.config.theming.injectHead,
|
|
||||||
injectBody: WIKI.config.theming.injectBody
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ThemingMutation: {
|
|
||||||
async setConfig(obj, args, context, info) {
|
|
||||||
try {
|
|
||||||
if (!_.isEmpty(args.injectCSS)) {
|
|
||||||
args.injectCSS = new CleanCSS({
|
|
||||||
inline: false
|
|
||||||
}).minify(args.injectCSS).styles
|
|
||||||
}
|
|
||||||
|
|
||||||
WIKI.config.theming = {
|
|
||||||
...WIKI.config.theming,
|
|
||||||
theme: args.theme,
|
|
||||||
iconset: args.iconset,
|
|
||||||
darkMode: args.darkMode,
|
|
||||||
injectCSS: args.injectCSS || '',
|
|
||||||
injectHead: args.injectHead || '',
|
|
||||||
injectBody: args.injectBody || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
await WIKI.configSvc.saveToDb(['theming'])
|
|
||||||
|
|
||||||
return {
|
|
||||||
responseResult: graphHelper.generateSuccess('Theme config updated')
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
return graphHelper.generateError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,18 @@
|
|||||||
|
|
||||||
const gql = require('graphql')
|
const gql = require('graphql')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = new gql.GraphQLScalarType({
|
||||||
Date: new gql.GraphQLScalarType({
|
name: 'Date',
|
||||||
name: 'Date',
|
description: 'ISO date-time string at UTC',
|
||||||
description: 'ISO date-time string at UTC',
|
parseValue(value) {
|
||||||
parseValue(value) {
|
return new Date(value)
|
||||||
return new Date(value)
|
},
|
||||||
},
|
serialize(value) {
|
||||||
serialize(value) {
|
return value.toISOString()
|
||||||
return value.toISOString()
|
},
|
||||||
},
|
parseLiteral(ast) {
|
||||||
parseLiteral(ast) {
|
if (ast.kind !== gql.Kind.STRING) {
|
||||||
if (ast.kind !== gql.Kind.STRING) {
|
throw new TypeError('Date value must be an string!')
|
||||||
throw new TypeError('Date value must be an string!')
|
|
||||||
}
|
|
||||||
return new Date(ast.value)
|
|
||||||
}
|
}
|
||||||
})
|
return new Date(ast.value)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
# ===============================================
|
|
||||||
# CONTRIBUTE
|
|
||||||
# ===============================================
|
|
||||||
|
|
||||||
extend type Query {
|
|
||||||
contribute: ContributeQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# QUERIES
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type ContributeQuery {
|
|
||||||
contributors: [ContributeContributor]
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# TYPES
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type ContributeContributor {
|
|
||||||
id: String!
|
|
||||||
source: String!
|
|
||||||
name: String!
|
|
||||||
joined: Date!
|
|
||||||
website: String
|
|
||||||
twitter: String
|
|
||||||
avatar: String
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
# ===============================================
|
|
||||||
# LOGGING
|
|
||||||
# ===============================================
|
|
||||||
|
|
||||||
extend type Query {
|
|
||||||
logging: LoggingQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
extend type Mutation {
|
|
||||||
logging: LoggingMutation
|
|
||||||
}
|
|
||||||
|
|
||||||
extend type Subscription {
|
|
||||||
loggingLiveTrail: LoggerTrailLine
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# QUERIES
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type LoggingQuery {
|
|
||||||
loggers(
|
|
||||||
filter: String
|
|
||||||
orderBy: String
|
|
||||||
): [Logger] @auth(requires: ["manage:system"])
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# MUTATIONS
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type LoggingMutation {
|
|
||||||
updateLoggers(
|
|
||||||
loggers: [LoggerInput]
|
|
||||||
): DefaultResponse @auth(requires: ["manage:system"])
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# 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]
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoggerTrailLine {
|
|
||||||
level: String!
|
|
||||||
output: String!
|
|
||||||
timestamp: Date!
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
# ===============================================
|
|
||||||
# THEMES
|
|
||||||
# ===============================================
|
|
||||||
|
|
||||||
extend type Query {
|
|
||||||
theming: ThemingQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
extend type Mutation {
|
|
||||||
theming: ThemingMutation
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# QUERIES
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type ThemingQuery {
|
|
||||||
themes: [ThemingTheme] @auth(requires: ["manage:theme", "manage:system"])
|
|
||||||
config: ThemingConfig @auth(requires: ["manage:theme", "manage:system"])
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# MUTATIONS
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type ThemingMutation {
|
|
||||||
setConfig(
|
|
||||||
theme: String!
|
|
||||||
iconset: String!
|
|
||||||
darkMode: Boolean!
|
|
||||||
injectCSS: String
|
|
||||||
injectHead: String
|
|
||||||
injectBody: String
|
|
||||||
): DefaultResponse @auth(requires: ["manage:theme", "manage:system"])
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# TYPES
|
|
||||||
# -----------------------------------------------
|
|
||||||
|
|
||||||
type ThemingConfig {
|
|
||||||
theme: String!
|
|
||||||
iconset: String!
|
|
||||||
darkMode: Boolean!
|
|
||||||
injectCSS: String
|
|
||||||
injectHead: String
|
|
||||||
injectBody: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type ThemingTheme {
|
|
||||||
key: String
|
|
||||||
title: String
|
|
||||||
author: String
|
|
||||||
}
|
|
@ -1,114 +1,135 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
q-dialog(ref='dialog', @hide='onDialogHide')
|
q-dialog(ref='dialogRef', @hide='onDialogHide')
|
||||||
q-card(style='min-width: 350px; max-width: 450px;')
|
q-card(style='min-width: 350px; max-width: 450px;')
|
||||||
q-card-section.card-header
|
q-card-section.card-header
|
||||||
q-icon(name='img:/_assets/icons/fluent-shutdown.svg', left, size='sm')
|
q-icon(name='img:/_assets/icons/fluent-shutdown.svg', left, size='sm')
|
||||||
span {{value ? $t(`admin.sites.activate`) : $t(`admin.sites.deactivate`)}}
|
span {{modelValue ? t(`admin.sites.activate`) : t(`admin.sites.deactivate`)}}
|
||||||
q-card-section
|
q-card-section
|
||||||
.text-body2
|
.text-body2
|
||||||
i18n-t(:keypath='value ? `admin.sites.activateConfirm` : `admin.sites.deactivateConfirm`')
|
i18n-t(:keypath='modelValue ? `admin.sites.activateConfirm` : `admin.sites.deactivateConfirm`')
|
||||||
template(v-slot:siteTitle)
|
template(v-slot:siteTitle)
|
||||||
strong {{site.title}}
|
strong {{props.site.title}}
|
||||||
q-card-actions.card-actions
|
q-card-actions.card-actions
|
||||||
q-space
|
q-space
|
||||||
q-btn.acrylic-btn(
|
q-btn.acrylic-btn(
|
||||||
flat
|
flat
|
||||||
:label='$t(`common.actions.cancel`)'
|
:label='t(`common.actions.cancel`)'
|
||||||
color='grey'
|
color='grey'
|
||||||
padding='xs md'
|
padding='xs md'
|
||||||
@click='hide'
|
@click='onDialogCancel'
|
||||||
)
|
)
|
||||||
q-btn(
|
q-btn(
|
||||||
unelevated
|
unelevated
|
||||||
:label='value ? $t(`common.actions.activate`) : $t(`common.actions.deactivate`)'
|
:label='modelValue ? t(`common.actions.activate`) : t(`common.actions.deactivate`)'
|
||||||
:color='value ? `positive` : `negative`'
|
:color='modelValue ? `positive` : `negative`'
|
||||||
padding='xs md'
|
padding='xs md'
|
||||||
@click='confirm'
|
@click='confirm'
|
||||||
|
:loading='state.isLoading'
|
||||||
)
|
)
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import cloneDeep from 'lodash/cloneDeep'
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useDialogPluginComponent, useQuasar } from 'quasar'
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
|
||||||
export default {
|
import { useAdminStore } from '../stores/admin'
|
||||||
props: {
|
|
||||||
site: {
|
// PROPS
|
||||||
type: Object
|
|
||||||
},
|
const props = defineProps({
|
||||||
value: {
|
site: {
|
||||||
type: Boolean,
|
type: Object,
|
||||||
default: false
|
required: true
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['ok', 'hide'],
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
modelValue: {
|
||||||
show () {
|
type: Boolean,
|
||||||
this.$refs.dialog.show()
|
default: false
|
||||||
},
|
}
|
||||||
hide () {
|
})
|
||||||
this.$refs.dialog.hide()
|
|
||||||
},
|
// EMITS
|
||||||
onDialogHide () {
|
|
||||||
this.$emit('hide')
|
defineEmits([
|
||||||
},
|
...useDialogPluginComponent.emits
|
||||||
async confirm () {
|
])
|
||||||
try {
|
|
||||||
const siteId = this.site.id
|
// QUASAR
|
||||||
const resp = await this.$apollo.mutate({
|
|
||||||
mutation: gql`
|
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
|
||||||
mutation updateSite (
|
const $q = useQuasar()
|
||||||
$id: UUID!
|
|
||||||
$newState: Boolean
|
// STORES
|
||||||
) {
|
|
||||||
updateSite(
|
const adminStore = useAdminStore()
|
||||||
id: $id
|
|
||||||
patch: {
|
// I18N
|
||||||
isEnabled: $newState
|
|
||||||
}
|
const { t } = useI18n()
|
||||||
) {
|
|
||||||
status {
|
// DATA
|
||||||
succeeded
|
|
||||||
message
|
const state = reactive({
|
||||||
}
|
isLoading: false
|
||||||
}
|
})
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
|
||||||
|
async function confirm () {
|
||||||
|
state.isLoading = true
|
||||||
|
try {
|
||||||
|
const resp = await APOLLO_CLIENT.mutate({
|
||||||
|
mutation: gql`
|
||||||
|
mutation updateSite (
|
||||||
|
$id: UUID!
|
||||||
|
$newState: Boolean
|
||||||
|
) {
|
||||||
|
updateSite(
|
||||||
|
id: $id
|
||||||
|
patch: {
|
||||||
|
isEnabled: $newState
|
||||||
}
|
}
|
||||||
`,
|
) {
|
||||||
variables: {
|
operation {
|
||||||
id: siteId,
|
succeeded
|
||||||
newState: this.value
|
message
|
||||||
}
|
|
||||||
})
|
|
||||||
if (resp?.data?.updateSite?.status?.succeeded) {
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: this.$t('admin.sites.updateSuccess')
|
|
||||||
})
|
|
||||||
this.$store.set('admin/sites', this.$store.get('admin/sites').map(s => {
|
|
||||||
if (s.id === siteId) {
|
|
||||||
const ns = cloneDeep(s)
|
|
||||||
ns.isEnabled = this.value
|
|
||||||
return ns
|
|
||||||
} else {
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
this.$emit('ok')
|
|
||||||
this.hide()
|
|
||||||
} else {
|
|
||||||
throw new Error(resp?.data?.updateSite?.status?.message || 'An unexpected error occured.')
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
`,
|
||||||
this.$q.notify({
|
variables: {
|
||||||
type: 'negative',
|
id: props.site.id,
|
||||||
message: err.message
|
newState: props.modelValue
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
if (resp?.data?.updateSite?.operation?.succeeded) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: this.$t('admin.sites.updateSuccess')
|
||||||
|
})
|
||||||
|
adminStore.$patch({
|
||||||
|
sites: adminStore.sites.map(s => {
|
||||||
|
if (s.id === props.site.id) {
|
||||||
|
const ns = cloneDeep(s)
|
||||||
|
ns.isEnabled = props.modelValue
|
||||||
|
return ns
|
||||||
|
} else {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
onDialogOK()
|
||||||
|
} else {
|
||||||
|
throw new Error(resp?.data?.updateSite?.operation?.message || 'An unexpected error occured.')
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: err.message
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
state.isLoading = false
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,94 +1,115 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
q-dialog(ref='dialog', @hide='onDialogHide')
|
q-dialog(ref='dialogRef', @hide='onDialogHide')
|
||||||
q-card(style='min-width: 350px; max-width: 450px;')
|
q-card(style='min-width: 350px; max-width: 450px;')
|
||||||
q-card-section.card-header
|
q-card-section.card-header
|
||||||
q-icon(name='img:/_assets/icons/fluent-delete-bin.svg', left, size='sm')
|
q-icon(name='img:/_assets/icons/fluent-delete-bin.svg', left, size='sm')
|
||||||
span {{$t(`admin.sites.delete`)}}
|
span {{t(`admin.sites.delete`)}}
|
||||||
q-card-section
|
q-card-section
|
||||||
.text-body2
|
.text-body2
|
||||||
i18n-t(keypath='admin.sites.deleteConfirm')
|
i18n-t(keypath='admin.sites.deleteConfirm')
|
||||||
template(v-slot:siteTitle)
|
template(v-slot:siteTitle)
|
||||||
strong {{site.title}}
|
strong {{props.site.title}}
|
||||||
.text-body2.q-mt-md
|
.text-body2.q-mt-md
|
||||||
strong.text-negative {{$t(`admin.sites.deleteConfirmWarn`)}}
|
strong.text-negative {{t(`admin.sites.deleteConfirmWarn`)}}
|
||||||
q-card-actions.card-actions
|
q-card-actions.card-actions
|
||||||
q-space
|
q-space
|
||||||
q-btn.acrylic-btn(
|
q-btn.acrylic-btn(
|
||||||
flat
|
flat
|
||||||
:label='$t(`common.actions.cancel`)'
|
:label='t(`common.actions.cancel`)'
|
||||||
color='grey'
|
color='grey'
|
||||||
padding='xs md'
|
padding='xs md'
|
||||||
@click='hide'
|
@click='onDialogCancel'
|
||||||
)
|
)
|
||||||
q-btn(
|
q-btn(
|
||||||
unelevated
|
unelevated
|
||||||
:label='$t(`common.actions.delete`)'
|
:label='t(`common.actions.delete`)'
|
||||||
color='negative'
|
color='negative'
|
||||||
padding='xs md'
|
padding='xs md'
|
||||||
@click='confirm'
|
@click='confirm'
|
||||||
|
:loading='state.isLoading'
|
||||||
)
|
)
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useDialogPluginComponent, useQuasar } from 'quasar'
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
export default {
|
import { useAdminStore } from '../stores/admin'
|
||||||
props: {
|
|
||||||
site: {
|
// PROPS
|
||||||
type: Object
|
|
||||||
}
|
const props = defineProps({
|
||||||
},
|
site: {
|
||||||
emits: ['ok', 'hide'],
|
type: Object,
|
||||||
data () {
|
required: true
|
||||||
return {
|
}
|
||||||
}
|
})
|
||||||
},
|
|
||||||
methods: {
|
// EMITS
|
||||||
show () {
|
|
||||||
this.$refs.dialog.show()
|
defineEmits([
|
||||||
},
|
...useDialogPluginComponent.emits
|
||||||
hide () {
|
])
|
||||||
this.$refs.dialog.hide()
|
|
||||||
},
|
// QUASAR
|
||||||
onDialogHide () {
|
|
||||||
this.$emit('hide')
|
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
|
||||||
},
|
const $q = useQuasar()
|
||||||
async confirm () {
|
|
||||||
try {
|
// STORES
|
||||||
const siteId = this.site.id
|
|
||||||
const resp = await this.$apollo.mutate({
|
const adminStore = useAdminStore()
|
||||||
mutation: gql`
|
|
||||||
mutation deleteSite ($id: UUID!) {
|
// I18N
|
||||||
deleteSite(id: $id) {
|
|
||||||
status {
|
const { t } = useI18n()
|
||||||
succeeded
|
|
||||||
message
|
// DATA
|
||||||
}
|
|
||||||
}
|
const state = reactive({
|
||||||
|
isLoading: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
|
||||||
|
async function confirm () {
|
||||||
|
state.isLoading = true
|
||||||
|
try {
|
||||||
|
const resp = await APOLLO_CLIENT.mutate({
|
||||||
|
mutation: gql`
|
||||||
|
mutation deleteSite ($id: UUID!) {
|
||||||
|
deleteSite(id: $id) {
|
||||||
|
status {
|
||||||
|
succeeded
|
||||||
|
message
|
||||||
}
|
}
|
||||||
`,
|
|
||||||
variables: {
|
|
||||||
id: siteId
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
if (resp?.data?.deleteSite?.status?.succeeded) {
|
|
||||||
this.$q.notify({
|
|
||||||
type: 'positive',
|
|
||||||
message: this.$t('admin.sites.deleteSuccess')
|
|
||||||
})
|
|
||||||
this.$store.set('admin/sites', this.$store.get('admin/sites').filter(s => s.id !== siteId))
|
|
||||||
this.$emit('ok')
|
|
||||||
this.hide()
|
|
||||||
} else {
|
|
||||||
throw new Error(resp?.data?.deleteSite?.status?.message || 'An unexpected error occured.')
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
`,
|
||||||
this.$q.notify({
|
variables: {
|
||||||
type: 'negative',
|
id: props.site.id
|
||||||
message: err.message
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
if (resp?.data?.deleteSite?.status?.succeeded) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: t('admin.sites.deleteSuccess')
|
||||||
|
})
|
||||||
|
adminStore.$patch({
|
||||||
|
sites: adminStore.sites.filter(s => s.id !== props.site.id)
|
||||||
|
})
|
||||||
|
onDialogOK()
|
||||||
|
} else {
|
||||||
|
throw new Error(resp?.data?.deleteSite?.status?.message || 'An unexpected error occured.')
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: err.message
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
state.isLoading = false
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in new issue