@serve.zone/catalog 1.0.1

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.
Files changed (122) hide show
  1. package/dist_ts_web/00_commitinfo_data.d.ts +8 -0
  2. package/dist_ts_web/00_commitinfo_data.js +9 -0
  3. package/dist_ts_web/elements/index.d.ts +33 -0
  4. package/dist_ts_web/elements/index.js +45 -0
  5. package/dist_ts_web/elements/sz-certificates-card.d.ts +14 -0
  6. package/dist_ts_web/elements/sz-certificates-card.js +210 -0
  7. package/dist_ts_web/elements/sz-dashboard-view.d.ts +33 -0
  8. package/dist_ts_web/elements/sz-dashboard-view.js +242 -0
  9. package/dist_ts_web/elements/sz-demo-view-dashboard.d.ts +18 -0
  10. package/dist_ts_web/elements/sz-demo-view-dashboard.js +184 -0
  11. package/dist_ts_web/elements/sz-demo-view-network.d.ts +32 -0
  12. package/dist_ts_web/elements/sz-demo-view-network.js +384 -0
  13. package/dist_ts_web/elements/sz-demo-view-registries.d.ts +22 -0
  14. package/dist_ts_web/elements/sz-demo-view-registries.js +240 -0
  15. package/dist_ts_web/elements/sz-demo-view-services.d.ts +32 -0
  16. package/dist_ts_web/elements/sz-demo-view-services.js +468 -0
  17. package/dist_ts_web/elements/sz-demo-view-settings.d.ts +19 -0
  18. package/dist_ts_web/elements/sz-demo-view-settings.js +151 -0
  19. package/dist_ts_web/elements/sz-demo-view-tokens.d.ts +20 -0
  20. package/dist_ts_web/elements/sz-demo-view-tokens.js +141 -0
  21. package/dist_ts_web/elements/sz-dns-ssl-card.d.ts +13 -0
  22. package/dist_ts_web/elements/sz-dns-ssl-card.js +180 -0
  23. package/dist_ts_web/elements/sz-domain-detail-view.d.ts +48 -0
  24. package/dist_ts_web/elements/sz-domain-detail-view.js +789 -0
  25. package/dist_ts_web/elements/sz-login-view.d.ts +18 -0
  26. package/dist_ts_web/elements/sz-login-view.js +384 -0
  27. package/dist_ts_web/elements/sz-network-dns-view.d.ts +20 -0
  28. package/dist_ts_web/elements/sz-network-dns-view.js +244 -0
  29. package/dist_ts_web/elements/sz-network-domains-view.d.ts +28 -0
  30. package/dist_ts_web/elements/sz-network-domains-view.js +312 -0
  31. package/dist_ts_web/elements/sz-network-proxy-view.d.ts +39 -0
  32. package/dist_ts_web/elements/sz-network-proxy-view.js +510 -0
  33. package/dist_ts_web/elements/sz-platform-service-detail-view.d.ts +49 -0
  34. package/dist_ts_web/elements/sz-platform-service-detail-view.js +733 -0
  35. package/dist_ts_web/elements/sz-platform-services-card.d.ts +19 -0
  36. package/dist_ts_web/elements/sz-platform-services-card.js +196 -0
  37. package/dist_ts_web/elements/sz-quick-actions-card.d.ts +19 -0
  38. package/dist_ts_web/elements/sz-quick-actions-card.js +194 -0
  39. package/dist_ts_web/elements/sz-registry-external-view.d.ts +22 -0
  40. package/dist_ts_web/elements/sz-registry-external-view.js +313 -0
  41. package/dist_ts_web/elements/sz-registry-onebox-view.d.ts +14 -0
  42. package/dist_ts_web/elements/sz-registry-onebox-view.js +307 -0
  43. package/dist_ts_web/elements/sz-resource-usage-card.d.ts +25 -0
  44. package/dist_ts_web/elements/sz-resource-usage-card.js +323 -0
  45. package/dist_ts_web/elements/sz-reverse-proxy-card.d.ts +16 -0
  46. package/dist_ts_web/elements/sz-reverse-proxy-card.js +216 -0
  47. package/dist_ts_web/elements/sz-service-create-view.d.ts +67 -0
  48. package/dist_ts_web/elements/sz-service-create-view.js +828 -0
  49. package/dist_ts_web/elements/sz-service-detail-view.d.ts +57 -0
  50. package/dist_ts_web/elements/sz-service-detail-view.js +728 -0
  51. package/dist_ts_web/elements/sz-services-backups-view.d.ts +37 -0
  52. package/dist_ts_web/elements/sz-services-backups-view.js +413 -0
  53. package/dist_ts_web/elements/sz-services-list-view.d.ts +20 -0
  54. package/dist_ts_web/elements/sz-services-list-view.js +272 -0
  55. package/dist_ts_web/elements/sz-settings-view.d.ts +30 -0
  56. package/dist_ts_web/elements/sz-settings-view.js +448 -0
  57. package/dist_ts_web/elements/sz-stat-card.d.ts +17 -0
  58. package/dist_ts_web/elements/sz-stat-card.js +249 -0
  59. package/dist_ts_web/elements/sz-status-grid-cluster.d.ts +19 -0
  60. package/dist_ts_web/elements/sz-status-grid-cluster.js +142 -0
  61. package/dist_ts_web/elements/sz-status-grid-infra.d.ts +17 -0
  62. package/dist_ts_web/elements/sz-status-grid-infra.js +140 -0
  63. package/dist_ts_web/elements/sz-status-grid-network.d.ts +30 -0
  64. package/dist_ts_web/elements/sz-status-grid-network.js +190 -0
  65. package/dist_ts_web/elements/sz-status-grid-services.d.ts +17 -0
  66. package/dist_ts_web/elements/sz-status-grid-services.js +145 -0
  67. package/dist_ts_web/elements/sz-tokens-view.d.ts +26 -0
  68. package/dist_ts_web/elements/sz-tokens-view.js +344 -0
  69. package/dist_ts_web/elements/sz-traffic-card.d.ts +24 -0
  70. package/dist_ts_web/elements/sz-traffic-card.js +255 -0
  71. package/dist_ts_web/index.d.ts +2 -0
  72. package/dist_ts_web/index.js +3 -0
  73. package/dist_ts_web/pages/index.d.ts +3 -0
  74. package/dist_ts_web/pages/index.js +4 -0
  75. package/dist_ts_web/pages/mainpage.d.ts +1 -0
  76. package/dist_ts_web/pages/mainpage.js +46 -0
  77. package/dist_ts_web/pages/sz-demo-app-shell.d.ts +13 -0
  78. package/dist_ts_web/pages/sz-demo-app-shell.js +212 -0
  79. package/dist_ts_web/pages/sz-demo-app.d.ts +2 -0
  80. package/dist_ts_web/pages/sz-demo-app.js +20 -0
  81. package/npmextra.json +24 -0
  82. package/package.json +45 -0
  83. package/ts_web/00_commitinfo_data.ts +8 -0
  84. package/ts_web/elements/index.ts +54 -0
  85. package/ts_web/elements/sz-certificates-card.ts +155 -0
  86. package/ts_web/elements/sz-dashboard-view.ts +217 -0
  87. package/ts_web/elements/sz-demo-view-dashboard.ts +150 -0
  88. package/ts_web/elements/sz-demo-view-network.ts +354 -0
  89. package/ts_web/elements/sz-demo-view-registries.ts +206 -0
  90. package/ts_web/elements/sz-demo-view-services.ts +434 -0
  91. package/ts_web/elements/sz-demo-view-settings.ts +118 -0
  92. package/ts_web/elements/sz-demo-view-tokens.ts +109 -0
  93. package/ts_web/elements/sz-dns-ssl-card.ts +130 -0
  94. package/ts_web/elements/sz-domain-detail-view.ts +766 -0
  95. package/ts_web/elements/sz-login-view.ts +329 -0
  96. package/ts_web/elements/sz-network-dns-view.ts +208 -0
  97. package/ts_web/elements/sz-network-domains-view.ts +273 -0
  98. package/ts_web/elements/sz-network-proxy-view.ts +456 -0
  99. package/ts_web/elements/sz-platform-service-detail-view.ts +714 -0
  100. package/ts_web/elements/sz-platform-services-card.ts +163 -0
  101. package/ts_web/elements/sz-quick-actions-card.ts +161 -0
  102. package/ts_web/elements/sz-registry-external-view.ts +279 -0
  103. package/ts_web/elements/sz-registry-onebox-view.ts +258 -0
  104. package/ts_web/elements/sz-resource-usage-card.ts +284 -0
  105. package/ts_web/elements/sz-reverse-proxy-card.ts +151 -0
  106. package/ts_web/elements/sz-service-create-view.ts +773 -0
  107. package/ts_web/elements/sz-service-detail-view.ts +710 -0
  108. package/ts_web/elements/sz-services-backups-view.ts +390 -0
  109. package/ts_web/elements/sz-services-list-view.ts +237 -0
  110. package/ts_web/elements/sz-settings-view.ts +417 -0
  111. package/ts_web/elements/sz-stat-card.ts +187 -0
  112. package/ts_web/elements/sz-status-grid-cluster.ts +105 -0
  113. package/ts_web/elements/sz-status-grid-infra.ts +88 -0
  114. package/ts_web/elements/sz-status-grid-network.ts +152 -0
  115. package/ts_web/elements/sz-status-grid-services.ts +99 -0
  116. package/ts_web/elements/sz-tokens-view.ts +308 -0
  117. package/ts_web/elements/sz-traffic-card.ts +222 -0
  118. package/ts_web/index.ts +2 -0
  119. package/ts_web/pages/index.ts +3 -0
  120. package/ts_web/pages/mainpage.ts +46 -0
  121. package/ts_web/pages/sz-demo-app-shell.ts +179 -0
  122. package/ts_web/pages/sz-demo-app.ts +20 -0
@@ -0,0 +1,710 @@
1
+ import {
2
+ DeesElement,
3
+ customElement,
4
+ html,
5
+ css,
6
+ cssManager,
7
+ property,
8
+ type TemplateResult,
9
+ } from '@design.estate/dees-element';
10
+
11
+ import './sz-stat-card.js';
12
+
13
+ declare global {
14
+ interface HTMLElementTagNameMap {
15
+ 'sz-service-detail-view': SzServiceDetailView;
16
+ }
17
+ }
18
+
19
+ export interface IServiceDetail {
20
+ name: string;
21
+ status: 'running' | 'stopped' | 'starting' | 'error';
22
+ image: string;
23
+ port: number;
24
+ domain: string | null;
25
+ containerId: string;
26
+ created: string;
27
+ updated: string;
28
+ registry: string;
29
+ repository: string;
30
+ tag: string;
31
+ }
32
+
33
+ export interface IServiceStats {
34
+ cpu: number;
35
+ memory: string;
36
+ memoryLimit: string;
37
+ networkIn: string;
38
+ networkOut: string;
39
+ }
40
+
41
+ export interface IServiceBackup {
42
+ id: string;
43
+ createdAt: string;
44
+ size: string;
45
+ type: string;
46
+ }
47
+
48
+ export interface ILogEntry {
49
+ timestamp: string;
50
+ message: string;
51
+ level?: 'info' | 'warn' | 'error';
52
+ }
53
+
54
+ @customElement('sz-service-detail-view')
55
+ export class SzServiceDetailView extends DeesElement {
56
+ public static demo = () => html`
57
+ <div style="padding: 24px; max-width: 1200px;">
58
+ <sz-service-detail-view
59
+ .service=${{
60
+ name: 'test-nginx',
61
+ status: 'running',
62
+ image: 'nginx:alpine',
63
+ port: 80,
64
+ domain: 'app.bleu.de',
65
+ containerId: 'pchbbr9fjr4g',
66
+ created: '11/18/2025, 2:06:55 PM',
67
+ updated: '11/26/2025, 4:05:46 PM',
68
+ registry: 'Docker Hub',
69
+ repository: 'nginx',
70
+ tag: 'alpine',
71
+ }}
72
+ .stats=${{
73
+ cpu: 0.5,
74
+ memory: '32.1 MB',
75
+ memoryLimit: '61.3 GB',
76
+ networkIn: '6.4 KB',
77
+ networkOut: '252 B',
78
+ }}
79
+ .backups=${[
80
+ { id: '1', createdAt: '1/2/2026, 2:00:03 AM', size: '21.96 MB', type: 'Docker Image' },
81
+ { id: '2', createdAt: '11/27/2025, 1:42:26 PM', size: '51.76 MB', type: 'Docker Image' },
82
+ ]}
83
+ .logs=${[
84
+ { timestamp: '2024-01-02 10:15:32', message: '192.168.1.100 - - [02/Jan/2024:10:15:32 +0000] "GET / HTTP/1.1" 200 612' },
85
+ { timestamp: '2024-01-02 10:15:30', message: '192.168.1.100 - - [02/Jan/2024:10:15:30 +0000] "GET /favicon.ico HTTP/1.1" 404 153' },
86
+ ]}
87
+ ></sz-service-detail-view>
88
+ </div>
89
+ `;
90
+
91
+ @property({ type: Object })
92
+ public accessor service: IServiceDetail = {
93
+ name: '',
94
+ status: 'stopped',
95
+ image: '',
96
+ port: 0,
97
+ domain: null,
98
+ containerId: '',
99
+ created: '',
100
+ updated: '',
101
+ registry: '',
102
+ repository: '',
103
+ tag: '',
104
+ };
105
+
106
+ @property({ type: Object })
107
+ public accessor stats: IServiceStats = {
108
+ cpu: 0,
109
+ memory: '0 MB',
110
+ memoryLimit: '0 GB',
111
+ networkIn: '0 B',
112
+ networkOut: '0 B',
113
+ };
114
+
115
+ @property({ type: Array })
116
+ public accessor backups: IServiceBackup[] = [];
117
+
118
+ @property({ type: Array })
119
+ public accessor logs: ILogEntry[] = [];
120
+
121
+ @property({ type: Boolean })
122
+ public accessor streaming: boolean = false;
123
+
124
+ public static styles = [
125
+ cssManager.defaultStyles,
126
+ css`
127
+ :host {
128
+ display: block;
129
+ }
130
+
131
+ .header {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 16px;
135
+ margin-bottom: 24px;
136
+ }
137
+
138
+ .back-link {
139
+ display: inline-flex;
140
+ align-items: center;
141
+ gap: 6px;
142
+ font-size: 14px;
143
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
144
+ cursor: pointer;
145
+ transition: color 200ms ease;
146
+ }
147
+
148
+ .back-link:hover {
149
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
150
+ }
151
+
152
+ .service-header {
153
+ display: flex;
154
+ align-items: center;
155
+ gap: 12px;
156
+ }
157
+
158
+ .service-name {
159
+ font-size: 24px;
160
+ font-weight: 700;
161
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
162
+ }
163
+
164
+ .status-badge {
165
+ display: inline-flex;
166
+ align-items: center;
167
+ padding: 4px 12px;
168
+ border-radius: 9999px;
169
+ font-size: 13px;
170
+ font-weight: 500;
171
+ }
172
+
173
+ .status-badge.running {
174
+ background: ${cssManager.bdTheme('#dcfce7', 'rgba(34, 197, 94, 0.2)')};
175
+ color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
176
+ }
177
+
178
+ .status-badge.stopped {
179
+ background: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.2)')};
180
+ color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
181
+ }
182
+
183
+ .content {
184
+ display: grid;
185
+ grid-template-columns: 1fr;
186
+ gap: 24px;
187
+ }
188
+
189
+ @media (min-width: 1024px) {
190
+ .content {
191
+ grid-template-columns: 2fr 1fr;
192
+ }
193
+ }
194
+
195
+ .main-content {
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: 24px;
199
+ }
200
+
201
+ .sidebar {
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: 24px;
205
+ }
206
+
207
+ .card {
208
+ background: ${cssManager.bdTheme('#ffffff', '#09090b')};
209
+ border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
210
+ border-radius: 8px;
211
+ overflow: hidden;
212
+ }
213
+
214
+ .card-header {
215
+ display: flex;
216
+ justify-content: space-between;
217
+ align-items: center;
218
+ padding: 16px;
219
+ border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
220
+ }
221
+
222
+ .card-title {
223
+ font-size: 16px;
224
+ font-weight: 600;
225
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
226
+ }
227
+
228
+ .card-subtitle {
229
+ font-size: 13px;
230
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
231
+ margin-top: 2px;
232
+ }
233
+
234
+ .card-content {
235
+ padding: 16px;
236
+ }
237
+
238
+ .detail-list {
239
+ display: flex;
240
+ flex-direction: column;
241
+ gap: 12px;
242
+ }
243
+
244
+ .detail-item {
245
+ display: flex;
246
+ justify-content: space-between;
247
+ align-items: flex-start;
248
+ }
249
+
250
+ .detail-label {
251
+ font-size: 14px;
252
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
253
+ }
254
+
255
+ .detail-value {
256
+ font-size: 14px;
257
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
258
+ text-align: right;
259
+ }
260
+
261
+ .detail-value a {
262
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
263
+ text-decoration: none;
264
+ }
265
+
266
+ .detail-value a:hover {
267
+ text-decoration: underline;
268
+ }
269
+
270
+ .stats-grid {
271
+ display: grid;
272
+ grid-template-columns: repeat(2, 1fr);
273
+ gap: 12px;
274
+ }
275
+
276
+ .stat-item {
277
+ background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
278
+ border-radius: 6px;
279
+ padding: 12px;
280
+ }
281
+
282
+ .stat-label {
283
+ display: flex;
284
+ align-items: center;
285
+ gap: 6px;
286
+ font-size: 13px;
287
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
288
+ margin-bottom: 4px;
289
+ }
290
+
291
+ .stat-value {
292
+ font-size: 18px;
293
+ font-weight: 600;
294
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
295
+ }
296
+
297
+ .stat-subvalue {
298
+ font-size: 12px;
299
+ color: ${cssManager.bdTheme('#a1a1aa', '#52525b')};
300
+ }
301
+
302
+ .actions-grid {
303
+ display: flex;
304
+ flex-direction: column;
305
+ gap: 8px;
306
+ }
307
+
308
+ .action-button {
309
+ width: 100%;
310
+ padding: 10px 16px;
311
+ border-radius: 6px;
312
+ font-size: 14px;
313
+ font-weight: 500;
314
+ cursor: pointer;
315
+ transition: all 200ms ease;
316
+ border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
317
+ background: ${cssManager.bdTheme('#ffffff', '#09090b')};
318
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
319
+ }
320
+
321
+ .action-button:hover {
322
+ background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
323
+ }
324
+
325
+ .action-button.danger {
326
+ color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
327
+ border-color: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.3)')};
328
+ }
329
+
330
+ .action-button.danger:hover {
331
+ background: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.2)')};
332
+ }
333
+
334
+ .backup-list {
335
+ display: flex;
336
+ flex-direction: column;
337
+ gap: 8px;
338
+ }
339
+
340
+ .backup-item {
341
+ display: flex;
342
+ justify-content: space-between;
343
+ align-items: center;
344
+ padding: 12px;
345
+ background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
346
+ border-radius: 6px;
347
+ }
348
+
349
+ .backup-info {
350
+ display: flex;
351
+ flex-direction: column;
352
+ gap: 2px;
353
+ }
354
+
355
+ .backup-date {
356
+ font-size: 13px;
357
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
358
+ }
359
+
360
+ .backup-meta {
361
+ font-size: 12px;
362
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
363
+ }
364
+
365
+ .backup-actions {
366
+ display: flex;
367
+ gap: 4px;
368
+ }
369
+
370
+ .icon-button {
371
+ padding: 6px;
372
+ background: transparent;
373
+ border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
374
+ border-radius: 4px;
375
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
376
+ cursor: pointer;
377
+ transition: all 200ms ease;
378
+ }
379
+
380
+ .icon-button:hover {
381
+ background: ${cssManager.bdTheme('#ffffff', '#09090b')};
382
+ color: ${cssManager.bdTheme('#18181b', '#fafafa')};
383
+ }
384
+
385
+ .logs-header {
386
+ display: flex;
387
+ justify-content: space-between;
388
+ align-items: center;
389
+ }
390
+
391
+ .logs-actions {
392
+ display: flex;
393
+ gap: 8px;
394
+ align-items: center;
395
+ }
396
+
397
+ .stream-button {
398
+ display: inline-flex;
399
+ align-items: center;
400
+ gap: 6px;
401
+ padding: 6px 12px;
402
+ background: ${cssManager.bdTheme('#2563eb', '#3b82f6')};
403
+ border: none;
404
+ border-radius: 4px;
405
+ font-size: 13px;
406
+ font-weight: 500;
407
+ color: white;
408
+ cursor: pointer;
409
+ }
410
+
411
+ .stream-button.streaming {
412
+ background: ${cssManager.bdTheme('#dc2626', '#ef4444')};
413
+ }
414
+
415
+ .clear-button {
416
+ padding: 6px 12px;
417
+ background: transparent;
418
+ border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
419
+ border-radius: 4px;
420
+ font-size: 13px;
421
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
422
+ cursor: pointer;
423
+ }
424
+
425
+ .logs-container {
426
+ padding: 16px;
427
+ font-family: monospace;
428
+ font-size: 12px;
429
+ max-height: 300px;
430
+ overflow-y: auto;
431
+ background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
432
+ }
433
+
434
+ .log-entry {
435
+ padding: 2px 0;
436
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
437
+ white-space: pre-wrap;
438
+ word-break: break-all;
439
+ }
440
+
441
+ .empty-logs {
442
+ padding: 24px;
443
+ text-align: center;
444
+ color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
445
+ }
446
+
447
+ .tag-badge {
448
+ display: inline-flex;
449
+ padding: 2px 8px;
450
+ background: ${cssManager.bdTheme('#dbeafe', 'rgba(59, 130, 246, 0.2)')};
451
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
452
+ border-radius: 4px;
453
+ font-size: 12px;
454
+ font-weight: 500;
455
+ }
456
+ `,
457
+ ];
458
+
459
+ public render(): TemplateResult {
460
+ return html`
461
+ <div class="header">
462
+ <div class="back-link" @click=${() => this.handleBack()}>
463
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
464
+ <polyline points="15 18 9 12 15 6"></polyline>
465
+ </svg>
466
+ Back to Services
467
+ </div>
468
+ </div>
469
+
470
+ <div class="service-header" style="margin-bottom: 24px;">
471
+ <h1 class="service-name">${this.service.name}</h1>
472
+ <span class="status-badge ${this.service.status}">${this.service.status}</span>
473
+ </div>
474
+
475
+ <div class="content">
476
+ <div class="main-content">
477
+ <div class="card">
478
+ <div class="card-header">
479
+ <div>
480
+ <div class="card-title">Service Details</div>
481
+ </div>
482
+ <button class="action-button" style="width: auto; padding: 6px 12px;" @click=${() => this.handleEdit()}>Edit</button>
483
+ </div>
484
+ <div class="card-content">
485
+ <div class="detail-list">
486
+ <div class="detail-item">
487
+ <span class="detail-label">Image</span>
488
+ <span class="detail-value">${this.service.image}</span>
489
+ </div>
490
+ <div class="detail-item">
491
+ <span class="detail-label">Port</span>
492
+ <span class="detail-value">${this.service.port}</span>
493
+ </div>
494
+ <div class="detail-item">
495
+ <span class="detail-label">Domain</span>
496
+ <span class="detail-value">
497
+ ${this.service.domain
498
+ ? html`<a href="https://${this.service.domain}" target="_blank">${this.service.domain}</a>`
499
+ : '-'}
500
+ </span>
501
+ </div>
502
+ <div class="detail-item">
503
+ <span class="detail-label">Container ID</span>
504
+ <span class="detail-value">${this.service.containerId}</span>
505
+ </div>
506
+ <div class="detail-item">
507
+ <span class="detail-label">Created</span>
508
+ <span class="detail-value">${this.service.created}</span>
509
+ </div>
510
+ <div class="detail-item">
511
+ <span class="detail-label">Updated</span>
512
+ <span class="detail-value">${this.service.updated}</span>
513
+ </div>
514
+ </div>
515
+ </div>
516
+ </div>
517
+
518
+ <div class="card">
519
+ <div class="card-header">
520
+ <div class="logs-header" style="width: 100%;">
521
+ <div>
522
+ <div class="card-title">Logs</div>
523
+ <div class="card-subtitle">Container logs</div>
524
+ </div>
525
+ <div class="logs-actions">
526
+ <button class="stream-button ${this.streaming ? 'streaming' : ''}" @click=${() => this.toggleStreaming()}>
527
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
528
+ ${this.streaming
529
+ ? html`<rect x="6" y="6" width="12" height="12" rx="1"/>`
530
+ : html`<polygon points="5,3 19,12 5,21"/>`
531
+ }
532
+ </svg>
533
+ ${this.streaming ? 'Stop' : 'Stream'}
534
+ </button>
535
+ <button class="clear-button" @click=${() => this.handleClearLogs()}>Clear logs</button>
536
+ </div>
537
+ </div>
538
+ </div>
539
+ <div class="logs-container">
540
+ ${this.logs.length > 0 ? this.logs.map(log => html`
541
+ <div class="log-entry">${log.timestamp} ${log.message}</div>
542
+ `) : html`
543
+ <div class="empty-logs">Click "Stream" to start live log streaming</div>
544
+ `}
545
+ </div>
546
+ </div>
547
+ </div>
548
+
549
+ <div class="sidebar">
550
+ <div class="card">
551
+ <div class="card-header">
552
+ <div class="card-title">Live stats</div>
553
+ </div>
554
+ <div class="card-content">
555
+ <div class="stats-grid">
556
+ <div class="stat-item">
557
+ <div class="stat-label">CPU</div>
558
+ <div class="stat-value">${this.stats.cpu.toFixed(1)}%</div>
559
+ </div>
560
+ <div class="stat-item">
561
+ <div class="stat-label">Memory</div>
562
+ <div class="stat-value">${this.stats.memory}</div>
563
+ <div class="stat-subvalue">of ${this.stats.memoryLimit}</div>
564
+ </div>
565
+ <div class="stat-item">
566
+ <div class="stat-label">Network In</div>
567
+ <div class="stat-value">${this.stats.networkIn}</div>
568
+ </div>
569
+ <div class="stat-item">
570
+ <div class="stat-label">Network Out</div>
571
+ <div class="stat-value">${this.stats.networkOut}</div>
572
+ </div>
573
+ </div>
574
+ </div>
575
+ </div>
576
+
577
+ <div class="card">
578
+ <div class="card-header">
579
+ <div>
580
+ <div class="card-title">Actions</div>
581
+ <div class="card-subtitle">Manage service state</div>
582
+ </div>
583
+ </div>
584
+ <div class="card-content">
585
+ <div class="actions-grid">
586
+ ${this.service.status === 'running'
587
+ ? html`<button class="action-button" @click=${() => this.handleAction('stop')}>Stop Service</button>`
588
+ : html`<button class="action-button" @click=${() => this.handleAction('start')}>Start Service</button>`
589
+ }
590
+ <button class="action-button" @click=${() => this.handleAction('restart')}>Restart Service</button>
591
+ <button class="action-button danger" @click=${() => this.handleAction('delete')}>Delete Service</button>
592
+ </div>
593
+ </div>
594
+ </div>
595
+
596
+ <div class="card">
597
+ <div class="card-header">
598
+ <div>
599
+ <div class="card-title">Image Source</div>
600
+ <div class="card-subtitle">${this.service.registry === 'Docker Hub' ? 'External container registry' : 'Onebox registry'}</div>
601
+ </div>
602
+ </div>
603
+ <div class="card-content">
604
+ <div class="detail-list">
605
+ <div class="detail-item">
606
+ <span class="detail-label">Registry</span>
607
+ <span class="detail-value">${this.service.registry}</span>
608
+ </div>
609
+ <div class="detail-item">
610
+ <span class="detail-label">Repository</span>
611
+ <span class="detail-value">${this.service.repository}</span>
612
+ </div>
613
+ <div class="detail-item">
614
+ <span class="detail-label">Tag</span>
615
+ <span class="detail-value"><span class="tag-badge">${this.service.tag}</span></span>
616
+ </div>
617
+ </div>
618
+ </div>
619
+ </div>
620
+
621
+ <div class="card">
622
+ <div class="card-header">
623
+ <div>
624
+ <div class="card-title">Backups</div>
625
+ <div class="card-subtitle">Create and manage service backups</div>
626
+ </div>
627
+ <button class="action-button" style="width: auto; padding: 6px 12px;" @click=${() => this.handleCreateBackup()}>
628
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 4px;">
629
+ <line x1="12" y1="5" x2="12" y2="19"></line>
630
+ <line x1="5" y1="12" x2="19" y2="12"></line>
631
+ </svg>
632
+ Create Backup
633
+ </button>
634
+ </div>
635
+ <div class="card-content">
636
+ <div class="backup-list">
637
+ ${this.backups.map(backup => html`
638
+ <div class="backup-item">
639
+ <div class="backup-info">
640
+ <div class="backup-date">${backup.createdAt}</div>
641
+ <div class="backup-meta">${backup.size} · ${backup.type}</div>
642
+ </div>
643
+ <div class="backup-actions">
644
+ <button class="icon-button" title="Download" @click=${() => this.handleDownloadBackup(backup)}>
645
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
646
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
647
+ <polyline points="7 10 12 15 17 10"/>
648
+ <line x1="12" y1="15" x2="12" y2="3"/>
649
+ </svg>
650
+ </button>
651
+ <button class="icon-button" title="Restore" @click=${() => this.handleRestoreBackup(backup)}>
652
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
653
+ <polyline points="1 4 1 10 7 10"/>
654
+ <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>
655
+ </svg>
656
+ </button>
657
+ <button class="icon-button" title="Delete" @click=${() => this.handleDeleteBackup(backup)}>
658
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
659
+ <polyline points="3,6 5,6 21,6"/>
660
+ <path d="M19,6v14a2,2,0,0,1-2,2H7a2,2,0,0,1-2-2V6m3,0V4a2,2,0,0,1,2-2h4a2,2,0,0,1,2,2v2"/>
661
+ </svg>
662
+ </button>
663
+ </div>
664
+ </div>
665
+ `)}
666
+ </div>
667
+ </div>
668
+ </div>
669
+ </div>
670
+ </div>
671
+ `;
672
+ }
673
+
674
+ private handleBack() {
675
+ this.dispatchEvent(new CustomEvent('back', { bubbles: true, composed: true }));
676
+ }
677
+
678
+ private handleEdit() {
679
+ this.dispatchEvent(new CustomEvent('edit', { detail: this.service, bubbles: true, composed: true }));
680
+ }
681
+
682
+ private handleAction(action: 'start' | 'stop' | 'restart' | 'delete') {
683
+ this.dispatchEvent(new CustomEvent('service-action', { detail: { service: this.service, action }, bubbles: true, composed: true }));
684
+ }
685
+
686
+ private toggleStreaming() {
687
+ this.streaming = !this.streaming;
688
+ this.dispatchEvent(new CustomEvent('stream-toggle', { detail: { streaming: this.streaming }, bubbles: true, composed: true }));
689
+ }
690
+
691
+ private handleClearLogs() {
692
+ this.dispatchEvent(new CustomEvent('clear-logs', { bubbles: true, composed: true }));
693
+ }
694
+
695
+ private handleCreateBackup() {
696
+ this.dispatchEvent(new CustomEvent('create-backup', { bubbles: true, composed: true }));
697
+ }
698
+
699
+ private handleDownloadBackup(backup: IServiceBackup) {
700
+ this.dispatchEvent(new CustomEvent('download-backup', { detail: backup, bubbles: true, composed: true }));
701
+ }
702
+
703
+ private handleRestoreBackup(backup: IServiceBackup) {
704
+ this.dispatchEvent(new CustomEvent('restore-backup', { detail: backup, bubbles: true, composed: true }));
705
+ }
706
+
707
+ private handleDeleteBackup(backup: IServiceBackup) {
708
+ this.dispatchEvent(new CustomEvent('delete-backup', { detail: backup, bubbles: true, composed: true }));
709
+ }
710
+ }