Add Pretty/Raw toggle for webhook test response display.
Render validation JSON as a borderless key/value table in Pretty mode; keep formatted JSON in Raw mode. Made-with: Cursor
This commit is contained in:
parent
ba5a4f50c5
commit
6a3094ea19
3 changed files with 98 additions and 2 deletions
|
|
@ -450,7 +450,41 @@
|
|||
</div>
|
||||
@if (webhookTestResponsePretty) {
|
||||
<div class="col-12">
|
||||
<pre class="webhook-response-block">{{ webhookTestResponsePretty }}</pre>
|
||||
<div class="webhook-response-view-toggle">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm"
|
||||
[class.btn-secondary]="webhookTestViewMode === 'pretty'"
|
||||
[class.btn-outline-secondary]="webhookTestViewMode !== 'pretty'"
|
||||
(click)="setWebhookTestViewMode('pretty')">
|
||||
Pretty
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm"
|
||||
[class.btn-secondary]="webhookTestViewMode === 'raw'"
|
||||
[class.btn-outline-secondary]="webhookTestViewMode !== 'raw'"
|
||||
(click)="setWebhookTestViewMode('raw')">
|
||||
Raw
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (webhookTestViewMode === 'pretty') {
|
||||
<div class="webhook-response-block webhook-response-pretty">
|
||||
<table class="table table-sm table-borderless mb-0">
|
||||
<tbody>
|
||||
@for (entry of webhookTestResponseEntries; track entry.key) {
|
||||
<tr>
|
||||
<th scope="row">{{ entry.key }}:</th>
|
||||
<td>{{ entry.value }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
} @else {
|
||||
<pre class="webhook-response-block">{{ webhookTestResponseRaw }}</pre>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -255,3 +255,28 @@ main
|
|||
background: var(--bs-tertiary-bg)
|
||||
white-space: pre-wrap
|
||||
word-break: break-word
|
||||
|
||||
.webhook-response-view-toggle
|
||||
display: inline-flex
|
||||
gap: 0.35rem
|
||||
margin-top: 0.25rem
|
||||
|
||||
.webhook-response-pretty
|
||||
table
|
||||
margin: 0
|
||||
|
||||
th,
|
||||
td
|
||||
padding: 0
|
||||
border: 0
|
||||
vertical-align: top
|
||||
line-height: 1.5
|
||||
|
||||
th
|
||||
width: 170px
|
||||
font-weight: 700
|
||||
color: var(--bs-emphasis-color)
|
||||
|
||||
td
|
||||
font-weight: 400
|
||||
color: var(--bs-emphasis-color)
|
||||
|
|
|
|||
|
|
@ -112,7 +112,10 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
|||
webhookTimeoutSec = 20;
|
||||
webhookSettingsStatus = '';
|
||||
webhookTestStatus = '';
|
||||
webhookTestViewMode: 'pretty' | 'raw' = 'pretty';
|
||||
webhookTestResponseEntries: Array<{ key: string; value: string }> = [];
|
||||
webhookTestResponsePretty = '';
|
||||
webhookTestResponseRaw = '';
|
||||
settingsModalOpen = false;
|
||||
focusedRefreshMs = 3000;
|
||||
backgroundRefreshMs = 30000;
|
||||
|
|
@ -371,6 +374,9 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
|||
|
||||
testWebhookService() {
|
||||
this.webhookTestStatus = 'Testing webhook endpoint...';
|
||||
this.webhookTestViewMode = 'pretty';
|
||||
this.webhookTestResponseEntries = [];
|
||||
this.webhookTestResponseRaw = '';
|
||||
this.webhookTestResponsePretty = '';
|
||||
this.cdr.markForCheck();
|
||||
this.downloads.testWebhookSettings({
|
||||
|
|
@ -385,18 +391,49 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
const result = resp as WebhookTestResponse;
|
||||
const display = result.response ?? result;
|
||||
this.webhookTestStatus = result.message || (result.status === 'ok' ? 'Webhook test succeeded.' : 'Webhook test completed with errors.');
|
||||
this.webhookTestResponsePretty = JSON.stringify(result.response ?? result, null, 2);
|
||||
this.webhookTestResponseRaw = JSON.stringify(display, null, 2);
|
||||
this.webhookTestResponsePretty = this.webhookTestResponseRaw;
|
||||
this.webhookTestResponseEntries = this.toWebhookResponseEntries(display);
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
error: () => {
|
||||
this.webhookTestStatus = 'Webhook test failed.';
|
||||
this.webhookTestResponseEntries = [];
|
||||
this.webhookTestResponseRaw = '';
|
||||
this.webhookTestResponsePretty = '';
|
||||
this.cdr.markForCheck();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setWebhookTestViewMode(mode: 'pretty' | 'raw') {
|
||||
this.webhookTestViewMode = mode;
|
||||
}
|
||||
|
||||
private toWebhookResponseEntries(value: unknown): Array<{ key: string; value: string }> {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
return [{ key: 'value', value: this.stringifyWebhookValue(value) }];
|
||||
}
|
||||
const obj = value as Record<string, unknown>;
|
||||
return Object.entries(obj).map(([key, entryValue]) => ({
|
||||
key,
|
||||
value: this.stringifyWebhookValue(entryValue),
|
||||
}));
|
||||
}
|
||||
|
||||
private stringifyWebhookValue(value: unknown): string {
|
||||
if (value === null || value === undefined) return '';
|
||||
if (typeof value === 'string') return value;
|
||||
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
||||
try {
|
||||
return JSON.stringify(value);
|
||||
} catch {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.downloads.queueChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||
this.queueMasterCheckbox()?.selectionChanged();
|
||||
|
|
|
|||
Loading…
Reference in a new issue