feat: navigation, editor improvements + graphql refactor

This commit is contained in:
NGPixel
2018-03-18 23:12:56 -04:00
parent 8462e18fc5
commit 3f0adc5daf
20 changed files with 284 additions and 400 deletions

View File

@@ -66,8 +66,7 @@
<script>
import _ from 'lodash'
/* global CONSTANTS */
import gql from 'graphql-tag'
export default {
data() {
@@ -84,7 +83,23 @@ export default {
},
apollo: {
providers: {
query: CONSTANTS.GRAPH.AUTHENTICATION.QUERY_PROVIDERS,
query: gql`
query {
authentication {
providers {
isEnabled
key
props
title
useForm
config {
key
value
}
}
}
}
`,
update: (data) => data.authentication.providers
}
},

View File

@@ -114,5 +114,12 @@ export default {
#voyager {
height: calc(100vh - 250px);
.title-area {
display: none;
}
.type-doc {
margin-top: 5px;
}
}
</style>

View File

@@ -5,54 +5,41 @@
.subheading.grey--text Manage groups
v-card
v-card-title
v-btn(color='primary', dark)
v-icon(left) add
| New Group
v-dialog(v-model='newGroupDialog', max-width='500')
v-btn(color='primary', dark, slot='activator')
v-icon(left) add
| New Group
v-card
v-card-title.headline.grey--text.text--darken-2 New Group
v-card-text
v-text-field(v-model='newGroupName', label='Group Name', autofocus, counter='255')
v-card-actions
v-spacer
v-btn(flat, @click='newGroupDialog = false') Cancel
v-btn(color='primary', @click='createGroup') Create
v-btn(icon)
v-icon.grey--text refresh
v-spacer
v-text-field(append-icon='search', label='Search', single-line, hide-details, v-model='search')
v-data-table(
v-model='selected'
:items='items',
:items='groups',
:headers='headers',
:search='search',
:pagination.sync='pagination',
:rows-per-page-items='[15]'
select-all,
hide-actions,
disable-initial-sort
)
template(slot='headers', slot-scope='props')
tr
th(width='50')
th.text-xs-right(
width='80'
:class='[`column sortable`, pagination.descending ? `desc` : `asc`, pagination.sortBy === `id` ? `active` : ``]'
@click='changeSort(`id`)'
)
v-icon(small) arrow_upward
| ID
th.text-xs-left(
v-for='header in props.headers'
:key='header.text'
:width='header.width'
:class='[`column sortable`, pagination.descending ? `desc` : `asc`, header.value === pagination.sortBy ? `active` : ``]'
@click='changeSort(header.value)'
)
| {{ header.text }}
v-icon(small) arrow_upward
template(slot='items', slot-scope='props')
tr(:active='props.selected')
td
v-checkbox(hide-details, :input-value='props.selected', color='blue darken-2', @click='props.selected = !props.selected')
td.text-xs-right {{ props.item.id }}
td {{ props.item.name }}
td {{ props.item.userCount }}
td: v-btn(icon): v-icon.grey--text.text--darken-1 more_horiz
template(slot='no-data')
v-alert(icon='warning', :value='true') No users to display!
.text-xs-center.py-2(v-if='items.length > 15')
v-alert.ma-3(icon='warning', :value='true', outline) No groups to display.
.text-xs-center.py-2(v-if='groups.length > 15')
v-pagination(v-model='pagination.page', :length='pages')
</template>
@@ -60,13 +47,13 @@
export default {
data() {
return {
newGroupDialog: false,
newGroupName: '',
selected: [],
pagination: {},
items: [
{ id: 1, name: 'Administrators', userCount: 1 },
{ id: 2, name: 'Users', userCount: 23 }
],
groups: [],
headers: [
{ text: 'ID', value: 'id', width: 50, align: 'right' },
{ text: 'Name', value: 'name' },
{ text: 'Users', value: 'userCount', width: 200 },
{ text: '', value: 'actions', sortable: false, width: 50 }
@@ -84,20 +71,18 @@ export default {
}
},
methods: {
changeSort (column) {
if (this.pagination.sortBy === column) {
this.pagination.descending = !this.pagination.descending
} else {
this.pagination.sortBy = column
this.pagination.descending = false
}
},
toggleAll () {
if (this.selected.length) {
this.selected = []
} else {
this.selected = this.items.slice()
}
async createGroup() {
// try {
// const resp = await this.$apollo.mutate({
// mutation: CONSTANTS.GRAPH.GROUPS.CREATE,
// variables: {
// name: this.newGroupName
// }
// })
// } catch (err) {
// }
}
}
}

View File

@@ -23,7 +23,7 @@
v-list-tile-title Latest Version
v-list-tile-sub-title {{ info.latestVersion }}
v-list-tile-action
v-list-tile-action-text Published 4 days ago
v-list-tile-action-text Published X days ago
v-divider
@@ -105,12 +105,12 @@
</template>
<script>
import gql from 'graphql-tag'
import IconCube from 'mdi/cube'
import IconDatabase from 'mdi/database'
import IconNodeJs from 'mdi/nodejs'
/* global CONSTANTS */
export default {
components: {
IconCube,
@@ -125,7 +125,29 @@ export default {
},
apollo: {
info: {
query: CONSTANTS.GRAPH.SYSTEM.QUERY_INFO,
query: gql`
query {
system {
info {
currentVersion
latestVersion
latestVersionReleaseDate
operatingSystem
hostname
cpuCores
ramTotal
workingDirectory
nodeVersion
redisVersion
redisUsedRAM
redisTotalRAM
redisHost
postgreVersion
postgreHost
}
}
}
`,
update: (data) => data.system.info
}
},

View File

@@ -1,8 +1,5 @@
<template lang='pug'>
.editor-code
v-toolbar(color='blue', flat, dense, dark)
v-icon(color='blue lighten-5') edit
v-toolbar-title.white--text Sample Page
.editor-code-toolbar
.editor-code-toolbar-group
.editor-code-toolbar-item(@click='toggleAround("**", "**")')
@@ -70,7 +67,7 @@
.editor-code-preview-title(@click='previewShown = false') Preview
.editor-code-preview-content.markdown-content(ref='editorPreview', v-html='previewHTML')
v-speed-dial(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', :fixed='true', :right='!isMobile', :left='isMobile', :bottom='true')
v-speed-dial(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', fixed, right, bottom)
v-btn(color='blue', fab, dark, v-model='fabInsertMenu', slot='activator')
v-icon add_circle
v-icon close
@@ -79,16 +76,6 @@
v-btn(color='red', fab, dark): v-icon play_circle_outline
v-btn(color='purple', fab, dark): v-icon multiline_chart
v-btn(color='indigo', fab, dark): v-icon functions
v-speed-dial(v-model='fabMainMenu', :open-on-hover='true', :direction='saveMenuDirection', transition='slide-x-reverse-transition', :fixed='true', :right='true', :top='!isMobile', :bottom='isMobile')
v-btn(color='white', fab, light, v-model='fabMainMenu' slot='activator')
v-icon(color='blue darken-2') blur_on
v-icon(color='blue darken-2') close
v-btn(color='blue-grey', fab, dark, @click.native.stop='$parent.openModal(`properties`)'): v-icon sort_by_alpha
v-btn(color='green', fab, dark, @click.native.stop='$parent.save()'): v-icon save
v-btn(color='red', fab, dark, small): v-icon not_interested
v-btn(color='orange', fab, dark, small, @click.native.stop='$parent.openModal(`access`)'): v-icon vpn_lock
v-btn(color='indigo', fab, dark, small): v-icon restore
v-btn(color='brown', fab, dark, small): v-icon archive
</template>
<script>
@@ -184,7 +171,6 @@ export default {
},
data() {
return {
fabMainMenu: false,
fabInsertMenu: false,
code: '# Header 1\n\nSample **Text**\nhttp://wiki.js.org\n:rocket: :) :( :| :P\n\n## Header 2\nSample Text\n\n```javascript\nvar test = require("test");\n\n// some comment\nconst foo = bar(\'param\') + 1.234;\n```\n\n### Header 3\nLorem *ipsum* ~~text~~',
cmOptions: {
@@ -210,9 +196,6 @@ export default {
},
isMobile() {
return this.$vuetify.breakpoint.smAndDown
},
saveMenuDirection() {
return this.isMobile ? 'top' : 'bottom'
}
},
methods: {

View File

@@ -49,7 +49,7 @@ export default {
methods: {
close() {
this.isShown = false
this.$parent.closeModal()
this.$parent.$parent.closeModal()
}
}
}

View File

@@ -31,7 +31,7 @@ export default {
methods: {
close() {
this.isShown = false
this.$parent.closeModal()
this.$parent.$parent.closeModal()
}
}
}

View File

@@ -1,13 +1,22 @@
<template lang="pug">
.editor
editor-code
component(:is='currentModal')
v-dialog(v-model='dialogProgress', persistent, max-width='300')
v-card
v-progress-linear.my-0(indeterminate, color='primary', height='5')
v-card-text.text-xs-center
.headline Saving
.caption Please wait...
nav-header
template(slot='actions')
v-btn(outline, color='green', @click.native.stop='save')
v-icon(color='green', left) save
span.white--text Save
v-btn(icon): v-icon(color='red') close
v-btn(icon, @click.native.stop='openModal(`properties`)'): v-icon(color='white') sort_by_alpha
v-btn(icon, @click.native.stop='openModal(`access`)'): v-icon(color='white') vpn_lock
v-content
editor-code
component(:is='currentModal')
v-dialog(v-model='dialogProgress', persistent, max-width='300')
v-card
v-progress-linear.my-0(indeterminate, color='primary', height='5')
v-card-text.text-xs-center
.headline Saving
.caption Please wait...
</template>
<script>

View File

@@ -1,5 +1,6 @@
<template lang="pug">
v-app
nav-header
.login(:class='{ "is-error": error }')
.login-container(:class='{ "is-expanded": strategies.length > 1, "is-loading": isLoading }')
.login-providers(v-show='strategies.length > 1')
@@ -37,9 +38,10 @@
</template>
<script>
/* global CONSTANTS, graphQL, siteConfig */
/* global graphQL, siteConfig */
import _ from 'lodash'
import gql from 'graphql-tag'
export default {
data () {
@@ -80,7 +82,21 @@ export default {
refreshStrategies () {
this.isLoading = true
graphQL.query({
query: CONSTANTS.GRAPH.AUTHENTICATION.QUERY_LOGIN_PROVIDERS
query: gql`
query {
authentication {
providers(
filter: "isEnabled eq true",
orderBy: "title ASC"
) {
key
title
useForm
icon
}
}
}
`
}).then(resp => {
if (_.has(resp, 'data.authentication.providers')) {
this.strategies = _.get(resp, 'data.authentication.providers', [])
@@ -116,7 +132,22 @@ export default {
} else {
this.isLoading = true
graphQL.mutate({
mutation: CONSTANTS.GRAPH.AUTHENTICATION.MUTATION_LOGIN,
mutation: gql`
mutation($username: String!, $password: String!, $provider: String!) {
authentication {
login(username: $username, password: $password, provider: $provider) {
operation {
succeeded
code
slug
message
}
tfaRequired
tfaLoginToken
}
}
}
`,
variables: {
username: this.username,
password: this.password,
@@ -169,7 +200,20 @@ export default {
} else {
this.isLoading = true
graphQL.mutate({
mutation: CONSTANTS.GRAPH.AUTHENTICATION.MUTATION_LOGINTFA,
mutation: gql`
mutation($loginToken: String!, $securityCode: String!) {
authentication {
loginTFA(loginToken: $loginToken, securityCode: $securityCode) {
operation {
succeeded
code
slug
message
}
}
}
}
`,
variables: {
loginToken: this.loginToken,
securityCode: this.securityCode

View File

@@ -1,7 +1,40 @@
<template lang='pug'>
v-toolbar(color='black', dark, app, clipped-left, fixed, flat)
v-toolbar-side-icon(@click.native='')
v-icon view_module
v-toolbar(color='black', dark, app, clipped-left, fixed, flat, dense)
v-menu(open-on-hover, offset-y, bottom, left, nudge-top='-18', min-width='250')
v-toolbar-side-icon(slot='activator')
v-icon view_module
v-list(dense)
v-list-tile(avatar, href='/')
v-list-tile-avatar: v-icon(color='blue') home
v-list-tile-content Home
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='green') add_box
v-list-tile-content New Page
v-divider.my-0
v-subheader Current Page
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='indigo') edit
v-list-tile-content Edit
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='indigo') history
v-list-tile-content History
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='indigo') code
v-list-tile-content View Source
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='indigo') forward
v-list-tile-content Move / Rename
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='red darken-2') delete
v-list-tile-content Delete
v-divider.my-0
v-subheader Assets
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='blue-grey') burst_mode
v-list-tile-content Images
v-list-tile(avatar, @click='')
v-list-tile-avatar: v-icon(color='blue-grey') description
v-list-tile-content Files
v-toolbar-title
span.subheading Wiki.js
v-spacer
@@ -29,6 +62,7 @@
)
v-spacer
v-progress-circular.mr-3(indeterminate, color='blue', v-show='$apollo.loading')
slot(name='actions')
transition(name='navHeaderSearch')
v-btn(icon, @click='searchToggle', v-if='!searchIsShown')
v-icon(color='grey') search
@@ -57,6 +91,7 @@
export default {
data() {
return {
menuIsShown: true,
searchIsLoading: false,
searchIsShown: false,
search: ''

View File

@@ -1,155 +0,0 @@
<template lang="pug">
.navigator
.navigator-bar
.navigator-fab
.navigator-fab-button(@click='toggleMainMenu')
svg.icons.is-24(role='img')
title Navigation
use(xlink:href='#gg-apps-grid')
.navigator-title
h1 {{ siteTitle }}
.navigator-subtitle(:class='subtitleClass')
transition(name='navigator-subtitle-icon')
svg.icons.is-24.navigator-subtitle-icon(role='img', v-if='subtitleIcon')
title {{subtitleText}}
use(:xlink:href='subtitleIconClass')
h2 {{subtitleText}}
.navigator-action
.navigator-action-item(:class='{"is-active": userMenuShown}', @click='toggleUserMenu')
svg.icons.is-32(role='img')
title User
use(xlink:href='#nc-user-circle')
transition(name='navigator-action-item-dropdown')
ul.navigator-action-item-dropdown(v-show='userMenuShown', v-cloak)
li
label Account
svg.icons.is-24(role='img')
title Account
use(xlink:href='#nc-man-green')
li(@click='logout')
label Sign out
svg.icons.is-24(role='img')
title Sign Out
use(xlink:href='#nc-exit')
transition(name='navigator-sd')
.navigator-sd(v-show='sdShown', v-cloak)
.navigator-sd-actions
a.is-active(href='', title='Search')
svg.icons.is-24(role='img')
title Search
use(xlink:href='#gg-search')
a(href='', title='New Document')
svg.icons.is-24(role='img')
title New Document
use(xlink:href='#nc-plus-circle')
a(href='', title='Edit Document')
svg.icons.is-24(role='img')
title Edit Document
use(xlink:href='#nc-pen-red')
a(href='', title='History')
svg.icons.is-24(role='img')
title History
use(xlink:href='#nc-restore')
a(href='', title='View Source')
svg.icons.is-24(role='img')
title View Source
use(xlink:href='#nc-code-editor')
a(href='', title='Move Document')
svg.icons.is-24(role='img')
title Move Document
use(xlink:href='#nc-move')
a(href='', title='Delete Document')
svg.icons.is-24(role='img')
title Delete Document
use(xlink:href='#nc-trash')
.navigator-sd-search
input(type='text', ref='iptSearch', placeholder='Search')
.navigator-sd-results
.navigator-sd-footer
a(href='', title='Settings')
svg.icons.is-24(role='img')
title Settings
use(xlink:href='#nc-gear')
a(href='', title='Users')
svg.icons.is-24(role='img')
title Users
use(xlink:href='#nc-users')
a(href='', title='Assets')
svg.icons.is-24(role='img')
title Assets
use(xlink:href='#nc-image')
</template>
<script>
/* global siteConfig */
import { mapState } from 'vuex'
export default {
data() {
return {
sdShown: false,
userMenuShown: false
}
},
computed: {
...mapState('navigator', [
'subtitleShown',
'subtitleStyle',
'subtitleText',
'subtitleIcon'
]),
siteTitle() {
return siteConfig.title
},
subtitleClass() {
return {
'is-active': this.subtitleShown,
'is-error': this.subtitleStyle === 'error',
'is-warning': this.subtitleStyle === 'warning',
'is-success': this.subtitleStyle === 'success',
'is-info': this.subtitleStyle === 'info'
}
},
subtitleIconClass() { return '#' + this.subtitleIcon }
},
methods: {
toggleMainMenu() {
this.sdShown = !this.sdShown
this.userMenuShown = false
if (this.sdShown) {
this.$nextTick(() => {
this.bindOutsideClick()
this.$refs.iptSearch.focus()
})
} else {
this.unbindOutsideClick()
}
},
toggleUserMenu() {
this.userMenuShown = !this.userMenuShown
this.sdShown = false
if (this.userMenuShown) {
this.bindOutsideClick()
} else {
this.unbindOutsideClick()
}
},
bindOutsideClick() {
document.addEventListener('mousedown', this.handleOutsideClick, false)
},
unbindOutsideClick() {
document.removeEventListener('mousedown', this.handleOutsideClick, false)
},
handleOutsideClick(ev) {
if (!this.$el.contains(ev.target)) {
this.sdShown = false
this.userMenuShown = false
}
},
logout() {
window.location.assign(this.$helpers.resolvePath('logout'))
}
}
}
</script>