From bf00c407a125248769ced6dabf235e0345fd2c90 Mon Sep 17 00:00:00 2001
From: Mikkel Ricky
Date: Thu, 19 Mar 2026 15:00:50 +0100
Subject: [PATCH 1/6] Added application metadata
---
src/app/applications/application.model.ts | 2 +
.../form-body-application.component.html | 6 ++
.../form-body-application.component.ts | 65 +++++++++++++++++++
3 files changed, 73 insertions(+)
diff --git a/src/app/applications/application.model.ts b/src/app/applications/application.model.ts
index 63fd9a97..4b2ff0c7 100644
--- a/src/app/applications/application.model.ts
+++ b/src/app/applications/application.model.ts
@@ -37,6 +37,7 @@ export class Application {
public permissions: PermissionResponse[];
public permissionIds: number[];
public dataTargets: Datatarget[];
+ public metadata?: string;
}
export class ApplicationRequest {
@@ -56,6 +57,7 @@ export class ApplicationRequest {
public controlledProperties?: ControlledPropertyTypes[];
public deviceTypes?: ApplicationDeviceTypeUnion[];
public permissionIds: number[];
+ public metadata?: string;
}
export interface ApplicationData {
diff --git a/src/app/shared/components/forms/form-body-application/form-body-application.component.html b/src/app/shared/components/forms/form-body-application/form-body-application.component.html
index 016b9c63..3ca3d47e 100644
--- a/src/app/shared/components/forms/form-body-application/form-body-application.component.html
+++ b/src/app/shared/components/forms/form-body-application/form-body-application.component.html
@@ -10,6 +10,12 @@
}
+
+
+
{{ "QUESTION.METADATA" | translate }}
+
+
+
}
-
-
{{ "QUESTION.METADATA" | translate }}
-
-
-
@@ -319,6 +314,11 @@
{{ "QUESTION.METADATA" | translate }}
+
+
{{ "QUESTION.METADATA" | translate }}
+
+
+
diff --git a/src/app/shared/components/forms/form-body-application/form-body-application.component.ts b/src/app/shared/components/forms/form-body-application/form-body-application.component.ts
index cd932518..9beaf3dc 100644
--- a/src/app/shared/components/forms/form-body-application/form-body-application.component.ts
+++ b/src/app/shared/components/forms/form-body-application/form-body-application.component.ts
@@ -16,8 +16,9 @@ import { SharedVariableService } from "@shared/shared-variable/shared-variable.s
import { isPhoneNumberValid } from "@shared/validators/phone-number.validator";
import { ReplaySubject, Subject, Subscription } from "rxjs";
import { takeUntil } from "rxjs/operators";
-import { jsonToList } from "@shared/helpers/json.helper";
import { keyValueListToMetadata, metadataToKeyValueList } from "@shared/helpers/metadata.helper";
+import { TranslatableError } from "@shared/translatable-error";
+import { addWarning } from "@angular-devkit/build-angular/src/utils/webpack-diagnostics";
export class User {
public name: string;
@@ -189,7 +190,12 @@ export class FormBodyApplicationComponent implements OnInit, OnDestroy {
try {
this.application.metadata = keyValueListToMetadata(this.metadataTags);
} catch (error) {
- this.handleError(this.buildErrorMessage(error.message), "application.metadata");
+ let message = error.message;
+ if (error instanceof TranslatableError) {
+ // @todo Can we safely use `instant` here?
+ message = this.translate.instant(message, error.context);
+ }
+ this.handleError(this.buildErrorMessage(message), "application.metadata");
return;
}
diff --git a/src/app/shared/helpers/metadata.helper.ts b/src/app/shared/helpers/metadata.helper.ts
index 079a8ec4..8b038448 100644
--- a/src/app/shared/helpers/metadata.helper.ts
+++ b/src/app/shared/helpers/metadata.helper.ts
@@ -1,5 +1,6 @@
import { KeyValue } from "@shared/types/tuple.type";
import { Metadata } from "@shared/types/metadata";
+import { TranslatableError } from "@shared/translatable-error";
export const metadataToKeyValueList = (metadata: object, shouldThrowOnError = false): KeyValue[] => {
try {
@@ -24,13 +25,12 @@ export const keyValueListToMetadata = (pairs: KeyValue[]): Metadata => {
const key = pair.key?.trim();
const value = pair.value?.trim();
if (!key) {
- throw new Error('Empty metadata key')
+ throw new TranslatableError("ERROR.METADATA-EMPTY-KEY");
+ } else if (key in metadata) {
+ throw new TranslatableError("ERROR.METADATA-DUPLICATE-KEY", { key });
}
if (!value) {
- throw new Error("Empty metadata value for key "+key);
- }
- if (key in metadata) {
- throw new Error("Duplicate metadata key: "+key)
+ throw new TranslatableError("ERROR.METADATA-EMPTY-VALUE", { key });
}
metadata[key] = value
}
diff --git a/src/app/shared/translatable-error.ts b/src/app/shared/translatable-error.ts
new file mode 100644
index 00000000..4e9c3258
--- /dev/null
+++ b/src/app/shared/translatable-error.ts
@@ -0,0 +1,12 @@
+import { InterpolationParameters } from "@ngx-translate/core";
+
+export class TranslatableError extends Error {
+ constructor(
+ msg: string,
+ public readonly context?: InterpolationParameters
+ ) {
+ super(msg);
+ // Set the prototype explicitly.
+ Object.setPrototypeOf(this, TranslatableError.prototype);
+ }
+}
diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json
index c2249658..97654258 100644
--- a/src/assets/i18n/da.json
+++ b/src/assets/i18n/da.json
@@ -1290,7 +1290,10 @@
"USER-INACTIVE": "Login successfuldt, men din bruger er deaktiveret i OS2IoT. Kontakt din administrator for at få tildelt rettigheder"
},
"ERROR": {
- "SEMANTIC": "Semantisk fejl, verificer at navn og værdier er på det rigtige format"
+ "SEMANTIC": "Semantisk fejl, verificer at navn og værdier er på det rigtige format",
+ "METADATA-EMPTY-KEY": "Metadatanavnet må ikke være tomt",
+ "METADATA-EMPTY-VALUE": "Metadataværdien for \"{{key}}\" må ikke være tom",
+ "METADATA-DUPLICATE-KEY": "Metadatanavnet \"{{key}}\" er allerede brugt"
},
"DIALOG": {
"SAVE.TITLE": "Slet",
From 2478d68278300c93b476a4aac7505a408c670c6b Mon Sep 17 00:00:00 2001
From: Mikkel Ricky
Date: Thu, 19 Mar 2026 16:30:36 +0100
Subject: [PATCH 4/6] Displayed application metadata
---
.../application-detail.component.html | 1 +
.../metadata-details.component.html | 16 ++++++++++++++++
.../metadata-details.component.ts | 4 ++++
src/assets/i18n/da.json | 3 ++-
4 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/src/app/applications/application-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html
index 1bff90fd..cee8771f 100644
--- a/src/app/applications/application-detail/application-detail.component.html
+++ b/src/app/applications/application-detail/application-detail.component.html
@@ -41,6 +41,7 @@ {{ "APPLICATION.DETAILS" | translate }}
[personalData]="application.personalData"
[startDate]="application.startDate"
[status]="application.status"
+ [metadata]="application.metadata"
>
diff --git a/src/app/shared/components/metadata-details/metadata-details.component.html b/src/app/shared/components/metadata-details/metadata-details.component.html
index 6b22ee26..d1d4dbba 100644
--- a/src/app/shared/components/metadata-details/metadata-details.component.html
+++ b/src/app/shared/components/metadata-details/metadata-details.component.html
@@ -69,3 +69,19 @@
>{{ deviceTypeText }}
}
+
+@if (metadata) {
+ {{ "APPLICATION.METADATA-FIELD.METADATA" | translate }}
+
+
+
+ {{ '' // @todo How can we iterate metadata (without using Object.keys }}
+ @for (key of Object.keys(metadata); track key) {
+
+ | {{ key }} |
+ {{ metadata[key]}} |
+
+ }
+
+
+}
diff --git a/src/app/shared/components/metadata-details/metadata-details.component.ts b/src/app/shared/components/metadata-details/metadata-details.component.ts
index 67ff019c..b330eddd 100644
--- a/src/app/shared/components/metadata-details/metadata-details.component.ts
+++ b/src/app/shared/components/metadata-details/metadata-details.component.ts
@@ -5,6 +5,7 @@ import { ApplicationDeviceType } from "@applications/models/application-device-t
import { TranslateService } from "@ngx-translate/core";
import { toPascalKebabCase } from "@shared/helpers/string.helper";
import { ControlledProperty } from "@shared/models/controlled-property.model";
+import { Metadata } from "@shared/types/metadata";
@Component({
selector: "app-metadata-details",
@@ -26,6 +27,7 @@ export class MetadataDetailsComponent implements OnInit {
@Input() hardware?: string;
@Input() controlledProperties?: ControlledProperty[];
@Input() deviceTypes?: ApplicationDeviceType[];
+ @Input() metadata?: Metadata;
controlledPropertyText: string;
deviceTypeText: string;
@@ -48,4 +50,6 @@ export class MetadataDetailsComponent implements OnInit {
.join(", ");
});
}
+
+ protected readonly Object = Object;
}
diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json
index 97654258..9b49cc81 100644
--- a/src/assets/i18n/da.json
+++ b/src/assets/i18n/da.json
@@ -157,7 +157,8 @@
"PERSONAL-DATA": "Persondata",
"HARDWARE": "Hardware",
"CONTROLLED-PROPERTY": "Data",
- "DEVICE-TYPE": "Forbindelsesteknologi"
+ "DEVICE-TYPE": "Forbindelsesteknologi",
+ "METADATA": "Metadata"
},
"CHANGE-ORGANIZATION": {
"TITLE": "Skift organisation",
From be54a05caea65efdc9cc1baaf313be17ee5fa51e Mon Sep 17 00:00:00 2001
From: Mikkel Ricky
Date: Fri, 27 Mar 2026 20:47:54 +0100
Subject: [PATCH 5/6] Cleaned up
---
.../form-body-application/form-body-application.component.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/app/shared/components/forms/form-body-application/form-body-application.component.ts b/src/app/shared/components/forms/form-body-application/form-body-application.component.ts
index 9beaf3dc..047567bc 100644
--- a/src/app/shared/components/forms/form-body-application/form-body-application.component.ts
+++ b/src/app/shared/components/forms/form-body-application/form-body-application.component.ts
@@ -166,8 +166,6 @@ export class FormBodyApplicationComponent implements OnInit, OnDestroy {
this.metadataTags = metadataToKeyValueList(application.metadata) ?? [];
}
- console.debug(application.metadata, this.metadataTags);
-
this.fillDefaultMetadata();
});
}
From 238e7480d0edd0e62cc3a4390c624ead90b815d3 Mon Sep 17 00:00:00 2001
From: Mikkel Ricky
Date: Fri, 27 Mar 2026 20:48:07 +0100
Subject: [PATCH 6/6] Updated metadata display
---
.../metadata-details.component.html | 23 ++++++++-----------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/src/app/shared/components/metadata-details/metadata-details.component.html b/src/app/shared/components/metadata-details/metadata-details.component.html
index d1d4dbba..e979d9fe 100644
--- a/src/app/shared/components/metadata-details/metadata-details.component.html
+++ b/src/app/shared/components/metadata-details/metadata-details.component.html
@@ -71,17 +71,14 @@
}
@if (metadata) {
- {{ "APPLICATION.METADATA-FIELD.METADATA" | translate }}
-
-
-
- {{ '' // @todo How can we iterate metadata (without using Object.keys }}
- @for (key of Object.keys(metadata); track key) {
-
- | {{ key }} |
- {{ metadata[key]}} |
-
- }
-
-
+
+ {{ "APPLICATION.METADATA-FIELD.METADATA" | translate }}
+
+ @for (key of Object.keys(metadata); track key; let i = $index) {
+
+ {{ i + 1 }}: {{ key }}
+ {{ metadata[key] }}
+
+ }
}