feat: admin dev pages modularity + storage state json fix

This commit is contained in:
Nick 2019-02-22 21:37:26 -05:00
parent 3743777b97
commit e3cb33f8b5
7 changed files with 274 additions and 187 deletions

1
.gitignore vendored
View File

@ -32,6 +32,7 @@ server/views/setup.pug
/data
/uploads
/content
/temp
*.sqlite
# IDE exclude

View File

@ -79,9 +79,22 @@
v-list-tile(to='/utilities', v-if='hasPermission(`manage:system`)', disabled)
v-list-tile-avatar: v-icon(color='grey lighten-2') build
v-list-tile-title {{ $t('admin:utilities.title') }}
v-list-tile(to='/dev', v-if='hasPermission([`manage:system`, `manage:api`])')
v-list-tile-avatar: v-icon weekend
v-list-tile-title {{ $t('admin:dev.title') }}
v-list-group(
prepend-icon='weekend'
value='true'
to='/dev'
no-action
v-if='hasPermission([`manage:system`, `manage:api`])'
)
v-list-tile(slot='activator')
v-list-tile-title {{ $t('admin:dev.title') }}
v-list-tile(to='/dev-flags')
v-list-tile-title {{ $t('admin:dev.flags.title') }}
v-list-tile(to='/dev-graphiql')
v-list-tile-title {{ $t('admin:dev.graphiql.title') }}
v-list-tile(to='/dev-voyager')
v-list-tile-title {{ $t('admin:dev.voyager.title') }}
v-divider.my-2
v-list-tile(to='/contribute')
v-list-tile-avatar: v-icon favorite
@ -132,7 +145,9 @@ const router = new VueRouter({
{ path: '/mail', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-mail.vue') },
{ path: '/system', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-system.vue') },
{ path: '/utilities', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-utilities.vue') },
{ path: '/dev', component: () => import(/* webpackChunkName: "admin-dev" */ './admin/admin-dev.vue') },
{ path: '/dev-flags', component: () => import(/* webpackChunkName: "admin-dev" */ './admin/admin-dev-flags.vue') },
{ path: '/dev-graphiql', component: () => import(/* webpackChunkName: "admin-dev" */ './admin/admin-dev-graphiql.vue') },
{ path: '/dev-voyager', component: () => import(/* webpackChunkName: "admin-dev" */ './admin/admin-dev-voyager.vue') },
{ path: '/contribute', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-contribute.vue') }
]
})

View File

@ -0,0 +1,59 @@
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header
img(src='/svg/icon-console.svg', alt='Developer Tools', style='width: 80px;')
.admin-header-title
.headline.primary--text Developer Tools
.subheading.grey--text Flags
v-spacer
v-btn(color='success', depressed, @click='save', large)
v-icon(left) check
span {{$t('common:actions.apply')}}
v-card.mt-3.white.grey--text.text--darken-3
v-alert(color='red', value='true', icon='warning')
span Do NOT enable these flags unless you know what you're doing!
.caption Doing so may result in data loss or broken installation!
v-card-text
v-switch.mt-3(
color='red'
hint='Log all queries made to the database to console.'
persistent-hint
label='SQL Query Logging'
v-model='flags.sqllog'
)
//- v-divider.mt-3
//- v-switch.mt-3(
//- color='primary'
//- hint='Log all queries made to the database to console.'
//- persistent-hint
//- label='SQL Query Log'
//- v-model='flags.sqllog'
//- )
</template>
<script>
import _ from 'lodash'
export default {
data() {
return {
flags: {
sqllog: false
}
}
},
methods: {
save() {
}
}
}
</script>
<style lang='scss'>
</style>

View File

@ -0,0 +1,101 @@
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header
img(src='/svg/icon-console.svg', alt='Developer Tools', style='width: 80px;')
.admin-header-title
.headline.primary--text Developer Tools
.subheading.grey--text GraphiQL
v-card.mt-3.white.grey--text.text--darken-3
#graphiql
</template>
<script>
import _ from 'lodash'
import React from 'react'
import ReactDOM from 'react-dom'
import GraphiQL from 'graphiql'
import 'graphiql/graphiql.css'
const fetcher = (qry, respType) => {
return fetch('/graphql', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(qry),
credentials: 'include'
}).then(response => {
if (respType === 'json') {
return response.json()
} else {
return response.text()
}
}).then(responseBody => {
try {
return JSON.parse(responseBody)
} catch (error) {
return responseBody
}
})
}
export default {
data() {
return { }
},
mounted() {
let graphiQLInstance
ReactDOM.render(
React.createElement(GraphiQL, {
ref(el) { graphiQLInstance = el },
async fetcher(qry) {
let resp = await fetcher(qry, 'text')
_.delay(() => {
graphiQLInstance.resultComponent.viewer.refresh()
}, 500)
return resp
},
response: null,
variables: '{}',
operationName: null,
websocketConnectionParams: null
}),
document.getElementById('graphiql')
)
graphiQLInstance.queryEditorComponent.editor.refresh()
graphiQLInstance.variableEditorComponent.editor.refresh()
graphiQLInstance.state.variableEditorOpen = true
graphiQLInstance.state.docExplorerOpen = true
}
}
</script>
<style lang='scss'>
#graphiql {
height: calc(100vh - 270px);
.topBar {
background-color: mc('grey', '200');
background-image: none;
padding: 1.5rem 0;
> .title {
display: none;
}
}
.toolbar {
background-color: initial;
box-shadow: initial;
}
.doc-explorer-title-bar, .history-title-bar {
height: auto;
}
}
</style>

View File

@ -0,0 +1,93 @@
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header
img(src='/svg/icon-console.svg', alt='Developer Tools', style='width: 80px;')
.admin-header-title
.headline.primary--text Developer Tools
.subheading.grey--text Voyager
v-card.mt-3.white.grey--text.text--darken-3
#voyager
</template>
<script>
import _ from 'lodash'
import React from 'react'
import ReactDOM from 'react-dom'
import { Voyager } from 'graphql-voyager'
import 'graphql-voyager/dist/voyager.css'
const fetcher = (qry, respType) => {
return fetch('/graphql', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(qry),
credentials: 'include'
}).then(response => {
if (respType === 'json') {
return response.json()
} else {
return response.text()
}
}).then(responseBody => {
try {
return JSON.parse(responseBody)
} catch (error) {
return responseBody
}
})
}
export default {
data() {
return {}
},
mounted() {
_.delay(() => {
ReactDOM.render(
React.createElement(Voyager, {
introspection: qry => fetcher({ query: qry }, 'json'),
workerURI: '/js/voyager.worker.js'
}),
document.getElementById('voyager')
)
}, 500)
}
}
</script>
<style lang='scss'>
#voyager {
height: calc(100vh - 270px);
.title-area {
display: none;
}
.type-doc {
margin-top: 5px;
}
.doc-navigation {
> span {
overflow-y: hidden;
display: block;
}
min-height: 40px;
}
.contents {
padding-bottom: 0;
color: #666;
}
.type-info-popover {
display: none;
}
}
</style>

View File

@ -1,182 +0,0 @@
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header
img(src='/svg/icon-console.svg', alt='Developer Tools', style='width: 80px;')
.admin-header-title
.headline.primary--text Developer Tools
.subheading.grey--text ¯\_()_/¯
v-spacer
v-card.radius-7
v-card-text
.caption Enables extra dev options and removes many safeguards.
.caption.red--text Do not enable unless you know what you're doing!
v-switch.mt-1(
color='primary'
hide-details
label='Dev Mode'
)
v-card.mt-3.white.grey--text.text--darken-3
v-tabs(
v-model='selectedTab'
color='grey darken-2'
fixed-tabs
slider-color='white'
show-arrows
dark
@change='tabChanged'
)
v-tab(key='0') Graph API Playground
v-tab(key='1') Graph API Map
v-tabs-items(v-model='selectedTab')
v-tab-item(key='0', :transition='false', :reverse-transition='false')
#graphiql
v-tab-item(key='1', :transition='false', :reverse-transition='false')
#voyager
</template>
<script>
import _ from 'lodash'
import React from 'react'
import ReactDOM from 'react-dom'
import GraphiQL from 'graphiql'
import { Voyager } from 'graphql-voyager'
import 'graphiql/graphiql.css'
import 'graphql-voyager/dist/voyager.css'
const fetcher = (qry, respType) => {
return fetch('/graphql', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(qry),
credentials: 'include'
}).then(response => {
if (respType === 'json') {
return response.json()
} else {
return response.text()
}
}).then(responseBody => {
try {
return JSON.parse(responseBody)
} catch (error) {
return responseBody
}
})
}
let graphiQLInstance
export default {
data() {
return {
selectedTab: 0
}
},
mounted() {
this.renderGraphiQL()
},
methods: {
tabChanged (tabId) {
switch (tabId) {
case 1:
this.renderVoyager()
break
}
},
renderGraphiQL() {
ReactDOM.render(
React.createElement(GraphiQL, {
ref(el) { graphiQLInstance = el },
async fetcher(qry) {
let resp = await fetcher(qry, 'text')
_.delay(() => {
graphiQLInstance.resultComponent.viewer.refresh()
}, 500)
return resp
},
response: null,
variables: '{}',
operationName: null,
websocketConnectionParams: null
}),
document.getElementById('graphiql')
)
graphiQLInstance.queryEditorComponent.editor.refresh()
graphiQLInstance.variableEditorComponent.editor.refresh()
graphiQLInstance.state.variableEditorOpen = true
graphiQLInstance.state.docExplorerOpen = true
},
renderVoyager() {
ReactDOM.render(
React.createElement(Voyager, {
introspection: qry => fetcher({ query: qry }, 'json'),
workerURI: '/js/voyager.worker.js'
}),
document.getElementById('voyager')
)
}
}
}
</script>
<style lang='scss'>
#graphiql {
height: calc(100vh - 270px);
.topBar {
background-color: mc('grey', '200');
background-image: none;
padding: 1.5rem 0;
> .title {
display: none;
}
}
.toolbar {
background-color: initial;
box-shadow: initial;
}
.doc-explorer-title-bar, .history-title-bar {
height: auto;
}
}
#voyager {
height: calc(100vh - 270px);
.title-area {
display: none;
}
.type-doc {
margin-top: 5px;
}
.doc-navigation {
> span {
overflow-y: hidden;
display: block;
}
min-height: 40px;
}
.contents {
padding-bottom: 0;
color: #666;
}
.type-info-popover {
display: none;
}
}
</style>

View File

@ -28,7 +28,7 @@ module.exports = class Storage extends Model {
}
static get jsonAttributes() {
return ['config']
return ['config', 'state']
}
static async getTargets() {