diff options
author | HampusM <hampus@hampusmat.com> | 2021-06-09 17:37:43 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2021-06-09 17:37:43 +0200 |
commit | 75e8ae6ebd9df23275fb14eea88da0b56d006313 (patch) | |
tree | cd8a261f856e2177626272e7018041be3102304b /packages | |
parent | dae7377188242e8dbc18f029bc97b7def9acb13c (diff) |
Frontend has proper error handling & api fetching is in it's own file
Diffstat (limited to 'packages')
-rw-r--r-- | packages/client/src/components/BaseErrorMessage.vue | 27 | ||||
-rw-r--r-- | packages/client/src/components/RepositoryTreeTree.vue | 2 | ||||
-rw-r--r-- | packages/client/src/util/fetch.js | 35 | ||||
-rw-r--r-- | packages/client/src/views/Home.vue | 29 | ||||
-rw-r--r-- | packages/client/src/views/RepositoryCommit.vue | 96 | ||||
-rw-r--r-- | packages/client/src/views/RepositoryLog.vue | 32 | ||||
-rw-r--r-- | packages/client/src/views/RepositoryTree.vue | 49 | ||||
-rw-r--r-- | packages/server/package.json | 2 |
8 files changed, 186 insertions, 86 deletions
diff --git a/packages/client/src/components/BaseErrorMessage.vue b/packages/client/src/components/BaseErrorMessage.vue new file mode 100644 index 0000000..7f193ce --- /dev/null +++ b/packages/client/src/components/BaseErrorMessage.vue @@ -0,0 +1,27 @@ +<template> + <div v-if="fetchFailed" class="fs-5"> + <span class="fetch-error-title">Error</span> + <p>{{ fetchFailed }}</p> + </div> +</template> + +<script> +export default { + name: "BaseErrorMessage", + props: { + fetchFailed: { + type: String, + required: true + } + } +}; +</script> + +<style lang="scss" scoped> +@use "../scss/colors"; + +.fetch-error-title { + color: colors.$danger; + font-weight: 700; +} +</style> diff --git a/packages/client/src/components/RepositoryTreeTree.vue b/packages/client/src/components/RepositoryTreeTree.vue index 89ffb81..376cafc 100644 --- a/packages/client/src/components/RepositoryTreeTree.vue +++ b/packages/client/src/components/RepositoryTreeTree.vue @@ -38,7 +38,7 @@ </a> </td> <td> - {{ getPrettyLastUpdated(entry.last_commit.time) }} + {{ getPrettyLastUpdated(entry.last_commit.date) }} </td> </tr> </tbody> diff --git a/packages/client/src/util/fetch.js b/packages/client/src/util/fetch.js new file mode 100644 index 0000000..a6a43b0 --- /dev/null +++ b/packages/client/src/util/fetch.js @@ -0,0 +1,35 @@ +export default async function(endpoint, fetch_failed, is_loading, data_name) { + const fetch_timeout = setTimeout(() => { + if(!fetch_failed.value) { + fetch_failed.value = `Failed to fetch ${data_name} data.`; + is_loading.value = false; + } + }, 5000); + + const data_req = await fetch(`${window.location.protocol}//${window.location.host}/api/v1/${endpoint}`).catch(() => { + if(!fetch_failed.value) { + fetch_failed.value = `Failed to fetch ${data_name} data.`; + is_loading.value = false; + clearTimeout(fetch_timeout); + } + return null; + }); + + if(data_req !== null) { + const data = await data_req.json().catch(() => { + fetch_failed.value = "Failed to parse server response."; + }); + + if(data_req.ok) { + clearTimeout(fetch_timeout); + is_loading.value = false; + return data.data; + } else { + fetch_failed.value = `Failed to fetch ${data_name} data.`; + } + } + + clearTimeout(fetch_timeout); + is_loading.value = false; + return null; +}; diff --git a/packages/client/src/views/Home.vue b/packages/client/src/views/Home.vue index 305d42b..397a3a1 100644 --- a/packages/client/src/views/Home.vue +++ b/packages/client/src/views/Home.vue @@ -3,8 +3,8 @@ <HomeHeader /> <HomeProjectsHeader /> <div class="row mx-0"> - <div class="col ms-4"> - <ul id="repos"> + <div class="col ms-4 vld-parent"> + <ul id="repos" v-if="projects"> <li v-for="(project, project_name, index) in projects" :key="index"> <div v-if="(search !== null && project_name.includes(search)) || search == null"> <span class="fs-3"> @@ -17,6 +17,11 @@ </div> </li> </ul> + <BaseErrorMessage :fetch-failed="fetch_failed" /> + <Loading + :active="is_loading" :height="24" + :width="24" color="#ffffff" + :opacity="0" :is-full-page="false" /> </div> </div> </div> @@ -25,26 +30,33 @@ <script> import HomeHeader from "@/components/HomeHeader"; import HomeProjectsHeader from "@/components/HomeProjectsHeader"; +import Loading from "vue-loading-overlay"; +import BaseErrorMessage from "@/components/BaseErrorMessage"; +import fetchData from "@/util/fetch"; import { ref } from "vue"; export default { name: "Home", components: { HomeHeader, - HomeProjectsHeader + HomeProjectsHeader, + Loading, + BaseErrorMessage }, setup() { const projects = ref({}); const search = ref(""); + const is_loading = ref(true); + const fetch_failed = ref(null); const fetchProjects = async() => { - const projects_data = await (await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos`)).json(); - projects.value = projects_data.data; + const projects_data = await fetchData("repos", fetch_failed, is_loading, "projects"); + projects.value = projects_data; }; search.value = (new URLSearchParams(window.location.search)).get("q"); - return { projects, search, fetchProjects }; + return { projects, search, is_loading, fetch_failed, fetchProjects }; }, mount() { this.fetchProjects(); @@ -58,6 +70,7 @@ export default { <style lang="scss" scoped> @use "../scss/colors"; @import "../scss/bootstrap"; +@import "~vue-loading-overlay/dist/vue-loading.css"; #repos { margin-top: 25px; @@ -81,4 +94,8 @@ ul { flex-flow: column; height: 100vh; } + +.row { + height: 100%; +} </style> diff --git a/packages/client/src/views/RepositoryCommit.vue b/packages/client/src/views/RepositoryCommit.vue index 6bbbcaa..97c06b0 100644 --- a/packages/client/src/views/RepositoryCommit.vue +++ b/packages/client/src/views/RepositoryCommit.vue @@ -2,45 +2,49 @@ <div class="row mx-0"> <div class="col ms-2 ps-4 ps-sm-5 fs-5 vld-parent"> <BaseBreadcrumb :items="[{ name: 'Log', path: '/' + $router.currentRoute._rawValue.params.repo + '/log' }]" :active-item="$router.currentRoute._rawValue.params.commit" /> - <table id="commit-info" class="table table-dark"> - <tbody> - <tr> - <td class="commit-info-title"> - Author - </td> - <td>{{ commit_data["author"] }}</td> - </tr> - <tr> - <td class="commit-info-title"> - Date - </td> - <td>{{ commit_data["date"] }}</td> - </tr> - <tr> - <td class="commit-info-title"> - Message - </td> - <td>{{ commit_data["message"] }}</td> - </tr> - </tbody> - </table> + <template v-if="commit"> + <table + id="commit-info" class="table table-dark"> + <tbody> + <tr> + <td class="commit-info-title"> + Author + </td> + <td>{{ commit["author"] }}</td> + </tr> + <tr> + <td class="commit-info-title"> + Date + </td> + <td>{{ commit["date"] }}</td> + </tr> + <tr> + <td class="commit-info-title"> + Message + </td> + <td>{{ commit["message"] }}</td> + </tr> + </tbody> + </table> + <div + v-for="(patch, index) in commit['patches']" :key="index" + class="commit-patch"> + <div class="commit-patch-header"> + <span class="fw-bold">{{ (patch.to === "/dev/null") ? patch.from : patch.to }} </span> + <span v-if="patch.to === '/dev/null'">Deleted</span> + <div class="commit-patch-add-del"> + <span>+{{ patch.additions }}</span> + <span>-{{ patch.deletions }}</span> + </div> + </div> + <CommitPatch :patch="patch" /> + </div> + </template> + <BaseErrorMessage :fetch-failed="fetch_failed" /> <Loading :active="is_loading" :height="24" :width="24" color="#ffffff" :opacity="0" :is-full-page="false" /> - <div - v-for="(patch, index) in commit_data['patches']" :key="index" - class="commit-patch"> - <div class="commit-patch-header"> - <span class="fw-bold">{{ (patch.to === "/dev/null") ? patch.from : patch.to }} </span> - <span v-if="patch.to === '/dev/null'">Deleted</span> - <div class="commit-patch-add-del"> - <span>+{{ patch.additions }}</span> - <span>-{{ patch.deletions }}</span> - </div> - </div> - <CommitPatch :patch="patch" /> - </div> </div> </div> </template> @@ -49,28 +53,34 @@ import BaseBreadcrumb from "@/components/BaseBreadcrumb"; import CommitPatch from "@/components/CommitPatch"; import Loading from "vue-loading-overlay"; +import BaseErrorMessage from "@/components/BaseErrorMessage"; import { ref } from "vue"; import { format } from "date-fns"; +import fetchData from "@/util/fetch"; export default { name: "RepositoryCommit", components: { BaseBreadcrumb, Loading, - CommitPatch + CommitPatch, + BaseErrorMessage }, setup() { - const commit_data = ref({}); + const commit = ref(null); const is_loading = ref(true); + const fetch_failed = ref(null); + + const fetchCommit = async(repository, commit_id) => { + const commit_data = await fetchData(`repos/${repository}/log/${commit_id}`, fetch_failed, is_loading, "commit"); - const fetchCommit = async(repository, commit) => { - const data = await (await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${repository}/log/${commit}`)).json(); - data.data.date = format(new Date(data.data.date), "yyyy-MM-dd hh:mm"); - commit_data.value = data.data; - is_loading.value = false; + if(commit_data) { + commit_data.date = format(new Date(commit_data.date), "yyyy-MM-dd hh:mm"); + commit.value = commit_data; + } }; - return { commit_data, is_loading, fetchCommit }; + return { commit, is_loading, fetch_failed, fetchCommit }; }, created() { this.fetchCommit(this.$router.currentRoute._rawValue.params.repo, this.$router.currentRoute._rawValue.params.commit); diff --git a/packages/client/src/views/RepositoryLog.vue b/packages/client/src/views/RepositoryLog.vue index 542831f..3b6248c 100644 --- a/packages/client/src/views/RepositoryLog.vue +++ b/packages/client/src/views/RepositoryLog.vue @@ -1,11 +1,9 @@ <template> - <div class="row mx-0 vld-parent"> - <Loading - :active="is_loading" :height="24" - :width="24" color="#ffffff" - :opacity="0" /> + <div class="row mx-0 vld-parent flex-fill"> <div class="col ms-4 ps-4 ps-sm-5 mt-3"> - <table id="log" class="table table-dark fs-5"> + <table + id="log" class="table table-dark fs-5" + v-if="commits"> <thead> <tr> <th class="text-secondary"> @@ -39,19 +37,27 @@ </tr> </tbody> </table> + <BaseErrorMessage :fetch-failed="fetch_failed" /> + <Loading + :active="is_loading" :height="24" + :width="24" color="#ffffff" + :opacity="0" :is-full-page="false" /> </div> </div> </template> <script> import Loading from "vue-loading-overlay"; +import BaseErrorMessage from "@/components/BaseErrorMessage"; import { ref } from "vue"; import { format } from "date-fns"; +import fetchData from "@/util/fetch"; export default { name: "RepositoryLog", components: { - Loading + Loading, + BaseErrorMessage }, data() { return { @@ -59,16 +65,18 @@ export default { }; }, setup() { - const commits = ref({}); + const commits = ref(null); const is_loading = ref(true); + const fetch_failed = ref(null); const fetchLog = async(repository) => { - const log_data = await (await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${repository}/log`)).json(); - commits.value = log_data.data; - is_loading.value = false; + const log_data = await fetchData(`repos/${repository}/log`, fetch_failed, is_loading, "log"); + if(log_data) { + commits.value = log_data; + } }; - return { commits, is_loading, fetchLog }; + return { commits, is_loading, fetch_failed, fetchLog }; }, created() { this.fetchLog(this.$router.currentRoute._rawValue.params.repo); diff --git a/packages/client/src/views/RepositoryTree.vue b/packages/client/src/views/RepositoryTree.vue index 1b61c42..898b12c 100644 --- a/packages/client/src/views/RepositoryTree.vue +++ b/packages/client/src/views/RepositoryTree.vue @@ -11,11 +11,11 @@ }))" :active-item="(pathArr.length === 0) ? $router.currentRoute._rawValue.params.repo : pathArr[pathArr.length - 1]" /> <RepositoryTreeTree :repository="$router.currentRoute._rawValue.params.repo" :path="path" - :tree="tree" v-if="type === 'tree'" - :is-loading="is_loading" /> + :tree="tree" v-if="tree" /> <RepositoryTreeBlob :repository="$router.currentRoute._rawValue.params.repo" :path="path" - :content="blob_content" v-else /> + :content="blob_content" v-if="blob_content" /> + <BaseErrorMessage :fetch-failed="fetch_failed" /> <Loading :active="is_loading" :height="24" :width="24" color="#ffffff" @@ -28,8 +28,10 @@ import BaseBreadcrumb from "@/components/BaseBreadcrumb"; import RepositoryTreeBlob from "@/components/RepositoryTreeBlob"; import RepositoryTreeTree from "@/components/RepositoryTreeTree"; +import BaseErrorMessage from "@/components/BaseErrorMessage"; import Loading from "vue-loading-overlay"; import { ref } from "vue"; +import fetchData from "@/util/fetch"; export default { name: "RepositoryTree", @@ -37,7 +39,8 @@ export default { BaseBreadcrumb, RepositoryTreeBlob, RepositoryTreeTree, - Loading + Loading, + BaseErrorMessage }, props: { pathArr: { @@ -48,45 +51,45 @@ export default { watch: { pathArr() { this.is_loading = true; - this.tree = {}; this.fetchTree(this.$router.currentRoute._rawValue.params.repo); } }, setup(props) { - const type = ref(""); - const tree = ref({}); - const blob_content = ref(""); + const tree = ref(null); + const blob_content = ref(null); const is_loading = ref(true); + const fetch_failed = ref(null); const path = ref(""); const fetchTree = async(repository) => { + blob_content.value = null; + tree.value = null; + path.value = props.pathArr ? props.pathArr.join("/") : undefined; - const data = await (await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos/${repository}/tree${path.value ? "?path=" + path.value : ""}`)).json(); - console.log(path.value); - type.value = data.data.type; - if(data.data.type === "tree") { - const tree_data = data.data.tree; + const tree_data = await fetchData(`repos/${repository}/tree${path.value ? "?path=" + path.value : ""}`, fetch_failed, is_loading, "tree"); - let tree_trees = Object.entries(tree_data).filter((entry) => entry[1].type === "tree"); - tree_trees = tree_trees.sort((a, b) => a[0].localeCompare(b[0])); + if(tree_data) { + if(tree_data.type === "tree") { + let tree_trees = Object.entries(tree_data.tree).filter((entry) => entry[1].type === "tree"); + tree_trees = tree_trees.sort((a, b) => a[0].localeCompare(b[0])); - let tree_blobs = Object.entries(tree_data).filter((entry) => entry[1].type === "blob"); - tree_blobs = tree_blobs.sort((a, b) => a[0].localeCompare(b[0])); + let tree_blobs = Object.entries(tree_data.tree).filter((entry) => entry[1].type === "blob"); + tree_blobs = tree_blobs.sort((a, b) => a[0].localeCompare(b[0])); - tree.value = Object.fromEntries(tree_trees.concat(tree_blobs)); - } else { - blob_content.value = data.data.content; + tree.value = Object.fromEntries(tree_trees.concat(tree_blobs)); + console.log(tree.value); + } else { + blob_content.value = tree_data.content; + } } - - is_loading.value = false; }; return { - type, tree, blob_content, is_loading, + fetch_failed, path, fetchTree }; diff --git a/packages/server/package.json b/packages/server/package.json index 012784b..90e54ea 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -5,7 +5,7 @@ "author": "HampusMat", "license": "MIT", "scripts": { - "dev": "concurrently -k --kill-others-on-fail \"yarn tsc --watch \" \"nodemon --exitcrash dist/app.js\"" + "dev": "yarn tsc && concurrently -k --kill-others-on-fail \"yarn tsc --watch \" \"nodemon --exitcrash dist/app.js\"" }, "dependencies": { "date-fns": "^2.22.1", |