mirror of https://github.com/nocodb/nocodb
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.
808 lines
28 KiB
808 lines
28 KiB
<template> |
|
<v-container fluid class="api-client grid-list-xs pa-0 " style="height: 100%;"> |
|
<splitpanes style="height:100%;" class="xc-theme"> |
|
<pane min-size="20" max-size="50" size="30" style="overflow: auto"> |
|
|
|
|
|
<v-tabs height="32"> |
|
<v-tab>History</v-tab> |
|
<v-tab>Collection</v-tab> |
|
|
|
|
|
<v-tab-item style="border-top: 1px solid grey"> |
|
<div class="apis-list"> |
|
<div v-for="(api,i) in $store.state.apiClient.list" :key="i" class="pa-0 ma-0 "> |
|
<v-list-item dense two-line @click="apiClickedOnList(api)"> |
|
|
|
<v-hover v-slot:default="{ hover }"> |
|
<v-list-item-content> |
|
<v-list-item-title class="grey--text"> |
|
<v-btn class="pl-0 ml-0" small text :tooltip="api.url" :color="apiMeta[api.type].color" |
|
> |
|
<b> |
|
<v-icon class="mx-0 ml-n2" |
|
:class="{'white--text': !api.response || !api.response.status,'red--text': api.response && api.response.status >= 400, 'green--text':api.response && api.response.status < 400}"> |
|
mdi-circle-small |
|
</v-icon> |
|
{{api.type}} </b> |
|
</v-btn> |
|
|
|
|
|
{{api.url}} |
|
</v-list-item-title> |
|
<v-list-item-subtitle v-show="!i || hover" class="text-right"> |
|
<span v-show="!i && !hover" class="grey--text text--darken-1 caption">(Last invoked API)</span> |
|
<v-btn small text v-show="hover" class=" " @click="apiDeleteFromList(i)"> |
|
<v-icon small>mdi-delete</v-icon> |
|
</v-btn> |
|
</v-list-item-subtitle> |
|
</v-list-item-content> |
|
</v-hover> |
|
</v-list-item> |
|
<v-divider></v-divider> |
|
</div> |
|
</div> |
|
</v-tab-item> |
|
<v-tab-item style="border-top: 1px solid grey"> |
|
<v-row class="pa-0 ma-0 pa-2 pl-2"> |
|
<div class="primary--text cursor-pointer" @click="openApiFileCollection"> |
|
<x-icon class="mr-1 cursor-pointer" @click="openNewCollection('/')" color="primary" |
|
tooltip="Create New API Collection">mdi-folder-plus-outline |
|
</x-icon> |
|
|
|
<x-icon class="mr-1" color="primary" tooltip="Open API Collection">mdi-folder-open-outline</x-icon> |
|
|
|
</div> |
|
</v-row> |
|
<v-divider></v-divider> |
|
<v-expansion-panels accordion focusable v-model="curApiCollectionPanel"> |
|
<v-expansion-panel |
|
v-for="(apiTv,i) in apiTvs" |
|
:key="i"> |
|
<v-expansion-panel-header hide-actions> |
|
<template v-slot:default="{open}"> |
|
<div class="d-flex"> |
|
|
|
<v-icon color="">{{open ? 'mdi-menu-down' : 'mdi-menu-right' }}</v-icon> |
|
<v-icon small color="grey" class="ml-1 mr-2">mdi-folder</v-icon> |
|
<span class="body-2 flex-grow-1">{{$store.getters['apiClient/GtrCurrentApiFilePaths'][i].fileName}}</span> |
|
|
|
<x-icon color="white grey" class="float-right mr-3" small |
|
@click="showCtxMenu[i]=true,x = $event.clientX,y = $event.clientY;" |
|
@click.stop=""> |
|
mdi-dots-horizontal |
|
</x-icon> |
|
|
|
<recursive-menu v-model="showCtxMenu[i]" |
|
:position-x="x" |
|
:position-y="y" |
|
:items="{ |
|
'Add Folder':'add-folder', |
|
'Reveal in Folder':'reveal-in-folder', |
|
'Delete Collection':'delete-collection', |
|
'Refresh Collection' : 'refresh-collection' |
|
}" |
|
@click="ctxMenuClickHandler($event,i)"> |
|
</recursive-menu> |
|
|
|
</div> |
|
</template> |
|
</v-expansion-panel-header> |
|
<v-expansion-panel-content class="expansion-wrap-0"> |
|
<vue-tree-list |
|
style="cursor: pointer" |
|
v-if="apiTvs[i]" |
|
class="body-2 sql-query-treeview px-1 pt-2 api-treeview" |
|
@click="tvNodeOnClick" |
|
@change-name="tvNodeRename" |
|
@delete-node="tvNodeDelete" |
|
@add-node="onAddNode" |
|
:model="apiTv" |
|
default-tree-node-name="new node" |
|
default-leaf-node-name="new leaf" |
|
v-bind:default-expanded="false"><span slot="leafNodeIcon"></span> |
|
<v-icon slot="treeNodeIcon" small color="grey" class="mr-1">mdi-folder-star</v-icon> |
|
|
|
<v-icon slot="addTreeNode" small>mdi-folder-plus</v-icon> |
|
<v-icon slot="addLeafNode" small>mdi-file-plus</v-icon> |
|
<v-icon slot="editNode" small class="mt-n1">mdi-file-edit</v-icon> |
|
<v-icon slot="delNode" small>mdi-delete</v-icon> |
|
<template v-slot:label="{item:api}"> |
|
<div v-if="api.isLeaf" class="d-flex" style="width: 100%"> |
|
<!-- <v-icon class="mx-0"--> |
|
<!-- :class="`${apiMeta[api.type].color}--text`"--> |
|
<!-- small>--> |
|
<!-- mdi-bookmark-outline--> |
|
<!-- </v-icon>--> |
|
<b style="display: inline-block;min-width: 45px;" :class="`${apiMeta[api.type].color}--text`"> |
|
{{api.type === 'DELETE' ? 'DEL' : api.type}} </b> |
|
|
|
<span class="grey--text d-block" style="text-overflow: ellipsis; |
|
overflow: hidden; |
|
white-space: nowrap;">{{api.name}}</span> |
|
</div> |
|
<div v-else style="width: 100%;text-overflow: ellipsis; |
|
overflow: hidden; |
|
white-space: nowrap;">{{api.name}} |
|
</div> |
|
</template> |
|
</vue-tree-list> |
|
</v-expansion-panel-content> |
|
</v-expansion-panel> |
|
</v-expansion-panels> |
|
</v-tab-item> |
|
</v-tabs> |
|
</pane> |
|
<pane min-size="10" size="75" style="overflow: auto"> |
|
|
|
<v-toolbar class=" toolbar-border-bottom elevation-0 d-flex req-inputs" height="55" |
|
style="position: relative;z-index:2;width: 100%"> |
|
|
|
<v-select |
|
:items="Object.keys(apiMeta)" |
|
v-model="api.type" |
|
dense |
|
solo |
|
hide-details |
|
outlined |
|
class="body-2" |
|
style="max-width:130px;border-bottom-right-radius: 0;border-top-right-radius: 0;border-right: 1px solid grey" |
|
></v-select> |
|
|
|
|
|
<xAutoComplete |
|
outlined |
|
class="flex-grow-1" |
|
:env="selectedEnv" |
|
placeholder="Enter HTTP URL" |
|
solo |
|
dense |
|
hide-details |
|
autofocus |
|
styles="border-bottom-left-radius: 0;border-top-left-radius:0 " |
|
v-model="api.url"></xAutoComplete> |
|
|
|
|
|
<x-btn btn.class="primary" dense @click.prevent="apiSend()" tooltip="Send Request"> |
|
<v-icon small class="ml-n3" v-if="isPerfFilled">mdi-truck-fast</v-icon> |
|
<v-icon small class="ml-n3" v-else>mdi-send</v-icon> |
|
SEND |
|
</x-btn> |
|
<x-btn btn.class="outlined" dense @click.prevent="bookmarkApi()" icon="save" |
|
tooltip="Save API"> |
|
</x-btn> |
|
<x-btn icon="mdi-eye-outline" v-if="$store.getters['project/GtrProjectJson']" |
|
@click="environmentDialog = true" tooltip="Environments"> |
|
|
|
</x-btn> |
|
|
|
</v-toolbar> |
|
|
|
|
|
<splitpanes horizontal style="height:calc(100% - 64px)" class="xc-theme"> |
|
<pane min-size="25" size="50" style="overflow: auto;" class="pa-1"> |
|
|
|
<v-tabs |
|
class="req-tabs" |
|
height="24" |
|
> |
|
<v-tab class="caption">Params <b v-if="paramsCount" class="green--text">({{paramsCount}})</b> |
|
</v-tab> |
|
<v-tab class="caption">Headers <b v-if="headersCount" class="green--text">({{headersCount }})</b> |
|
</v-tab> |
|
<v-tab class="caption">Body</v-tab> |
|
<v-tab class="caption">Auth</v-tab> |
|
<v-tab class="caption">Perf Test</v-tab> |
|
<div class="flex-grow-1 d-flex text-right pr-4 justify-end "> |
|
<div class="flex-shrink-1 "> |
|
<v-select |
|
v-model="selectedEnv" |
|
height="19" |
|
class="caption envs" |
|
dense |
|
:items="environmentList" |
|
placeholder="Environment" |
|
single-line |
|
> |
|
<template v-slot:selection="{item}"> |
|
<span |
|
style="text-transform: uppercase">{{item}}</span> <span class="grey--text">(env)</span> |
|
</template> |
|
|
|
</v-select> |
|
|
|
</div> |
|
</div> |
|
<!-- <div class="flex-grow-1 text-right pr-4 caption" v-if="api.response">--> |
|
<!-- <!– <x-icon iconClass="mr-4" v-if="$store.getters['project/GtrProjectJson']" @click="environmentDialog = true" tooltip="Environments">–>--> |
|
<!-- <!– mdi-eye-outline–>--> |
|
<!-- <!– </x-icon>–>--> |
|
<!-- </div>--> |
|
<v-tab-item> |
|
|
|
<params v-model="api.params" |
|
:env.sync="selectedEnv" |
|
></params> |
|
</v-tab-item> |
|
<v-tab-item> |
|
<headers v-model="api.headers" |
|
:env.sync="selectedEnv" |
|
></headers> |
|
</v-tab-item> |
|
<v-tab-item> |
|
<monaco-json-editor |
|
style="height: 250px" |
|
class="editor card" |
|
theme="vs-dark" |
|
v-model="api.body" |
|
language="json" |
|
:options="{validate:true,documentFormattingEdits:true,foldingRanges:true}" |
|
> |
|
</monaco-json-editor> |
|
|
|
</v-tab-item> |
|
<v-tab-item> |
|
<!-- <monaco-editor--> |
|
<!-- :code.sync="api.auth"--> |
|
<!-- cssStyle="height:250px"></monaco-editor>--> |
|
</v-tab-item> |
|
|
|
<v-tab-item> |
|
<perf-test v-model="api.perf"></perf-test> |
|
</v-tab-item> |
|
|
|
</v-tabs> |
|
</pane> |
|
<pane min-size="25" size="50" style="overflow: auto" class="pa-1"> |
|
<!-- <h3 class="mb-2 grey--text lighten-1">--> |
|
<!-- Response Body :--> |
|
<!-- <div v-if="api.response">--> |
|
<!-- <span v-if="api.response.status === 200" class="green--text">{{api.response.status}}</span>--> |
|
<!-- <span v-if="api.response.status !== 200" class="red--text">{{api.response.status}}</span>--> |
|
<!-- </div>--> |
|
<!-- </h3>--> |
|
|
|
|
|
<v-tabs |
|
v-if="api.response" |
|
height="24" |
|
> |
|
<v-tab class="caption">Body</v-tab> |
|
<v-tab class="caption">Headers<span class="green--text" v-if="api.response.headers">( {{Object.keys(api.response.headers).length}} )</span> |
|
</v-tab> |
|
<div class="flex-grow-1 text-right pr-4 caption" v-if="api.response"> |
|
<template v-if="api.response.status"><span class="grey--text">Status:</span><span :class="{ |
|
'green--text' : api.response.status === 200 , |
|
'red--text' : api.response.status !== 200 |
|
}"><b>{{api.response.status}}</b></span></template> |
|
|
|
|
|
<template v-if="api.timeTaken"><span class="grey--text">Time:</span><span class="green--text"><b>{{api.timeTaken}}ms</b></span> |
|
</template> |
|
|
|
|
|
</div> |
|
<v-tab-item> |
|
<code v-if="api.response" class="black pa-1 grey--text " |
|
style="overflow-x: auto;min-height:50px;overflow-y:auto;min-width: 100%">{{api.response.data}}</code> |
|
|
|
<!-- <pre v-if="api.response" class="black pa-1" style="overflow-x: auto;min-height:50px;overflow-y:auto">{{api.response.data}}</pre>--> |
|
</v-tab-item> |
|
<v-tab-item> |
|
<code v-if="api.response" class="black pa-1 grey--text " |
|
style="overflow-x: auto;min-height:50px;overflow-y:auto;min-width: 100%">{{api.response.headers}}</code> |
|
</v-tab-item> |
|
</v-tabs> |
|
</pane> |
|
</splitpanes> |
|
|
|
</pane> |
|
</splitpanes> |
|
<environment v-if="$store.getters['project/GtrProjectJson']" env="dev" v-model="environmentDialog"></environment> |
|
|
|
</v-container> |
|
</template> |
|
<script> |
|
import {mapGetters, mapActions} from "vuex"; |
|
|
|
import Vue from 'vue'; |
|
|
|
|
|
import {VueTreeList, Tree, TreeNode} from 'vue-tree-list' |
|
import {Splitpanes, Pane} from 'splitpanes' |
|
import params from "../apiClient/params"; |
|
import headers from "../apiClient/headers"; |
|
|
|
import {MonacoJsonEditor} from "../monaco/index"; |
|
|
|
import environment from "../environment"; |
|
import PerfTest from "../apiClient/perfTest"; |
|
|
|
// const {app, dialog, path, fs, shell, FileCollection} = require("electron").remote.require( |
|
// "./libs" |
|
// ); |
|
|
|
|
|
export default { |
|
components: { |
|
PerfTest, |
|
MonacoJsonEditor, |
|
VueTreeList, |
|
Splitpanes, Pane, |
|
params, |
|
headers, |
|
environment |
|
}, |
|
data() { |
|
return { |
|
environmentDialog: false, |
|
showCtxMenu: {}, |
|
apiTvs: [], |
|
apiFilePaths: [], |
|
apiFileCollections: [], |
|
curApiCollectionPanel: null, |
|
|
|
x: 0, |
|
y: 0, |
|
|
|
apiMeta: { |
|
GET: { |
|
color: 'success' |
|
}, |
|
POST: { |
|
color: 'warning' |
|
}, |
|
DELETE: { |
|
color: 'error' |
|
}, |
|
PUT: { |
|
color: 'info' |
|
}, |
|
HEAD: { |
|
color: 'info' |
|
}, |
|
PATCH: { |
|
color: 'info' |
|
}, |
|
}, |
|
|
|
// current api |
|
api: { |
|
type: 'GET', |
|
url: '', |
|
body: '', |
|
params: [], |
|
auth: '', |
|
headers: [], |
|
response: {}, |
|
perf: {} |
|
}, |
|
|
|
} |
|
}, |
|
computed: { |
|
isPerfFilled() { |
|
return this.api.perf && Object.values(this.api.perf).some(v => v) |
|
}, |
|
...mapGetters({ |
|
sqlMgr: "sqlMgr/sqlMgr", |
|
currentProjectFolder: "project/currentProjectFolder", |
|
projectApisFolder: "project/projectApisFolder" |
|
}), |
|
paramsCount() { |
|
return this.api.params && this.api.params.filter(p => p.name && p.enabled).length; |
|
}, |
|
headersCount() { |
|
|
|
return this.api.headers && this.api.headers.filter(h => h.name && h.enabled).length; |
|
}, |
|
environmentList() { |
|
return Object.keys(this.$store.getters['project/GtrApiEnvironment']); |
|
}, |
|
selectedEnv: { |
|
get() { |
|
return this.$store.state.apiClient.activeEnvironment[this.$route.params.project] || this.environmentList[0]; |
|
}, set(env) { |
|
this.$store.commit('apiClient/MutActiveEnvironment', {env, projectId: this.$route.params.project}); |
|
} |
|
} |
|
}, |
|
methods: { |
|
async handleKeyDown({metaKey, key, altKey, shiftKey, ctrlKey}) { |
|
console.log(metaKey, key, altKey, shiftKey, ctrlKey) |
|
// cmd + s -> save |
|
// cmd + l -> reload |
|
// cmd + n -> new |
|
// cmd + d -> delete |
|
// cmd + enter -> send api |
|
|
|
switch ([metaKey, key].join('_')) { |
|
case 'true_s' : |
|
await this.bookmarkApi(); |
|
break; |
|
case 'true_e' : |
|
this.environmentDialog = true |
|
break; |
|
// case 'true_n' : |
|
// this.addColumn(); |
|
// break; |
|
case 'true_d' : |
|
await this.deleteProcedure('showDialog'); |
|
break; |
|
case 'true_Enter' : |
|
await this.apiSend(); |
|
break; |
|
} |
|
}, |
|
|
|
async openCollectionFolder(pathString) { |
|
shell.showItemInFolder(pathString); |
|
}, |
|
async openNewCollection() { |
|
try { |
|
var toLocalPath = path.join(this.currentProjectFolder, 'server', 'tool', this.projectApisFolder); |
|
|
|
var userChosenPath = dialog.showSaveDialog({ |
|
defaultPath: toLocalPath, |
|
filters: [{name: 'JSON', extensions: ['json']}] |
|
}); |
|
|
|
if (userChosenPath) { |
|
console.log(userChosenPath) |
|
fs.writeFileSync(userChosenPath, "[]", 'utf-8'); |
|
let pathObj = { |
|
path: userChosenPath, |
|
fileName: path.basename(userChosenPath) |
|
}; |
|
this.$store.commit('apiClient/MutApiFilePathsAdd', pathObj) |
|
await this.loadFileCollection(pathObj); |
|
} |
|
this.$toast.success('New API collection loaded successfully').goAway(5000); |
|
} catch (e) { |
|
console.log(e); |
|
throw e; |
|
} |
|
|
|
}, |
|
async ctxMenuClickHandler(actionEvent, index) { |
|
console.log(actionEvent, index); |
|
switch (actionEvent.value) { |
|
case 'add-folder': |
|
this.tvNodeFolderAdd(index); |
|
break; |
|
case 'reveal-in-folder': |
|
await this.openCollectionFolder(this.$store.getters['apiClient/GtrCurrentApiFilePaths'][index].path) |
|
break; |
|
case 'delete-collection': |
|
this.$store.commit('apiClient/MutApiFilePathsRemove', index); |
|
this.apiFileCollections.splice(index, 1); |
|
this.apiTvs.splice(index, 1); |
|
break; |
|
case 'refresh-collection': |
|
await this.refreshFileCollection(index); |
|
break; |
|
default: |
|
break; |
|
} |
|
//this.deleteQueryByPath(this.apiTvs, this.menuItem.path); |
|
}, |
|
openUrl(url) { |
|
shell.openExternal(url); |
|
}, |
|
|
|
apiClickedOnList(api) { |
|
this.api = { |
|
...api, |
|
params: api.params && api.params.map(param => ({...param})), |
|
headers: api.headers && api.headers.map(header => ({...header})) |
|
}; |
|
}, |
|
|
|
apiDeleteFromList(index) { |
|
this.$store.commit('apiClient/MutListRemove', index); |
|
}, |
|
|
|
async apiSend() { |
|
|
|
console.log('apiSend') |
|
|
|
if (!this.api.url.trim()) { |
|
this.$toast.info('Please enter http url').goAway(3000); |
|
return; |
|
} |
|
|
|
|
|
const envs = this.$store.getters['project/GtrApiEnvironment'][this.selectedEnv]; |
|
|
|
let apiDecoded = JSON.parse( |
|
JSON.stringify(this.api).replace(/{{\s*(\w+)\s*}}/g, (m, m1) => { |
|
if (m1 in envs) { |
|
return envs[m1]; |
|
} else { |
|
this.$toast.info('Environment variable is not found : ' + m1).goAway(3000); |
|
return m; |
|
} |
|
}) |
|
) |
|
|
|
|
|
let result = await this.$store.dispatch('apiClient/send', {api: this.api, apiDecoded}); |
|
this.api.response = result; |
|
if (result) { |
|
if (result.status === 200) { |
|
//this.$toast.success('API invoked successfully',{duration:1000}); |
|
} else { |
|
this.$toast.error(`Error:${result.status}`, {duration: 1000}); |
|
} |
|
} else { |
|
this.$toast.error(`Some internal error occurred`, {duration: 1000}); |
|
} |
|
|
|
}, |
|
|
|
async fileCollectionReload() { |
|
let data = new Tree(await this.apiFileCollection.read()); |
|
console.log(data); |
|
|
|
this.apiTv = data; |
|
// this.$set(this, 'apiCollections', data); |
|
}, |
|
|
|
async tvNodeDelete(node) { |
|
console.log(node, this.curApiCollectionPanel) |
|
node.remove() |
|
await this.savefileCollections(this.curApiCollectionPanel); |
|
}, |
|
|
|
async tvNodeRename(params) { |
|
console.log(params) |
|
await this.savefileCollections(this.curApiCollectionPanel); |
|
}, |
|
|
|
async onAddNode(params) { |
|
console.log(params) |
|
await this.savefileCollections(this.curApiCollectionPanel); |
|
}, |
|
|
|
async tvNodeOnClick({parent, children, ...params}) { |
|
console.log(params) |
|
this.apiClickedOnList(params); |
|
// if (params.query) ; |
|
// this.selectQuery(params) |
|
}, |
|
|
|
async savefileCollections(index = 0) { |
|
await this.apiFileCollections[index].write({data: this.tvToObject(index)}); |
|
// this.apiTvs = await this.fileCollections.read(); |
|
//this.$set(this.apiTvs, index, this.apiTvs); |
|
}, |
|
|
|
tvToObject(index) { |
|
var vm = this |
|
|
|
function _dfs(oldNode) { |
|
var newNode = {} |
|
|
|
for (var k in oldNode) { |
|
if (k !== 'children' && k !== 'parent') { |
|
newNode[k] = oldNode[k] |
|
} |
|
} |
|
|
|
if (oldNode.children && oldNode.children.length > 0) { |
|
newNode.children = [] |
|
for (var i = 0, len = oldNode.children.length; i < len; i++) { |
|
newNode.children.push(_dfs(oldNode.children[i])) |
|
} |
|
} |
|
return newNode |
|
} |
|
|
|
return _dfs(vm.apiTvs[index]).children |
|
}, |
|
|
|
async tvNodeFolderAdd(index) { |
|
var node = new TreeNode({name: 'New Folder', isLeaf: false, children: []}) |
|
if (!this.apiTvs[index].children) this.apiTvs[index].children = [] |
|
this.apiTvs[index].addChildren(node); |
|
|
|
await this.saveFileCollection(index); |
|
|
|
}, |
|
|
|
openApiFileCollection() { |
|
const vm = this; |
|
// console.log(obj, key); |
|
const file = dialog.showOpenDialog({ |
|
properties: ["openFile"] |
|
}); |
|
|
|
if (file && file[0]) { |
|
let fileName = path.basename(file[0]); |
|
const pathObj = { |
|
path: file[0] + '', |
|
fileName: fileName |
|
}; |
|
|
|
if (this.$store.getters['apiClient/GtrCurrentApiFilePaths'].every(({path: p}) => p !== pathObj.path)) { |
|
this.$store.commit('apiClient/MutApiFilePathsAdd', pathObj) |
|
this.loadFileCollection(pathObj); |
|
} else { |
|
this.$toast.info('File already exist in collection').goAway(4000); |
|
} |
|
} |
|
}, |
|
|
|
async saveFileCollection(index = 0) { |
|
await this.apiFileCollections[index].write({data: this.tvToObject(index)}); |
|
}, |
|
|
|
async loadFileCollection(path, index = 0) { |
|
|
|
try { |
|
const fileCollection = new FileCollection(path); |
|
await fileCollection.init(); |
|
|
|
this.apiFileCollections.push(fileCollection); |
|
|
|
let data = new Tree(await fileCollection.read()); |
|
this.apiTvs.push(data); |
|
} catch (e) { |
|
console.log('Error in loadFileCollection:', e); |
|
throw e; |
|
} |
|
|
|
}, |
|
async refreshFileCollection(index = 0) { |
|
try { |
|
const path = this.$store.getters['apiClient/GtrCurrentApiFilePaths'][index]; |
|
const fileCollection = new FileCollection(path); |
|
await fileCollection.init(); |
|
this.apiFileCollections[index] = fileCollection; |
|
const data = new Tree(await fileCollection.read()); |
|
this.$set(this.apiTvs, index, data); |
|
} catch (e) { |
|
console.log('Error in loadFileCollection:', e); |
|
throw e; |
|
} |
|
|
|
}, |
|
|
|
async bookmarkApi() { |
|
let q = this.api; |
|
var node = new TreeNode({ |
|
"id": Date.now(), |
|
"label": "Latest Api", |
|
"name": "Last Saved Api", |
|
"pid": 0, |
|
isLeaf: true, |
|
...q |
|
}) |
|
|
|
let expandedPanelIndex = this.curApiCollectionPanel; |
|
if (typeof expandedPanelIndex !== 'number' || expandedPanelIndex === -1) { |
|
expandedPanelIndex = this.$store.getters['apiClient/GtrCurrentApiFilePaths'].findIndex( |
|
file => file.path === path.join(this.currentProjectFolder, 'server', 'tool', this.projectApisFolder, 'apis.xc.json') |
|
); |
|
} |
|
|
|
|
|
if (!this.apiTvs[expandedPanelIndex].children) this.apiTvs[expandedPanelIndex].children = [] |
|
this.apiTvs[expandedPanelIndex].addChildren(node) |
|
await this.savefileCollections(expandedPanelIndex); |
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
beforeCreated() { |
|
}, |
|
async created() { |
|
|
|
console.log('ApisList', this.$store.state.apiClient.list); |
|
|
|
this.$store.dispatch('apiClient/loadApiCollectionForProject', { |
|
projectId: this.$route.params.project, |
|
projectName: this.$store.getters['project/GtrProjectName'] |
|
}) |
|
|
|
|
|
try { |
|
|
|
/* load all files that are were previously opened */ |
|
if (!this.$store.getters['apiClient/GtrCurrentApiFilePaths'].length) { |
|
const defaultPath = path.join(this.currentProjectFolder, 'server', 'tool', this.projectApisFolder, 'apis.xc.json'); |
|
this.$store.commit('apiClient/MutApiFilePathsAdd', { |
|
path: defaultPath, |
|
fileName: path.basename(defaultPath) |
|
}) |
|
} |
|
|
|
for (let i = 0; i < this.$store.getters['apiClient/GtrCurrentApiFilePaths'].length; ++i) { |
|
await this.loadFileCollection(this.$store.getters['apiClient/GtrCurrentApiFilePaths'][i]); |
|
} |
|
|
|
|
|
} catch (e) { |
|
console.log('Failed to load previously opened query collections', e); |
|
} |
|
|
|
|
|
if (this.nodes.url) { |
|
Vue.set(this.api, 'type', 'GET'); |
|
this.api.url = this.nodes.url |
|
} |
|
console.log(this.nodes); |
|
}, |
|
mounted() { |
|
}, |
|
beforeDestroy() { |
|
}, |
|
destroy() { |
|
}, |
|
validate({params}) { |
|
return true; |
|
}, |
|
head() { |
|
return {}; |
|
}, |
|
props: ["nodes"], |
|
watch: {}, |
|
directives: {} |
|
}; |
|
</script> |
|
|
|
<style scoped> |
|
|
|
.apis-list { |
|
height: calc(100%); |
|
overflow-y: auto; |
|
} |
|
|
|
.apis-request { |
|
overflow-y: auto; |
|
} |
|
|
|
/deep/ > .req-inputs .v-toolbar__content { |
|
width: 100%; |
|
display: flex; |
|
padding: 2px; |
|
} |
|
|
|
/deep/ .req-tabs > .v-tabs-items { |
|
border-top: 1px solid #7F828B33; |
|
} |
|
|
|
.envs /deep/ .v-select__selections { |
|
color: var(--v-accent-base) |
|
} |
|
|
|
/*.envs /deep/ .v-select__selections input { display: none}*/ |
|
|
|
</style> |
|
|
|
<!-- |
|
/** |
|
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
|
* |
|
* @author Naveen MR <oof1lab@gmail.com> |
|
* @author Pranav C Balan <pranavxc@gmail.com> |
|
* |
|
* @license GNU AGPL version 3 or any later version |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU Affero General Public License as |
|
* published by the Free Software Foundation, either version 3 of the |
|
* License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU Affero General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU Affero General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
* |
|
*/ |
|
-->
|
|
|