feat: label editor

This commit is contained in:
2025-10-16 15:38:22 +02:00
parent 55cc8c8d8c
commit bf19071cc4
5 changed files with 744 additions and 3 deletions

View File

@@ -504,6 +504,7 @@ class ClusterMembersComponent extends Component {
newMembers.forEach((newMember) => {
const prevMember = prevByIp.get(newMember.ip);
if (prevMember && this.hasMemberChanged(newMember, prevMember)) {
logger.debug('ClusterMembersComponent: Member changed, updating card for:', newMember.ip);
this.updateMemberCard(newMember);
}
});
@@ -511,9 +512,33 @@ class ClusterMembersComponent extends Component {
// Check if a specific member has changed
hasMemberChanged(newMember, prevMember) {
return newMember.status !== prevMember.status ||
newMember.latency !== prevMember.latency ||
newMember.hostname !== prevMember.hostname;
// Check basic properties
if (newMember.status !== prevMember.status ||
newMember.latency !== prevMember.latency ||
newMember.hostname !== prevMember.hostname) {
return true;
}
// Check labels for changes
const newLabels = newMember.labels || {};
const prevLabels = prevMember.labels || {};
// Compare label keys
const newKeys = Object.keys(newLabels);
const prevKeys = Object.keys(prevLabels);
if (newKeys.length !== prevKeys.length) {
return true;
}
// Compare label values
for (const key of newKeys) {
if (newLabels[key] !== prevLabels[key]) {
return true;
}
}
return false;
}
// Update a specific member card without re-rendering the entire component
@@ -551,6 +576,43 @@ class ClusterMembersComponent extends Component {
if (hostnameElement && member.hostname !== hostnameElement.textContent) {
hostnameElement.textContent = member.hostname || 'Unknown Device';
}
// Update labels (add/update/remove labels row as needed)
const labels = (member && typeof member.labels === 'object') ? member.labels : {};
const hasLabels = labels && Object.keys(labels).length > 0;
let labelsRow = card.querySelector('.member-row-2');
if (hasLabels) {
const chipsHtml = Object.entries(labels)
.map(([key, value]) => `<span class="label-chip">${this.escapeHtml(String(key))}: ${this.escapeHtml(String(value))}</span>`)
.join('');
if (labelsRow) {
const labelsContainer = labelsRow.querySelector('.member-labels');
if (labelsContainer) {
labelsContainer.innerHTML = chipsHtml;
}
} else {
// Create labels row below row-1
const memberInfo = card.querySelector('.member-info');
if (memberInfo) {
labelsRow = document.createElement('div');
labelsRow.className = 'member-row-2';
const labelsContainer = document.createElement('div');
labelsContainer.className = 'member-labels';
labelsContainer.innerHTML = chipsHtml;
labelsRow.appendChild(labelsContainer);
// Insert after the first row if present, otherwise append
const firstRow = memberInfo.querySelector('.member-row-1');
if (firstRow && firstRow.nextSibling) {
memberInfo.insertBefore(labelsRow, firstRow.nextSibling);
} else {
memberInfo.appendChild(labelsRow);
}
}
}
} else if (labelsRow) {
// No labels now: remove the labels row if it exists
labelsRow.remove();
}
}
render() {