Skip to content
This repository was archived by the owner on Jun 18, 2023. It is now read-only.

Commit bca7d2b

Browse files
sam0r040timonback
andauthored
Feature/add message binding to channel documentation (#35)
* feat: Add new tab with message binding to channel documentation and add header and message binding example to example tab * Add message binding to the request made by PublisherService so that the backend can use the message binding to construct a message * Improve mapping of message bindings to be more resilient if a backend creates a specification without message binding * Rename Binding in example tab to Message Binding and add full payload to log statement when producing messages * Display raw message bindings Regression: Previously included mapped ui attributes chore: Improve [protocol: string]: any typings Co-authored-by: david.mueller@codecentric.de --------- Co-authored-by: Timon Back <timon.back@otto.de>
1 parent 9c3cf8e commit bca7d2b

File tree

9 files changed

+245
-83
lines changed

9 files changed

+245
-83
lines changed

src/app/channels/channel-main/channel-main.component.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ button {
3333
padding: 6px;
3434
font-weight: normal;
3535
}
36+
37+
[hidden] {
38+
display: none !important;
39+
}

src/app/channels/channel-main/channel-main.component.html

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,51 @@ <h4>{{ operation.message.description }}</h4>
77
<mat-tab-group animationDuration="0ms">
88
<mat-tab label="Example">
99
<div fxLayout="column">
10-
<textarea spellcheck="false"
11-
#exampleTextArea
12-
[rows]="exampleTextAreaLineCount"
13-
[value]="defaultExample?.value"
14-
(keyup)="recalculateLineCount('example', exampleTextArea.value)"
15-
></textarea>
10+
<div [hidden]="isEmptyObject(operation.message.bindings.get(protocolName))" fxLayout="column" fxLayoutGap="5px">
11+
<h4>Message Binding</h4>
12+
<textarea spellcheck="false"
13+
#bindingTextArea
14+
[rows]="messageBindingExampleTextAreaLineCount"
15+
[value]="createMessageBindingExample(operation.message.bindings.get(protocolName))?.value"
16+
(keyup)="recalculateLineCount('massageBindingExample', bindingTextArea.value)"
17+
></textarea>
18+
</div>
19+
<div [hidden]="!(headersExample?.lineCount > 1)" fxLayout="column" fxLayoutGap="0px">
20+
21+
<h4>Header</h4>
22+
<textarea spellcheck="false"
23+
#headersTextArea
24+
[rows]="headersTextAreaLineCount"
25+
[value]="headersExample?.value"
26+
(keyup)="recalculateLineCount('headers', headersTextArea.value)"
27+
></textarea>
28+
29+
</div>
30+
<div fxLayout="column" fxLayoutGap="5px">
31+
<h4>Message</h4>
32+
<textarea spellcheck="false"
33+
#messageTextArea
34+
[rows]="exampleTextAreaLineCount"
35+
[value]="defaultExample?.value"
36+
(keyup)="recalculateLineCount('example', messageTextArea.value)"
37+
></textarea>
38+
</div>
1639
<div fxLayout fxLayoutGap="8px">
17-
<button mat-raised-button color="primary" (click)="publish(exampleTextArea.value, headersTextArea.value)">
40+
<button mat-raised-button color="primary"
41+
(click)="publish(messageTextArea.value, headersTextArea?.value, bindingTextArea?.value)">
1842
Publish
1943
</button>
2044
<button mat-raised-button color="primary"
21-
(click)="exampleTextArea.value = defaultExample.value; exampleTextAreaLineCount=defaultExample.lineCount">
45+
(click)="
46+
messageTextArea.value = defaultExample.value;
47+
exampleTextAreaLineCount = defaultExample.lineCount || 0;
48+
headersTextArea.value = headersExample?.value;
49+
headersTextAreaLineCount = headersExample?.lineCount || 0;
50+
bindingTextArea.value = createMessageBindingExample(operation.message.bindings.get(protocolName))?.value;
51+
messageBindingExampleTextAreaLineCount = messageBindingExample?.lineCount || 0">
2252
Default
2353
</button>
24-
<button mat-raised-button color="primary" [cdkCopyToClipboard]="exampleTextArea.value">Copy</button>
54+
<button mat-raised-button color="primary" [cdkCopyToClipboard]="messageTextArea.value">Copy</button>
2555
</div>
2656
</div>
2757
</mat-tab>
@@ -43,16 +73,14 @@ <h4>
4373
</h4>
4474
<app-schema *ngIf="headers" [schema]="headers"></app-schema>
4575
<div fxLayout="column">
46-
<textarea spellcheck="false"
47-
#headersTextArea
48-
[rows]="headersTextAreaLineCount"
49-
[value]="headersExample?.value"
50-
(keyup)="recalculateLineCount('headers', headersTextArea.value)"
51-
></textarea>
76+
<app-json [json]="headersExample?.value"></app-json>
5277
</div>
5378
</mat-tab>
54-
<mat-tab label="Bindings">
79+
<mat-tab label="Operation Bindings">
5580
<app-json [data]="operation.bindings[protocolName]"></app-json>
5681
</mat-tab>
82+
<mat-tab label="Message Bindings">
83+
<app-json [data]="operation.message.rawBindings[protocolName]"></app-json>
84+
</mat-tab>
5785
</mat-tab-group>
5886
</section>

src/app/channels/channel-main/channel-main.component.ts

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Example } from 'src/app/shared/models/example.model';
44
import { Schema } from 'src/app/shared/models/schema.model';
55
import { PublisherService } from 'src/app/shared/publisher.service';
66
import { MatSnackBar } from '@angular/material/snack-bar';
7-
import { Operation } from 'src/app/shared/models/channel.model';
7+
import {MessageBinding, Operation} from 'src/app/shared/models/channel.model';
88
import { STATUS } from 'angular-in-memory-web-api';
99

1010
@Component({
@@ -27,6 +27,8 @@ export class ChannelMainComponent implements OnInit {
2727
headersExample: Example;
2828
headersTextAreaLineCount: number;
2929
protocolName: string;
30+
messageBindingExample?: Example;
31+
messageBindingExampleTextAreaLineCount: number;
3032

3133
constructor(
3234
private asyncApiService: AsyncApiService,
@@ -38,47 +40,83 @@ export class ChannelMainComponent implements OnInit {
3840
ngOnInit(): void {
3941
this.asyncApiService.getAsyncApi().subscribe(
4042
asyncapi => {
41-
let schemas: Map<string, Schema> = asyncapi.components.schemas;
42-
this.schemaName = this.operation.message.payload.name.slice(this.operation.message.payload.name.lastIndexOf('/') + 1)
43+
const schemas: Map<string, Schema> = asyncapi.components.schemas;
44+
this.schemaName = this.operation.message.payload.name.slice(this.operation.message.payload.name.lastIndexOf('/') + 1);
4345
this.schema = schemas.get(this.schemaName);
4446

4547
this.defaultExample = this.schema.example;
4648
this.exampleTextAreaLineCount = this.defaultExample?.lineCount || 0;
4749

48-
this.headersSchemaName = this.operation.message.headers.name.slice(this.operation.message.headers.name.lastIndexOf('/') + 1)
50+
this.headersSchemaName = this.operation.message.headers.name.slice(this.operation.message.headers.name.lastIndexOf('/') + 1);
4951
this.headers = schemas.get(this.headersSchemaName);
5052
this.headersExample = this.headers.example;
5153
this.headersTextAreaLineCount = this.headersExample?.lineCount || 0;
54+
this.messageBindingExampleTextAreaLineCount = this.messageBindingExample?.lineCount || 0;
5255
}
5356
);
5457

5558
this.protocolName = Object.keys(this.operation.bindings)[0];
5659
}
5760

61+
isEmptyObject(object?: any): boolean {
62+
return (object === undefined || object === null) || Object.keys(object).length === 0;
63+
}
64+
65+
createMessageBindingExample(messageBinding?: MessageBinding): Example | undefined {
66+
if (messageBinding === undefined || messageBinding === null) {
67+
return undefined;
68+
}
69+
70+
const bindingExampleObject = {};
71+
Object.keys(messageBinding).forEach((bindingKey) => {
72+
if (bindingKey !== 'bindingVersion') {
73+
bindingExampleObject[bindingKey] = this.getExampleValue(messageBinding[bindingKey]);
74+
}
75+
});
76+
77+
const bindingExample = new Example(bindingExampleObject);
78+
79+
this.messageBindingExampleTextAreaLineCount = bindingExample.lineCount;
80+
81+
return bindingExample;
82+
}
83+
84+
getExampleValue(bindingValue: string | Schema): any {
85+
if (typeof bindingValue === 'string') {
86+
return bindingValue;
87+
} else {
88+
return bindingValue.example.value;
89+
}
90+
}
91+
5892
recalculateLineCount(field: string, text: string): void {
5993
switch (field) {
6094
case 'example':
6195
this.exampleTextAreaLineCount = text.split('\n').length;
6296
break;
6397
case 'headers':
64-
this.headersTextAreaLineCount = text.split('\n').length
98+
this.headersTextAreaLineCount = text.split('\n').length;
99+
break;
100+
case 'massageBindingExample':
101+
this.messageBindingExampleTextAreaLineCount = text.split('\n').length;
65102
break;
66103
}
67104
}
68105

69-
publish(example: string, headers: string): void {
106+
publish(example: string, headers?: string, bindings?: string): void {
70107
try {
71108
const payloadJson = JSON.parse(example);
72-
const headersJson = JSON.parse(headers)
109+
const headersJson = JSON.parse(headers);
110+
const bindingsJson = JSON.parse(bindings);
73111

74-
this.publisherService.publish(this.protocolName, this.channelName, payloadJson, headersJson).subscribe(
112+
this.publisherService.publish(this.protocolName, this.channelName, payloadJson, headersJson, bindingsJson).subscribe(
75113
_ => this.handlePublishSuccess(),
76114
err => this.handlePublishError(err)
77115
);
78-
} catch(error) {
116+
} catch (error) {
79117
this.snackBar.open('Example payload is not valid', 'ERROR', {
80118
duration: 3000
81-
})
119+
});
82120
}
83121
}
84122

0 commit comments

Comments
 (0)