You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

433 lines
16 KiB

  1. <template lang='pug'>
  2. .editor-api
  3. .editor-api-main
  4. v-list.editor-api-sidebar.radius-0(nav, :class='$vuetify.theme.dark ? `grey darken-4` : `primary`', dark)
  5. v-list-item-group(v-model='tab')
  6. v-list-item.animated.fadeInLeft(value='info')
  7. v-list-item-icon: v-icon mdi-book-information-variant
  8. v-list-item-title Info
  9. v-list-item.mt-3.animated.fadeInLeft.wait-p2s(value='servers')
  10. v-list-item-icon: v-icon mdi-server
  11. v-list-item-title Servers
  12. v-list-item.mt-3.animated.fadeInLeft.wait-p3s(value='endpoints')
  13. v-list-item-icon: v-icon mdi-code-braces
  14. v-list-item-title Endpoints
  15. v-list-item.mt-3.animated.fadeInLeft.wait-p4s(value='models')
  16. v-list-item-icon: v-icon mdi-buffer
  17. v-list-item-title Models
  18. v-list-item.mt-3.animated.fadeInLeft.wait-p5s(value='auth')
  19. v-list-item-icon: v-icon mdi-lock
  20. v-list-item-title Authentication
  21. .editor-api-editor
  22. template(v-if='tab === `info`')
  23. v-container.px-2.pt-1(fluid)
  24. v-row(dense)
  25. v-col(cols='12')
  26. .pa-3
  27. .subtitle-2 API General Information
  28. .caption.grey--text.text--darken-1 Global metadata about the API
  29. v-col(cols='12', lg='6')
  30. v-card.pt-2
  31. v-card-text
  32. v-text-field(
  33. label='Title'
  34. outlined
  35. hint='Required - Title of the API'
  36. persistent-hint
  37. v-model='info.title'
  38. )
  39. v-divider.mt-2.mb-4
  40. v-text-field(
  41. label='Version'
  42. outlined
  43. hint='Required - Semantic versioning like 1.0.0 or an arbitrary string like 0.99-beta.'
  44. persistent-hint
  45. v-model='info.version'
  46. )
  47. v-divider.mt-2.mb-4
  48. v-textarea(
  49. label='Description'
  50. outlined
  51. hint='Optional - Markdown formatting is supported.'
  52. persistent-hint
  53. v-model='info.description'
  54. )
  55. v-col(cols='12', lg='6')
  56. v-card.pt-2
  57. v-card-text
  58. v-list(nav, two-line)
  59. v-list-item-group(v-model='kind', mandatory, color='primary')
  60. v-list-item(value='rest')
  61. v-list-item-avatar
  62. img(src='/svg/icon-transaction-list.svg', alt='REST')
  63. v-list-item-content
  64. v-list-item-title REST API
  65. v-list-item-subtitle Classic REST Endpoints
  66. v-list-item-avatar
  67. v-icon(:color='kind === `rest` ? `primary` : `grey lighten-3`') mdi-check-circle
  68. v-list-item(value='graphql', disabled)
  69. v-list-item-avatar
  70. img(src='/svg/icon-graphql.svg', alt='GraphQL')
  71. v-list-item-content
  72. v-list-item-title GraphQL
  73. v-list-item-subtitle.grey--text.text--lighten-1 Schema-based API
  74. v-list-item-action
  75. //- v-icon(:color='kind === `graphql` ? `primary` : `grey lighten-3`') mdi-check-circle
  76. v-chip(label, small) Coming soon
  77. template(v-else-if='tab === `servers`')
  78. v-container.px-2.pt-1(fluid)
  79. v-row(dense)
  80. v-col(cols='12')
  81. .pa-3
  82. .d-flex.align-center.justify-space-between
  83. div
  84. .subtitle-2 List of servers / load balancers where this API reside
  85. .caption.grey--text.text--darken-1 Enter all environments, e.g. Integration, QA, Pre-production, Production, etc.
  86. v-btn(color='primary', large, @click='addServer')
  87. v-icon(left) mdi-plus
  88. span Add Server
  89. v-col(cols='12', lg='6', v-for='srv of servers', :key='srv.id')
  90. v-card.pt-1
  91. v-card-text
  92. .d-flex
  93. .d-flex.flex-column.justify-space-between
  94. v-menu(offset-y, min-width='200')
  95. template(v-slot:activator='{ on }')
  96. v-btn(text, x-large, style='min-width: 0;', v-on='on')
  97. v-icon(large, :color='iconColor(srv.icon)') {{iconKey(srv.icon)}}
  98. v-list(nav, dense)
  99. v-list-item-group(v-model='srv.icon', mandatory)
  100. v-list-item(:value='srvKey', v-for='(srv, srvKey) in serverTypes', :key='srvKey')
  101. v-list-item-icon: v-icon(large, :color='srv.color', v-text='srv.icon')
  102. v-list-item-content: v-list-item-title(v-text='srv.title')
  103. v-btn.mb-2(depressed, small, @click='removeServer(srv.id)')
  104. v-icon(left) mdi-close
  105. span Delete
  106. v-divider.ml-5(vertical)
  107. .pl-5(style='flex: 1 1 100%;')
  108. v-text-field(
  109. label='Environment / Server Name'
  110. outlined
  111. hint='Required - Name of the environment (e.g. QA, Production)'
  112. persistent-hint
  113. v-model='srv.name'
  114. )
  115. v-text-field.mt-4(
  116. label='URL'
  117. outlined
  118. hint='Required - URL of the environment (e.g. https://api.example.com/v1)'
  119. persistent-hint
  120. v-model='srv.url'
  121. )
  122. template(v-else-if='tab === `endpoints`')
  123. v-container.px-2.pt-1(fluid)
  124. v-row(dense)
  125. v-col(cols='12')
  126. .pa-3
  127. .d-flex.align-center.justify-space-between
  128. div
  129. .subtitle-2 List of endpoints
  130. .caption.grey--text.text--darken-1 Groups of REST endpoints (GET, POST, PUT, DELETE).
  131. v-btn(color='primary', large, @click='addGroup')
  132. v-icon(left) mdi-plus
  133. span Add Group
  134. v-col(cols='12', v-for='grp of endpointGroups', :key='grp.id')
  135. v-card(color='grey darken-2')
  136. v-card-text
  137. v-toolbar(color='grey darken-2', flat, height='86')
  138. v-text-field.mr-1(
  139. flat
  140. dark
  141. label='Group Name'
  142. solo
  143. hint='Group Name'
  144. persistent-hint
  145. v-model='grp.name'
  146. )
  147. v-text-field.mx-1(
  148. flat
  149. dark
  150. label='Group Description'
  151. solo
  152. hint='Group Description'
  153. persistent-hint
  154. v-model='grp.description'
  155. )
  156. v-divider.mx-3(vertical, dark)
  157. v-btn.mx-1.align-self-start(color='grey lighten-2', @click='addEndpoint(grp)', dark, text, height='48')
  158. v-icon(left) mdi-trash-can
  159. span Delete
  160. v-divider.mx-3(vertical, dark)
  161. v-btn.ml-1.align-self-start(color='pink', @click='addEndpoint(grp)', dark, depressed, height='48')
  162. v-icon(left) mdi-plus
  163. span Add Endpoint
  164. v-container.pa-0.mt-2(fluid)
  165. v-row(dense)
  166. v-col(cols='12', v-for='ept of grp.endpoints', :key='ept.id')
  167. v-card.pt-1
  168. v-card-text
  169. .d-flex
  170. .d-flex.flex-column
  171. v-menu(offset-y, min-width='140')
  172. template(v-slot:activator='{ on }')
  173. v-btn.subtitle-1(depressed, large, dark, style='min-width: 140px;', height='48', v-on='on', :color='methodColor(ept.method)')
  174. strong {{ept.method}}
  175. v-list(nav, dense)
  176. v-list-item-group(v-model='ept.method', mandatory)
  177. v-list-item(:value='mtd.key', v-for='mtd of endpointMethods', :key='mtd.key')
  178. v-list-item-content
  179. v-chip.text-center(label, :color='mtd.color', dark) {{mtd.key}}
  180. v-btn.mt-2(v-if='!ept.expanded', small, @click='ept.expanded = true', color='pink', outlined)
  181. v-icon(left) mdi-arrow-down-box
  182. span Expand
  183. v-btn.mt-2(v-else, small, @click='ept.expanded = false', color='pink', outlined)
  184. v-icon(left) mdi-arrow-up-box
  185. span Collapse
  186. template(v-if='ept.expanded')
  187. v-spacer
  188. v-btn.my-2(depressed, small, @click='removeEndpoint(grp, ept.id)')
  189. v-icon(left) mdi-close
  190. span Delete
  191. v-divider.ml-5(vertical)
  192. .pl-5(style='flex: 1 1 100%;')
  193. .d-flex
  194. v-text-field.mr-2(
  195. label='Path'
  196. outlined
  197. hint='Required - Path to the endpoint (e.g. /planets/{planetId})'
  198. persistent-hint
  199. v-model='ept.path'
  200. )
  201. v-text-field.ml-2(
  202. label='Summary'
  203. outlined
  204. hint='Required - A short summary of the endpoint (a few words).'
  205. persistent-hint
  206. v-model='ept.summary'
  207. )
  208. template(v-if='ept.expanded')
  209. v-text-field.mt-3(
  210. label='Description'
  211. outlined
  212. v-model='ept.description'
  213. )
  214. v-system-bar.editor-api-sysbar(dark, status, color='grey darken-3')
  215. .caption.editor-api-sysbar-locale {{locale.toUpperCase()}}
  216. .caption.px-3 /{{path}}
  217. template(v-if='$vuetify.breakpoint.mdAndUp')
  218. v-spacer
  219. .caption API Docs
  220. v-spacer
  221. .caption OpenAPI 3.0
  222. </template>
  223. <script>
  224. import _ from 'lodash'
  225. import { v4 as uuid } from 'uuid'
  226. import { get, sync } from 'vuex-pathify'
  227. export default {
  228. data() {
  229. return {
  230. tab: `endpoints`,
  231. kind: 'rest',
  232. kinds: [
  233. { text: 'REST', value: 'rest' },
  234. { text: 'GraphQL', value: 'graphql' }
  235. ],
  236. info: {
  237. title: '',
  238. version: '1.0.0',
  239. description: ''
  240. },
  241. servers: [
  242. { name: 'Production', url: 'https://api.example.com/v1', icon: 'server', id: '123456' }
  243. ],
  244. serverTypes: {
  245. aws: {
  246. color: 'orange',
  247. icon: 'mdi-aws',
  248. title: 'AWS'
  249. },
  250. azure: {
  251. color: 'blue darken-2',
  252. icon: 'mdi-azure',
  253. title: 'Azure'
  254. },
  255. digitalocean: {
  256. color: 'blue',
  257. icon: 'mdi-digital-ocean',
  258. title: 'DigitalOcean'
  259. },
  260. docker: {
  261. color: 'blue',
  262. icon: 'mdi-docker',
  263. title: 'Docker'
  264. },
  265. google: {
  266. color: 'red',
  267. icon: 'mdi-google',
  268. title: 'Google'
  269. },
  270. kubernetes: {
  271. color: 'blue darken-2',
  272. icon: 'mdi-kubernetes',
  273. title: 'Kubernetes'
  274. },
  275. linux: {
  276. color: 'grey darken-3',
  277. icon: 'mdi-linux',
  278. title: 'Linux'
  279. },
  280. mac: {
  281. color: 'grey darken-2',
  282. icon: 'mdi-apple',
  283. title: 'Mac'
  284. },
  285. server: {
  286. color: 'grey',
  287. icon: 'mdi-server',
  288. title: 'Server'
  289. },
  290. windows: {
  291. color: 'blue darken-2',
  292. icon: 'mdi-windows',
  293. title: 'Windows'
  294. }
  295. },
  296. endpointGroups: [
  297. {
  298. id: '345678',
  299. name: '',
  300. description: '',
  301. endpoints: [
  302. { method: 'GET', path: '/pet', expanded: false, id: '234567' }
  303. ]
  304. }
  305. ],
  306. endpointMethods: [
  307. { key: 'GET', color: 'blue' },
  308. { key: 'POST', color: 'green' },
  309. { key: 'PUT', color: 'orange' },
  310. { key: 'PATCH', color: 'cyan' },
  311. { key: 'DELETE', color: 'red' },
  312. { key: 'HEAD', color: 'deep-purple' },
  313. { key: 'OPTIONS', color: 'blue-grey' }
  314. ]
  315. }
  316. },
  317. computed: {
  318. isMobile() {
  319. return this.$vuetify.breakpoint.smAndDown
  320. },
  321. locale: get('page/locale'),
  322. path: get('page/path'),
  323. mode: get('editor/mode'),
  324. activeModal: sync('editor/activeModal')
  325. },
  326. methods: {
  327. iconColor (val) {
  328. return _.get(this.serverTypes, `${val}.color`, 'white')
  329. },
  330. iconKey (val) {
  331. return _.get(this.serverTypes, `${val}.icon`, 'mdi-server')
  332. },
  333. methodColor (val) {
  334. return _.get(_.find(this.endpointMethods, ['key', val]), 'color', 'grey')
  335. },
  336. addServer () {
  337. this.servers.push({
  338. id: uuid(),
  339. name: 'Production',
  340. url: 'https://api.example.com/v1',
  341. icon: 'server'
  342. })
  343. },
  344. removeServer (id) {
  345. this.servers = _.reject(this.servers, ['id', id])
  346. },
  347. addGroup () {
  348. this.endpointGroups.push({
  349. id: uuid(),
  350. name: '',
  351. description: '',
  352. endpoints: []
  353. })
  354. },
  355. addEndpoint (grp) {
  356. grp.endpoints.push({
  357. id: uuid(),
  358. method: 'GET',
  359. path: '/pet',
  360. expanded: false
  361. })
  362. },
  363. removeEndpoint (grp, eptId) {
  364. grp.endpoints = _.reject(grp.endpoints, ['id', eptId])
  365. },
  366. toggleModal(key) {
  367. this.activeModal = (this.activeModal === key) ? '' : key
  368. this.helpShown = false
  369. },
  370. closeAllModal() {
  371. this.activeModal = ''
  372. this.helpShown = false
  373. }
  374. },
  375. mounted() {
  376. this.$store.set('editor/editorKey', 'api')
  377. if (this.mode === 'create') {
  378. this.$store.set('editor/content', '<h1>Title</h1>\n\n<p>Some text here</p>')
  379. }
  380. },
  381. beforeDestroy() {
  382. this.$root.$off('editorInsert')
  383. }
  384. }
  385. </script>
  386. <style lang='scss'>
  387. $editor-height: calc(100vh - 64px - 24px);
  388. $editor-height-mobile: calc(100vh - 56px - 16px);
  389. .editor-api {
  390. &-main {
  391. display: flex;
  392. width: 100%;
  393. }
  394. &-editor {
  395. background-color: darken(mc('grey', '100'), 4.5%);
  396. flex: 1 1 50%;
  397. display: block;
  398. height: $editor-height;
  399. position: relative;
  400. @at-root .theme--dark & {
  401. background-color: darken(mc('grey', '900'), 4.5%);
  402. }
  403. }
  404. &-sidebar {
  405. width: 200px;
  406. }
  407. &-sysbar {
  408. padding-left: 0 !important;
  409. &-locale {
  410. background-color: rgba(255,255,255,.25);
  411. display:inline-flex;
  412. padding: 0 12px;
  413. height: 24px;
  414. width: 63px;
  415. justify-content: center;
  416. align-items: center;
  417. }
  418. }
  419. }
  420. </style>