@webda/debug 4.0.0-beta.4 → 4.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/debugservice.service.d.ts +134 -23
- package/lib/debugservice.service.js +417 -73
- package/lib/debugservice.service.js.map +1 -1
- package/lib/introspection.d.ts +17 -0
- package/lib/introspection.js +52 -6
- package/lib/introspection.js.map +1 -1
- package/lib/security.d.ts +155 -0
- package/lib/security.js +217 -0
- package/lib/security.js.map +1 -0
- package/lib/tui/client.d.ts +4 -1
- package/lib/tui/client.js +10 -3
- package/lib/tui/client.js.map +1 -1
- package/lib/tui/tui.d.ts +2 -1
- package/lib/tui/tui.js +6 -3
- package/lib/tui/tui.js.map +1 -1
- package/package.json +17 -9
- package/webui/assets/favicon-CVPPk1M-.svg +1 -0
- package/webui/assets/index-BSEtev2p.js +51 -0
- package/webui/assets/index-Bw7FTaDv.css +1 -0
- package/webui/index.html +13 -20
- package/webui/app.js +0 -177
- package/webui/components/logs.js +0 -128
- package/webui/components/model-graph.js +0 -292
- package/webui/components/models.js +0 -213
- package/webui/components/operations.js +0 -315
- package/webui/components/requests.js +0 -264
- package/webui/components/schema-form.js +0 -268
- package/webui/components/services.js +0 -248
- package/webui/logo.svg +0 -1
- package/webui/styles.css +0 -685
- package/webui/vendor/htm.js +0 -1
- package/webui/vendor/preact-hooks.js +0 -2
- package/webui/vendor/preact.js +0 -2
- package/webui/webda.png +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--ifm-color-primary: #3578e5;--ifm-color-primary-dark: #1d68e1;--ifm-color-secondary: #ebedf0;--ifm-color-success: #00a400;--ifm-color-info: #54c7ec;--ifm-color-warning: #ffba00;--ifm-color-danger: #fa383e;--ifm-color-gray-0: #fff;--ifm-color-gray-100: #f5f6f7;--ifm-color-gray-200: #ebedf0;--ifm-color-gray-300: #dadde1;--ifm-color-gray-400: #ccd0d5;--ifm-color-gray-500: #bec3c9;--ifm-color-gray-600: #8d949e;--ifm-color-gray-700: #606770;--ifm-color-gray-800: #444950;--ifm-color-gray-900: #1c1e21;--ifm-color-gray-1000: #000;--ifm-color-emphasis-0: var(--ifm-color-gray-0);--ifm-color-emphasis-100: var(--ifm-color-gray-100);--ifm-color-emphasis-200: var(--ifm-color-gray-200);--ifm-color-emphasis-300: var(--ifm-color-gray-300);--ifm-color-emphasis-400: var(--ifm-color-gray-400);--ifm-color-emphasis-500: var(--ifm-color-gray-500);--ifm-color-emphasis-600: var(--ifm-color-gray-600);--ifm-color-emphasis-700: var(--ifm-color-gray-700);--ifm-color-emphasis-800: var(--ifm-color-gray-800);--ifm-color-emphasis-900: var(--ifm-color-gray-900);--ifm-color-emphasis-1000: var(--ifm-color-gray-1000);--ifm-color-content: var(--ifm-color-emphasis-900);--ifm-color-content-inverse: var(--ifm-color-emphasis-0);--ifm-color-content-secondary: #525860;--ifm-background-color: #fff;--ifm-background-surface-color: var(--ifm-color-content-inverse);--ifm-hover-overlay: rgba(0, 0, 0, .05);--ifm-font-color-base: var(--ifm-color-content);--ifm-font-color-secondary: var(--ifm-color-content-secondary);--ifm-font-family-base: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, BlinkMacSystemFont, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--ifm-font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--ifm-font-size-base: 100%;--ifm-line-height-base: 1.65;--ifm-code-font-size: 90%;--ifm-global-radius: .4rem;--ifm-global-spacing: 1rem;--ifm-link-color: var(--ifm-color-primary);--ifm-navbar-height: 0px}html[data-theme=dark]{--ifm-color-emphasis-0: var(--ifm-color-gray-1000);--ifm-color-emphasis-100: var(--ifm-color-gray-900);--ifm-color-emphasis-200: var(--ifm-color-gray-800);--ifm-color-emphasis-300: var(--ifm-color-gray-700);--ifm-color-emphasis-400: var(--ifm-color-gray-600);--ifm-color-emphasis-500: var(--ifm-color-gray-500);--ifm-color-emphasis-600: var(--ifm-color-gray-400);--ifm-color-emphasis-700: var(--ifm-color-gray-300);--ifm-color-emphasis-800: var(--ifm-color-gray-200);--ifm-color-emphasis-900: var(--ifm-color-gray-100);--ifm-color-emphasis-1000: var(--ifm-color-gray-0);--ifm-background-color: #1b1b1d;--ifm-background-surface-color: #242526;--ifm-hover-overlay: rgba(255, 255, 255, .05);--ifm-color-content: #e3e3e3;--ifm-color-content-secondary: rgba(255, 255, 255, 1)}html,body{margin:0;padding:0;height:100%;background:var(--ifm-background-color);color:var(--ifm-font-color-base);font:var(--ifm-font-size-base) / var(--ifm-line-height-base) var(--ifm-font-family-base);color-scheme:light}html[data-theme=dark]{color-scheme:dark}#app{min-height:100%;display:flex;flex-direction:column}#app>.webda-debug-ui{flex:1}.webda-debug-ui{--wdbg-orange: #ff9901;--wdbg-green: #7ebf6a;--wdbg-blue: #3f51b5;--wdbg-purple: #a855f7;--wdbg-neutral: var(--ifm-color-emphasis-700);--wdbg-red: var(--ifm-color-danger);--wdbg-yellow: var(--ifm-color-warning);--wdbg-border: var(--ifm-color-emphasis-300);--wdbg-surface: var(--ifm-background-surface-color);--wdbg-surface-2: var(--ifm-color-emphasis-100);--wdbg-muted: var(--ifm-color-emphasis-600);--wdbg-radius: var(--ifm-global-radius);--wdbg-mono: var(--ifm-font-family-monospace);--wdbg-graph-inheritance: var(--ifm-color-emphasis-500);--wdbg-graph-link: var(--wdbg-blue);--wdbg-graph-query: var(--wdbg-green);--wdbg-graph-parent: var(--wdbg-purple);--wdbg-graph-binary: var(--wdbg-orange);--wdbg-graph-map: var(--ifm-color-info);--focus-color: var(--wdbg-orange);display:flex;flex-direction:column;min-height:100%;font-family:var(--ifm-font-family-base);font-size:.9375rem;line-height:1.5;color:var(--ifm-font-color-base);background:var(--ifm-background-color);box-sizing:border-box}.webda-debug-ui *,.webda-debug-ui *:before,.webda-debug-ui *:after{box-sizing:border-box}[data-theme=dark] .webda-debug-ui{--wdbg-blue: #8c9eff;--wdbg-neutral: var(--ifm-color-emphasis-800)}.wdbg-header{display:flex;align-items:center;gap:.75rem;height:48px;padding:0 var(--ifm-global-spacing);background:var(--wdbg-surface);border-bottom:2px solid var(--wdbg-border);flex-shrink:0;transition:border-color .3s,filter .3s;animation:wdbg-focus-rotate 9s ease-in-out infinite}.wdbg-disconnected .wdbg-header{border-bottom-color:var(--wdbg-red)}.wdbg-disconnected .wdbg-brand,.wdbg-disconnected .wdbg-tabs{filter:grayscale(1);opacity:.5}.wdbg-disconnected .wdbg-tab-active{color:var(--wdbg-muted)!important;border-bottom-color:var(--wdbg-muted)!important}.wdbg-brand{display:flex;align-items:center;gap:.5rem;white-space:nowrap}.wdbg-logo{width:28px;height:28px;color:var(--wdbg-blue)}.wdbg-brand-title{font-size:1rem;font-weight:600}.wdbg-brand-title span{color:var(--focus-color)}@property --focus-color{syntax: "<color>"; inherits: true; initial-value: #ff9901;}@keyframes wdbg-focus-rotate{0%,to{--focus-color: #ff9901}25%{--focus-color: #7ebf6a}50%{--focus-color: #3f51b5}75%{--focus-color: #a855f7}}@media(prefers-reduced-motion:reduce){.wdbg-header{animation:none}}.wdbg-app-info{padding-left:.75rem;border-left:1px solid var(--wdbg-border);line-height:1.2;min-width:0;flex:0 1 auto}.wdbg-app-name{font-size:.8rem}.wdbg-app-cwd{font-size:.65rem;color:var(--wdbg-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:260px}.wdbg-tabs{display:flex;height:100%;overflow-x:auto;flex:1 0 auto;min-width:0;margin-left:.75rem}.wdbg-tab{padding:0 1rem;height:100%;display:flex;align-items:center;cursor:pointer;color:var(--wdbg-muted);background:none;border:none;border-bottom:2px solid transparent;margin-bottom:-2px;font:inherit;font-size:.875rem;white-space:nowrap;transition:color .15s,border-color .15s}.wdbg-tab:hover{color:var(--ifm-font-color-base)}.wdbg-header-status{margin-left:auto;font-size:.75rem;white-space:nowrap;flex:0 1 auto;min-width:0}.wdbg-header-status .wdbg-conn-label{overflow:hidden;text-overflow:ellipsis}.wdbg-conn{display:inline-flex;align-items:center;gap:.4rem}.wdbg-conn-dot{width:8px;height:8px;border-radius:50%;background:var(--ifm-color-emphasis-400);flex-shrink:0}.wdbg-conn-ok .wdbg-conn-dot{background:var(--ifm-color-success)}.wdbg-conn-warn .wdbg-conn-dot{background:var(--ifm-color-warning);animation:wdbg-pulse 1.5s infinite}.wdbg-conn-off .wdbg-conn-dot{background:var(--ifm-color-danger);animation:wdbg-pulse 1.5s infinite}@keyframes wdbg-pulse{0%,to{opacity:1}50%{opacity:.3}}.wdbg-content{flex:1;padding:var(--ifm-global-spacing);overflow:auto;min-height:0}.wdbg-footer{display:flex;gap:1rem;align-items:center;padding:.4rem var(--ifm-global-spacing);border-top:1px solid var(--wdbg-border);font-size:.75rem;color:var(--wdbg-muted);flex-shrink:0}.wdbg-footer a{color:var(--ifm-link-color)}.wdbg-mono,.webda-debug-ui code,.webda-debug-ui pre{font-family:var(--wdbg-mono)}.webda-debug-ui code{font-size:.85em;background:var(--wdbg-surface-2);padding:.05rem .3rem;border-radius:3px;border:none}.wdbg-muted{color:var(--wdbg-muted)}.wdbg-strong{font-weight:600}.wdbg-accent{color:var(--ifm-color-primary)}.wdbg-small{font-size:.75rem}.wdbg-italic{font-style:italic}.wdbg-break{word-break:break-all}.wdbg-nowrap{white-space:nowrap}.wdbg-pre-wrap{white-space:pre-wrap}.wdbg-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wdbg-right{text-align:right}.wdbg-pad{padding:.5rem}.wdbg-grow{flex:1}.wdbg-link{color:var(--ifm-link-color);text-decoration:none}.wdbg-link:hover{text-decoration:underline}.wdbg-title{font-size:1.25rem;font-weight:600;color:var(--ifm-color-primary);margin:0 0 .5rem}.wdbg-subtitle{font-size:.8125rem;margin-bottom:1rem}.wdbg-count{font-size:.8125rem;margin-bottom:.75rem}.wdbg-empty{color:var(--wdbg-muted);padding:2rem;text-align:center}.wdbg-facts{display:flex;gap:.5rem;margin-bottom:1rem;flex-wrap:wrap;align-items:center}.wdbg-fact{background:var(--wdbg-surface-2);padding:.375rem .625rem;border-radius:var(--wdbg-radius);font-size:.8125rem}.wdbg-badges{display:flex;gap:.375rem;flex-wrap:wrap;margin-bottom:1rem}.wdbg-row-between{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem;gap:.5rem}.wdbg-actions{margin-top:1rem;display:flex;gap:.5rem}.wdbg-preview{margin-top:.75rem}.wdbg-preview-label{color:var(--wdbg-muted);font-size:.75rem;text-transform:uppercase;letter-spacing:.05em}.wdbg-inheritance{display:flex;align-items:center;gap:.375rem;flex-wrap:wrap;font-size:.8125rem}.wdbg-pre{background:var(--wdbg-surface-2);padding:.75rem 1rem;border-radius:var(--wdbg-radius);overflow:auto;font-size:.8125rem;line-height:1.5;margin:.25rem 0 0}.wdbg-pre-inline{margin:0;white-space:pre-wrap;font-size:.8125rem;background:none;padding:0}.wdbg-code{margin:0;background:var(--wdbg-surface-2);padding:1rem;border-radius:var(--wdbg-radius);overflow:auto;max-height:500px;font-size:.8125rem;line-height:1.6;-moz-tab-size:2;tab-size:2}.wdbg-hl-keyword{color:#d73a49}.wdbg-hl-string{color:#032f62}.wdbg-hl-number{color:#005cc5}.wdbg-hl-comment{color:var(--wdbg-muted);font-style:italic}[data-theme=dark] .wdbg-hl-keyword{color:#ff7b72}[data-theme=dark] .wdbg-hl-string{color:#a5d6ff}[data-theme=dark] .wdbg-hl-number{color:#79c0ff}.wdbg-table-container{overflow-x:auto}.wdbg-table{width:100%;border-collapse:collapse;font-size:.875rem;display:table;margin:0}.wdbg-table th{text-align:left;padding:.5rem .75rem;border:none;border-bottom:1px solid var(--wdbg-border);color:var(--wdbg-muted);font-weight:500;white-space:nowrap;background:none}.wdbg-table td{padding:.5rem .75rem;border:none;border-bottom:1px solid var(--wdbg-border);vertical-align:top}.wdbg-table tr{background:none;border:none}.wdbg-table tr:hover td{background:var(--ifm-hover-overlay)}.wdbg-row-clickable{cursor:pointer}.wdbg-row-selected td{background:var(--wdbg-surface-2)}.wdbg-url-cell{max-width:400px}.wdbg-headers{width:100%;font-size:.75rem;border-collapse:collapse;display:table}.wdbg-headers td{padding:2px 8px 2px 0;vertical-align:top;border:none;background:none}.wdbg-headers td:first-child{white-space:nowrap}.wdbg-badge{display:inline-block;padding:.125rem .5rem;border-radius:3px;font-size:.75rem;font-weight:500;font-family:var(--wdbg-mono);line-height:1.4;background:var(--wdbg-surface-2);color:var(--wdbg-muted)}.wdbg-badge-small{font-size:.5625rem;padding:.0625rem .25rem}.wdbg-badge-green,.wdbg-method-get{background:#7ebf6a2e;color:#3d7a2c}.wdbg-badge-yellow,.wdbg-method-put{background:#ffba0033;color:#8a5a00}.wdbg-badge-red,.wdbg-method-delete{background:#fa383e26;color:#c21f25}.wdbg-badge-blue,.wdbg-method-post{background:#3f51b526;color:#3f51b5}.wdbg-badge-purple{background:#a855f726;color:#7e22ce}.wdbg-badge-orange,.wdbg-method-patch{background:#ff99012e;color:#b35f00}.wdbg-badge-muted{background:var(--wdbg-surface-2);color:var(--wdbg-muted)}[data-theme=dark] .wdbg-badge-green,[data-theme=dark] .wdbg-method-get{color:#7ebf6a}[data-theme=dark] .wdbg-badge-yellow,[data-theme=dark] .wdbg-method-put{color:#ffba00}[data-theme=dark] .wdbg-badge-red,[data-theme=dark] .wdbg-method-delete{color:#ff6b6f}[data-theme=dark] .wdbg-badge-blue,[data-theme=dark] .wdbg-method-post{color:#8c9eff}[data-theme=dark] .wdbg-badge-purple{color:#c084fc}[data-theme=dark] .wdbg-badge-orange,[data-theme=dark] .wdbg-method-patch{color:#ff9901}.wdbg-level{color:#fff}.wdbg-level-error{background:#ef4444}.wdbg-level-warn{background:#d99a00}.wdbg-level-info{background:#22a35b}.wdbg-level-debug{background:#6b7280}.wdbg-level-trace{background:#4b5563}.wdbg-status-2xx{color:var(--ifm-color-success)}.wdbg-status-3xx{color:var(--ifm-color-warning)}.wdbg-status-4xx{color:var(--wdbg-orange)}.wdbg-status-5xx{color:var(--ifm-color-danger)}.wdbg-status-pending{color:var(--wdbg-muted)}.wdbg-split{display:flex;gap:var(--ifm-global-spacing);min-height:0;height:calc(100vh - var(--ifm-navbar-height, 0px) - 48px - 3rem - 2rem)}.wdbg-split-left{width:280px;flex-shrink:0;overflow-y:auto;border-right:1px solid var(--wdbg-border);padding-right:1rem}.wdbg-split-right{flex:1;overflow-y:auto;min-width:0}.wdbg-list-item{display:flex;justify-content:space-between;align-items:center;gap:.5rem;padding:.5rem .75rem;cursor:pointer;border-radius:var(--wdbg-radius);font-size:.875rem;color:var(--wdbg-muted);transition:background .1s,color .1s;word-break:break-all}.wdbg-list-item:hover{background:var(--ifm-hover-overlay);color:var(--ifm-font-color-base)}.wdbg-list-item:focus-visible{outline:2px solid var(--ifm-color-primary);outline-offset:-2px}.wdbg-list-item-active{background:var(--wdbg-surface-2);color:var(--ifm-color-primary)}.wdbg-list-item-pinned{border-bottom:1px solid var(--wdbg-border);border-radius:0;margin-bottom:.5rem;padding-bottom:.625rem;color:var(--ifm-font-color-base)}.wdbg-op-item{min-width:0;flex:1}.wdbg-op-io{font-size:.6875rem;color:var(--wdbg-muted)}.wdbg-op-rest{font-size:.625rem;margin-top:.125rem;display:flex;align-items:center;gap:.25rem;min-width:0}.wdbg-search,.wdbg-select{width:100%;padding:.5rem .75rem;background:var(--ifm-background-color);border:1px solid var(--wdbg-border);border-radius:var(--wdbg-radius);color:var(--ifm-font-color-base);font:inherit;font-size:.875rem;margin-bottom:.75rem;outline:none}.wdbg-search:focus,.wdbg-select:focus{border-color:var(--ifm-color-primary)}.wdbg-select{width:auto}.wdbg-toolbar{display:flex;gap:.5rem;align-items:center;margin-bottom:.25rem}.wdbg-toolbar .wdbg-search,.wdbg-toolbar .wdbg-select{margin-bottom:0}.wdbg-checkbox{display:flex;align-items:center;gap:.25rem;color:var(--wdbg-muted);font-size:.75rem;white-space:nowrap}.wdbg-logs{overflow-y:auto;max-height:calc(100vh - var(--ifm-navbar-height, 0px) - 220px)}.wdbg-btn{font:inherit;font-size:.8125rem;padding:.375rem .875rem;border-radius:var(--wdbg-radius);border:1px solid var(--wdbg-border);background:var(--wdbg-surface);color:var(--ifm-font-color-base);cursor:pointer;transition:background .1s,color .1s}.wdbg-btn:hover:not(:disabled){background:var(--ifm-hover-overlay)}.wdbg-btn:disabled{opacity:.5;cursor:not-allowed}.wdbg-btn-primary{background:var(--ifm-color-primary);border-color:var(--ifm-color-primary);color:#fff}.wdbg-btn-primary:hover:not(:disabled){background:var(--ifm-color-primary-dark, var(--ifm-color-primary))}.wdbg-btn-ghost{background:transparent}.wdbg-btn-active{border-color:var(--ifm-color-primary);color:var(--ifm-color-primary)}.wdbg-theme-toggle{padding:.25rem .5rem;font-size:1rem;line-height:1}.wdbg-subtabs{display:flex;margin-bottom:.75rem;border-bottom:1px solid var(--wdbg-border);overflow-x:auto}.wdbg-subtab{padding:6px 16px;background:transparent;color:var(--wdbg-muted);border:none;border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;font:inherit;font-size:.875rem;white-space:nowrap}.wdbg-subtab-active{background:var(--wdbg-surface-2);color:var(--ifm-color-primary);border-bottom-color:var(--ifm-color-primary);font-weight:600}.wdbg-card{padding:1rem;border:1px solid var(--wdbg-border);border-radius:var(--wdbg-radius);margin-top:1rem;background:var(--wdbg-surface)}.wdbg-card-error{border-color:var(--ifm-color-danger)}.wdbg-alert{padding:.5rem .75rem;border-radius:var(--wdbg-radius);margin-bottom:1rem;font-size:.875rem}.wdbg-alert-danger{background:#fa383e1a;border:1px solid rgba(250,56,62,.3)}.wdbg-alert-warning{background:#ffba001f;border-bottom:1px solid rgba(255,186,0,.4);margin:0;border-radius:0}.wdbg-request-url{margin-left:.5rem}.wdbg-request-meta{display:flex;gap:1.5rem;font-size:.75rem;color:var(--wdbg-muted);margin-bottom:1rem}.wdbg-request-grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem}.wdbg-request-grid h4{margin:1rem 0 .5rem;font-size:.8125rem}.wdbg-request-grid h4:first-child{margin-top:0}.wdbg-connection-error{max-width:640px;margin:2rem auto;padding:1.5rem;border:1px solid var(--wdbg-border);border-radius:var(--wdbg-radius);background:var(--wdbg-surface)}.wdbg-connection-error h2{margin:0 0 .75rem;font-size:1.125rem}.wdbg-connection-error p{margin:0 0 .5rem}.wdbg-port-picker{display:flex;gap:.5rem;align-items:center;margin-top:1rem;padding-top:1rem;border-top:1px solid var(--wdbg-border)}.wdbg-port-picker label{font-size:.8125rem;color:var(--wdbg-muted)}.wdbg-port-picker .wdbg-search{width:120px;margin-bottom:0}.wdbg-detail-section{margin-bottom:1.5rem}.wdbg-detail-section h3{font-size:.8125rem;color:var(--wdbg-muted);margin:0 0 .5rem;text-transform:uppercase;letter-spacing:.05em}.wdbg-json-tree{font-family:var(--wdbg-mono);font-size:.8125rem;line-height:1.6}.wdbg-json-key{color:var(--ifm-color-primary)}.wdbg-json-string{color:#22863a}.wdbg-json-number{color:#b35f00}.wdbg-json-boolean{color:#7e22ce}.wdbg-json-null{color:var(--wdbg-muted)}[data-theme=dark] .wdbg-json-string{color:#7ebf6a}[data-theme=dark] .wdbg-json-number{color:#ff9901}[data-theme=dark] .wdbg-json-boolean{color:#c084fc}.wdbg-json-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--wdbg-muted);font-size:.6rem}.wdbg-json-indent{padding-left:1.25rem}.wdbg-graph{display:flex;flex-direction:column;height:100%}.wdbg-graph-legend{display:flex;gap:1rem;margin-bottom:.5rem;flex-wrap:wrap;align-items:center;flex-shrink:0}.wdbg-graph-legend-item{display:flex;align-items:center;gap:.3rem;font-size:.7rem;color:var(--wdbg-muted)}.wdbg-graph-legend-dot{width:8px;height:8px;border-radius:50%;display:inline-block}.wdbg-graph-legend-line{width:16px;height:0;border-top-width:2px;display:inline-block}.wdbg-graph-canvas{flex:1;overflow:auto;border:1px solid var(--wdbg-border);border-radius:var(--wdbg-radius);background:var(--ifm-background-color);min-height:200px}.wdbg-graph-node{cursor:pointer}.wdbg-graph-node rect{fill:var(--wdbg-surface-2);stroke:var(--wdbg-blue)}.wdbg-graph-node text{fill:var(--ifm-font-color-base);font-family:var(--ifm-font-family-base)}.wdbg-graph-node:hover rect{stroke:var(--ifm-color-primary)}.wdbg-graph-node-selected rect{stroke:var(--wdbg-orange)}.wdbg-graph-node-selected text{fill:var(--wdbg-orange)}.wdbg-graph-label{font-family:var(--wdbg-mono)}.wdbg-sf-root{font-size:.875rem}.wdbg-sf-title{font-size:1rem;font-weight:600;color:var(--ifm-color-primary);margin-bottom:.25rem}.wdbg-sf-schema-desc{color:var(--wdbg-muted);font-size:.8125rem;margin-bottom:1rem;line-height:1.4}.wdbg-sf-empty{color:var(--wdbg-muted);padding:1rem 0}.wdbg-sf-fields{display:flex;flex-direction:column;gap:.75rem}.wdbg-sf-field{padding:.5rem .625rem;border-radius:var(--wdbg-radius);border:1px solid transparent;transition:border-color .15s}.wdbg-sf-field:hover{border-color:var(--wdbg-border)}.wdbg-sf-has-value{border-left:2px solid var(--ifm-color-primary)}.wdbg-sf-label-row{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.125rem}.wdbg-sf-label{font-weight:500;font-size:.8125rem}.wdbg-sf-required{color:var(--ifm-color-danger);margin-left:.125rem}.wdbg-sf-type{font-family:var(--wdbg-mono);font-size:.6875rem;color:var(--wdbg-muted);background:var(--wdbg-surface-2);padding:.0625rem .375rem;border-radius:3px}.wdbg-sf-description{color:var(--wdbg-muted);font-size:.75rem;margin-bottom:.375rem;line-height:1.4}.wdbg-sf-default{font-size:.6875rem;color:var(--wdbg-muted);margin-top:.25rem}.wdbg-sf-input{width:100%;padding:.375rem .5rem;background:var(--ifm-background-color);border:1px solid var(--wdbg-border);border-radius:var(--wdbg-radius);color:var(--ifm-font-color-base);font:inherit;font-size:.8125rem;outline:none;transition:border-color .15s}.wdbg-sf-input:focus{border-color:var(--ifm-color-primary)}.wdbg-sf-input:read-only,.wdbg-sf-input:disabled{opacity:.6;cursor:not-allowed}.wdbg-sf-textarea{font-family:var(--wdbg-mono);font-size:.75rem;resize:vertical;min-height:2.5rem}.wdbg-sf-collapsible{border:1px solid var(--wdbg-border);border-radius:var(--wdbg-radius);overflow:hidden}.wdbg-sf-collapsible-header{display:flex;align-items:center;gap:.375rem;padding:.375rem .5rem;background:var(--wdbg-surface-2);cursor:pointer;-webkit-user-select:none;user-select:none;font-size:.8125rem}.wdbg-sf-collapsible-header:hover{background:var(--ifm-hover-overlay)}.wdbg-sf-chevron{font-size:.5rem;color:var(--wdbg-muted);transition:transform .15s}.wdbg-sf-open{transform:rotate(90deg)}.wdbg-sf-collapsible-title{font-weight:500}.wdbg-sf-badge{font-family:var(--wdbg-mono);font-size:.625rem;color:var(--wdbg-muted);background:var(--ifm-background-color);padding:.0625rem .3rem;border-radius:3px;margin-left:auto}.wdbg-sf-collapsible-body{padding:.5rem;border-top:1px solid var(--wdbg-border)}.wdbg-sf-array{display:flex;flex-direction:column;gap:.375rem}.wdbg-sf-array-item{display:flex;gap:.375rem;align-items:flex-start}.wdbg-sf-array-item-content{flex:1;min-width:0}.wdbg-sf-btn{font:inherit;font-size:.75rem;padding:.25rem .5rem;border:1px solid var(--wdbg-border);border-radius:3px;background:var(--wdbg-surface-2);color:var(--wdbg-muted);cursor:pointer}.wdbg-sf-btn:hover{background:var(--ifm-hover-overlay);color:var(--ifm-font-color-base)}.wdbg-sf-btn-remove{color:var(--ifm-color-danger);font-size:.875rem;line-height:1;flex-shrink:0}.wdbg-sf-btn-add{align-self:flex-start;margin-top:.125rem}.webda-debug-ui ::-webkit-scrollbar{width:6px;height:6px}.webda-debug-ui ::-webkit-scrollbar-thumb{background:var(--wdbg-border);border-radius:3px}.wdbg-hosted-bar{display:flex;align-items:center;gap:1rem;padding:.35rem var(--ifm-global-spacing);background:var(--ifm-background-surface-color);border-bottom:1px solid var(--ifm-color-emphasis-300);font-size:.875rem;font-family:var(--ifm-font-family-base)}.wdbg-hosted-brand{display:inline-flex;align-items:center;gap:.4rem;font-weight:600;color:var(--ifm-font-color-base);text-decoration:none}.wdbg-hosted-brand .wdbg-logo{width:22px;height:22px;color:#3f51b5}.wdbg-hosted-link{margin-left:auto;color:var(--ifm-link-color)}.wdbg-boot{padding:3rem var(--ifm-global-spacing);text-align:center;color:var(--ifm-color-emphasis-700)}.wdbg-graph-toggle{margin-left:auto}@media(max-width:1440px){.wdbg-app-cwd{max-width:180px}}@media(max-width:1280px){.wdbg-header-status .wdbg-conn-label,.wdbg-app-cwd{display:none}.wdbg-tab{padding:0 .75rem}}@media(max-width:1024px){.wdbg-app-info,.wdbg-brand-title{display:none}}@media(max-width:768px){.wdbg-split{flex-direction:column;height:auto}.wdbg-split-left{width:100%;border-right:none;border-bottom:1px solid var(--wdbg-border);padding-right:0;padding-bottom:1rem;max-height:200px}.wdbg-request-grid{grid-template-columns:1fr}.wdbg-app-info,.wdbg-conn-label{display:none}}
|
package/webui/index.html
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
17
|
-
</head>
|
|
18
|
-
<body>
|
|
19
|
-
<div id="app"></div>
|
|
20
|
-
<script type="module" src="/app.js"></script>
|
|
21
|
-
</body>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="robots" content="noindex" />
|
|
7
|
+
<title>Webda Debug Dashboard</title>
|
|
8
|
+
<link rel="icon" href="./assets/favicon-CVPPk1M-.svg" type="image/svg+xml" />
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-BSEtev2p.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="./assets/index-Bw7FTaDv.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="app"></div>
|
|
14
|
+
</body>
|
|
22
15
|
</html>
|
package/webui/app.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { h, render } from "preact";
|
|
2
|
-
import { useState, useEffect, useRef, useCallback } from "preact/hooks";
|
|
3
|
-
import htm from "htm";
|
|
4
|
-
|
|
5
|
-
import { ModelsPanel } from "./components/models.js";
|
|
6
|
-
import { ServicesPanel } from "./components/services.js";
|
|
7
|
-
import { OperationsPanel } from "./components/operations.js";
|
|
8
|
-
import { RequestsPanel } from "./components/requests.js";
|
|
9
|
-
import { LogsPanel } from "./components/logs.js";
|
|
10
|
-
|
|
11
|
-
const html = htm.bind(h);
|
|
12
|
-
|
|
13
|
-
const TABS = [
|
|
14
|
-
{ id: "logs", label: "Logs", color: "#f7992c" },
|
|
15
|
-
{ id: "models", label: "Models", color: "#81bf6b" },
|
|
16
|
-
{ id: "services", label: "Services", color: "#6b8fd4" },
|
|
17
|
-
{ id: "operations", label: "Operations", color: "#f4f4f4" },
|
|
18
|
-
{ id: "requests", label: "Requests", color: "#6b8fd4" }
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Fetch JSON from the debug API.
|
|
23
|
-
* @param {string} path
|
|
24
|
-
* @returns {Promise<any>}
|
|
25
|
-
*/
|
|
26
|
-
async function fetchApi(path) {
|
|
27
|
-
const res = await fetch(path);
|
|
28
|
-
return res.json();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function App() {
|
|
32
|
-
const [tab, setTab] = useState("logs");
|
|
33
|
-
const [wsConnected, setWsConnected] = useState(false);
|
|
34
|
-
const [wsEvents, setWsEvents] = useState([]);
|
|
35
|
-
const [dataVersion, setDataVersion] = useState(0);
|
|
36
|
-
const [cache, setCache] = useState({});
|
|
37
|
-
const wsRef = useRef(null);
|
|
38
|
-
const reconnectTimer = useRef(null);
|
|
39
|
-
|
|
40
|
-
// Load all data upfront and on rebuild (restart event)
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
Promise.all([
|
|
43
|
-
fetchApi("/api/info").catch(() => null),
|
|
44
|
-
fetchApi("/api/models").catch(() => []),
|
|
45
|
-
fetchApi("/api/services").catch(() => []),
|
|
46
|
-
fetchApi("/api/operations").catch(() => []),
|
|
47
|
-
fetchApi("/api/config").catch(() => {}),
|
|
48
|
-
fetchApi("/api/requests").catch(() => []),
|
|
49
|
-
fetchApi("/api/logs").catch(() => [])
|
|
50
|
-
]).then(([info, models, services, operations, config, requests, logs]) => {
|
|
51
|
-
setCache({ info, models, services, operations, config, requests, logs });
|
|
52
|
-
});
|
|
53
|
-
}, [dataVersion]);
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
const onKeyDown = (e) => {
|
|
57
|
-
if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA" || e.target.tagName === "SELECT") return;
|
|
58
|
-
if (e.key === "ArrowLeft") {
|
|
59
|
-
e.preventDefault();
|
|
60
|
-
setTab((prev) => {
|
|
61
|
-
const idx = TABS.findIndex((t) => t.id === prev);
|
|
62
|
-
return TABS[(idx - 1 + TABS.length) % TABS.length].id;
|
|
63
|
-
});
|
|
64
|
-
} else if (e.key === "ArrowRight") {
|
|
65
|
-
e.preventDefault();
|
|
66
|
-
setTab((prev) => {
|
|
67
|
-
const idx = TABS.findIndex((t) => t.id === prev);
|
|
68
|
-
return TABS[(idx + 1) % TABS.length].id;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
window.addEventListener("keydown", onKeyDown);
|
|
73
|
-
return () => window.removeEventListener("keydown", onKeyDown);
|
|
74
|
-
}, []);
|
|
75
|
-
|
|
76
|
-
const connectWs = useCallback(() => {
|
|
77
|
-
if (wsRef.current && wsRef.current.readyState <= 1) return;
|
|
78
|
-
|
|
79
|
-
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
|
|
80
|
-
const ws = new WebSocket(`${protocol}//${location.host}/ws`);
|
|
81
|
-
wsRef.current = ws;
|
|
82
|
-
|
|
83
|
-
ws.addEventListener("open", () => {
|
|
84
|
-
setWsConnected(true);
|
|
85
|
-
if (reconnectTimer.current) {
|
|
86
|
-
clearTimeout(reconnectTimer.current);
|
|
87
|
-
reconnectTimer.current = null;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
ws.addEventListener("message", (e) => {
|
|
92
|
-
try {
|
|
93
|
-
const data = JSON.parse(e.data);
|
|
94
|
-
if (data.type === "restart") {
|
|
95
|
-
// Trigger data refetch across all panels
|
|
96
|
-
setDataVersion((v) => v + 1);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
// Dispatch custom event so individual panels can listen
|
|
100
|
-
window.dispatchEvent(new CustomEvent("debug-ws-event", { detail: data }));
|
|
101
|
-
setWsEvents((prev) => [data, ...prev].slice(0, 500));
|
|
102
|
-
} catch {
|
|
103
|
-
// ignore parse errors
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
ws.addEventListener("close", () => {
|
|
108
|
-
setWsConnected(false);
|
|
109
|
-
wsRef.current = null;
|
|
110
|
-
// Auto-reconnect after 2 seconds
|
|
111
|
-
reconnectTimer.current = setTimeout(connectWs, 2000);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
ws.addEventListener("error", () => {
|
|
115
|
-
ws.close();
|
|
116
|
-
});
|
|
117
|
-
}, []);
|
|
118
|
-
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
connectWs();
|
|
121
|
-
return () => {
|
|
122
|
-
if (wsRef.current) wsRef.current.close();
|
|
123
|
-
if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
|
|
124
|
-
};
|
|
125
|
-
}, [connectWs]);
|
|
126
|
-
|
|
127
|
-
const renderPanel = () => {
|
|
128
|
-
switch (tab) {
|
|
129
|
-
case "models":
|
|
130
|
-
return html`<${ModelsPanel} data=${cache.models} fetchApi=${fetchApi} dataVersion=${dataVersion} />`;
|
|
131
|
-
case "services":
|
|
132
|
-
return html`<${ServicesPanel} data=${cache.services} config=${cache.config} fetchApi=${fetchApi} dataVersion=${dataVersion} />`;
|
|
133
|
-
case "operations":
|
|
134
|
-
return html`<${OperationsPanel} data=${cache.operations} fetchApi=${fetchApi} dataVersion=${dataVersion} />`;
|
|
135
|
-
case "requests":
|
|
136
|
-
return html`<${RequestsPanel} data=${cache.requests} fetchApi=${fetchApi} dataVersion=${dataVersion} wsEvents=${wsEvents} />`;
|
|
137
|
-
case "logs":
|
|
138
|
-
return html`<${LogsPanel} data=${cache.logs} fetchApi=${fetchApi} dataVersion=${dataVersion} />`;
|
|
139
|
-
default:
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
return html`
|
|
145
|
-
<div class="header ${wsConnected ? "" : "disconnected"}">
|
|
146
|
-
<div class="header-logo">
|
|
147
|
-
<img src="/logo.svg" alt="Webda" />
|
|
148
|
-
<div class="header-title">web<span>da</span> debug</div>
|
|
149
|
-
${cache.info && html`<div class="header-app-info">
|
|
150
|
-
<div class="header-app-name">${cache.info.package?.name || "unknown"}</div>
|
|
151
|
-
<div class="header-cwd">${(cache.info.workingDirectory || "").replace(/^\/(Users|home)\/[^/]+\//, "~/")}</div>
|
|
152
|
-
</div>`}
|
|
153
|
-
</div>
|
|
154
|
-
<nav class="nav-tabs">
|
|
155
|
-
${TABS.map(
|
|
156
|
-
(t) => html`
|
|
157
|
-
<button
|
|
158
|
-
key=${t.id}
|
|
159
|
-
class="nav-tab ${tab === t.id ? "active" : ""}"
|
|
160
|
-
style="${tab === t.id ? `color:${t.color};border-bottom-color:${t.color}` : ""}"
|
|
161
|
-
onClick=${() => setTab(t.id)}
|
|
162
|
-
>
|
|
163
|
-
${t.label}
|
|
164
|
-
</button>
|
|
165
|
-
`
|
|
166
|
-
)}
|
|
167
|
-
</nav>
|
|
168
|
-
<div class="ws-indicator">
|
|
169
|
-
<span class="ws-dot ${wsConnected ? "" : "disconnected"}"></span>
|
|
170
|
-
<span>${wsConnected ? "Connected" : "Reconnecting..."}</span>
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
173
|
-
<div class="content">${renderPanel()}</div>
|
|
174
|
-
`;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
render(html`<${App} />`, document.getElementById("app"));
|
package/webui/components/logs.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { h } from "preact";
|
|
2
|
-
import { useState, useEffect, useRef, useMemo } from "preact/hooks";
|
|
3
|
-
import htm from "htm";
|
|
4
|
-
|
|
5
|
-
const html = htm.bind(h);
|
|
6
|
-
|
|
7
|
-
const LEVEL_COLORS = {
|
|
8
|
-
ERROR: "#ef4444",
|
|
9
|
-
WARN: "#eab308",
|
|
10
|
-
INFO: "#22c55e",
|
|
11
|
-
DEBUG: "#6b7280",
|
|
12
|
-
TRACE: "#4b5563"
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const LEVEL_ORDER = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"];
|
|
16
|
-
|
|
17
|
-
function formatTime(ts) {
|
|
18
|
-
if (!ts) return "-";
|
|
19
|
-
return new Date(ts).toISOString().substring(11, 23);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function LogsPanel({ data }) {
|
|
23
|
-
const [liveEntries, setLiveEntries] = useState([]);
|
|
24
|
-
const [search, setSearch] = useState("");
|
|
25
|
-
const [autoScroll, setAutoScroll] = useState(true);
|
|
26
|
-
const [levelFilter, setLevelFilter] = useState(() => localStorage.getItem("webda-log-level") || "INFO");
|
|
27
|
-
const listRef = useRef(null);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// Merge cached + live, deduplicate by id
|
|
31
|
-
const allEntries = useMemo(() => {
|
|
32
|
-
const seen = new Set();
|
|
33
|
-
const merged = [];
|
|
34
|
-
for (const e of liveEntries) {
|
|
35
|
-
if (!seen.has(e.id)) { seen.add(e.id); merged.push(e); }
|
|
36
|
-
}
|
|
37
|
-
for (const e of (data || [])) {
|
|
38
|
-
if (!seen.has(e.id)) { seen.add(e.id); merged.push(e); }
|
|
39
|
-
}
|
|
40
|
-
return merged;
|
|
41
|
-
}, [data, liveEntries]);
|
|
42
|
-
|
|
43
|
-
const entries = search
|
|
44
|
-
? allEntries.filter(e => e.message?.toLowerCase().includes(search.toLowerCase()) || e.level?.toLowerCase().includes(search.toLowerCase()))
|
|
45
|
-
: allEntries;
|
|
46
|
-
|
|
47
|
-
// Listen for live log events via custom event dispatched from WebSocket handler
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
const handler = (event) => {
|
|
50
|
-
if (event.detail?.type === "log") {
|
|
51
|
-
setLiveEntries((prev) => [event.detail, ...prev].slice(0, 2000));
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
window.addEventListener("debug-ws-event", handler);
|
|
55
|
-
return () => window.removeEventListener("debug-ws-event", handler);
|
|
56
|
-
}, []);
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (autoScroll && listRef.current) {
|
|
60
|
-
listRef.current.scrollTop = listRef.current.scrollHeight;
|
|
61
|
-
}
|
|
62
|
-
}, [entries, autoScroll]);
|
|
63
|
-
|
|
64
|
-
const minLevel = LEVEL_ORDER.indexOf(levelFilter);
|
|
65
|
-
const filtered = minLevel <= 0 ? entries : entries.filter((e) => LEVEL_ORDER.indexOf(e.level) >= minLevel);
|
|
66
|
-
|
|
67
|
-
return html`
|
|
68
|
-
<div>
|
|
69
|
-
<div style="display:flex;gap:8px;margin-bottom:12px;align-items:center">
|
|
70
|
-
<input
|
|
71
|
-
type="text"
|
|
72
|
-
placeholder="Search logs..."
|
|
73
|
-
value=${search}
|
|
74
|
-
onInput=${(e) => setSearch(e.target.value)}
|
|
75
|
-
style="flex:1;padding:6px 10px;background:var(--bg-tertiary);border:1px solid var(--border);color:var(--text-primary);border-radius:4px;font-family:monospace"
|
|
76
|
-
/>
|
|
77
|
-
<select
|
|
78
|
-
value=${levelFilter}
|
|
79
|
-
onChange=${(e) => { setLevelFilter(e.target.value); localStorage.setItem("webda-log-level", e.target.value); }}
|
|
80
|
-
style="padding:6px;background:var(--bg-tertiary);border:1px solid var(--border);color:var(--text-primary);border-radius:4px"
|
|
81
|
-
>
|
|
82
|
-
<option value="ERROR">ERROR</option>
|
|
83
|
-
<option value="WARN">WARN+</option>
|
|
84
|
-
<option value="INFO">INFO+</option>
|
|
85
|
-
<option value="DEBUG">DEBUG+</option>
|
|
86
|
-
<option value="TRACE">TRACE+</option>
|
|
87
|
-
</select>
|
|
88
|
-
<label style="display:flex;align-items:center;gap:4px;color:var(--text-muted);font-size:12px">
|
|
89
|
-
<input type="checkbox" checked=${autoScroll} onChange=${(e) => setAutoScroll(e.target.checked)} />
|
|
90
|
-
Auto-scroll
|
|
91
|
-
</label>
|
|
92
|
-
</div>
|
|
93
|
-
<div style="margin-bottom:0.75rem;color:var(--text-muted);font-size:0.8125rem">
|
|
94
|
-
${filtered.length} log${filtered.length !== 1 ? "s" : ""}
|
|
95
|
-
</div>
|
|
96
|
-
<div ref=${listRef} class="table-container" style="overflow-y:auto;max-height:calc(100vh - 200px)">
|
|
97
|
-
<table>
|
|
98
|
-
<thead>
|
|
99
|
-
<tr>
|
|
100
|
-
<th style="width:120px">Time</th>
|
|
101
|
-
<th style="width:70px">Level</th>
|
|
102
|
-
<th>Message</th>
|
|
103
|
-
</tr>
|
|
104
|
-
</thead>
|
|
105
|
-
<tbody>
|
|
106
|
-
${filtered.map(
|
|
107
|
-
(entry) => html`
|
|
108
|
-
<tr key=${entry.id}>
|
|
109
|
-
<td class="mono" style="white-space:nowrap;color:var(--text-muted);font-size:12px">${formatTime(entry.timestamp)}</td>
|
|
110
|
-
<td><span class="badge" style="background:${LEVEL_COLORS[entry.level] || "#666"}">${entry.level}</span></td>
|
|
111
|
-
<td class="mono" style="font-size:13px;white-space:pre-wrap;word-break:break-all">${entry.message}</td>
|
|
112
|
-
</tr>
|
|
113
|
-
`
|
|
114
|
-
)}
|
|
115
|
-
${filtered.length === 0 &&
|
|
116
|
-
html`
|
|
117
|
-
<tr>
|
|
118
|
-
<td colspan="3" style="color:var(--text-muted);text-align:center;padding:2rem">
|
|
119
|
-
No logs${search ? " matching search" : " yet"}. Logs will appear here in real-time.
|
|
120
|
-
</td>
|
|
121
|
-
</tr>
|
|
122
|
-
`}
|
|
123
|
-
</tbody>
|
|
124
|
-
</table>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
`;
|
|
128
|
-
}
|