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.
+## 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 (
-
- {services.map((service) => (
- - s).join("-")}
- service={service}
- group={group}
- useEqualHeights={layout?.useEqualHeights ?? useEqualHeights}
- />
- ))}
-
+ <>
+
+ {services.map((service) => (
+ - s).join("-")}
+ service={service}
+ group={group}
+ useEqualHeights={layout?.useEqualHeights ?? useEqualHeights}
+ />
+ ))}
+
+ {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) {