| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 | <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='/_assets/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='/_assets/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 { v4 as uuid } from 'uuid'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>
 |