aboutsummaryrefslogtreecommitdiff
path: root/packages/client/src/views
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2021-06-05 19:37:52 +0200
committerHampusM <hampus@hampusmat.com>2021-06-05 19:37:52 +0200
commit4da3272bf7893760f6710c9a1ec7de02358136e6 (patch)
tree92eb961bf20a7ef9f7c0650ba288baf512986fca /packages/client/src/views
parent4e3074dfd752dd52951d300090c642aee76cfaac (diff)
Reorganized into a monorepo, refactored the frontend again, goodbye Parcel
Diffstat (limited to 'packages/client/src/views')
-rw-r--r--packages/client/src/views/Home.vue79
-rw-r--r--packages/client/src/views/Repository.vue27
-rw-r--r--packages/client/src/views/RepositoryCommit.vue202
-rw-r--r--packages/client/src/views/RepositoryLog.vue111
-rw-r--r--packages/client/src/views/RepositoryTree.vue106
5 files changed, 525 insertions, 0 deletions
diff --git a/packages/client/src/views/Home.vue b/packages/client/src/views/Home.vue
new file mode 100644
index 0000000..80f2e9a
--- /dev/null
+++ b/packages/client/src/views/Home.vue
@@ -0,0 +1,79 @@
+<template>
+ <div class="container-fluid px-0">
+ <HomeHeader />
+ <HomeProjectsHeader />
+ <div class="row mx-0">
+ <div class="col ms-4">
+ <ul id="repos">
+ <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">
+ <router-link :to="project_name">
+ {{ project_name }}
+ </router-link>
+ </span>
+ <span class="repo-last-updated fs-5">Last updated about {{ project["last_updated"] }} ago</span>
+ <span class="fs-5">{{ project["description"] }}</span>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import HomeHeader from "@/components/HomeHeader";
+import HomeProjectsHeader from "@/components/HomeProjectsHeader";
+import { ref } from "vue";
+
+export default {
+ name: "Home",
+ components: {
+ HomeHeader,
+ HomeProjectsHeader
+ },
+ setup() {
+ const projects = ref({});
+ const search = ref("");
+
+ const fetchProjects = async() => {
+ const projects_data = await (await fetch(`${window.location.protocol}//${window.location.host}/api/v1/repos`)).json();
+ projects.value = projects_data.data;
+ };
+
+ search.value = (new URLSearchParams(window.location.search)).get("q");
+
+ return { projects, search, fetchProjects };
+ },
+ mount() {
+ this.fetchProjects();
+ },
+ created() {
+ this.fetchProjects();
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+@use "../scss/colors";
+@import "../scss/bootstrap";
+
+#repos {
+ margin-top: 25px;
+ li {
+ margin-bottom: 25px;
+ }
+}
+
+.repo-last-updated {
+ display: block;
+ font-weight: 300;
+ font-style: italic;
+}
+
+ul {
+ list-style-type: none;
+ padding: 0;
+}
+</style>
diff --git a/packages/client/src/views/Repository.vue b/packages/client/src/views/Repository.vue
new file mode 100644
index 0000000..93c3f82
--- /dev/null
+++ b/packages/client/src/views/Repository.vue
@@ -0,0 +1,27 @@
+<template>
+ <div class="container-fluid px-0 d-flex">
+ <RepositoryHeader :repository="$router.currentRoute._rawValue.params.repo" />
+ <RepositoryNavbar :repository="$router.currentRoute._rawValue.params.repo" :active-page="$router.currentRoute._rawValue.path.split('/')[2]" />
+ <router-view />
+ </div>
+</template>
+
+<script>
+import RepositoryHeader from "@/components/RepositoryHeader";
+import RepositoryNavbar from "@/components/RepositoryNavbar";
+
+export default {
+ name: "Repository",
+ components: {
+ RepositoryHeader,
+ RepositoryNavbar
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+.container-fluid {
+ flex-flow: column;
+ height: 100vh;
+}
+</style>
diff --git a/packages/client/src/views/RepositoryCommit.vue b/packages/client/src/views/RepositoryCommit.vue
new file mode 100644
index 0000000..6bbbcaa
--- /dev/null
+++ b/packages/client/src/views/RepositoryCommit.vue
@@ -0,0 +1,202 @@
+<template>
+ <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>
+ <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>
+
+<script>
+import BaseBreadcrumb from "@/components/BaseBreadcrumb";
+import CommitPatch from "@/components/CommitPatch";
+import Loading from "vue-loading-overlay";
+import { ref } from "vue";
+import { format } from "date-fns";
+
+export default {
+ name: "RepositoryCommit",
+ components: {
+ BaseBreadcrumb,
+ Loading,
+ CommitPatch
+ },
+ setup() {
+ const commit_data = ref({});
+ const is_loading = ref(true);
+
+ 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;
+ };
+
+ return { commit_data, is_loading, fetchCommit };
+ },
+ created() {
+ this.fetchCommit(this.$router.currentRoute._rawValue.params.repo, this.$router.currentRoute._rawValue.params.commit);
+ }
+};
+</script>
+
+<style lang="scss">
+@use "../scss/colors";
+@import "../scss/bootstrap";
+
+@import "~bootstrap/scss/tables";
+
+@import "~vue-loading-overlay/dist/vue-loading.css";
+@import "~highlight.js/scss/srcery.scss";
+
+#commit-info {
+ margin-bottom: 2rem;
+ tbody tr {
+ td {
+ padding: 0px;
+ padding-right: 10px;
+ }
+ }
+}
+
+.commit-patch {
+ margin-bottom: 50px;
+ table {
+ padding-top: 15px;
+ tbody tr td {
+ padding: 0px;
+ padding-left: 8px;
+ vertical-align: top;
+ &:nth-child(2) {
+ padding-right: 7px;
+ }
+ &:nth-child(3) {
+ padding-right: 15px;
+ }
+ }
+ }
+}
+
+.commit-patch-add-del {
+ margin-left: auto;
+ margin-right: 23px;
+ span {
+ margin-right: 10px !important;
+ font-weight: 700;
+ &:nth-child(1) {
+ color: colors.$new;
+ }
+ }
+}
+
+.commit-patch-header {
+ display: flex;
+ background-color: lighten(#000000, 14%);
+ padding: 10px;
+ span {
+ margin-right: 30px;
+ &:nth-child(2) {
+ color: colors.$danger;
+ }
+ }
+}
+
+.commit-info-title {
+ color: colors.$secondary;
+ padding-right: 30px;
+ width: 20px;
+}
+
+.patch-too-large {
+ font-weight: 600;
+}
+
+.commit-file-pos-change {
+ color: colors.$text-gray;
+}
+
+.commit-file-no-newline {
+ color: colors.$text-gray;
+}
+
+.line-new {
+ color: colors.$new;
+}
+.line-deleted {
+ color: colors.$danger;
+}
+
+.line-unchanged {
+ color: colors.$text-gray;
+}
+
+[patch-line-col-unsel]::before {
+ content: attr(patch-line-col-unsel);
+}
+
+.line-highlight-new {
+ border-right: 1px solid colors.$new;
+}
+.line-highlight-deleted {
+ border-right: 1px solid colors.$danger;
+}
+
+code {
+ white-space: pre-wrap;
+ word-wrap: anywhere;
+}
+
+.row {
+ height: 100%;
+}
+
+@include media-breakpoint-down(sm) {
+ .commit-patch table tbody tr td {
+ padding-left: 4px;
+ &:nth-child(2) {
+ padding-right: 4px;
+ }
+ &:nth-child(3) {
+ padding-right: 5px;
+ }
+ }
+}
+</style>
diff --git a/packages/client/src/views/RepositoryLog.vue b/packages/client/src/views/RepositoryLog.vue
new file mode 100644
index 0000000..542831f
--- /dev/null
+++ b/packages/client/src/views/RepositoryLog.vue
@@ -0,0 +1,111 @@
+<template>
+ <div class="row mx-0 vld-parent">
+ <Loading
+ :active="is_loading" :height="24"
+ :width="24" color="#ffffff"
+ :opacity="0" />
+ <div class="col ms-4 ps-4 ps-sm-5 mt-3">
+ <table id="log" class="table table-dark fs-5">
+ <thead>
+ <tr>
+ <th class="text-secondary">
+ Subject
+ </th>
+ <th class="text-secondary">
+ Author
+ </th>
+ <th class="text-secondary">
+ Date
+ </th>
+ <th class="text-secondary">
+ Files
+ </th>
+ <th class="text-secondary">
+ Del/Add
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="(commit, index) in commits" :key="index">
+ <td>
+ <router-link :to="'log/' + commit['commit']">
+ {{ commit["message"] }}
+ </router-link>
+ </td>
+ <td>{{ commit["author_name"] }}</td>
+ <td>{{ format(new Date(commit["date"]), "yyyy-MM-dd hh:mm") }}</td>
+ <td>{{ commit["files_changed"] }}</td>
+ <td><span class="text-danger">-{{ commit["deletions"] }}</span> / <span class="text-success">+{{ commit["insertions"] }}</span></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</template>
+
+<script>
+import Loading from "vue-loading-overlay";
+import { ref } from "vue";
+import { format } from "date-fns";
+
+export default {
+ name: "RepositoryLog",
+ components: {
+ Loading
+ },
+ data() {
+ return {
+ format
+ };
+ },
+ setup() {
+ const commits = ref({});
+ const is_loading = ref(true);
+
+ 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;
+ };
+
+ return { commits, is_loading, fetchLog };
+ },
+ created() {
+ this.fetchLog(this.$router.currentRoute._rawValue.params.repo);
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+@use "../scss/colors";
+
+@import "~vue-loading-overlay/dist/vue-loading.css";
+@import "../scss/bootstrap";
+@import "../scss/fonts";
+
+@import "~bootstrap/scss/tables";
+
+#log {
+ border-spacing: 0;
+ tbody tr {
+ &:hover {
+ --bs-table-bg: 0;
+ background-color: lighten(colors.$background, 5%);
+ }
+ td {
+ padding-bottom: 1em;
+ }
+ }
+ th {
+ text-align: start;
+ padding-bottom: 1em;
+ }
+}
+
+@include media-breakpoint-down(sm) {
+ .table > :not(caption) > * > * {
+ padding: 0.1rem;
+ }
+}
+
+</style>
diff --git a/packages/client/src/views/RepositoryTree.vue b/packages/client/src/views/RepositoryTree.vue
new file mode 100644
index 0000000..1b61c42
--- /dev/null
+++ b/packages/client/src/views/RepositoryTree.vue
@@ -0,0 +1,106 @@
+<template>
+ <div class="row mx-0">
+ <div class="col ms-4 ps-4 ps-sm-5 mt-3 fs-5 vld-parent">
+ <BaseBreadcrumb
+ :items="(pathArr.length === 0) ? [] : [{ name: $router.currentRoute._rawValue.params.repo, path: '/' + $router.currentRoute._rawValue.params.repo + '/tree' }].concat(pathArr.slice(0, -1).map((path_part, index) =>
+ {
+ return {
+ name: path_part,
+ path: '/' + $router.currentRoute._rawValue.params.repo + '/tree/' + pathArr.slice(0, index + 1).join('/')
+ }
+ }))" :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" />
+ <RepositoryTreeBlob
+ :repository="$router.currentRoute._rawValue.params.repo" :path="path"
+ :content="blob_content" v-else />
+ <Loading
+ :active="is_loading" :height="24"
+ :width="24" color="#ffffff"
+ :opacity="0" :is-full-page="false" />
+ </div>
+ </div>
+</template>
+
+<script>
+import BaseBreadcrumb from "@/components/BaseBreadcrumb";
+import RepositoryTreeBlob from "@/components/RepositoryTreeBlob";
+import RepositoryTreeTree from "@/components/RepositoryTreeTree";
+import Loading from "vue-loading-overlay";
+import { ref } from "vue";
+
+export default {
+ name: "RepositoryTree",
+ components: {
+ BaseBreadcrumb,
+ RepositoryTreeBlob,
+ RepositoryTreeTree,
+ Loading
+ },
+ props: {
+ pathArr: {
+ type: Array,
+ required: true
+ }
+ },
+ 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 is_loading = ref(true);
+ const path = ref("");
+
+ const fetchTree = async(repository) => {
+ 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;
+
+ 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]));
+
+ 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]));
+
+ tree.value = Object.fromEntries(tree_trees.concat(tree_blobs));
+ } else {
+ blob_content.value = data.data.content;
+ }
+
+ is_loading.value = false;
+ };
+
+ return {
+ type,
+ tree,
+ blob_content,
+ is_loading,
+ path,
+ fetchTree
+ };
+ },
+ created() {
+ this.fetchTree(this.$router.currentRoute._rawValue.params.repo);
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+@import "~vue-loading-overlay/dist/vue-loading.css";
+
+.row {
+ height: 100%;
+}
+</style>