Skip to content

Commit

Permalink
Merge branch 'main' into 48-component-page and fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rouk1 committed Jul 19, 2024
2 parents 39808c1 + 5e144bc commit 1ef4370
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 335 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ check-wip:
python -m pytest tests

serve-api:
MANDR_ROOT=.datamander MANDR_PATH=probabl-ai python -m uvicorn mandr.dashboard.webapp:app --reload --reload-dir ./src --host 0.0.0.0 --timeout-graceful-shutdown 0
MANDR_ROOT=.datamander python -m uvicorn mandr.dashboard.webapp:app --reload --reload-dir ./src --host 0.0.0.0 --timeout-graceful-shutdown 0

build-frontend:
# build the SPA
Expand Down
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@

![lint and test](https://github.com/probabl-ai/mandr/actions/workflows/lint-and-test.yml/badge.svg)

Service to send data into, install via

```
python -m pip install -e
python -m pip install flask diskcache pandas altair
```
A service to send data into.

## Example

```python
from mandr import InfoMander
Expand All @@ -21,16 +17,19 @@ mander.add_templates(...)
mander.add_views(...)
```

When ready to view, run flask:
## Development

```
python -m flask --app mandr.app run --reload
Install dependencies with
```sh
make install
```

## Dependencies
You can run the API server with
```sh
make serve-api
```

When dependencies are changed in `pyproject.toml` the lockfiles should be updated by running [`pip-compile`](https://github.com/jazzband/pip-tools):
When dependencies are changed in `pyproject.toml` the lockfiles should be updated via [`pip-compile`](https://github.com/jazzband/pip-tools):
```sh
pip-compile --output-file=requirements.txt pyproject.toml
pip-compile --extra=test --output-file=requirements-test.txt pyproject.toml
make pip-compile
```
20 changes: 16 additions & 4 deletions frontend/src/components/DataStoreDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,25 @@ const props = defineProps<{ dataStore: DataStore }>();

<template>
<div class="item-list">
<DataStoreItemList title="Views" icon="icon-plot" :elements="Object.keys(dataStore.views)" />
<DataStoreItemList title="Info" icon="icon-text" :elements="Object.keys(dataStore.info)" />
<DataStoreItemList title="Logs" icon="icon-gift" :elements="Object.keys(dataStore.logs)" />
<DataStoreItemList
title="Views"
icon="icon-plot"
:elements="Object.keys(props.dataStore.views)"
/>
<DataStoreItemList
title="Info"
icon="icon-text"
:elements="Object.keys(props.dataStore.info)"
/>
<DataStoreItemList
title="Logs"
icon="icon-gift"
:elements="Object.keys(props.dataStore.logs)"
/>
<DataStoreItemList
title="Logs"
icon="icon-folder"
:elements="Object.keys(dataStore.artifacts)"
:elements="Object.keys(props.dataStore.artifacts)"
/>
</div>
</template>
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/components/FileTree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@ export interface FileTreeNode {
children?: FileTreeNode[];
indentationLevel?: number;
}
export function transformUrisToTree(uris: string[]) {
const tree: FileTreeNode[] = [];
for (let p of uris) {
const segments = p.split("/");
const rootSegment = segments[0];
let currentNode = tree.find((n) => n.uri == rootSegment);
if (!currentNode) {
currentNode = { uri: rootSegment };
tree.push(currentNode);
}
let n = currentNode!;
for (let s of segments.slice(1)) {
n.children = n.children || [];
const uri = `${n.uri}/${s}`;
let childNode = n.children.find((n) => n.uri == uri);
if (!childNode) {
childNode = { uri };
n.children.push(childNode);
}
n = childNode;
}
}
return tree;
}
</script>

<script setup lang="ts">
Expand Down
31 changes: 4 additions & 27 deletions frontend/src/views/DashboardView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,21 @@ import { computed, ref, watch } from "vue";
import { useRoute } from "vue-router";
import DataStoreDetail from "../components/DataStoreDetail.vue";
import FileTree, { type FileTreeNode } from "../components/FileTree.vue";
import FileTree, { transformUrisToTree } from "../components/FileTree.vue";
import { type DataStore } from "../models";
import { fetchAllManderUris, fetchMander } from "../services/api";
const route = useRoute();
const dataStoreUris = ref<string[]>([]);
const dataStore = ref<DataStore | null>();
const pathsAsFileTreeNodes = computed(() => {
const tree: FileTreeNode[] = [];
for (let p of dataStoreUris.value) {
const segments = p.split("/");
const rootSegment = segments[0];
let currentNode = tree.find((n) => n.uri == rootSegment);
if (!currentNode) {
currentNode = { uri: rootSegment };
tree.push(currentNode);
}
let n = currentNode!;
for (let s of segments.slice(1)) {
n.children = n.children || [];
const uri = `${n.uri}/${s}`;
let childNode = n.children.find((n) => n.uri == uri);
if (!childNode) {
childNode = { uri };
n.children.push(childNode);
}
n = childNode;
}
}
return tree;
});
const fileTree = computed(() => transformUrisToTree(dataStoreUris.value));
async function fetchDataStoreDetail(path: string | string[]) {
const p = Array.isArray(path) ? path.join("/") : path;
const m = await fetchMander(p);
dataStore.value = m;
}
watch(
() => route.params.segments,
async (newSegments) => {
Expand All @@ -55,7 +32,7 @@ await fetchDataStoreDetail(route.params.segments);
<template>
<main>
<nav>
<FileTree :nodes="pathsAsFileTreeNodes" />
<FileTree :nodes="fileTree" />
</nav>
<article :class="{ 'not-found': dataStore == null }">
<DataStoreDetail v-if="dataStore" :dataStore="dataStore" />
Expand Down
41 changes: 40 additions & 1 deletion frontend/tests/components/FileTree.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";

import FileTree, { type FileTreeNode } from "@/components/FileTree.vue";
import FileTree, { transformUrisToTree, type FileTreeNode } from "@/components/FileTree.vue";
import { mount } from "@vue/test-utils";

function countLeaves(nodes: FileTreeNode[]): number {
Expand Down Expand Up @@ -93,4 +93,43 @@ describe("FileTree", () => {
const leaves = treeItems.filter((c) => c.findAll(itemSelector).length == 0);
expect(leaves).toHaveLength(leavesCount);
});

it("Can transform an array of URIs to a tree", () => {
const uris = [
"probabl-ai/demo-usecase/training/0",
"probabl-ai/test-mandr/0",
"probabl-ai/test-mandr/1",
"probabl-ai/test-mandr/2",
"probabl-ai/test-mandr/3",
"probabl-ai/test-mandr/4",
];

const tree = transformUrisToTree(uris);
expect(tree).toEqual([
{
uri: "probabl-ai",
children: [
{
uri: "probabl-ai/demo-usecase",
children: [
{
uri: "probabl-ai/demo-usecase/training",
children: [{ uri: "probabl-ai/demo-usecase/training/0" }],
},
],
},
{
uri: "probabl-ai/test-mandr",
children: [
{ uri: "probabl-ai/test-mandr/0" },
{ uri: "probabl-ai/test-mandr/1" },
{ uri: "probabl-ai/test-mandr/2" },
{ uri: "probabl-ai/test-mandr/3" },
{ uri: "probabl-ai/test-mandr/4" },
],
},
],
},
]);
});
});
70 changes: 20 additions & 50 deletions frontend/tests/views/dashboard.spec.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,34 @@
import FileTree from "@/components/FileTree.vue";
import DashboardView from "@/views/DashboardView.vue";
import { VueWrapper } from "@vue/test-utils";
import { describe, expect, it, vi } from "vitest";
import { useRoute } from "vue-router";
import { createFetchResponse, mockedFetch, mountSuspense } from "../test.utils";

vi.mock("vue-router", () => ({
useRoute: vi.fn(),
useRouter: vi.fn(() => ({
push: () => {},
})),
}));
import DashboardView from "@/views/DashboardView.vue";

describe("DashboardView", () => {
it("Parse the list of fetched list of mander to an array of FileTreeNode.", async () => {
const paths = [
"probabl-ai/demo-usecase/training/0",
"probabl-ai/test-mandr/0",
"probabl-ai/test-mandr/1",
"probabl-ai/test-mandr/2",
"probabl-ai/test-mandr/3",
"probabl-ai/test-mandr/4",
];
import FileTree from "@/components/FileTree.vue";
import { beforeEach } from "node:test";
import { mountSuspense } from "../test.utils";

mockedFetch.mockResolvedValue(createFetchResponse(paths));
beforeEach(() => {
vi.mock("vue-router", () => ({
useRoute: vi.fn(),
useRouter: vi.fn(() => ({
push: () => {},
})),
}));
});

describe("DashboardView", () => {
it("Renders properly", async () => {
(useRoute as any).mockImplementationOnce(() => ({
params: {
segments: ["a", "b"],
},
}));

const wrapper = await mountSuspense(DashboardView);
const fileTree = wrapper.getComponent(FileTree);
expect(fileTree.props()).toEqual({
nodes: [
{
uri: "probabl-ai",
children: [
{
uri: "probabl-ai/demo-usecase",
children: [
{
uri: "probabl-ai/demo-usecase/training",
children: [{ uri: "probabl-ai/demo-usecase/training/0" }],
},
],
},
{
uri: "probabl-ai/test-mandr",
children: [
{ uri: "probabl-ai/test-mandr/0" },
{ uri: "probabl-ai/test-mandr/1" },
{ uri: "probabl-ai/test-mandr/2" },
{ uri: "probabl-ai/test-mandr/3" },
{ uri: "probabl-ai/test-mandr/4" },
],
},
],
},
],
});
const dashboard = await mountSuspense(DashboardView);
expect(dashboard).toBeInstanceOf(VueWrapper);

const fileTree = await dashboard.findComponent(FileTree);
expect(fileTree).toBeInstanceOf(VueWrapper);
});
});
22 changes: 0 additions & 22 deletions src/mandr/templates/page.html

This file was deleted.

17 changes: 0 additions & 17 deletions src/mandr/templates/partials/artifacts.html

This file was deleted.

Loading

0 comments on commit 1ef4370

Please sign in to comment.