From 4fa024bca6aebb3acf817cffbc732826a47a06a4 Mon Sep 17 00:00:00 2001 From: damii Date: Wed, 27 Nov 2024 15:07:25 +1100 Subject: [PATCH] Features: Add group nesting/subgroups --- docs/configs/services.md | 19 ++++++++++++ src/components/services/group.jsx | 11 ++++++- src/components/services/list.jsx | 46 +++++++++++++++++++---------- src/pages/index.jsx | 2 ++ src/utils/config/api-response.js | 7 +++++ src/utils/config/service-helpers.js | 38 +++++++++++++----------- 6 files changed, 88 insertions(+), 35 deletions(-) diff --git a/docs/configs/services.md b/docs/configs/services.md index 9cb75177..d0b6719d 100644 --- a/docs/configs/services.md +++ b/docs/configs/services.md @@ -21,6 +21,25 @@ Groups are defined as top-level array entries. Service Groups +## Subgroups + +Subgroups are defined as array entries with `type: group` and an array `services: ...`, + +``` +- Group A: + - Subgroup A: + type: group + services: + - Service A: + href: http://localhost/ + - Service B: + href: http://localhost/ + +- Group B: + - Service C: + href: http://localhost/ +``` + ## Services Services are defined as array entries on groups, diff --git a/src/components/services/group.jsx b/src/components/services/group.jsx index cdbb89f3..0b0b36ae 100644 --- a/src/components/services/group.jsx +++ b/src/components/services/group.jsx @@ -8,12 +8,14 @@ import ResolvedIcon from "components/resolvedicon"; export default function ServicesGroup({ group, + subgroups, services, layout, fiveColumns, disableCollapse, useEqualHeights, groupsInitiallyCollapsed, + isSubgroup = false, }) { const panel = useRef(); @@ -29,6 +31,7 @@ export default function ServicesGroup({ layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4", layout?.style !== "row" && fiveColumns ? "3xl:basis-1/5" : "", layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1", + isSubgroup === false ? "" : "bg-theme-500/20 dark:bg-white/5 rounded-md px-2 py-2", )} > @@ -74,7 +77,13 @@ export default function ServicesGroup({ }} > - + diff --git a/src/components/services/list.jsx b/src/components/services/list.jsx index f3fd6e2a..e437067f 100644 --- a/src/components/services/list.jsx +++ b/src/components/services/list.jsx @@ -3,23 +3,37 @@ import classNames from "classnames"; import { columnMap } from "../../utils/layout/columns"; import Item from "components/services/item"; +import Group from "components/services/group"; -export default function List({ group, services, layout, useEqualHeights }) { +export default function List({ group, subgroups = [], services, layout, useEqualHeights }) { return ( - + <> + + {subgroups + .filter((subgroup) => subgroup != []) + .map((subgroup) => ( + + ))} + ); } diff --git a/src/pages/index.jsx b/src/pages/index.jsx index dd0df95f..993cc75c 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -292,6 +292,7 @@ function Home({ initialSettings }) { { const discoveredDockerGroup = discoveredDockerServices.find((group) => group.name === groupName) || { services: [], + subgroups: [], }; const discoveredKubernetesGroup = discoveredKubernetesServices.find((group) => group.name === groupName) || { services: [], + subgroups: [], }; const configuredGroup = configuredServices.find((group) => group.name === groupName) || { services: [] }; @@ -153,6 +155,11 @@ export async function servicesResponse() { services: [...discoveredDockerGroup.services, ...discoveredKubernetesGroup.services, ...configuredGroup.services] .filter((service) => service) .sort(compareServices), + subgroups: [ + ...discoveredDockerGroup.subgroups, + ...discoveredKubernetesGroup.subgroups, + ...configuredGroup.subgroups, + ].filter((subgroup) => subgroup), }; if (definedLayouts) { diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index ea82c735..035b5860 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -25,24 +25,22 @@ export async function servicesFromConfig() { return []; } - // map easy to write YAML objects into easy to consume JS arrays - const servicesArray = services.map((servicesGroup) => ({ + const mappingFunc = (servicesGroup, servicesArr = servicesGroup[Object.keys(servicesGroup)[0]]) => ({ name: Object.keys(servicesGroup)[0], - services: servicesGroup[Object.keys(servicesGroup)[0]].map((entries) => ({ - name: Object.keys(entries)[0], - ...entries[Object.keys(entries)[0]], - type: "service", - })), - })); - - // add default weight to services based on their position in the configuration - servicesArray.forEach((group, groupIndex) => { - group.services.forEach((service, serviceIndex) => { - if (service.weight === undefined) { - servicesArray[groupIndex].services[serviceIndex].weight = (serviceIndex + 1) * 100; - } - }); + services: servicesArr + .filter((entry) => entry[Object.keys(entry)[0]].type != "group") + .map((entries, entryIndex) => ({ + name: Object.keys(entries)[0], + weight: (entryIndex + 1) * 100, + type: entries[Object.keys(entries)[0]].type ? entries[Object.keys(entries)[0]].type : "service", + ...entries[Object.keys(entries)[0]], + })), + subgroups: servicesArr + .filter((entry) => entry[Object.keys(entry)[0]].type == "group") + .map((entries) => mappingFunc(entries, entries[Object.keys(entries)[0]].services)), }); + // map easy to write YAML objects into easy to consume JS arrays + const servicesArray = services.map((servicesGroup) => mappingFunc(servicesGroup)); return servicesArray; } @@ -134,6 +132,7 @@ export async function servicesFromDocker() { mappedServiceGroups.push({ name: serverService.group, services: [], + subgroups: [], }); serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1]; } @@ -317,6 +316,7 @@ export async function servicesFromKubernetes() { mappedServiceGroups.push({ name: serverService.group, services: [], + subgroups: [], }); serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1]; } @@ -338,7 +338,7 @@ export async function servicesFromKubernetes() { } export function cleanServiceGroups(groups) { - return groups.map((serviceGroup) => ({ + const cleanerFunc = (serviceGroup) => ({ name: serviceGroup.name, services: serviceGroup.services.map((service) => { const cleanedService = { ...service }; @@ -663,7 +663,9 @@ export function cleanServiceGroups(groups) { return cleanedService; }), - })); + subgroups: serviceGroup.subgroups.map((serviceGroup) => cleanerFunc(serviceGroup)), + }); + return groups.map((serviceGroup) => cleanerFunc(serviceGroup)); } export async function getServiceItem(group, service) {