diff --git a/.vscode/launch.json b/.vscode/launch.json
index 08fa19c2..712806dc 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -28,7 +28,7 @@
"CONTENT_ROOT": "projects/aas-server/build",
"WEB_ROOT": "projects/aas-portal/dist",
"ASSETS": "projects/aas-server/src/assets",
- "USER_STORAGE": "mongodb://localhost:27017/aasportal-users",
+ // "USER_STORAGE": "mongodb://localhost:27017/aasportal-users",
// "TEMPLATE_STORAGE": "http://localhost:8080/templates",
// "AAS_INDEX": "mysql://localhost:3306",
"ENDPOINTS": "[\"file:///endpoints/samples?name=Samples\"]",
diff --git a/package-lock.json b/package-lock.json
index 2b0b33d0..3d6a4dbe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "aas-portal-project",
- "version": "3.0.0-development.17",
+ "version": "3.0.0-development.22",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "aas-portal-project",
- "version": "3.0.0-development.17",
+ "version": "3.0.0-development.22",
"license": "Apache-2.0",
"workspaces": [
"./projects/common",
@@ -29275,6 +29275,7 @@
"tsoa": "^6.0.0",
"tsyringe": "^4.8.0",
"uuid": "^8.3.2",
+ "webdav": "^4.10.0",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1",
"ws": "^8.16.0",
@@ -34949,6 +34950,7 @@
"tsoa": "^6.0.0",
"tsyringe": "^4.8.0",
"uuid": "^8.3.2",
+ "webdav": "^4.10.0",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1",
"ws": "^8.16.0",
diff --git a/projects/aas-lib/src/lib/aas-table/aas-table.component.html b/projects/aas-lib/src/lib/aas-table/aas-table.component.html
index 5c519244..21ffa59d 100644
--- a/projects/aas-lib/src/lib/aas-table/aas-table.component.html
+++ b/projects/aas-lib/src/lib/aas-table/aas-table.component.html
@@ -72,70 +72,71 @@
}
- } @else {
-
+} @else {
+
-
-
-
- |
-
- COLUMN_NAME
- |
-
- COLUMN_ID
- |
-
-
-
- @for (row of rows | async; track row) {
-
+
+
+
+ |
+
+ COLUMN_NAME
+ |
+
+ COLUMN_ID
+ |
+
+
+
+ @for (row of rows | async; track row) {
+
-
- |
-
+ |
+
-
- @if (!row.isLeaf && !row.expanded && row.hasChildren) {
-
-
-
-
-
- }
- @if (!row.isLeaf && !row.expanded && !row.hasChildren) {
-
-
-
- }
- @if (!row.isLeaf && row.expanded) {
-
-
-
-
-
- }
- @if (row.isLeaf) {
+
+ @if (row.isLeaf) {
- }
-
+ }@else {
+ @if (row.expanded) {
+
+
+
+
+
+ }@else {
+ @if (row.hasChildren) {
+
+
+
+
+
+ }@else {
+
+
+
+ }
+ }
+ }
+
-
-
+
+
+
- |
-
+ |
+
{{row.endpoint}}
{{row.id | max:80}}
- |
-
- }
-
-
- }
+
+
+ }
+
+
+ }
diff --git a/projects/aas-lib/src/lib/aas-table/aas-table.effects.ts b/projects/aas-lib/src/lib/aas-table/aas-table.effects.ts
index f30ed6ad..11740689 100644
--- a/projects/aas-lib/src/lib/aas-table/aas-table.effects.ts
+++ b/projects/aas-lib/src/lib/aas-table/aas-table.effects.ts
@@ -53,10 +53,10 @@ export class AASTableEffects {
const rows = documents.map(document => {
const row = map.get(`${document.endpoint}:${document.id}`);
if (row) {
- return row.document === document ? row : this.cloneD(row, document);
+ return row.document === document ? row : this.cloneWithNewDocument(row, document);
}
- return new AASTableRow(document, false, false, false, -1, -1, -1);
+ return new AASTableRow(document, -1, false, false, false, false, -1, -1, -1);
});
return rows;
@@ -69,7 +69,7 @@ export class AASTableEffects {
documents.forEach(document => {
const row = map.get(`${document.endpoint}:${document.id}`);
if (row) {
- rows.push(row.document === document ? row : this.cloneD(row, document));
+ rows.push(row.document === document ? row : this.cloneWithNewDocument(row, document));
} else {
nodes.push(document);
}
@@ -89,6 +89,8 @@ export class AASTableEffects {
const children = nodes.filter(node => this.isChild(root, node));
const rootRow = new AASTableRow(
root,
+ -1,
+ false,
false,
false,
children.length === 0,
@@ -115,7 +117,17 @@ export class AASTableEffects {
let previous: AASTableRow | null = null;
const children = nodes.filter(node => this.isChild(parent, node));
for (const child of children) {
- const row = new AASTableRow(child, false, false, children.length === 0, level, -1, -1);
+ const row = new AASTableRow(
+ child,
+ rows.length - 1,
+ false,
+ false,
+ false,
+ children.length === 0,
+ level,
+ -1,
+ -1,
+ );
rows.push(row);
if (previous) {
@@ -142,8 +154,10 @@ export class AASTableEffects {
private clone(row: AASTableRow): AASTableRow {
return new AASTableRow(
row.document,
+ row.parent,
row.selected,
row.expanded,
+ row.highlighted,
row.isLeaf,
row.level,
row.firstChild,
@@ -151,11 +165,13 @@ export class AASTableEffects {
);
}
- private cloneD(row: AASTableRow, document: AASDocument): AASTableRow {
+ private cloneWithNewDocument(row: AASTableRow, document: AASDocument): AASTableRow {
return new AASTableRow(
document,
+ row.parent,
row.selected,
row.expanded,
+ row.highlighted,
row.isLeaf,
row.level,
row.firstChild,
diff --git a/projects/aas-lib/src/lib/aas-table/aas-table.reducer.ts b/projects/aas-lib/src/lib/aas-table/aas-table.reducer.ts
index 3749b5c3..f08d0e00 100644
--- a/projects/aas-lib/src/lib/aas-table/aas-table.reducer.ts
+++ b/projects/aas-lib/src/lib/aas-table/aas-table.reducer.ts
@@ -9,7 +9,7 @@
import { createReducer, on } from '@ngrx/store';
import { AASDocument } from 'common';
import * as AASTableActions from './aas-table.actions';
-import { AASTableRow, AASTableState } from './aas-table.state';
+import { AASTableRow, AASTableState, AASTableTree } from './aas-table.state';
import { ViewMode } from '../types/view-mode';
const initialState: AASTableState = {
@@ -34,110 +34,39 @@ export const aasTableReducer = createReducer(
function setViewMode(state: AASTableState, viewMode: ViewMode): AASTableState {
return state.viewMode !== viewMode ? { ...state, rows: [], viewMode } : state;
}
+
function setRows(state: AASTableState, rows: AASTableRow[]): AASTableState {
return { ...state, rows };
}
function setSelections(state: AASTableState, documents: AASDocument[]): AASTableState {
- const rows = [...state.rows];
- const set = new Set(documents);
- for (let i = 0, n = rows.length; i < n; i++) {
- const row = rows[i];
- if (!row.selected && set.has(row.document)) {
- rows[i] = clone(row, true);
- } else if (row.selected) {
- rows[i] = clone(row, false);
- }
- }
-
- return { ...state, rows };
+ const tree = new AASTableTree(state.rows);
+ tree.selectedElements = documents;
+ return { ...state, rows: tree.nodes };
}
function toggleSelected(state: AASTableState, row: AASTableRow, altKey: boolean, shiftKey: boolean): AASTableState {
- let rows: AASTableRow[];
- if (altKey) {
- rows = state.rows.map(item =>
- item === row ? clone(row, !row.selected) : item.selected ? clone(item, false) : item,
- );
- } else if (shiftKey) {
- const index = state.rows.indexOf(row);
- let begin = index;
- let end = index;
- const selection = state.rows.map(row => row.selected);
- const last = selection.lastIndexOf(true);
- if (last >= 0) {
- if (last > index) {
- begin = index;
- end = selection.indexOf(true);
- } else if (last < index) {
- begin = last;
- end = index;
- }
- }
-
- rows = [];
- for (let i = 0, n = state.rows.length; i < n; i++) {
- const row = state.rows[i];
- if (i < begin || i > end) {
- rows.push(row.selected ? clone(row, false) : row);
- } else {
- rows.push(row.selected ? row : clone(row, true));
- }
- }
- } else {
- const i = state.rows.indexOf(row);
- rows = [...state.rows];
- rows[i] = clone(row, !row.selected);
- }
-
- return { ...state, rows };
+ const tree = new AASTableTree(state.rows);
+ tree.toggleSelected(row, altKey, shiftKey);
+ return { ...state, rows: tree.nodes };
}
function toggleSelections(state: AASTableState): AASTableState {
- const rows = [...state.rows];
- if (rows.length > 0) {
- const value = !rows.every(row => row.selected);
- for (let index = 0, n = rows.length; index < n; ++index) {
- const row = rows[index];
- if (row.selected !== value) {
- rows[index] = clone(row, value);
- }
- }
- }
-
- return { ...state, rows };
-}
-
-function clone(row: AASTableRow, selected?: boolean): AASTableRow {
- if (selected === undefined) {
- selected = row.selected;
- }
-
- return new AASTableRow(
- row.document,
- selected,
- row.expanded,
- row.isLeaf,
- row.level,
- row.firstChild,
- row.nextSibling,
- );
+ const tree = new AASTableTree(state.rows);
+ tree.toggleSelections();
+ return { ...state, rows: tree.nodes };
}
function expandRow(state: AASTableState, row: AASTableRow): AASTableState {
- const rows = [...state.rows];
- const index = rows.indexOf(row);
- rows[index] = new AASTableRow(row.document, false, true, row.isLeaf, row.level, row.firstChild, row.nextSibling);
-
- return { ...state, rows };
+ const tree = new AASTableTree(state.rows);
+ tree.expand(row);
+ return { ...state, rows: tree.nodes };
}
function collapseRow(state: AASTableState, row: AASTableRow): AASTableState {
- const rows = [...state.rows];
- const index = rows.indexOf(row);
- rows[index] = new AASTableRow(row.document, false, false, row.isLeaf, row.level, row.firstChild, row.nextSibling);
-
- return { ...state, rows };
+ const tree = new AASTableTree(state.rows);
+ tree.collapse(row);
+ return { ...state, rows: tree.nodes };
}
function setFilter(state: AASTableState, filter?: string): AASTableState {
diff --git a/projects/aas-lib/src/lib/aas-table/aas-table.state.ts b/projects/aas-lib/src/lib/aas-table/aas-table.state.ts
index a3479ac6..4cb79bf2 100644
--- a/projects/aas-lib/src/lib/aas-table/aas-table.state.ts
+++ b/projects/aas-lib/src/lib/aas-table/aas-table.state.ts
@@ -8,17 +8,22 @@
import { AASDocument } from 'common';
import { ViewMode } from '../types/view-mode';
+import { Tree, TreeNode } from '../tree';
-export class AASTableRow {
+export class AASTableRow extends TreeNode {
public constructor(
public readonly document: AASDocument,
- public readonly selected: boolean,
- public readonly expanded: boolean,
+ parent: number,
+ selected: boolean,
+ expanded: boolean,
+ highlighted: boolean,
public readonly isLeaf: boolean,
- public readonly level: number,
- public firstChild: number,
- public nextSibling: number,
- ) {}
+ level: number,
+ firstChild: number,
+ nextSibling: number,
+ ) {
+ super(document, parent, level, expanded, selected, highlighted, firstChild, nextSibling);
+ }
public get id(): string {
return this.document.id;
@@ -36,10 +41,6 @@ export class AASTableRow {
return this.document.endpoint;
}
- public get hasChildren(): boolean {
- return this.firstChild >= 0;
- }
-
public get state(): 'loaded' | 'unloaded' | 'unavailable' {
if (this.document.content === null) {
return 'unloaded';
@@ -51,38 +52,41 @@ export class AASTableRow {
return 'unavailable';
}
+}
- public getChildren(rows: AASTableRow[]): AASTableRow[] {
- const children: AASTableRow[] = [];
- if (this.firstChild >= 0) {
- let child = rows[this.firstChild];
- children.push(child);
- while (child.nextSibling >= 0) {
- child = rows[child.nextSibling];
- children.push(child);
- }
- }
+export class AASTableTree extends Tree {
+ private _nodes: AASTableRow[];
- return children;
+ public constructor(nodes: AASTableRow[]) {
+ super();
+
+ this._nodes = nodes;
}
- public getExpanded(rows: AASTableRow[]): AASTableRow[] {
- return this.traverse(rows, this, [this]);
+ public get nodes(): AASTableRow[] {
+ return this._nodes;
}
- private traverse(rows: AASTableRow[], row: AASTableRow, expanded: AASTableRow[]): AASTableRow[] {
- if (row.firstChild >= 0 && row.expanded) {
- let child = rows[row.firstChild];
- expanded.push(child);
- this.traverse(rows, child, expanded);
- while (child.nextSibling >= 0) {
- child = rows[child.nextSibling];
- expanded.push(child);
- this.traverse(rows, child, expanded);
- }
- }
+ protected override getNodes(): AASTableRow[] {
+ return this._nodes;
+ }
+
+ protected override setNodes(nodes: AASTableRow[]): void {
+ this._nodes = nodes;
+ }
- return expanded;
+ protected override cloneNode(node: AASTableRow): AASTableRow {
+ return new AASTableRow(
+ node.document,
+ node.parent,
+ node.selected,
+ node.expanded,
+ node.highlighted,
+ node.isLeaf,
+ node.level,
+ node.firstChild,
+ node.nextSibling,
+ );
}
}
diff --git a/projects/aas-lib/src/lib/aas-tree/aas-tree-search.ts b/projects/aas-lib/src/lib/aas-tree/aas-tree-search.ts
index a771dc60..01c27239 100644
--- a/projects/aas-lib/src/lib/aas-tree/aas-tree-search.ts
+++ b/projects/aas-lib/src/lib/aas-tree/aas-tree-search.ts
@@ -105,6 +105,10 @@ export class AASTreeSearch {
if (this.rows.length > 0 && this.terms.length > 0) {
let match = false;
let i = this.index < 0 ? 0 : this.index + 1;
+ if (i >= this.rows.length) {
+ i = 0;
+ }
+
const start = i;
while (this.loop) {
if (this.match(this.rows[i])) {
diff --git a/projects/aas-lib/src/lib/aas-tree/aas-tree.component.html b/projects/aas-lib/src/lib/aas-tree/aas-tree.component.html
index 270617a3..812cfe0d 100644
--- a/projects/aas-lib/src/lib/aas-tree/aas-tree.component.html
+++ b/projects/aas-lib/src/lib/aas-tree/aas-tree.component.html
@@ -32,30 +32,33 @@
- @if (!node.isLeaf && !node.expanded && node.hasChildren) {
-
-
-
-
-
- }
- @if (!node.isLeaf && !node.expanded && !node.hasChildren) {
-
-
-
- }
- @if (!node.isLeaf && node.expanded) {
-
-
-
-
-
- }
@if (node.isLeaf) {
-
+
+ }@else {
+ @if (node.expanded) {
+
+
+
+
+
+ }@else {
+ @if (node.hasChildren) {
+
+
+
+
+
+ }@else {
+
+
+
+ }
+ }
}
+
{{node.abbreviation}}
+
@if (node.hasSemantic) {
{{node.name}}
@@ -63,8 +66,7 @@
{{node.typeInfo}}
]
- }
- @if (!node.hasSemantic) {
+ }@else {
{{node.name}}
[
@@ -75,15 +77,17 @@
|
@if (node.isLeaf) {
-
- @if (node.displayType === 'text') {
- {{getValue(node)}}
- }
- @if (node.displayType === 'boolean') {
-
- }
- @if (node.displayType === 'url') {
- {{node.value}}
+ |
+ @switch(node.displayType) {
+ @case('boolean') {
+
+ }
+ @case ('url') {
+ {{node.value}}
+ }
+ @default {
+ {{getValue(node)}}
+ }
}
|
}
diff --git a/projects/aas-lib/src/lib/aas-tree/aas-tree.reducer.ts b/projects/aas-lib/src/lib/aas-tree/aas-tree.reducer.ts
index 7da44a72..4428b0eb 100644
--- a/projects/aas-lib/src/lib/aas-tree/aas-tree.reducer.ts
+++ b/projects/aas-lib/src/lib/aas-tree/aas-tree.reducer.ts
@@ -6,27 +6,11 @@
*
*****************************************************************************/
-import { isEqual } from 'lodash-es';
import { createReducer, on } from '@ngrx/store';
-import {
- AASDocument,
- convertToString,
- getAbbreviation,
- getLocaleValue,
- aas,
- isProperty,
- isReferenceElement,
- isIdentifiable,
- selectReferable,
- isBooleanType,
- toLocale,
- toBoolean,
- mimeTypeToExtension,
-} from 'common';
+import { aas } from 'common';
-import { AASTreeRow, AASTreeState, DisplayType, SearchTerm } from './aas-tree.state';
+import { AASTree, AASTreeRow, AASTreeState, SearchTerm } from './aas-tree.state';
import * as AASTreeActions from './aas-tree.actions';
-import { basename, normalize } from '../convert';
const initialState: AASTreeState = {
rows: [],
@@ -48,7 +32,8 @@ export const aasTreeReducer = createReducer(
on(AASTreeActions.toggleSelections, state => toggleSelections(state)),
on(AASTreeActions.updateRows, (state, { document, localeId }) => {
try {
- return updateRows(state, document, localeId);
+ const tree = AASTree.from(document, localeId);
+ return { ...state, rows: tree.nodes, error: null };
} catch (error) {
return { ...state, error };
}
@@ -56,538 +41,40 @@ export const aasTreeReducer = createReducer(
on(AASTreeActions.setSelectedElements, (state, { elements }) => setSelectedElements(state, elements)),
);
-function updateRows(state: AASTreeState, document: AASDocument | null, localeId: string): AASTreeState {
- const rows: AASTreeRow[] = [];
- const env = document?.content;
- if (env) {
- for (const shell of env.assetAdministrationShells) {
- const row = createRow(shell, -1, 0, true);
- rows.push(row);
- row.firstChild = hasChildren(shell) ? rows.length : -1;
- traverse(shell, rows.length - 1, 1);
- for (const stateRow of state.rows) {
- if (stateRow.expanded || stateRow.selected) {
- const row = findRow(rows, stateRow.element);
- if (row) {
- row.expanded = stateRow.expanded;
- row.selected = stateRow.selected;
- }
- }
- }
- }
- }
-
- return { ...state, rows, error: null };
-
- function traverse(element: aas.Referable, parent: number, level: number): void {
- let previous: AASTreeRow | null = null;
- for (const child of getChildren(element)) {
- const row = createRow(child, parent, level, false);
- rows.push(row);
- if (previous) {
- previous.nextSibling = rows.length - 1;
- }
-
- const descendants = getChildren(child);
- if (descendants.length > 0) {
- row.firstChild = rows.length;
- traverse(child, rows.length - 1, level + 1);
- }
-
- previous = row;
- }
- }
-
- function hasChildren(referable: aas.Referable): boolean {
- switch (referable.modelType) {
- case 'AssetAdministrationShell': {
- const shell = referable as aas.AssetAdministrationShell;
- return shell.submodels != null && shell.submodels.length > 0;
- }
- case 'Submodel': {
- const submodel = referable as aas.Submodel;
- return submodel.submodelElements != null && submodel.submodelElements.length > 0;
- }
- case 'SubmodelElementCollection': {
- const collection = referable as aas.SubmodelElementCollection;
- return collection.value != null && collection.value.length > 0;
- }
- case 'SubmodelElementList': {
- const list = referable as aas.SubmodelElementList;
- return list.value != null && list.value.length > 0;
- }
- default:
- return false;
- }
- }
-
- function getChildren(referable: aas.Referable): aas.Referable[] {
- switch (referable.modelType) {
- case 'AssetAdministrationShell': {
- const shell = referable as aas.AssetAdministrationShell;
- const children: aas.Referable[] = [];
- if (shell.submodels) {
- for (const reference of shell.submodels) {
- const submodel = selectReferable(env!, reference);
- if (submodel) {
- children.push(submodel);
- }
- }
- }
-
- return children;
- }
- case 'Submodel':
- return (referable as aas.Submodel).submodelElements ?? [];
- case 'SubmodelElementCollection':
- return (referable as aas.SubmodelElementCollection).value ?? [];
- case 'SubmodelElementList':
- return (referable as aas.SubmodelElementList).value ?? [];
- default:
- return [];
- }
- }
-
- function createRow(element: aas.Referable, parent: number, level: number, expanded: boolean): AASTreeRow {
- let valueType = DisplayType.undefined;
- let isLeaf = true;
- switch (element.modelType) {
- case 'AssetAdministrationShell':
- case 'Submodel':
- case 'SubmodelElementCollection':
- case 'SubmodelElementList':
- isLeaf = false;
- break;
- case 'Property':
- valueType = getPropertyDisplayType(element as aas.Property);
- break;
- case 'MultiLanguageProperty':
- case 'Range':
- valueType = DisplayType.Text;
- break;
- case 'Entity':
- case 'ReferenceElement':
- case 'Operation':
- valueType = DisplayType.Url;
- break;
- case 'File': {
- const file = element as aas.File;
- valueType = file.contentType && file.value ? DisplayType.Url : DisplayType.Text;
- break;
- }
- case 'Blob': {
- const blob = element as aas.Blob;
- valueType = blob.contentType ? DisplayType.Url : DisplayType.Text;
- break;
- }
- }
-
- return new AASTreeRow(
- `row_${rows.length + 1}`,
- element,
- expanded,
- false,
- false,
- level,
- getAbbreviation(element.modelType) ?? '',
- element.idShort,
- getTypeInfo(element),
- getValue(element, localeId),
- valueType,
- isLeaf,
- parent,
- -1,
- -1,
- );
-
- function getPropertyDisplayType(property: aas.Property): DisplayType {
- switch (property.valueType) {
- case 'xs:anyURI':
- return DisplayType.Url;
- case 'xs:boolean':
- return DisplayType.Boolean;
- default:
- return DisplayType.Text;
- }
- }
- }
-
- function findRow(rows: AASTreeRow[], referable: aas.Referable): AASTreeRow | undefined {
- return rows.find(row => isEqual(createReference(row.element), createReference(referable)));
- }
-
- function createReference(referable: aas.Referable): aas.Reference {
- let keys: aas.Key[];
- if (referable.parent) {
- keys = [
- ...referable.parent.keys.map(key => ({ ...key })),
- {
- type: referable.modelType as aas.KeyTypes,
- value: referable.idShort,
- },
- ];
- } else if (isIdentifiable(referable)) {
- keys = [
- {
- type: referable.modelType as aas.KeyTypes,
- value: referable.id,
- },
- ];
- } else {
- throw new Error('Unexpected referable.');
- }
-
- return { type: 'ModelReference', keys };
- }
-}
-
function expandRow(state: AASTreeState, arg: number | AASTreeRow): AASTreeState {
- const rows = [...state.rows];
- const ancestors: AASTreeRow[] = [];
- let row = typeof arg === 'number' ? state.rows[arg] : arg;
- if (!row.expanded) {
- expand(row);
- }
-
- let parentRow = row.parent >= 0 ? state.rows[row.parent] : null;
- while (parentRow) {
- if (parentRow.expanded) {
- break;
- }
-
- ancestors.push(parentRow);
- row = parentRow;
- parentRow = row.parent >= 0 ? state.rows[row.parent] : null;
- }
-
- while (ancestors.length > 0) {
- const row = ancestors.pop();
- if (!row) {
- break;
- }
-
- expand(row);
- }
-
- return { ...state, rows, error: null };
-
- function expand(row: AASTreeRow) {
- const index = rows.indexOf(row);
- rows[index] = new AASTreeRow(
- row.id,
- row.element,
- true,
- row.selected,
- row.highlighted,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
- }
+ const tree = new AASTree(state.rows);
+ tree.expand(arg);
+ return { ...state, rows: tree.nodes, error: null };
}
function collapseRow(state: AASTreeState, row: AASTreeRow): AASTreeState {
- const rows = [...state.rows];
- const index = rows.indexOf(row);
- rows[index] = new AASTreeRow(
- row.id,
- row.element,
- false,
- row.selected,
- row.highlighted,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
-
- return { ...state, rows, error: null };
+ const tree = new AASTree(state.rows);
+ tree.collapse(row);
+ return { ...state, rows: tree.nodes, error: null };
}
function collapse(state: AASTreeState): AASTreeState {
- const rows = state.rows.map((row, index) => {
- if (index === 0) {
- if (!row.expanded) {
- return new AASTreeRow(
- row.id,
- row.element,
- true,
- row.selected,
- row.highlighted,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
- }
- } else if (!row.isLeaf && row.expanded) {
- return new AASTreeRow(
- row.id,
- row.element,
- false,
- row.selected,
- row.highlighted,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
- }
-
- return row;
- });
-
- return { ...state, rows, error: null };
+ const tree = new AASTree(state.rows);
+ tree.collapse();
+ return { ...state, rows: tree.nodes, error: null };
}
function toggleSelected(state: AASTreeState, row: AASTreeRow, altKey: boolean, shiftKey: boolean): AASTreeState {
- let rows: AASTreeRow[];
- if (altKey) {
- rows = state.rows.map(item =>
- item === row ? clone(row, !row.selected) : item.selected ? clone(item, false) : item,
- );
- } else if (shiftKey) {
- const index = state.rows.indexOf(row);
- let begin = index;
- let end = index;
- const selection = state.rows.map(row => row.selected);
- const last = selection.lastIndexOf(true);
- if (last >= 0) {
- if (last > index) {
- begin = index;
- end = selection.indexOf(true);
- } else if (last < index) {
- begin = last;
- end = index;
- }
- }
-
- rows = [];
- for (let i = 0, n = state.rows.length; i < n; i++) {
- const row = state.rows[i];
- if (i < begin || i > end) {
- rows.push(row.selected ? clone(row, false) : row);
- } else {
- rows.push(row.selected ? row : clone(row, true));
- }
- }
- } else {
- const i = state.rows.indexOf(row);
- rows = [...state.rows];
- rows[i] = clone(row, !row.selected);
- }
-
- return { ...state, rows, error: null };
+ const tree = new AASTree(state.rows);
+ tree.toggleSelected(row, altKey, shiftKey);
+ return { ...state, rows: tree.nodes, error: null };
}
function toggleSelections(state: AASTreeState): AASTreeState {
- const rows = [...state.rows];
- if (rows.length > 0) {
- const value = !state.rows.every(row => row.selected);
- for (let index = 0, n = rows.length; index < n; ++index) {
- const row = rows[index];
- if (row.selected !== value) {
- rows[index] = clone(row, value);
- }
- }
- }
-
- return { ...state, rows, error: null };
+ const tree = new AASTree(state.rows);
+ tree.toggleSelections();
+ return { ...state, rows: tree.nodes, error: null };
}
function setSelectedElements(state: AASTreeState, elements: aas.Referable[]): AASTreeState {
- const rows = [...state.rows];
- const set = new Set(elements);
- for (let i = 0, n = rows.length; i < n; i++) {
- const row = rows[i];
- if (set.has(row.element)) {
- if (!row.selected) {
- rows[i] = clone(row, true);
- }
- } else if (row.selected) {
- rows[i] = clone(row, false);
- }
- }
-
- return { ...state, rows };
-}
-
-function clone(row: AASTreeRow, selected: boolean): AASTreeRow {
- return new AASTreeRow(
- row.id,
- row.element,
- row.expanded,
- selected,
- row.highlighted,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
-}
-
-function getTypeInfo(referable: aas.Referable | null): string {
- let value: string;
- if (referable) {
- switch (referable.modelType) {
- case 'AssetAdministrationShell':
- value = (referable as aas.Submodel).id;
- break;
- case 'Submodel':
- value = `Semantic ID: ${referenceToString((referable as aas.Submodel).semanticId)}`;
- break;
- case 'SubmodelElementCollection':
- value = (referable as aas.SubmodelElementCollection).value?.length.toString() ?? '0';
- break;
- case 'SubmodelElementList':
- value = (referable as aas.SubmodelElementList).value?.length.toString() ?? '0';
- break;
- case 'Property':
- value = (referable as aas.Property).valueType;
- break;
- case 'Range':
- value = (referable as aas.Range).valueType;
- break;
- case 'File':
- value = (referable as aas.File).contentType;
- break;
- case 'Blob':
- value = (referable as aas.Blob).contentType;
- break;
- case 'MultiLanguageProperty': {
- const mlp = referable as aas.MultiLanguageProperty;
- value = '';
- if (mlp && Array.isArray(mlp.value)) {
- value += `${mlp.value.map(item => item.language).join(', ')}`;
- }
- break;
- }
- case 'Entity': {
- const entity = referable as aas.Entity;
- value = '';
- if (entity?.globalAssetId) {
- value = entity.globalAssetId;
- }
- break;
- }
- case 'Operation': {
- const operation = referable as aas.Operation;
- value = '';
- if (operation.inputVariables && operation.inputVariables.length > 0) {
- value += '(' + operation.inputVariables.map(v => variableToString(v.value)).join(', ') + ')';
- }
-
- if (operation.outputVariables && operation.outputVariables.length === 1) {
- value += `: ${variableToString(operation.outputVariables[0].value)}`;
- } else if (operation.outputVariables && operation.outputVariables.length > 1) {
- value += ': {' + operation.outputVariables.map(v => variableToString(v.value)).join(', ') + '}';
- }
- break;
- }
- default:
- value = '-';
- break;
- }
- } else {
- value = '-';
- }
-
- return value;
-
- function variableToString(value: aas.SubmodelElement): string {
- if (isProperty(value)) {
- return `${value.idShort}: ${value.valueType}`;
- }
-
- if (isReferenceElement(value)) {
- return `${value.idShort}: ${value?.value?.keys.map(key => key.value).join('/')}`;
- }
-
- return `${value.idShort}: ${value.modelType}`;
- }
-
- function referenceToString(reference?: aas.Reference): string {
- return reference?.keys.map(key => key.value).join('/') ?? '-';
- }
-}
-
-function getValue(referable: aas.Referable | null, localeId: string): boolean | string | undefined {
- if (referable) {
- switch (referable.modelType) {
- case 'Property':
- return getPropertyValue(referable as aas.Property, localeId);
- case 'Range': {
- const range = referable as aas.Range;
- return `${convertToString(range.min, localeId)} ... ${convertToString(range.max, localeId)}`;
- }
- case 'File': {
- const file = referable as aas.File;
- return file.value ? basename(normalize(file.value)) : '-';
- }
- case 'Blob': {
- const blob = referable as aas.Blob;
- const extension = mimeTypeToExtension(blob.contentType) ?? '';
- return blob.contentType ? `${blob.idShort}${extension}` : '-';
- }
- case 'ReferenceElement':
- return (referable as aas.ReferenceElement).value.keys.map(item => item.value).join('/');
- case 'RelationshipElement':
- return getRelationshipElementValue(referable as aas.RelationshipElement);
- case 'MultiLanguageProperty':
- return getLocaleValue((referable as aas.MultiLanguageProperty).value, localeId) ?? '-';
- case 'Entity':
- return (referable as aas.Entity).globalAssetId ?? '-';
- default:
- return '-';
- }
- }
-
- return '';
-
- function getPropertyValue(property: aas.Property, localeId: string): string | boolean | undefined {
- if (isBooleanType(property.valueType)) {
- return toBoolean(property.value);
- } else {
- return toLocale(property.value, property.valueType, localeId);
- }
- }
-
- function getRelationshipElementValue(relationship: aas.RelationshipElement): string {
- const first = relationship.first.keys.map(key => key.value).join('/');
- const second = relationship.second.keys.map(key => key.value).join('/');
- return `1. ${first}; 2. ${second}`;
- }
+ const tree = new AASTree(state.rows);
+ tree.selectedElements = elements;
+ return { ...state, rows: tree.nodes };
}
function setSearchText(state: AASTreeState, terms: SearchTerm[]): AASTreeState {
@@ -595,65 +82,7 @@ function setSearchText(state: AASTreeState, terms: SearchTerm[]): AASTreeState {
}
function setMatchIndex(state: AASTreeState, index: number): AASTreeState {
- if (index >= 0) {
- return {
- ...state,
- rows: updateHighlighted(index),
- index: index,
- error: null,
- };
- } else {
- return {
- rows: updateHighlighted(-1),
- index: -1,
- terms: [],
- error: null,
- };
- }
-
- function updateHighlighted(index: number): AASTreeRow[] {
- const rows = [...state.rows];
- for (let i = 0; i < rows.length; i++) {
- const row = rows[i];
- if (i === index) {
- rows[i] = new AASTreeRow(
- row.id,
- row.element,
- row.expanded,
- row.selected,
- true,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
- } else if (rows[i].highlighted) {
- rows[i] = new AASTreeRow(
- row.id,
- row.element,
- row.expanded,
- row.selected,
- false,
- row.level,
- row.abbreviation,
- row.name,
- row.typeInfo,
- row.value,
- row.displayType,
- row.isLeaf,
- row.parent,
- row.firstChild,
- row.nextSibling,
- );
- }
- }
-
- return rows;
- }
+ const tree = new AASTree(state.rows);
+ tree.highlight(index);
+ return { ...state, rows: tree.nodes, index };
}
diff --git a/projects/aas-lib/src/lib/aas-tree/aas-tree.selectors.ts b/projects/aas-lib/src/lib/aas-tree/aas-tree.selectors.ts
index 5d4c40db..b21b35e7 100644
--- a/projects/aas-lib/src/lib/aas-tree/aas-tree.selectors.ts
+++ b/projects/aas-lib/src/lib/aas-tree/aas-tree.selectors.ts
@@ -7,7 +7,7 @@
*****************************************************************************/
import { createSelector } from '@ngrx/store';
-import { AASTreeFeatureState } from './aas-tree.state';
+import { AASTree, AASTreeFeatureState } from './aas-tree.state';
const getState = (state: AASTreeFeatureState) => state.tree;
const getRows = (state: AASTreeFeatureState) => state.tree.rows;
@@ -31,7 +31,7 @@ export const selectRow = (index: number) => {
return createSelector(getRows, rows => rows[index]);
};
-export const selectNodes = createSelector(getRows, rows => rows.find(row => row.level === 0)?.getExpanded(rows) ?? []);
+export const selectNodes = createSelector(getRows, rows => new AASTree(rows).expanded);
export const selectSelectedElements = createSelector(getRows, rows =>
rows.filter(row => row.selected).map(item => item.element),
diff --git a/projects/aas-lib/src/lib/aas-tree/aas-tree.state.ts b/projects/aas-lib/src/lib/aas-tree/aas-tree.state.ts
index 100e6181..f35c9f97 100644
--- a/projects/aas-lib/src/lib/aas-tree/aas-tree.state.ts
+++ b/projects/aas-lib/src/lib/aas-tree/aas-tree.state.ts
@@ -6,29 +6,49 @@
*
*****************************************************************************/
-import { aas, isSubmodel } from 'common';
+import {
+ AASDocument,
+ aas,
+ convertToString,
+ getAbbreviation,
+ getLocaleValue,
+ isBooleanType,
+ isIdentifiable,
+ isProperty,
+ isReferenceElement,
+ isSubmodel,
+ mimeTypeToExtension,
+ selectReferable,
+ toBoolean,
+ toLocale,
+} from 'common';
import { resolveSemanticId, supportedSubmodelTemplates } from '../submodel-template/submodel-template';
+import { Tree, TreeNode } from '../tree';
+import { basename, normalize } from '../convert';
+import { isEqual } from 'lodash-es';
-export class AASTreeRow {
+export class AASTreeRow extends TreeNode {
public constructor(
public readonly id: string,
- public readonly element: aas.Referable,
- public expanded: boolean,
- public selected: boolean,
- public readonly highlighted: boolean,
- public readonly level: number,
+ element: aas.Referable,
+ expanded: boolean,
+ selected: boolean,
+ highlighted: boolean,
+ level: number,
public readonly abbreviation: string,
public readonly name: string,
public readonly typeInfo: string,
public readonly value: string | boolean | undefined,
public readonly displayType: DisplayType,
public readonly isLeaf: boolean,
- public readonly parent: number,
- public firstChild: number,
- public nextSibling: number,
- ) {}
+ parent: number,
+ firstChild: number,
+ nextSibling: number,
+ ) {
+ super(element, parent, level, expanded, selected, highlighted, firstChild, nextSibling);
+ }
- public get hasChildren(): boolean {
+ public override get hasChildren(): boolean {
return this.firstChild >= 0;
}
@@ -41,39 +61,6 @@ export class AASTreeRow {
return false;
}
-
- public getChildren(rows: AASTreeRow[]): AASTreeRow[] {
- const children: AASTreeRow[] = [];
- if (this.firstChild >= 0) {
- let child = rows[this.firstChild];
- children.push(child);
- while (child.nextSibling >= 0) {
- child = rows[child.nextSibling];
- children.push(child);
- }
- }
-
- return children;
- }
-
- public getExpanded(rows: AASTreeRow[]): AASTreeRow[] {
- return this.traverse(rows, this, [this]);
- }
-
- private traverse(rows: AASTreeRow[], row: AASTreeRow, expanded: AASTreeRow[]): AASTreeRow[] {
- if (row.firstChild >= 0 && row.expanded) {
- let child = rows[row.firstChild];
- expanded.push(child);
- this.traverse(rows, child, expanded);
- while (child.nextSibling >= 0) {
- child = rows[child.nextSibling];
- expanded.push(child);
- this.traverse(rows, child, expanded);
- }
- }
-
- return expanded;
- }
}
export enum DisplayType {
@@ -107,3 +94,377 @@ export interface AASTreeState {
export interface AASTreeFeatureState {
tree: AASTreeState;
}
+
+class TreeInitialize {
+ private readonly rows: AASTreeRow[] = [];
+ public constructor(
+ private readonly env: aas.Environment,
+ private readonly language: string,
+ ) {}
+
+ public get(): AASTreeRow[] {
+ for (const shell of this.env.assetAdministrationShells) {
+ const row = this.createRow(shell, -1, 0, true);
+ this.rows.push(row);
+ row.firstChild = this.hasChildren(shell) ? this.rows.length : -1;
+ this.traverse(shell, this.rows.length - 1, 1);
+ for (const stateRow of this.rows) {
+ if (stateRow.expanded || stateRow.selected) {
+ const row = this.findRow(this.rows, stateRow.element);
+ if (row) {
+ row.expanded = stateRow.expanded;
+ row.selected = stateRow.selected;
+ }
+ }
+ }
+ }
+
+ return this.rows;
+ }
+
+ private createRow(element: aas.Referable, parent: number, level: number, expanded: boolean): AASTreeRow {
+ let valueType = DisplayType.undefined;
+ let isLeaf = true;
+ switch (element.modelType) {
+ case 'AssetAdministrationShell':
+ case 'Submodel':
+ case 'SubmodelElementCollection':
+ case 'SubmodelElementList':
+ isLeaf = false;
+ break;
+ case 'Property':
+ valueType = this.getPropertyDisplayType(element as aas.Property);
+ break;
+ case 'MultiLanguageProperty':
+ case 'Range':
+ valueType = DisplayType.Text;
+ break;
+ case 'Entity':
+ case 'ReferenceElement':
+ case 'Operation':
+ valueType = DisplayType.Url;
+ break;
+ case 'File': {
+ const file = element as aas.File;
+ valueType = file.contentType && file.value ? DisplayType.Url : DisplayType.Text;
+ break;
+ }
+ case 'Blob': {
+ const blob = element as aas.Blob;
+ valueType = blob.contentType ? DisplayType.Url : DisplayType.Text;
+ break;
+ }
+ }
+
+ return new AASTreeRow(
+ `row_${this.rows.length + 1}`,
+ element,
+ expanded,
+ false,
+ false,
+ level,
+ getAbbreviation(element.modelType) ?? '',
+ element.idShort,
+ this.getTypeInfo(element),
+ this.getValue(element, this.language),
+ valueType,
+ isLeaf,
+ parent,
+ -1,
+ -1,
+ );
+ }
+
+ private traverse(element: aas.Referable, parent: number, level: number): void {
+ let previous: AASTreeRow | null = null;
+ for (const child of this.getChildren(element)) {
+ const row = this.createRow(child, parent, level, false);
+ this.rows.push(row);
+ if (previous) {
+ previous.nextSibling = this.rows.length - 1;
+ }
+
+ const descendants = this.getChildren(child);
+ if (descendants.length > 0) {
+ row.firstChild = this.rows.length;
+ this.traverse(child, this.rows.length - 1, level + 1);
+ }
+
+ previous = row;
+ }
+ }
+
+ private getChildren(referable: aas.Referable): aas.Referable[] {
+ switch (referable.modelType) {
+ case 'AssetAdministrationShell': {
+ const shell = referable as aas.AssetAdministrationShell;
+ const children: aas.Referable[] = [];
+ if (shell.submodels) {
+ for (const reference of shell.submodels) {
+ const submodel = selectReferable(this.env!, reference);
+ if (submodel) {
+ children.push(submodel);
+ }
+ }
+ }
+
+ return children;
+ }
+ case 'Submodel':
+ return (referable as aas.Submodel).submodelElements ?? [];
+ case 'SubmodelElementCollection':
+ return (referable as aas.SubmodelElementCollection).value ?? [];
+ case 'SubmodelElementList':
+ return (referable as aas.SubmodelElementList).value ?? [];
+ default:
+ return [];
+ }
+ }
+
+ private findRow(rows: AASTreeRow[], referable: aas.Referable): AASTreeRow | undefined {
+ return rows.find(row => isEqual(this.createReference(row.element), this.createReference(referable)));
+ }
+
+ private createReference(referable: aas.Referable): aas.Reference {
+ let keys: aas.Key[];
+ if (referable.parent) {
+ keys = [
+ ...referable.parent.keys.map(key => ({ ...key })),
+ {
+ type: referable.modelType as aas.KeyTypes,
+ value: referable.idShort,
+ },
+ ];
+ } else if (isIdentifiable(referable)) {
+ keys = [
+ {
+ type: referable.modelType as aas.KeyTypes,
+ value: referable.id,
+ },
+ ];
+ } else {
+ throw new Error('Unexpected referable.');
+ }
+
+ return { type: 'ModelReference', keys };
+ }
+
+ private getPropertyDisplayType(property: aas.Property): DisplayType {
+ switch (property.valueType) {
+ case 'xs:anyURI':
+ return DisplayType.Url;
+ case 'xs:boolean':
+ return DisplayType.Boolean;
+ default:
+ return DisplayType.Text;
+ }
+ }
+
+ private getValue(referable: aas.Referable | null, localeId: string): boolean | string | undefined {
+ if (referable) {
+ switch (referable.modelType) {
+ case 'Property':
+ return this.getPropertyValue(referable as aas.Property, localeId);
+ case 'Range': {
+ const range = referable as aas.Range;
+ return `${convertToString(range.min, localeId)} ... ${convertToString(range.max, localeId)}`;
+ }
+ case 'File': {
+ const file = referable as aas.File;
+ return file.value ? basename(normalize(file.value)) : '-';
+ }
+ case 'Blob': {
+ const blob = referable as aas.Blob;
+ const extension = mimeTypeToExtension(blob.contentType) ?? '';
+ return blob.contentType ? `${blob.idShort}${extension}` : '-';
+ }
+ case 'ReferenceElement':
+ return (referable as aas.ReferenceElement).value.keys.map(item => item.value).join('/');
+ case 'RelationshipElement':
+ return this.getRelationshipElementValue(referable as aas.RelationshipElement);
+ case 'MultiLanguageProperty':
+ return getLocaleValue((referable as aas.MultiLanguageProperty).value, localeId) ?? '-';
+ case 'Entity':
+ return (referable as aas.Entity).globalAssetId ?? '-';
+ default:
+ return '-';
+ }
+ }
+
+ return '';
+ }
+
+ private hasChildren(referable: aas.Referable): boolean {
+ switch (referable.modelType) {
+ case 'AssetAdministrationShell': {
+ const shell = referable as aas.AssetAdministrationShell;
+ return shell.submodels != null && shell.submodels.length > 0;
+ }
+ case 'Submodel': {
+ const submodel = referable as aas.Submodel;
+ return submodel.submodelElements != null && submodel.submodelElements.length > 0;
+ }
+ case 'SubmodelElementCollection': {
+ const collection = referable as aas.SubmodelElementCollection;
+ return collection.value != null && collection.value.length > 0;
+ }
+ case 'SubmodelElementList': {
+ const list = referable as aas.SubmodelElementList;
+ return list.value != null && list.value.length > 0;
+ }
+ default:
+ return false;
+ }
+ }
+
+ private getPropertyValue(property: aas.Property, localeId: string): string | boolean | undefined {
+ if (isBooleanType(property.valueType)) {
+ return toBoolean(property.value);
+ } else {
+ return toLocale(property.value, property.valueType, localeId);
+ }
+ }
+
+ private getRelationshipElementValue(relationship: aas.RelationshipElement): string {
+ const first = relationship.first.keys.map(key => key.value).join('/');
+ const second = relationship.second.keys.map(key => key.value).join('/');
+ return `1. ${first}; 2. ${second}`;
+ }
+
+ private getTypeInfo(referable: aas.Referable | null): string {
+ let value: string;
+ if (referable) {
+ switch (referable.modelType) {
+ case 'AssetAdministrationShell':
+ value = (referable as aas.Submodel).id;
+ break;
+ case 'Submodel':
+ value = `Semantic ID: ${this.referenceToString((referable as aas.Submodel).semanticId)}`;
+ break;
+ case 'SubmodelElementCollection':
+ value = (referable as aas.SubmodelElementCollection).value?.length.toString() ?? '0';
+ break;
+ case 'SubmodelElementList':
+ value = (referable as aas.SubmodelElementList).value?.length.toString() ?? '0';
+ break;
+ case 'Property':
+ value = (referable as aas.Property).valueType;
+ break;
+ case 'Range':
+ value = (referable as aas.Range).valueType;
+ break;
+ case 'File':
+ value = (referable as aas.File).contentType;
+ break;
+ case 'Blob':
+ value = (referable as aas.Blob).contentType;
+ break;
+ case 'MultiLanguageProperty': {
+ const mlp = referable as aas.MultiLanguageProperty;
+ value = '';
+ if (mlp && Array.isArray(mlp.value)) {
+ value += `${mlp.value.map(item => item.language).join(', ')}`;
+ }
+ break;
+ }
+ case 'Entity': {
+ const entity = referable as aas.Entity;
+ value = '';
+ if (entity?.globalAssetId) {
+ value = entity.globalAssetId;
+ }
+ break;
+ }
+ case 'Operation': {
+ const operation = referable as aas.Operation;
+ value = '';
+ if (operation.inputVariables && operation.inputVariables.length > 0) {
+ value +=
+ '(' + operation.inputVariables.map(v => this.variableToString(v.value)).join(', ') + ')';
+ }
+
+ if (operation.outputVariables && operation.outputVariables.length === 1) {
+ value += `: ${this.variableToString(operation.outputVariables[0].value)}`;
+ } else if (operation.outputVariables && operation.outputVariables.length > 1) {
+ value +=
+ ': {' + operation.outputVariables.map(v => this.variableToString(v.value)).join(', ') + '}';
+ }
+ break;
+ }
+ default:
+ value = '-';
+ break;
+ }
+ } else {
+ value = '-';
+ }
+
+ return value;
+ }
+
+ private variableToString(value: aas.SubmodelElement): string {
+ if (isProperty(value)) {
+ return `${value.idShort}: ${value.valueType}`;
+ }
+
+ if (isReferenceElement(value)) {
+ return `${value.idShort}: ${value?.value?.keys.map(key => key.value).join('/')}`;
+ }
+
+ return `${value.idShort}: ${value.modelType}`;
+ }
+
+ private referenceToString(reference?: aas.Reference): string {
+ return reference?.keys.map(key => key.value).join('/') ?? '-';
+ }
+}
+
+export class AASTree extends Tree {
+ private _nodes: AASTreeRow[];
+
+ public constructor(nodes: AASTreeRow[]) {
+ super();
+
+ this._nodes = nodes;
+ }
+
+ public get nodes(): AASTreeRow[] {
+ return this._nodes;
+ }
+
+ public static from(document: AASDocument | null, language: string): AASTree {
+ if (!document || !document.content) {
+ return new AASTree([]);
+ }
+
+ return new AASTree(new TreeInitialize(document.content, language).get());
+ }
+
+ protected override getNodes(): AASTreeRow[] {
+ return this._nodes;
+ }
+
+ protected override setNodes(nodes: AASTreeRow[]): void {
+ this._nodes = nodes;
+ }
+
+ protected override cloneNode(node: AASTreeRow): AASTreeRow {
+ return new AASTreeRow(
+ node.id,
+ node.element,
+ node.expanded,
+ node.selected,
+ node.highlighted,
+ node.level,
+ node.abbreviation,
+ node.name,
+ node.typeInfo,
+ node.value,
+ node.displayType,
+ node.isLeaf,
+ node.parent,
+ node.firstChild,
+ node.nextSibling,
+ );
+ }
+}
diff --git a/projects/aas-lib/src/lib/aas-tree/operation-call-form/operation-call-form.component.scss b/projects/aas-lib/src/lib/aas-tree/operation-call-form/operation-call-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/aas-tree/operation-call-form/operation-call-form.component.scss
+++ b/projects/aas-lib/src/lib/aas-tree/operation-call-form/operation-call-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/aas-tree/show-image-form/show-image-form.component.scss b/projects/aas-lib/src/lib/aas-tree/show-image-form/show-image-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/aas-tree/show-image-form/show-image-form.component.scss
+++ b/projects/aas-lib/src/lib/aas-tree/show-image-form/show-image-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/aas-tree/show-video-form/show-video-form.component.scss b/projects/aas-lib/src/lib/aas-tree/show-video-form/show-video-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/aas-tree/show-video-form/show-video-form.component.scss
+++ b/projects/aas-lib/src/lib/aas-tree/show-video-form/show-video-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/auth/auth.component.scss b/projects/aas-lib/src/lib/auth/auth.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/auth/auth.component.scss
+++ b/projects/aas-lib/src/lib/auth/auth.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/auth/login-form/login-form.component.scss b/projects/aas-lib/src/lib/auth/login-form/login-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/auth/login-form/login-form.component.scss
+++ b/projects/aas-lib/src/lib/auth/login-form/login-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/auth/profile-form/profile-form.component.scss b/projects/aas-lib/src/lib/auth/profile-form/profile-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/auth/profile-form/profile-form.component.scss
+++ b/projects/aas-lib/src/lib/auth/profile-form/profile-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/auth/register-form/register-form.component.scss b/projects/aas-lib/src/lib/auth/register-form/register-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/auth/register-form/register-form.component.scss
+++ b/projects/aas-lib/src/lib/auth/register-form/register-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/customer-feedback/customer-feedback.component.scss b/projects/aas-lib/src/lib/customer-feedback/customer-feedback.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/customer-feedback/customer-feedback.component.scss
+++ b/projects/aas-lib/src/lib/customer-feedback/customer-feedback.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/digital-nameplate/digital-nameplate.component.scss b/projects/aas-lib/src/lib/digital-nameplate/digital-nameplate.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/digital-nameplate/digital-nameplate.component.scss
+++ b/projects/aas-lib/src/lib/digital-nameplate/digital-nameplate.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/library-table/library-table.component.scss b/projects/aas-lib/src/lib/library-table/library-table.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/library-table/library-table.component.scss
+++ b/projects/aas-lib/src/lib/library-table/library-table.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/localize/localize.component.scss b/projects/aas-lib/src/lib/localize/localize.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/localize/localize.component.scss
+++ b/projects/aas-lib/src/lib/localize/localize.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/message-table/message-table.component.scss b/projects/aas-lib/src/lib/message-table/message-table.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/message-table/message-table.component.scss
+++ b/projects/aas-lib/src/lib/message-table/message-table.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/notify/notify.component.scss b/projects/aas-lib/src/lib/notify/notify.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/notify/notify.component.scss
+++ b/projects/aas-lib/src/lib/notify/notify.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/secured-image/secured-image.component.scss b/projects/aas-lib/src/lib/secured-image/secured-image.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-lib/src/lib/secured-image/secured-image.component.scss
+++ b/projects/aas-lib/src/lib/secured-image/secured-image.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-lib/src/lib/tree.ts b/projects/aas-lib/src/lib/tree.ts
new file mode 100644
index 00000000..8f0ac7f0
--- /dev/null
+++ b/projects/aas-lib/src/lib/tree.ts
@@ -0,0 +1,247 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
+
+export abstract class TreeNode {
+ protected constructor(
+ public readonly element: TElement,
+ public readonly parent: number,
+ public readonly level: number,
+ public expanded: boolean,
+ public selected: boolean,
+ public highlighted: boolean,
+ public firstChild: number,
+ public nextSibling: number,
+ ) {}
+
+ public get hasChildren(): boolean {
+ return this.firstChild >= 0;
+ }
+
+ public abstract get isLeaf(): boolean;
+}
+
+export abstract class Tree> {
+ public get expanded(): TNode[] {
+ const root = this.getNodes().find(node => node.level === 0);
+ if (!root) {
+ return [];
+ }
+
+ return this.traverseNodes(root, [root]);
+ }
+
+ public get selectedElements(): TElement[] {
+ return this.getNodes()
+ .filter(node => node.selected)
+ .map(node => node.element);
+ }
+
+ public set selectedElements(elements: TElement[]) {
+ const nodes = [...this.getNodes()];
+ const set = new Set(elements);
+ for (let i = 0, n = nodes.length; i < n; i++) {
+ const row = nodes[i];
+ if (set.has(row.element)) {
+ if (!row.selected) {
+ nodes[i] = this.clone(row, true);
+ }
+ } else if (row.selected) {
+ nodes[i] = this.clone(row, false);
+ }
+ }
+
+ this.setNodes(nodes);
+ }
+
+ public getChildren(node: TNode): TNode[] {
+ const children: TNode[] = [];
+ const nodes = this.getNodes();
+ if (node.firstChild >= 0) {
+ let child = nodes[node.firstChild];
+ children.push(child);
+ while (child.nextSibling >= 0) {
+ child = nodes[child.nextSibling];
+ children.push(child);
+ }
+ }
+
+ return children;
+ }
+
+ public get highlighted(): TNode[] {
+ return [];
+ }
+
+ public expand(arg: number | TNode): void {
+ const nodes = [...this.getNodes()];
+ const ancestors: TNode[] = [];
+ let node = typeof arg === 'number' ? nodes[arg] : arg;
+ if (!node.expanded) {
+ this.expandNode(node, nodes);
+ }
+
+ let parentRow = node.parent >= 0 ? nodes[node.parent] : null;
+ while (parentRow) {
+ if (parentRow.expanded) {
+ break;
+ }
+
+ ancestors.push(parentRow);
+ node = parentRow;
+ parentRow = node.parent >= 0 ? nodes[node.parent] : null;
+ }
+
+ while (ancestors.length > 0) {
+ const ancestor = ancestors.pop();
+ if (!ancestor) {
+ break;
+ }
+
+ this.expandNode(ancestor, nodes);
+ }
+
+ this.setNodes(nodes);
+ }
+
+ public collapse(node?: TNode): void {
+ let nodes: TNode[];
+ if (node) {
+ nodes = [...this.getNodes()];
+ const index = nodes.indexOf(node);
+ const clone = this.cloneNode(node);
+ clone.expanded = false;
+ nodes[index] = clone;
+ } else {
+ nodes = this.getNodes().map((node, index) => {
+ if (index === 0) {
+ if (!node.expanded) {
+ const clone = this.cloneNode(node);
+ clone.expanded = true;
+ return clone;
+ }
+ } else if (!node.isLeaf && node.expanded) {
+ const clone = this.cloneNode(node);
+ clone.expanded = false;
+ return clone;
+ }
+
+ return node;
+ });
+ }
+
+ this.setNodes(nodes);
+ }
+
+ public toggleSelected(node: TNode, altKey: boolean, shiftKey: boolean): void {
+ let nodes: TNode[];
+ if (altKey) {
+ nodes = this.getNodes().map(item =>
+ item === node ? this.clone(node, !node.selected) : item.selected ? this.clone(item, false) : item,
+ );
+ } else if (shiftKey) {
+ const index = this.getNodes().indexOf(node);
+ let begin = index;
+ let end = index;
+ const selection = this.getNodes().map(row => row.selected);
+ const last = selection.lastIndexOf(true);
+ if (last >= 0) {
+ if (last > index) {
+ begin = index;
+ end = selection.indexOf(true);
+ } else if (last < index) {
+ begin = last;
+ end = index;
+ }
+ }
+
+ nodes = this.getNodes().map((node, i) => {
+ if (i < begin || i > end) {
+ return node.selected ? this.clone(node, false) : node;
+ } else {
+ return node.selected ? node : this.clone(node, true);
+ }
+ });
+ } else {
+ nodes = [...this.getNodes()];
+ const i = nodes.indexOf(node);
+ nodes[i] = this.clone(node, !node.selected);
+ }
+
+ this.setNodes(nodes);
+ }
+
+ public toggleSelections(): void {
+ const nodes = [...this.getNodes()];
+ if (nodes.length > 0) {
+ const value = !nodes.every(row => row.selected);
+ for (let index = 0, n = nodes.length; index < n; ++index) {
+ const node = nodes[index];
+ if (node.selected !== value) {
+ nodes[index] = this.clone(node, value);
+ }
+ }
+ }
+
+ this.setNodes(nodes);
+ }
+
+ public highlight(arg: TNode | number): void {
+ const index = typeof arg === 'number' ? arg : this.getNodes().indexOf(arg);
+ this.updateHighlighted(index);
+ }
+
+ protected abstract getNodes(): TNode[];
+
+ protected abstract setNodes(nodes: TNode[]): void;
+
+ protected abstract cloneNode(node: TNode): TNode;
+
+ private expandNode(node: TNode, nodes: TNode[]) {
+ const index = nodes.indexOf(node);
+ const clone = this.cloneNode(node);
+ clone.expanded = true;
+ nodes[index] = clone;
+ }
+
+ private updateHighlighted(index: number): void {
+ const nodes = [...this.getNodes()];
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+ if (i === index) {
+ nodes[i] = this.cloneNode(node);
+ nodes[i].highlighted = true;
+ } else if (node.highlighted) {
+ nodes[i] = this.cloneNode(node);
+ nodes[i].highlighted = false;
+ }
+ }
+
+ this.setNodes(nodes);
+ }
+
+ private traverseNodes(node: TNode, expanded: TNode[]): TNode[] {
+ if (node.firstChild >= 0 && node.expanded) {
+ let child = this.getNodes()[node.firstChild];
+ expanded.push(child);
+ this.traverseNodes(child, expanded);
+ while (child.nextSibling >= 0) {
+ child = this.getNodes()[child.nextSibling];
+ expanded.push(child);
+ this.traverseNodes(child, expanded);
+ }
+ }
+
+ return expanded;
+ }
+
+ private clone(node: TNode, selected: boolean): TNode {
+ const clone = this.cloneNode(node);
+ clone.selected = selected;
+ return clone;
+ }
+}
diff --git a/projects/aas-portal/src/app/aas/edit-element-form/edit-element-form.component.scss b/projects/aas-portal/src/app/aas/edit-element-form/edit-element-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/aas/edit-element-form/edit-element-form.component.scss
+++ b/projects/aas-portal/src/app/aas/edit-element-form/edit-element-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/aas/new-element-form/new-element-form.component.scss b/projects/aas-portal/src/app/aas/new-element-form/new-element-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/aas/new-element-form/new-element-form.component.scss
+++ b/projects/aas-portal/src/app/aas/new-element-form/new-element-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/about/about.component.scss b/projects/aas-portal/src/app/about/about.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/about/about.component.scss
+++ b/projects/aas-portal/src/app/about/about.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/main/main.component.scss b/projects/aas-portal/src/app/main/main.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/main/main.component.scss
+++ b/projects/aas-portal/src/app/main/main.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/start/remove-endpoint-form/remove-endpoint-form.component.scss b/projects/aas-portal/src/app/start/remove-endpoint-form/remove-endpoint-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/start/remove-endpoint-form/remove-endpoint-form.component.scss
+++ b/projects/aas-portal/src/app/start/remove-endpoint-form/remove-endpoint-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/start/start.actions.ts b/projects/aas-portal/src/app/start/start.actions.ts
index bf51c7c4..6745dbbf 100644
--- a/projects/aas-portal/src/app/start/start.actions.ts
+++ b/projects/aas-portal/src/app/start/start.actions.ts
@@ -62,7 +62,7 @@ export const setPage = createAction(
export const setContent = createAction(
StartActionType.SET_CONTENT,
- props<{ document: AASDocument; content: aas.Environment }>(),
+ props<{ document: AASDocument; content: aas.Environment | null | undefined }>(),
);
export const getFavorites = createAction(
diff --git a/projects/aas-portal/src/app/start/start.component.scss b/projects/aas-portal/src/app/start/start.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/start/start.component.scss
+++ b/projects/aas-portal/src/app/start/start.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/start/start.effects.ts b/projects/aas-portal/src/app/start/start.effects.ts
index edfdda22..a064772e 100644
--- a/projects/aas-portal/src/app/start/start.effects.ts
+++ b/projects/aas-portal/src/app/start/start.effects.ts
@@ -10,7 +10,7 @@ import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Action, Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
-import { EMPTY, exhaustMap, map, mergeMap, first, concat, of, from, Observable } from 'rxjs';
+import { EMPTY, exhaustMap, map, mergeMap, first, concat, of, from, Observable, catchError } from 'rxjs';
import { AASDocument, AASDocumentId, AASPage } from 'common';
import { ViewMode } from 'aas-lib';
@@ -189,9 +189,10 @@ export class StartEffects {
of(StartActions.setFavorites({ name: action.name, documents: action.documents })),
from(action.documents).pipe(
mergeMap(document =>
- this.api
- .getContent(document.endpoint, document.id)
- .pipe(map(content => StartActions.setContent({ document, content }))),
+ this.api.getContent(document.endpoint, document.id).pipe(
+ catchError(() => of(undefined)),
+ map(content => StartActions.setContent({ document, content })),
+ ),
),
),
),
@@ -208,9 +209,10 @@ export class StartEffects {
of(StartActions.setPage({ page, limit, filter })),
from(page.documents).pipe(
mergeMap(document =>
- this.api
- .getContent(document.endpoint, document.id)
- .pipe(map(content => StartActions.setContent({ document, content }))),
+ this.api.getContent(document.endpoint, document.id).pipe(
+ catchError(() => of(undefined)),
+ map(content => StartActions.setContent({ document, content })),
+ ),
),
),
);
diff --git a/projects/aas-portal/src/app/start/start.reducer.ts b/projects/aas-portal/src/app/start/start.reducer.ts
index ecc5b720..ed2cee1f 100644
--- a/projects/aas-portal/src/app/start/start.reducer.ts
+++ b/projects/aas-portal/src/app/start/start.reducer.ts
@@ -59,7 +59,7 @@ function setFavorites(state: StartState, favorites: string, documents: AASDocume
return { ...state, favorites, documents, viewMode: ViewMode.List };
}
-function setContent(state: StartState, document: AASDocument, content: aas.Environment): StartState {
+function setContent(state: StartState, document: AASDocument, content: aas.Environment | null | undefined): StartState {
const documents = [...state.documents];
const index = documents.findIndex(item => item.endpoint === document.endpoint && item.id === document.id);
if (index >= 0) {
diff --git a/projects/aas-portal/src/app/start/upload-form/upload-form.component.scss b/projects/aas-portal/src/app/start/upload-form/upload-form.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/start/upload-form/upload-form.component.scss
+++ b/projects/aas-portal/src/app/start/upload-form/upload-form.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/
diff --git a/projects/aas-portal/src/app/view/view.component.scss b/projects/aas-portal/src/app/view/view.component.scss
index 1b4785f3..3caf3822 100644
--- a/projects/aas-portal/src/app/view/view.component.scss
+++ b/projects/aas-portal/src/app/view/view.component.scss
@@ -1,7 +1,7 @@
-/******************************************************************************
- *
- * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
- * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
- * zur Foerderung der angewandten Forschung e.V.
- *
- *****************************************************************************/
+/******************************************************************************
+ *
+ * Copyright (c) 2019-2024 Fraunhofer IOSB-INA Lemgo,
+ * eine rechtlich nicht selbstaendige Einrichtung der Fraunhofer-Gesellschaft
+ * zur Foerderung der angewandten Forschung e.V.
+ *
+ *****************************************************************************/