feat: show and hide sidebar - fixed #1716

This commit is contained in:
liyasthomas
2021-06-12 16:40:12 +05:30
parent 779f5e9af4
commit 58296505a8
5 changed files with 324 additions and 79 deletions

View File

@@ -0,0 +1,47 @@
<template>
<div
v-tooltip="$t(active ? 'hide_sidebar' : 'show_sidebar')"
class="
absolute
hidden
md:flex
items-center
justify-center
px-2
py-1
bg-brdColor
text-fgLightColor
hover:text-fgColor
my-4
z-10
rounded-l
right-0
cursor-pointer
"
@click="$emit('toggle')"
>
<i
class="
transition
origin-center
transform
material-icons
pointer-events-none
"
:class="{ 'rotate-180': active }"
>
menu_open
</i>
</div>
</template>
<script>
export default {
props: {
active: {
type: Boolean,
default: false,
},
},
}
</script>

View File

@@ -337,5 +337,7 @@
"check_your_inbox": "Check your inbox.",
"you_can_dismiss_this_modal": "You can dismiss this ",
"we_sent_magic_link": "We sent you a magic link!",
"we_sent_magic_link_description": "We sent an email to {email}. It contains a magic link thatll log you in."
"we_sent_magic_link_description": "We sent an email to {email}. It contains a magic link thatll log you in.",
"hide_sidebar": "Hide sidebar",
"show_sidebar": "Show sidebar"
}

View File

@@ -5,7 +5,7 @@
<AppSidenav />
<main>
<AppHeader />
<nuxt />
<nuxt class="container" />
<AppFooter />
</main>
</div>

View File

@@ -24,7 +24,8 @@
<button
class="icon"
@click="
customMethod = methodMenuItem == 'CUSTOM' ? true : false
customMethod =
methodMenuItem == 'CUSTOM' ? true : false
method = methodMenuItem
"
v-close-popover
@@ -77,14 +78,27 @@
</ul>
<ul>
<li>
<label for="request-name" class="text-sm">{{ $t("token_req_name") }}</label>
<input id="request-name" name="request-name" type="text" v-model="name" class="text-sm" />
<label for="request-name" class="text-sm">{{
$t("token_req_name")
}}</label>
<input
id="request-name"
name="request-name"
type="text"
v-model="name"
class="text-sm"
/>
</li>
</ul>
<div label="Request Body" v-if="['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)">
<div
label="Request Body"
v-if="['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)"
>
<ul>
<li>
<label for="contentType" class="text-sm">{{ $t("content_type") }}</label>
<label for="contentType" class="text-sm">{{
$t("content_type")
}}</label>
<span class="select-wrapper">
<v-popover>
<input
@@ -95,14 +109,14 @@
/>
<template slot="popover">
<div
v-for="(contentTypeMenuItem, index) in validContentTypes"
v-for="(
contentTypeMenuItem, index
) in validContentTypes"
:key="`content-type-${index}`"
>
<button
class="icon"
@click="
contentType = contentTypeMenuItem
"
@click="contentType = contentTypeMenuItem"
v-close-popover
>
{{ contentTypeMenuItem }}
@@ -207,7 +221,8 @@
<SmartTab
:id="'params'"
:label="
$t('parameters') + `${params.length !== 0 ? ' \xA0 • \xA0 ' + params.length : ''}`
$t('parameters') +
`${params.length !== 0 ? ' \xA0 • \xA0 ' + params.length : ''}`
"
:selected="true"
>
@@ -222,7 +237,10 @@
<SmartTab
:id="'headers'"
:label="
$t('headers') + `${headers.length !== 0 ? ' \xA0 • \xA0 ' + headers.length : ''}`
$t('headers') +
`${
headers.length !== 0 ? ' \xA0 • \xA0 ' + headers.length : ''
}`
"
>
<HttpHeaders
@@ -235,7 +253,11 @@
</SmartTab>
<SmartTab :id="'authentication'" :label="$t('authentication')">
<AppSection :label="$t('authentication')" ref="authentication" no-legend>
<AppSection
:label="$t('authentication')"
ref="authentication"
no-legend
>
<ul>
<li>
<div class="row-wrapper">
@@ -262,7 +284,11 @@
</ul>
<ul v-if="auth === 'Basic Auth'">
<li>
<input placeholder="User" name="http_basic_user" v-model="httpUser" />
<input
placeholder="User"
name="http_basic_user"
v-model="httpUser"
/>
</li>
<li>
<input
@@ -274,9 +300,19 @@
</li>
<div>
<li>
<button class="icon" ref="switchVisibility" @click="switchVisibility">
<i class="material-icons" v-if="passwordFieldType === 'text'">visibility</i>
<i class="material-icons" v-if="passwordFieldType !== 'text'"
<button
class="icon"
ref="switchVisibility"
@click="switchVisibility"
>
<i
class="material-icons"
v-if="passwordFieldType === 'text'"
>visibility</i
>
<i
class="material-icons"
v-if="passwordFieldType !== 'text'"
>visibility_off</i
>
</button>
@@ -286,7 +322,11 @@
<ul v-if="auth === 'Bearer Token' || auth === 'OAuth 2.0'">
<li>
<div class="row-wrapper">
<input placeholder="Token" name="bearer_token" v-model="bearerToken" />
<input
placeholder="Token"
name="bearer_token"
v-model="bearerToken"
/>
<button
v-if="auth === 'OAuth 2.0'"
class="icon"
@@ -307,7 +347,10 @@
</li>
</ul>
<div class="row-wrapper">
<SmartToggle :on="!URL_EXCLUDES.auth" @change="setExclude('auth', !$event)">
<SmartToggle
:on="!URL_EXCLUDES.auth"
@change="setExclude('auth', !$event)"
>
{{ $t("include_in_url") }}
</SmartToggle>
</div>
@@ -362,7 +405,9 @@
{{ $t("oidc_discovery_url") }}
</label>
<input
:disabled="this.authUrl !== '' || this.accessTokenUrl !== ''"
:disabled="
this.authUrl !== '' || this.accessTokenUrl !== ''
"
id="oidc-discovery-url"
name="oidc_discovery_url"
type="url"
@@ -434,7 +479,10 @@
</AppSection>
</SmartTab>
<SmartTab :id="'pre_request_script'" :label="$t('pre_request_script')">
<SmartTab
:id="'pre_request_script'"
:label="$t('pre_request_script')"
>
<AppSection
v-if="showPreRequestScript"
class="orange"
@@ -526,19 +574,27 @@
</button>
</div>
</div>
<div v-for="(testReport, index) in testReports" :key="index">
<div
v-for="(testReport, index) in testReports"
:key="index"
>
<div v-if="testReport.startBlock" class="info">
<hr />
<h4>{{ testReport.startBlock }}</h4>
</div>
<p v-else-if="testReport.result" class="row-wrapper info">
<p
v-else-if="testReport.result"
class="row-wrapper info"
>
<span :class="testReport.styles.class">
<i class="material-icons">
{{ testReport.styles.icon }}
</i>
<span>&nbsp; {{ testReport.result }}</span>
<span v-if="testReport.message">
<label>&nbsp; &nbsp; {{ testReport.message }}</label>
<label
>&nbsp; • &nbsp; {{ testReport.message }}</label
>
</span>
</span>
</p>
@@ -552,14 +608,22 @@
</SmartTabs>
</section>
<HttpResponse :response="response" :active="runningRequest" ref="response" />
<HttpResponse
:response="response"
:active="runningRequest"
ref="response"
/>
</div>
<aside v-if="activeSidebar" class="sticky-inner inner-right lg:max-w-md">
<section>
<SmartTabs>
<SmartTab :id="'history'" :label="$t('history')" :selected="true">
<History :page="'rest'" @useHistory="handleUseHistory" ref="historyComponent" />
<History
:page="'rest'"
@useHistory="handleUseHistory"
ref="historyComponent"
/>
</SmartTab>
<SmartTab :id="'collections'" :label="$t('collections')">
@@ -576,6 +640,11 @@
</SmartTabs>
</section>
</aside>
<SmartHideMenu
:active="activeSidebar"
@toggle="activeSidebar = !activeSidebar"
/>
</div>
<CollectionsSaveRequest
@@ -608,7 +677,10 @@
@hide-modal="showTokenListModal = false"
/>
<SmartModal v-if="showTokenRequestList" @close="showTokenRequestList = false">
<SmartModal
v-if="showTokenRequestList"
@close="showTokenRequestList = false"
>
<div slot="header">
<div class="row-wrapper">
<h3 class="title">{{ $t("manage_token_req") }}</h3>
@@ -650,7 +722,11 @@
:disabled="this.tokenReqs.length === 0"
@change="tokenReqChange($event)"
>
<option v-for="(req, index) in tokenReqs" :key="index" :value="req.name">
<option
v-for="(req, index) in tokenReqs"
:key="index"
:value="req.name"
>
{{ req.name }}
</option>
</select>
@@ -662,7 +738,12 @@
<label for="token-req-details">
{{ $t("token_req_details") }}
</label>
<textarea id="token-req-details" readonly rows="7" v-model="tokenReqDetails"></textarea>
<textarea
id="token-req-details"
readonly
rows="7"
v-model="tokenReqDetails"
></textarea>
</div>
<div slot="footer">
<div class="row-wrapper">
@@ -690,10 +771,17 @@ import parseTemplateString from "~/helpers/templating"
import { tokenRequest, oauthRedirect } from "~/helpers/oauth"
import { cancelRunningRequest, sendNetworkRequest } from "~/helpers/network"
import { fb } from "~/helpers/fb"
import { hasPathParams, addPathParamsToVariables, getQueryParams } from "~/helpers/requestParams"
import {
hasPathParams,
addPathParamsToVariables,
getQueryParams,
} from "~/helpers/requestParams"
import { parseUrlAndPath } from "~/helpers/utils/uri"
import { httpValid } from "~/helpers/utils/valid"
import { knownContentTypes, isJSONContentType } from "~/helpers/utils/contenttypes"
import {
knownContentTypes,
isJSONContentType,
} from "~/helpers/utils/contenttypes"
import { generateCodeWithGenerator } from "~/helpers/codegen/codegen"
import { getSettingSubject, applySetting } from "~/newstore/settings"
import { addRESTHistoryEntry } from "~/newstore/history"
@@ -753,7 +841,9 @@ export default {
SCROLL_INTO_ENABLED: getSettingSubject("SCROLL_INTO_ENABLED"),
PROXY_ENABLED: getSettingSubject("PROXY_ENABLED"),
URL_EXCLUDES: getSettingSubject("URL_EXCLUDES"),
EXPERIMENTAL_URL_BAR_ENABLED: getSettingSubject("EXPERIMENTAL_URL_BAR_ENABLED"),
EXPERIMENTAL_URL_BAR_ENABLED: getSettingSubject(
"EXPERIMENTAL_URL_BAR_ENABLED"
),
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
SYNC_HISTORY: getSettingSubject("syncHistory"),
@@ -783,7 +873,10 @@ export default {
}
return ""
}
if (!this.rawParams || this.rawParams === getDefaultParams(oldContentType)) {
if (
!this.rawParams ||
this.rawParams === getDefaultParams(oldContentType)
) {
this.rawParams = getDefaultParams(contentType)
}
this.setRouteQueryState()
@@ -843,7 +936,9 @@ export default {
this.showSaveRequestModal = true
},
method() {
this.contentType = ["POST", "PUT", "PATCH", "DELETE"].includes(this.method)
this.contentType = ["POST", "PUT", "PATCH", "DELETE"].includes(
this.method
)
? this.contentType
: "application/json"
},
@@ -865,14 +960,24 @@ export default {
},
uri: {
get() {
return this.$store.state.request.uri ? this.$store.state.request.uri : this.url + this.path
return this.$store.state.request.uri
? this.$store.state.request.uri
: this.url + this.path
},
set(value) {
this.$store.commit("setState", { value, attribute: "uri" })
let url = value
if ((this.preRequestScript && this.showPreRequestScript) || hasPathParams(this.params)) {
let environmentVariables = getEnvironmentVariablesFromScript(this.preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
if (
(this.preRequestScript && this.showPreRequestScript) ||
hasPathParams(this.params)
) {
let environmentVariables = getEnvironmentVariablesFromScript(
this.preRequestScript
)
environmentVariables = addPathParamsToVariables(
this.params,
environmentVariables
)
url = parseTemplateString(value, environmentVariables)
}
let result = parseUrlAndPath(url)
@@ -1144,7 +1249,9 @@ export default {
try {
const obj = JSON.parse(
`{${bodyParams
.filter((item) => (item.hasOwnProperty("active") ? item.active == true : true))
.filter((item) =>
item.hasOwnProperty("active") ? item.active == true : true
)
.filter(({ key }) => !!key)
.map(({ key, value }) => `"${key}": "${value}"`)
.join()}}`
@@ -1163,23 +1270,36 @@ export default {
}
} else {
return bodyParams
.filter((item) => (item.hasOwnProperty("active") ? item.active == true : true))
.filter((item) =>
item.hasOwnProperty("active") ? item.active == true : true
)
.filter(({ key }) => !!key)
.map(({ key, value }) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.map(
({ key, value }) =>
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
)
.join("&")
}
},
queryString() {
const result = getQueryParams(this.params)
.map(({ key, value }) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.map(
({ key, value }) =>
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
)
.join("&")
return result === "" ? "" : `?${result}`
},
requestCode() {
let headers = []
if (this.preRequestScript || hasPathParams(this.params)) {
let environmentVariables = getEnvironmentVariablesFromScript(this.preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
let environmentVariables = getEnvironmentVariablesFromScript(
this.preRequestScript
)
environmentVariables = addPathParamsToVariables(
this.params,
environmentVariables
)
for (let k of this.headers.filter((item) =>
item.hasOwnProperty("active") ? item.active == true : true
)) {
@@ -1262,16 +1382,29 @@ export default {
}
if (preRequestScript || hasPathParams(this.params)) {
let environmentVariables = getEnvironmentVariablesFromScript(preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
requestOptions.url = parseTemplateString(requestOptions.url, environmentVariables)
let environmentVariables =
getEnvironmentVariablesFromScript(preRequestScript)
environmentVariables = addPathParamsToVariables(
this.params,
environmentVariables
)
requestOptions.url = parseTemplateString(
requestOptions.url,
environmentVariables
)
if (!(requestOptions.data instanceof FormData)) {
// TODO: Parse env variables for form data too
requestOptions.data = parseTemplateString(requestOptions.data, environmentVariables)
requestOptions.data = parseTemplateString(
requestOptions.data,
environmentVariables
)
}
for (let k in requestOptions.headers) {
const kParsed = parseTemplateString(k, environmentVariables)
const valParsed = parseTemplateString(requestOptions.headers[k], environmentVariables)
const valParsed = parseTemplateString(
requestOptions.headers[k],
environmentVariables
)
delete requestOptions.headers[k]
requestOptions.headers[kParsed] = valParsed
}
@@ -1407,9 +1540,17 @@ export default {
usesPostScripts: this.testsEnabled,
}
if ((this.preRequestScript && this.showPreRequestScript) || hasPathParams(this.params)) {
let environmentVariables = getEnvironmentVariablesFromScript(this.preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
if (
(this.preRequestScript && this.showPreRequestScript) ||
hasPathParams(this.params)
) {
let environmentVariables = getEnvironmentVariablesFromScript(
this.preRequestScript
)
environmentVariables = addPathParamsToVariables(
this.params,
environmentVariables
)
entry.path = parseTemplateString(entry.path, environmentVariables)
entry.url = parseTemplateString(entry.url, environmentVariables)
}
@@ -1463,8 +1604,13 @@ export default {
(this.preRequestScript && this.showPreRequestScript) ||
hasPathParams(this.params)
) {
let environmentVariables = getEnvironmentVariablesFromScript(this.preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
let environmentVariables = getEnvironmentVariablesFromScript(
this.preRequestScript
)
environmentVariables = addPathParamsToVariables(
this.params,
environmentVariables
)
entry.path = parseTemplateString(entry.path, environmentVariables)
entry.url = parseTemplateString(entry.url, environmentVariables)
}
@@ -1506,7 +1652,9 @@ export default {
) {
try {
syntheticResponse.body = JSON.parse(
new TextDecoder("utf-8").decode(new Uint8Array(syntheticResponse.body))
new TextDecoder("utf-8").decode(
new Uint8Array(syntheticResponse.body)
)
)
} catch (_e) {}
}
@@ -1531,8 +1679,13 @@ export default {
pathInputHandler() {
if (this.uri.includes("?")) {
const queryString = this.getQueryStringFromPath()
let environmentVariables = getEnvironmentVariablesFromScript(this.preRequestScript)
environmentVariables = addPathParamsToVariables(this.params, environmentVariables)
let environmentVariables = getEnvironmentVariablesFromScript(
this.preRequestScript
)
environmentVariables = addPathParamsToVariables(
this.params,
environmentVariables
)
const params = this.queryStringToArray(queryString)
let parsedParams = []
for (let k of params.filter((item) =>
@@ -1570,7 +1723,12 @@ export default {
})
},
addRequestParam() {
this.$store.commit("addParams", { key: "", value: "", type: "query", active: true })
this.$store.commit("addParams", {
key: "",
value: "",
type: "query",
active: true,
})
return false
},
removeRequestParam(index) {
@@ -1630,7 +1788,10 @@ export default {
this.$toast.info(this.$t("copied_to_clipboard"), {
icon: "done",
})
setTimeout(() => (this.$refs.copyRequest.innerHTML = this.copyButton), 1000)
setTimeout(
() => (this.$refs.copyRequest.innerHTML = this.copyButton),
1000
)
}
},
setRouteQueryState() {
@@ -1639,7 +1800,9 @@ export default {
const haveItems = [...this[key]].length
if (haveItems && this[key]["value"] !== "") {
// Exclude files fro query params
const filesRemoved = this[key].filter((item) => !(item?.value?.[0] instanceof File))
const filesRemoved = this[key].filter(
(item) => !(item?.value?.[0] instanceof File)
)
return `${key}=${JSON.stringify(filesRemoved)}&`
}
return ""
@@ -1657,7 +1820,9 @@ export default {
.filter((item) => item !== null)
.map((item) => flat(item))
const deeps = ["headers", "params"].map((item) => deep(item))
const bodyParams = this.rawInput ? [flat("rawParams")] : [deep("bodyParams")]
const bodyParams = this.rawInput
? [flat("rawParams")]
: [deep("bodyParams")]
history.replaceState(
window.location.href,
"",
@@ -1667,7 +1832,8 @@ export default {
)
},
setRouteQueries(queries) {
if (typeof queries !== "object") throw new Error("Route query parameters must be a Object")
if (typeof queries !== "object")
throw new Error("Route query parameters must be a Object")
for (const key in queries) {
if (["headers", "params", "bodyParams"].includes(key))
this[key] = JSON.parse(decodeURI(encodeURI(queries[key])))
@@ -1702,7 +1868,9 @@ export default {
const { value: text } = document.getElementById("import-curl")
try {
const parsedCurl = parseCurlCommand(text)
const { origin, pathname } = new URL(parsedCurl.url.replace(/"/g, "").replace(/'/g, ""))
const { origin, pathname } = new URL(
parsedCurl.url.replace(/"/g, "").replace(/'/g, "")
)
this.url = origin
this.path = pathname
this.uri = this.url + this.path
@@ -1739,7 +1907,8 @@ export default {
}
},
switchVisibility() {
this.passwordFieldType = this.passwordFieldType === "password" ? "text" : "password"
this.passwordFieldType =
this.passwordFieldType === "password" ? "text" : "password"
},
clearContent(name, { target }) {
switch (name) {
@@ -1809,7 +1978,10 @@ export default {
this.$toast.info(this.$t("cleared"), {
icon: "clear_all",
})
setTimeout(() => (target.innerHTML = '<i class="material-icons">clear_all</i>'), 1000)
setTimeout(
() => (target.innerHTML = '<i class="material-icons">clear_all</i>'),
1000
)
},
saveRequest() {
let urlAndPath = parseUrlAndPath(this.uri)
@@ -1829,12 +2001,17 @@ export default {
rawInput: this.rawInput,
contentType: this.contentType,
requestType: this.requestType,
preRequestScript: this.showPreRequestScript == true ? this.preRequestScript : null,
preRequestScript:
this.showPreRequestScript == true ? this.preRequestScript : null,
testScript: this.testsEnabled == true ? this.testScript : null,
name: this.requestName,
}
if (this.selectedRequest.url) {
this.editRequest = Object.assign({}, this.selectedRequest, this.editRequest)
this.editRequest = Object.assign(
{},
this.selectedRequest,
this.editRequest
)
}
this.showSaveRequestModal = true
},
@@ -1862,7 +2039,10 @@ export default {
this.rawParams = rawParams
},
async handleAccessTokenRequest() {
if (this.oidcDiscoveryUrl === "" && (this.authUrl === "" || this.accessTokenUrl === "")) {
if (
this.oidcDiscoveryUrl === "" &&
(this.authUrl === "" || this.accessTokenUrl === "")
) {
this.$toast.error(this.$t("complete_config_urls"), {
icon: "error",
})
@@ -1937,7 +2117,9 @@ export default {
},
removeOAuthTokenReq(index) {
const oldTokenReqs = this.tokenReqs.slice()
const targetReqIndex = this.tokenReqs.findIndex(({ name }) => name === this.tokenReqName)
const targetReqIndex = this.tokenReqs.findIndex(
({ name }) => name === this.tokenReqName
)
if (targetReqIndex < 0) return
this.$store.commit("removeOAuthTokenReq", targetReqIndex)
this.$toast.error(this.$t("deleted"), {
@@ -1952,8 +2134,11 @@ export default {
})
},
tokenReqChange({ target }) {
const { details, name } = this.tokenReqs.find(({ name }) => name === target.value)
const { oidcDiscoveryUrl, authUrl, accessTokenUrl, clientId, scope } = details
const { details, name } = this.tokenReqs.find(
({ name }) => name === target.value
)
const { oidcDiscoveryUrl, authUrl, accessTokenUrl, clientId, scope } =
details
this.tokenReqName = name
this.oidcDiscoveryUrl = oidcDiscoveryUrl
this.authUrl = authUrl
@@ -2013,16 +2198,27 @@ export default {
this.method = "DELETE"
}
if (e.key == "ArrowUp" && e.altKey && this.currentMethodIndex > 0) {
this.method = this.methodMenuItems[--this.currentMethodIndex % this.methodMenuItems.length]
} else if (e.key == "ArrowDown" && e.altKey && this.currentMethodIndex < 9) {
this.method = this.methodMenuItems[++this.currentMethodIndex % this.methodMenuItems.length]
this.method =
this.methodMenuItems[
--this.currentMethodIndex % this.methodMenuItems.length
]
} else if (
e.key == "ArrowDown" &&
e.altKey &&
this.currentMethodIndex < 9
) {
this.method =
this.methodMenuItems[
++this.currentMethodIndex % this.methodMenuItems.length
]
}
}
document.addEventListener("keydown", this._keyListener.bind(this))
await this.oauthRedirectReq()
},
created() {
if (Object.keys(this.$route.query).length) this.setRouteQueries(this.$route.query)
if (Object.keys(this.$route.query).length)
this.setRouteQueries(this.$route.query)
this.$watch(
(vm) => [
vm.name,

View File

@@ -17,9 +17,9 @@ export default {
skew: false,
},
theme: {
// container: {
// center: true,
// },
container: {
center: true,
},
extend: {
colors: {
bgColor: "var(--bg-color)",