diff --git a/aas-web-ui/entrypoint.sh b/aas-web-ui/entrypoint.sh index 895862b..e06d7e7 100644 --- a/aas-web-ui/entrypoint.sh +++ b/aas-web-ui/entrypoint.sh @@ -78,6 +78,14 @@ if [ -n "$ENDPOINT_CONFIG_AVAILABLE" ]; then jq '.endpointConfigAvailable = env.ENDPOINT_CONFIG_AVAILABLE' /usr/src/app/dist/config.json > /tmp/config.json && mv /tmp/config.json /usr/src/app/dist/config.json fi +if [ -n "$SINGLE_AAS" ]; then + jq '.singleAas = env.SINGLE_AAS' /usr/src/app/dist/config.json > /tmp/config.json && mv /tmp/config.json /usr/src/app/dist/config.json +fi + +if [ -n "$SINGLE_AAS_REDIRECT" ]; then + jq '.singleAasRedirect = env.SINGLE_AAS_REDIRECT' /usr/src/app/dist/config.json > /tmp/config.json && mv /tmp/config.json /usr/src/app/dist/config.json +fi + if [ -n "$BASE_PATH" ]; then echo "=====================" echo "BASE_PATH: $BASE_PATH" diff --git a/aas-web-ui/public/config.json b/aas-web-ui/public/config.json index 2569163..12672d7 100644 --- a/aas-web-ui/public/config.json +++ b/aas-web-ui/public/config.json @@ -15,5 +15,7 @@ "keycloakUrl": "", "keycloakRealm": "", "keycloakClientId": "", - "endpointConfigAvailable": true + "endpointConfigAvailable": true, + "singleAas": false, + "singleAasRedirect": "" } diff --git a/aas-web-ui/src/App.vue b/aas-web-ui/src/App.vue index fcc6d46..8317a29 100644 --- a/aas-web-ui/src/App.vue +++ b/aas-web-ui/src/App.vue @@ -20,17 +20,9 @@ import RequestHandling from '@/mixins/RequestHandling'; import SubmodelElementHandling from '@/mixins/SubmodelElementHandling'; import { useAASStore } from '@/store/AASDataStore'; + import { useEnvStore } from '@/store/EnvironmentStore'; import { useNavigationStore } from '@/store/NavigationStore'; - interface AASType { - endpoints: Array<{ - protocolInformation: { - href: string; - }; - interface: string; - }>; - } - export default defineComponent({ name: 'App', components: { @@ -46,16 +38,18 @@ const aasStore = useAASStore(); const route = useRoute(); const router = useRouter(); + const envStore = useEnvStore(); return { navigationStore, // NavigationStore Object aasStore, // AASStore Object route, // Route Object router, // Router Object + envStore, // EnvironmentStore Object }; }, - mounted() { + async mounted() { let mobile = this.$vuetify.display.mobile; // include IPad as mobile device if (this.$vuetify.display.platform.mac && this.$vuetify.display.platform.touch) { @@ -76,6 +70,20 @@ const aasEndpoint = searchParams.get('aas'); const submodelElementPath = searchParams.get('path'); + // Ensure available aasEndpoint query parameter + if ( + this.envStore.singleAas && + (aasEndpoint === null || aasEndpoint === undefined || aasEndpoint.trim() === '') + ) { + if (this.envStore.getSingleAasRedirect) { + window.location.replace(this.envStore.getSingleAasRedirect); + return; + } else if (this.route.name !== '404NotFound404') { + this.router.push({ name: 'NotFound404' }); + return; + } + } + // check which platform is used and change the fitting view if (mobile) { if (this.route.name === 'MainWindow') { @@ -117,12 +125,7 @@ if (aasEndpoint) { // console.log('AAS Query is set: ', aasEndpoint); - let aas = {} as AASType; - let endpoints = []; - endpoints.push({ protocolInformation: { href: aasEndpoint }, interface: 'AAS-3.0' }); - aas.endpoints = endpoints; - // dispatch the AAS set by the URL to the store - this.aasStore.dispatchSelectedAAS(aas); + await this.fetchAndDispatchAas(aasEndpoint); } if (aasEndpoint && submodelElementPath) { @@ -142,7 +145,7 @@ this.aasStore.dispatchNode(response.data); // set the updatedNode in the AASStore } else { // execute if the Request failed - if (Object.keys(response.data).length == 0) { + if (response?.data && Object.keys(response?.data).length === 0) { // don't copy the static SubmodelElement Data if no Node is selected or Node is invalid this.navigationStore.dispatchSnackbar({ status: true, diff --git a/aas-web-ui/src/UserPlugins/HelloWorldPlugin.vue b/aas-web-ui/src/UserPlugins/HelloWorldPlugin.vue index 261086f..0341e6a 100644 --- a/aas-web-ui/src/UserPlugins/HelloWorldPlugin.vue +++ b/aas-web-ui/src/UserPlugins/HelloWorldPlugin.vue @@ -65,7 +65,7 @@ methods: { // Function to initialize the HelloWorld-Plugin initializePlugin() { - if (Object.keys(this.submodelElementData).length == 0) { + if (Object.keys(this.submodelElementData).length === 0) { this.pluginData = {}; // Reset the Plugin Data when no Node is selected return; } diff --git a/aas-web-ui/src/components/AASTreeview.vue b/aas-web-ui/src/components/AASTreeview.vue index 6c8695e..0247367 100644 --- a/aas-web-ui/src/components/AASTreeview.vue +++ b/aas-web-ui/src/components/AASTreeview.vue @@ -7,9 +7,9 @@ AAS Treeview - + {{ - 'AAS: ' + nameToDisplay(SelectedAAS) + 'AAS: ' + nameToDisplay(selectedAAS) }} @@ -29,14 +29,20 @@ - - + @@ -81,15 +87,10 @@ computed: { // get selected AAS from Store - SelectedAAS() { + selectedAAS() { return this.aasStore.getSelectedAAS; }, - // get the trigger for AAS selection from Store - triggerAAS() { - return this.navigationStore.getTriggerAASSelected; - }, - // gets loading State from Store loading() { return this.aasStore.getLoadingState; @@ -116,8 +117,7 @@ }, watch: { - // initialize Treeview when AAS gets selected - triggerAAS() { + selectedAAS() { this.initializeTree(); }, @@ -154,74 +154,32 @@ }, methods: { - // Function to get the Submodels from the selected AAS (retrieved from the AAS with the provided endpoint) - initializeTree() { - // console.log('Initialize Treeview', this.initialUpdate, this.initialNode); + async initializeTree() { + // console.log('Initialize Treeview', this.SelectedAAS, this.initialUpdate, this.initialNode); // return if no endpoints are available - if (!this.SelectedAAS || !this.SelectedAAS.endpoints || this.SelectedAAS.endpoints.length === 0) { - // TODO: this seems to get executed on reload with a selected AAS + if (!this.selectedAAS || !this.selectedAAS.endpoints || this.selectedAAS.endpoints.length === 0) { // this.navigationStore.dispatchSnackbar({ status: true, timeout: 4000, color: 'error', btnColor: 'buttonText', text: 'AAS with no (valid) Endpoint selected!' }); this.submodelData = []; return; } if (this.loading && !this.initialUpdate) return; // return if loading state is true -> prevents multiple requests this.aasStore.dispatchLoadingState(true); // set loading state to true - this.submodelData = []; // reset Treeview Data - // retrieve AAS from endpoint - const shellHref = this.extractEndpointHref(this.selectedAAS, 'AAS-3.0'); - let path = shellHref; - let context = 'retrieving AAS Data'; - let disableMessage = false; - this.getRequest(path, context, disableMessage) - .then(async (response: any) => { - if (response.success) { - // execute if the Request was successful - try { - let AAS = response.data; - AAS.endpoints = this.SelectedAAS.endpoints; - this.aasStore.dispatchSelectedAAS(AAS); // dispatch the selected AAS to the Store - if (!AAS.submodels) { - throw new Error('No Submodels found in AAS!'); - } - // request submodels from the retrieved AAS (top layer of the Treeview) - let submodelData = await this.requestSubmodels(AAS.submodels); - // set the isActive prop of the initialNode if it exists and the initialUpdate flag is set - if (this.initialUpdate && this.initialNode) { - let expandedSubmodelData = this.expandTree(submodelData, this.initialNode); // Update the Treeview to expand until the initially set node is reached - // this.updateNode(this.initialNode); // set the isActive prop of the initialNode to true - this.initialUpdate = false; - this.initialNode = {}; - // console.log('Expanded Treeview Data: ', expandedSubmodelData) - this.submodelData = expandedSubmodelData; // set the Treeview Data - } else { - this.submodelData = submodelData; // set the Treeview Data - // console.log('Treeview Data: ', this.submodelData) - } - } catch (error: any) { - // console.error('Error while parsing the Submodel References: ', error); - const errorMessage = error.message; - const errorStack = error.stack; - const errorLocation = errorStack ? errorStack.split('\n')[1] : ''; - this.navigationStore.dispatchSnackbar({ - status: true, - timeout: 60000, - color: 'error', - btnColor: 'buttonText', - baseError: 'Error while parsing the Submodel References!', - extendedError: `Error: ${errorMessage}\nLocation: ${errorLocation.trim()}`, - }); - } finally { - this.aasStore.dispatchLoadingState(false); - } - } else { - // execute if the Request failed - this.submodelData = []; - this.aasStore.dispatchLoadingState(false); - } - }) - .catch(() => { - this.aasStore.dispatchLoadingState(false); - }); + if (this.selectedAAS.submodels) { + let submodelData = await this.requestSubmodels(this.selectedAAS.submodels); + // set the isActive prop of the initialNode if it exists and the initialUpdate flag is set + if (this.initialUpdate && this.initialNode) { + let expandedSubmodelData = this.expandTree(submodelData, this.initialNode); // Update the Treeview to expand until the initially set node is reached + // this.updateNode(this.initialNode); // set the isActive prop of the initialNode to true + this.initialUpdate = false; + this.initialNode = {}; + this.submodelData = expandedSubmodelData; + } else { + this.submodelData = submodelData; + } + } else { + this.submodelData = []; + } + this.aasStore.dispatchLoadingState(false); }, // Function to request all Submodels for the selected AAS @@ -231,8 +189,9 @@ // retrieve endpoint for submodel from submodel registry // console.log('SubmodelRef: ', submodelRef, ' Submodel Registry: ', this.submodelRegistryServerURL); // check if submodelRegistryURL includes "/submodel-descriptors" and add id if not (backward compatibility) - if (!this.submodelRegistryURL.includes('/submodel-descriptors')) { - this.submodelRegistryURL += '/submodel-descriptors'; + let submodelRegistryURL = this.submodelRegistryURL; + if (!submodelRegistryURL.includes('/submodel-descriptors')) { + submodelRegistryURL += '/submodel-descriptors'; } const submodelId = submodelRef.keys[0].value; let path = this.submodelRegistryURL + '/' + this.URLEncode(submodelId); @@ -439,9 +398,9 @@ // Function to initialize the treeview with route params initTreeWithRouteParams() { - // check if the SelectedAAS is already set in the Store and initialize the Treeview if so - if (this.SelectedAAS && this.SelectedAAS.endpoints && this.SelectedAAS.endpoints.length > 0) { - // console.log('init Tree from Route Params: ', this.SelectedAAS); + // check if the selectedAAS is already set in the Store and initialize the Treeview if so + if (this.selectedAAS && this.selectedAAS.endpoints && this.selectedAAS.endpoints.length > 0) { + // console.log('init Tree from Route Params: ', this.selectedAAS); this.initializeTree(); } diff --git a/aas-web-ui/src/components/AppNavigation/AASList.vue b/aas-web-ui/src/components/AppNavigation/AASList.vue index 337bdd6..3474a6d 100644 --- a/aas-web-ui/src/components/AppNavigation/AASList.vue +++ b/aas-web-ui/src/components/AppNavigation/AASList.vue @@ -1,11 +1,11 @@