Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions aas-web-ui/public/config/basyx-infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
# The configuration will be loaded at application startup and merged with user settings.
# When VITE_ENDPOINT_CONFIG_AVAILABLE=false, this configuration takes full precedence.
# When VITE_ENDPOINT_CONFIG_AVAILABLE=true, users can edit these infrastructures.
# Optional component flags:
# - hasRegistryIntegration: Backend repository creates/updates/deletes descriptors automatically.
# - hasDiscoveryIntegration: Backend AAS registry creates/updates/deletes discovery asset links automatically.

infrastructures:
# Specify which infrastructure should be selected by default
Expand All @@ -21,12 +24,15 @@ infrastructures:
baseUrl: "http://localhost:9084"
aasRegistry:
baseUrl: "http://localhost:9082"
hasDiscoveryIntegration: true
submodelRegistry:
baseUrl: "http://localhost:9083"
aasRepository:
baseUrl: "http://localhost:9081"
hasRegistryIntegration: true
submodelRepository:
baseUrl: "http://localhost:9081"
hasRegistryIntegration: true
conceptDescriptionRepository:
baseUrl: "http://localhost:9081"
security:
Expand Down
53 changes: 52 additions & 1 deletion aas-web-ui/src/components/AppNavigation/DeleteAAS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@
</template>

<script lang="ts" setup>
import { ref, watch } from 'vue';
import { computed, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useAASHandling } from '@/composables/AAS/AASHandling';
import { useSMHandling } from '@/composables/AAS/SMHandling';
import { useAASDiscoveryClient } from '@/composables/Client/AASDiscoveryClient';
import { useAASRegistryClient } from '@/composables/Client/AASRegistryClient';
import { useSMRegistryClient } from '@/composables/Client/SMRegistryClient';
import { useAASStore } from '@/store/AASDataStore';
import { useInfrastructureStore } from '@/store/InfrastructureStore';
import { useNavigationStore } from '@/store/NavigationStore';

// Vue Router
Expand All @@ -50,11 +54,15 @@

// Stores
const aasStore = useAASStore();
const infrastructureStore = useInfrastructureStore();
const navigationStore = useNavigationStore();

// Composables
const { deleteAasById, getSubmodelRefsById } = useAASHandling();
const { deleteSmById, fetchSmById } = useSMHandling();
const { deleteAasDescriptor } = useAASRegistryClient();
const { deleteSubmodelDescriptor } = useSMRegistryClient();
const { deleteAssetLinksForAas } = useAASDiscoveryClient();

const props = defineProps<{
modelValue: boolean;
Expand All @@ -72,6 +80,17 @@
const submodelIds = ref<any[]>([]); // Variable to store the Submodel Ids of the AAS
const selected = ref<string[]>([]); // Variable to store the selected Submodel Ids

const selectedInfrastructure = computed(() => infrastructureStore.getSelectedInfrastructure);
const aasRepoHasRegistryIntegration = computed(
() => selectedInfrastructure.value?.components?.AASRepo?.hasRegistryIntegration ?? true
);
const submodelRepoHasRegistryIntegration = computed(
() => selectedInfrastructure.value?.components?.SubmodelRepo?.hasRegistryIntegration ?? true
);
const aasRegistryHasDiscoveryIntegration = computed(
() => selectedInfrastructure.value?.components?.AASRegistry?.hasDiscoveryIntegration ?? true
);

watch(
() => props.modelValue,
async (value) => {
Expand Down Expand Up @@ -107,17 +126,38 @@
async function confirmDelete(): Promise<void> {
deleteLoading.value = true;
let error = false;
const warnings: string[] = [];
try {
if (deleteSubmodels.value) {
// Extract all references in an array called submodelIds from each keys[0].value
const submodelIds = selected.value;
// Remove each submodel
for (const submodelId of submodelIds) {
error = error || !(await deleteSmById(submodelId));
if (!error && !submodelRepoHasRegistryIntegration.value) {
const descriptorDeleted = await deleteSubmodelDescriptor(submodelId);
if (!descriptorDeleted) {
warnings.push(`Failed to delete Submodel descriptor '${submodelId}'.`);
}
}
}
}

error = error || !(await removeAAS(props.aas));

if (!error && !aasRepoHasRegistryIntegration.value) {
const descriptorDeleted = await deleteAasDescriptor(props.aas.id);
if (!descriptorDeleted) {
warnings.push(`Failed to delete AAS descriptor '${props.aas.id}'.`);
}
}

if (!error && !aasRegistryHasDiscoveryIntegration.value) {
const assetLinksDeleted = await deleteAssetLinksForAas(props.aas.id);
if (!assetLinksDeleted) {
warnings.push(`Failed to delete discovery asset links for '${props.aas.id}'.`);
}
}
} finally {
deleteDialog.value = false;
deleteSubmodels.value = false;
Expand All @@ -134,6 +174,17 @@
}
navigationStore.dispatchTriggerAASListReload(); // Reload AAS List
}

if (warnings.length > 0) {
navigationStore.dispatchSnackbar({
status: true,
timeout: 9000,
color: 'warning',
btnColor: 'buttonText',
baseError: 'Delete completed with synchronization warnings.',
extendedError: warnings.join('\n'),
});
}
deleteLoading.value = false;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,71 @@
<template>
<v-container class="pa-0">
<v-text-field
v-for="componentKey in BASYX_COMPONENT_KEYS"
:key="componentKey"
:name="`basyx-${componentKey}-endpoint`"
:model-value="components[componentKey].url"
:label="getComponentLabel(componentKey) + ' Endpoint URL'"
variant="outlined"
density="compact"
placeholder="https://example.com/api"
autocomplete="url"
class="mb-2"
@update:model-value="handleUrlUpdate(componentKey, $event)"
@keyup.enter="$emit('test-connection', componentKey)">
<template #prepend-inner>
<v-icon
:color="
componentConnectionStatus[componentKey] === true
? 'success'
: componentConnectionStatus[componentKey] === false
? 'error'
: components[componentKey].url
? 'grey'
: 'grey'
"
size="small">
{{
componentConnectionStatus[componentKey] === true
? 'mdi-check-circle'
: componentConnectionStatus[componentKey] === false
? 'mdi-alert-circle'
: components[componentKey].url
? 'mdi-help-circle'
: 'mdi-circle-outline'
}}
</v-icon>
</template>
<template #append-inner>
<v-btn
icon
size="x-small"
variant="text"
:loading="componentTestingLoading[componentKey]"
:disabled="!components[componentKey].url"
@click.stop="$emit('test-connection', componentKey)">
<v-icon>mdi-connection</v-icon>
<v-tooltip activator="parent" location="bottom"> Test Connection </v-tooltip>
</v-btn>
</template>
</v-text-field>
<div v-for="componentKey in BASYX_COMPONENT_KEYS" :key="componentKey" class="mb-2">
<v-text-field
:name="`basyx-${componentKey}-endpoint`"
:model-value="components[componentKey].url"
:label="getComponentLabel(componentKey) + ' Endpoint URL'"
variant="outlined"
density="compact"
placeholder="https://example.com/api"
autocomplete="url"
@update:model-value="handleUrlUpdate(componentKey, $event)"
@keyup.enter="$emit('test-connection', componentKey)">
<template #prepend-inner>
<v-icon
:color="
componentConnectionStatus[componentKey] === true
? 'success'
: componentConnectionStatus[componentKey] === false
? 'error'
: components[componentKey].url
? 'grey'
: 'grey'
"
size="small">
{{
componentConnectionStatus[componentKey] === true
? 'mdi-check-circle'
: componentConnectionStatus[componentKey] === false
? 'mdi-alert-circle'
: components[componentKey].url
? 'mdi-help-circle'
: 'mdi-circle-outline'
}}
</v-icon>
</template>
<template #append-inner>
<v-btn
icon
size="x-small"
variant="text"
:loading="componentTestingLoading[componentKey]"
:disabled="!components[componentKey].url"
@click.stop="$emit('test-connection', componentKey)">
<v-icon>mdi-connection</v-icon>
<v-tooltip activator="parent" location="bottom"> Test Connection </v-tooltip>
</v-btn>
</template>
</v-text-field>

<v-checkbox
v-if="componentKey === 'AASRepo' || componentKey === 'SubmodelRepo'"
:model-value="components[componentKey].hasRegistryIntegration ?? true"
label="Backend creates descriptors automatically"
hide-details
density="compact"
class="mt-n1 mb-1"
@update:model-value="handleRegistryIntegrationUpdate(componentKey, $event)" />

<v-checkbox
v-if="componentKey === 'AASRegistry'"
:model-value="components[componentKey].hasDiscoveryIntegration ?? true"
label="Backend creates AAS discovery asset links automatically"
hide-details
density="compact"
class="mt-n1 mb-1"
@update:model-value="handleDiscoveryIntegrationUpdate(componentKey, $event)" />
</div>
</v-container>
</template>

Expand All @@ -73,10 +90,20 @@
'test-connection': [componentKey: BaSyxComponentKey];
'update:componentUrl': [componentKey: BaSyxComponentKey, url: string];
'update:connectionStatus': [componentKey: BaSyxComponentKey, status: boolean | null];
'update:registryIntegration': [componentKey: BaSyxComponentKey, enabled: boolean];
'update:discoveryIntegration': [componentKey: BaSyxComponentKey, enabled: boolean];
}>();

function handleUrlUpdate(componentKey: BaSyxComponentKey, url: string): void {
emit('update:componentUrl', componentKey, url);
emit('update:connectionStatus', componentKey, null);
}

function handleRegistryIntegrationUpdate(componentKey: BaSyxComponentKey, value: boolean | null): void {
emit('update:registryIntegration', componentKey, Boolean(value));
}

function handleDiscoveryIntegrationUpdate(componentKey: BaSyxComponentKey, value: boolean | null): void {
emit('update:discoveryIntegration', componentKey, Boolean(value));
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@
:component-testing-loading="componentTestingLoading"
@test-connection="testComponentConnection"
@update:component-url="handleComponentUrlUpdate"
@update:connection-status="handleConnectionStatusUpdate" />
@update:connection-status="handleConnectionStatusUpdate"
@update:registry-integration="handleRegistryIntegrationUpdate"
@update:discovery-integration="handleDiscoveryIntegrationUpdate" />
<!-- Security Configuration -->
<v-divider></v-divider>
<v-list-subheader class="mb-3">Security Configuration</v-list-subheader>
Expand Down Expand Up @@ -368,4 +370,12 @@
function handleConnectionStatusUpdate(componentKey: BaSyxComponentKey, status: boolean | null): void {
componentConnectionStatus.value[componentKey] = status;
}

function handleRegistryIntegrationUpdate(componentKey: BaSyxComponentKey, enabled: boolean): void {
editingInfrastructure.value.components[componentKey].hasRegistryIntegration = enabled;
}

function handleDiscoveryIntegrationUpdate(componentKey: BaSyxComponentKey, enabled: boolean): void {
editingInfrastructure.value.components[componentKey].hasDiscoveryIntegration = enabled;
}
</script>
Loading
Loading