aboutsummaryrefslogtreecommitdiff
path: root/packages/client
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2021-06-09 17:37:43 +0200
committerHampusM <hampus@hampusmat.com>2021-06-09 17:37:43 +0200
commit75e8ae6ebd9df23275fb14eea88da0b56d006313 (patch)
treecd8a261f856e2177626272e7018041be3102304b /packages/client
parentdae7377188242e8dbc18f029bc97b7def9acb13c (diff)
Frontend has proper error handling & api fetching is in it's own file
Diffstat (limited to 'packages/client')
-rw-r--r--packages/client/src/components/BaseErrorMessage.vue27
-rw-r--r--packages/client/src/components/RepositoryTreeTree.vue2
-rw-r--r--packages/client/src/util/fetch.js35
-rw-r--r--packages/client/src/views/Home.vue29
-rw-r--r--packages/client/src/views/RepositoryCommit.vue96
-rw-r--r--packages/client/src/views/RepositoryLog.vue32
-rw-r--r--packages/client/src/views/RepositoryTree.vue49
7 files changed, 185 insertions, 85 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
};