Skip to content

Commit

Permalink
display currently selected mander
Browse files Browse the repository at this point in the history
  • Loading branch information
rouk1 committed Jul 16, 2024
1 parent ea3f7c1 commit 93df841
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 75 deletions.
12 changes: 8 additions & 4 deletions frontend/src/components/FileTree.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
<script lang="ts">
export interface FileTreeNode {
label: string;
path: string;
children?: FileTreeNode[];
indentationLevel?: number;
}
</script>

<script setup lang="ts">
import { computed } from "vue";
import FileTreeItem from "./FileTreeItem.vue";
defineProps<{ nodes: FileTreeNode[] }>();
const props = defineProps<{ nodes: FileTreeNode[] }>();
defineEmits<{
onItemClick: [nodePath: string];
}>();
</script>

<template>
<FileTreeItem
v-for="(node, index) in nodes"
:key="index"
:label="node.label"
:path="node.path"
:children="node.children"
:indentation-level="0"
/>
</template>

<style>
<style scoped>
.file-tree {
padding: 1em;
background-color: green;
Expand Down
24 changes: 20 additions & 4 deletions frontend/src/components/FileTreeItem.vue
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
<script setup lang="ts">
import { computed } from "vue";
import { useRouter } from "vue-router";
import { type FileTreeNode } from "./FileTree.vue";
import FolderIcon from "./icons/FolderIcon.vue";
import ManderIcon from "./icons/ManderIcon.vue";
const router = useRouter();
const props = defineProps<FileTreeNode>();
const hasChildren = computed(() => props.children?.length);
const label = computed(() => {
const slugs = props.path.split("/");
return slugs[slugs.length - 1];
});
function onClick() {
router.push({
name: "mander",
params: {
slug: props.path.split("/"),
},
});
}
</script>

<template>
<div class="file-tree-item" :style="`--indentation-level: ${indentationLevel};`">
<div class="label">
<div class="label" @click="onClick">
<div class="icon">
<FolderIcon v-if="hasChildren" />
<ManderIcon v-else />
</div>
<div class="text">{{ props.label }}</div>
<div class="text">{{ label }}</div>
</div>
<div class="children" v-if="hasChildren">
<FileTreeItem
v-for="(child, index) in props.children"
:key="index"
:label="child.label"
:path="child.path"
:children="child.children"
:indentation-level="(indentationLevel ?? 0) + 1"
/>
</div>
</div>
</template>
<style>
<style scoped>
.file-tree-item {
margin-left: calc(8px * var(--indentation-level));
Expand All @@ -45,6 +60,7 @@ const hasChildren = computed(() => props.children?.length);
&:hover {
background-color: #ddd;
font-weight: 500;
}
& .icon {
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export interface Mander {
path: string;
views: string[];
logs: string[];
artifacts: {
[key: string]: {
path: string;
};
};
info: {
[key: string]: any;
};
}
5 changes: 5 additions & 0 deletions frontend/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ const router = createRouter({
name: "home",
component: DashboardView,
},
{
path: "/:slug+",
name: "mander",
component: DashboardView,
},
],
});

Expand Down
15 changes: 14 additions & 1 deletion frontend/src/services/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { type Mander } from "../models";

const BASE_URL = "http://localhost:8000/api";

function getErrorMessage(error: unknown) {
Expand All @@ -9,7 +11,7 @@ function reportError(message: string) {
console.error(message);
}

export async function getAllManderPaths(): Promise<string[]> {
export async function fetchAllManderPaths(): Promise<string[]> {
try {
const r = await fetch(`${BASE_URL}/mandrs`);
const paths = await r.json();
Expand All @@ -19,3 +21,14 @@ export async function getAllManderPaths(): Promise<string[]> {
return [];
}
}

export async function fetchMander(path: string): Promise<Mander | null> {
try {
const r = await fetch(`${BASE_URL}/mandrs/${path}`);
const m = await r.json();
return m as Mander;
} catch (error) {
reportError(getErrorMessage(error));
return null;
}
}
77 changes: 64 additions & 13 deletions frontend/src/views/DashboardView.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,88 @@
<script setup lang="ts">
import { computed } from "vue";
import FileTree, { type FileTreeNode } from "@/components/FileTree.vue";
import { getAllManderPaths } from "@/services/api";
import { computed, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { type Mander } from "../models";
import { fetchAllManderPaths, fetchMander } from "../services/api";
import FileTree, { type FileTreeNode } from "../components/FileTree.vue";
import ManderView from "./ManderView.vue";
const route = useRoute();
const manderPaths = ref<string[]>([]);
const mander = ref<Mander>();
const manderPaths = await getAllManderPaths();
const pathsAsFileTreeNodes = computed(() => {
const tree: FileTreeNode[] = [];
for (let p of manderPaths) {
for (let p of manderPaths.value) {
const slugs = p.split("/");
const rootSlug = slugs[0];
let currentNode = tree.find((n) => n.label == rootSlug);
let currentNode = tree.find((n) => n.path == rootSlug);
if (!currentNode) {
currentNode = { label: rootSlug };
currentNode = { path: rootSlug };
tree.push(currentNode);
}
let n = currentNode!;
for (let s of slugs.slice(1)) {
n.children = n.children || [];
let childNode = n.children.find((n) => n.label == s);
const path = `${n.path}/${s}`;
let childNode = n.children.find((n) => n.path == path);
if (!childNode) {
childNode = { label: s };
childNode = { path };
n.children.push(childNode);
}
n = childNode;
}
}
return tree;
});
watch(
() => route.params.slug,
async (newSlug) => {
const path = Array.isArray(newSlug) ? newSlug.join("/") : newSlug;
const m = await fetchMander(path);
if (m) {
mander.value = m;
}
// TODO handle error
}
);
manderPaths.value = await fetchAllManderPaths();
</script>

<template>
<div class="dashboard">
<FileTree :nodes="pathsAsFileTreeNodes"></FileTree>
</div>
<main>
<nav>
<FileTree :nodes="pathsAsFileTreeNodes" />
</nav>
<article>
<ManderView v-if="mander" :mander="mander" />
</article>
</main>
</template>

<style scoped>
main {
display: flex;
flex-direction: row;
nav,
article {
overflow: scroll;
height: 100dvh;
}
nav {
width: 285px;
flex-shrink: 0;
padding: 10px;
border-left: 1px solid #e9e9e9;
background-color: #f2f1f1;
}
article {
flex-grow: 1;
}
}
</style>
53 changes: 53 additions & 0 deletions frontend/src/views/ManderView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script setup lang="ts">
import { type Mander } from "../models";
const props = defineProps<{ mander: Mander }>();
</script>

<template>
<h1>{{ props.mander.path }}</h1>
<aside>
<h2>Views</h2>
<div v-for="(value, name, index) in props.mander.views" :key="index">
<h3>{{ name }}</h3>
<div v-html="value" />
</div>
</aside>
<aside>
<h2>Logs</h2>
<div v-for="(value, name, index) in props.mander.logs" :key="index">
<h3>{{ name }}</h3>
<div v-html="value" />
</div>
</aside>
<aside>
<h2>Artifacts</h2>
<div v-for="(value, name, index) in props.mander.artifacts" :key="index">
<h3>{{ name }}</h3>
<div v-html="value.path" />
</div>
</aside>
<aside>
<h2>Info</h2>
<div v-for="(value, name, index) in props.mander.info" :key="index">
<h3>{{ name }}</h3>
<div v-html="value" />
</div>
</aside>
</template>

<style scoped>
aside {
border: 1px solid #e9e9e9;
margin: 5px;
h2 {
background-color: #f2f1f1;
color: #7e7e7e;
}
& > div {
padding: 5px;
}
}
</style>
Loading

0 comments on commit 93df841

Please sign in to comment.