@skyhook-io/k8s-ui 1.0.0
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/package.json +63 -0
- package/src/components/dock/BottomDock.tsx +204 -0
- package/src/components/dock/DockContext.tsx +212 -0
- package/src/components/dock/TerminalTab.tsx +333 -0
- package/src/components/dock/index.ts +3 -0
- package/src/components/gitops/GitOpsActions.tsx +227 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
- package/src/components/gitops/ManagedResourcesList.tsx +210 -0
- package/src/components/gitops/SyncCountdown.tsx +146 -0
- package/src/components/gitops/index.ts +4 -0
- package/src/components/logs/JsonLogLine.tsx +90 -0
- package/src/components/logs/LogCore.tsx +553 -0
- package/src/components/logs/LogToolbarSelects.tsx +74 -0
- package/src/components/logs/LogsViewer.tsx +146 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
- package/src/components/logs/index.ts +13 -0
- package/src/components/logs/useLogBuffer.ts +138 -0
- package/src/components/logs/useLogSearch.ts +151 -0
- package/src/components/logs/useLogStream.ts +61 -0
- package/src/components/resources/ResourcesView.tsx +5494 -0
- package/src/components/resources/index.ts +17 -0
- package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
- package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
- package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
- package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
- package/src/components/resources/renderers/EventRenderer.tsx +175 -0
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
- package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
- package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
- package/src/components/resources/renderers/HPARenderer.tsx +164 -0
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
- package/src/components/resources/renderers/JobRenderer.tsx +103 -0
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
- package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
- package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
- package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
- package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
- package/src/components/resources/renderers/PodRenderer.tsx +677 -0
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
- package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
- package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
- package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
- package/src/components/resources/renderers/VPARenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
- package/src/components/resources/renderers/argo-cells.tsx +118 -0
- package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
- package/src/components/resources/renderers/eso-cells.tsx +115 -0
- package/src/components/resources/renderers/flux-cells.tsx +253 -0
- package/src/components/resources/renderers/index.ts +105 -0
- package/src/components/resources/renderers/istio-cells.tsx +210 -0
- package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
- package/src/components/resources/renderers/keda-cells.tsx +94 -0
- package/src/components/resources/renderers/knative-cells.tsx +396 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
- package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
- package/src/components/resources/renderers/traefik-cells.tsx +120 -0
- package/src/components/resources/renderers/trivy-cells.tsx +153 -0
- package/src/components/resources/renderers/trivy-shared.tsx +67 -0
- package/src/components/resources/renderers/velero-cells.tsx +164 -0
- package/src/components/resources/resource-utils-argo.ts +155 -0
- package/src/components/resources/resource-utils-certmanager.ts +198 -0
- package/src/components/resources/resource-utils-cnpg.ts +344 -0
- package/src/components/resources/resource-utils-eso.ts +385 -0
- package/src/components/resources/resource-utils-flux.ts +186 -0
- package/src/components/resources/resource-utils-istio.ts +372 -0
- package/src/components/resources/resource-utils-karpenter.ts +150 -0
- package/src/components/resources/resource-utils-keda.ts +203 -0
- package/src/components/resources/resource-utils-knative.ts +218 -0
- package/src/components/resources/resource-utils-kyverno.ts +224 -0
- package/src/components/resources/resource-utils-prometheus.ts +159 -0
- package/src/components/resources/resource-utils-traefik.ts +180 -0
- package/src/components/resources/resource-utils-trivy.ts +146 -0
- package/src/components/resources/resource-utils-velero.ts +293 -0
- package/src/components/resources/resource-utils.ts +1558 -0
- package/src/components/shared/EditableYamlView.tsx +302 -0
- package/src/components/shared/ResourceActionsBar.tsx +924 -0
- package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
- package/src/components/shared/index.ts +3 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/timeline/shared.tsx +614 -0
- package/src/components/topology/GroupNode.tsx +198 -0
- package/src/components/topology/K8sResourceNode.tsx +440 -0
- package/src/components/topology/TopologyControls.tsx +62 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
- package/src/components/topology/TopologyGraph.tsx +748 -0
- package/src/components/topology/TopologySearch.tsx +304 -0
- package/src/components/topology/index.ts +7 -0
- package/src/components/topology/layout.ts +734 -0
- package/src/components/topology/layout.worker.ts +272 -0
- package/src/components/topology/topology.css +129 -0
- package/src/components/ui/CodeViewer.tsx +451 -0
- package/src/components/ui/ConfirmDialog.tsx +188 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
- package/src/components/ui/HealthRing.tsx +72 -0
- package/src/components/ui/MetricsChart.tsx +259 -0
- package/src/components/ui/ResourceBar.tsx +68 -0
- package/src/components/ui/Toast.tsx +225 -0
- package/src/components/ui/Tooltip.tsx +165 -0
- package/src/components/ui/YamlEditor.tsx +280 -0
- package/src/components/ui/drawer-components.tsx +792 -0
- package/src/components/ui/index.ts +10 -0
- package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
- package/src/components/workload/WorkloadView.tsx +1109 -0
- package/src/components/workload/index.ts +2 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useAnimatedUnmount.ts +30 -0
- package/src/hooks/useKeyboardShortcuts.tsx +336 -0
- package/src/hooks/useRefreshAnimation.ts +58 -0
- package/src/index.ts +35 -0
- package/src/types/core.ts +894 -0
- package/src/types/gitops.ts +458 -0
- package/src/types/index.ts +2 -0
- package/src/utils/animation.ts +40 -0
- package/src/utils/api-resources.ts +185 -0
- package/src/utils/badge-colors.ts +399 -0
- package/src/utils/context-name.ts +72 -0
- package/src/utils/download.ts +19 -0
- package/src/utils/format.ts +233 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/log-format.ts +300 -0
- package/src/utils/navigation.ts +119 -0
- package/src/utils/resource-hierarchy.ts +630 -0
- package/src/utils/resource-icons.ts +206 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// Centralized badge color utilities for consistent light/dark mode theming
|
|
2
|
+
// This file is the single source of truth for all badge colors across the application
|
|
3
|
+
|
|
4
|
+
// Kind badge colors - for K8s resource type badges
|
|
5
|
+
export const KIND_BADGE_COLORS: Record<string, string> = {
|
|
6
|
+
// Workload controllers
|
|
7
|
+
Deployment: 'bg-emerald-500/15 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300',
|
|
8
|
+
StatefulSet: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
9
|
+
DaemonSet: 'bg-teal-500/15 text-teal-700 dark:bg-teal-900/50 dark:text-teal-300',
|
|
10
|
+
ReplicaSet: 'bg-green-500/15 text-green-700 dark:bg-green-900/50 dark:text-green-300',
|
|
11
|
+
Pod: 'bg-lime-500/15 text-lime-700 dark:bg-lime-900/50 dark:text-lime-300',
|
|
12
|
+
|
|
13
|
+
// Networking
|
|
14
|
+
Service: 'bg-blue-500/15 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300',
|
|
15
|
+
Ingress: 'bg-violet-500/15 text-violet-700 dark:bg-violet-900/50 dark:text-violet-300',
|
|
16
|
+
Gateway: 'bg-violet-500/15 text-violet-700 dark:bg-violet-900/50 dark:text-violet-300',
|
|
17
|
+
HTTPRoute: 'bg-purple-500/15 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300',
|
|
18
|
+
GRPCRoute: 'bg-purple-500/15 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300',
|
|
19
|
+
TCPRoute: 'bg-purple-500/15 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300',
|
|
20
|
+
TLSRoute: 'bg-purple-500/15 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300',
|
|
21
|
+
|
|
22
|
+
// Config
|
|
23
|
+
ConfigMap: 'bg-amber-500/15 text-amber-700 dark:bg-amber-900/50 dark:text-amber-300',
|
|
24
|
+
Secret: 'bg-red-500/15 text-red-700 dark:bg-red-900/50 dark:text-red-300',
|
|
25
|
+
|
|
26
|
+
// Jobs
|
|
27
|
+
Job: 'bg-purple-500/15 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300',
|
|
28
|
+
CronJob: 'bg-purple-500/15 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300',
|
|
29
|
+
|
|
30
|
+
// Autoscaling & Storage
|
|
31
|
+
HorizontalPodAutoscaler: 'bg-pink-500/15 text-pink-700 dark:bg-pink-900/50 dark:text-pink-300',
|
|
32
|
+
PersistentVolumeClaim: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
33
|
+
|
|
34
|
+
// Argo Rollouts
|
|
35
|
+
Rollout: 'bg-emerald-500/15 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300',
|
|
36
|
+
|
|
37
|
+
// GitOps
|
|
38
|
+
Application: 'bg-orange-500/15 text-orange-700 dark:bg-orange-900/50 dark:text-orange-300',
|
|
39
|
+
Kustomization: 'bg-indigo-500/15 text-indigo-700 dark:bg-indigo-900/50 dark:text-indigo-300',
|
|
40
|
+
GitRepository: 'bg-indigo-500/15 text-indigo-700 dark:bg-indigo-900/50 dark:text-indigo-300',
|
|
41
|
+
|
|
42
|
+
// Cluster-scoped
|
|
43
|
+
Node: 'bg-sky-500/15 text-sky-700 dark:bg-sky-900/50 dark:text-sky-300',
|
|
44
|
+
Namespace: 'bg-gray-500/15 text-gray-700 dark:bg-gray-900/50 dark:text-gray-300',
|
|
45
|
+
|
|
46
|
+
// Knative Serving
|
|
47
|
+
KnativeService: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
48
|
+
KnativeConfiguration: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
49
|
+
KnativeRevision: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
50
|
+
KnativeRoute: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
51
|
+
|
|
52
|
+
// Knative Eventing
|
|
53
|
+
Broker: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
54
|
+
Trigger: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
55
|
+
|
|
56
|
+
// Knative Sources
|
|
57
|
+
PingSource: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
58
|
+
ApiServerSource: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
59
|
+
ContainerSource: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
60
|
+
SinkBinding: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
61
|
+
Channel: 'bg-fuchsia-500/15 text-fuchsia-700 dark:bg-fuchsia-900/50 dark:text-fuchsia-300',
|
|
62
|
+
|
|
63
|
+
// Traefik
|
|
64
|
+
IngressRoute: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
65
|
+
IngressRouteTCP: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
66
|
+
IngressRouteUDP: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
67
|
+
Middleware: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
68
|
+
MiddlewareTCP: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
69
|
+
TraefikService: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
70
|
+
ServersTransport: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
71
|
+
ServersTransportTCP: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
72
|
+
TLSOption: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
73
|
+
TLSStore: 'bg-cyan-500/15 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300',
|
|
74
|
+
|
|
75
|
+
// Special
|
|
76
|
+
HelmRelease: 'bg-purple-500/20 text-purple-700 dark:text-purple-300',
|
|
77
|
+
Event: 'bg-slate-500/15 text-slate-700 dark:bg-slate-900/50 dark:text-slate-300',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Kind badge colors with border - for prominent badges in drawers/modals
|
|
81
|
+
export const KIND_BADGE_BORDERED: Record<string, string> = {
|
|
82
|
+
// Workload controllers
|
|
83
|
+
Deployment: 'bg-emerald-500/20 text-emerald-700 dark:text-emerald-300 border border-emerald-500/30',
|
|
84
|
+
StatefulSet: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
85
|
+
DaemonSet: 'bg-teal-500/20 text-teal-700 dark:text-teal-300 border border-teal-500/30',
|
|
86
|
+
ReplicaSet: 'bg-green-500/20 text-green-700 dark:text-green-300 border border-green-500/30',
|
|
87
|
+
Pod: 'bg-lime-500/20 text-lime-700 dark:text-lime-300 border border-lime-500/30',
|
|
88
|
+
PodGroup: 'bg-lime-500/20 text-lime-700 dark:text-lime-300 border border-lime-500/30',
|
|
89
|
+
|
|
90
|
+
// Networking
|
|
91
|
+
Internet: 'bg-blue-500/20 text-blue-700 dark:text-blue-300 border border-blue-500/30',
|
|
92
|
+
Service: 'bg-blue-500/20 text-blue-700 dark:text-blue-300 border border-blue-500/30',
|
|
93
|
+
Ingress: 'bg-violet-500/20 text-violet-700 dark:text-violet-300 border border-violet-500/30',
|
|
94
|
+
Gateway: 'bg-violet-500/20 text-violet-700 dark:text-violet-300 border border-violet-500/30',
|
|
95
|
+
HTTPRoute: 'bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/30',
|
|
96
|
+
GRPCRoute: 'bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/30',
|
|
97
|
+
TCPRoute: 'bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/30',
|
|
98
|
+
TLSRoute: 'bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/30',
|
|
99
|
+
|
|
100
|
+
// Config
|
|
101
|
+
ConfigMap: 'bg-amber-500/20 text-amber-700 dark:text-amber-300 border border-amber-500/30',
|
|
102
|
+
Secret: 'bg-red-500/20 text-red-700 dark:text-red-300 border border-red-500/30',
|
|
103
|
+
|
|
104
|
+
// Jobs
|
|
105
|
+
Job: 'bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/30',
|
|
106
|
+
CronJob: 'bg-purple-500/20 text-purple-700 dark:text-purple-300 border border-purple-500/30',
|
|
107
|
+
|
|
108
|
+
// Autoscaling & Storage
|
|
109
|
+
HorizontalPodAutoscaler: 'bg-pink-500/20 text-pink-700 dark:text-pink-300 border border-pink-500/30',
|
|
110
|
+
PersistentVolumeClaim: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
111
|
+
|
|
112
|
+
// Argo Rollouts
|
|
113
|
+
Rollout: 'bg-emerald-500/20 text-emerald-700 dark:text-emerald-300 border border-emerald-500/30',
|
|
114
|
+
|
|
115
|
+
// GitOps
|
|
116
|
+
Application: 'bg-orange-500/20 text-orange-700 dark:text-orange-300 border border-orange-500/30',
|
|
117
|
+
Kustomization: 'bg-indigo-500/20 text-indigo-700 dark:text-indigo-300 border border-indigo-500/30',
|
|
118
|
+
GitRepository: 'bg-indigo-500/20 text-indigo-700 dark:text-indigo-300 border border-indigo-500/30',
|
|
119
|
+
|
|
120
|
+
// Cluster-scoped
|
|
121
|
+
Node: 'bg-sky-500/20 text-sky-700 dark:text-sky-300 border border-sky-500/30',
|
|
122
|
+
Namespace: 'bg-gray-500/20 text-gray-700 dark:text-gray-300 border border-gray-500/30',
|
|
123
|
+
|
|
124
|
+
// Knative
|
|
125
|
+
KnativeService: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
126
|
+
KnativeConfiguration: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
127
|
+
KnativeRevision: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
128
|
+
KnativeRoute: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
129
|
+
Broker: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
130
|
+
Trigger: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
131
|
+
PingSource: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
132
|
+
ApiServerSource: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
133
|
+
ContainerSource: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
134
|
+
SinkBinding: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
135
|
+
Channel: 'bg-fuchsia-500/20 text-fuchsia-700 dark:text-fuchsia-300 border border-fuchsia-500/30',
|
|
136
|
+
|
|
137
|
+
// Traefik
|
|
138
|
+
IngressRoute: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
139
|
+
IngressRouteTCP: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
140
|
+
IngressRouteUDP: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
141
|
+
Middleware: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
142
|
+
MiddlewareTCP: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
143
|
+
TraefikService: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
144
|
+
ServersTransport: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
145
|
+
ServersTransportTCP: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
146
|
+
TLSOption: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
147
|
+
TLSStore: 'bg-cyan-500/20 text-cyan-700 dark:text-cyan-300 border border-cyan-500/30',
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Event type colors - for K8s event types (Normal, Warning)
|
|
151
|
+
export const EVENT_TYPE_COLORS: Record<string, string> = {
|
|
152
|
+
Warning: 'bg-amber-500/20 text-amber-700 dark:text-amber-300',
|
|
153
|
+
Normal: 'bg-green-500/20 text-green-700 dark:text-green-300',
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Operation colors - for change events (add, update, delete)
|
|
157
|
+
export const OPERATION_COLORS: Record<string, string> = {
|
|
158
|
+
add: 'text-green-700 dark:text-green-300',
|
|
159
|
+
update: 'text-blue-700 dark:text-blue-300',
|
|
160
|
+
delete: 'text-red-700 dark:text-red-300',
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Operation background colors - for badges with background
|
|
164
|
+
export const OPERATION_BADGE_COLORS: Record<string, string> = {
|
|
165
|
+
add: 'bg-green-500/20 text-green-700 dark:text-green-300',
|
|
166
|
+
update: 'bg-blue-500/20 text-blue-700 dark:text-blue-300',
|
|
167
|
+
delete: 'bg-red-500/20 text-red-700 dark:text-red-300',
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Health badge colors - for health state indicators
|
|
171
|
+
export const HEALTH_BADGE_COLORS: Record<string, string> = {
|
|
172
|
+
healthy: 'bg-green-500/20 text-green-700 dark:text-green-300',
|
|
173
|
+
degraded: 'bg-yellow-500/20 text-yellow-700 dark:text-yellow-300',
|
|
174
|
+
unhealthy: 'bg-red-500/20 text-red-700 dark:text-red-300',
|
|
175
|
+
unknown: 'bg-theme-hover/50 text-theme-text-secondary',
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Helm release status colors
|
|
179
|
+
export const HELM_STATUS_COLORS: Record<string, string> = {
|
|
180
|
+
deployed: 'bg-green-500/20 text-green-700 dark:text-green-300',
|
|
181
|
+
superseded: 'bg-theme-hover/50 text-theme-text-secondary',
|
|
182
|
+
failed: 'bg-red-500/20 text-red-700 dark:text-red-300',
|
|
183
|
+
'pending-install': 'bg-yellow-500/20 text-yellow-700 dark:text-yellow-300',
|
|
184
|
+
'pending-upgrade': 'bg-yellow-500/20 text-yellow-700 dark:text-yellow-300',
|
|
185
|
+
'pending-rollback': 'bg-yellow-500/20 text-yellow-700 dark:text-yellow-300',
|
|
186
|
+
uninstalling: 'bg-orange-500/20 text-orange-700 dark:text-orange-300',
|
|
187
|
+
uninstalled: 'bg-theme-hover/50 text-theme-text-secondary',
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Default fallback color
|
|
191
|
+
export const DEFAULT_BADGE_COLOR = 'bg-theme-elevated text-theme-text-secondary'
|
|
192
|
+
|
|
193
|
+
// =============================================================================
|
|
194
|
+
// SEVERITY COLORS - for status indicators, alerts, and feedback
|
|
195
|
+
// =============================================================================
|
|
196
|
+
|
|
197
|
+
// Severity badge colors - with background (for badges, pills, tags)
|
|
198
|
+
export const SEVERITY_BADGE = {
|
|
199
|
+
success: 'bg-green-500/20 text-green-700 dark:text-green-300',
|
|
200
|
+
warning: 'bg-amber-500/20 text-amber-700 dark:text-amber-300',
|
|
201
|
+
error: 'bg-red-500/20 text-red-700 dark:text-red-300',
|
|
202
|
+
info: 'bg-blue-500/20 text-blue-700 dark:text-blue-300',
|
|
203
|
+
neutral: 'bg-theme-hover/50 text-theme-text-secondary',
|
|
204
|
+
} as const
|
|
205
|
+
|
|
206
|
+
// Severity text colors - without background (for inline text, icons)
|
|
207
|
+
export const SEVERITY_TEXT = {
|
|
208
|
+
success: 'text-green-700 dark:text-green-300',
|
|
209
|
+
warning: 'text-amber-700 dark:text-amber-300',
|
|
210
|
+
error: 'text-red-700 dark:text-red-300',
|
|
211
|
+
info: 'text-blue-700 dark:text-blue-300',
|
|
212
|
+
neutral: 'text-theme-text-secondary',
|
|
213
|
+
} as const
|
|
214
|
+
|
|
215
|
+
// Severity dot/indicator colors - solid colors for small status dots
|
|
216
|
+
export const SEVERITY_DOT = {
|
|
217
|
+
success: 'bg-green-500',
|
|
218
|
+
warning: 'bg-yellow-500',
|
|
219
|
+
error: 'bg-red-500',
|
|
220
|
+
info: 'bg-blue-500',
|
|
221
|
+
neutral: 'bg-theme-hover',
|
|
222
|
+
} as const
|
|
223
|
+
|
|
224
|
+
// Severity border colors - for bordered elements
|
|
225
|
+
export const SEVERITY_BORDER = {
|
|
226
|
+
success: 'border-green-500/30',
|
|
227
|
+
warning: 'border-amber-500/30',
|
|
228
|
+
error: 'border-red-500/30',
|
|
229
|
+
info: 'border-blue-500/30',
|
|
230
|
+
neutral: 'border-theme-border',
|
|
231
|
+
} as const
|
|
232
|
+
|
|
233
|
+
// Combined severity styles - badge with border (for prominent indicators)
|
|
234
|
+
export const SEVERITY_BADGE_BORDERED = {
|
|
235
|
+
success: 'bg-green-500/20 text-green-700 dark:text-green-300 border border-green-500/30',
|
|
236
|
+
warning: 'bg-amber-500/20 text-amber-700 dark:text-amber-300 border border-amber-500/30',
|
|
237
|
+
error: 'bg-red-500/20 text-red-700 dark:text-red-300 border border-red-500/30',
|
|
238
|
+
info: 'bg-blue-500/20 text-blue-700 dark:text-blue-300 border border-blue-500/30',
|
|
239
|
+
neutral: 'bg-theme-hover/50 text-theme-text-secondary border border-theme-border',
|
|
240
|
+
} as const
|
|
241
|
+
|
|
242
|
+
// Severity type
|
|
243
|
+
export type Severity = 'success' | 'warning' | 'error' | 'info' | 'neutral'
|
|
244
|
+
|
|
245
|
+
// =============================================================================
|
|
246
|
+
// RESOURCE STATUS COLORS - for K8s resource states
|
|
247
|
+
// =============================================================================
|
|
248
|
+
|
|
249
|
+
// Pod/workload status colors - maps common K8s status strings to severity
|
|
250
|
+
export const RESOURCE_STATUS_COLORS: Record<string, string> = {
|
|
251
|
+
// Success states
|
|
252
|
+
running: SEVERITY_BADGE.success,
|
|
253
|
+
active: SEVERITY_BADGE.success,
|
|
254
|
+
succeeded: SEVERITY_BADGE.success,
|
|
255
|
+
bound: SEVERITY_BADGE.success,
|
|
256
|
+
ready: SEVERITY_BADGE.success,
|
|
257
|
+
available: SEVERITY_BADGE.success,
|
|
258
|
+
|
|
259
|
+
// Warning states
|
|
260
|
+
pending: SEVERITY_BADGE.warning,
|
|
261
|
+
progressing: SEVERITY_BADGE.warning,
|
|
262
|
+
suspended: SEVERITY_BADGE.warning,
|
|
263
|
+
'scaled to 0': SEVERITY_BADGE.warning,
|
|
264
|
+
waiting: SEVERITY_BADGE.warning,
|
|
265
|
+
|
|
266
|
+
// Error states
|
|
267
|
+
failed: SEVERITY_BADGE.error,
|
|
268
|
+
error: SEVERITY_BADGE.error,
|
|
269
|
+
crashloopbackoff: SEVERITY_BADGE.error,
|
|
270
|
+
imagepullbackoff: SEVERITY_BADGE.error,
|
|
271
|
+
evicted: SEVERITY_BADGE.error,
|
|
272
|
+
oomkilled: SEVERITY_BADGE.error,
|
|
273
|
+
|
|
274
|
+
// Info/completed states
|
|
275
|
+
completed: SEVERITY_BADGE.info,
|
|
276
|
+
terminated: SEVERITY_BADGE.info,
|
|
277
|
+
|
|
278
|
+
// Unknown/neutral
|
|
279
|
+
unknown: SEVERITY_BADGE.neutral,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Helper functions
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get severity badge classes (with background)
|
|
286
|
+
*/
|
|
287
|
+
export function getSeverityBadge(severity: Severity): string {
|
|
288
|
+
return SEVERITY_BADGE[severity]
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Get severity text classes (no background)
|
|
293
|
+
*/
|
|
294
|
+
export function getSeverityText(severity: Severity): string {
|
|
295
|
+
return SEVERITY_TEXT[severity]
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get severity dot classes (solid background for indicators)
|
|
300
|
+
*/
|
|
301
|
+
export function getSeverityDot(severity: Severity): string {
|
|
302
|
+
return SEVERITY_DOT[severity]
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Get severity badge with border classes
|
|
307
|
+
*/
|
|
308
|
+
export function getSeverityBadgeBordered(severity: Severity): string {
|
|
309
|
+
return SEVERITY_BADGE_BORDERED[severity]
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get resource status badge color from a status string
|
|
314
|
+
* Automatically maps common K8s status strings to appropriate colors
|
|
315
|
+
*/
|
|
316
|
+
export function getResourceStatusColor(status: string): string {
|
|
317
|
+
if (!status) return SEVERITY_BADGE.neutral
|
|
318
|
+
const statusLower = status.toLowerCase()
|
|
319
|
+
return RESOURCE_STATUS_COLORS[statusLower] || SEVERITY_BADGE.neutral
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Map a health/status level to a severity
|
|
324
|
+
*/
|
|
325
|
+
export function healthToSeverity(health: string): Severity {
|
|
326
|
+
switch (health.toLowerCase()) {
|
|
327
|
+
case 'healthy':
|
|
328
|
+
case 'success':
|
|
329
|
+
case 'running':
|
|
330
|
+
case 'ready':
|
|
331
|
+
return 'success'
|
|
332
|
+
case 'degraded':
|
|
333
|
+
case 'warning':
|
|
334
|
+
case 'pending':
|
|
335
|
+
return 'warning'
|
|
336
|
+
case 'unhealthy':
|
|
337
|
+
case 'error':
|
|
338
|
+
case 'failed':
|
|
339
|
+
return 'error'
|
|
340
|
+
case 'info':
|
|
341
|
+
return 'info'
|
|
342
|
+
default:
|
|
343
|
+
return 'neutral'
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// =============================================================================
|
|
348
|
+
// LEGACY HELPER FUNCTIONS - for backward compatibility
|
|
349
|
+
// =============================================================================
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Get the badge color classes for a K8s resource kind
|
|
353
|
+
*/
|
|
354
|
+
export function getKindBadgeColor(kind: string): string {
|
|
355
|
+
return KIND_BADGE_COLORS[kind] || DEFAULT_BADGE_COLOR
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Get the badge color classes with border for a K8s resource kind
|
|
360
|
+
*/
|
|
361
|
+
export function getKindBadgeBordered(kind: string): string {
|
|
362
|
+
return KIND_BADGE_BORDERED[kind] || 'bg-theme-hover/50 text-theme-text-secondary border border-theme-border'
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Get the badge color classes for a K8s event type (Normal, Warning)
|
|
367
|
+
*/
|
|
368
|
+
export function getEventTypeColor(eventType: string): string {
|
|
369
|
+
return EVENT_TYPE_COLORS[eventType] || DEFAULT_BADGE_COLOR
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get the text color classes for a change operation (add, update, delete)
|
|
374
|
+
*/
|
|
375
|
+
export function getOperationColor(operation: string): string {
|
|
376
|
+
return OPERATION_COLORS[operation] || 'text-theme-text-secondary'
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get the badge color classes for a change operation (add, update, delete)
|
|
381
|
+
*/
|
|
382
|
+
export function getOperationBadgeColor(operation: string): string {
|
|
383
|
+
return OPERATION_BADGE_COLORS[operation] || DEFAULT_BADGE_COLOR
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Get the badge color classes for a health state
|
|
388
|
+
*/
|
|
389
|
+
export function getHealthBadgeColor(healthState: string): string {
|
|
390
|
+
return HEALTH_BADGE_COLORS[healthState] || HEALTH_BADGE_COLORS.unknown
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get the badge color classes for a Helm release status
|
|
395
|
+
*/
|
|
396
|
+
export function getHelmStatusColor(status: string): string {
|
|
397
|
+
const statusLower = status.toLowerCase()
|
|
398
|
+
return HELM_STATUS_COLORS[statusLower] || 'bg-theme-hover/50 text-theme-text-secondary'
|
|
399
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface ParsedContextName {
|
|
2
|
+
provider: 'GKE' | 'EKS' | 'AKS' | null
|
|
3
|
+
account: string | null // Project (GCP) or Account ID (AWS) or Resource Group (Azure)
|
|
4
|
+
region: string | null
|
|
5
|
+
clusterName: string
|
|
6
|
+
raw: string // Original context name
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Parse a kubeconfig context name to extract cloud provider, account, region,
|
|
11
|
+
* and cluster name. Used by the context switcher and error views.
|
|
12
|
+
*/
|
|
13
|
+
export function parseContextName(name: string): ParsedContextName {
|
|
14
|
+
// GKE format: gke_{project}_{region}_{cluster-name}
|
|
15
|
+
const gkeMatch = name.match(/^gke_([^_]+)_([^_]+)_(.+)$/)
|
|
16
|
+
if (gkeMatch) {
|
|
17
|
+
const [, project, region, cluster] = gkeMatch
|
|
18
|
+
return {
|
|
19
|
+
provider: 'GKE',
|
|
20
|
+
account: project,
|
|
21
|
+
region,
|
|
22
|
+
clusterName: cluster,
|
|
23
|
+
raw: name,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// EKS ARN format: arn:aws:eks:{region}:{account}:cluster/{cluster-name}
|
|
28
|
+
const eksArnMatch = name.match(/^arn:aws:eks:([^:]+):(\d+):cluster\/(.+)$/)
|
|
29
|
+
if (eksArnMatch) {
|
|
30
|
+
const [, region, account, cluster] = eksArnMatch
|
|
31
|
+
return {
|
|
32
|
+
provider: 'EKS',
|
|
33
|
+
account,
|
|
34
|
+
region,
|
|
35
|
+
clusterName: cluster,
|
|
36
|
+
raw: name,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// eksctl format: {user}@{cluster}.{region}.eksctl.io
|
|
41
|
+
const eksctlMatch = name.match(/^(.+)@([^.]+)\.([^.]+)\.eksctl\.io$/)
|
|
42
|
+
if (eksctlMatch) {
|
|
43
|
+
const [, , cluster, region] = eksctlMatch
|
|
44
|
+
return {
|
|
45
|
+
provider: 'EKS',
|
|
46
|
+
account: 'eksctl',
|
|
47
|
+
region,
|
|
48
|
+
clusterName: cluster,
|
|
49
|
+
raw: name,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// AKS format: try to detect
|
|
54
|
+
if (name.toLowerCase().includes('aks') || name.includes('.azure.') || name.includes('azurecr')) {
|
|
55
|
+
return {
|
|
56
|
+
provider: 'AKS',
|
|
57
|
+
account: null,
|
|
58
|
+
region: null,
|
|
59
|
+
clusterName: name,
|
|
60
|
+
raw: name,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Other/unknown - just use the name as cluster name
|
|
65
|
+
return {
|
|
66
|
+
provider: null,
|
|
67
|
+
account: null,
|
|
68
|
+
region: null,
|
|
69
|
+
clusterName: name,
|
|
70
|
+
raw: name,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Triggers a file download in the browser or desktop webview. */
|
|
2
|
+
export function triggerDownload(content: string, mime: string, filename: string): void {
|
|
3
|
+
const blob = new Blob([content], { type: mime })
|
|
4
|
+
const url = URL.createObjectURL(blob)
|
|
5
|
+
const a = document.createElement('a')
|
|
6
|
+
|
|
7
|
+
a.href = url
|
|
8
|
+
a.download = filename
|
|
9
|
+
a.style.display = 'none'
|
|
10
|
+
|
|
11
|
+
document.body.appendChild(a)
|
|
12
|
+
a.click()
|
|
13
|
+
|
|
14
|
+
// Delay cleanup so embedded webviews still have time to consume the blob URL.
|
|
15
|
+
window.setTimeout(() => {
|
|
16
|
+
URL.revokeObjectURL(url)
|
|
17
|
+
a.remove()
|
|
18
|
+
}, 1000)
|
|
19
|
+
}
|