Skip to content
4 changes: 4 additions & 0 deletions aas-web-ui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import { onBeforeUnmount, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { usePopupOverlay } from '@/composables/PopupOverlay';
import { useGlobalShortcuts } from '@/composables/shortcuts/useGlobalShortcuts';
import { useInfrastructureStore } from '@/store/InfrastructureStore';
import { useNavigationStore } from '@/store/NavigationStore';

Expand All @@ -32,6 +33,9 @@
const infrastructureStore = useInfrastructureStore();
const navigationStore = useNavigationStore();

// Register global shortcuts
useGlobalShortcuts();

// Popup Overlay
const { isPopupOverlayVisible } = usePopupOverlay();

Expand Down
2 changes: 2 additions & 0 deletions aas-web-ui/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ declare module 'vue' {
CarbonFootprint_v0_9: typeof import('./components/Plugins/Submodels/CarbonFootprint_v0_9.vue')['default']
CarbonFootprint_v1_0: typeof import('./components/Plugins/Submodels/CarbonFootprint_v1_0.vue')['default']
CollectionForm: typeof import('./components/EditorComponents/SubmodelElements/CollectionForm.vue')['default']
CommanderList: typeof import('./components/AASCommander/CommanderList.vue')['default']
CommanderPane: typeof import('./components/AASCommander/CommanderPane.vue')['default']
ComponentConfigPanel: typeof import('./components/AppNavigation/Settings/ComponentConfigPanel.vue')['default']
ComponentVisualization: typeof import('./components/ComponentVisualization.vue')['default']
ConceptDescription: typeof import('./components/UIComponents/ConceptDescription.vue')['default']
Expand Down
66 changes: 66 additions & 0 deletions aas-web-ui/src/components/AASCommander/CommanderPane.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<template>
<v-container fluid class="pa-0 fill-height" style="width: 100%">
<v-card border rounded="lg" class="fill-height d-flex flex-column" style="width: 100%">
<v-card-title>Commander List</v-card-title>
<v-divider></v-divider>
<v-card-text class="flex-grow-1 overflow-auto"></v-card-text>
</v-card>
</v-container>
<!-- Dialog for creating/editing AAS -->
<!-- <AASForm v-model="editDialog" :new-shell="newShell" :aas="aasToEdit"></AASForm> -->
<!-- Dialog for uploading AAS -->
<!-- <UploadAAS v-model="uploadAASDialog"></UploadAAS> -->
<!-- Dialog for deleting AAS -->
<!-- <DeleteAAS v-model="deleteDialog" :aas="aasToDelete" :list-loading-state="listLoading"></DeleteAAS> -->
<!-- Dialog for downloading AAS -->
<!-- <DownloadAAS v-model="downloadAASDialog" :aas="aasToDownload"></DownloadAAS> -->
</template>

<script lang="ts" setup></script>

<style>
.custom-loader {
animation: loader 1s infinite;
display: flex;
}

@-moz-keyframes loader {
from {
transform: rotate(0);
}

to {
transform: rotate(360deg);
}
}

@-webkit-keyframes loader {
from {
transform: rotate(0);
}

to {
transform: rotate(360deg);
}
}

@-o-keyframes loader {
from {
transform: rotate(0);
}

to {
transform: rotate(360deg);
}
}

@keyframes loader {
from {
transform: rotate(0);
}

to {
transform: rotate(360deg);
}
}
</style>
116 changes: 85 additions & 31 deletions aas-web-ui/src/components/AppNavigation/AppNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,78 @@
<!-- Logo in the App Bar -->
<img :src="LogoPath" style="min-height: 42px; max-height: 42px" alt="Logo" />
</v-card>
<v-divider v-if="!isMobile" vertical inset class="ml-6" :class="!isMobile ? '' : ''"></v-divider>
<!-- Home button -->
<v-tooltip v-if="!isMobile" open-delay="600" location="bottom">
<template #activator="{ props }">
<v-btn
icon="mdi-home-outline"
variant="plain"
v-bind="props"
:to="{ name: currentRoute, query: {} }"
class="ml-2">
</v-btn>
</template>
<span>Home</span>
</v-tooltip>
<!-- Menu Toggle (Desktop) -->
<v-menu v-if="!isMobile" v-model="mainMenu" :close-on-content-click="false" :offset="8">
<template #activator="{ props }">
<v-btn class="text-none" v-bind="props" append-icon="mdi-chevron-down" variant="text">
{{ route.meta?.title ? route.meta.title.toString() : route.meta?.name?.toString() }}
</v-btn>
</template>
<!-- Main Menu Component -->
<MainMenu @close-menu="mainMenu = false"></MainMenu>
</v-menu>
<v-btn-group v-if="!isMobile" class="ml-7" density="compact" border>
<v-tooltip open-delay="600" location="bottom">
<template #activator="{ props }">
<v-btn
variant="plain"
style="padding-right: 20px; padding-left: 20px"
icon
v-bind="props"
:to="{ name: currentRoute, query: {} }">
<v-icon size="small">mdi-home-outline</v-icon>
</v-btn>
</template>
<div class="d-flex flex-column align-center">
<div class="d-flex align-center mb-1">
<v-hotkey :keys="homeCombo" variant="elevated" class="mr-2" />
<span>Home</span>
</div>
<span>Clears the current query parameters</span>
</div>
</v-tooltip>
<v-divider vertical inset></v-divider>
<!-- Menu Toggle (Desktop) -->
<v-menu v-model="mainMenu" :close-on-content-click="false" :offset="8">
<template #activator="{ props: menuProps }">
<v-tooltip open-delay="600" location="bottom">
<template #activator="{ props: tooltipProps }">
<v-btn
class="text-none"
v-bind="{ ...tooltipProps, ...menuProps }"
append-icon="mdi-menu-down"
variant="plain"
size="small">
{{
route.meta?.title
? route.meta.title.toString()
: route.meta?.name?.toString()
}}
</v-btn>
</template>
<v-hotkey :keys="navigationMenuCombo" variant="elevated" class="mr-2" />
<span>Navigate to</span>
</v-tooltip>
</template>
<!-- Main Menu Component -->
<MainMenu @close-menu="mainMenu = false"></MainMenu>
</v-menu>
<v-divider vertical inset></v-divider>
<v-tooltip open-delay="600" location="bottom">
<template #activator="{ props }">
<v-btn variant="plain" style="padding-right: 20px; padding-left: 20px" icon v-bind="props">
<v-icon size="small">mdi-console-line</v-icon>
</v-btn>
</template>
<span>
<v-hotkey :keys="commandPaletteCombo" variant="elevated" class="mr-2" />
Command Palette
</span>
</v-tooltip>
</v-btn-group>
<v-spacer></v-spacer>
<AutoSync v-if="showAutoSync"></AutoSync>
<!-- Platform I 4.0 Logo -->
<v-img v-if="!isMobile" src="@/assets/IDTA_Logo_Blue_Web_S.svg" max-width="120px" />
<!-- Menu Toggle (Mobile) -->
<!-- Settings (Desktop) -->
<v-btn-group v-if="!isMobile" density="compact" class="mr-3" border>
<!-- Auto Sync Toggle -->
<AutoSync v-if="showAutoSync"></AutoSync>
<v-divider v-if="showAutoSync" vertical inset></v-divider>
<!-- Settings Menu -->
<Settings></Settings>
</v-btn-group>
<!-- Auto Sync Toggle (Mobile) -->
<AutoSync v-else></AutoSync>
<!-- Settings Dialog (Mobile) -->
<v-dialog v-if="isMobile" v-model="mainMenu" fullscreen :z-index="9993" :transition="false">
<template #activator="{ props }">
<v-btn icon="mdi-cog" v-bind="props" variant="text"></v-btn>
Expand All @@ -59,14 +102,12 @@
<v-divider v-if="endpointConfigAvailable" class="mt-2"></v-divider>
</v-col>
<v-col cols="12" class="text-center">
<!-- Platform I 4.0 Logo -->
<!-- IDTA Logo -->
<v-img src="@/assets/IDTA_Logo_Blue_Web_S.svg" max-width="120px" class="mx-auto" />
</v-col>
</v-row>
</v-card>
</v-dialog>
<!-- Settings Menu -->
<Settings v-if="!isMobile"></Settings>
<!-- Auth Status with user Menu -->
<User v-if="!isMobile" />
</v-row>
Expand All @@ -76,12 +117,18 @@
<Snackbar />

<!-- App Footer -->
<v-footer app class="bg-appBar text-center d-flex flex-column py-0">
<v-footer app class="bg-appBar text-center d-flex py-0">
<v-spacer></v-spacer>
<v-list-item class="px-1">
<v-list-item-title>
<div>{{ new Date().getFullYear() }} — <strong>Eclipse BaSyx™ ©</strong></div>
</v-list-item-title>
</v-list-item>
<v-spacer></v-spacer>
<!-- IDTA Logo -->
<a href="https://industrialdigitaltwin.org/" target="_blank" rel="noopener">
<v-img v-if="!isMobile" src="@/assets/IDTA_Logo_Blue_Web_S.svg" width="80px" class="cursor-pointer" />
</a>
</v-footer>

<!-- left Side Menu with the AAS List -->
Expand Down Expand Up @@ -223,6 +270,12 @@
// Vuetify
const theme = useTheme();

// Platform detection for hotkey
const isMac = computed(() => typeof navigator !== 'undefined' && /macintosh|mac os x/i.test(navigator.userAgent));
const commandPaletteCombo = computed(() => (isMac.value ? 'cmd+k' : 'ctrl+k'));
const homeCombo = computed(() => (isMac.value ? 'cmd+shift+h' : 'ctrl+shift+h'));
const navigationMenuCombo = computed(() => (isMac.value ? '/' : '/'));

// Data
const mainMenu = ref(false); // Variable to show the Main Menu

Expand Down Expand Up @@ -293,6 +346,7 @@
'Visualization',
'AASEditor',
'AASSubmodelViewer',
'AASCommander',
].includes(route.name as string);
});

Expand Down
19 changes: 4 additions & 15 deletions aas-web-ui/src/components/AppNavigation/AutoSync.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,9 @@
<v-btn icon="mdi-autorenew"></v-btn>
</v-badge>
<!-- Desktop Autosync Menu -->
<v-btn v-else class="multiline-button mr-6" variant="outlined">
<div class="text-left">
<p>
<span class="mr-1" :style="statusCheck.state ? 'font-size: 0.75em' : ''">{{ 'Auto Sync:' }}</span>
<span class="text-primary" :style="statusCheck.state ? 'font-size: 0.75em' : ''">{{
autoSync.state ? 'On' : 'Off'
}}</span>
</p>
<p v-if="statusCheck.state" class="mt-n1">
<span class="mr-1" style="font-size: 0.75em">{{ 'Status Check:' }}</span>
<span class="text-primary" style="font-size: 0.75em">{{ statusCheck.state ? 'On' : 'Off' }}</span>
</p>
</div>
<v-icon :style="{ 'margin-left': autoSync.state ? '12.5px' : '6px' }">mdi-chevron-down</v-icon>
<v-btn v-else variant="plain" icon size="small" style="padding-right: 28px; padding-left: 28px">
<v-icon>mdi-autorenew</v-icon>
<v-icon>mdi-menu-down</v-icon>
<v-menu activator="parent" :close-on-content-click="false" width="300px">
<v-list nav class="py-0 bg-navigationMenu" style="border-style: solid; border-width: 1px">
<!-- Switch to activate/deactive auto-sync -->
Expand Down Expand Up @@ -81,6 +70,7 @@
<StatusSwitch></StatusSwitch>
</v-list>
</v-menu>
<v-badge dot :color="autoSync.state ? 'success' : 'rgba(0,0,0,0)'" :offset-x="16" :offset-y="-10"> </v-badge>
</v-btn>
</template>

Expand All @@ -94,7 +84,6 @@
// Computed properties
const isMobile = computed(() => navigationStore.getIsMobile);
const autoSync = computed(() => navigationStore.getAutoSync);
const statusCheck = computed(() => navigationStore.getStatusCheck);

// Checks if the input is smaller than 100ms and sets it to 100ms if it is
function checkMin(e: boolean) {
Expand Down
23 changes: 22 additions & 1 deletion aas-web-ui/src/components/AppNavigation/MainMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@
</v-avatar>
</template>
</v-list-item>
<v-list-item
v-if="currentTab === 'aas'"
class="mt-3 py-2"
nav
:active="false"
:border="isActiveRoutePath('/aascommander')"
subtitle="Norton's Way of Managing AAS"
title="AAS Commander"
:to="isActiveRoutePath('/aascommander') ? '' : '/aascommander'"
@click="closeMenu">
<template #prepend>
<v-avatar color="surface-light" icon="mdi-rocket-launch" rounded>
<v-icon color="medium-emphasis" />
</v-avatar>
</template>
</v-list-item>
<v-list-item
v-if="smViewerEditor && currentTab === 'submodel'"
class="py-2"
Expand Down Expand Up @@ -284,7 +300,12 @@
}

function setTabByRoutePath(): void {
if (isActiveRoutePath('/') || isActiveRoutePath('/aaseditor') || isActiveRoutePath('/aassmviewer')) {
if (
isActiveRoutePath('/') ||
isActiveRoutePath('/aaseditor') ||
isActiveRoutePath('/aassmviewer') ||
isActiveRoutePath('/aascommander')
) {
currentTab.value = 'aas';
} else if (isActiveRoutePath('/smviewer') || isActiveRoutePath('/smeditor') || isActiveRoutePath('/visu')) {
currentTab.value = 'submodel';
Expand Down
5 changes: 4 additions & 1 deletion aas-web-ui/src/components/AppNavigation/Settings.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<template>
<v-menu :close-on-content-click="false" location="bottom">
<template #activator="{ props }">
<v-btn v-bind="props" icon="mdi-cog" class="ml-3"></v-btn>
<v-btn v-bind="props" icon variant="plain" size="small" style="padding-right: 28px; padding-left: 28px">
<v-icon>mdi-cog</v-icon>
<v-icon>mdi-menu-down</v-icon>
</v-btn>
</template>
<v-card
:width="364"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
>
</v-list-item>
<!-- Input Field to set the sync-interval -->
<v-list-item class="py-y0 mt-n3">
<v-list-item class="py-0 mt-n3 mb-3">
<v-text-field
v-model="statusCheck.interval"
density="compact"
Expand Down
2 changes: 2 additions & 0 deletions aas-web-ui/src/components/AppNavigation/User.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<v-btn
v-if="isAuthEnabled"
v-bind="menuProps"
variant="tonal"
size="small"
:icon="isAuthenticated ? 'mdi-account-lock' : 'mdi-lock-remove'"></v-btn>
<v-tooltip v-else text="Authorization Status" location="bottom" :open-delay="600">
<template #activator="{ props: tooltipProps }">
Expand Down
Loading
Loading