chore: frontend updates
This commit is contained in:
parent
570c0ba087
commit
7345744e41
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
<title>OliveTin</title>
|
<title>OliveTin</title>
|
||||||
|
|
||||||
<link rel = "stylesheet" type = "text/css" href = "/style.css" />
|
|
||||||
<link rel = "stylesheet" type = "text/css" href = "/theme.css" />
|
<link rel = "stylesheet" type = "text/css" href = "/theme.css" />
|
||||||
<link rel = "stylesheet" href = "node_modules/@xterm/xterm/css/xterm.css" />
|
<link rel = "stylesheet" href = "node_modules/@xterm/xterm/css/xterm.css" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
import 'femtocrank/style.css'
|
import 'femtocrank/style.css'
|
||||||
|
import '/style.css'
|
||||||
|
|
||||||
import { createClient } from '@connectrpc/connect'
|
import { createClient } from '@connectrpc/connect'
|
||||||
import { createConnectTransport } from '@connectrpc/connect-web'
|
import { createConnectTransport } from '@connectrpc/connect-web'
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -11,8 +11,8 @@
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.3.1",
|
"eslint-plugin-promise": "^4.3.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"stylelint": "^15.6.0",
|
"stylelint": "^16.23.1",
|
||||||
"stylelint-config-standard": "^33.0.0"
|
"stylelint-config-standard": "^39.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
@ -27,16 +27,16 @@
|
||||||
],
|
],
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@connectrpc/connect": "^2.0.3",
|
"@connectrpc/connect": "^2.1.0",
|
||||||
"@connectrpc/connect-web": "^2.0.3",
|
"@connectrpc/connect-web": "^2.1.0",
|
||||||
"@hugeicons/core-free-icons": "^1.0.16",
|
"@hugeicons/core-free-icons": "^1.0.16",
|
||||||
"@hugeicons/vue": "^1.0.3",
|
"@hugeicons/vue": "^1.0.3",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"femtocrank": "^1.2.4",
|
"picocrank": "^1.3.1",
|
||||||
"unplugin-vue-components": "^28.8.0",
|
"unplugin-vue-components": "^29.0.0",
|
||||||
"vite": "^7.0.6",
|
"vite": "^7.1.4",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,6 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fg1">
|
|
||||||
<Breadcrumbs />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="banner" v-if="bannerMessage" :style="bannerCss">
|
<div id="banner" v-if="bannerMessage" :style="bannerCss">
|
||||||
<p>{{ bannerMessage }}</p>
|
<p>{{ bannerMessage }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -65,10 +61,11 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import Sidebar from './components/Sidebar.vue';
|
import Sidebar from 'picocrank/vue/components/Sidebar.vue';
|
||||||
import { HugeiconsIcon } from '@hugeicons/vue'
|
import { HugeiconsIcon } from '@hugeicons/vue'
|
||||||
import { Menu01Icon } from '@hugeicons/core-free-icons'
|
import { Menu01Icon } from '@hugeicons/core-free-icons'
|
||||||
import { UserCircle02Icon } from '@hugeicons/core-free-icons'
|
import { UserCircle02Icon } from '@hugeicons/core-free-icons'
|
||||||
|
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
|
||||||
|
|
||||||
const sidebar = ref(null);
|
const sidebar = ref(null);
|
||||||
const username = ref('guest');
|
const username = ref('guest');
|
||||||
|
|
@ -88,22 +85,29 @@ async function requestInit() {
|
||||||
try {
|
try {
|
||||||
const initResponse = await window.client.init({})
|
const initResponse = await window.client.init({})
|
||||||
|
|
||||||
console.log("init response", initResponse)
|
|
||||||
|
|
||||||
username.value = initResponse.authenticatedUser
|
username.value = initResponse.authenticatedUser
|
||||||
currentVersion.value = initResponse.currentVersion
|
currentVersion.value = initResponse.currentVersion
|
||||||
bannerMessage.value = initResponse.bannerMessage || '';
|
bannerMessage.value = initResponse.bannerMessage || '';
|
||||||
bannerCss.value = initResponse.bannerCss || '';
|
bannerCss.value = initResponse.bannerCss || '';
|
||||||
|
|
||||||
|
sidebar.value.addRouterLink('Actions')
|
||||||
|
|
||||||
for (const rootDashboard of initResponse.rootDashboards) {
|
for (const rootDashboard of initResponse.rootDashboards) {
|
||||||
sidebar.value.addNavigationLink({
|
sidebar.value.addNavigationLink({
|
||||||
id: rootDashboard,
|
id: rootDashboard,
|
||||||
|
name: rootDashboard,
|
||||||
title: rootDashboard,
|
title: rootDashboard,
|
||||||
path: `/dashboards/${rootDashboard}`,
|
path: `/dashboards/${rootDashboard}`,
|
||||||
icon: '📊'
|
icon: DashboardSquare01Icon,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sidebar.value.addSeparator()
|
||||||
|
sidebar.value.addRouterLink('Entities')
|
||||||
|
sidebar.value.addRouterLink('Logs')
|
||||||
|
sidebar.value.addRouterLink('Diagnostics')
|
||||||
|
|
||||||
|
|
||||||
hasLoaded.value = true;
|
hasLoaded.value = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error initializing client", error)
|
console.error("Error initializing client", error)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ const props = defineProps({
|
||||||
const dashboard = ref(null)
|
const dashboard = ref(null)
|
||||||
|
|
||||||
async function getDashboard() {
|
async function getDashboard() {
|
||||||
console.log("getting dashboard", props.title)
|
|
||||||
const ret = await window.client.getDashboard({
|
const ret = await window.client.getDashboard({
|
||||||
title: props.title,
|
title: props.title,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,246 +0,0 @@
|
||||||
<template>
|
|
||||||
<aside :class="{ 'shown': isOpen, 'stuck': isStuck }" class="sidebar">
|
|
||||||
<div class = "flex-row">
|
|
||||||
<h2>Navigation</h2>
|
|
||||||
<div class = "fg1" />
|
|
||||||
<button
|
|
||||||
class="stick-toggle"
|
|
||||||
:aria-pressed="isStuck"
|
|
||||||
:title="isStuck ? 'Unstick sidebar' : 'Stick sidebar'"
|
|
||||||
@click="toggleStick"
|
|
||||||
>
|
|
||||||
<span v-if="isStuck">
|
|
||||||
<HugeiconsIcon :icon="Pin02Icon" width = "1em" height = "1em" />
|
|
||||||
</span>
|
|
||||||
<span v-else>
|
|
||||||
<HugeiconsIcon :icon="PinIcon" width = "1em" height = "1em" />
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="mainnav">
|
|
||||||
<ul class="navigation-links">
|
|
||||||
<li v-for="link in navigationLinks" :key="link.id" :title="link.title">
|
|
||||||
<router-link :to="link.path" :class="{ active: isActive(link.path) }">
|
|
||||||
<HugeiconsIcon :icon="link.icon" />
|
|
||||||
<span>{{ link.title }}</span>
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="supplemental-links">
|
|
||||||
<li v-for="link in supplementalLinks" :key="link.id" :title="link.title">
|
|
||||||
<router-link :to="link.path" :class="{ active: isActive(link.path) }">
|
|
||||||
<HugeiconsIcon :icon="link.icon" />
|
|
||||||
<span>{{ link.title }}</span>
|
|
||||||
</router-link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, onMounted, getCurrentInstance } from 'vue'
|
|
||||||
import { useRoute } from 'vue-router'
|
|
||||||
import { HugeiconsIcon } from '@hugeicons/vue'
|
|
||||||
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
|
|
||||||
import { LeftToRightListDashIcon } from '@hugeicons/core-free-icons'
|
|
||||||
import { Wrench01Icon } from '@hugeicons/core-free-icons'
|
|
||||||
import { Pin02Icon } from '@hugeicons/core-free-icons'
|
|
||||||
import { PinIcon } from '@hugeicons/core-free-icons'
|
|
||||||
import { CellsIcon } from '@hugeicons/core-free-icons'
|
|
||||||
|
|
||||||
const isOpen = ref(false)
|
|
||||||
const isStuck = ref(false)
|
|
||||||
const navigationLinks = ref([
|
|
||||||
{
|
|
||||||
id: 'actions',
|
|
||||||
title: 'Actions',
|
|
||||||
path: '/',
|
|
||||||
icon: DashboardSquare01Icon,
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
const supplementalLinks = ref([
|
|
||||||
{
|
|
||||||
id: 'entities',
|
|
||||||
title: 'Entities',
|
|
||||||
path: '/entities',
|
|
||||||
icon: CellsIcon,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'logs',
|
|
||||||
title: 'Logs',
|
|
||||||
path: '/logs',
|
|
||||||
icon: LeftToRightListDashIcon,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'diagnostics',
|
|
||||||
title: 'Diagnostics',
|
|
||||||
path: '/diagnostics',
|
|
||||||
icon: Wrench01Icon,
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
function toggleStick() {
|
|
||||||
isStuck.value = !isStuck.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
isOpen.value = !isOpen.value
|
|
||||||
isStuck.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
isOpen.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
isOpen.value = false
|
|
||||||
isStuck.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function isActive(path) {
|
|
||||||
return route.path === path
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to add navigation links from other components
|
|
||||||
function addNavigationLink(link) {
|
|
||||||
link.icon = DashboardSquare01Icon
|
|
||||||
|
|
||||||
const existingIndex = navigationLinks.value.findIndex(l => l.id === link.id)
|
|
||||||
if (existingIndex >= 0) {
|
|
||||||
navigationLinks.value[existingIndex] = { ...link }
|
|
||||||
} else {
|
|
||||||
navigationLinks.value.push({ ...link })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to add supplemental links from other components
|
|
||||||
function addSupplementalLink(link) {
|
|
||||||
const existingIndex = supplementalLinks.value.findIndex(l => l.id === link.id)
|
|
||||||
if (existingIndex >= 0) {
|
|
||||||
supplementalLinks.value[existingIndex] = { ...link }
|
|
||||||
} else {
|
|
||||||
supplementalLinks.value.push({ ...link })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to remove links
|
|
||||||
function removeNavigationLink(linkId) {
|
|
||||||
navigationLinks.value = navigationLinks.value.filter(link => link.id !== linkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeSupplementalLink(linkId) {
|
|
||||||
supplementalLinks.value = supplementalLinks.value.filter(link => link.id !== linkId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to clear all links
|
|
||||||
function clearNavigationLinks() {
|
|
||||||
navigationLinks.value = []
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearSupplementalLinks() {
|
|
||||||
supplementalLinks.value = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to get all links
|
|
||||||
function getNavigationLinks() {
|
|
||||||
return [...navigationLinks.value]
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSupplementalLinks() {
|
|
||||||
return [...supplementalLinks.value]
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// Make the sidebar globally accessible
|
|
||||||
window.sidebar = {
|
|
||||||
get isOpen() { return isOpen.value },
|
|
||||||
set isOpen(val) { isOpen.value = val },
|
|
||||||
toggle,
|
|
||||||
open,
|
|
||||||
close,
|
|
||||||
addNavigationLink,
|
|
||||||
addSupplementalLink,
|
|
||||||
removeNavigationLink,
|
|
||||||
removeSupplementalLink,
|
|
||||||
clearNavigationLinks,
|
|
||||||
clearSupplementalLinks,
|
|
||||||
getNavigationLinks,
|
|
||||||
getSupplementalLinks
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
isOpen,
|
|
||||||
navigationLinks,
|
|
||||||
supplementalLinks,
|
|
||||||
toggle,
|
|
||||||
open,
|
|
||||||
close,
|
|
||||||
isActive,
|
|
||||||
addNavigationLink,
|
|
||||||
addSupplementalLink,
|
|
||||||
removeNavigationLink,
|
|
||||||
removeSupplementalLink,
|
|
||||||
clearNavigationLinks,
|
|
||||||
clearSupplementalLinks,
|
|
||||||
getNavigationLinks,
|
|
||||||
getSupplementalLinks
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
.active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.navigation-links a,
|
|
||||||
.supplemental-links a {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
color: #333;
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
border-left: 3px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navigation-links a:hover,
|
|
||||||
.supplemental-links a:hover {
|
|
||||||
background: #f8f9fa;
|
|
||||||
color: #007bff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
font-size: 1.2em;
|
|
||||||
width: 1.5rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.supplemental-links {
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive design */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.sidebar {
|
|
||||||
width: 100%;
|
|
||||||
left: -100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar.shown {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
|
||||||
|
import { Wrench01Icon } from '@hugeicons/core-free-icons'
|
||||||
|
import { LeftToRightListDashIcon } from '@hugeicons/core-free-icons'
|
||||||
|
import { CellsIcon } from '@hugeicons/core-free-icons'
|
||||||
|
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Home',
|
name: 'Actions',
|
||||||
component: () => import('./Dashboard.vue'),
|
component: () => import('./Dashboard.vue'),
|
||||||
props: { title: 'default' },
|
props: { title: 'default' },
|
||||||
meta: { title: 'OliveTin - Dashboard' }
|
meta: { title: 'Actions', icon: DashboardSquare01Icon }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/dashboards/:title',
|
path: '/dashboards/:title',
|
||||||
|
|
@ -26,13 +31,19 @@ const routes = [
|
||||||
path: '/logs',
|
path: '/logs',
|
||||||
name: 'Logs',
|
name: 'Logs',
|
||||||
component: () => import('./views/LogsListView.vue'),
|
component: () => import('./views/LogsListView.vue'),
|
||||||
meta: { title: 'OliveTin - Logs' }
|
meta: {
|
||||||
|
title: 'OliveTin - Logs',
|
||||||
|
icon: LeftToRightListDashIcon
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/entities',
|
path: '/entities',
|
||||||
name: 'Entities',
|
name: 'Entities',
|
||||||
component: () => import('./views/EntitiesView.vue'),
|
component: () => import('./views/EntitiesView.vue'),
|
||||||
meta: { title: 'OliveTin - Entities' }
|
meta: {
|
||||||
|
title: 'OliveTin - Entities',
|
||||||
|
icon: CellsIcon
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/entity-details/:entityType/:entityKey',
|
path: '/entity-details/:entityType/:entityKey',
|
||||||
|
|
@ -64,7 +75,10 @@ const routes = [
|
||||||
path: '/diagnostics',
|
path: '/diagnostics',
|
||||||
name: 'Diagnostics',
|
name: 'Diagnostics',
|
||||||
component: () => import('./views/DiagnosticsView.vue'),
|
component: () => import('./views/DiagnosticsView.vue'),
|
||||||
meta: { title: 'OliveTin - Diagnostics' }
|
meta: {
|
||||||
|
title: 'OliveTin - Diagnostics',
|
||||||
|
icon: Wrench01Icon
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<Section title = "Get support">
|
||||||
<div class="section-header">
|
<p>If you are having problems with OliveTin and want to raise a support request, it would be very helpful to include a sosreport from this page.
|
||||||
<h2>Get support</h2>
|
</p>
|
||||||
</div>
|
<ul>
|
||||||
<div class="section-content">
|
<li>
|
||||||
<p>If you are having problems with OliveTin and want to raise a support request, it would be very helpful to include a sosreport from this page.
|
<a href="https://docs.olivetin.app/sosreport.html" target="_blank">sosreport Documentation</a>
|
||||||
</p>
|
</li>
|
||||||
<ul>
|
<li>
|
||||||
<li>
|
<a href = "https://docs.olivetin.app/troubleshooting/wheretofindhelp.html" target="_blank">Where to find help</a>
|
||||||
<a href="https://docs.olivetin.app/sosreport.html" target="_blank">sosreport Documentation</a>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
<li>
|
</Section>
|
||||||
<a href = "https://docs.olivetin.app/troubleshooting/wheretofindhelp.html" target="_blank">Where to find help</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
<Section title = "SSH">
|
||||||
<div class="section-header">
|
<dl>
|
||||||
<h2>SSH</h2>
|
<dt>Found Key</dt>
|
||||||
</div>
|
<dd>{{ diagnostics.sshFoundKey || '?' }}</dd>
|
||||||
<div class="section-content">
|
<dt>Found Config</dt>
|
||||||
<dl>
|
<dd>{{ diagnostics.sshFoundConfig || '?' }}</dd>
|
||||||
<dt>Found Key</dt>
|
</dl>
|
||||||
<dd>{{ diagnostics.sshFoundKey || '?' }}</dd>
|
</Section>
|
||||||
<dt>Found Config</dt>
|
|
||||||
<dd>{{ diagnostics.sshFoundConfig || '?' }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
<Section title = "SOS Report">
|
||||||
<div class="section-header">
|
<p>This section allows you to generate a detailed report of your configuration and environment. It is a good idea to include this when raising a support request.</p>
|
||||||
<h2>SOS Report</h2>
|
|
||||||
|
<div role="toolbar">
|
||||||
|
<button @click="generateSosReport" :disabled="loading" class = "good">Generate SOS Report</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-content">
|
|
||||||
|
|
||||||
<p>This section allows you to generate a detailed report of your configuration and environment. It is a good idea to include this when raising a support request.</p>
|
<textarea v-model="sosReport" readonly style="flex: 1; min-height: 200px; resize: vertical;"></textarea>
|
||||||
|
</Section>
|
||||||
<div role="toolbar">
|
|
||||||
<button @click="generateSosReport" :disabled="loading" class = "good">Generate SOS Report</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<textarea v-model="sosReport" readonly style="flex: 1; min-height: 200px; resize: vertical;"></textarea>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
import Section from 'picocrank/vue/components/Section.vue'
|
||||||
|
|
||||||
const diagnostics = ref({})
|
const diagnostics = ref({})
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<section class = "with-header-and-content" v-if="entityDefinitions.length === 0">
|
<Section class = "with-header-and-content" v-if="entityDefinitions.length === 0" title="Loading entity definitions...">
|
||||||
<div class = "section-header">
|
<div class = "section-header">
|
||||||
<h2 class="loading-message">
|
<h2 class="loading-message">
|
||||||
Loading entity definitions...
|
Loading entity definitions...
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</Section>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<section v-for="def in entityDefinitions" :key="def.name" class="with-header-and-content">
|
<Section v-for="def in entityDefinitions" :key="def.name" :title="'Entity: ' + def.title ">
|
||||||
<div class = "section-header">
|
|
||||||
<h2>Entity: {{ def.title }}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class = "section-content">
|
<div class = "section-content">
|
||||||
<p>{{ def.instances.length }} instances.</p>
|
<p>{{ def.instances.length }} instances.</p>
|
||||||
|
|
||||||
|
|
@ -32,12 +28,13 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</Section>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
import Section from 'picocrank/vue/components/Section.vue'
|
||||||
|
|
||||||
const entityDefinitions = ref([])
|
const entityDefinitions = ref([])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="with-header-and-content">
|
<Section title="Entity Details">
|
||||||
<div class="section-header">
|
<div>
|
||||||
<h2>Entity Details</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section-content">
|
|
||||||
<p v-if="!entityDetails">Loading entity details...</p>
|
<p v-if="!entityDetails">Loading entity details...</p>
|
||||||
<p v-else-if="!entityDetails.title">No details available for this entity.</p>
|
<p v-else-if="!entityDetails.title">No details available for this entity.</p>
|
||||||
<p v-else>{{ entityDetails.title }}</p>
|
<p v-else>{{ entityDetails.title }}</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</Section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
import Section from 'picocrank/vue/components/Section.vue'
|
||||||
|
|
||||||
const entityDetails = ref(null)
|
const entityDetails = ref(null)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="with-header-and-content">
|
<Section :title="'Execution Results: ' + title">
|
||||||
<div class="section-header">
|
<template #toolbar>
|
||||||
<h2>Execution Results: {{ title }}</h2>
|
|
||||||
|
|
||||||
<button @click="toggleSize" title="Toggle dialog size">
|
<button @click="toggleSize" title="Toggle dialog size">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||||||
<path fill="currentColor"
|
<path fill="currentColor"
|
||||||
d="M3 3h6v2H6.462l4.843 4.843l-1.415 1.414L5 6.367V9H3zm0 18h6v-2H6.376l4.929-4.928l-1.415-1.414L5 17.548V15H3zm12 0h6v-6h-2v2.524l-4.867-4.866l-1.414 1.414L17.647 19H15zm6-18h-6v2h2.562l-4.843 4.843l1.414 1.414L19 6.39V9h2z" />
|
d="M3 3h6v2H6.462l4.843 4.843l-1.415 1.414L5 6.367V9H3zm0 18h6v-2H6.376l4.929-4.928l-1.415-1.414L5 17.548V15H3zm12 0h6v-6h-2v2.524l-4.867-4.866l-1.414 1.414L17.647 19H15zm6-18h-6v2h2.562l-4.843 4.843l1.414 1.414L19 6.39V9h2z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
</div>
|
<div v-if="logEntry" class = "flex-row">
|
||||||
<div class="section-content">
|
<dl class = "fg1">
|
||||||
<div v-if="logEntry">
|
|
||||||
<div class="action-header padded-content" style="float: right">
|
|
||||||
<span class="icon" role="img" v-html="icon"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>Duration</dt>
|
<dt>Duration</dt>
|
||||||
<dd><span v-html="duration"></span></dd>
|
<dd><span v-html="duration"></span></dd>
|
||||||
|
|
||||||
|
|
@ -26,9 +19,10 @@
|
||||||
<ActionStatusDisplay :log-entry="logEntry" />
|
<ActionStatusDisplay :log-entry="logEntry" />
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
<span class="icon" role="img" v-html="icon" style = "align-self: start"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div ref="xtermOutput"></div>
|
<div ref="xtermOutput"></div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
@ -49,13 +43,14 @@
|
||||||
Kill
|
Kill
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</section>
|
</Section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
|
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||||
import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
|
import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
|
||||||
|
import Section from 'picocrank/vue/components/Section.vue'
|
||||||
import { OutputTerminal } from '../../../js/OutputTerminal.js'
|
import { OutputTerminal } from '../../../js/OutputTerminal.js'
|
||||||
import { HugeiconsIcon } from '@hugeicons/vue'
|
import { HugeiconsIcon } from '@hugeicons/vue'
|
||||||
import { WorkoutRunIcon, Cancel02Icon, ArrowLeftIcon } from '@hugeicons/core-free-icons'
|
import { WorkoutRunIcon, Cancel02Icon, ArrowLeftIcon } from '@hugeicons/core-free-icons'
|
||||||
|
|
@ -66,7 +61,6 @@ const router = useRouter()
|
||||||
|
|
||||||
// Refs for DOM elements
|
// Refs for DOM elements
|
||||||
const xtermOutput = ref(null)
|
const xtermOutput = ref(null)
|
||||||
const dialog = ref(null)
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
executionTrackingId: {
|
executionTrackingId: {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<Section title="Logs" :padding="false">
|
||||||
<div class="section-header">
|
<template #toolbar>
|
||||||
<h2>Logs</h2>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="input-with-icons">
|
<label class="input-with-icons">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||||||
<path fill="currentColor"
|
<path fill="currentColor"
|
||||||
|
|
@ -17,12 +14,9 @@
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
</div>
|
<p class = "padding">This is a list of logs from actions that have been executed. You can filter the list by action title.</p>
|
||||||
|
|
||||||
<div class="section-content">
|
|
||||||
<p>This is a list of logs from actions that have been executed. You can filter the list by action title.</p>
|
|
||||||
<div v-show="filteredLogs.length > 0">
|
<div v-show="filteredLogs.length > 0">
|
||||||
<table class="logs-table">
|
<table class="logs-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -60,7 +54,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" @page-change="handlePageChange"
|
<Pagination :pageSize="pageSize" :total="totalCount" :currentPage="currentPage" @page-change="handlePageChange" class = "padding"
|
||||||
@page-size-change="handlePageSizeChange" itemTitle="execution logs" />
|
@page-size-change="handlePageSizeChange" itemTitle="execution logs" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -68,13 +62,13 @@
|
||||||
<p>There are no logs to display.</p>
|
<p>There are no logs to display.</p>
|
||||||
<router-link to="/">Return to index</router-link>
|
<router-link to="/">Return to index</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Section>
|
||||||
</section>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import Pagination from '../components/Pagination.vue'
|
import Pagination from '../components/Pagination.vue'
|
||||||
|
import Section from 'picocrank/vue/components/Section.vue'
|
||||||
|
|
||||||
const logs = ref([])
|
const logs = ref([])
|
||||||
const searchText = ref('')
|
const searchText = ref('')
|
||||||
|
|
|
||||||
|
|
@ -92,10 +92,6 @@ div.buttons button svg {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
section .section-content {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
font-size: small;
|
font-size: small;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue