openflexure-microscope-server/webapp/src/components/appContent.vue
Richard Bowman 37f6251d41 Eliminate references to old extensions API
Some of these will, in the future, be replaced by the new
API but, for now, the features in question are disabled anyway.
2024-01-03 14:28:31 +00:00

406 lines
11 KiB
Vue

<template>
<div
id="app-content"
class="uk-margin-remove uk-padding-remove uk-height-1-1"
uk-grid
>
<!-- Initialisation modals -->
<calibrationModal
ref="calibrationModal"
:available-plugins="plugins"
@onClose="enterApp()"
></calibrationModal>
<!-- Vertical tab bar -->
<div id="switcher-left-container">
<div
id="switcher-left"
class="uk-flex uk-flex-column uk-padding-remove uk-width-auto uk-height-1-1 uk-text-center"
>
<!-- For each top tab -->
<template v-for="(item, index) in topTabs">
<!-- Render the tab icon -->
<tabIcon
:id="item.id + '-tab-icon'"
:key="item.id + '-tab-icon'"
:tab-i-d="item.id"
:require-connection="true"
:current-tab="currentTab"
:class="item.class"
@set-tab="setTab"
>
<img
v-if="item.iconURL"
style="filter: grayscale(100%);width: 22px;margin-top: 5px;margin-bottom: 8px;"
:src="item.iconURL"
/>
<i v-if="!item.iconURL" class="material-icons">
{{ item.icon }}
</i>
</tabIcon>
<!-- Add a divider if item.divide is true -->
<hr v-if="item.divide" :key="'tab-divider-' + index" />
</template>
<!-- For each plugin tab -->
<tabIcon
v-for="plugin in pluginsGuiList"
:key="plugin.id"
:tab-i-d="plugin.id"
:title="plugin.title"
:require-connection="plugin.requiresConnection"
:current-tab="currentTab"
:click-callback="updatePlugins"
@set-tab="setTab"
>
<i class="material-icons">{{ plugin.icon || "extension" }}</i>
</tabIcon>
<tabIcon
v-for="imjoyTab in imjoyTabs"
:key="imjoyTab.id"
:tab-i-d="'ImJoy-Plugin-' + imjoyTab.id"
:title="imjoyTab.name"
:require-connection="false"
:current-tab="currentTab"
@set-tab="setTab"
>
<img
v-if="imjoyTab.iconURL"
style="filter: grayscale(100%);width: 22px;margin-top: 5px;margin-bottom: 8px;"
:src="imjoyTab.iconURL"
/>
<i v-if="!imjoyTab.iconURL" class="material-icons">
{{ imjoyTab.iconName || "extension" }}
</i>
</tabIcon>
<hr id="extension-tab-divider" />
<!-- For each bottom tab -->
<template v-for="(item, index) in bottomTabs">
<!-- Render the tab icon -->
<tabIcon
:id="item.id + '-tab-icon'"
:key="item.id + '-tab-icon'"
:tab-i-d="item.id"
:require-connection="true"
:current-tab="currentTab"
:class="item.class"
@set-tab="setTab"
>
<i class="material-icons">{{ item.icon }}</i>
</tabIcon>
<!-- Add a divider if item.divide is true -->
<hr v-if="item.divide" :key="'tab-divider-' + index" />
</template>
</div>
</div>
<!-- Corresponding vertical tab content -->
<div
id="container-left"
class="uk-padding-remove uk-height-1-1 uk-width-expand"
>
<!-- For each top tab -->
<tabContent
v-for="item in topTabs"
:id="item.id + '-tab-content'"
:key="item.id + '-tab-content'"
:tab-i-d="item.id"
:require-connection="true"
:current-tab="currentTab"
>
<component :is="item.component"></component>
</tabContent>
<!-- For each plugin tab -->
<tabContent
v-for="plugin in pluginsGuiList"
:key="plugin.id"
:tab-i-d="plugin.id"
:require-connection="plugin.requiresConnection"
:current-tab="currentTab"
>
<extensionContent
:forms="plugin.forms"
:frame="plugin.frame"
:web-component="plugin.wc"
:view-panel="plugin.viewPanel"
@reloadForms="updatePlugins()"
/>
</tabContent>
<tabContent
v-for="imjoyTab in imjoyTabs"
:key="imjoyTab.id"
:tab-i-d="'ImJoy-Plugin-' + imjoyTab.id"
:require-connection="false"
:current-tab="currentTab"
>
<div :id="imjoyTab.window_id" class="window-container">Loading...</div>
</tabContent>
<!-- For each bottom tab -->
<tabContent
v-for="item in bottomTabs"
:id="item.id + '-tab-content'"
:key="item.id + '-tab-content'"
:tab-i-d="item.id"
:require-connection="true"
:current-tab="currentTab"
>
<component :is="item.component"></component>
</tabContent>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
// Import generic components
import tabIcon from "./genericComponents/tabIcon";
import tabContent from "./genericComponents/tabContent";
// Import new content components
import navigateContent from "./tabContentComponents/navigateContent.vue";
import captureContent from "./tabContentComponents/captureContent.vue";
import slideScanContent from "./tabContentComponents/slideScanContent.vue";
import viewContent from "./tabContentComponents/viewContent.vue";
import settingsContent from "./tabContentComponents/settingsContent.vue";
import extensionContent from "./tabContentComponents/extensionContent.vue";
import aboutContent from "./tabContentComponents/aboutContent.vue";
import loggingContent from "./tabContentComponents/loggingContent.vue";
// ImJoy and the gallery are loaded asynchronously to allow them to be disabled if needed
const galleryContent = () =>
import(
/* webpackChunkName: "gallery" */ "./tabContentComponents/galleryContent.vue"
);
const imjoyContent = () =>
import(
/* webpackChunkName: "imjoy" */ "./tabContentComponents/imjoyContent.vue"
);
// Import modal components for device initialisation
import calibrationModal from "./modalComponents/calibrationModal.vue";
import TabIcon from "./genericComponents/tabIcon.vue";
// Export main app
export default {
name: "AppContent",
components: {
tabIcon,
tabContent,
navigateContent,
captureContent,
slideScanContent,
viewContent,
settingsContent,
galleryContent,
extensionContent,
calibrationModal,
aboutContent,
loggingContent,
TabIcon,
imjoyContent
},
data: function() {
return {
plugins: [],
currentTab: "view",
bottomTabs: [
{
id: "settings",
icon: "settings",
component: settingsContent,
class: "uk-margin-auto-top"
},
{
id: "logging",
icon: "assignment_late",
component: loggingContent
},
{
id: "about",
icon: "info",
component: aboutContent
}
]
};
},
computed: {
pluginsGuiList: function() {
// List of plugin GUIs, obtained from this.plugins values
var pluginGuis = [];
for (let plugin of Object.values(this.plugins)) {
if (plugin.meta.gui) {
pluginGuis.push(plugin.meta.gui);
}
}
return pluginGuis;
},
tabOrder: function() {
var ind = [];
for (const tab of this.topTabs) {
ind.push(tab.id);
}
for (const plugin of this.pluginsGuiList) {
ind.push(plugin.id);
}
for (const tab of this.bottomTabs) {
ind.push(tab.id);
}
return ind;
},
topTabs: function() {
let tabs = [
{
id: "view",
icon: "visibility",
component: viewContent
},
/*{
id: "gallery",
icon: "photo_library",
component: galleryContent,
divide: true // Add a divider after this tab icon
},*/
{
id: "navigate",
icon: "gamepad",
component: navigateContent
},
{
id: "slidescan",
icon: "settings_overscan",
component: slideScanContent,
divide: true
}
];
if (!this.$store.state.galleryEnabled) {
tabs = tabs.filter(tab => tab.id != "gallery");
}
if (this.$store.state.imjoyEnabled) {
tabs.push({
id: "imjoy",
iconURL: "https://imjoy.io/static/img/imjoy-icon.svg",
component: imjoyContent,
divide: true
});
}
return tabs;
},
currentTabIndex: function() {
return this.tabOrder.indexOf(this.currentTab);
},
// Map the tabs from ImJoy's store module so we can display them
...mapState("imjoy", { imjoyTabs: "tabs" }),
...mapState({ imjoyEnabled: "imjoyEnabled" })
},
created: function() {
if (this.$store.getters.ready) {
// Update plugins
this.updatePlugins().then(() => {
// Start initialisation modals
this.startModals();
});
}
},
mounted() {
// A global signal listener to switch tab
this.$root.$on("globalSwitchTab", tabID => {
this.currentTab = tabID;
});
// A global signal listener to increment tab
this.$root.$on("globalIncrementTab", () => {
this.incrementTabBy(1);
});
// A global signal listener to decrement tab
this.$root.$on("globalDecrementTab", () => {
this.incrementTabBy(-1);
});
},
methods: {
updatePlugins: function() {
/*return axios
.get(this.pluginsUri)
.then(response => {
this.plugins = response.data;
})
.catch(error => {
this.modalError(error); // Let mixin handle error
});*/
return new Promise(resolve => {
resolve({});
});
},
setTab: function(event, tab) {
if (!(this.currentTab == tab)) {
this.currentTab = tab;
}
},
incrementTabBy: function(n) {
const newIndex =
(((this.currentTabIndex + n) % this.tabOrder.length) +
this.tabOrder.length) %
this.tabOrder.length;
const newId = this.tabOrder[newIndex];
this.currentTab = newId;
},
startModals: function() {
this.$refs["calibrationModal"].show();
},
enterApp: function() {
// Stuff to do once connected and all init modals are finished
}
}
};
</script>
<style scoped lang="less">
.window-container {
width: 100%;
height: 100%;
}
#component-left {
width: 100%;
height: 100%;
}
#container-left {
overflow: auto;
background-color: rgba(180, 180, 180, 0.025);
width: 100%;
height: 100%;
}
#switcher-left {
width: 75px;
padding-top: 2px !important;
}
#switcher-left-container {
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
height: 100%;
background-color: rgba(180, 180, 180, 0.1);
border-width: 0 1px 0 0;
border-style: solid;
border-color: rgba(180, 180, 180, 0.25);
}
#switcher-left a {
padding: 10px 8px;
}
</style>