Skip to content

Commit 895f048

Browse files
authored
Merge pull request #28 from NeoScript/send_attributes
Send attributes via UI
2 parents 1b1963f + bc4634d commit 895f048

8 files changed

+186
-23
lines changed

webapp/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webapp",
3-
"version": "0.0.4",
3+
"version": "0.0.5",
44
"scripts": {
55
"ng": "ng",
66
"start": "ng serve",

webapp/src/app/components/projects/projects.component.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import { SubscriptionDetailsComponent } from '../subscription-details/subscripti
1010
import { TopicDetailsComponent } from '../topic-details/topic-details.component';
1111

1212
@Component({
13-
selector: 'app-projects',
14-
templateUrl: './projects.component.html',
15-
styleUrls: ['./projects.component.scss'],
16-
standalone: true,
17-
imports: [TopicListComponent, SubscriptionListComponent, NgClass, SubscriptionDetailsComponent, TopicDetailsComponent, AsyncPipe]
13+
selector: 'app-projects',
14+
templateUrl: './projects.component.html',
15+
styleUrls: ['./projects.component.scss'],
16+
standalone: true,
17+
imports: [TopicListComponent, SubscriptionListComponent, NgClass, SubscriptionDetailsComponent, TopicDetailsComponent, AsyncPipe]
1818
})
1919
export class ProjectsComponent implements OnInit {
2020
private route = inject(ActivatedRoute);
@@ -48,11 +48,12 @@ export class ProjectsComponent implements OnInit {
4848
this.subscriptionList$ = this.pubsub.listSubscriptionsOnTopic(topic.name)
4949
}
5050

51-
handlePublishRequest(event: { topic: Topic, message: string }) {
51+
handlePublishRequest(event: { topic: Topic, message: string, attributes: { [key: string]: string } }) {
5252
console.log("publish message request:", event.message)
5353

5454
const pubsubMessage: PubsubMessage = {
55-
data: btoa(event.message)
55+
data: btoa(event.message),
56+
attributes: event.attributes
5657
}
5758

5859
this.pubsub.publishMessages(event.topic.name, [pubsubMessage]).subscribe(result => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<mat-dialog-content>
2+
<h2>Message Attributes</h2>
3+
4+
@if(this.attributes){
5+
@for(entry of this.attributes | keyvalue; track entry.key){
6+
<div class="row">
7+
<div class="key">{{entry.key}}</div>
8+
<div class="value">{{entry.value}}</div>
9+
<div class="actions">
10+
<button mat-icon-button (click)="deleteAttribute(entry.key)">
11+
<mat-icon>delete</mat-icon>
12+
</button>
13+
</div>
14+
</div>
15+
}
16+
}
17+
18+
<div class="new-attribute-input">
19+
<mat-form-field appearance="outline">
20+
<input matInput [formControl]="newKeyControl" placeholder="New Key">
21+
</mat-form-field>
22+
23+
<mat-form-field appearance="outline">
24+
<input matInput [formControl]="newValueControl" placeholder="New Value">
25+
</mat-form-field>
26+
</div>
27+
<button mat-stroked-button id="add-button" (click)="addAttribute()">Add Attribute <mat-icon>add</mat-icon></button>
28+
29+
</mat-dialog-content>
30+
31+
<mat-dialog-actions class="split-view">
32+
<button mat-flat-button (click)="discardChanges()">Cancel</button>
33+
<button mat-raised-button color="primary" (click)="saveChanges()">Save Changes</button>
34+
</mat-dialog-actions>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.split-view {
2+
display: flex;
3+
flex-direction: row;
4+
justify-content: space-between;
5+
}
6+
7+
.row {
8+
display: flex;
9+
flex-direction: row;
10+
justify-content: space-between;
11+
align-items: center;
12+
}
13+
14+
.new-attribute-input {
15+
display: flex;
16+
flex-direction: row;
17+
flex-wrap: nowrap;
18+
19+
justify-content: space-between;
20+
}
21+
22+
#add-button {
23+
justify-self: center;
24+
align-self: center;
25+
text-align: center;
26+
width: 100%;
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { AttributeEditorComponent } from './attribute-editor.component';
4+
5+
describe('AttributeEditorComponent', () => {
6+
let component: AttributeEditorComponent;
7+
let fixture: ComponentFixture<AttributeEditorComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [AttributeEditorComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(AttributeEditorComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { KeyValuePipe } from '@angular/common';
2+
import { Component, inject } from '@angular/core';
3+
import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
4+
import { MatButton, MatIconButton } from '@angular/material/button';
5+
import { MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogRef } from '@angular/material/dialog';
6+
import { MatIcon } from '@angular/material/icon';
7+
import { MatFormField, MatInput } from '@angular/material/input';
8+
9+
@Component({
10+
selector: 'app-attribute-editor',
11+
standalone: true,
12+
imports: [
13+
MatButton,
14+
MatDialogContent,
15+
MatDialogActions,
16+
KeyValuePipe,
17+
MatIcon,
18+
MatIconButton,
19+
MatInput,
20+
MatFormField,
21+
FormsModule,
22+
ReactiveFormsModule
23+
],
24+
templateUrl: './attribute-editor.component.html',
25+
styleUrl: './attribute-editor.component.scss'
26+
})
27+
export class AttributeEditorComponent {
28+
public attributes: { [key: string]: string } = inject(MAT_DIALOG_DATA).attributes
29+
newKeyControl = new FormControl<string>("", Validators.required)
30+
newValueControl = new FormControl<string>("", Validators.required)
31+
32+
constructor(
33+
private dialogRef: MatDialogRef<AttributeEditorComponent>
34+
) { }
35+
36+
deleteAttribute(key: string) {
37+
delete this.attributes[key]
38+
}
39+
40+
addAttribute() {
41+
if (this.newKeyControl.valid && this.newValueControl.valid) {
42+
const key = this.newKeyControl.value
43+
const value = this.newValueControl.value
44+
45+
this.attributes[key!] = value!
46+
47+
this.newKeyControl.reset()
48+
this.newValueControl.reset()
49+
}
50+
}
51+
52+
discardChanges() {
53+
this.dialogRef.close()
54+
}
55+
56+
saveChanges() {
57+
this.dialogRef.close(this.attributes)
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<div class="header">
22
<h3>Publish Message to topic: {{this.topic?.name}}</h3>
3+
<button mat-stroked-button color="accent" (click)="editAttributes()">
4+
Edit Attributes ({{this.attributeCount}})
5+
</button>
36
<button mat-raised-button color="primary" [disabled]="this.inputField.invalid" (click)="this.publishMessage()">
47
Publish Message!
58
<mat-icon>send</mat-icon>
@@ -8,5 +11,4 @@ <h3>Publish Message to topic: {{this.topic?.name}}</h3>
811

912
<mat-form-field appearance="outline" class="text-field">
1013
<textarea matInput [cdkTextareaAutosize]="true" cdkAutosizeMinRows="15" [formControl]="this.inputField"></textarea>
11-
</mat-form-field>
12-
14+
</mat-form-field>
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,53 @@
1-
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2-
import { UntypedFormControl, Validators, ReactiveFormsModule } from '@angular/forms';
3-
import { Topic } from 'src/app/services/pubsub.service';
1+
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
2+
import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core';
3+
import { ReactiveFormsModule, UntypedFormControl, Validators } from '@angular/forms';
44
import { MatButton } from '@angular/material/button';
5-
import { MatIcon } from '@angular/material/icon';
5+
import { MatDialog } from '@angular/material/dialog';
66
import { MatFormField } from '@angular/material/form-field';
7+
import { MatIcon } from '@angular/material/icon';
78
import { MatInput } from '@angular/material/input';
8-
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
9+
import { Topic } from 'src/app/services/pubsub.service';
10+
import { AttributeEditorComponent } from './attribute-editor/attribute-editor.component';
911

1012
@Component({
11-
selector: 'app-topic-details',
12-
templateUrl: './topic-details.component.html',
13-
styleUrls: ['./topic-details.component.scss'],
14-
standalone: true,
15-
imports: [MatButton, MatIcon, MatFormField, MatInput, CdkTextareaAutosize, ReactiveFormsModule]
13+
selector: 'app-topic-details',
14+
templateUrl: './topic-details.component.html',
15+
styleUrls: ['./topic-details.component.scss'],
16+
standalone: true,
17+
imports: [MatButton, MatIcon, MatFormField, MatInput, CdkTextareaAutosize, ReactiveFormsModule]
1618
})
1719
export class TopicDetailsComponent implements OnInit {
1820

1921
@Input() topic?: Topic
22+
@Output() onMessagePublish = new EventEmitter<{ topic: Topic, message: string, attributes: { [key: string]: string } }>()
2023

21-
@Output() onMessagePublish = new EventEmitter<{ topic: Topic, message: string }>()
22-
24+
_dialog = inject(MatDialog)
2325
public inputField = new UntypedFormControl('', Validators.required)
26+
attributes: { [key: string]: string } = {}
27+
attributeCount = 0
2428
constructor() { }
2529

2630
ngOnInit(): void {
2731
}
2832

33+
editAttributes() {
34+
let dialogRef = this._dialog.open(AttributeEditorComponent, { data: { attributes: this.attributes } })
35+
36+
dialogRef.afterClosed().subscribe(result => {
37+
if (result) {
38+
this.attributes = result
39+
this.attributeCount = Object.keys(this.attributes).length
40+
}
41+
})
42+
}
43+
2944
publishMessage() {
3045
console.log("this value was found", this.inputField.value)
3146

32-
this.onMessagePublish.emit({ topic: this.topic!, message: this.inputField.value })
47+
this.onMessagePublish.emit({ topic: this.topic!, message: this.inputField.value, attributes: this.attributes })
3348
this.inputField.reset()
49+
this.attributes = {}
50+
this.attributeCount = 0
3451
}
3552

3653
}

0 commit comments

Comments
 (0)