Add cards, use oboe to stream JSON, handle connection failures

This commit is contained in:
user 2024-10-31 16:41:45 +01:00
parent 2f45d49ac0
commit d6127e8dfa
6 changed files with 149 additions and 30 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.vscode .vscode
.DS_Store .DS_Store
.venv

View File

@ -0,0 +1,41 @@
<script setup>
import { ref, watch } from 'vue'
const type = ref();
const card = ref();
defineProps(['title', 'description', 'type'])
watch(type, (prev, current) => {
card.style.toggleClass('type-a', current.match(/a/i))
card.style.toggleClass('type-b', current.match(/b/i))
})
</script>
<template>
<section ref="card" class="card">
<footer>{{ type }}</footer>
<header><h1>{{ title }}</h1></header>
<main>{{ description }}</main>
</section>
</template>
<style>
.card {
background-color: lightgrey;
height: 100%;
width: 100%;
}
.card.type-a {
background-color: red;
}
.card.type-b {
background-color: orange;
}
.card footer {
float: right;
}
.card h1 {
size: 1em;
}
</style>

View File

@ -1,9 +1,6 @@
import axios from "axios"; import oboe from "oboe";
export async function useAxios(path: string, options: any) { export async function streamRequest(path: string, callback: oboe.CallbackSignature, onFail: Function, onSuccess: Function) {
const runtimeConfig = useRuntimeConfig(); const runtimeConfig = useRuntimeConfig();
return await axios(`${runtimeConfig.public.apiBaseUrl}${path}`, { return oboe(`${runtimeConfig.public.apiBaseUrl}${path}`).node({ 'items.*': callback }).fail(_ => onFail()).done(_ => onSuccess());
...options,
headers: options.headers,
});
} }

View File

@ -10,10 +10,12 @@
"postinstall": "nuxt prepare" "postinstall": "nuxt prepare"
}, },
"dependencies": { "dependencies": {
"@types/oboe": "^2.1.4",
"@vueuse/nuxt": "^10.9.0", "@vueuse/nuxt": "^10.9.0",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"axios": "^1.7.2", "axios": "^1.7.2",
"nuxt": "^3.11.2", "nuxt": "^3.11.2",
"oboe": "^2.1.7",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"tailwindcss": "^3.4.3", "tailwindcss": "^3.4.3",
"vue": "^3.4.27", "vue": "^3.4.27",

View File

@ -1,34 +1,68 @@
<template> <template>
<NuxtLayout name="ui"> <NuxtLayout name="ui">
<h1 class="px-10 py-10">TEST CASE - Welkom to the page!</h1> <header :class="errorClasses">
<div class="relative px-10 py-10 flex items-center justify-center"> Connection failed. <button @click="update">Click here to retry</button>.
<div class="flex flex-col gap-4"> </header>
<button <main class="grid">
@click="helloWorld" <Card v-for="item in items" :title="item.title" :description="item.description" :type="item.type"/>
class="bg-red-300 rounded-md px-2 hover:bg-slate-300" </main>
>
Click me!
</button>
<div class="bg-slate-600 rounded-md text-md text-white px-2"> <div class="bg-slate-600 rounded-md text-md text-white px-2">
{{ sync }}
</div> </div>
</div>
</div>
</NuxtLayout> </NuxtLayout>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const sync: Ref<string> = ref(""); import Card from '../components/Card.vue'
import { ref, onMounted } from 'vue'
function reset() { onMounted(_ => update())
sync.value = "";
const items = ref([...new Array(9)].map((_, i) => ({
title: `Item ${i}`,
description: "",
type: "?"
}))
)
const errorClasses = ref("error hidden")
function updateItem(item) {
items.value.forEach(n => {
if (n.title == item.title) {
if (item.description)
n.description = item.description;
if (item.type)
n.type = item.type;
}
})
} }
async function helloWorld() { function failure() {
reset(); errorClasses.value = "error"
const res = await useAxios(`/hello_world`, { console.log("aaaaaa")
method: "GET", }
});
sync.value = res.data; async function update() {
errorClasses.value = "error hidden"
await streamRequest("/hello_world/json", updateItem, failure, update);
} }
</script> </script>
<style>
.grid {
align-items: center;
display: grid;
grid-template-columns: auto auto auto;
grid-template-rows: auto auto auto;
margin: 1em;
gap: 1em;
}
.error {
background-color: red;
}
.hidden {
display: none;
}
</style>

View File

@ -1299,6 +1299,13 @@
dependencies: dependencies:
undici-types "~5.26.4" undici-types "~5.26.4"
"@types/oboe@^2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@types/oboe/-/oboe-2.1.4.tgz#d92c4636d0b7737803e4361e10e8dad488f39634"
integrity sha512-bXt4BXSQy0N/buSIak1o0TjYAk2SAeK1aZV9xKcb+xVGWYP8NcMOFy2T7Um3kIvEcQJzrdgJ8R6fpbRcp/LEww==
dependencies:
"@types/node" "*"
"@types/resolve@1.20.2": "@types/resolve@1.20.2":
version "1.20.2" version "1.20.2"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
@ -3042,6 +3049,11 @@ http-errors@2.0.0:
statuses "2.0.1" statuses "2.0.1"
toidentifier "1.0.1" toidentifier "1.0.1"
http-https@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b"
integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==
http-proxy-agent@^7.0.0: http-proxy-agent@^7.0.0:
version "7.0.2" version "7.0.2"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e"
@ -4139,6 +4151,13 @@ object-hash@^3.0.0:
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
oboe@^2.1.7:
version "2.1.7"
resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.7.tgz#14cb69c750757a964c760383e094887822a32947"
integrity sha512-Y2oCMU2xgITORaNvIDCvUyn2ZG/5NI19lLjMFThgYzCH+GA/fgYvVcwxAqnZPiMiUrPq64jLzCkBXqKSu/R6MA==
dependencies:
http-https "^1.0.0"
ofetch@^1.3.3, ofetch@^1.3.4: ofetch@^1.3.3, ofetch@^1.3.4:
version "1.3.4" version "1.3.4"
resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635" resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635"
@ -5113,7 +5132,16 @@ streamx@^2.15.0:
optionalDependencies: optionalDependencies:
bare-events "^2.2.0" bare-events "^2.2.0"
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: "string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -5145,7 +5173,14 @@ string_decoder@~1.1.1:
dependencies: dependencies:
safe-buffer "~5.1.0" safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: "strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -5821,7 +5856,16 @@ wide-align@^1.1.2:
dependencies: dependencies:
string-width "^1.0.2 || 2 || 3 || 4" string-width "^1.0.2 || 2 || 3 || 4"
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==