1import { 2 RigaDateTimeService 3} from "./chunk-RAL4KSWL.js"; 4import { 5 Clipboard 6} from "./chunk-Q4KBCFNF.js"; 7import { 8 AlertController, 9 IonBadge, 10 IonButton, 11 IonButtons, 12 IonCard, 13 IonCardContent, 14 IonCardHeader, 15 IonCardTitle, 16 IonChip, 17 IonCol, 18 IonContent, 19 IonGrid, 20 IonHeader, 21 IonInput, 22 IonItem, 23 IonLabel, 24 IonList, 25 IonMenuButton, 26 IonNote, 27 IonProgressBar, 28 IonRefresher, 29 IonRefresherContent, 30 IonRow, 31 IonSegment, 32 IonSegmentButton, 33 IonSelect, 34 IonSelectOption, 35 IonSpinner, 36 IonTextarea, 37 IonTitle, 38 IonToggle, 39 IonToolbar 40} from "./chunk-RLZ522BW.js"; 41import { 42 ToastService 43} from "./chunk-GR5DEE5Y.js"; 44import { 45 TranslateModule, 46 TranslatePipe, 47 TranslateService 48} from "./chunk-O5XYYQCR.js"; 49import { 50 ApiUrlService 51} from "./chunk-MAIAEXGG.js"; 52import "./chunk-L4O6SE3A.js"; 53import "./chunk-INK5THDW.js"; 54import { 55 NgIcon, 56 lucideActivity, 57 lucideCheck, 58 lucideChevronDown, 59 lucideChevronUp, 60 lucideCircle, 61 lucideCircleDot, 62 lucideClock, 63 lucideCopy, 64 lucideExternalLink, 65 lucideEye, 66 lucideEyeOff, 67 lucideFilter, 68 lucideFlaskConical, 69 lucidePencil, 70 lucidePlay, 71 lucidePlus, 72 lucideRefreshCw, 73 lucideRotateCw, 74 lucideTrash2, 75 lucideTriangleAlert, 76 lucideWebhook, 77 lucideX, 78 lucideZap, 79 provideIcons 80} from "./chunk-GMPIA5L4.js"; 81import { 82 CommonModule, 83 Component, 84 DecimalPipe, 85 FormBuilder, 86 FormControlName, 87 FormGroupDirective, 88 HttpClient, 89 HttpParams, 90 Injectable, 91 NgControlStatus, 92 NgControlStatusGroup, 93 ReactiveFormsModule, 94 Validators, 95 delay, 96 finalize, 97 of, 98 setClassMetadata, 99 ɵNgNoValidate, 100 ɵsetClassDebugInfo, 101 ɵɵProvidersFeature, 102 ɵɵadvance, 103 ɵɵclassProp, 104 ɵɵconditional, 105 ɵɵdefineComponent, 106 ɵɵdefineInjectable, 107 ɵɵdirectiveInject, 108 ɵɵelement, 109 ɵɵelementEnd, 110 ɵɵelementStart, 111 ɵɵgetCurrentView, 112 ɵɵinject, 113 ɵɵlistener, 114 ɵɵnextContext, 115 ɵɵpipe, 116 ɵɵpipeBind1, 117 ɵɵpipeBind2, 118 ɵɵproperty, 119 ɵɵpropertyInterpolate, 120 ɵɵrepeater, 121 ɵɵrepeaterCreate, 122 ɵɵrepeaterTrackByIdentity, 123 ɵɵresetView, 124 ɵɵrestoreView, 125 ɵɵsanitizeUrl, 126 ɵɵtemplate, 127 ɵɵtext, 128 ɵɵtextInterpolate, 129 ɵɵtextInterpolate1, 130 ɵɵtextInterpolate2 131} from "./chunk-UQ6LLOJ6.js"; 132import "./chunk-BD3NMR2S.js"; 133import "./chunk-6HPUB4U6.js"; 134import "./chunk-WGFJL45C.js"; 135import "./chunk-7WVISTDL.js"; 136import "./chunk-2S57T3GS.js"; 137import "./chunk-R4QHACMO.js"; 138import "./chunk-4MEJEBWM.js"; 139import "./chunk-RIBVNXHQ.js"; 140import "./chunk-Z42OVMMO.js"; 141import "./chunk-O5S42IXR.js"; 142import "./chunk-QBR2RTFG.js"; 143import "./chunk-MIOLVGSM.js"; 144import "./chunk-V3YFOG6Q.js"; 145import "./chunk-LPMBLWVS.js"; 146import "./chunk-5LKHIIQE.js"; 147import "./chunk-ITE2OHLM.js"; 148import "./chunk-C46CB72A.js"; 149import "./chunk-SRPSML5O.js"; 150import "./chunk-NRSVX4KN.js"; 151import "./chunk-T4GYAOTA.js"; 152import "./chunk-2VHYZHLL.js"; 153import "./chunk-S6LHOZ5A.js"; 154import "./chunk-Y6HZOH3Q.js"; 155import "./chunk-TWQHADEW.js"; 156import "./chunk-3J4L7S6G.js"; 157import "./chunk-IL42VKT6.js"; 158import "./chunk-LONO5O5R.js"; 159import "./chunk-KFBF5L4X.js"; 160import "./chunk-PWC4K6CW.js"; 161import "./chunk-R6JLIESI.js"; 162import "./chunk-UG6K57PI.js"; 163import "./chunk-UR6VIRNL.js"; 164import "./chunk-OJO5RD3M.js"; 165import { 166 __async 167} from "./chunk-CO64IJQE.js"; 168
169// src/app/pages/webhook-sandbox/webhook-mock-data.ts 170var _WebhookMockData = class _WebhookMockData { 171 static generateDeliveries() { 172 const deliveries = []; 173 const entityTypes = ["Room", "Person", "PersonRoom", "Building", "Floor"]; 174 const eventTypes = ["Created", "Updated", "Deleted"]; 175 const statuses = ["Delivered", "Delivered", "Delivered", "Delivered", "Failed", "Retrying", "Pending"]; 176 const targetUrls = [ 177 "https://med.stridenavigation.com/api/v2/webhooks/ehr", 178 "https://med.stridenavigation.com/api/nurse-station/location", 179 "https://med.stridenavigation.com/analytics/ingest" 180 ]; 181 for (let i = 0; i < 25; i++) { 182 const status = statuses[Math.floor(Math.random() * statuses.length)]; 183 const entityType = entityTypes[Math.floor(Math.random() * entityTypes.length)]; 184 const eventType = eventTypes[Math.floor(Math.random() * eventTypes.length)]; 185 const targetUrl = targetUrls[Math.floor(Math.random() * targetUrls.length)]; 186 const createdAt = new Date(Date.now() - i * 8 * 60 * 1e3); 187 const delivery = { 188 id: `mock-delivery-${i + 1}`, 189 webhookSubscriptionId: "mock-sub-1", 190 subscriptionTargetUrl: targetUrl, 191 entityType, 192 eventType, 193 entityId: `entity-${1e3 + i}`, 194 campusId: "campus-1", 195 status, 196 attemptCount: status === "Retrying" ? Math.floor(Math.random() * 4) + 1 : 1, 197 createdAt: createdAt.toISOString() 198 }; 199 if (status === "Delivered") { 200 delivery.httpStatusCode = Math.random() > 0.3 ? 200 : 201; 201 delivery.responseTimeMs = Math.floor(Math.random() * 200) + 20; 202 delivery.deliveredAt = new Date(createdAt.getTime() + delivery.responseTimeMs).toISOString(); 203 } else if (status === "Failed") { 204 delivery.httpStatusCode = [500, 502, 503, 504, 408][Math.floor(Math.random() * 5)]; 205 delivery.errorMessage = _WebhookMockData.getErrorMessage(delivery.httpStatusCode); 206 delivery.responseTimeMs = Math.floor(Math.random() * 5e3) + 1e3; 207 } else if (status === "Retrying") { 208 delivery.httpStatusCode = 503; 209 delivery.errorMessage = "Service temporarily unavailable"; 210 delivery.nextRetryAt = new Date(Date.now() + Math.floor(Math.random() * 300) * 1e3).toISOString(); 211 } 212 deliveries.push(delivery); 213 } 214 return deliveries; 215 } 216 static getErrorMessage(statusCode) { 217 const messages = { 218 500: "Internal server error: upstream service crashed", 219 502: "Bad gateway: load balancer could not reach backend", 220 503: "Service unavailable: server is under maintenance", 221 504: "Gateway timeout: request exceeded 30s limit", 222 408: "Request timeout: connection timed out after 10s" 223 }; 224 return messages[statusCode] || "Unknown error"; 225 } 226 static getSubscriptions() { 227 return { 228 items: [...this.MOCK_SUBSCRIPTIONS], 229 totalCount: this.MOCK_SUBSCRIPTIONS.length, 230 page: 1, 231 pageSize: 100, 232 totalPages: 1, 233 hasNextPage: false, 234 hasPreviousPage: false 235 }; 236 } 237 static getDeliveries(status, page = 1, pageSize = 20) { 238 let items = this.generateDeliveries(); 239 if (status && status !== "all") { 240 items = items.filter((d) => d.status === status); 241 } 242 const start = (page - 1) * pageSize; 243 const paginatedItems = items.slice(start, start + pageSize); 244 return { 245 items: paginatedItems, 246 totalCount: items.length, 247 page, 248 pageSize, 249 totalPages: Math.ceil(items.length / pageSize), 250 hasNextPage: start + pageSize < items.length, 251 hasPreviousPage: page > 1 252 }; 253 } 254 static getStats() { 255 return { 256 subscriptions: { 257 total: 4, 258 active: 3, 259 circuitOpen: 1 260 }, 261 deliveries: { 262 last24Hours: { 263 total: 1247, 264 delivered: 1176, 265 failed: 42, 266 retrying: 18, 267 pending: 11 268 }, 269 last7Days: { 270 total: 8432, 271 delivered: 7891, 272 failed: 541 273 } 274 }, 275 events: { 276 pending: 23, 277 processedLast24Hours: 4521 278 } 279 }; 280 } 281}; 282_WebhookMockData.MOCK_SUBSCRIPTIONS = [ 283 { 284 id: "mock-sub-1", 285 targetUrl: "https://med.stridenavigation.com/api/v2/webhooks/ehr", 286 description: "EHR patient location sync - production", 287 entityTypes: ["Room", "Person", "PersonRoom"], 288 eventTypes: ["Created", "Updated", "Deleted"], 289 isActive: true, 290 secretPrefix: "whsec_prod", 291 totalDeliveries: 1247, 292 totalFailures: 42, 293 consecutiveFailures: 0, 294 lastDeliveryAt: new Date(Date.now() - 2 * 60 * 1e3).toISOString(), 295 lastSuccessAt: new Date(Date.now() - 2 * 60 * 1e3).toISOString(), 296 createdAt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString(), 297 apiKeyName: "EHR Integration Key" 298 }, 299 { 300 id: "mock-sub-2", 301 targetUrl: "https://med.stridenavigation.com/api/nurse-station/location", 302 description: "Nurse station display - real-time updates", 303 entityTypes: ["PersonRoom"], 304 eventTypes: ["Created", "Updated"], 305 isActive: true, 306 secretPrefix: "whsec_nurse", 307 totalDeliveries: 3891, 308 totalFailures: 12, 309 consecutiveFailures: 0, 310 lastDeliveryAt: new Date(Date.now() - 45 * 1e3).toISOString(), 311 lastSuccessAt: new Date(Date.now() - 45 * 1e3).toISOString(), 312 createdAt: new Date(Date.now() - 14 * 24 * 60 * 60 * 1e3).toISOString(), 313 apiKeyName: "Nurse Station API" 314 }, 315 { 316 id: "mock-sub-3", 317 targetUrl: "https://med.stridenavigation.com/legacy/webhook-bridge", 318 description: "Legacy system bridge (deprecated)", 319 entityTypes: ["Room", "Building", "Floor"], 320 eventTypes: ["Updated"], 321 isActive: false, 322 secretPrefix: "whsec_legacy", 323 totalDeliveries: 156, 324 totalFailures: 89, 325 consecutiveFailures: 5, 326 lastDeliveryAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1e3).toISOString(), 327 lastSuccessAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString(), 328 circuitBrokenUntil: new Date(Date.now() + 15 * 60 * 1e3).toISOString(), 329 createdAt: new Date(Date.now() - 90 * 24 * 60 * 60 * 1e3).toISOString(), 330 apiKeyName: "Legacy Bridge" 331 }, 332 { 333 id: "mock-sub-4", 334 targetUrl: "https://med.stridenavigation.com/analytics/ingest", 335 description: "Analytics data pipeline", 336 entityTypes: ["Room", "Person", "PersonRoom", "Building", "Floor"], 337 eventTypes: ["Created", "Updated", "Deleted"], 338 isActive: true, 339 secretPrefix: "whsec_analytics", 340 totalDeliveries: 8432, 341 totalFailures: 23, 342 consecutiveFailures: 0, 343 lastDeliveryAt: new Date(Date.now() - 5 * 60 * 1e3).toISOString(), 344 lastSuccessAt: new Date(Date.now() - 5 * 60 * 1e3).toISOString(), 345 createdAt: new Date(Date.now() - 60 * 24 * 60 * 60 * 1e3).toISOString(), 346 apiKeyName: "Analytics Pipeline" 347 } 348]; 349var WebhookMockData = _WebhookMockData; 350
351// src/app/services/webhook/webhook.models.ts 352var ENTITY_TYPES = ["Room", "Person", "PersonRoom", "Building", "Floor"]; 353var EVENT_TYPES = ["Created", "Updated", "Deleted"]; 354
355// src/app/services/webhook/webhook.service.ts 356var _WebhookService = class _WebhookService { 357 constructor(http, apiUrlService) { 358 this.http = http; 359 this.apiUrlService = apiUrlService; 360 this.adminBaseUrl = this.apiUrlService.getSelectedUrl() + "/api/admin/webhooks"; 361 this.apiUrlService.selectedUrl$.subscribe((url) => { 362 this.adminBaseUrl = url + "/api/admin/webhooks"; 363 }); 364 } 365 // Subscriptions 366 getSubscriptions(params) { 367 let httpParams = new HttpParams(); 368 if (params) { 369 if (params.apiKeyId) 370 httpParams = httpParams.set("apiKeyId", params.apiKeyId); 371 if (params.isActive !== void 0) 372 httpParams = httpParams.set("isActive", params.isActive.toString()); 373 if (params.page) 374 httpParams = httpParams.set("page", params.page.toString()); 375 if (params.pageSize) 376 httpParams = httpParams.set("pageSize", params.pageSize.toString()); 377 } 378 return this.http.get(`${this.adminBaseUrl}/subscriptions`, { params: httpParams }); 379 } 380 getSubscription(id) { 381 return this.http.get(`${this.adminBaseUrl}/subscriptions/${id}`); 382 } 383 createSubscription(request) { 384 return this.http.post(`${this.adminBaseUrl}/subscriptions`, request); 385 } 386 updateSubscription(id, request) { 387 return this.http.put(`${this.adminBaseUrl}/subscriptions/${id}`, request); 388 } 389 deleteSubscription(id) { 390 return this.http.delete(`${this.adminBaseUrl}/subscriptions/${id}`); 391 } 392 testSubscription(id) { 393 return this.http.post(`${this.adminBaseUrl}/subscriptions/${id}/test`, {}); 394 } 395 resetCircuitBreaker(id) { 396 return this.http.post(`${this.adminBaseUrl}/subscriptions/${id}/reset-circuit`, {}); 397 } 398 // Deliveries 399 getDeliveries(params) { 400 let httpParams = new HttpParams(); 401 if (params) { 402 if (params.subscriptionId) 403 httpParams = httpParams.set("subscriptionId", params.subscriptionId); 404 if (params.status) 405 httpParams = httpParams.set("status", params.status); 406 if (params.entityType) 407 httpParams = httpParams.set("entityType", params.entityType); 408 if (params.from) 409 httpParams = httpParams.set("from", params.from); 410 if (params.to) 411 httpParams = httpParams.set("to", params.to); 412 if (params.page) 413 httpParams = httpParams.set("page", params.page.toString()); 414 if (params.pageSize) 415 httpParams = httpParams.set("pageSize", params.pageSize.toString()); 416 } 417 return this.http.get(`${this.adminBaseUrl}/deliveries`, { params: httpParams }); 418 } 419 retryDelivery(id) { 420 return this.http.post(`${this.adminBaseUrl}/deliveries/${id}/retry`, {}); 421 } 422 // Statistics 423 getStats() { 424 return this.http.get(`${this.adminBaseUrl}/stats`); 425 } 426}; 427_WebhookService.\u0275fac = function WebhookService_Factory(__ngFactoryType__) { 428 return new (__ngFactoryType__ || _WebhookService)(\u0275\u0275inject(HttpClient), \u0275\u0275inject(ApiUrlService)); 429}; 430_WebhookService.\u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _WebhookService, factory: _WebhookService.\u0275fac, providedIn: "root" }); 431var WebhookService = _WebhookService; 432(() => { 433 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(WebhookService, [{ 434 type: Injectable, 435 args: [{ 436 providedIn: "root" 437 }] 438 }], () => [{ type: HttpClient }, { type: ApiUrlService }], null); 439})(); 440
441// src/app/pages/webhook-sandbox/webhook-sandbox.page.ts 442var _forTrack0 = ($index, $item) => $item.id; 443function WebhookSandboxPage_Conditional_30_Conditional_1_Template(rf, ctx) { 444 if (rf & 1) { 445 \u0275\u0275elementStart(0, "div", 14); 446 \u0275\u0275element(1, "ion-spinner", 19); 447 \u0275\u0275elementEnd(); 448 } 449} 450function WebhookSandboxPage_Conditional_30_Conditional_2_Template(rf, ctx) { 451 if (rf & 1) { 452 \u0275\u0275elementStart(0, "div", 15); 453 \u0275\u0275element(1, "ng-icon", 20); 454 \u0275\u0275elementStart(2, "p"); 455 \u0275\u0275text(3); 456 \u0275\u0275pipe(4, "translate"); 457 \u0275\u0275elementEnd()(); 458 } 459 if (rf & 2) { 460 \u0275\u0275advance(3); 461 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(4, 1, "webhookSandbox.subscriptions.noSubscriptions")); 462 } 463} 464function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_14_Template(rf, ctx) { 465 if (rf & 1) { 466 \u0275\u0275element(0, "ng-icon", 32); 467 } 468} 469function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_15_Template(rf, ctx) { 470 if (rf & 1) { 471 \u0275\u0275element(0, "ng-icon", 33); 472 } 473} 474function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_16_Template(rf, ctx) { 475 if (rf & 1) { 476 \u0275\u0275elementStart(0, "ion-card-title", 34); 477 \u0275\u0275text(1); 478 \u0275\u0275elementEnd(); 479 } 480 if (rf & 2) { 481 const sub_r3 = \u0275\u0275nextContext().$implicit; 482 \u0275\u0275advance(); 483 \u0275\u0275textInterpolate(sub_r3.description); 484 } 485} 486function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_For_21_Template(rf, ctx) { 487 if (rf & 1) { 488 \u0275\u0275elementStart(0, "ion-chip", 37); 489 \u0275\u0275text(1); 490 \u0275\u0275pipe(2, "translate"); 491 \u0275\u0275elementEnd(); 492 } 493 if (rf & 2) { 494 const et_r5 = ctx.$implicit; 495 \u0275\u0275advance(); 496 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(2, 1, "webhookSandbox.entityTypes." + et_r5)); 497 } 498} 499function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_For_26_Template(rf, ctx) { 500 if (rf & 1) { 501 \u0275\u0275elementStart(0, "ion-chip", 39); 502 \u0275\u0275text(1); 503 \u0275\u0275pipe(2, "translate"); 504 \u0275\u0275elementEnd(); 505 } 506 if (rf & 2) { 507 const evt_r6 = ctx.$implicit; 508 \u0275\u0275advance(); 509 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(2, 1, "webhookSandbox.eventTypes." + evt_r6)); 510 } 511} 512function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_28_Template(rf, ctx) { 513 if (rf & 1) { 514 \u0275\u0275elementStart(0, "ion-badge", 41); 515 \u0275\u0275element(1, "ng-icon", 47); 516 \u0275\u0275text(2); 517 \u0275\u0275pipe(3, "translate"); 518 \u0275\u0275elementEnd(); 519 } 520 if (rf & 2) { 521 const sub_r3 = \u0275\u0275nextContext().$implicit; 522 const ctx_r3 = \u0275\u0275nextContext(3); 523 \u0275\u0275advance(2); 524 \u0275\u0275textInterpolate2(" ", \u0275\u0275pipeBind1(3, 2, "webhookSandbox.subscriptions.circuitOpen"), " (", ctx_r3.getCircuitOpenUntil(sub_r3), ") "); 525 } 526} 527function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_29_Template(rf, ctx) { 528 if (rf & 1) { 529 \u0275\u0275elementStart(0, "ion-badge", 42); 530 \u0275\u0275element(1, "ng-icon", 48); 531 \u0275\u0275text(2); 532 \u0275\u0275pipe(3, "translate"); 533 \u0275\u0275elementEnd(); 534 } 535 if (rf & 2) { 536 \u0275\u0275advance(2); 537 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(3, 1, "webhookSandbox.subscriptions.active"), " "); 538 } 539} 540function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_30_Template(rf, ctx) { 541 if (rf & 1) { 542 \u0275\u0275elementStart(0, "ion-badge", 43); 543 \u0275\u0275text(1); 544 \u0275\u0275pipe(2, "translate"); 545 \u0275\u0275elementEnd(); 546 } 547 if (rf & 2) { 548 \u0275\u0275advance(); 549 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(2, 1, "webhookSandbox.subscriptions.inactive"), " "); 550 } 551} 552function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_33_Template(rf, ctx) { 553 if (rf & 1) { 554 \u0275\u0275elementStart(0, "span", 45); 555 \u0275\u0275text(1); 556 \u0275\u0275elementEnd(); 557 } 558 if (rf & 2) { 559 const sub_r3 = \u0275\u0275nextContext().$implicit; 560 \u0275\u0275advance(); 561 \u0275\u0275textInterpolate1("", sub_r3.totalFailures, " failed"); 562 } 563} 564function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_6_Template(rf, ctx) { 565 if (rf & 1) { 566 \u0275\u0275elementStart(0, "p", 51); 567 \u0275\u0275text(1); 568 \u0275\u0275elementEnd(); 569 } 570 if (rf & 2) { 571 const sub_r3 = \u0275\u0275nextContext(2).$implicit; 572 const ctx_r3 = \u0275\u0275nextContext(3); 573 \u0275\u0275advance(); 574 \u0275\u0275textInterpolate1("Last delivery: ", ctx_r3.formatTimeAgo(sub_r3.lastDeliveryAt), ""); 575 } 576} 577function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_7_Template(rf, ctx) { 578 if (rf & 1) { 579 \u0275\u0275elementStart(0, "p", 51); 580 \u0275\u0275text(1); 581 \u0275\u0275elementEnd(); 582 } 583 if (rf & 2) { 584 const sub_r3 = \u0275\u0275nextContext(2).$implicit; 585 const ctx_r3 = \u0275\u0275nextContext(3); 586 \u0275\u0275advance(); 587 \u0275\u0275textInterpolate1("Last success: ", ctx_r3.formatTimeAgo(sub_r3.lastSuccessAt), ""); 588 } 589} 590function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_8_Template(rf, ctx) { 591 if (rf & 1) { 592 \u0275\u0275elementStart(0, "p", 51); 593 \u0275\u0275text(1); 594 \u0275\u0275elementEnd(); 595 } 596 if (rf & 2) { 597 const sub_r3 = \u0275\u0275nextContext(2).$implicit; 598 \u0275\u0275advance(); 599 \u0275\u0275textInterpolate1("Secret: ", sub_r3.secretPrefix, "..."); 600 } 601} 602function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_10_Template(rf, ctx) { 603 if (rf & 1) { 604 const _r8 = \u0275\u0275getCurrentView(); 605 \u0275\u0275elementStart(0, "ion-button", 56); 606 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_10_Template_ion_button_click_0_listener() { 607 \u0275\u0275restoreView(_r8); 608 const sub_r3 = \u0275\u0275nextContext(2).$implicit; 609 const ctx_r3 = \u0275\u0275nextContext(3);
610 return \u0275\u0275resetView(ctx_r3.resetCircuitBreaker(sub_r3)); 611 }); 612 \u0275\u0275element(1, "ng-icon", 57); 613 \u0275\u0275text(2, " Reset Circuit "); 614 \u0275\u0275elementEnd(); 615 } 616} 617function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Template(rf, ctx) { 618 if (rf & 1) { 619 const _r7 = \u0275\u0275getCurrentView(); 620 \u0275\u0275elementStart(0, "div", 46)(1, "ion-item", 49)(2, "ion-label"); 621 \u0275\u0275text(3); 622 \u0275\u0275pipe(4, "translate"); 623 \u0275\u0275elementEnd(); 624 \u0275\u0275elementStart(5, "ion-toggle", 50); 625 \u0275\u0275listener("ionChange", function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Template_ion_toggle_ionChange_5_listener() { 626 \u0275\u0275restoreView(_r7); 627 const sub_r3 = \u0275\u0275nextContext().$implicit; 628 const ctx_r3 = \u0275\u0275nextContext(3); 629 return \u0275\u0275resetView(ctx_r3.toggleSubscriptionActive(sub_r3)); 630 }); 631 \u0275\u0275elementEnd()(); 632 \u0275\u0275template(6, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_6_Template, 2, 1, "p", 51)(7, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_7_Template, 2, 1, "p", 51)(8, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_8_Template, 2, 1, "p", 51); 633 \u0275\u0275elementStart(9, "div", 52); 634 \u0275\u0275template(10, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Conditional_10_Template, 3, 0, "ion-button", 53); 635 \u0275\u0275elementStart(11, "ion-button", 54); 636 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Template_ion_button_click_11_listener() { 637 \u0275\u0275restoreView(_r7); 638 const sub_r3 = \u0275\u0275nextContext().$implicit; 639 const ctx_r3 = \u0275\u0275nextContext(3); 640 return \u0275\u0275resetView(ctx_r3.confirmDeleteSubscription(sub_r3)); 641 }); 642 \u0275\u0275element(12, "ng-icon", 55); 643 \u0275\u0275text(13); 644 \u0275\u0275pipe(14, "translate"); 645 \u0275\u0275elementEnd()()(); 646 } 647 if (rf & 2) { 648 const sub_r3 = \u0275\u0275nextContext().$implicit; 649 const ctx_r3 = \u0275\u0275nextContext(3); 650 \u0275\u0275advance(3); 651 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(4, 7, "webhookSandbox.subscriptions.active")); 652 \u0275\u0275advance(2); 653 \u0275\u0275property("checked", sub_r3.isActive); 654 \u0275\u0275advance(); 655 \u0275\u0275conditional(sub_r3.lastDeliveryAt ? 6 : -1); 656 \u0275\u0275advance(); 657 \u0275\u0275conditional(sub_r3.lastSuccessAt ? 7 : -1); 658 \u0275\u0275advance(); 659 \u0275\u0275conditional(sub_r3.secretPrefix ? 8 : -1); 660 \u0275\u0275advance(2); 661 \u0275\u0275conditional(ctx_r3.isCircuitOpen(sub_r3) ? 10 : -1); 662 \u0275\u0275advance(3); 663 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(14, 9, "webhookSandbox.subscriptions.delete"), " "); 664 } 665} 666function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Template(rf, ctx) { 667 if (rf & 1) { 668 const _r2 = \u0275\u0275getCurrentView(); 669 \u0275\u0275elementStart(0, "ion-card", 22)(1, "ion-card-header")(2, "div", 23)(3, "div", 24)(4, "span", 25); 670 \u0275\u0275text(5); 671 \u0275\u0275elementEnd(); 672 \u0275\u0275elementStart(6, "a", 26); 673 \u0275\u0275element(7, "ng-icon", 27); 674 \u0275\u0275elementEnd()(); 675 \u0275\u0275elementStart(8, "div", 28)(9, "ion-button", 29); 676 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Template_ion_button_click_9_listener() { 677 const sub_r3 = \u0275\u0275restoreView(_r2).$implicit; 678 const ctx_r3 = \u0275\u0275nextContext(3); 679 return \u0275\u0275resetView(ctx_r3.testSubscription(sub_r3)); 680 }); 681 \u0275\u0275element(10, "ng-icon", 30); 682 \u0275\u0275elementEnd(); 683 \u0275\u0275elementStart(11, "ion-button", 29); 684 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Template_ion_button_click_11_listener() { 685 const sub_r3 = \u0275\u0275restoreView(_r2).$implicit; 686 const ctx_r3 = \u0275\u0275nextContext(3);
687 return \u0275\u0275resetView(ctx_r3.openEditForm(sub_r3)); 688 }); 689 \u0275\u0275element(12, "ng-icon", 31); 690 \u0275\u0275elementEnd(); 691 \u0275\u0275elementStart(13, "ion-button", 29); 692 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Template_ion_button_click_13_listener() { 693 const sub_r3 = \u0275\u0275restoreView(_r2).$implicit; 694 const ctx_r3 = \u0275\u0275nextContext(3); 695 return \u0275\u0275resetView(ctx_r3.toggleSubscriptionExpand(sub_r3.id)); 696 }); 697 \u0275\u0275template(14, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_14_Template, 1, 0, "ng-icon", 32)(15, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_15_Template, 1, 0, "ng-icon", 33); 698 \u0275\u0275elementEnd()()(); 699 \u0275\u0275template(16, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_16_Template, 2, 1, "ion-card-title", 34); 700 \u0275\u0275elementEnd(); 701 \u0275\u0275elementStart(17, "ion-card-content")(18, "div", 35)(19, "div", 36); 702 \u0275\u0275repeaterCreate(20, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_For_21_Template, 3, 3, "ion-chip", 37, \u0275\u0275repeaterTrackByIdentity); 703 \u0275\u0275elementEnd(); 704 \u0275\u0275elementStart(22, "span", 38); 705 \u0275\u0275text(23, "|"); 706 \u0275\u0275elementEnd(); 707 \u0275\u0275elementStart(24, "div", 36); 708 \u0275\u0275repeaterCreate(25, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_For_26_Template, 3, 3, "ion-chip", 39, \u0275\u0275repeaterTrackByIdentity); 709 \u0275\u0275elementEnd()(); 710 \u0275\u0275elementStart(27, "div", 40); 711 \u0275\u0275template(28, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_28_Template, 4, 4, "ion-badge", 41)(29, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_29_Template, 4, 3, "ion-badge", 42)(30, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_30_Template, 3, 3, "ion-badge", 43); 712 \u0275\u0275elementStart(31, "span", 44); 713 \u0275\u0275text(32); 714 \u0275\u0275elementEnd(); 715 \u0275\u0275template(33, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_33_Template, 2, 1, "span", 45); 716 \u0275\u0275elementEnd(); 717 \u0275\u0275template(34, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Conditional_34_Template, 15, 11, "div", 46); 718 \u0275\u0275elementEnd()(); 719 } 720 if (rf & 2) { 721 const sub_r3 = ctx.$implicit; 722 const ctx_r3 = \u0275\u0275nextContext(3); 723 \u0275\u0275classProp("circuit-open", ctx_r3.isCircuitOpen(sub_r3)); 724 \u0275\u0275advance(5); 725 \u0275\u0275textInterpolate(sub_r3.targetUrl); 726 \u0275\u0275advance(); 727 \u0275\u0275property("href", sub_r3.targetUrl, \u0275\u0275sanitizeUrl); 728 \u0275\u0275advance(8); 729 \u0275\u0275conditional(ctx_r3.expandedSubscriptionId === sub_r3.id ? 14 : 15); 730 \u0275\u0275advance(2); 731 \u0275\u0275conditional(sub_r3.description ? 16 : -1); 732 \u0275\u0275advance(4); 733 \u0275\u0275repeater(sub_r3.entityTypes); 734 \u0275\u0275advance(5); 735 \u0275\u0275repeater(sub_r3.eventTypes); 736 \u0275\u0275advance(3); 737 \u0275\u0275conditional(ctx_r3.isCircuitOpen(sub_r3) ? 28 : sub_r3.isActive ? 29 : 30); 738 \u0275\u0275advance(4); 739 \u0275\u0275textInterpolate1("", sub_r3.totalDeliveries, " delivered"); 740 \u0275\u0275advance(); 741 \u0275\u0275conditional(sub_r3.totalFailures > 0 ? 33 : -1); 742 \u0275\u0275advance(); 743 \u0275\u0275conditional(ctx_r3.expandedSubscriptionId === sub_r3.id ? 34 : -1); 744 } 745} 746function WebhookSandboxPage_Conditional_30_Conditional_3_Template(rf, ctx) { 747 if (rf & 1) { 748 \u0275\u0275elementStart(0, "ion-list"); 749 \u0275\u0275repeaterCreate(1, WebhookSandboxPage_Conditional_30_Conditional_3_For_2_Template, 35, 10, "ion-card", 21, _forTrack0); 750 \u0275\u0275elementEnd(); 751 } 752 if (rf & 2) { 753 const ctx_r3 = \u0275\u0275nextContext(2); 754 \u0275\u0275advance(); 755 \u0275\u0275repeater(ctx_r3.subscriptions); 756 } 757} 758function WebhookSandboxPage_Conditional_30_Template(rf, ctx) { 759 if (rf & 1) { 760 const _r1 = \u0275\u0275getCurrentView(); 761 \u0275\u0275elementStart(0, "div", 12); 762 \u0275\u0275template(1, WebhookSandboxPage_Conditional_30_Conditional_1_Template, 2, 0, "div", 14)(2, WebhookSandboxPage_Conditional_30_Conditional_2_Template, 5, 3, "div", 15)(3, WebhookSandboxPage_Conditional_30_Conditional_3_Template, 3, 0, "ion-list"); 763 \u0275\u0275elementStart(4, "div", 16)(5, "ion-button", 17); 764 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_30_Template_ion_button_click_5_listener() { 765 \u0275\u0275restoreView(_r1); 766 const ctx_r3 = \u0275\u0275nextContext();
767 return \u0275\u0275resetView(ctx_r3.openCreateForm()); 768 }); 769 \u0275\u0275element(6, "ng-icon", 18); 770 \u0275\u0275text(7); 771 \u0275\u0275pipe(8, "translate"); 772 \u0275\u0275elementEnd()()(); 773 } 774 if (rf & 2) { 775 const ctx_r3 = \u0275\u0275nextContext(); 776 \u0275\u0275advance(); 777 \u0275\u0275conditional(ctx_r3.isLoadingSubscriptions ? 1 : ctx_r3.subscriptions.length === 0 ? 2 : 3); 778 \u0275\u0275advance(6); 779 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(8, 2, "webhookSandbox.subscriptions.create"), " "); 780 } 781} 782function WebhookSandboxPage_Conditional_31_Conditional_19_Template(rf, ctx) { 783 if (rf & 1) { 784 \u0275\u0275elementStart(0, "div", 14); 785 \u0275\u0275element(1, "ion-spinner", 19); 786 \u0275\u0275elementEnd(); 787 } 788} 789function WebhookSandboxPage_Conditional_31_Conditional_20_Template(rf, ctx) { 790 if (rf & 1) { 791 \u0275\u0275elementStart(0, "div", 15); 792 \u0275\u0275element(1, "ng-icon", 65); 793 \u0275\u0275elementStart(2, "p"); 794 \u0275\u0275text(3); 795 \u0275\u0275pipe(4, "translate"); 796 \u0275\u0275elementEnd()(); 797 } 798 if (rf & 2) { 799 \u0275\u0275advance(3); 800 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(4, 1, "webhookSandbox.deliveries.noDeliveries")); 801 } 802} 803function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_6_Template(rf, ctx) { 804 if (rf & 1) { 805 \u0275\u0275element(0, "ng-icon", 48); 806 } 807} 808function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_7_Template(rf, ctx) { 809 if (rf & 1) { 810 \u0275\u0275element(0, "ng-icon", 71); 811 } 812} 813function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_8_Template(rf, ctx) { 814 if (rf & 1) { 815 \u0275\u0275element(0, "ng-icon", 72); 816 } 817} 818function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_9_Template(rf, ctx) { 819 if (rf & 1) { 820 \u0275\u0275element(0, "ng-icon", 73); 821 } 822} 823function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_11_Template(rf, ctx) { 824 if (rf & 1) { 825 \u0275\u0275text(0); 826 } 827 if (rf & 2) { 828 const delivery_r10 = \u0275\u0275nextContext().$implicit; 829 \u0275\u0275textInterpolate1(" (", delivery_r10.httpStatusCode, ") "); 830 } 831} 832function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_13_Template(rf, ctx) { 833 if (rf & 1) { 834 \u0275\u0275elementStart(0, "span", 75); 835 \u0275\u0275text(1); 836 \u0275\u0275elementEnd(); 837 } 838 if (rf & 2) { 839 const delivery_r10 = \u0275\u0275nextContext().$implicit; 840 \u0275\u0275advance(); 841 \u0275\u0275textInterpolate(delivery_r10.subscriptionTargetUrl); 842 } 843} 844function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_14_Template(rf, ctx) { 845 if (rf & 1) { 846 \u0275\u0275elementStart(0, "span", 76); 847 \u0275\u0275text(1); 848 \u0275\u0275elementEnd(); 849 } 850 if (rf & 2) { 851 const delivery_r10 = \u0275\u0275nextContext().$implicit; 852 \u0275\u0275advance(); 853 \u0275\u0275textInterpolate1("", delivery_r10.responseTimeMs, "ms"); 854 } 855} 856function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_17_Template(rf, ctx) { 857 if (rf & 1) { 858 \u0275\u0275elementStart(0, "div", 78); 859 \u0275\u0275text(1); 860 \u0275\u0275elementEnd(); 861 } 862 if (rf & 2) { 863 const delivery_r10 = \u0275\u0275nextContext().$implicit; 864 \u0275\u0275advance(); 865 \u0275\u0275textInterpolate(delivery_r10.errorMessage); 866 } 867} 868function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_18_Template(rf, ctx) { 869 if (rf & 1) { 870 const _r11 = \u0275\u0275getCurrentView(); 871 \u0275\u0275elementStart(0, "ion-button", 81); 872 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_18_Template_ion_button_click_0_listener() { 873 \u0275\u0275restoreView(_r11); 874 const delivery_r10 = \u0275\u0275nextContext().$implicit; 875 const ctx_r3 = \u0275\u0275nextContext(3); 876 return \u0275\u0275resetView(ctx_r3.retryDelivery(delivery_r10)); 877 }); 878 \u0275\u0275element(1, "ng-icon", 57); 879 \u0275\u0275text(2); 880 \u0275\u0275pipe(3, "translate"); 881 \u0275\u0275elementEnd(); 882 } 883 if (rf & 2) { 884 \u0275\u0275advance(2); 885 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(3, 1, "webhookSandbox.deliveries.retry"), " "); 886 } 887} 888function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_19_Template(rf, ctx) { 889 if (rf & 1) { 890 \u0275\u0275elementStart(0, "div", 80); 891 \u0275\u0275text(1); 892 \u0275\u0275elementEnd(); 893 } 894 if (rf & 2) { 895 const delivery_r10 = \u0275\u0275nextContext().$implicit; 896 const ctx_r3 = \u0275\u0275nextContext(3); 897 \u0275\u0275advance(); 898 \u0275\u0275textInterpolate2(" Attempt ", delivery_r10.attemptCount, "/8 | Next: ", ctx_r3.formatTimeAgo(delivery_r10.nextRetryAt), " "); 899 } 900} 901function WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Template(rf, ctx) { 902 if (rf & 1) { 903 \u0275\u0275elementStart(0, "ion-item")(1, "div", 67)(2, "div", 68)(3, "span", 69); 904 \u0275\u0275text(4); 905 \u0275\u0275elementEnd(); 906 \u0275\u0275elementStart(5, "ion-badge", 70); 907 \u0275\u0275template(6, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_6_Template, 1, 0, "ng-icon", 48)(7, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_7_Template, 1, 0, "ng-icon", 71)(8, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_8_Template, 1, 0, "ng-icon", 72)(9, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_9_Template, 1, 0, "ng-icon", 73); 908 \u0275\u0275text(10); 909 \u0275\u0275template(11, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_11_Template, 1, 1); 910 \u0275\u0275elementEnd()(); 911 \u0275\u0275elementStart(12, "div", 74); 912 \u0275\u0275template(13, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_13_Template, 2, 1, "span", 75)(14, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_14_Template, 2, 1, "span", 76); 913 \u0275\u0275elementStart(15, "span", 77); 914 \u0275\u0275text(16); 915 \u0275\u0275elementEnd()(); 916 \u0275\u0275template(17, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_17_Template, 2, 1, "div", 78)(18, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_18_Template, 4, 3, "ion-button", 79)(19, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Conditional_19_Template, 2, 2, "div", 80); 917 \u0275\u0275elementEnd()(); 918 } 919 if (rf & 2) { 920 const delivery_r10 = ctx.$implicit; 921 const ctx_r3 = \u0275\u0275nextContext(3); 922 \u0275\u0275advance(4); 923 \u0275\u0275textInterpolate2("", delivery_r10.entityType, ".", delivery_r10.eventType, ""); 924 \u0275\u0275advance(); 925 \u0275\u0275property("color", ctx_r3.getDeliveryStatusColor(delivery_r10.status)); 926 \u0275\u0275advance(); 927 \u0275\u0275conditional(delivery_r10.status === "Delivered" ? 6 : delivery_r10.status === "Failed" ? 7 : delivery_r10.status === "Retrying" ? 8 : 9); 928 \u0275\u0275advance(4); 929 \u0275\u0275textInterpolate1(" ", delivery_r10.status, " "); 930 \u0275\u0275advance(); 931 \u0275\u0275conditional(delivery_r10.httpStatusCode ? 11 : -1); 932 \u0275\u0275advance(2); 933 \u0275\u0275conditional(delivery_r10.subscriptionTargetUrl ? 13 : -1); 934 \u0275\u0275advance(); 935 \u0275\u0275conditional(delivery_r10.responseTimeMs ? 14 : -1); 936 \u0275\u0275advance(2); 937 \u0275\u0275textInterpolate(ctx_r3.formatTimeAgo(delivery_r10.createdAt)); 938 \u0275\u0275advance(); 939 \u0275\u0275conditional(delivery_r10.errorMessage ? 17 : -1); 940 \u0275\u0275advance(); 941 \u0275\u0275conditional(delivery_r10.status === "Failed" ? 18 : -1); 942 \u0275\u0275advance(); 943 \u0275\u0275conditional(delivery_r10.status === "Retrying" && delivery_r10.nextRetryAt ? 19 : -1); 944 } 945} 946function WebhookSandboxPage_Conditional_31_Conditional_21_Conditional_3_Conditional_2_Template(rf, ctx) { 947 if (rf & 1) { 948 \u0275\u0275element(0, "ion-spinner", 83); 949 } 950} 951function WebhookSandboxPage_Conditional_31_Conditional_21_Conditional_3_Template(rf, ctx) { 952 if (rf & 1) { 953 const _r12 = \u0275\u0275getCurrentView(); 954 \u0275\u0275elementStart(0, "div", 66)(1, "ion-button", 82); 955 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_31_Conditional_21_Conditional_3_Template_ion_button_click_1_listener() { 956 \u0275\u0275restoreView(_r12); 957 const ctx_r3 = \u0275\u0275nextContext(3);
958 return \u0275\u0275resetView(ctx_r3.loadMoreDeliveries()); 959 }); 960 \u0275\u0275template(2, WebhookSandboxPage_Conditional_31_Conditional_21_Conditional_3_Conditional_2_Template, 1, 0, "ion-spinner", 83); 961 \u0275\u0275text(3, " Load More "); 962 \u0275\u0275elementEnd()(); 963 } 964 if (rf & 2) { 965 const ctx_r3 = \u0275\u0275nextContext(3); 966 \u0275\u0275advance(); 967 \u0275\u0275property("disabled", ctx_r3.isLoadingDeliveries); 968 \u0275\u0275advance(); 969 \u0275\u0275conditional(ctx_r3.isLoadingDeliveries ? 2 : -1); 970 } 971} 972function WebhookSandboxPage_Conditional_31_Conditional_21_Template(rf, ctx) { 973 if (rf & 1) { 974 \u0275\u0275elementStart(0, "ion-list"); 975 \u0275\u0275repeaterCreate(1, WebhookSandboxPage_Conditional_31_Conditional_21_For_2_Template, 20, 12, "ion-item", null, _forTrack0); 976 \u0275\u0275elementEnd(); 977 \u0275\u0275template(3, WebhookSandboxPage_Conditional_31_Conditional_21_Conditional_3_Template, 4, 2, "div", 66); 978 } 979 if (rf & 2) { 980 const ctx_r3 = \u0275\u0275nextContext(2); 981 \u0275\u0275advance(); 982 \u0275\u0275repeater(ctx_r3.deliveries); 983 \u0275\u0275advance(2); 984 \u0275\u0275conditional(ctx_r3.hasMoreDeliveries ? 3 : -1); 985 } 986} 987function WebhookSandboxPage_Conditional_31_Template(rf, ctx) { 988 if (rf & 1) { 989 const _r9 = \u0275\u0275getCurrentView(); 990 \u0275\u0275elementStart(0, "div", 12)(1, "div", 58)(2, "ion-select", 59); 991 \u0275\u0275pipe(3, "translate"); 992 \u0275\u0275listener("ionChange", function WebhookSandboxPage_Conditional_31_Template_ion_select_ionChange_2_listener($event) { 993 \u0275\u0275restoreView(_r9); 994 const ctx_r3 = \u0275\u0275nextContext(); 995 return \u0275\u0275resetView(ctx_r3.onDeliveryFilterChange($event)); 996 }); 997 \u0275\u0275elementStart(4, "ion-select-option", 60); 998 \u0275\u0275text(5); 999 \u0275\u0275pipe(6, "translate"); 1000 \u0275\u0275elementEnd(); 1001 \u0275\u0275elementStart(7, "ion-select-option", 61); 1002 \u0275\u0275text(8); 1003 \u0275\u0275pipe(9, "translate"); 1004 \u0275\u0275elementEnd(); 1005 \u0275\u0275elementStart(10, "ion-select-option", 62); 1006 \u0275\u0275text(11); 1007 \u0275\u0275pipe(12, "translate"); 1008 \u0275\u0275elementEnd(); 1009 \u0275\u0275elementStart(13, "ion-select-option", 63); 1010 \u0275\u0275text(14); 1011 \u0275\u0275pipe(15, "translate"); 1012 \u0275\u0275elementEnd(); 1013 \u0275\u0275elementStart(16, "ion-select-option", 64); 1014 \u0275\u0275text(17); 1015 \u0275\u0275pipe(18, "translate"); 1016 \u0275\u0275elementEnd()()(); 1017 \u0275\u0275template(19, WebhookSandboxPage_Conditional_31_Conditional_19_Template, 2, 0, "div", 14)(20, WebhookSandboxPage_Conditional_31_Conditional_20_Template, 5, 3, "div", 15)(21, WebhookSandboxPage_Conditional_31_Conditional_21_Template, 4, 1); 1018 \u0275\u0275elementEnd(); 1019 } 1020 if (rf & 2) { 1021 const ctx_r3 = \u0275\u0275nextContext(); 1022 \u0275\u0275advance(2); 1023 \u0275\u0275propertyInterpolate("label", \u0275\u0275pipeBind1(3, 8, "webhookSandbox.deliveries.status")); 1024 \u0275\u0275property("value", ctx_r3.deliveryStatusFilter); 1025 \u0275\u0275advance(3); 1026 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(6, 10, "webhookSandbox.deliveries.filter.all")); 1027 \u0275\u0275advance(3); 1028 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(9, 12, "webhookSandbox.deliveries.delivered")); 1029 \u0275\u0275advance(3); 1030 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(12, 14, "webhookSandbox.deliveries.failed")); 1031 \u0275\u0275advance(3); 1032 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(15, 16, "webhookSandbox.deliveries.retrying")); 1033 \u0275\u0275advance(3); 1034 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(18, 18, "webhookSandbox.deliveries.pending")); 1035 \u0275\u0275advance(2); 1036 \u0275\u0275conditional(ctx_r3.isLoadingDeliveries && ctx_r3.deliveries.length === 0 ? 19 : ctx_r3.deliveries.length === 0 ? 20 : 21); 1037 } 1038} 1039function WebhookSandboxPage_Conditional_32_Conditional_1_Template(rf, ctx) { 1040 if (rf & 1) { 1041 \u0275\u0275elementStart(0, "div", 14); 1042 \u0275\u0275element(1, "ion-spinner", 19); 1043 \u0275\u0275elementEnd(); 1044 } 1045} 1046function WebhookSandboxPage_Conditional_32_Conditional_2_Conditional_30_Template(rf, ctx) { 1047 if (rf & 1) { 1048 const _r13 = \u0275\u0275getCurrentView(); 1049 \u0275\u0275elementStart(0, "ion-button", 105); 1050 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_32_Conditional_2_Conditional_30_Template_ion_button_click_0_listener() { 1051 \u0275\u0275restoreView(_r13); 1052 const ctx_r3 = \u0275\u0275nextContext(3);
1053 return \u0275\u0275resetView(ctx_r3.resetAllCircuitBreakers()); 1054 }); 1055 \u0275\u0275text(1); 1056 \u0275\u0275pipe(2, "translate"); 1057 \u0275\u0275elementEnd(); 1058 } 1059 if (rf & 2) { 1060 \u0275\u0275advance(); 1061 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(2, 1, "webhookSandbox.stats.resetAll"), " "); 1062 } 1063} 1064function WebhookSandboxPage_Conditional_32_Conditional_2_Template(rf, ctx) { 1065 if (rf & 1) { 1066 \u0275\u0275elementStart(0, "ion-grid")(1, "ion-row")(2, "ion-col", 84)(3, "ion-card", 85)(4, "ion-card-header")(5, "ion-card-title"); 1067 \u0275\u0275text(6); 1068 \u0275\u0275pipe(7, "translate"); 1069 \u0275\u0275elementEnd()(); 1070 \u0275\u0275elementStart(8, "ion-card-content")(9, "div", 86); 1071 \u0275\u0275text(10); 1072 \u0275\u0275elementEnd(); 1073 \u0275\u0275elementStart(11, "div", 87)(12, "span", 88); 1074 \u0275\u0275text(13); 1075 \u0275\u0275pipe(14, "translate"); 1076 \u0275\u0275elementEnd(); 1077 \u0275\u0275elementStart(15, "span", 89); 1078 \u0275\u0275text(16); 1079 \u0275\u0275pipe(17, "translate"); 1080 \u0275\u0275elementEnd()()()()(); 1081 \u0275\u0275elementStart(18, "ion-col", 84)(19, "ion-card", 85)(20, "ion-card-header")(21, "ion-card-title"); 1082 \u0275\u0275text(22); 1083 \u0275\u0275pipe(23, "translate"); 1084 \u0275\u0275elementEnd()(); 1085 \u0275\u0275elementStart(24, "ion-card-content")(25, "div", 86); 1086 \u0275\u0275text(26); 1087 \u0275\u0275elementEnd(); 1088 \u0275\u0275elementStart(27, "div", 90); 1089 \u0275\u0275text(28); 1090 \u0275\u0275pipe(29, "translate"); 1091 \u0275\u0275elementEnd(); 1092 \u0275\u0275template(30, WebhookSandboxPage_Conditional_32_Conditional_2_Conditional_30_Template, 3, 3, "ion-button", 91); 1093 \u0275\u0275elementEnd()()()(); 1094 \u0275\u0275elementStart(31, "ion-row")(32, "ion-col", 92)(33, "ion-card", 85)(34, "ion-card-header")(35, "ion-card-title"); 1095 \u0275\u0275text(36); 1096 \u0275\u0275pipe(37, "translate"); 1097 \u0275\u0275elementEnd()(); 1098 \u0275\u0275elementStart(38, "ion-card-content")(39, "div", 93); 1099 \u0275\u0275text(40); 1100 \u0275\u0275elementEnd(); 1101 \u0275\u0275element(41, "ion-progress-bar", 94); 1102 \u0275\u0275elementStart(42, "div", 95); 1103 \u0275\u0275text(43); 1104 \u0275\u0275pipe(44, "number"); 1105 \u0275\u0275pipe(45, "translate"); 1106 \u0275\u0275elementEnd(); 1107 \u0275\u0275elementStart(46, "div", 96)(47, "span", 97); 1108 \u0275\u0275element(48, "ng-icon", 98); 1109 \u0275\u0275text(49); 1110 \u0275\u0275elementEnd(); 1111 \u0275\u0275elementStart(50, "span", 99); 1112 \u0275\u0275element(51, "ng-icon", 100); 1113 \u0275\u0275text(52); 1114 \u0275\u0275elementEnd(); 1115 \u0275\u0275elementStart(53, "span", 101); 1116 \u0275\u0275element(54, "ng-icon", 102); 1117 \u0275\u0275text(55); 1118 \u0275\u0275elementEnd(); 1119 \u0275\u0275elementStart(56, "span", 103); 1120 \u0275\u0275element(57, "ng-icon", 104); 1121 \u0275\u0275text(58); 1122 \u0275\u0275elementEnd()()()()()(); 1123 \u0275\u0275elementStart(59, "ion-row")(60, "ion-col", 84)(61, "ion-card", 85)(62, "ion-card-header")(63, "ion-card-title"); 1124 \u0275\u0275text(64); 1125 \u0275\u0275pipe(65, "translate"); 1126 \u0275\u0275elementEnd()(); 1127 \u0275\u0275elementStart(66, "ion-card-content")(67, "div", 86); 1128 \u0275\u0275text(68); 1129 \u0275\u0275elementEnd(); 1130 \u0275\u0275elementStart(69, "div", 87)(70, "span", 97); 1131 \u0275\u0275text(71); 1132 \u0275\u0275elementEnd(); 1133 \u0275\u0275elementStart(72, "span", 99); 1134 \u0275\u0275text(73); 1135 \u0275\u0275elementEnd()(); 1136 \u0275\u0275elementStart(74, "div", 95); 1137 \u0275\u0275text(75); 1138 \u0275\u0275pipe(76, "number"); 1139 \u0275\u0275elementEnd()()()(); 1140 \u0275\u0275elementStart(77, "ion-col", 84)(78, "ion-card", 85)(79, "ion-card-header")(80, "ion-card-title"); 1141 \u0275\u0275text(81); 1142 \u0275\u0275pipe(82, "translate"); 1143 \u0275\u0275elementEnd()(); 1144 \u0275\u0275elementStart(83, "ion-card-content")(84, "div", 86); 1145 \u0275\u0275text(85); 1146 \u0275\u0275elementEnd(); 1147 \u0275\u0275elementStart(86, "div", 90); 1148 \u0275\u0275text(87); 1149 \u0275\u0275pipe(88, "translate"); 1150 \u0275\u0275elementEnd(); 1151 \u0275\u0275elementStart(89, "ion-note"); 1152 \u0275\u0275text(90); 1153 \u0275\u0275elementEnd()()()()()(); 1154 } 1155 if (rf & 2) { 1156 const ctx_r3 = \u0275\u0275nextContext(2); 1157 \u0275\u0275advance(6); 1158 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(7, 30, "webhookSandbox.stats.subscriptions")); 1159 \u0275\u0275advance(4); 1160 \u0275\u0275textInterpolate(ctx_r3.stats.subscriptions.total); 1161 \u0275\u0275advance(3); 1162 \u0275\u0275textInterpolate2("", ctx_r3.stats.subscriptions.active, " ", \u0275\u0275pipeBind1(14, 32, "webhookSandbox.stats.active"), ""); 1163 \u0275\u0275advance(3); 1164 \u0275\u0275textInterpolate2("", ctx_r3.stats.subscriptions.total - ctx_r3.stats.subscriptions.active, " ", \u0275\u0275pipeBind1(17, 34, "webhookSandbox.stats.inactive"), ""); 1165 \u0275\u0275advance(3); 1166 \u0275\u0275classProp("warning", ctx_r3.stats.subscriptions.circuitOpen > 0); 1167 \u0275\u0275advance(3); 1168 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(23, 36, "webhookSandbox.stats.circuitBreakers")); 1169 \u0275\u0275advance(4); 1170 \u0275\u0275textInterpolate(ctx_r3.stats.subscriptions.circuitOpen); 1171 \u0275\u0275advance(2); 1172 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(29, 38, "webhookSandbox.stats.open")); 1173 \u0275\u0275advance(2); 1174 \u0275\u0275conditional(ctx_r3.stats.subscriptions.circuitOpen > 0 ? 30 : -1); 1175 \u0275\u0275advance(6); 1176 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(37, 40, "webhookSandbox.stats.deliveries24h")); 1177 \u0275\u0275advance(4); 1178 \u0275\u0275textInterpolate(ctx_r3.stats.deliveries.last24Hours.total); 1179 \u0275\u0275advance(); 1180 \u0275\u0275property("value", ctx_r3.getSuccessRate24h() / 100); 1181 \u0275\u0275advance(2); 1182 \u0275\u0275textInterpolate2("", \u0275\u0275pipeBind2(44, 42, ctx_r3.getSuccessRate24h(), "1.1-1"), "% ", \u0275\u0275pipeBind1(45, 45, "webhookSandbox.stats.successRate"), ""); 1183 \u0275\u0275advance(6); 1184 \u0275\u0275textInterpolate1(" ", ctx_r3.stats.deliveries.last24Hours.delivered, " "); 1185 \u0275\u0275advance(3); 1186 \u0275\u0275textInterpolate1(" ", ctx_r3.stats.deliveries.last24Hours.failed, " "); 1187 \u0275\u0275advance(3); 1188 \u0275\u0275textInterpolate1(" ", ctx_r3.stats.deliveries.last24Hours.retrying, " "); 1189 \u0275\u0275advance(3); 1190 \u0275\u0275textInterpolate1(" ", ctx_r3.stats.deliveries.last24Hours.pending, " "); 1191 \u0275\u0275advance(6); 1192 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(65, 47, "webhookSandbox.stats.deliveries7d")); 1193 \u0275\u0275advance(4); 1194 \u0275\u0275textInterpolate(ctx_r3.stats.deliveries.last7Days.total); 1195 \u0275\u0275advance(3); 1196 \u0275\u0275textInterpolate1("", ctx_r3.stats.deliveries.last7Days.delivered, " delivered"); 1197 \u0275\u0275advance(2); 1198 \u0275\u0275textInterpolate1("", ctx_r3.stats.deliveries.last7Days.failed, " failed"); 1199 \u0275\u0275advance(2); 1200 \u0275\u0275textInterpolate1("", \u0275\u0275pipeBind2(76, 49, ctx_r3.getSuccessRate7d(), "1.1-1"), "%"); 1201 \u0275\u0275advance(6); 1202 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(82, 52, "webhookSandbox.stats.pendingEvents")); 1203 \u0275\u0275advance(4); 1204 \u0275\u0275textInterpolate(ctx_r3.stats.events.pending); 1205 \u0275\u0275advance(2); 1206 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(88, 54, "webhookSandbox.stats.queue")); 1207 \u0275\u0275advance(3); 1208 \u0275\u0275textInterpolate1("", ctx_r3.stats.events.processedLast24Hours, " processed (24h)"); 1209 } 1210} 1211function WebhookSandboxPage_Conditional_32_Template(rf, ctx) { 1212 if (rf & 1) { 1213 \u0275\u0275elementStart(0, "div", 13); 1214 \u0275\u0275template(1, WebhookSandboxPage_Conditional_32_Conditional_1_Template, 2, 0, "div", 14)(2, WebhookSandboxPage_Conditional_32_Conditional_2_Template, 91, 56, "ion-grid"); 1215 \u0275\u0275elementEnd(); 1216 } 1217 if (rf & 2) { 1218 const ctx_r3 = \u0275\u0275nextContext(); 1219 \u0275\u0275advance(); 1220 \u0275\u0275conditional(ctx_r3.isLoadingStats ? 1 : ctx_r3.stats ? 2 : -1); 1221 } 1222} 1223function WebhookSandboxPage_Conditional_33_Conditional_4_Template(rf, ctx) { 1224 if (rf & 1) { 1225 \u0275\u0275text(0); 1226 \u0275\u0275pipe(1, "translate"); 1227 } 1228 if (rf & 2) { 1229 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(1, 1, "webhookSandbox.subscriptions.edit"), " "); 1230 } 1231} 1232function WebhookSandboxPage_Conditional_33_Conditional_5_Template(rf, ctx) { 1233 if (rf & 1) { 1234 \u0275\u0275text(0); 1235 \u0275\u0275pipe(1, "translate"); 1236 } 1237 if (rf & 2) { 1238 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(1, 1, "webhookSandbox.subscriptions.create"), " "); 1239 } 1240} 1241function WebhookSandboxPage_Conditional_33_Conditional_14_Template(rf, ctx) { 1242 if (rf & 1) { 1243 \u0275\u0275elementStart(0, "span", 114); 1244 \u0275\u0275text(1, "URL is required"); 1245 \u0275\u0275elementEnd(); 1246 } 1247} 1248function WebhookSandboxPage_Conditional_33_Conditional_15_Template(rf, ctx) { 1249 if (rf & 1) { 1250 \u0275\u0275elementStart(0, "span", 114); 1251 \u0275\u0275text(1, "Must be a valid HTTPS URL"); 1252 \u0275\u0275elementEnd(); 1253 } 1254} 1255function WebhookSandboxPage_Conditional_33_For_27_Template(rf, ctx) { 1256 if (rf & 1) { 1257 const _r15 = \u0275\u0275getCurrentView(); 1258 \u0275\u0275elementStart(0, "ion-chip", 122); 1259 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_33_For_27_Template_ion_chip_click_0_listener() { 1260 const type_r16 = \u0275\u0275restoreView(_r15).$implicit; 1261 const ctx_r3 = \u0275\u0275nextContext(2);
1262 return \u0275\u0275resetView(ctx_r3.toggleEntityType(type_r16)); 1263 }); 1264 \u0275\u0275text(1); 1265 \u0275\u0275pipe(2, "translate"); 1266 \u0275\u0275elementEnd(); 1267 } 1268 if (rf & 2) { 1269 const type_r16 = ctx.$implicit; 1270 const ctx_r3 = \u0275\u0275nextContext(2); 1271 \u0275\u0275property("color", ctx_r3.isEntityTypeSelected(type_r16) ? "primary" : "medium")("outline", !ctx_r3.isEntityTypeSelected(type_r16)); 1272 \u0275\u0275advance(); 1273 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(2, 3, "webhookSandbox.entityTypes." + type_r16), " "); 1274 } 1275} 1276function WebhookSandboxPage_Conditional_33_Conditional_28_Template(rf, ctx) { 1277 if (rf & 1) { 1278 \u0275\u0275elementStart(0, "span", 118); 1279 \u0275\u0275text(1, "Select at least one entity type"); 1280 \u0275\u0275elementEnd(); 1281 } 1282} 1283function WebhookSandboxPage_Conditional_33_For_35_Template(rf, ctx) { 1284 if (rf & 1) { 1285 const _r17 = \u0275\u0275getCurrentView(); 1286 \u0275\u0275elementStart(0, "ion-chip", 122); 1287 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_33_For_35_Template_ion_chip_click_0_listener() { 1288 const type_r18 = \u0275\u0275restoreView(_r17).$implicit; 1289 const ctx_r3 = \u0275\u0275nextContext(2); 1290 return \u0275\u0275resetView(ctx_r3.toggleEventType(type_r18)); 1291 }); 1292 \u0275\u0275text(1); 1293 \u0275\u0275pipe(2, "translate"); 1294 \u0275\u0275elementEnd(); 1295 } 1296 if (rf & 2) { 1297 const type_r18 = ctx.$implicit; 1298 const ctx_r3 = \u0275\u0275nextContext(2); 1299 \u0275\u0275property("color", ctx_r3.isEventTypeSelected(type_r18) ? "secondary" : "medium")("outline", !ctx_r3.isEventTypeSelected(type_r18)); 1300 \u0275\u0275advance(); 1301 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(2, 3, "webhookSandbox.eventTypes." + type_r18), " "); 1302 } 1303} 1304function WebhookSandboxPage_Conditional_33_Conditional_36_Template(rf, ctx) { 1305 if (rf & 1) { 1306 \u0275\u0275elementStart(0, "span", 118); 1307 \u0275\u0275text(1, "Select at least one event type"); 1308 \u0275\u0275elementEnd(); 1309 } 1310} 1311function WebhookSandboxPage_Conditional_33_Conditional_42_Template(rf, ctx) { 1312 if (rf & 1) { 1313 \u0275\u0275element(0, "ion-spinner", 83); 1314 } 1315} 1316function WebhookSandboxPage_Conditional_33_Conditional_43_Template(rf, ctx) { 1317 if (rf & 1) { 1318 \u0275\u0275text(0); 1319 \u0275\u0275pipe(1, "translate"); 1320 } 1321 if (rf & 2) { 1322 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(1, 1, "common.update"), " "); 1323 } 1324} 1325function WebhookSandboxPage_Conditional_33_Conditional_44_Template(rf, ctx) { 1326 if (rf & 1) { 1327 \u0275\u0275text(0); 1328 \u0275\u0275pipe(1, "translate"); 1329 } 1330 if (rf & 2) { 1331 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(1, 1, "webhookSandbox.subscriptions.create"), " "); 1332 } 1333} 1334function WebhookSandboxPage_Conditional_33_Template(rf, ctx) { 1335 if (rf & 1) { 1336 const _r14 = \u0275\u0275getCurrentView(); 1337 \u0275\u0275elementStart(0, "div", 106); 1338 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_33_Template_div_click_0_listener() { 1339 \u0275\u0275restoreView(_r14); 1340 const ctx_r3 = \u0275\u0275nextContext(); 1341 return \u0275\u0275resetView(ctx_r3.closeForm()); 1342 }); 1343 \u0275\u0275elementEnd(); 1344 \u0275\u0275elementStart(1, "div", 107)(2, "div", 108)(3, "h2"); 1345 \u0275\u0275template(4, WebhookSandboxPage_Conditional_33_Conditional_4_Template, 2, 3)(5, WebhookSandboxPage_Conditional_33_Conditional_5_Template, 2, 3); 1346 \u0275\u0275elementEnd(); 1347 \u0275\u0275elementStart(6, "ion-button", 109); 1348 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_33_Template_ion_button_click_6_listener() { 1349 \u0275\u0275restoreView(_r14); 1350 const ctx_r3 = \u0275\u0275nextContext(); 1351 return \u0275\u0275resetView(ctx_r3.closeForm()); 1352 }); 1353 \u0275\u0275element(7, "ng-icon", 110); 1354 \u0275\u0275elementEnd()(); 1355 \u0275\u0275elementStart(8, "form", 111); 1356 \u0275\u0275listener("ngSubmit", function WebhookSandboxPage_Conditional_33_Template_form_ngSubmit_8_listener() { 1357 \u0275\u0275restoreView(_r14); 1358 const ctx_r3 = \u0275\u0275nextContext();
1359 return \u0275\u0275resetView(ctx_r3.submitForm()); 1360 }); 1361 \u0275\u0275elementStart(9, "div", 112)(10, "ion-label"); 1362 \u0275\u0275text(11); 1363 \u0275\u0275pipe(12, "translate"); 1364 \u0275\u0275elementEnd(); 1365 \u0275\u0275element(13, "ion-input", 113); 1366 \u0275\u0275template(14, WebhookSandboxPage_Conditional_33_Conditional_14_Template, 2, 0, "span", 114)(15, WebhookSandboxPage_Conditional_33_Conditional_15_Template, 2, 0, "span", 114); 1367 \u0275\u0275elementEnd(); 1368 \u0275\u0275elementStart(16, "div", 112)(17, "ion-label"); 1369 \u0275\u0275text(18); 1370 \u0275\u0275pipe(19, "translate"); 1371 \u0275\u0275elementEnd(); 1372 \u0275\u0275element(20, "ion-textarea", 115); 1373 \u0275\u0275elementEnd(); 1374 \u0275\u0275elementStart(21, "div", 112)(22, "ion-label"); 1375 \u0275\u0275text(23); 1376 \u0275\u0275pipe(24, "translate"); 1377 \u0275\u0275elementEnd(); 1378 \u0275\u0275elementStart(25, "div", 116); 1379 \u0275\u0275repeaterCreate(26, WebhookSandboxPage_Conditional_33_For_27_Template, 3, 5, "ion-chip", 117, \u0275\u0275repeaterTrackByIdentity); 1380 \u0275\u0275elementEnd(); 1381 \u0275\u0275template(28, WebhookSandboxPage_Conditional_33_Conditional_28_Template, 2, 0, "span", 118); 1382 \u0275\u0275elementEnd(); 1383 \u0275\u0275elementStart(29, "div", 112)(30, "ion-label"); 1384 \u0275\u0275text(31); 1385 \u0275\u0275pipe(32, "translate"); 1386 \u0275\u0275elementEnd(); 1387 \u0275\u0275elementStart(33, "div", 116); 1388 \u0275\u0275repeaterCreate(34, WebhookSandboxPage_Conditional_33_For_35_Template, 3, 5, "ion-chip", 117, \u0275\u0275repeaterTrackByIdentity); 1389 \u0275\u0275elementEnd(); 1390 \u0275\u0275template(36, WebhookSandboxPage_Conditional_33_Conditional_36_Template, 2, 0, "span", 118); 1391 \u0275\u0275elementEnd(); 1392 \u0275\u0275elementStart(37, "div", 119)(38, "ion-button", 120); 1393 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_33_Template_ion_button_click_38_listener() { 1394 \u0275\u0275restoreView(_r14); 1395 const ctx_r3 = \u0275\u0275nextContext(); 1396 return \u0275\u0275resetView(ctx_r3.closeForm()); 1397 }); 1398 \u0275\u0275text(39); 1399 \u0275\u0275pipe(40, "translate"); 1400 \u0275\u0275elementEnd(); 1401 \u0275\u0275elementStart(41, "ion-button", 121); 1402 \u0275\u0275template(42, WebhookSandboxPage_Conditional_33_Conditional_42_Template, 1, 0, "ion-spinner", 83)(43, WebhookSandboxPage_Conditional_33_Conditional_43_Template, 2, 3)(44, WebhookSandboxPage_Conditional_33_Conditional_44_Template, 2, 3); 1403 \u0275\u0275elementEnd()()()(); 1404 } 1405 if (rf & 2) { 1406 let tmp_4_0; 1407 let tmp_5_0; 1408 const ctx_r3 = \u0275\u0275nextContext(); 1409 \u0275\u0275advance(4); 1410 \u0275\u0275conditional(ctx_r3.isEditMode ? 4 : 5); 1411 \u0275\u0275advance(4); 1412 \u0275\u0275property("formGroup", ctx_r3.subscriptionForm); 1413 \u0275\u0275advance(3); 1414 \u0275\u0275textInterpolate1("", \u0275\u0275pipeBind1(12, 14, "webhookSandbox.subscriptions.targetUrl"), " *"); 1415 \u0275\u0275advance(3); 1416 \u0275\u0275conditional(((tmp_4_0 = ctx_r3.subscriptionForm.get("targetUrl")) == null ? null : tmp_4_0.touched) && ((tmp_4_0 = ctx_r3.subscriptionForm.get("targetUrl")) == null ? null : tmp_4_0.hasError("required")) ? 14 : -1); 1417 \u0275\u0275advance(); 1418 \u0275\u0275conditional(((tmp_5_0 = ctx_r3.subscriptionForm.get("targetUrl")) == null ? null : tmp_5_0.touched) && ((tmp_5_0 = ctx_r3.subscriptionForm.get("targetUrl")) == null ? null : tmp_5_0.hasError("pattern")) ? 15 : -1); 1419 \u0275\u0275advance(3); 1420 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(19, 16, "webhookSandbox.subscriptions.description")); 1421 \u0275\u0275advance(5); 1422 \u0275\u0275textInterpolate1("", \u0275\u0275pipeBind1(24, 18, "webhookSandbox.subscriptions.entityTypes"), " *"); 1423 \u0275\u0275advance(3); 1424 \u0275\u0275repeater(ctx_r3.entityTypes); 1425 \u0275\u0275advance(2); 1426 \u0275\u0275conditional(ctx_r3.selectedEntityTypes.length === 0 ? 28 : -1); 1427 \u0275\u0275advance(3); 1428 \u0275\u0275textInterpolate1("", \u0275\u0275pipeBind1(32, 20, "webhookSandbox.subscriptions.eventTypes"), " *"); 1429 \u0275\u0275advance(3); 1430 \u0275\u0275repeater(ctx_r3.eventTypes); 1431 \u0275\u0275advance(2); 1432 \u0275\u0275conditional(ctx_r3.selectedEventTypes.length === 0 ? 36 : -1); 1433 \u0275\u0275advance(3); 1434 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(40, 22, "common.cancel"), " "); 1435 \u0275\u0275advance(2); 1436 \u0275\u0275property("disabled", ctx_r3.isSubmitting); 1437 \u0275\u0275advance(); 1438 \u0275\u0275conditional(ctx_r3.isSubmitting ? 42 : -1); 1439 \u0275\u0275advance(); 1440 \u0275\u0275conditional(ctx_r3.isEditMode ? 43 : 44); 1441 } 1442} 1443function WebhookSandboxPage_Conditional_34_Conditional_20_Template(rf, ctx) { 1444 if (rf & 1) { 1445 \u0275\u0275element(0, "ng-icon", 131); 1446 } 1447} 1448function WebhookSandboxPage_Conditional_34_Conditional_21_Template(rf, ctx) { 1449 if (rf & 1) { 1450 \u0275\u0275element(0, "ng-icon", 132); 1451 } 1452} 1453function WebhookSandboxPage_Conditional_34_Template(rf, ctx) { 1454 if (rf & 1) { 1455 const _r19 = \u0275\u0275getCurrentView(); 1456 \u0275\u0275elementStart(0, "div", 106); 1457 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_34_Template_div_click_0_listener() { 1458 \u0275\u0275restoreView(_r19); 1459 const ctx_r3 = \u0275\u0275nextContext();
1460 return \u0275\u0275resetView(ctx_r3.closeSecretModal()); 1461 }); 1462 \u0275\u0275elementEnd(); 1463 \u0275\u0275elementStart(1, "div", 123)(2, "div", 124); 1464 \u0275\u0275element(3, "ng-icon", 125); 1465 \u0275\u0275elementStart(4, "h2"); 1466 \u0275\u0275text(5); 1467 \u0275\u0275pipe(6, "translate"); 1468 \u0275\u0275elementEnd()(); 1469 \u0275\u0275elementStart(7, "div", 126)(8, "div", 127); 1470 \u0275\u0275element(9, "ng-icon", 128); 1471 \u0275\u0275elementStart(10, "p"); 1472 \u0275\u0275text(11); 1473 \u0275\u0275pipe(12, "translate"); 1474 \u0275\u0275elementEnd()(); 1475 \u0275\u0275elementStart(13, "div", 112)(14, "ion-label"); 1476 \u0275\u0275text(15); 1477 \u0275\u0275pipe(16, "translate"); 1478 \u0275\u0275elementEnd(); 1479 \u0275\u0275elementStart(17, "div", 129); 1480 \u0275\u0275element(18, "ion-input", 130); 1481 \u0275\u0275elementStart(19, "ion-button", 109); 1482 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_34_Template_ion_button_click_19_listener() { 1483 \u0275\u0275restoreView(_r19); 1484 const ctx_r3 = \u0275\u0275nextContext(); 1485 return \u0275\u0275resetView(ctx_r3.toggleSecretVisibility()); 1486 }); 1487 \u0275\u0275template(20, WebhookSandboxPage_Conditional_34_Conditional_20_Template, 1, 0, "ng-icon", 131)(21, WebhookSandboxPage_Conditional_34_Conditional_21_Template, 1, 0, "ng-icon", 132); 1488 \u0275\u0275elementEnd(); 1489 \u0275\u0275elementStart(22, "ion-button", 109); 1490 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_34_Template_ion_button_click_22_listener() { 1491 \u0275\u0275restoreView(_r19); 1492 const ctx_r3 = \u0275\u0275nextContext(); 1493 return \u0275\u0275resetView(ctx_r3.copySecret()); 1494 }); 1495 \u0275\u0275element(23, "ng-icon", 133); 1496 \u0275\u0275elementEnd()()(); 1497 \u0275\u0275elementStart(24, "p", 134); 1498 \u0275\u0275text(25, " Use this secret to verify webhook signatures."); 1499 \u0275\u0275element(26, "br"); 1500 \u0275\u0275text(27, " Header: "); 1501 \u0275\u0275elementStart(28, "code"); 1502 \u0275\u0275text(29, "X-Webhook-Signature: sha256={hash}"); 1503 \u0275\u0275elementEnd()()(); 1504 \u0275\u0275elementStart(30, "div", 119)(31, "ion-button", 17); 1505 \u0275\u0275listener("click", function WebhookSandboxPage_Conditional_34_Template_ion_button_click_31_listener() { 1506 \u0275\u0275restoreView(_r19); 1507 const ctx_r3 = \u0275\u0275nextContext(); 1508 return \u0275\u0275resetView(ctx_r3.closeSecretModal()); 1509 }); 1510 \u0275\u0275text(32, " Done "); 1511 \u0275\u0275elementEnd()()(); 1512 } 1513 if (rf & 2) { 1514 const ctx_r3 = \u0275\u0275nextContext(); 1515 \u0275\u0275advance(5); 1516 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(6, 6, "webhookSandbox.subscriptions.secretTitle")); 1517 \u0275\u0275advance(6); 1518 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(12, 8, "webhookSandbox.subscriptions.secretWarning")); 1519 \u0275\u0275advance(4); 1520 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(16, 10, "webhookSandbox.subscriptions.secretLabel")); 1521 \u0275\u0275advance(3); 1522 \u0275\u0275property("value", ctx_r3.createdSecret)("type", ctx_r3.isSecretVisible ? "text" : "password"); 1523 \u0275\u0275advance(2); 1524 \u0275\u0275conditional(ctx_r3.isSecretVisible ? 20 : 21); 1525 } 1526} 1527var _WebhookSandboxPage = class _WebhookSandboxPage { 1528 constructor(fb, webhookService, toastService, alertController, translateService) { 1529 this.fb = fb; 1530 this.webhookService = webhookService; 1531 this.toastService = toastService; 1532 this.alertController = alertController; 1533 this.translateService = translateService; 1534 this.isMockEnabled = true; 1535 this.activeTab = "subscriptions"; 1536 this.subscriptions = []; 1537 this.isLoadingSubscriptions = false; 1538 this.expandedSubscriptionId = null; 1539 this.isFormVisible = false; 1540 this.isEditMode = false; 1541 this.editingSubscriptionId = null; 1542 this.isSubmitting = false; 1543 this.isSecretModalVisible = false; 1544 this.createdSecret = null; 1545 this.isSecretVisible = false; 1546 this.deliveries = []; 1547 this.isLoadingDeliveries = false; 1548 this.deliveryStatusFilter = "all"; 1549 this.deliveryPage = 1; 1550 this.hasMoreDeliveries = true; 1551 this.stats = null; 1552 this.isLoadingStats = false;
1553 this.entityTypes = ENTITY_TYPES; 1554 this.eventTypes = EVENT_TYPES; 1555 this.selectedEntityTypes = []; 1556 this.selectedEventTypes = []; 1557 } 1558 ngOnInit() { 1559 this.initForm(); 1560 this.loadMockPreference(); 1561 this.loadSubscriptions(); 1562 } 1563 loadMockPreference() { 1564 const stored = localStorage.getItem(_WebhookSandboxPage.MOCK_STORAGE_KEY); 1565 this.isMockEnabled = stored === null ? true : stored === "true"; 1566 } 1567 toggleMockData(event) { 1568 this.isMockEnabled = event.detail.checked; 1569 localStorage.setItem(_WebhookSandboxPage.MOCK_STORAGE_KEY, String(this.isMockEnabled)); 1570 this.resetAndReload(); 1571 } 1572 resetAndReload() { 1573 this.subscriptions = []; 1574 this.deliveries = []; 1575 this.stats = null; 1576 this.deliveryPage = 1; 1577 if (this.activeTab === "subscriptions") { 1578 this.loadSubscriptions(); 1579 } else if (this.activeTab === "deliveries") { 1580 this.loadDeliveries(); 1581 } else { 1582 this.loadStats(); 1583 } 1584 } 1585 ngOnDestroy() { 1586 var _a; 1587 (_a = this.subscriptionsSubscription) == null ? void 0 : _a.unsubscribe(); 1588 } 1589 // Tab navigation 1590 onTabChange(event) { 1591 this.activeTab = event.detail.value; 1592 if (this.activeTab === "deliveries" && this.deliveries.length === 0) { 1593 this.loadDeliveries(); 1594 } else if (this.activeTab === "statistics" && !this.stats) { 1595 this.loadStats(); 1596 } 1597 } 1598 // Pull-to-refresh 1599 doRefresh(event) { 1600 const refresher = event.target; 1601 if (this.activeTab === "subscriptions") { 1602 this.loadSubscriptions(() => refresher.complete()); 1603 } else if (this.activeTab === "deliveries") { 1604 this.deliveryPage = 1; 1605 this.loadDeliveries(() => refresher.complete()); 1606 } else { 1607 this.loadStats(() => refresher.complete()); 1608 } 1609 } 1610 // Manual refresh button 1611 manualRefresh() { 1612 if (this.activeTab === "subscriptions") { 1613 this.loadSubscriptions(); 1614 } else if (this.activeTab === "deliveries") { 1615 this.deliveryPage = 1; 1616 this.loadDeliveries(); 1617 } else { 1618 this.loadStats(); 1619 } 1620 } 1621 // ==================== SUBSCRIPTIONS TAB ==================== 1622 loadSubscriptions(callback) { 1623 this.isLoadingSubscriptions = true; 1624 if (this.isMockEnabled) { 1625 of(WebhookMockData.getSubscriptions()).pipe(delay(300), finalize(() => { 1626 this.isLoadingSubscriptions = false; 1627 callback == null ? void 0 : callback(); 1628 })).subscribe((result) => { 1629 this.subscriptions = result.items; 1630 }); 1631 return; 1632 } 1633 this.webhookService.getSubscriptions({ pageSize: 100 }).pipe(finalize(() => { 1634 this.isLoadingSubscriptions = false; 1635 callback == null ? void 0 : callback(); 1636 })).subscribe({ 1637 next: (result) => { 1638 this.subscriptions = result.items; 1639 }, 1640 error: (err) => { 1641 var _a; 1642 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to load subscriptions"); 1643 } 1644 }); 1645 } 1646 toggleSubscriptionExpand(id) { 1647 this.expandedSubscriptionId = this.expandedSubscriptionId === id ? null : id; 1648 } 1649 isCircuitOpen(sub) { 1650 if (!sub.circuitBrokenUntil) 1651 return false; 1652 return new Date(sub.circuitBrokenUntil) > /* @__PURE__ */ new Date(); 1653 } 1654 getCircuitOpenUntil(sub) { 1655 if (!sub.circuitBrokenUntil) 1656 return ""; 1657 return RigaDateTimeService.formatInRiga(sub.circuitBrokenUntil, { 1658 hour: "2-digit", 1659 minute: "2-digit", 1660 second: "2-digit" 1661 }); 1662 } 1663 // Form handling 1664 initForm() { 1665 this.subscriptionForm = this.fb.group({ 1666 targetUrl: ["", [Validators.required, Validators.pattern(/^https:\/\/.+/)]], 1667 description: ["", [Validators.maxLength(500)]] 1668 }); 1669 } 1670 openCreateForm() { 1671 this.isEditMode = false; 1672 this.editingSubscriptionId = null; 1673 this.selectedEntityTypes = []; 1674 this.selectedEventTypes = []; 1675 this.subscriptionForm.reset(); 1676 this.isFormVisible = true; 1677 } 1678 openEditForm(sub) { 1679 this.isEditMode = true; 1680 this.editingSubscriptionId = sub.id; 1681 this.selectedEntityTypes = [...sub.entityTypes]; 1682 this.selectedEventTypes = [...sub.eventTypes]; 1683 this.subscriptionForm.patchValue({ 1684 targetUrl: sub.targetUrl, 1685 description: sub.description || "" 1686 }); 1687 this.isFormVisible = true; 1688 } 1689 closeForm() { 1690 this.isFormVisible = false;
1691 this.subscriptionForm.reset(); 1692 this.selectedEntityTypes = []; 1693 this.selectedEventTypes = []; 1694 } 1695 toggleEntityType(type) { 1696 const idx = this.selectedEntityTypes.indexOf(type); 1697 if (idx >= 0) { 1698 this.selectedEntityTypes.splice(idx, 1); 1699 } else { 1700 this.selectedEntityTypes.push(type); 1701 } 1702 } 1703 toggleEventType(type) { 1704 const idx = this.selectedEventTypes.indexOf(type); 1705 if (idx >= 0) { 1706 this.selectedEventTypes.splice(idx, 1); 1707 } else { 1708 this.selectedEventTypes.push(type); 1709 } 1710 } 1711 isEntityTypeSelected(type) { 1712 return this.selectedEntityTypes.includes(type); 1713 } 1714 isEventTypeSelected(type) { 1715 return this.selectedEventTypes.includes(type); 1716 } 1717 submitForm() { 1718 return __async(this, null, function* () { 1719 if (this.subscriptionForm.invalid || this.selectedEntityTypes.length === 0 || this.selectedEventTypes.length === 0) { 1720 this.subscriptionForm.markAllAsTouched(); 1721 return; 1722 } 1723 this.isSubmitting = true; 1724 if (this.isEditMode && this.editingSubscriptionId) { 1725 const request = { 1726 targetUrl: this.subscriptionForm.value.targetUrl, 1727 description: this.subscriptionForm.value.description || void 0, 1728 entityTypes: this.selectedEntityTypes.join(","), 1729 eventTypes: this.selectedEventTypes.join(",") 1730 }; 1731 this.webhookService.updateSubscription(this.editingSubscriptionId, request).pipe(finalize(() => this.isSubmitting = false)).subscribe({ 1732 next: () => { 1733 this.toastService.showSuccess(this.translateService.instant("webhookSandbox.subscriptions.updateSuccess")); 1734 this.closeForm(); 1735 this.loadSubscriptions(); 1736 }, 1737 error: (err) => { 1738 var _a; 1739 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to update subscription"); 1740 } 1741 }); 1742 } else { 1743 const request = { 1744 targetUrl: this.subscriptionForm.value.targetUrl, 1745 description: this.subscriptionForm.value.description || void 0, 1746 entityTypes: this.selectedEntityTypes.join(","), 1747 eventTypes: this.selectedEventTypes.join(",") 1748 }; 1749 this.webhookService.createSubscription(request).pipe(finalize(() => this.isSubmitting = false)).subscribe({ 1750 next: (response) => { 1751 this.createdSecret = response.secret; 1752 this.isSecretModalVisible = true; 1753 this.closeForm(); 1754 this.loadSubscriptions(); 1755 }, 1756 error: (err) => { 1757 var _a; 1758 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to create subscription"); 1759 } 1760 }); 1761 } 1762 }); 1763 } 1764 // Secret modal 1765 closeSecretModal() { 1766 this.isSecretModalVisible = false; 1767 this.createdSecret = null; 1768 this.isSecretVisible = false; 1769 } 1770 toggleSecretVisibility() { 1771 this.isSecretVisible = !this.isSecretVisible; 1772 } 1773 copySecret() { 1774 return __async(this, null, function* () { 1775 var _a; 1776 if (!this.createdSecret) 1777 return; 1778 try { 1779 yield Clipboard.write({ string: this.createdSecret }); 1780 this.toastService.showSuccess(this.translateService.instant("webhookSandbox.subscriptions.secretCopied")); 1781 } catch { 1782 (_a = navigator.clipboard) == null ? void 0 : _a.writeText(this.createdSecret); 1783 this.toastService.showSuccess(this.translateService.instant("webhookSandbox.subscriptions.secretCopied")); 1784 } 1785 }); 1786 } 1787 // Subscription actions 1788 testSubscription(sub) { 1789 return __async(this, null, function* () { 1790 this.webhookService.testSubscription(sub.id).subscribe({ 1791 next: (result) => { 1792 if (result.success) { 1793 this.toastService.showSuccess(`${this.translateService.instant("webhookSandbox.subscriptions.testSuccess")} (${result.httpStatusCode}, ${result.responseTimeMs}ms)`); 1794 } else { 1795 this.toastService.showError(`${this.translateService.instant("webhookSandbox.subscriptions.testFailed")}: ${result.errorMessage}`); 1796 } 1797 }, 1798 error: (err) => { 1799 var _a; 1800 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Test failed"); 1801 } 1802 }); 1803 }); 1804 } 1805 toggleSubscriptionActive(sub) { 1806 return __async(this, null, function* () { 1807 this.webhookService.updateSubscription(sub.id, { isActive: !sub.isActive }).subscribe({ 1808 next: () => { 1809 sub.isActive = !sub.isActive; 1810 this.toastService.showSuccess(sub.isActive ? "Subscription activated" : "Subscription deactivated"); 1811 }, 1812 error: (err) => { 1813 var _a; 1814 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to update subscription"); 1815 } 1816 }); 1817 }); 1818 } 1819 resetCircuitBreaker(sub) { 1820 return __async(this, null, function* () { 1821 this.webhookService.resetCircuitBreaker(sub.id).subscribe({ 1822 next: () => { 1823 sub.circuitBrokenUntil = void 0; 1824 sub.consecutiveFailures = 0; 1825 this.toastService.showSuccess("Circuit breaker reset"); 1826 }, 1827 error: (err) => { 1828 var _a; 1829 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to reset circuit breaker"); 1830 } 1831 }); 1832 }); 1833 } 1834 confirmDeleteSubscription(sub) { 1835 return __async(this, null, function* () { 1836 const alert = yield this.alertController.create({ 1837 header: this.translateService.instant("webhookSandbox.subscriptions.delete"), 1838 message: this.translateService.instant("webhookSandbox.subscriptions.deleteConfirm"), 1839 buttons: [ 1840 { 1841 text: this.translateService.instant("common.cancel"), 1842 role: "cancel" 1843 }, 1844 { 1845 text: this.translateService.instant("common.delete"), 1846 role: "destructive", 1847 handler: () => this.deleteSubscription(sub) 1848 } 1849 ] 1850 }); 1851 yield alert.present(); 1852 }); 1853 } 1854 deleteSubscription(sub) { 1855 this.webhookService.deleteSubscription(sub.id).subscribe({ 1856 next: () => { 1857 this.subscriptions = this.subscriptions.filter((s) => s.id !== sub.id); 1858 this.toastService.showSuccess("Subscription deleted"); 1859 }, 1860 error: (err) => { 1861 var _a; 1862 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to delete subscription"); 1863 } 1864 }); 1865 } 1866 // ==================== DELIVERIES TAB ==================== 1867 loadDeliveries(callback, append = false) { 1868 this.isLoadingDeliveries = true; 1869 if (this.isMockEnabled) { 1870 of(WebhookMockData.getDeliveries(this.deliveryStatusFilter, this.deliveryPage, 20)).pipe(delay(300), finalize(() => { 1871 this.isLoadingDeliveries = false;
1872 callback == null ? void 0 : callback(); 1873 })).subscribe((result) => { 1874 if (append) { 1875 this.deliveries = [...this.deliveries, ...result.items]; 1876 } else { 1877 this.deliveries = result.items; 1878 } 1879 this.hasMoreDeliveries = result.hasNextPage; 1880 }); 1881 return; 1882 } 1883 const params = { 1884 page: this.deliveryPage, 1885 pageSize: 20 1886 }; 1887 if (this.deliveryStatusFilter !== "all") { 1888 params.status = this.deliveryStatusFilter; 1889 } 1890 this.webhookService.getDeliveries(params).pipe(finalize(() => { 1891 this.isLoadingDeliveries = false; 1892 callback == null ? void 0 : callback(); 1893 })).subscribe({ 1894 next: (result) => { 1895 if (append) { 1896 this.deliveries = [...this.deliveries, ...result.items]; 1897 } else { 1898 this.deliveries = result.items; 1899 } 1900 this.hasMoreDeliveries = result.hasNextPage; 1901 }, 1902 error: (err) => { 1903 var _a; 1904 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to load deliveries"); 1905 } 1906 }); 1907 } 1908 onDeliveryFilterChange(event) { 1909 this.deliveryStatusFilter = event.detail.value; 1910 this.deliveryPage = 1; 1911 this.loadDeliveries(); 1912 } 1913 loadMoreDeliveries() { 1914 this.deliveryPage++; 1915 this.loadDeliveries(void 0, true); 1916 } 1917 retryDelivery(delivery) { 1918 this.webhookService.retryDelivery(delivery.id).subscribe({ 1919 next: () => { 1920 delivery.status = "Retrying"; 1921 this.toastService.showSuccess(this.translateService.instant("webhookSandbox.deliveries.retryScheduled")); 1922 }, 1923 error: (err) => { 1924 var _a; 1925 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to retry delivery"); 1926 } 1927 }); 1928 } 1929 getDeliveryStatusColor(status) { 1930 switch (status) { 1931 case "Delivered": 1932 return "success"; 1933 case "Failed": 1934 return "danger"; 1935 case "Retrying": 1936 return "warning"; 1937 case "Pending": 1938 return "medium"; 1939 default: 1940 return "medium"; 1941 } 1942 } 1943 formatTimeAgo(dateStr) { 1944 const date = new Date(dateStr); 1945 const now = /* @__PURE__ */ new Date(); 1946 const diffMs = now.getTime() - date.getTime(); 1947 const diffMins = Math.floor(diffMs / 6e4); 1948 if (diffMins < 1) 1949 return "just now"; 1950 if (diffMins < 60) 1951 return `${diffMins}m ago`; 1952 const diffHours = Math.floor(diffMins / 60); 1953 if (diffHours < 24) 1954 return `${diffHours}h ago`; 1955 const diffDays = Math.floor(diffHours / 24); 1956 return `${diffDays}d ago`; 1957 } 1958 // ==================== STATISTICS TAB ==================== 1959 loadStats(callback) { 1960 this.isLoadingStats = true; 1961 if (this.isMockEnabled) { 1962 of(WebhookMockData.getStats()).pipe(delay(300), finalize(() => { 1963 this.isLoadingStats = false; 1964 callback == null ? void 0 : callback(); 1965 })).subscribe((stats) => { 1966 this.stats = stats; 1967 }); 1968 return; 1969 } 1970 this.webhookService.getStats().pipe(finalize(() => { 1971 this.isLoadingStats = false; 1972 callback == null ? void 0 : callback(); 1973 })).subscribe({ 1974 next: (stats) => { 1975 this.stats = stats; 1976 }, 1977 error: (err) => { 1978 var _a; 1979 this.toastService.showError(((_a = err.error) == null ? void 0 : _a.message) || "Failed to load statistics"); 1980 } 1981 }); 1982 } 1983 getSuccessRate24h() { 1984 if (!this.stats || this.stats.deliveries.last24Hours.total === 0) 1985 return 0; 1986 return this.stats.deliveries.last24Hours.delivered / this.stats.deliveries.last24Hours.total * 100; 1987 } 1988 getSuccessRate7d() { 1989 if (!this.stats || this.stats.deliveries.last7Days.total === 0) 1990 return 0; 1991 return this.stats.deliveries.last7Days.delivered / this.stats.deliveries.last7Days.total * 100; 1992 } 1993 resetAllCircuitBreakers() { 1994 return __async(this, null, function* () { 1995 const alert = yield this.alertController.create({ 1996 header: this.translateService.instant("webhookSandbox.stats.resetAll"), 1997 message: "Reset all open circuit breakers?", 1998 buttons: [ 1999 { text: this.translateService.instant("common.cancel"), role: "cancel" }, 2000 { 2001 text: this.translateService.instant("common.ok"),
2002 handler: () => { 2003 this.subscriptions.filter((s) => this.isCircuitOpen(s)).forEach((s) => this.resetCircuitBreaker(s)); 2004 } 2005 } 2006 ] 2007 }); 2008 yield alert.present(); 2009 }); 2010 } 2011}; 2012_WebhookSandboxPage.MOCK_STORAGE_KEY = "webhook_sandbox_mock_enabled"; 2013_WebhookSandboxPage.\u0275fac = function WebhookSandboxPage_Factory(__ngFactoryType__) { 2014 return new (__ngFactoryType__ || _WebhookSandboxPage)(\u0275\u0275directiveInject(FormBuilder), \u0275\u0275directiveInject(WebhookService), \u0275\u0275directiveInject(ToastService), \u0275\u0275directiveInject(AlertController), \u0275\u0275directiveInject(TranslateService)); 2015}; 2016_WebhookSandboxPage.\u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _WebhookSandboxPage, selectors: [["app-webhook-sandbox"]], features: [\u0275\u0275ProvidersFeature([], [provideIcons({ 2017 lucideWebhook, 2018 lucideRefreshCw, 2019 lucidePlus, 2020 lucidePencil, 2021 lucideTrash2, 2022 lucidePlay, 2023 lucideCheck, 2024 lucideX, 2025 lucideTriangleAlert, 2026 lucideClock, 2027 lucideRotateCw, 2028 lucideCopy, 2029 lucideEye, 2030 lucideEyeOff, 2031 lucideActivity, 2032 lucideZap, 2033 lucideCircle, 2034 lucideCircleDot, 2035 lucideExternalLink, 2036 lucideChevronDown, 2037 lucideChevronUp, 2038 lucideFilter, 2039 lucideFlaskConical 2040})])], decls: 35, vars: 21, consts: [["slot", "start"], ["slot", "end"], [1, "mock-toggle"], ["name", "lucideFlaskConical", "size", "1em"], ["labelPlacement", "start", 3, "ionChange", "checked"], [3, "click"], ["name", "lucideRefreshCw", "size", "1.25em"], [3, "ionChange", "value"], ["value", "subscriptions"], ["value", "deliveries"], ["value", "statistics"], ["slot", "fixed", 3, "ionRefresh"], [1, "tab-content"], [1, "tab-content", "stats-tab"], [1, "loading-container"], [1, "empty-state"], [1, "fab-container"], ["expand", "block", 3, "click"], ["name", "lucidePlus", "size", "1.25em", "slot", "start"], ["name", "crescent"], ["name", "lucideWebhook", "size", "3em"], [1, "subscription-card", 3, "circuit-open"], [1, "subscription-card"], [1, "card-header-row"], [1, "url-container"], [1, "target-url"], ["target", "_blank", 1, "external-link", 3, "href"], ["name", "lucideExternalLink", "size", "0.9em"], [1, "action-buttons"], ["fill", "clear", "size", "small", 3, "click"], ["name", "lucidePlay", "size", "1em"], ["name", "lucidePencil", "size", "1em"], ["name", "lucideChevronUp", "size", "1em"], ["name", "lucideChevronDown", "size", "1em"], [1, "description"], [1, "types-row"], [1, "type-chips"], ["color", "primary", "outline", "true"], [1, "separator"], ["color", "secondary", "outline", "true"], [1, "status-row"], ["color", "danger"], ["color", "success"], ["color", "medium"], [1, "stat"], [1, "stat", "failed"], [1, "expanded-content"], ["name", "lucideTriangleAlert", "size", "0.8em"], ["name", "lucideCheck", "size", "0.8em"], ["lines", "none"], [3, "ionChange", "checked"], [1, "meta"], [1, "expanded-actions"], ["size", "small", "fill", "outline", "color", "warning"], ["size", "small", "fill", "outline", "color", "danger", 3, "click"], ["name", "lucideTrash2", "size", "1em", "slot", "start"], ["size", "small", "fill", "outline", "color", "warning", 3, "click"], ["name", "lucideRotateCw", "size", "1em", "slot", "start"], [1, "filter-row"], ["interface", "popover", "labelPlacement", "start", 3, "ionChange", "value", "label"], ["value", "all"], ["value", "Delivered"], ["value", "Failed"], ["value", "Retrying"], ["value", "Pending"], ["name", "lucideActivity", "size", "3em"], [1, "load-more"], [1, "delivery-item"], [1, "delivery-header"], [1, "event-info"], [3, "color"], ["name", "lucideX", "size", "0.8em"], ["name", "lucideRotateCw", "size", "0.8em"], ["name", "lucideClock", "size", "0.8em"], [1, "delivery-details"], [1, "target"], [1, "response-time"], [1, "time-ago"], [1, "error-message"], ["size", "small", "fill", "clear"], [1, "retry-info"], ["size", "small", "fill", "clear", 3, "click"], ["fill", "outline", 3, "click", "disabled"], ["name", "crescent", "slot", "start"], ["size", "6"], [1, "stat-card"], [1, "stat-value"], [1, "stat-breakdown"], [1, "active"], [1, "inactive"], [1, "stat-label"], ["size", "small", "fill", "outline"], ["size", "12"], [1, "stat-value", "large"], ["color", "success", 3, "value"], [1, "progress-label"], [1, "stat-breakdown", "horizontal"], [1, "success"], ["name", "lucideCheck", "size", "0.9em"], [1, "failed"], ["name", "lucideX", "size", "0.9em"], [1, "retrying"], ["name", "lucideRotateCw", "size", "0.9em"], [1, "pending"], ["name", "lucideClock", "size", "0.9em"], ["size", "small", "fill", "outline", 3, "click"], [1, "modal-backdrop", 3, "click"], [1, "form-modal"], [1, "modal-header"], ["fill", "clear", 3, "click"], ["name", "lucideX", "size", "1.5em"], [3, "ngSubmit", "formGroup"], [1, "form-field"], ["formControlName", "targetUrl", "type", "url", "placeholder", "https://your-service.com/webhook"], [1, "error-text"], ["formControlName", "description", "placeholder", "Optional description for this webhook", "rows", "2"], [1, "chip-selector"], [3, "color", "outline"], [1, "hint-text"], [1, "form-actions"], ["fill", "outline", 3, "click"], ["type", "submit", 3, "disabled"], [3, "click", "color", "outline"], [1, "form-modal", "secret-modal"], [1, "modal-header", "success"], ["name", "lucideCheck", "size", "1.5em"], [1, "secret-content"], [1, "warning-box"], ["name", "lucideTriangleAlert", "size", "1.25em"], [1, "secret-input-container"], ["readonly", "", 3, "value", "type"], ["name", "lucideEyeOff", "size", "1.25em"], ["name", "lucideEye", "size", "1.25em"], ["name", "lucideCopy", "size", "1.25em"], [1, "signature-hint"]], template: function WebhookSandboxPage_Template(rf, ctx) { 2041 if (rf & 1) {
2042 \u0275\u0275elementStart(0, "ion-header")(1, "ion-toolbar")(2, "ion-buttons", 0); 2043 \u0275\u0275element(3, "ion-menu-button"); 2044 \u0275\u0275elementEnd(); 2045 \u0275\u0275elementStart(4, "ion-title"); 2046 \u0275\u0275text(5); 2047 \u0275\u0275pipe(6, "translate"); 2048 \u0275\u0275elementEnd(); 2049 \u0275\u0275elementStart(7, "ion-buttons", 1)(8, "div", 2); 2050 \u0275\u0275element(9, "ng-icon", 3); 2051 \u0275\u0275elementStart(10, "ion-toggle", 4); 2052 \u0275\u0275listener("ionChange", function WebhookSandboxPage_Template_ion_toggle_ionChange_10_listener($event) { 2053 return ctx.toggleMockData($event); 2054 }); 2055 \u0275\u0275elementEnd()(); 2056 \u0275\u0275elementStart(11, "ion-button", 5); 2057 \u0275\u0275listener("click", function WebhookSandboxPage_Template_ion_button_click_11_listener() { 2058 return ctx.manualRefresh(); 2059 }); 2060 \u0275\u0275element(12, "ng-icon", 6); 2061 \u0275\u0275elementEnd()()(); 2062 \u0275\u0275elementStart(13, "ion-toolbar")(14, "ion-segment", 7); 2063 \u0275\u0275listener("ionChange", function WebhookSandboxPage_Template_ion_segment_ionChange_14_listener($event) { 2064 return ctx.onTabChange($event); 2065 }); 2066 \u0275\u0275elementStart(15, "ion-segment-button", 8)(16, "ion-label"); 2067 \u0275\u0275text(17); 2068 \u0275\u0275pipe(18, "translate"); 2069 \u0275\u0275elementEnd()(); 2070 \u0275\u0275elementStart(19, "ion-segment-button", 9)(20, "ion-label"); 2071 \u0275\u0275text(21); 2072 \u0275\u0275pipe(22, "translate"); 2073 \u0275\u0275elementEnd()(); 2074 \u0275\u0275elementStart(23, "ion-segment-button", 10)(24, "ion-label"); 2075 \u0275\u0275text(25); 2076 \u0275\u0275pipe(26, "translate"); 2077 \u0275\u0275elementEnd()()()()(); 2078 \u0275\u0275elementStart(27, "ion-content")(28, "ion-refresher", 11); 2079 \u0275\u0275listener("ionRefresh", function WebhookSandboxPage_Template_ion_refresher_ionRefresh_28_listener($event) { 2080 return ctx.doRefresh($event); 2081 }); 2082 \u0275\u0275element(29, "ion-refresher-content"); 2083 \u0275\u0275elementEnd(); 2084 \u0275\u0275template(30, WebhookSandboxPage_Conditional_30_Template, 9, 4, "div", 12)(31, WebhookSandboxPage_Conditional_31_Template, 22, 20, "div", 12)(32, WebhookSandboxPage_Conditional_32_Template, 3, 1, "div", 13)(33, WebhookSandboxPage_Conditional_33_Template, 45, 24)(34, WebhookSandboxPage_Conditional_34_Template, 33, 12); 2085 \u0275\u0275elementEnd(); 2086 } 2087 if (rf & 2) { 2088 \u0275\u0275advance(5); 2089 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(6, 13, "webhookSandbox.title")); 2090 \u0275\u0275advance(4); 2091 \u0275\u0275classProp("active", ctx.isMockEnabled); 2092 \u0275\u0275advance(); 2093 \u0275\u0275property("checked", ctx.isMockEnabled); 2094 \u0275\u0275advance(4); 2095 \u0275\u0275property("value", ctx.activeTab); 2096 \u0275\u0275advance(3); 2097 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(18, 15, "webhookSandbox.tabs.subscriptions")); 2098 \u0275\u0275advance(4); 2099 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(22, 17, "webhookSandbox.tabs.deliveries")); 2100 \u0275\u0275advance(4); 2101 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(26, 19, "webhookSandbox.tabs.statistics")); 2102 \u0275\u0275advance(5); 2103 \u0275\u0275conditional(ctx.activeTab === "subscriptions" ? 30 : -1); 2104 \u0275\u0275advance(); 2105 \u0275\u0275conditional(ctx.activeTab === "deliveries" ? 31 : -1); 2106 \u0275\u0275advance(); 2107 \u0275\u0275conditional(ctx.activeTab === "statistics" ? 32 : -1); 2108 \u0275\u0275advance(); 2109 \u0275\u0275conditional(ctx.isFormVisible ? 33 : -1); 2110 \u0275\u0275advance(); 2111 \u0275\u0275conditional(ctx.isSecretModalVisible ? 34 : -1); 2112 } 2113}, dependencies: [ 2114 CommonModule, 2115 DecimalPipe, 2116 ReactiveFormsModule, 2117 \u0275NgNoValidate, 2118 NgControlStatus, 2119 NgControlStatusGroup, 2120 FormGroupDirective, 2121 FormControlName, 2122 TranslateModule, 2123 TranslatePipe, 2124 NgIcon, 2125 IonHeader, 2126 IonToolbar, 2127 IonButtons, 2128 IonMenuButton, 2129 IonTitle, 2130 IonContent, 2131 IonSegment, 2132 IonSegmentButton, 2133 IonLabel, 2134 IonList, 2135 IonItem, 2136 IonCard, 2137 IonCardHeader, 2138 IonCardTitle, 2139 IonCardContent, 2140 IonButton, 2141 IonBadge, 2142 IonInput, 2143 IonTextarea,
2144 IonChip, 2145 IonRefresher, 2146 IonRefresherContent, 2147 IonSpinner, 2148 IonSelect, 2149 IonSelectOption, 2150 IonToggle, 2151 IonGrid, 2152 IonRow, 2153 IonCol, 2154 IonProgressBar, 2155 IonNote 2156], styles: ["\n\n.mock-toggle[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-right: 8px;\n}\n.mock-toggle[_ngcontent-%COMP%] ng-icon[_ngcontent-%COMP%] {\n color: var(--ion-color-medium);\n transition: color 0.2s ease;\n}\n.mock-toggle[_ngcontent-%COMP%] ng-icon.active[_ngcontent-%COMP%] {\n color: var(--ion-color-warning);\n}\n.mock-toggle[_ngcontent-%COMP%] ion-toggle[_ngcontent-%COMP%] {\n --track-background: var(--ion-color-medium);\n --track-background-checked: var(--ion-color-warning);\n --handle-background-checked: var(--ion-color-warning-contrast);\n padding: 0;\n}\n.tab-content[_ngcontent-%COMP%] {\n padding: 16px;\n padding-bottom: 80px;\n}\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 200px;\n}\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 300px;\n color: var(--ion-color-medium);\n text-align: center;\n}\n.empty-state[_ngcontent-%COMP%] ng-icon[_ngcontent-%COMP%] {\n opacity: 0.5;\n margin-bottom: 16px;\n}\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1.1em;\n}\n.subscription-card[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n.subscription-card.circuit-open[_ngcontent-%COMP%] {\n border-left: 4px solid var(--ion-color-danger);\n}\n.subscription-card[_ngcontent-%COMP%] ion-card-header[_ngcontent-%COMP%] {\n padding-bottom: 8px;\n}\n.subscription-card[_ngcontent-%COMP%] .card-header-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px;\n}\n.subscription-card[_ngcontent-%COMP%] .url-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n.subscription-card[_ngcontent-%COMP%] .url-container[_ngcontent-%COMP%] .target-url[_ngcontent-%COMP%] {\n font-size: 0.85em;\n font-weight: 500;\n color: var(--ion-color-primary);\n word-break: break-all;\n}\n.subscription-card[_ngcontent-%COMP%] .url-container[_ngcontent-%COMP%] .external-link[_ngcontent-%COMP%] {\n color: var(--ion-color-medium);\n flex-shrink: 0;\n}\n.subscription-card[_ngcontent-%COMP%] .action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0;\n flex-shrink: 0;\n}\n.subscription-card[_ngcontent-%COMP%] .action-buttons[_ngcontent-%COMP%] ion-button[_ngcontent-%COMP%] {\n --padding-start: 8px;\n --padding-end: 8px;\n}\n.subscription-card[_ngcontent-%COMP%] .description[_ngcontent-%COMP%] {\n font-size: 0.95em;\n font-weight: normal;\n margin-top: 4px;\n}\n.subscription-card[_ngcontent-%COMP%] .types-row[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n margin-bottom: 12px;\n}\n.subscription-card[_ngcontent-%COMP%] .types-row[_ngcontent-%COMP%] .separator[_ng
2156content-%COMP%] {\n color: var(--ion-color-medium);\n margin: 0 4px;\n}\n.subscription-card[_ngcontent-%COMP%] .types-row[_ngcontent-%COMP%] .type-chips[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.subscription-card[_ngcontent-%COMP%] .types-row[_ngcontent-%COMP%] ion-chip[_ngcontent-%COMP%] {\n height: 24px;\n font-size: 0.75em;\n margin: 0;\n}\n.subscription-card[_ngcontent-%COMP%] .status-row[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n}\n.subscription-card[_ngcontent-%COMP%] .status-row[_ngcontent-%COMP%] ion-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.subscription-card[_ngcontent-%COMP%] .status-row[_ngcontent-%COMP%] .stat[_ngcontent-%COMP%] {\n font-size: 0.85em;\n color: var(--ion-color-medium);\n}\n.subscription-card[_ngcontent-%COMP%] .status-row[_ngcontent-%COMP%] .stat.failed[_ngcontent-%COMP%] {\n color: var(--ion-color-danger);\n}\n.subscription-card[_ngcontent-%COMP%] .expanded-content[_ngcontent-%COMP%] {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid var(--ion-color-light);\n}\n.subscription-card[_ngcontent-%COMP%] .expanded-content[_ngcontent-%COMP%] .meta[_ngcontent-%COMP%] {\n font-size: 0.85em;\n color: var(--ion-color-medium);\n margin: 4px 0;\n}\n.subscription-card[_ngcontent-%COMP%] .expanded-content[_ngcontent-%COMP%] .expanded-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n.fab-container[_ngcontent-%COMP%] {\n position: fixed;\n bottom: 16px;\n left: 16px;\n right: 16px;\n z-index: 100;\n}\n.filter-row[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n}\n.filter-row[_ngcontent-%COMP%] ion-select[_ngcontent-%COMP%] {\n max-width: 300px;\n}\n.delivery-item[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 0;\n}\n.delivery-item[_ngcontent-%COMP%] .delivery-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n.delivery-item[_ngcontent-%COMP%] .delivery-header[_ngcontent-%COMP%] .event-info[_ngcontent-%COMP%] {\n font-weight: 500;\n font-size: 0.95em;\n}\n.delivery-item[_ngcontent-%COMP%] .delivery-header[_ngcontent-%COMP%] ion-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.delivery-item[_ngcontent-%COMP%] .delivery-details[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n font-size: 0.85em;\n color: var(--ion-color-medium);\n}\n.delivery-item[_ngcontent-%COMP%] .delivery-details[_ngcontent-%COMP%] .target[_ngcontent-%COMP%] {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.delivery-item[_ngcontent-%COMP%] .delivery-details[_ngcontent-%COMP%] .response-time[_ng
2156content-%COMP%] {\n color: var(--ion-color-success);\n}\n.delivery-item[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n margin-top: 8px;\n padding: 8px;\n background: var(--ion-color-danger-tint);\n border-radius: 4px;\n font-size: 0.85em;\n color: var(--ion-color-danger-shade);\n}\n.delivery-item[_ngcontent-%COMP%] .retry-info[_ngcontent-%COMP%] {\n margin-top: 4px;\n font-size: 0.8em;\n color: var(--ion-color-warning-shade);\n}\n.load-more[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 16px;\n}\n.stats-tab[_ngcontent-%COMP%] ion-grid[_ngcontent-%COMP%] {\n padding: 0;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] {\n height: 100%;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card.warning[_ngcontent-%COMP%] {\n border-left: 4px solid var(--ion-color-warning);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] ion-card-header[_ngcontent-%COMP%] {\n padding-bottom: 4px;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] ion-card-title[_ngcontent-%COMP%] {\n font-size: 0.85em;\n color: var(--ion-color-medium);\n text-transform: uppercase;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] ion-card-content[_ngcontent-%COMP%] {\n padding-top: 8px;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2em;\n font-weight: bold;\n color: var(--ion-color-dark);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-value.large[_ngcontent-%COMP%] {\n font-size: 2.5em;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.9em;\n color: var(--ion-color-medium);\n margin-top: 4px;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-top: 8px;\n font-size: 0.85em;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown.horizontal[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 12px;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] .active[_ngcontent-%COMP%], \n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] .success[_ngcontent-%COMP%] {\n color: var(--ion-color-success);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] .inactive[_ngcontent-%COMP%] {\n color: var(--ion-color-medium);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] .failed[_ngcontent-%COMP%] {\n color: var(--ion-color-danger);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] .retrying[_ngcontent-%COMP%] {\n color: var(--ion-color-warning);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] .pending[_ngcontent-%COMP%] {\n color: var(--ion-color-medium);\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .stat-breakdown[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] ion-progress-bar[_ngcontent-%COMP%] {\n margin: 12px 0 8px;\n height: 8px;\n border-radius: 4px;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] .progress-label[_ngcontent-%COMP%] {\n font-size: 0.9em;\n color: var(--ion-color-success);\n font-weight: 500;\n}\n.stats-tab[_ngcontent-%COMP%] .stat-card[_ngcontent-%COMP%] ion-note[_ngcontent-%COMP%] {\n display: block;\n margin-top: 8px;\n}\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000;\n}\n.form-modal[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 90%;\n max-width: 500px;\n max-height: 90vh;\n background: var(--ion-item-background, #ffffff);\n border-radius: 12px;\n z-index: 1001;\n overflow-y: auto;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\n animation: modalEnter 0.2s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .form-modal[_ngcontent-%COMP%] {\n background: var(--ion-item-background, #1e1e1e);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n }\n}
2156\n.form-modal[_ngcontent-%COMP%] .modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--ion-color-light);\n}\n.form-modal[_ngcontent-%COMP%] .modal-header.success[_ngcontent-%COMP%] {\n background: var(--ion-color-success);\n color: white;\n border-bottom: none;\n}\n.form-modal[_ngcontent-%COMP%] .modal-header.success[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.form-modal[_ngcontent-%COMP%] .modal-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1.2em;\n}\n.form-modal[_ngcontent-%COMP%] .modal-header[_ngcontent-%COMP%] ion-button[_ngcontent-%COMP%] {\n --padding-start: 8px;\n --padding-end: 8px;\n}\n.form-modal[_ngcontent-%COMP%] form[_ngcontent-%COMP%], \n.form-modal[_ngcontent-%COMP%] .secret-content[_ngcontent-%COMP%] {\n padding: 20px;\n}\n.form-modal[_ngcontent-%COMP%] .form-field[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n.form-modal[_ngcontent-%COMP%] .form-field[_ngcontent-%COMP%] ion-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.9em;\n font-weight: 500;\n margin-bottom: 8px;\n color: var(--ion-color-dark);\n}\n.form-modal[_ngcontent-%COMP%] .form-field[_ngcontent-%COMP%] ion-input[_ngcontent-%COMP%], \n.form-modal[_ngcontent-%COMP%] .form-field[_ngcontent-%COMP%] ion-textarea[_ngcontent-%COMP%] {\n --background: var(--ion-color-light);\n --border-radius: 8px;\n --padding-start: 12px;\n --padding-end: 12px;\n}\n.form-modal[_ngcontent-%COMP%] .form-field[_ngcontent-%COMP%] .error-text[_ngcontent-%COMP%] {\n display: block;\n color: var(--ion-color-danger);\n font-size: 0.8em;\n margin-top: 4px;\n}\n.form-modal[_ngcontent-%COMP%] .form-field[_ngcontent-%COMP%] .hint-text[_ngcontent-%COMP%] {\n display: block;\n color: var(--ion-color-medium);\n font-size: 0.8em;\n margin-top: 4px;\n}\n.form-modal[_ngcontent-%COMP%] .chip-selector[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.form-modal[_ngcontent-%COMP%] .chip-selector[_ngcontent-%COMP%] ion-chip[_ngcontent-%COMP%] {\n cursor: pointer;\n margin: 0;\n}\n.form-modal[_ngcontent-%COMP%] .form-actions[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--ion-color-light);\n margin-top: 20px;\n}\n.secret-modal[_ngcontent-%COMP%] .warning-box[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px;\n background: var(--ion-color-warning-tint);\n border-radius: 8px;\n margin-bottom: 20px;\n}\n.secret-modal[_ngcontent-%COMP%] .warning-box[_ngcontent-%COMP%] ng-icon[_ngcontent-%COMP%] {\n color: var(--ion-color-warning-shade);\n flex-shrink: 0;\n}\n.secret-modal[_ngcontent-%COMP%] .warning-box[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.9em;\n color: var(--ion-color-warning-shade);\n}\n.secret-modal[_ngcontent-%COMP%] .secret-input-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n background: var(--ion-color-light);\n border-radius: 8px;\n padding-right: 4px;\n}\n.secret-modal[_ngcontent-%COMP%] .secret-input-container[_ngcontent-%COMP%] ion-input[_ngcontent-%COMP%] {\n flex: 1;\n --background: transparent;\n font-family: monospace;\n font-size: 0.85em;\n}\n.secret-modal[_ngcontent-%COMP%] .secret-input-container[_ngcontent-%COMP%] ion-button[_ngcontent-%COMP%] {\n --padding-start: 8px;\n --padding-end: 8px;\n}\n.secret-modal[_ngcontent-%COMP%] .signature-hint[_ngcontent-%COMP%] {\n margin-top: 16px;\n font-size: 0.85em;\n color: var(--ion-color-medium);\n}\n.secret-modal[_ngcontent-%COMP%] .signature-hint[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n display: inline-block;\n background: var(--ion-color-light);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 0.9em;\n}\n.secret-modal[_ngcontent-%COMP%] .form-actions[_ngcontent-%COMP%] {\n border-top: none;\n margin-top: 0;\n padding-top: 0;\n}"] }); 2157var WebhookSandboxPage = _WebhookSandboxPage; 2158(() => { 2159 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(WebhookSandboxPage, [{ 2160 type: Component, 2161 args: [{ selector: "app-webhook-sandbox", standalone: true, imports: [ 2162 CommonModule, 2163 ReactiveFormsModule, 2164 TranslateModule, 2165 NgIcon, 2166 IonHeader, 2167 IonToolbar, 2168 IonButtons, 2169 IonMenuButton, 2170 IonTitle, 2171 IonContent, 2172 IonSegment, 2173 IonSegmentButton, 2174 IonLabel, 2175 IonList, 2176 IonItem, 2177 IonCard,
2178 IonCardHeader, 2179 IonCardTitle, 2180 IonCardContent, 2181 IonButton, 2182 IonBadge, 2183 IonInput, 2184 IonTextarea, 2185 IonChip, 2186 IonRefresher, 2187 IonRefresherContent, 2188 IonSpinner, 2189 IonSelect, 2190 IonSelectOption, 2191 IonToggle, 2192 IonGrid, 2193 IonRow, 2194 IonCol, 2195 IonProgressBar, 2196 IonNote 2197 ], viewProviders: [provideIcons({ 2198 lucideWebhook, 2199 lucideRefreshCw, 2200 lucidePlus, 2201 lucidePencil, 2202 lucideTrash2, 2203 lucidePlay, 2204 lucideCheck, 2205 lucideX, 2206 lucideTriangleAlert, 2207 lucideClock, 2208 lucideRotateCw, 2209 lucideCopy, 2210 lucideEye, 2211 lucideEyeOff, 2212 lucideActivity, 2213 lucideZap, 2214 lucideCircle, 2215 lucideCircleDot, 2216 lucideExternalLink, 2217 lucideChevronDown, 2218 lucideChevronUp, 2219 lucideFilter, 2220 lucideFlaskConical 2221 })], template: `<ion-header> 2222 <ion-toolbar> 2223 <ion-buttons slot="start"> 2224 <ion-menu-button></ion-menu-button> 2225 </ion-buttons> 2226 <ion-title>{{ 'webhookSandbox.title' | translate }}</ion-title> 2227 <ion-buttons slot="end"> 2228 <div class="mock-toggle"> 2229 <ng-icon name="lucideFlaskConical" size="1em" [class.active]="isMockEnabled"></ng-icon> 2230 <ion-toggle 2231 [checked]="isMockEnabled" 2232 (ionChange)="toggleMockData($event)" 2233 labelPlacement="start" 2234 ></ion-toggle> 2235 </div> 2236 <ion-button (click)="manualRefresh()"> 2237 <ng-icon name="lucideRefreshCw" size="1.25em"></ng-icon> 2238 </ion-button> 2239 </ion-buttons> 2240 </ion-toolbar> 2241 2242 <ion-toolbar> 2243 <ion-segment [value]="activeTab" (ionChange)="onTabChange($event)"> 2244 <ion-segment-button value="subscriptions"> 2245 <ion-label>{{ 'webhookSandbox.tabs.subscriptions' | translate }}</ion-label> 2246 </ion-segment-button> 2247 <ion-segment-button value="deliveries"> 2248 <ion-label>{{ 'webhookSandbox.tabs.deliveries' | translate }}</ion-label> 2249 </ion-segment-button> 2250 <ion-segment-button value="statistics"> 2251 <ion-label>{{ 'webhookSandbox.tabs.statistics' | translate }}</ion-label> 2252 </ion-segment-button> 2253 </ion-segment> 2254 </ion-toolbar> 2255</ion-header> 2256 2257<ion-content> 2258 <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)"> 2259 <ion-refresher-content></ion-refresher-content> 2260 </ion-refresher> 2261 2262 <!-- ==================== SUBSCRIPTIONS TAB ==================== --> 2263 @if (activeTab === 'subscriptions') { 2264 <div class="tab-content"> 2265 @if (isLoadingSubscriptions) { 2266 <div class="loading-container"> 2267 <ion-spinner name="crescent"></ion-spinner> 2268 </div> 2269 } @else if (subscriptions.length === 0) { 2270 <div class="empty-state"> 2271 <ng-icon name="lucideWebhook" size="3em"></ng-icon> 2272 <p>{{ 'webhookSandbox.subscriptions.noSubscriptions' | translate }}</p> 2273 </div> 2274 } @else { 2275 <ion-list> 2276 @for (sub of subscriptions; track sub.id) { 2277 <ion-card class="subscription-card" [class.circuit-open]="isCircuitOpen(sub)"> 2278 <ion-card-header> 2279 <div class="card-header-row"> 2280 <div class="url-container"> 2281 <span class="target-url">{{ sub.targetUrl }}</span> 2282 <a [href]="sub.targetUrl" target="_blank" class="external-link"> 2283 <ng-icon name="lucideExternalLink" size="0.9em"></ng-icon> 2284 </a> 2285 </div> 2286 <div class="action-buttons"> 2287 <ion-button fill="clear" size="small" (click)="testSubscription(sub)"> 2288 <ng-icon name="lucidePlay" size="1em"></ng-icon> 2289 </ion-button> 2290 <ion-button fill="clear" size="small" (click)="openEditForm(sub)"> 2291 <ng-icon name="lucidePencil" size="1em"></ng-icon> 2292 </ion-button> 2293 <ion-button fill="clear" size="small" (click)="toggleSubscriptionExpand(sub.id)"> 2294 @if (expandedSubscriptionId === sub.id) { 2295 <ng-icon name="lucideChevronUp" size="1em"></ng-icon> 2296 } @else { 2297 <ng-icon name="lucideChevronDown" size="1em"></ng-icon> 2298 } 2299 </ion-button> 2300 </div> 2301 </div> 2302 @if (sub.description) { 2303 <ion-card-title class="description">{{ sub.description }}</ion-card-title> 2304 } 2305 </ion-card-header> 2306 2307 <ion-card-content> 2308 <div class="types-row"> 2309 <div class="type-chips"> 2310 @for (et of sub.entityTypes; track et) { 2311 <ion-chip color="primary" outline="true">{{ 'webhookSandbox.entityTypes.' + et | translate }}</ion-chip> 2312 } 2313 </div>
2314 <span class="separator">|</span> 2315 <div class="type-chips"> 2316 @for (evt of sub.eventTypes; track evt) { 2317 <ion-chip color="secondary" outline="true">{{ 'webhookSandbox.eventTypes.' + evt | translate }}</ion-chip> 2318 } 2319 </div> 2320 </div> 2321 2322 <div class="status-row"> 2323 @if (isCircuitOpen(sub)) { 2324 <ion-badge color="danger"> 2325 <ng-icon name="lucideTriangleAlert" size="0.8em"></ng-icon> 2326 {{ 'webhookSandbox.subscriptions.circuitOpen' | translate }} ({{ getCircuitOpenUntil(sub) }}) 2327 </ion-badge> 2328 } @else if (sub.isActive) { 2329 <ion-badge color="success"> 2330 <ng-icon name="lucideCheck" size="0.8em"></ng-icon> 2331 {{ 'webhookSandbox.subscriptions.active' | translate }} 2332 </ion-badge> 2333 } @else { 2334 <ion-badge color="medium"> 2335 {{ 'webhookSandbox.subscriptions.inactive' | translate }} 2336 </ion-badge> 2337 } 2338 2339 <span class="stat">{{ sub.totalDeliveries }} delivered</span> 2340 @if (sub.totalFailures > 0) { 2341 <span class="stat failed">{{ sub.totalFailures }} failed</span> 2342 } 2343 </div> 2344 2345 @if (expandedSubscriptionId === sub.id) { 2346 <div class="expanded-content"> 2347 <ion-item lines="none"> 2348 <ion-label>{{ 'webhookSandbox.subscriptions.active' | translate }}</ion-label> 2349 <ion-toggle [checked]="sub.isActive" (ionChange)="toggleSubscriptionActive(sub)"></ion-toggle> 2350 </ion-item> 2351 2352 @if (sub.lastDeliveryAt) { 2353 <p class="meta">Last delivery: {{ formatTimeAgo(sub.lastDeliveryAt) }}</p> 2354 } 2355 @if (sub.lastSuccessAt) { 2356 <p class="meta">Last success: {{ formatTimeAgo(sub.lastSuccessAt) }}</p> 2357 } 2358 @if (sub.secretPrefix) { 2359 <p class="meta">Secret: {{ sub.secretPrefix }}...</p> 2360 } 2361 2362 <div class="expanded-actions"> 2363 @if (isCircuitOpen(sub)) { 2364 <ion-button size="small" fill="outline" color="warning" (click)="resetCircuitBreaker(sub)"> 2365 <ng-icon name="lucideRotateCw" size="1em" slot="start"></ng-icon> 2366 Reset Circuit 2367 </ion-button> 2368 } 2369 <ion-button size="small" fill="outline" color="danger" (click)="confirmDeleteSubscription(sub)"> 2370 <ng-icon name="lucideTrash2" size="1em" slot="start"></ng-icon> 2371 {{ 'webhookSandbox.subscriptions.delete' | translate }} 2372 </ion-button> 2373 </div> 2374 </div> 2375 } 2376 </ion-card-content> 2377 </ion-card> 2378 } 2379 </ion-list> 2380 } 2381 2382 <div class="fab-container"> 2383 <ion-button expand="block" (click)="openCreateForm()"> 2384 <ng-icon name="lucidePlus" size="1.25em" slot="start"></ng-icon> 2385 {{ 'webhookSandbox.subscriptions.create' | translate }} 2386 </ion-button> 2387 </div> 2388 </div> 2389 } 2390 2391 <!-- ==================== DELIVERIES TAB ==================== --> 2392 @if (activeTab === 'deliveries') { 2393 <div class="tab-content"> 2394 <div class="filter-row"> 2395 <ion-select 2396 [value]="deliveryStatusFilter" 2397 (ionChange)="onDeliveryFilterChange($event)" 2398 interface="popover" 2399 label="{{ 'webhookSandbox.deliveries.status' | translate }}" 2400 labelPlacement="start" 2401 > 2402 <ion-select-option value="all">{{ 'webhookSandbox.deliveries.filter.all' | translate }}</ion-select-option> 2403 <ion-select-option value="Delivered">{{ 'webhookSandbox.deliveries.delivered' | translate }}</ion-select-option> 2404 <ion-select-option value="Failed">{{ 'webhookSandbox.deliveries.failed' | translate }}</ion-select-option> 2405 <ion-select-option value="Retrying">{{ 'webhookSandbox.deliveries.retrying' | translate }}</ion-select-option> 2406 <ion-select-option value="Pending">{{ 'webhookSandbox.deliveries.pending' | translate }}</ion-select-option> 2407 </ion-select> 2408 </div> 2409 2410 @if (isLoadingDeliveries && deliveries.length === 0) { 2411 <div class="loading-container"> 2412 <ion-spinner name="crescent"></ion-spinner> 2413 </div> 2414 } @else if (deliveries.length === 0) { 2415 <div class="empty-state"> 2416 <ng-icon name="lucideActivity" size="3em"></ng-icon> 2417 <p>{{ 'webhookSandbox.deliveries.noDeliveries' | translate }}</p> 2418 </div> 2419 } @else { 2420 <ion-list> 2421 @for (delivery of deliveries; track delivery.id) { 2422 <ion-item> 2423 <div class="delivery-item"> 2424 <div class="delivery-header">
2425 <span class="event-info">{{ delivery.entityType }}.{{ delivery.eventType }}</span> 2426 <ion-badge [color]="getDeliveryStatusColor(delivery.status)"> 2427 @if (delivery.status === 'Delivered') { 2428 <ng-icon name="lucideCheck" size="0.8em"></ng-icon> 2429 } @else if (delivery.status === 'Failed') { 2430 <ng-icon name="lucideX" size="0.8em"></ng-icon> 2431 } @else if (delivery.status === 'Retrying') { 2432 <ng-icon name="lucideRotateCw" size="0.8em"></ng-icon> 2433 } @else { 2434 <ng-icon name="lucideClock" size="0.8em"></ng-icon> 2435 } 2436 {{ delivery.status }} 2437 @if (delivery.httpStatusCode) { 2438 ({{ delivery.httpStatusCode }}) 2439 } 2440 </ion-badge> 2441 </div> 2442 <div class="delivery-details"> 2443 @if (delivery.subscriptionTargetUrl) { 2444 <span class="target">{{ delivery.subscriptionTargetUrl }}</span> 2445 } 2446 @if (delivery.responseTimeMs) { 2447 <span class="response-time">{{ delivery.responseTimeMs }}ms</span> 2448 } 2449 <span class="time-ago">{{ formatTimeAgo(delivery.createdAt) }}</span> 2450 </div> 2451 @if (delivery.errorMessage) { 2452 <div class="error-message">{{ delivery.errorMessage }}</div> 2453 } 2454 @if (delivery.status === 'Failed') { 2455 <ion-button size="small" fill="clear" (click)="retryDelivery(delivery)"> 2456 <ng-icon name="lucideRotateCw" size="1em" slot="start"></ng-icon> 2457 {{ 'webhookSandbox.deliveries.retry' | translate }} 2458 </ion-button> 2459 } 2460 @if (delivery.status === 'Retrying' && delivery.nextRetryAt) { 2461 <div class="retry-info"> 2462 Attempt {{ delivery.attemptCount }}/8 | Next: {{ formatTimeAgo(delivery.nextRetryAt) }} 2463 </div> 2464 } 2465 </div> 2466 </ion-item> 2467 } 2468 </ion-list> 2469 2470 @if (hasMoreDeliveries) { 2471 <div class="load-more"> 2472 <ion-button fill="outline" (click)="loadMoreDeliveries()" [disabled]="isLoadingDeliveries"> 2473 @if (isLoadingDeliveries) { 2474 <ion-spinner name="crescent" slot="start"></ion-spinner> 2475 } 2476 Load More 2477 </ion-button> 2478 </div> 2479 } 2480 } 2481 </div> 2482 } 2483 2484 <!-- ==================== STATISTICS TAB ==================== --> 2485 @if (activeTab === 'statistics') { 2486 <div class="tab-content stats-tab"> 2487 @if (isLoadingStats) { 2488 <div class="loading-container"> 2489 <ion-spinner name="crescent"></ion-spinner> 2490 </div> 2491 } @else if (stats) { 2492 <ion-grid> 2493 <ion-row> 2494 <ion-col size="6"> 2495 <ion-card class="stat-card"> 2496 <ion-card-header> 2497 <ion-card-title>{{ 'webhookSandbox.stats.subscriptions' | translate }}</ion-card-title> 2498 </ion-card-header> 2499 <ion-card-content> 2500 <div class="stat-value">{{ stats.subscriptions.total }}</div> 2501 <div class="stat-breakdown"> 2502 <span class="active">{{ stats.subscriptions.active }} {{ 'webhookSandbox.stats.active' | translate }}</span> 2503 <span class="inactive">{{ stats.subscriptions.total - stats.subscriptions.active }} {{ 'webhookSandbox.stats.inactive' | translate }}</span> 2504 </div> 2505 </ion-card-content> 2506 </ion-card> 2507 </ion-col> 2508 2509 <ion-col size="6"> 2510 <ion-card class="stat-card" [class.warning]="stats.subscriptions.circuitOpen > 0"> 2511 <ion-card-header> 2512 <ion-card-title>{{ 'webhookSandbox.stats.circuitBreakers' | translate }}</ion-card-title> 2513 </ion-card-header> 2514 <ion-card-content> 2515 <div class="stat-value">{{ stats.subscriptions.circuitOpen }}</div> 2516 <div class="stat-label">{{ 'webhookSandbox.stats.open' | translate }}</div> 2517 @if (stats.subscriptions.circuitOpen > 0) { 2518 <ion-button size="small" fill="outline" (click)="resetAllCircuitBreakers()"> 2519 {{ 'webhookSandbox.stats.resetAll' | translate }} 2520 </ion-button> 2521 } 2522 </ion-card-content> 2523 </ion-card> 2524 </ion-col> 2525 </ion-row> 2526 2527 <ion-row> 2528 <ion-col size="12"> 2529 <ion-card class="stat-card"> 2530 <ion-card-header> 2531 <ion-card-title>{{ 'webhookSandbox.stats.deliveries24h' | translate }}</ion-card-title> 2532 </ion-card-header> 2533 <ion-card-content> 2534 <div class="stat-value large">{{ stats.deliveries.last24Hours.total }}</div> 2535 <ion-progress-bar [value]="getSuccessRate24h() / 100" color="success"></ion-progress-bar> 2536 <div class="progress-label">{{ getSuccessRate24h() | number:'1.1-1' }}% {{ 'webhookSandbox.stats.successRate' | translate }}</div> 2537 <div class="stat-breakdown horizontal">
2538 <span class="success"> 2539 <ng-icon name="lucideCheck" size="0.9em"></ng-icon> 2540 {{ stats.deliveries.last24Hours.delivered }} 2541 </span> 2542 <span class="failed"> 2543 <ng-icon name="lucideX" size="0.9em"></ng-icon> 2544 {{ stats.deliveries.last24Hours.failed }} 2545 </span> 2546 <span class="retrying"> 2547 <ng-icon name="lucideRotateCw" size="0.9em"></ng-icon> 2548 {{ stats.deliveries.last24Hours.retrying }} 2549 </span> 2550 <span class="pending"> 2551 <ng-icon name="lucideClock" size="0.9em"></ng-icon> 2552 {{ stats.deliveries.last24Hours.pending }} 2553 </span> 2554 </div> 2555 </ion-card-content> 2556 </ion-card> 2557 </ion-col> 2558 </ion-row> 2559 2560 <ion-row> 2561 <ion-col size="6"> 2562 <ion-card class="stat-card"> 2563 <ion-card-header> 2564 <ion-card-title>{{ 'webhookSandbox.stats.deliveries7d' | translate }}</ion-card-title> 2565 </ion-card-header> 2566 <ion-card-content> 2567 <div class="stat-value">{{ stats.deliveries.last7Days.total }}</div> 2568 <div class="stat-breakdown"> 2569 <span class="success">{{ stats.deliveries.last7Days.delivered }} delivered</span> 2570 <span class="failed">{{ stats.deliveries.last7Days.failed }} failed</span> 2571 </div> 2572 <div class="progress-label">{{ getSuccessRate7d() | number:'1.1-1' }}%</div> 2573 </ion-card-content> 2574 </ion-card> 2575 </ion-col> 2576 2577 <ion-col size="6"> 2578 <ion-card class="stat-card"> 2579 <ion-card-header> 2580 <ion-card-title>{{ 'webhookSandbox.stats.pendingEvents' | translate }}</ion-card-title> 2581 </ion-card-header> 2582 <ion-card-content> 2583 <div class="stat-value">{{ stats.events.pending }}</div> 2584 <div class="stat-label">{{ 'webhookSandbox.stats.queue' | translate }}</div> 2585 <ion-note>{{ stats.events.processedLast24Hours }} processed (24h)</ion-note> 2586 </ion-card-content> 2587 </ion-card> 2588 </ion-col> 2589 </ion-row> 2590 </ion-grid> 2591 } 2592 </div> 2593 } 2594 2595 <!-- ==================== CREATE/EDIT FORM MODAL ==================== --> 2596 @if (isFormVisible) { 2597 <div class="modal-backdrop" (click)="closeForm()"></div> 2598 <div class="form-modal"> 2599 <div class="modal-header"> 2600 <h2> 2601 @if (isEditMode) { 2602 {{ 'webhookSandbox.subscriptions.edit' | translate }} 2603 } @else { 2604 {{ 'webhookSandbox.subscriptions.create' | translate }} 2605 } 2606 </h2> 2607 <ion-button fill="clear" (click)="closeForm()"> 2608 <ng-icon name="lucideX" size="1.5em"></ng-icon> 2609 </ion-button> 2610 </div> 2611 2612 <form [formGroup]="subscriptionForm" (ngSubmit)="submitForm()"> 2613 <div class="form-field"> 2614 <ion-label>{{ 'webhookSandbox.subscriptions.targetUrl' | translate }} *</ion-label> 2615 <ion-input 2616 formControlName="targetUrl" 2617 type="url" 2618 placeholder="https://your-service.com/webhook" 2619 ></ion-input> 2620 @if (subscriptionForm.get('targetUrl')?.touched && subscriptionForm.get('targetUrl')?.hasError('required')) { 2621 <span class="error-text">URL is required</span> 2622 } 2623 @if (subscriptionForm.get('targetUrl')?.touched && subscriptionForm.get('targetUrl')?.hasError('pattern')) { 2624 <span class="error-text">Must be a valid HTTPS URL</span> 2625 } 2626 </div> 2627 2628 <div class="form-field"> 2629 <ion-label>{{ 'webhookSandbox.subscriptions.description' | translate }}</ion-label> 2630 <ion-textarea 2631 formControlName="description" 2632 placeholder="Optional description for this webhook" 2633 rows="2" 2634 ></ion-textarea> 2635 </div> 2636 2637 <div class="form-field"> 2638 <ion-label>{{ 'webhookSandbox.subscriptions.entityTypes' | translate }} *</ion-label> 2639 <div class="chip-selector"> 2640 @for (type of entityTypes; track type) { 2641 <ion-chip 2642 [color]="isEntityTypeSelected(type) ? 'primary' : 'medium'" 2643 [outline]="!isEntityTypeSelected(type)" 2644 (click)="toggleEntityType(type)" 2645 > 2646 {{ 'webhookSandbox.entityTypes.' + type | translate }} 2647 </ion-chip> 2648 } 2649 </div> 2650 @if (selectedEntityTypes.length === 0) {
2651 <span class="hint-text">Select at least one entity type</span> 2652 } 2653 </div> 2654 2655 <div class="form-field"> 2656 <ion-label>{{ 'webhookSandbox.subscriptions.eventTypes' | translate }} *</ion-label> 2657 <div class="chip-selector"> 2658 @for (type of eventTypes; track type) { 2659 <ion-chip 2660 [color]="isEventTypeSelected(type) ? 'secondary' : 'medium'" 2661 [outline]="!isEventTypeSelected(type)" 2662 (click)="toggleEventType(type)" 2663 > 2664 {{ 'webhookSandbox.eventTypes.' + type | translate }} 2665 </ion-chip> 2666 } 2667 </div> 2668 @if (selectedEventTypes.length === 0) { 2669 <span class="hint-text">Select at least one event type</span> 2670 } 2671 </div> 2672 2673 <div class="form-actions"> 2674 <ion-button fill="outline" (click)="closeForm()"> 2675 {{ 'common.cancel' | translate }} 2676 </ion-button> 2677 <ion-button type="submit" [disabled]="isSubmitting"> 2678 @if (isSubmitting) { 2679 <ion-spinner name="crescent" slot="start"></ion-spinner> 2680 } 2681 @if (isEditMode) { 2682 {{ 'common.update' | translate }} 2683 } @else { 2684 {{ 'webhookSandbox.subscriptions.create' | translate }} 2685 } 2686 </ion-button> 2687 </div> 2688 </form> 2689 </div> 2690 } 2691 2692 <!-- ==================== SECRET DISPLAY MODAL ==================== --> 2693 @if (isSecretModalVisible) { 2694 <div class="modal-backdrop" (click)="closeSecretModal()"></div> 2695 <div class="form-modal secret-modal"> 2696 <div class="modal-header success"> 2697 <ng-icon name="lucideCheck" size="1.5em"></ng-icon> 2698 <h2>{{ 'webhookSandbox.subscriptions.secretTitle' | translate }}</h2> 2699 </div> 2700 2701 <div class="secret-content"> 2702 <div class="warning-box"> 2703 <ng-icon name="lucideTriangleAlert" size="1.25em"></ng-icon> 2704 <p>{{ 'webhookSandbox.subscriptions.secretWarning' | translate }}</p> 2705 </div> 2706 2707 <div class="form-field"> 2708 <ion-label>{{ 'webhookSandbox.subscriptions.secretLabel' | translate }}</ion-label> 2709 <div class="secret-input-container"> 2710 <ion-input 2711 [value]="createdSecret" 2712 [type]="isSecretVisible ? 'text' : 'password'" 2713 readonly 2714 ></ion-input> 2715 <ion-button fill="clear" (click)="toggleSecretVisibility()"> 2716 @if (isSecretVisible) { 2717 <ng-icon name="lucideEyeOff" size="1.25em"></ng-icon> 2718 } @else { 2719 <ng-icon name="lucideEye" size="1.25em"></ng-icon> 2720 } 2721 </ion-button> 2722 <ion-button fill="clear" (click)="copySecret()"> 2723 <ng-icon name="lucideCopy" size="1.25em"></ng-icon> 2724 </ion-button> 2725 </div> 2726 </div> 2727 2728 <p class="signature-hint"> 2729 Use this secret to verify webhook signatures.<br> 2730 Header: <code>X-Webhook-Signature: sha256={hash}</code> 2731 </p> 2732 </div> 2733 2734 <div class="form-actions"> 2735 <ion-button expand="block" (click)="closeSecretModal()"> 2736 Done 2737 </ion-button> 2738 </div> 2739 </div> 2740 } 2741</ion-content> 2742`, styles: ["/* src/app/pages/webhook-sandbox/webhook-sandbox.page.scss */\n.mock-toggle {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-right: 8px;\n}\n.mock-toggle ng-icon {\n color: var(--ion-color-medium);\n transition: color 0.2s ease;\n}\n.mock-toggle ng-icon.active {\n color: var(--ion-color-warning);\n}\n.mock-toggle ion-toggle {\n --track-background: var(--ion-color-medium);\n --track-background-checked: var(--ion-color-warning);\n --handle-background-checked: var(--ion-color-warning-contrast);\n padding: 0;\n}\n.tab-content {\n padding: 16px;\n padding-bottom: 80px;\n}\n.loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 200px;\n}\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 300px;\n color: var(--ion-color-medium);\n text-align: center;\n}\n.empty-state ng-icon {\n opacity: 0.5;\n margin-bottom: 16px;\n}\n.empty-state p {\n font-size: 1.1em;\n}\n.subscription-card {\n margin-bottom: 12px;\n}\n.subscription-card.circuit-open {\n border-left: 4px solid var(--ion-color-danger);\n}\n.subscription-card ion-card-header {\n padding-bottom: 8px;\n}\n.subscription-card .card-header-row {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px;\n}\n.subscription-card .url-container {\n display: flex;\n align-items: center;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n.subscription-card .url-container .target-url {\n font-size: 0.85em;\n font-weight: 500;\n color: var(--ion-color-primary);\n word-break: break-all;\n}\n.subscription-card .url-container .external-link {\n color: var(--ion-color-medium);\n flex-shrink: 0;\n}\n.subscription-card .action-buttons {\n display: flex;\n gap: 0;\n flex-shrink: 0;\n}\n.subscription-card .action-buttons ion-button {\n --padding-start: 8px;\n --padding-end: 8px;\n}\n.subscription-card .description {\n font-size: 0.95em;\n font-weight: normal;\n margin-top: 4px;\n}\n.subscription-card .types-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n margin-bottom: 12px;\n}\n.subscription-card .types-row .separator {\n color: var(--ion-color-medium);\n margin: 0 4px;\n}\n.subscription-card .types-row .type-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.subscription-card .types-row ion-chip {\n height: 24px;\n font-size: 0.75em;\n margin: 0;\n}\n.subscription-card .status-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n}\n.subscription-card .status-row ion-badge {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.subscription-card .status-row .stat {\n font-size: 0.85em;\n color: var(--ion-color-medium);\n}\n.subscription-card .status-row .stat.failed {\n color: var(--ion-color-danger);\n}\n.subscription-card .expanded-content {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid var(--ion-color-light);\n}\n.subscription-card .expanded-content .meta {\n font-size: 0.85em;\n color: var(--ion-color-medium);\n margin: 4px 0;\n}\n.subscription-card .expanded-content .expanded-actions {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n.fab-container {\n position: fixed;\n bottom: 16px;\n left: 16px;\n right: 16px;\n z-index: 100;\n}\n.filter-row {\n margin-bottom: 16px;\n}\n.filter-row ion-select {\n max-width: 300px;\n}\n.delivery-item {\n width: 100%;\n padding: 8px 0;\n}\n.delivery-item .delivery-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n.delivery-item .delivery-header .event-info {\n font-weight: 500;\n font-size: 0.95em;\n}\n.delivery-item .delivery-header ion-badge {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.delivery-item .delivery-details {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n font-size: 0.85em;\n color: var(--ion-color-medium);\n}\n.delivery-item .delivery-details .target {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.delivery-item .delivery-details .response-time {\n color: var(--ion-color-success);\n}\n.delivery-item .error-message {\n margin-top: 8px;\n padding: 8px;\n background: var(--ion-color-danger-tint);\n border-radius: 4px;\n font-size: 0.85em;
2742\n color: var(--ion-color-danger-shade);\n}\n.delivery-item .retry-info {\n margin-top: 4px;\n font-size: 0.8em;\n color: var(--ion-color-warning-shade);\n}\n.load-more {\n display: flex;\n justify-content: center;\n padding: 16px;\n}\n.stats-tab ion-grid {\n padding: 0;\n}\n.stats-tab .stat-card {\n height: 100%;\n}\n.stats-tab .stat-card.warning {\n border-left: 4px solid var(--ion-color-warning);\n}\n.stats-tab .stat-card ion-card-header {\n padding-bottom: 4px;\n}\n.stats-tab .stat-card ion-card-title {\n font-size: 0.85em;\n color: var(--ion-color-medium);\n text-transform: uppercase;\n}\n.stats-tab .stat-card ion-card-content {\n padding-top: 8px;\n}\n.stats-tab .stat-card .stat-value {\n font-size: 2em;\n font-weight: bold;\n color: var(--ion-color-dark);\n}\n.stats-tab .stat-card .stat-value.large {\n font-size: 2.5em;\n}\n.stats-tab .stat-card .stat-label {\n font-size: 0.9em;\n color: var(--ion-color-medium);\n margin-top: 4px;\n}\n.stats-tab .stat-card .stat-breakdown {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-top: 8px;\n font-size: 0.85em;\n}\n.stats-tab .stat-card .stat-breakdown.horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 12px;\n}\n.stats-tab .stat-card .stat-breakdown .active,\n.stats-tab .stat-card .stat-breakdown .success {\n color: var(--ion-color-success);\n}\n.stats-tab .stat-card .stat-breakdown .inactive {\n color: var(--ion-color-medium);\n}\n.stats-tab .stat-card .stat-breakdown .failed {\n color: var(--ion-color-danger);\n}\n.stats-tab .stat-card .stat-breakdown .retrying {\n color: var(--ion-color-warning);\n}\n.stats-tab .stat-card .stat-breakdown .pending {\n color: var(--ion-color-medium);\n}\n.stats-tab .stat-card .stat-breakdown span {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.stats-tab .stat-card ion-progress-bar {\n margin: 12px 0 8px;\n height: 8px;\n border-radius: 4px;\n}\n.stats-tab .stat-card .progress-label {\n font-size: 0.9em;\n color: var(--ion-color-success);\n font-weight: 500;\n}\n.stats-tab .stat-card ion-note {\n display: block;\n margin-top: 8px;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000;\n}\n.form-modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 90%;\n max-width: 500px;\n max-height: 90vh;\n background: var(--ion-item-background, #ffffff);\n border-radius: 12px;\n z-index: 1001;\n overflow-y: auto;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\n animation: modalEnter 0.2s ease-out;\n}\n@media (prefers-color-scheme: dark) {\n .form-modal {\n background: var(--ion-item-background, #1e1e1e);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n }\n}\n.form-modal .modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--ion-color-light);\n}\n.form-modal .modal-header.success {\n background: var(--ion-color-success);\n color: white;\n border-bottom: none;\n}\n.form-modal .modal-header.success h2 {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.form-modal .modal-header h2 {\n margin: 0;\n font-size: 1.2em;\n}\n.form-modal .modal-header ion-button {\n --padding-start: 8px;\n --padding-end: 8px;\n}\n.form-modal form,\n.form-modal .secret-content {\n padding: 20px;\n}\n.form-modal .form-field {\n margin-bottom: 20px;\n}\n.form-modal .form-field ion-label {\n display: block;\n font-size: 0.9em;\n font-weight: 500;\n margin-bottom: 8px;\n color: var(--ion-color-dark);\n}\n.form-modal .form-field ion-input,\n.form-modal .form-field ion-textarea {\n --background: var(--ion-color-light);\n --border-radius: 8px;\n --padding-start: 12px;\n --padding-end: 12px;\n}\n.form-modal .form-field .error-text {\n display: block;\n color: var(--ion-color-danger);\n font-size: 0.8em;\n margin-top: 4px;\n}\n.form-modal .form-field .hint-text {\n display: block;\n color: var(--ion-color-medium);\n font-size: 0.8em;\n margin-top: 4px;\n}\n.form-modal .chip-selector {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.form-modal .chip-selector ion-chip {\n cursor: pointer;\n margin: 0;\n}\n.form-modal .form-actions {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--ion-color-light);\n margin-top: 20px;\n}\n.secret-modal .warning-box {\n display: flex;\n gap: 12px;\n padding: 16px;\n background: var(--ion-color-warning-tint);\n border-radius: 8px;\n margin-bottom: 20px;\n}\n.secret-modal .warning-box ng-icon {\n color: var(--ion-color-warning-shade);\n flex-shrink: 0;\n}\n.secret-modal .warning-box p {\n margin: 0;\n font-size: 0.9em;\n color: var(--ion-color-warning-shade);\n}\n.secret-modal .secret-input-container {\n display: flex;\n align-items: center;\n gap: 4px;\n background: var(--ion-color-light);\n border-radius: 8px;\n padding-right: 4px;\n}\n.secret-modal .secret-input-container ion-input {\n flex: 1;\n --background: transparent;\n font-family: monospace;\n font-size: 0.85em;\n}\n.secret-modal .secret-input-container ion-button {\n --padding-start: 8px;\n --padding-end: 8px;\n}\n.secret-modal .signature-hint {\n margin-top: 16px;\n font-size: 0.85em;\n color: var(--ion-color-medium);\n}\n.secret-modal .signature-hint code {\n display: inline-block;\n background: var(--ion-color-light);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 0.9em;\n}\n.secret-modal .form-actions {\n border-top: none;\n margin-top: 0;\n padding-top: 0;\n}\n"] }] 2743 }], () => [{ type: FormBuilder }, { type: WebhookService }, { type: ToastService }, { type: AlertController }, { type: TranslateService }], null); 2744})(); 2745(() => { 2746 (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(WebhookSandboxPage, { className: "WebhookSandboxPage", filePath: "src/app/pages/webhook-sandbox/webhook-sandbox.page.ts", lineNumber: 58 }); 2747})(); 2748export { 2749 WebhookSandboxPage 2750};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.