* Initial UI refactor - move raw and key-value body to components and tabs * Delete package-lock.json * deps * Add multipart/form-data as a content type * fix: add default contentType value * Allow http body param request body with multipart/form-data * Add form data to vuex * move raw body components to 'Raw Request Body' tab * Add files addition logic * Set Dockerfile to run nuxt in dev mode * Set Dockerfile to run nuxt in dev mode * Draft version of file upload * refactor: clean up * Add file chip to denote file input * Remove console.log * refactor(ui): matching styles * refactor(ui): matching styles * fix(ui): mobile responsiveness * fix(ui): mobile responsiveness * refactor: minor cleanup * Remove file from any form of persistence * Add warning that form data files will not be saved to local storage * Add remove file functionality * Prevent file from being saved to collections * Remove console.log * fix active toggle on multipart/form-data + cleanup * auto import components Co-authored-by: nelsontky <nelson@ccb.wtf>
398 lines
11 KiB
JavaScript
398 lines
11 KiB
JavaScript
import Vue from "vue"
|
|
|
|
export const SETTINGS_KEYS = [
|
|
/**
|
|
* Whether or not to enable scrolling to a specified element, when certain
|
|
* actions are triggered.
|
|
*/
|
|
"SCROLL_INTO_ENABLED",
|
|
|
|
/**
|
|
* Normally, section frames are multicolored in the UI
|
|
* to emphasise the different sections.
|
|
* This setting allows that to be turned off.
|
|
*/
|
|
"FRAME_COLORS_ENABLED",
|
|
|
|
/**
|
|
* Whether or not requests should be proxied.
|
|
*/
|
|
"PROXY_ENABLED",
|
|
|
|
/**
|
|
* The URL of the proxy to connect to for requests.
|
|
*/
|
|
"PROXY_URL",
|
|
/**
|
|
* The security key of the proxy.
|
|
*/
|
|
"PROXY_KEY",
|
|
|
|
/**
|
|
* An array of properties to exclude from the URL.
|
|
* e.g. 'auth'
|
|
*/
|
|
"URL_EXCLUDES",
|
|
|
|
/**
|
|
* A boolean value indicating whether to use the browser extensions
|
|
* to run the requests
|
|
*/
|
|
"EXTENSIONS_ENABLED",
|
|
|
|
/**
|
|
* A boolean value indicating whether to use the URL bar experiments
|
|
*/
|
|
"EXPERIMENTAL_URL_BAR_ENABLED",
|
|
]
|
|
|
|
export const state = () => ({
|
|
settings: {},
|
|
collections: [
|
|
{
|
|
name: "My Collection",
|
|
folders: [],
|
|
requests: [],
|
|
},
|
|
],
|
|
environments: [
|
|
{
|
|
name: "My Environment Variables",
|
|
variables: [],
|
|
},
|
|
],
|
|
editingEnvironment: {},
|
|
selectedRequest: {},
|
|
editingRequest: {},
|
|
})
|
|
|
|
export const mutations = {
|
|
applySetting({ settings }, setting) {
|
|
if (setting === null || !(setting instanceof Array) || setting.length !== 2) {
|
|
throw new Error("You must provide a setting (array in the form [key, value])")
|
|
}
|
|
|
|
const [key, value] = setting
|
|
// Do not just remove this check.
|
|
// Add your settings key to the SETTINGS_KEYS array at the
|
|
// top of the file.
|
|
// This is to ensure that application settings remain documented.
|
|
if (!SETTINGS_KEYS.includes(key)) {
|
|
throw new Error(`The settings structure does not include the key ${key}`)
|
|
}
|
|
|
|
settings[key] = value
|
|
},
|
|
|
|
removeVariables({ editingEnvironment }, value) {
|
|
editingEnvironment.variables = value
|
|
},
|
|
|
|
setEditingEnvironment(state, value) {
|
|
state.editingEnvironment = { ...value }
|
|
},
|
|
|
|
setVariableKey({ editingEnvironment }, { index, value }) {
|
|
editingEnvironment.variables[index].key = value
|
|
},
|
|
|
|
setVariableValue({ editingEnvironment }, { index, value }) {
|
|
editingEnvironment.variables[index].value = testValue(value)
|
|
},
|
|
|
|
removeVariable({ editingEnvironment }, variables) {
|
|
editingEnvironment.variables = variables
|
|
},
|
|
|
|
addVariable({ editingEnvironment }, value) {
|
|
editingEnvironment.variables.push(value)
|
|
},
|
|
|
|
replaceEnvironments(state, environments) {
|
|
state.environments = environments
|
|
},
|
|
|
|
importAddEnvironments(state, { environments, confirmation }) {
|
|
const duplicateEnvironment = environments.some((item) => {
|
|
return state.environments.some((item2) => {
|
|
return item.name.toLowerCase() === item2.name.toLowerCase()
|
|
})
|
|
})
|
|
if (duplicateEnvironment) {
|
|
this.$toast.info("Duplicate environment")
|
|
return
|
|
}
|
|
state.environments = [...state.environments, ...environments]
|
|
|
|
let index = 0
|
|
for (let environment of state.environments) {
|
|
environment.environmentIndex = index
|
|
index += 1
|
|
}
|
|
this.$toast.info(confirmation, {
|
|
icon: "folder_shared",
|
|
})
|
|
},
|
|
|
|
removeEnvironment({ environments }, environmentIndex) {
|
|
environments.splice(environmentIndex, 1)
|
|
},
|
|
|
|
saveEnvironment({ environments }, payload) {
|
|
const { environment, environmentIndex } = payload
|
|
const { name } = environment
|
|
const duplicateEnvironment =
|
|
environments.length === 1
|
|
? false
|
|
: environments.some(
|
|
(item) =>
|
|
item.environmentIndex !== environmentIndex &&
|
|
item.name.toLowerCase() === name.toLowerCase()
|
|
)
|
|
if (duplicateEnvironment) {
|
|
this.$toast.info("Duplicate environment")
|
|
return
|
|
}
|
|
environments[environmentIndex] = environment
|
|
},
|
|
|
|
replaceCollections(state, collections) {
|
|
state.collections = collections
|
|
},
|
|
|
|
importCollections(state, collections) {
|
|
state.collections = [...state.collections, ...collections]
|
|
|
|
let index = 0
|
|
for (let collection of collections) {
|
|
collection.collectionIndex = index
|
|
index += 1
|
|
}
|
|
},
|
|
|
|
addNewCollection({ collections }, collection) {
|
|
const { name } = collection
|
|
const duplicateCollection = collections.some(
|
|
(item) => item.name.toLowerCase() === name.toLowerCase()
|
|
)
|
|
if (duplicateCollection) {
|
|
this.$toast.info("Duplicate collection")
|
|
return
|
|
}
|
|
collections.push({
|
|
name: "",
|
|
folders: [],
|
|
requests: [],
|
|
...collection,
|
|
})
|
|
},
|
|
|
|
removeCollection({ collections }, payload) {
|
|
const { collectionIndex } = payload
|
|
collections.splice(collectionIndex, 1)
|
|
},
|
|
|
|
editCollection({ collections }, payload) {
|
|
const { collection, collectionIndex } = payload
|
|
const { name } = collection
|
|
const duplicateCollection = collections.some(
|
|
(item) => item.name.toLowerCase() === name.toLowerCase()
|
|
)
|
|
if (duplicateCollection) {
|
|
this.$toast.info("Duplicate collection")
|
|
return
|
|
}
|
|
collections[collectionIndex] = collection
|
|
},
|
|
|
|
addFolder({ collections }, payload) {
|
|
const { name, path } = payload
|
|
|
|
const newFolder = {
|
|
name: name,
|
|
requests: [],
|
|
folders: [],
|
|
}
|
|
|
|
// Walk from collections to destination with the path
|
|
const indexPaths = path.split("/").map((x) => parseInt(x))
|
|
|
|
let target = collections[indexPaths.shift()]
|
|
while (indexPaths.length > 0) target = target.folders[indexPaths.shift()]
|
|
|
|
target.folders.push(newFolder)
|
|
},
|
|
|
|
editFolder({ collections }, payload) {
|
|
const { collectionIndex, folder, folderIndex, folderName } = payload
|
|
const collection = collections[collectionIndex]
|
|
|
|
let parentFolder = findFolder(folderName, collection, true)
|
|
if (parentFolder && parentFolder.folders) {
|
|
Vue.set(parentFolder.folders, folderIndex, folder)
|
|
}
|
|
},
|
|
|
|
removeFolder({ collections }, payload) {
|
|
const { collectionIndex, folderIndex, folderName } = payload
|
|
const collection = collections[collectionIndex]
|
|
|
|
let parentFolder = findFolder(folderName, collection, true)
|
|
if (parentFolder && parentFolder.folders) {
|
|
parentFolder.folders.splice(folderIndex, 1)
|
|
}
|
|
},
|
|
|
|
editRequest({ collections }, payload) {
|
|
const {
|
|
requestCollectionIndex,
|
|
requestFolderName,
|
|
requestFolderIndex,
|
|
requestNew,
|
|
requestIndex,
|
|
} = payload
|
|
|
|
let collection = collections[requestCollectionIndex]
|
|
|
|
if (requestFolderIndex === -1) {
|
|
Vue.set(collection.requests, requestIndex, requestNew)
|
|
return
|
|
}
|
|
|
|
let folder = findFolder(requestFolderName, collection, false)
|
|
Vue.set(folder.requests, requestIndex, requestNew)
|
|
},
|
|
|
|
saveRequestAs({ collections }, payload) {
|
|
let { request, collectionIndex, folderName, requestIndex } = payload
|
|
|
|
// Filter out all file inputs
|
|
request = {
|
|
...request,
|
|
bodyParams: request.bodyParams.map((param) =>
|
|
param?.value?.[0] instanceof File ? { ...param, value: "" } : param
|
|
),
|
|
}
|
|
|
|
const specifiedCollection = collectionIndex !== undefined
|
|
const specifiedFolder = folderName !== undefined
|
|
const specifiedRequest = requestIndex !== undefined
|
|
|
|
if (specifiedCollection && specifiedFolder && specifiedRequest) {
|
|
const folder = findFolder(folderName, collections[collectionIndex])
|
|
Vue.set(folder.requests, requestIndex, request)
|
|
} else if (specifiedCollection && specifiedFolder && !specifiedRequest) {
|
|
const folder = findFolder(folderName, collections[collectionIndex])
|
|
const requests = folder.requests
|
|
const lastRequestIndex = requests.length - 1
|
|
Vue.set(requests, lastRequestIndex + 1, request)
|
|
} else if (specifiedCollection && !specifiedFolder && specifiedRequest) {
|
|
const requests = collections[collectionIndex].requests
|
|
Vue.set(requests, requestIndex, request)
|
|
} else if (specifiedCollection && !specifiedFolder && !specifiedRequest) {
|
|
const requests = collections[collectionIndex].requests
|
|
const lastRequestIndex = requests.length - 1
|
|
Vue.set(requests, lastRequestIndex + 1, request)
|
|
}
|
|
},
|
|
|
|
removeRequest({ collections }, payload) {
|
|
const { collectionIndex, folderName, requestIndex } = payload
|
|
let collection = collections[collectionIndex]
|
|
|
|
if (collection.name === folderName) {
|
|
collection.requests.splice(requestIndex, 1)
|
|
return
|
|
}
|
|
let folder = findFolder(folderName, collection, false)
|
|
|
|
if (folder) {
|
|
folder.requests.splice(requestIndex, 1)
|
|
}
|
|
},
|
|
|
|
selectRequest(state, { request }) {
|
|
state.selectedRequest = Object.assign({}, request)
|
|
},
|
|
|
|
moveRequest({ collections }, payload) {
|
|
const {
|
|
oldCollectionIndex,
|
|
newCollectionIndex,
|
|
newFolderIndex,
|
|
newFolderName,
|
|
oldFolderName,
|
|
requestIndex,
|
|
} = payload
|
|
|
|
const isCollection = newFolderIndex === -1
|
|
const oldCollection = collections[oldCollectionIndex]
|
|
const newCollection = collections[newCollectionIndex]
|
|
const request = findRequest(oldFolderName, oldCollection, requestIndex)
|
|
|
|
if (isCollection) {
|
|
newCollection.requests.push(request)
|
|
return
|
|
}
|
|
|
|
if (!isCollection) {
|
|
const folder = findFolder(newFolderName, newCollection, false)
|
|
if (folder) {
|
|
folder.requests.push(request)
|
|
return
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
function testValue(myValue) {
|
|
try {
|
|
return JSON.parse(myValue)
|
|
} catch (ex) {
|
|
// Now we know it's a string just leave it as a string value.
|
|
return myValue
|
|
}
|
|
}
|
|
|
|
function findRequest(folderName, currentFolder, requestIndex) {
|
|
let selectedFolder, result
|
|
|
|
if (folderName === currentFolder.name) {
|
|
let request = currentFolder.requests[requestIndex]
|
|
currentFolder.requests.splice(requestIndex, 1)
|
|
return request
|
|
} else {
|
|
for (let i = 0; i < currentFolder.folders.length; i += 1) {
|
|
selectedFolder = currentFolder.folders[i]
|
|
|
|
result = findRequest(folderName, selectedFolder, requestIndex)
|
|
|
|
if (result !== false) {
|
|
return result
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
function findFolder(folderName, currentFolder, returnParent, parentFolder) {
|
|
let selectedFolder, result
|
|
|
|
if (folderName === currentFolder.name && returnParent) {
|
|
return parentFolder
|
|
} else if (folderName === currentFolder.name && !returnParent) {
|
|
return currentFolder
|
|
} else {
|
|
for (let i = 0; i < currentFolder.folders.length; i++) {
|
|
selectedFolder = currentFolder.folders[i]
|
|
|
|
result = findFolder(folderName, selectedFolder, returnParent, currentFolder)
|
|
|
|
if (result !== false) {
|
|
return result
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|