feat: admin dev pages modularity + storage state json fix
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -32,6 +32,7 @@ server/views/setup.pug | |||||||
| /data | /data | ||||||
| /uploads | /uploads | ||||||
| /content | /content | ||||||
|  | /temp | ||||||
| *.sqlite | *.sqlite | ||||||
|  |  | ||||||
| # IDE exclude | # IDE exclude | ||||||
|   | |||||||
| @@ -79,9 +79,22 @@ | |||||||
|             v-list-tile(to='/utilities', v-if='hasPermission(`manage:system`)', disabled) |             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-avatar: v-icon(color='grey lighten-2') build | ||||||
|               v-list-tile-title {{ $t('admin:utilities.title') }} |               v-list-tile-title {{ $t('admin:utilities.title') }} | ||||||
|             v-list-tile(to='/dev', v-if='hasPermission([`manage:system`, `manage:api`])') |             v-list-group( | ||||||
|               v-list-tile-avatar: v-icon weekend |               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-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-divider.my-2 | ||||||
|           v-list-tile(to='/contribute') |           v-list-tile(to='/contribute') | ||||||
|             v-list-tile-avatar: v-icon favorite |             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: '/mail', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-mail.vue') }, | ||||||
|     { path: '/system', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-system.vue') }, |     { path: '/system', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-system.vue') }, | ||||||
|     { path: '/utilities', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-utilities.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') } |     { path: '/contribute', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-contribute.vue') } | ||||||
|   ] |   ] | ||||||
| }) | }) | ||||||
|   | |||||||
							
								
								
									
										59
									
								
								client/components/admin/admin-dev-flags.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								client/components/admin/admin-dev-flags.vue
									
									
									
									
									
										Normal 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> | ||||||
							
								
								
									
										101
									
								
								client/components/admin/admin-dev-graphiql.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								client/components/admin/admin-dev-graphiql.vue
									
									
									
									
									
										Normal 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> | ||||||
							
								
								
									
										93
									
								
								client/components/admin/admin-dev-voyager.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								client/components/admin/admin-dev-voyager.vue
									
									
									
									
									
										Normal 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> | ||||||
| @@ -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> |  | ||||||
| @@ -28,7 +28,7 @@ module.exports = class Storage extends Model { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   static get jsonAttributes() { |   static get jsonAttributes() { | ||||||
|     return ['config'] |     return ['config', 'state'] | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static async getTargets() { |   static async getTargets() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user