diff --git a/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.html b/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.html index d99ba2f..4c10a1f 100644 --- a/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.html +++ b/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.html @@ -1,7 +1,13 @@ -

Message Attributes

+
+

Message Attributes

+ +
- @if(this.attributes){ + @if(!jsonMode) { @for(entry of this.attributes | keyvalue; track entry.key){
{{entry.key}}
@@ -13,7 +19,6 @@

Message Attributes

} - }
@@ -25,10 +30,20 @@

Message Attributes

+ } @else { + + + + @if(jsonError) { +
Invalid JSON — must be an object with string values, e.g. + {{ '{' }}"key": "value"{{ '}' }}
+ } + }
+ \ No newline at end of file diff --git a/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.scss b/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.scss index 63e6e1a..0ef17ea 100644 --- a/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.scss +++ b/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.scss @@ -7,8 +7,24 @@ .row { display: flex; flex-direction: row; - justify-content: space-between; align-items: center; + gap: 8px; + + .key { + flex-shrink: 0; + width: 40%; + } + + .value { + flex: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .actions { + flex-shrink: 0; + } } .new-attribute-input { @@ -24,4 +40,35 @@ align-self: center; text-align: center; width: 100%; +} + +.dialog-header { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + gap: 16px; +} + +.json-field { + width: 100%; + + textarea { + min-height: 160px; + font-family: monospace; + font-size: 13px; + } +} + +.json-error { + color: var(--mdc-theme-error, #f44336); + font-size: 12px; + margin-top: -8px; + margin-bottom: 8px; + + code { + background: rgba(0, 0, 0, 0.06); + padding: 1px 4px; + border-radius: 3px; + } } \ No newline at end of file diff --git a/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.ts b/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.ts index 2c2dbd7..9e6f681 100644 --- a/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.ts +++ b/webapp/src/app/components/topic-details/attribute-editor/attribute-editor.component.ts @@ -25,9 +25,12 @@ import { MatFormField, MatInput } from '@angular/material/input'; styleUrl: './attribute-editor.component.scss' }) export class AttributeEditorComponent { - public attributes: { [key: string]: string } = inject(MAT_DIALOG_DATA).attributes + public attributes: { [key: string]: string } = { ...inject(MAT_DIALOG_DATA).attributes } newKeyControl = new FormControl("", Validators.required) newValueControl = new FormControl("", Validators.required) + jsonMode = false + jsonInput = new FormControl("") + jsonError = false constructor( private dialogRef: MatDialogRef @@ -49,11 +52,55 @@ export class AttributeEditorComponent { } } + toggleJsonMode() { + if (!this.jsonMode) { + // Entering JSON mode: serialize current attributes + this.jsonInput.setValue(JSON.stringify(this.attributes, null, 2)) + this.jsonError = false + this.jsonMode = true + } else { + // Leaving JSON mode: try to parse + if (this.applyJson()) { + this.jsonMode = false + } + } + } + + private applyJson(): boolean { + try { + const parsed = JSON.parse(this.jsonInput.value ?? '{}') + if (typeof parsed !== 'object' || Array.isArray(parsed)) { + this.jsonError = true + return false + } + for (const val of Object.values(parsed)) { + if (typeof val !== 'string') { + this.jsonError = true + return false + } + } + this.attributes = parsed + this.jsonError = false + return true + } catch { + this.jsonError = true + return false + } + } + + clearAll() { + this.attributes = {} + this.jsonInput.setValue('{}') + } + discardChanges() { this.dialogRef.close() } saveChanges() { + if (this.jsonMode) { + if (!this.applyJson()) return + } this.dialogRef.close(this.attributes) } } diff --git a/webapp/src/app/components/topic-details/topic-details.component.html b/webapp/src/app/components/topic-details/topic-details.component.html index 213adc6..649774c 100644 --- a/webapp/src/app/components/topic-details/topic-details.component.html +++ b/webapp/src/app/components/topic-details/topic-details.component.html @@ -3,6 +3,12 @@

Publish Message to topic: {{this.topic?.name}}

+ @if(this.attributeCount > 0) { + + }