Rework app configure to use custom tab and content view
This commit is contained in:
@@ -7,7 +7,7 @@ const i18n = useI18n();
|
||||
const t = i18n.t;
|
||||
|
||||
import { ref, onMounted, onBeforeUnmount, useTemplateRef, computed } from 'vue';
|
||||
import { Button, ButtonGroup, TabView } from 'pankow';
|
||||
import { Button, ButtonGroup } from 'pankow';
|
||||
import Info from '../components/app/Info.vue';
|
||||
import Security from '../components/app/Security.vue';
|
||||
import Cron from '../components/app/Cron.vue';
|
||||
@@ -19,28 +19,9 @@ import { APP_TYPES } from '../constants.js';
|
||||
|
||||
const appsModel = AppsModel.create();
|
||||
|
||||
const tabView = useTemplateRef('tabView');
|
||||
const tabs = ref({
|
||||
info: t('app.infoTabTitle'),
|
||||
display: t('app.displayTabTitle'),
|
||||
location: t('app.locationTabTitle'),
|
||||
proxy: 'Proxy',
|
||||
access: t('app.accessControlTabTitle'),
|
||||
resources: t('app.resourcesTabTitle'),
|
||||
services: t('app.servicesTabTitle'),
|
||||
storage: t('app.storageTabTitle'),
|
||||
graphs: t('app.graphsTabTitle'),
|
||||
security: t('app.securityTabTitle'),
|
||||
email: t('app.emailTabTitle'),
|
||||
cron: t('app.cronTabTitle'),
|
||||
updates: t('app.updatesTabTitle'),
|
||||
backups: t('app.backupsTabTitle'),
|
||||
repair: t('app.repairTabTitle'),
|
||||
eventlog: t('app.eventlogTabTitle'),
|
||||
uninstall: t('app.uninstallTabTitle'),
|
||||
});
|
||||
const id = ref('');
|
||||
const app = ref({});
|
||||
const view = ref('');
|
||||
const link = ref('');
|
||||
const infoMenu = ref([]);
|
||||
const hasLocalStorage = ref(false);
|
||||
@@ -49,8 +30,9 @@ const isAppStopped = computed(() => {
|
||||
return appsModel.isStopped(app.value);
|
||||
});
|
||||
|
||||
function onTabChanged(tab) {
|
||||
window.location.hash = `/app/${id.value}/${tab}`;
|
||||
function onSetView(newView) {
|
||||
view.value = newView;
|
||||
window.location.hash = `/app/${id.value}/${newView}`;
|
||||
}
|
||||
|
||||
async function onToggleRunState() {
|
||||
@@ -134,7 +116,7 @@ onMounted(async () => {
|
||||
|
||||
await refresh();
|
||||
|
||||
tabView.value.open(parts[1] || 'info');
|
||||
onSetView(parts[1] || 'info');
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -144,62 +126,117 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="titlebar">
|
||||
<div style="display: flex;">
|
||||
<img :src="API_ORIGIN + app.iconUrl" v-fallback-image="API_ORIGIN + '/img/appicon_fallback.png'" style="width: 64px; margin-right: 10px;"/>
|
||||
<h2>{{ app.label || app.fqdn }}</h2>
|
||||
<div class="configure-outer">
|
||||
<div class="configure-inner">
|
||||
<div class="titlebar">
|
||||
<div style="display: flex;">
|
||||
<img :src="API_ORIGIN + app.iconUrl" v-fallback-image="API_ORIGIN + '/img/appicon_fallback.png'" style="width: 64px; margin-right: 10px;"/>
|
||||
<h2>{{ app.label || app.fqdn }}</h2>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<Button outline tool
|
||||
@click="onToggleRunState()"
|
||||
:disabled="app.taskId || app.error || app.installationState === 'pending_start' || app.installationState === 'pending_stop'"
|
||||
v-tooltip="$t(isAppStopped ? 'app.uninstall.startStop.startAction' : 'app.uninstall.startStop.stopAction')"
|
||||
:loading="app.installationState === 'pending_start' || app.installationState === 'pending_stop'"
|
||||
:icon="isAppStopped ? 'fa-solid fa-play' : 'fa-solid fa-power-off'"
|
||||
/>
|
||||
<ButtonGroup>
|
||||
<Button outline tool :href="`/logs.html?appId=${app.id}`" target="_blank" v-tooltip="$t('app.logsActionTooltip')" icon="fa-solid fa-align-left" />
|
||||
<Button outline tool v-if="app.type !== APP_TYPES.PROXIED" :href="`/terminal.html?id=${app.id}`" target="_blank" v-tooltip="$t('app.terminalActionTooltip')" icon="fa fa-terminal" />
|
||||
<Button outline tool v-if="hasLocalStorage" :href="`/filemanager.html#/home/app/${app.id}`" target="_blank" v-tooltip="$t('app.filemanagerActionTooltip')" icon="fas fa-folder" />
|
||||
</ButtonGroup>
|
||||
|
||||
<Button outline tool icon="fa-solid fa-book" v-tooltip="$t('app.docsActionTooltip')" :menu="infoMenu" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<Button outline tool
|
||||
@click="onToggleRunState()"
|
||||
:disabled="app.taskId || app.error || app.installationState === 'pending_start' || app.installationState === 'pending_stop'"
|
||||
v-tooltip="$t(isAppStopped ? 'app.uninstall.startStop.startAction' : 'app.uninstall.startStop.stopAction')"
|
||||
:loading="app.installationState === 'pending_start' || app.installationState === 'pending_stop'"
|
||||
:icon="isAppStopped ? 'fa-solid fa-play' : 'fa-solid fa-power-off'"
|
||||
/>
|
||||
<ButtonGroup>
|
||||
<Button outline tool :href="`/logs.html?appId=${app.id}`" target="_blank" v-tooltip="$t('app.logsActionTooltip')" icon="fa-solid fa-align-left" />
|
||||
<Button outline tool v-if="app.type !== APP_TYPES.PROXIED" :href="`/terminal.html?id=${app.id}`" target="_blank" v-tooltip="$t('app.terminalActionTooltip')" icon="fa fa-terminal" />
|
||||
<Button outline tool v-if="hasLocalStorage" :href="`/filemanager.html#/home/app/${app.id}`" target="_blank" v-tooltip="$t('app.filemanagerActionTooltip')" icon="fas fa-folder" />
|
||||
</ButtonGroup>
|
||||
|
||||
<Button outline tool icon="fa-solid fa-book" v-tooltip="$t('app.docsActionTooltip')" :menu="infoMenu" />
|
||||
<div class="configure-body">
|
||||
<div class="configure-menu">
|
||||
<div class="configure-menu-item" @click="onSetView('info')" :active="view === 'info' ? true : null">{{ $t('app.infoTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('display')" :active="view === 'display' ? true : null">{{ $t('app.displayTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('location')" :active="view === 'location' ? true : null">{{ $t('app.locationTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('proxy')" :active="view === 'proxy' ? true : null">Proxy</div>
|
||||
<div class="configure-menu-item" @click="onSetView('access')" :active="view === 'access' ? true : null">{{ $t('app.accessControlTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('resources')" :active="view === 'resources' ? true : null">{{ $t('app.resourcesTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('services')" :active="view === 'services' ? true : null">{{ $t('app.servicesTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('storage')" :active="view === 'storage' ? true : null">{{ $t('app.storageTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('graphs')" :active="view === 'graphs' ? true : null">{{ $t('app.graphsTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('security')" :active="view === 'security' ? true : null">{{ $t('app.securityTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('email')" :active="view === 'email' ? true : null">{{ $t('app.emailTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('cron')" :active="view === 'cron' ? true : null">{{ $t('app.cronTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('updates')" :active="view === 'updates' ? true : null">{{ $t('app.updatesTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('backups')" :active="view === 'backups' ? true : null">{{ $t('app.backupsTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('repair')" :active="view === 'repair' ? true : null">{{ $t('app.repairTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('eventlog')" :active="view === 'eventlog' ? true : null">{{ $t('app.eventlogTabTitle') }}</div>
|
||||
<div class="configure-menu-item" @click="onSetView('uninstall')" :active="view === 'uninstall' ? true : null">{{ $t('app.uninstallTabTitle') }}</div>
|
||||
</div>
|
||||
<div class="configure-content">
|
||||
<Info v-if="view === 'info'" :app="app"/>
|
||||
<div v-if="view === 'display'"></div>
|
||||
<div v-if="view === 'location'"></div>
|
||||
<div v-if="view === 'proxy'"></div>
|
||||
<div v-if="view === 'access'"></div>
|
||||
<div v-if="view === 'resources'"></div>
|
||||
<div v-if="view === 'services'"></div>
|
||||
<div v-if="view === 'storage'"></div>
|
||||
<div v-if="view === 'graphs'"></div>
|
||||
<Security :app="app" v-if="view === 'security'"/>
|
||||
<div v-if="view === 'email'"></div>
|
||||
<Cron :app="app" v-if="view === 'cron'"/>
|
||||
<Updates :app="app" v-if="view === 'updates'"/>
|
||||
<div v-if="view === 'backups'"></div>
|
||||
<div v-if="view === 'repair'"></div>
|
||||
<Eventlog :app="app" v-if="view === 'eventlog'"/>
|
||||
<Uninstall :app="app" v-if="view === 'uninstall'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TabView ref="tabView" :tabs="tabs" @changed="onTabChanged" tab-position="left">
|
||||
<template #info><Info :app="app"/></template>
|
||||
<template #display></template>
|
||||
<template #location></template>
|
||||
<template #proxy></template>
|
||||
<template #access></template>
|
||||
<template #resources></template>
|
||||
<template #services></template>
|
||||
<template #storage></template>
|
||||
<template #graphs></template>
|
||||
<template #security><Security :app="app"/></template>
|
||||
<template #email></template>
|
||||
<template #cron><Cron :app="app"/></template>
|
||||
<template #updates><Updates :app="app"/></template>
|
||||
<template #backups></template>
|
||||
<template #repair></template>
|
||||
<template #eventlog><Eventlog :app="app"/></template>
|
||||
<template #uninstall><Uninstall :app="app"/></template>
|
||||
</TabView>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.configure-outer {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.configure-inner {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.titlebar {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
justify-content: space-between;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: var(--pankow-body-background-color);
|
||||
}
|
||||
|
||||
.configure-body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.configure-menu-item {
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
padding: 4px 60px 4px 0;
|
||||
}
|
||||
|
||||
.configure-menu-item[active] {
|
||||
color: var(--pankow-color-primary-active);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.configure-menu-item:hover {
|
||||
color: var(--pankow-color-primary-hover);
|
||||
}
|
||||
|
||||
.configure-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user