Enhancement: support automatic service discovery services with layout-only nesting (#4900)

This commit is contained in:
shamoon 2025-03-10 09:45:50 -07:00 committed by GitHub
parent f33ff582fd
commit 4c91dfa71b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -85,6 +85,18 @@ export async function widgetsResponse() {
return configuredWidgets; return configuredWidgets;
} }
function convertLayoutGroupToGroup(name, layoutGroup) {
const group = { name, services: [], groups: [] };
if (layoutGroup) {
Object.entries(layoutGroup).forEach(([key, value]) => {
if (typeof value === "object") {
group.groups.push(convertLayoutGroupToGroup(key, value));
}
});
}
return group;
}
function mergeSubgroups(configuredGroups, mergedGroup) { function mergeSubgroups(configuredGroups, mergedGroup) {
configuredGroups.forEach((group) => { configuredGroups.forEach((group) => {
if (group.name === mergedGroup.name) { if (group.name === mergedGroup.name) {
@ -96,6 +108,33 @@ function mergeSubgroups(configuredGroups, mergedGroup) {
}); });
} }
function ensureParentGroupExists(sortedGroups, configuredGroups, group, definedLayouts) {
// make sure the top level parent group exists in the sortedGroups array
const parentGroupName = group.parent;
const parentGroup = findGroupByName(configuredGroups, parentGroupName);
if (parentGroup && parentGroup.parent) {
ensureParentGroupExists(sortedGroups, configuredGroups, parentGroup);
} else {
const parentGroupIndex = definedLayouts.findIndex((layout) => layout === parentGroupName);
if (parentGroupIndex > -1) {
sortedGroups[parentGroupIndex] = parentGroup;
}
}
}
function pruneEmptyGroups(groups) {
// remove any groups that have no services
return groups.filter((group) => {
if (group.services.length === 0 && group.groups.length === 0) {
return false;
}
if (group.groups.length > 0) {
group.groups = pruneEmptyGroups(group.groups);
}
return true;
});
}
export async function servicesResponse() { export async function servicesResponse() {
let discoveredDockerServices; let discoveredDockerServices;
let discoveredKubernetesServices; let discoveredKubernetesServices;
@ -150,6 +189,17 @@ export async function servicesResponse() {
const sortedGroups = []; const sortedGroups = [];
const unsortedGroups = []; const unsortedGroups = [];
const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null; const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null;
if (definedLayouts) {
// this handles cases where groups are only defined in the settings.yaml layout and not in the services.yaml
const layoutConfiguredGroups = Object.entries(initialSettings.layout).map(([key, value]) =>
convertLayoutGroupToGroup(key, value),
);
layoutConfiguredGroups.forEach((group) => {
if (!configuredServices.find((serviceGroup) => serviceGroup.name === group.name)) {
configuredServices.push(group);
}
});
}
mergedGroupsNames.forEach((groupName) => { mergedGroupsNames.forEach((groupName) => {
const discoveredDockerGroup = findGroupByName(discoveredDockerServices, groupName) || { const discoveredDockerGroup = findGroupByName(discoveredDockerServices, groupName) || {
@ -174,6 +224,8 @@ export async function servicesResponse() {
else if (configuredGroup.parent) { else if (configuredGroup.parent) {
// this is a nested group, so find the parent group and merge the services // this is a nested group, so find the parent group and merge the services
mergeSubgroups(configuredServices, mergedGroup); mergeSubgroups(configuredServices, mergedGroup);
// make sure the top level parent group exists in the sortedGroups array
ensureParentGroupExists(sortedGroups, configuredServices, configuredGroup, definedLayouts);
} else unsortedGroups.push(mergedGroup); } else unsortedGroups.push(mergedGroup);
} else if (configuredGroup.parent) { } else if (configuredGroup.parent) {
// this is a nested group, so find the parent group and merge the services // this is a nested group, so find the parent group and merge the services
@ -183,5 +235,6 @@ export async function servicesResponse() {
} }
}); });
return [...sortedGroups.filter((g) => g), ...unsortedGroups]; const allGroups = [...sortedGroups.filter((g) => g), ...unsortedGroups];
return pruneEmptyGroups(allGroups);
} }