|
|
@@ -1,37 +1,39 @@
|
|
|
<template>
|
|
|
- <header>
|
|
|
- <div id="sidebar-button" class="flex-row" @click="toggleSidebar">
|
|
|
- <img src="../../OliveTinLogo.png" alt="OliveTin logo" class="logo" />
|
|
|
-
|
|
|
- <h1 id="page-title">OliveTin</h1>
|
|
|
-
|
|
|
- <div class="fg1" />
|
|
|
- <button id="sidebar-toggler-button" aria-label="Open sidebar navigation" aria-pressed="false" aria-haspopup="menu" class="neutral">
|
|
|
- <HugeiconsIcon :icon="Menu01Icon" width = "1em" height = "1em" />
|
|
|
- </button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div id="banner" v-if="bannerMessage" :style="bannerCss">
|
|
|
- <p>{{ bannerMessage }}</p>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="flex-row" style="gap: .5em;">
|
|
|
- <span id="link-login" v-if="!isLoggedIn"><router-link to="/login">Login</router-link></span>
|
|
|
- <span id="link-logout" v-if="isLoggedIn"><a href="/api/Logout">Logout</a></span>
|
|
|
- <span id="username-text" :title="'Provider: ' + userProvider">{{ username }}</span>
|
|
|
- <HugeiconsIcon :icon="UserCircle02Icon" width = "1.5em" height = "1.5em" />
|
|
|
- </div>
|
|
|
- </header>
|
|
|
+ <Header title="OliveTin" :logoUrl="logoUrl" @toggleSidebar="toggleSidebar">
|
|
|
+ <template #toolbar>
|
|
|
+ <div id="banner" v-if="bannerMessage" :style="bannerCss">
|
|
|
+ <p>{{ bannerMessage }}</p>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template #user-info>
|
|
|
+ <div class="flex-row" style="gap: .5em;">
|
|
|
+ <span id="link-login" v-if="!isLoggedIn"><router-link to="/login">Login</router-link></span>
|
|
|
+ <div v-else>
|
|
|
+ <span id="username-text" :title="'Provider: ' + userProvider">{{ username }}</span>
|
|
|
+ <span id="link-logout" v-if="isLoggedIn"><a href="/api/Logout">Logout</a></span>
|
|
|
+ </div>
|
|
|
+ <HugeiconsIcon :icon="UserCircle02Icon" width = "1.5em" height = "1.5em" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </template>
|
|
|
+ </Header>
|
|
|
|
|
|
<div id="layout">
|
|
|
- <Sidebar ref="sidebar" />
|
|
|
+ <Sidebar ref="sidebar" id = "mainnav" v-if="showNavigation && !initError" />
|
|
|
|
|
|
<div id="content" initial-martial-complete="{{ hasLoaded }}">
|
|
|
<main title="Main content">
|
|
|
- <router-view :key="$route.fullPath" />
|
|
|
+ <section v-if="initError" class="error-container error" style="text-align: center; padding: 2em;">
|
|
|
+ <h2>Failed to Initialize OliveTin</h2>
|
|
|
+ <p><strong>Error Message:</strong> {{ initErrorMessage }}</p>
|
|
|
+ <p>Please check the your browser console first, and then the server logs for more details.</p>
|
|
|
+ <button @click="retryInit" class="bad">Retry</button>
|
|
|
+ </section>
|
|
|
+ <router-view v-else :key="$route.fullPath" />
|
|
|
</main>
|
|
|
|
|
|
- <footer title="footer">
|
|
|
+ <footer title="footer" v-if="showFooter && !initError">
|
|
|
<p>
|
|
|
<img title="application icon" src="../../OliveTinLogo.png" alt="OliveTin logo" height="1em"
|
|
|
class="logo" />
|
|
|
@@ -62,10 +64,12 @@
|
|
|
<script setup>
|
|
|
import { ref, onMounted } from 'vue';
|
|
|
import Sidebar from 'picocrank/vue/components/Sidebar.vue';
|
|
|
+import Header from 'picocrank/vue/components/Header.vue';
|
|
|
import { HugeiconsIcon } from '@hugeicons/vue'
|
|
|
import { Menu01Icon } from '@hugeicons/core-free-icons'
|
|
|
import { UserCircle02Icon } from '@hugeicons/core-free-icons'
|
|
|
import { DashboardSquare01Icon } from '@hugeicons/core-free-icons'
|
|
|
+import logoUrl from '../../OliveTinLogo.png';
|
|
|
|
|
|
const sidebar = ref(null);
|
|
|
const username = ref('guest');
|
|
|
@@ -76,6 +80,12 @@ const currentVersion = ref('?');
|
|
|
const bannerMessage = ref('');
|
|
|
const bannerCss = ref('');
|
|
|
const hasLoaded = ref(false);
|
|
|
+const showFooter = ref(true)
|
|
|
+const showNavigation = ref(true)
|
|
|
+const showLogs = ref(true)
|
|
|
+const showDiagnostics = ref(true)
|
|
|
+const initError = ref(false)
|
|
|
+const initErrorMessage = ref('')
|
|
|
|
|
|
function toggleSidebar() {
|
|
|
sidebar.value.toggle()
|
|
|
@@ -85,37 +95,74 @@ async function requestInit() {
|
|
|
try {
|
|
|
const initResponse = await window.client.init({})
|
|
|
|
|
|
+ window.initResponse = initResponse
|
|
|
+ window.initError = false
|
|
|
+ window.initErrorMessage = ''
|
|
|
+ window.initCompleted = true
|
|
|
+
|
|
|
username.value = initResponse.authenticatedUser
|
|
|
currentVersion.value = initResponse.currentVersion
|
|
|
bannerMessage.value = initResponse.bannerMessage || '';
|
|
|
bannerCss.value = initResponse.bannerCss || '';
|
|
|
-
|
|
|
- sidebar.value.addRouterLink('Actions')
|
|
|
+ showFooter.value = initResponse.showFooter
|
|
|
+ showNavigation.value = initResponse.showNavigation
|
|
|
+ showLogs.value = initResponse.showLogList
|
|
|
+ showDiagnostics.value = initResponse.showDiagnostics
|
|
|
|
|
|
for (const rootDashboard of initResponse.rootDashboards) {
|
|
|
sidebar.value.addNavigationLink({
|
|
|
id: rootDashboard,
|
|
|
name: rootDashboard,
|
|
|
title: rootDashboard,
|
|
|
- path: `/dashboards/${rootDashboard}`,
|
|
|
+ path: rootDashboard === 'Actions' ? '/' : `/dashboards/${rootDashboard}`,
|
|
|
icon: DashboardSquare01Icon,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
sidebar.value.addSeparator()
|
|
|
sidebar.value.addRouterLink('Entities')
|
|
|
- sidebar.value.addRouterLink('Logs')
|
|
|
- sidebar.value.addRouterLink('Diagnostics')
|
|
|
|
|
|
+ if (showLogs.value) {
|
|
|
+ sidebar.value.addRouterLink('Logs')
|
|
|
+ }
|
|
|
+
|
|
|
+ if (showDiagnostics.value) {
|
|
|
+ sidebar.value.addRouterLink('Diagnostics')
|
|
|
+ }
|
|
|
|
|
|
- hasLoaded.value = true;
|
|
|
+ hasLoaded.value = true;
|
|
|
+ initError.value = false;
|
|
|
+
|
|
|
+ // Only start websocket connection after successful init
|
|
|
+ if (window.checkWebsocketConnection) {
|
|
|
+ window.checkWebsocketConnection()
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
console.error("Error initializing client", error)
|
|
|
+ initError.value = true
|
|
|
+ initErrorMessage.value = error.message || 'Failed to connect to OliveTin server'
|
|
|
+ window.initError = true
|
|
|
+ window.initErrorMessage = error.message || 'Failed to connect to OliveTin server'
|
|
|
+ window.initCompleted = false
|
|
|
+ serverConnection.value = 'Disconnected'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function retryInit() {
|
|
|
+ initError.value = false
|
|
|
+ initErrorMessage.value = ''
|
|
|
+ window.initError = false
|
|
|
+ window.initErrorMessage = ''
|
|
|
+ window.initCompleted = false
|
|
|
+ requestInit()
|
|
|
+}
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
serverConnection.value = 'Connected';
|
|
|
+ // Initialize global state
|
|
|
+ window.initError = false
|
|
|
+ window.initErrorMessage = ''
|
|
|
+ window.initCompleted = false
|
|
|
requestInit()
|
|
|
})
|
|
|
</script>
|