File size: 4,362 Bytes
b7a7142 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | class CustomNodeGroup extends HTMLElement {
connectedCallback() {
const title = this.getAttribute('title') || 'Nodes';
const status = this.getAttribute('status') || 'operational';
const count = this.getAttribute('count') || '0';
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.card {
background: rgba(15, 23, 42, 0.5);
backdrop-filter: blur(10px);
border: 1px solid rgba(30, 41, 59, 0.5);
transition: all 0.2s;
}
.card:hover {
border-color: rgba(56, 182, 255, 0.3);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.status-badge {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
border-radius: 9999px;
}
.status-operational {
background-color: rgba(74, 222, 128, 0.1);
color: rgb(74, 222, 128);
}
.status-degraded {
background-color: rgba(250, 204, 21, 0.1);
color: rgb(250, 204, 21);
}
.status-outage {
background-color: rgba(248, 113, 113, 0.1);
color: rgb(248, 113, 113);
}
.node-item {
border-bottom: 1px solid rgba(30, 41, 59, 0.5);
transition: background-color 0.2s;
}
.node-item:last-child {
border-bottom: none;
}
.node-item:hover {
background-color: rgba(30, 41, 59, 0.3);
}
.latency-normal {
color: rgb(74, 222, 128);
}
.latency-warning {
color: rgb(250, 204, 21);
}
.latency-high {
color: rgb(248, 113, 113);
}
</style>
<div class="card rounded-xl overflow-hidden mb-6">
<div class="px-6 py-4 flex justify-between items-center border-b border-graphite-800">
<h3 class="text-lg font-semibold">${title}</h3>
<span class="status-badge status-${status} flex items-center">
<i data-feather="${status === 'operational' ? 'check-circle' : status === 'degraded' ? 'alert-triangle' : 'x-circle'}" class="w-3 h-3 mr-1"></i>
${status.charAt(0).toUpperCase() + status.slice(1)} (${count})
</span>
</div>
<div class="divide-y divide-graphite-800">
${this.generateNodeItems(title, count)}
</div>
</div>
`;
}
generateNodeItems(group, count) {
const nodes = [];
const groupPrefix = group.split(' ')[0].toLowerCase();
for (let i = 1; i <= parseInt(count); i++) {
const latency = Math.floor(Math.random() * 500) + 50;
const latencyClass = latency <= 300 ? 'latency-normal' :
latency <= 700 ? 'latency-warning' : 'latency-high';
nodes.push(`
<div class="node-item px-6 py-4 flex justify-between items-center">
<div class="flex items-center">
<i data-feather="server" class="w-5 h-5 mr-3 text-blue-400"></i>
<div>
<div class="font-medium">${groupPrefix}-node-${i}</div>
<div class="text-xs text-graphite-400">${groupPrefix.toUpperCase()} • us-east-1</div>
</div>
</div>
<div class="${latencyClass} font-mono">${latency} ms</div>
</div>
`);
}
return nodes.join('');
}
}
customElements.define('custom-node-group', CustomNodeGroup); |