Initial lens implementation

This commit is contained in:
Andrew Bastin
2020-06-21 17:14:20 -04:00
parent 307e44a7b9
commit 7911d17b2f
13 changed files with 301 additions and 27 deletions

View File

@@ -0,0 +1,42 @@
<template>
<div>
<tabs>
<tab
v-for="(lens, index) in validLenses"
:id="lens.lensName"
:key="lens.lensName"
:label="lens.lensName"
:selected="index === 0"
>
<component :is="lens.renderer" :response="response" />
</tab>
</tabs>
</div>
</template>
<script>
import getSuitableLenses from "../../helpers/lenses/lenses"
export default {
components: {
// Lens Renderers
raw: () => import("../lenses/renderers/RawLensRenderer"),
json: () => import("../lenses/renderers/JSONLensRenderer"),
imageres: () => import("../lenses/renderers/ImageLensRenderer"),
htmlres: () => import("../lenses/renderers/HTMLLensRenderer"),
tabs: () => import("../ui/tabs"),
tab: () => import("../ui/tab"),
},
props: {
response: {},
},
computed: {
validLenses() {
return getSuitableLenses(this.response)
},
},
}
</script>

View File

@@ -0,0 +1,36 @@
<template>
<ul>
<li>
<Editor
:value="responseBodyText"
:lang="'html'"
:options="{
maxLines: 16,
minLines: '16',
fontSize: '16px',
autoScrollEditorIntoView: true,
readOnly: true,
showPrintMargin: false,
useWorker: false,
}"
/>
</li>
</ul>
</template>
<script>
import AceEditor from "../../ui/ace-editor"
export default {
components: {
Editor: AceEditor,
},
props: {
response: {},
},
computed: {
responseBodyText() {
return new TextDecoder("utf-8").decode(this.response.body)
},
},
}
</script>

View File

@@ -0,0 +1,56 @@
<template>
<ul>
<li>
<img :src="imageSource" />
</li>
</ul>
</template>
<script>
export default {
props: {
response: {},
},
data() {
return {
imageSource: "",
}
},
watch: {
response: {
immediate: true,
handler(newValue) {
console.log("wetch")
this.imageSource = ""
const buf = this.response.body
const bytes = new Uint8Array(buf)
const blob = new Blob([bytes.buffer])
const reader = new FileReader()
reader.onload = (e) => {
console.log(e.target.result)
this.imageSource = e.target.result
}
reader.readAsDataURL(blob)
},
},
},
mounted() {
console.log("mount")
this.imageSource = ""
console.log(this.response)
const buf = this.response.body
const bytes = new Uint8Array(buf)
const blob = new Blob([bytes.buffer])
const reader = new FileReader()
reader.onload = (e) => {
console.log(e.target.result)
this.imageSource = e.target.result
}
reader.readAsDataURL(blob)
},
}
</script>

View File

@@ -0,0 +1,45 @@
<template>
<ul>
<li>
<Editor
:value="responseBodyText"
:lang="'json'"
:options="{
maxLines: 16,
minLines: '16',
fontSize: '16px',
autoScrollEditorIntoView: true,
readOnly: true,
showPrintMargin: false,
useWorker: false,
}"
/>
</li>
</ul>
</template>
<script>
import AceEditor from "../../ui/ace-editor"
export default {
components: {
Editor: AceEditor,
},
props: {
response: {},
},
computed: {
responseBodyText() {
try {
return JSON.stringify(
JSON.parse(new TextDecoder("utf-8").decode(new Uint8Array(this.response.body))),
null,
2
)
} catch (e) {
// Most probs invalid JSON was returned, so drop prettification (should we warn ?)
return new TextDecoder("utf-8").decode(new Uint8Array(this.response.body))
}
},
},
}
</script>

View File

@@ -0,0 +1,36 @@
<template>
<ul>
<li>
<Editor
:value="responseBodyText"
:lang="'plain_text'"
:options="{
maxLines: 16,
minLines: '16',
fontSize: '16px',
autoScrollEditorIntoView: true,
readOnly: true,
showPrintMargin: false,
useWorker: false,
}"
/>
</li>
</ul>
</template>
<script>
import AceEditor from "../../ui/ace-editor"
export default {
components: {
Editor: AceEditor,
},
props: {
response: {},
},
computed: {
responseBodyText() {
return new TextDecoder("utf-8").decode(new Uint8Array(this.response.body))
},
},
}
</script>

View File

@@ -76,6 +76,7 @@ export default {
})
},
lang(value) {
console.log("ace/mode/" + value)
this.editor.getSession().setMode("ace/mode/" + value)
},
options(value) {

View File

@@ -0,0 +1,7 @@
const htmlLens = {
lensName: "HTML",
supportedContentTypes: ["text/html"],
renderer: "htmlres",
}
export default htmlLens

View File

@@ -0,0 +1,12 @@
const imageLens = {
lensName: "Image",
supportedContentTypes: [
"image/gif",
"image/jpeg",
"image/png",
// TODO : Add more image types!
],
renderer: "imageres",
}
export default imageLens

View File

@@ -0,0 +1,7 @@
const jsonLens = {
lensName: "JSON",
supportedContentTypes: ["application/json", "application/hal+json", "application/vnd.api+json"],
renderer: "json",
}
export default jsonLens

37
helpers/lenses/lenses.js Normal file
View File

@@ -0,0 +1,37 @@
import jsonLens from "./jsonLens"
import rawLens from "./rawLens"
import imageLens from "./imageLens"
import htmlLens from "./htmlLens"
const lenses = [
jsonLens,
imageLens,
htmlLens,
// Keep Raw Lens as the last option
rawLens,
]
function getSuitableLenses(response) {
const result = []
if (response && response.headers && response.headers["content-type"]) {
const properContentType = response.headers["content-type"].split(";")[0]
for (const lens of lenses) {
if (
lens.supportedContentTypes === null ||
lens.supportedContentTypes.includes(properContentType)
) {
result.push(lens)
}
}
} else {
// We don't know the content type, so lets just add rawLens
result.push(rawLens)
}
return result
}
export default getSuitableLenses

View File

@@ -0,0 +1,7 @@
const rawLens = {
lensName: "Raw",
supportedContentTypes: null,
renderer: "raw",
}
export default rawLens

View File

@@ -1,4 +1,5 @@
import axios from "axios"
import { isJSONContentType } from "../utils/contenttypes"
let cancelSource = axios.CancelToken.source()
@@ -34,28 +35,9 @@ const axiosWithoutProxy = async (req, _store) => {
const res = await axios({
...req,
cancelToken: cancelSource.token,
transformResponse: [
(data, headers) => {
// If the response has a JSON content type, try parsing it
if (
headers["content-type"] &&
(headers["content-type"].startsWith("application/json") ||
headers["content-type"].startsWith("application/vnd.api+json") ||
headers["content-type"].startsWith("application/hal+json"))
) {
try {
const jsonData = JSON.parse(data)
return jsonData
} catch (e) {
return data
}
}
// Else return the string itself without any transformations
return data
},
],
responseType: "arraybuffer",
})
return res
} catch (e) {
if (axios.isCancel(e)) {

View File

@@ -952,6 +952,10 @@
/>
</li>
</ul>
<div v-if="response.body">
<response-renderer :response="response" />
</div>
<!--
<ul v-if="response.body">
<li>
<div class="flex-wrap">
@@ -1023,6 +1027,7 @@
</div>
</li>
</ul>
-->
<ul v-for="(value, key) in response.headers" :key="key" class="response-headers">
<li>
<label :for="key">{{ key }}</label>
@@ -1420,12 +1425,13 @@ export default {
collections: () => import("~/components/collections"),
saveRequestAs: () => import("~/components/collections/saveRequestAs"),
Editor: AceEditor,
environments: () => import("~/components/environments"),
inputform: () => import("~/components/firebase/inputform"),
notes: () => import("~/components/firebase/feeds"),
login: () => import("~/components/firebase/login"),
tabs: () => import("~/components/ui/tabs"),
tab: () => import("~/components/ui/tab"),
environments: () => import("../components/environments"),
inputform: () => import("../components/firebase/inputform"),
notes: () => import("../components/firebase/feeds"),
login: () => import("../components/firebase/login"),
tabs: () => import("../components/ui/tabs"),
tab: () => import("../components/ui/tab"),
"response-renderer": () => import("../components/lenses/ResponseBodyRenderer"),
},
data() {
return {