mirror of https://github.com/Requarks/wiki.git
14 changed files with 1911 additions and 1216 deletions
Split View
Diff Options
-
3client/components/admin.vue
-
84client/components/admin/admin-theme.vue
-
1client/components/admin/admin-utilities-importv1.vue
-
4client/components/editor.vue
-
9client/components/editor/api/server-selector.vue
-
433client/components/editor/editor-api.vue
-
20client/components/editor/editor-modal-editorselect.vue
-
1client/static/svg/icon-graphql.svg
-
1client/static/svg/icon-transaction-list.svg
-
30client/themes/default/components/nav-sidebar.vue
-
44client/themes/default/theme.yml
-
133package.json
-
6server/modules/editor/api/definition.yml
-
2358yarn.lock
@ -0,0 +1,9 @@ |
|||
<template lang="pug"> |
|||
|
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
|
|||
} |
|||
</script> |
@ -0,0 +1,433 @@ |
|||
<template lang='pug'> |
|||
.editor-api |
|||
.editor-api-main |
|||
v-list.editor-api-sidebar.radius-0(nav, :class='$vuetify.theme.dark ? `grey darken-4` : `primary`', dark) |
|||
v-list-item-group(v-model='tab') |
|||
v-list-item.animated.fadeInLeft(value='info') |
|||
v-list-item-icon: v-icon mdi-book-information-variant |
|||
v-list-item-title Info |
|||
v-list-item.mt-3.animated.fadeInLeft.wait-p2s(value='servers') |
|||
v-list-item-icon: v-icon mdi-server |
|||
v-list-item-title Servers |
|||
v-list-item.mt-3.animated.fadeInLeft.wait-p3s(value='endpoints') |
|||
v-list-item-icon: v-icon mdi-code-braces |
|||
v-list-item-title Endpoints |
|||
v-list-item.mt-3.animated.fadeInLeft.wait-p4s(value='models') |
|||
v-list-item-icon: v-icon mdi-buffer |
|||
v-list-item-title Models |
|||
v-list-item.mt-3.animated.fadeInLeft.wait-p5s(value='auth') |
|||
v-list-item-icon: v-icon mdi-lock |
|||
v-list-item-title Authentication |
|||
.editor-api-editor |
|||
template(v-if='tab === `info`') |
|||
v-container.px-2.pt-1(fluid) |
|||
v-row(dense) |
|||
v-col(cols='12') |
|||
.pa-3 |
|||
.subtitle-2 API General Information |
|||
.caption.grey--text.text--darken-1 Global metadata about the API |
|||
v-col(cols='12', lg='6') |
|||
v-card.pt-2 |
|||
v-card-text |
|||
v-text-field( |
|||
label='Title' |
|||
outlined |
|||
hint='Required - Title of the API' |
|||
persistent-hint |
|||
v-model='info.title' |
|||
) |
|||
v-divider.mt-2.mb-4 |
|||
v-text-field( |
|||
label='Version' |
|||
outlined |
|||
hint='Required - Semantic versioning like 1.0.0 or an arbitrary string like 0.99-beta.' |
|||
persistent-hint |
|||
v-model='info.version' |
|||
) |
|||
v-divider.mt-2.mb-4 |
|||
v-textarea( |
|||
label='Description' |
|||
outlined |
|||
hint='Optional - Markdown formatting is supported.' |
|||
persistent-hint |
|||
v-model='info.description' |
|||
) |
|||
v-col(cols='12', lg='6') |
|||
v-card.pt-2 |
|||
v-card-text |
|||
v-list(nav, two-line) |
|||
v-list-item-group(v-model='kind', mandatory, color='primary') |
|||
v-list-item(value='rest') |
|||
v-list-item-avatar |
|||
img(src='/svg/icon-transaction-list.svg', alt='REST') |
|||
v-list-item-content |
|||
v-list-item-title REST API |
|||
v-list-item-subtitle Classic REST Endpoints |
|||
v-list-item-avatar |
|||
v-icon(:color='kind === `rest` ? `primary` : `grey lighten-3`') mdi-check-circle |
|||
v-list-item(value='graphql', disabled) |
|||
v-list-item-avatar |
|||
img(src='/svg/icon-graphql.svg', alt='GraphQL') |
|||
v-list-item-content |
|||
v-list-item-title GraphQL |
|||
v-list-item-subtitle.grey--text.text--lighten-1 Schema-based API |
|||
v-list-item-action |
|||
//- v-icon(:color='kind === `graphql` ? `primary` : `grey lighten-3`') mdi-check-circle |
|||
v-chip(label, small) Coming soon |
|||
template(v-else-if='tab === `servers`') |
|||
v-container.px-2.pt-1(fluid) |
|||
v-row(dense) |
|||
v-col(cols='12') |
|||
.pa-3 |
|||
.d-flex.align-center.justify-space-between |
|||
div |
|||
.subtitle-2 List of servers / load balancers where this API reside |
|||
.caption.grey--text.text--darken-1 Enter all environments, e.g. Integration, QA, Pre-production, Production, etc. |
|||
v-btn(color='primary', large, @click='addServer') |
|||
v-icon(left) mdi-plus |
|||
span Add Server |
|||
v-col(cols='12', lg='6', v-for='srv of servers', :key='srv.id') |
|||
v-card.pt-1 |
|||
v-card-text |
|||
.d-flex |
|||
.d-flex.flex-column.justify-space-between |
|||
v-menu(offset-y, min-width='200') |
|||
template(v-slot:activator='{ on }') |
|||
v-btn(text, x-large, style='min-width: 0;', v-on='on') |
|||
v-icon(large, :color='iconColor(srv.icon)') {{iconKey(srv.icon)}} |
|||
v-list(nav, dense) |
|||
v-list-item-group(v-model='srv.icon', mandatory) |
|||
v-list-item(:value='srvKey', v-for='(srv, srvKey) in serverTypes', :key='srvKey') |
|||
v-list-item-icon: v-icon(large, :color='srv.color', v-text='srv.icon') |
|||
v-list-item-content: v-list-item-title(v-text='srv.title') |
|||
v-btn.mb-2(depressed, small, @click='removeServer(srv.id)') |
|||
v-icon(left) mdi-close |
|||
span Delete |
|||
v-divider.ml-5(vertical) |
|||
.pl-5(style='flex: 1 1 100%;') |
|||
v-text-field( |
|||
label='Environment / Server Name' |
|||
outlined |
|||
hint='Required - Name of the environment (e.g. QA, Production)' |
|||
persistent-hint |
|||
v-model='srv.name' |
|||
) |
|||
v-text-field.mt-4( |
|||
label='URL' |
|||
outlined |
|||
hint='Required - URL of the environment (e.g. https://api.example.com/v1)' |
|||
persistent-hint |
|||
v-model='srv.url' |
|||
) |
|||
|
|||
template(v-else-if='tab === `endpoints`') |
|||
v-container.px-2.pt-1(fluid) |
|||
v-row(dense) |
|||
v-col(cols='12') |
|||
.pa-3 |
|||
.d-flex.align-center.justify-space-between |
|||
div |
|||
.subtitle-2 List of endpoints |
|||
.caption.grey--text.text--darken-1 Groups of REST endpoints (GET, POST, PUT, DELETE). |
|||
v-btn(color='primary', large, @click='addGroup') |
|||
v-icon(left) mdi-plus |
|||
span Add Group |
|||
v-col(cols='12', v-for='grp of endpointGroups', :key='grp.id') |
|||
v-card(color='grey darken-2') |
|||
v-card-text |
|||
v-toolbar(color='grey darken-2', flat, height='86') |
|||
v-text-field.mr-1( |
|||
flat |
|||
dark |
|||
label='Group Name' |
|||
solo |
|||
hint='Group Name' |
|||
persistent-hint |
|||
v-model='grp.name' |
|||
) |
|||
v-text-field.mx-1( |
|||
flat |
|||
dark |
|||
label='Group Description' |
|||
solo |
|||
hint='Group Description' |
|||
persistent-hint |
|||
v-model='grp.description' |
|||
) |
|||
v-divider.mx-3(vertical, dark) |
|||
v-btn.mx-1.align-self-start(color='grey lighten-2', @click='addEndpoint(grp)', dark, text, height='48') |
|||
v-icon(left) mdi-trash-can |
|||
span Delete |
|||
v-divider.mx-3(vertical, dark) |
|||
v-btn.ml-1.align-self-start(color='pink', @click='addEndpoint(grp)', dark, depressed, height='48') |
|||
v-icon(left) mdi-plus |
|||
span Add Endpoint |
|||
v-container.pa-0.mt-2(fluid) |
|||
v-row(dense) |
|||
v-col(cols='12', v-for='ept of grp.endpoints', :key='ept.id') |
|||
v-card.pt-1 |
|||
v-card-text |
|||
.d-flex |
|||
.d-flex.flex-column |
|||
v-menu(offset-y, min-width='140') |
|||
template(v-slot:activator='{ on }') |
|||
v-btn.subtitle-1(depressed, large, dark, style='min-width: 140px;', height='48', v-on='on', :color='methodColor(ept.method)') |
|||
strong {{ept.method}} |
|||
v-list(nav, dense) |
|||
v-list-item-group(v-model='ept.method', mandatory) |
|||
v-list-item(:value='mtd.key', v-for='mtd of endpointMethods', :key='mtd.key') |
|||
v-list-item-content |
|||
v-chip.text-center(label, :color='mtd.color', dark) {{mtd.key}} |
|||
v-btn.mt-2(v-if='!ept.expanded', small, @click='ept.expanded = true', color='pink', outlined) |
|||
v-icon(left) mdi-arrow-down-box |
|||
span Expand |
|||
v-btn.mt-2(v-else, small, @click='ept.expanded = false', color='pink', outlined) |
|||
v-icon(left) mdi-arrow-up-box |
|||
span Collapse |
|||
template(v-if='ept.expanded') |
|||
v-spacer |
|||
v-btn.my-2(depressed, small, @click='removeEndpoint(grp, ept.id)') |
|||
v-icon(left) mdi-close |
|||
span Delete |
|||
v-divider.ml-5(vertical) |
|||
.pl-5(style='flex: 1 1 100%;') |
|||
.d-flex |
|||
v-text-field.mr-2( |
|||
label='Path' |
|||
outlined |
|||
hint='Required - Path to the endpoint (e.g. /planets/{planetId})' |
|||
persistent-hint |
|||
v-model='ept.path' |
|||
) |
|||
v-text-field.ml-2( |
|||
label='Summary' |
|||
outlined |
|||
hint='Required - A short summary of the endpoint (a few words).' |
|||
persistent-hint |
|||
v-model='ept.summary' |
|||
) |
|||
template(v-if='ept.expanded') |
|||
v-text-field.mt-3( |
|||
label='Description' |
|||
outlined |
|||
v-model='ept.description' |
|||
) |
|||
|
|||
v-system-bar.editor-api-sysbar(dark, status, color='grey darken-3') |
|||
.caption.editor-api-sysbar-locale {{locale.toUpperCase()}} |
|||
.caption.px-3 /{{path}} |
|||
template(v-if='$vuetify.breakpoint.mdAndUp') |
|||
v-spacer |
|||
.caption API Docs |
|||
v-spacer |
|||
.caption OpenAPI 3.0 |
|||
</template> |
|||
|
|||
<script> |
|||
import _ from 'lodash' |
|||
import uuid from 'uuid/v4' |
|||
import { get, sync } from 'vuex-pathify' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
tab: `endpoints`, |
|||
kind: 'rest', |
|||
kinds: [ |
|||
{ text: 'REST', value: 'rest' }, |
|||
{ text: 'GraphQL', value: 'graphql' } |
|||
], |
|||
info: { |
|||
title: '', |
|||
version: '1.0.0', |
|||
description: '' |
|||
}, |
|||
servers: [ |
|||
{ name: 'Production', url: 'https://api.example.com/v1', icon: 'server', id: '123456' } |
|||
], |
|||
serverTypes: { |
|||
aws: { |
|||
color: 'orange', |
|||
icon: 'mdi-aws', |
|||
title: 'AWS' |
|||
}, |
|||
azure: { |
|||
color: 'blue darken-2', |
|||
icon: 'mdi-azure', |
|||
title: 'Azure' |
|||
}, |
|||
digitalocean: { |
|||
color: 'blue', |
|||
icon: 'mdi-digital-ocean', |
|||
title: 'DigitalOcean' |
|||
}, |
|||
docker: { |
|||
color: 'blue', |
|||
icon: 'mdi-docker', |
|||
title: 'Docker' |
|||
}, |
|||
google: { |
|||
color: 'red', |
|||
icon: 'mdi-google', |
|||
title: 'Google' |
|||
}, |
|||
kubernetes: { |
|||
color: 'blue darken-2', |
|||
icon: 'mdi-kubernetes', |
|||
title: 'Kubernetes' |
|||
}, |
|||
linux: { |
|||
color: 'grey darken-3', |
|||
icon: 'mdi-linux', |
|||
title: 'Linux' |
|||
}, |
|||
mac: { |
|||
color: 'grey darken-2', |
|||
icon: 'mdi-apple', |
|||
title: 'Mac' |
|||
}, |
|||
server: { |
|||
color: 'grey', |
|||
icon: 'mdi-server', |
|||
title: 'Server' |
|||
}, |
|||
windows: { |
|||
color: 'blue darken-2', |
|||
icon: 'mdi-windows', |
|||
title: 'Windows' |
|||
} |
|||
}, |
|||
endpointGroups: [ |
|||
{ |
|||
id: '345678', |
|||
name: '', |
|||
description: '', |
|||
endpoints: [ |
|||
{ method: 'GET', path: '/pet', expanded: false, id: '234567' } |
|||
] |
|||
} |
|||
], |
|||
endpointMethods: [ |
|||
{ key: 'GET', color: 'blue' }, |
|||
{ key: 'POST', color: 'green' }, |
|||
{ key: 'PUT', color: 'orange' }, |
|||
{ key: 'PATCH', color: 'cyan' }, |
|||
{ key: 'DELETE', color: 'red' }, |
|||
{ key: 'HEAD', color: 'deep-purple' }, |
|||
{ key: 'OPTIONS', color: 'blue-grey' } |
|||
] |
|||
} |
|||
}, |
|||
computed: { |
|||
isMobile() { |
|||
return this.$vuetify.breakpoint.smAndDown |
|||
}, |
|||
locale: get('page/locale'), |
|||
path: get('page/path'), |
|||
mode: get('editor/mode'), |
|||
activeModal: sync('editor/activeModal') |
|||
}, |
|||
methods: { |
|||
iconColor (val) { |
|||
return _.get(this.serverTypes, `${val}.color`, 'white') |
|||
}, |
|||
iconKey (val) { |
|||
return _.get(this.serverTypes, `${val}.icon`, 'mdi-server') |
|||
}, |
|||
methodColor (val) { |
|||
return _.get(_.find(this.endpointMethods, ['key', val]), 'color', 'grey') |
|||
}, |
|||
addServer () { |
|||
this.servers.push({ |
|||
id: uuid(), |
|||
name: 'Production', |
|||
url: 'https://api.example.com/v1', |
|||
icon: 'server' |
|||
}) |
|||
}, |
|||
removeServer (id) { |
|||
this.servers = _.reject(this.servers, ['id', id]) |
|||
}, |
|||
addGroup () { |
|||
this.endpointGroups.push({ |
|||
id: uuid(), |
|||
name: '', |
|||
description: '', |
|||
endpoints: [] |
|||
}) |
|||
}, |
|||
addEndpoint (grp) { |
|||
grp.endpoints.push({ |
|||
id: uuid(), |
|||
method: 'GET', |
|||
path: '/pet', |
|||
expanded: false |
|||
}) |
|||
}, |
|||
removeEndpoint (grp, eptId) { |
|||
grp.endpoints = _.reject(grp.endpoints, ['id', eptId]) |
|||
}, |
|||
toggleModal(key) { |
|||
this.activeModal = (this.activeModal === key) ? '' : key |
|||
this.helpShown = false |
|||
}, |
|||
closeAllModal() { |
|||
this.activeModal = '' |
|||
this.helpShown = false |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$store.set('editor/editorKey', 'api') |
|||
|
|||
if (this.mode === 'create') { |
|||
this.$store.set('editor/content', '<h1>Title</h1>\n\n<p>Some text here</p>') |
|||
} |
|||
}, |
|||
beforeDestroy() { |
|||
this.$root.$off('editorInsert') |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss'> |
|||
$editor-height: calc(100vh - 64px - 24px); |
|||
$editor-height-mobile: calc(100vh - 56px - 16px); |
|||
|
|||
.editor-api { |
|||
&-main { |
|||
display: flex; |
|||
width: 100%; |
|||
} |
|||
|
|||
&-editor { |
|||
background-color: darken(mc('grey', '100'), 4.5%); |
|||
flex: 1 1 50%; |
|||
display: block; |
|||
height: $editor-height; |
|||
position: relative; |
|||
|
|||
@at-root .theme--dark & { |
|||
background-color: darken(mc('grey', '900'), 4.5%); |
|||
} |
|||
} |
|||
|
|||
&-sidebar { |
|||
width: 200px; |
|||
} |
|||
|
|||
&-sysbar { |
|||
padding-left: 0 !important; |
|||
|
|||
&-locale { |
|||
background-color: rgba(255,255,255,.25); |
|||
display:inline-flex; |
|||
padding: 0 12px; |
|||
height: 24px; |
|||
width: 63px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
} |
|||
|
|||
} |
|||
</style> |
@ -0,0 +1 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#ff4081" d="M24.5,45.161L7,34.82V14.18L24.5,3.839L42,14.18V34.82L24.5,45.161z M9,33.68l15.5,9.159L40,33.68 V15.32L24.5,6.161L9,15.32V33.68z"/><circle cx="24.5" cy="5.5" r="3.5" fill="#ff4081"/><circle cx="24.5" cy="43.5" r="3.5" fill="#ff4081"/><circle cx="8.5" cy="33.5" r="3.5" fill="#ff4081"/><circle cx="40.5" cy="33.5" r="3.5" fill="#ff4081"/><circle cx="8.5" cy="15.5" r="3.5" fill="#ff4081"/><circle cx="40.5" cy="15.5" r="3.5" fill="#ff4081"/><path fill="#ff4081" d="M42.72,35H6.28L24.5,2.978L42.72,35z M9.72,33H39.28L24.5,7.022L9.72,33z"/></svg> |
@ -0,0 +1 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128px" height="128px"><path fill="#fff" d="M14,108V25c0-2.761,2.239-5,5-5h90c2.761,0,5,2.239,5,5v83"/><path fill="none" stroke="#9eb9d3" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6" d="M28 61L35 61M47 61L76 61"/><path fill="#9eb9d3" d="M88 58A3 3 0 1 0 88 64 3 3 0 1 0 88 58zM100 58A3 3 0 1 0 100 64 3 3 0 1 0 100 58z"/><path fill="none" stroke="#9eb9d3" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6" d="M28 77L35 77M47 77L76 77"/><path fill="#9eb9d3" d="M100 74A3 3 0 1 0 100 80A3 3 0 1 0 100 74Z"/><path fill="none" stroke="#9eb9d3" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6" d="M28 93L35 93M47 93L76 93"/><path fill="#9eb9d3" d="M88 90A3 3 0 1 0 88 96 3 3 0 1 0 88 90zM100 90A3 3 0 1 0 100 96 3 3 0 1 0 100 90zM114 43H14V25c0-2.761 2.239-5 5-5h90c2.761 0 5 2.239 5 5V43z"/><path fill="#fff" d="M104,30H69c-1.657,0-3,1.343-3,3c0,1.657,1.343,3,3,3h35c1.657,0,3-1.343,3-3S105.657,30,104,30z"/><path fill="none" stroke="#444b54" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6" d="M14,108V25 c0-2.761,2.239-5,5-5h90c2.761,0,5,2.239,5,5v83"/><path fill="#fff" d="M24 30A3 3 0 1 0 24 36 3 3 0 1 0 24 30zM34 30A3 3 0 1 0 34 36 3 3 0 1 0 34 30zM44 30A3 3 0 1 0 44 36 3 3 0 1 0 44 30z"/></svg> |
@ -0,0 +1,6 @@ |
|||
key: api |
|||
title: API Docs |
|||
description: REST / GraphQL Editor |
|||
contentType: yml |
|||
author: requarks.io |
|||
props: {} |
2358
yarn.lock
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save