show active jobs in web ui; node-sass -> sass

feat/vaults
Tomáš Mládek 2021-02-21 10:47:28 +01:00
parent 550e8d5c0f
commit c0c240256a
6 changed files with 15229 additions and 758 deletions

15881
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,8 @@
"dependencies": {
"@shoelace-style/shoelace": "^2.0.0-beta.19",
"core-js": "^3.6.5",
"node-sass": "^4.14.1",
"normalize.css": "^8.0.1",
"sass": "^1.32.8",
"sass-loader": "^10.0.2",
"swrv": "^1.0.0-beta.4",
"vue": "^3.0.0-0",

View File

@ -1,15 +1,22 @@
<template>
<div id="app">
<div class="header"><h1>UpEnd</h1></div>
<router-view />
<header><h1>UpEnd</h1></header>
<main>
<router-view/>
</main>
<footer>
<Jobs/>
</footer>
</div>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import Jobs from "@/components/Jobs.vue";
export default defineComponent({
name: "App"
name: "App",
components: {Jobs}
});
</script>
@ -17,15 +24,24 @@ export default defineComponent({
@import "../node_modules/normalize.css/normalize.css";
@import "../node_modules/@shoelace-style/shoelace/dist/shoelace/shoelace.css";
html, body, #app {
height: calc(100% - 1rem);
}
#app {
font-family: Helvetica, Arial, sans-serif;
color: #2c3e50;
padding: 1rem;
display: flex;
flex-direction: column;
justify-content: space-between;
margin: 1rem;
--monospace-font: "Fira Code", "Consolas", "JetBrains Mono", "Inconsolata", monospace;
}
.header {
header {
box-shadow: var(--sl-shadow-large);
margin-bottom: 1rem;
padding: 1rem;
@ -39,4 +55,8 @@ export default defineComponent({
margin: 0;
}
}
main {
flex-grow: 1;
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<transition-group name="fade">
<div class="job" v-for="job in activeJobs" :key="job.id">
<div class="job-label">{{ job.title }}</div>
<sl-progress-bar :percentage="job.progress">{{ Math.round(job.progress) }}%</sl-progress-bar>
</div>
</transition-group>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import {Job} from "@/types/base";
interface JobWithId extends Job {
id: string;
}
export default defineComponent({
name: "Jobs",
data: () => {
return {
jobs: {} as { [key: string]: Job }
};
},
computed: {
activeJobs(): JobWithId[] {
return Object.entries(this.jobs).filter(([_, job]) => job.progress < 100).map(([id, job]) => {
return {id, ...job};
});
}
},
mounted() {
setInterval(async () => {
let request = await fetch("/api/jobs");
this.jobs = await request.json();
}, 1000);
}
});
</script>
<style scoped lang="scss">
.job {
display: flex;
.job-label {
white-space: nowrap;
margin-right: 2em;
}
sl-progress-bar {
width: 100%;
}
}
</style>
<style lang="scss">
.fade-enter-active,
.fade-leave-active {
transition: all 1s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(30px);
}
</style>

View File

@ -10,3 +10,8 @@ export interface IEntry {
export interface ListingResult {
[key: string]: IEntry
}
export interface Job {
title: string;
progress: number;
}

View File

@ -23,7 +23,7 @@ export default defineComponent({
watch: {
async searchQuery() {
const response = await fetch(
`/api/lookup?${new URLSearchParams({query: this.searchQuery})}`
`/api/obj?${new URLSearchParams({query: `(matches ? ? (contains "${this.searchQuery}"))`})}`
);
this.results = await response.json();
}