Features: Add group nesting/subgroups

This commit is contained in:
damii 2024-11-27 15:07:25 +11:00
parent 5ee2ea559c
commit 4fa024bca6
6 changed files with 88 additions and 35 deletions

View File

@ -21,6 +21,25 @@ Groups are defined as top-level array entries.
<img width="1038" alt="Service Groups" src="https://user-images.githubusercontent.com/82196/187040754-28065242-4534-4409-881c-93d1921c6141.png">
## 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,

View File

@ -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",
)}
>
<Disclosure defaultOpen={!(layout?.initiallyCollapsed ?? groupsInitiallyCollapsed) ?? true}>
@ -74,7 +77,13 @@ export default function ServicesGroup({
}}
>
<Disclosure.Panel className="transition-all overflow-hidden duration-300 ease-out" ref={panel} static>
<List group={group} services={services.services} layout={layout} useEqualHeights={useEqualHeights} />
<List
group={group}
subgroups={subgroups}
services={services.services}
layout={layout}
useEqualHeights={useEqualHeights}
/>
</Disclosure.Panel>
</Transition>
</>

View File

@ -3,9 +3,11 @@ 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 (
<>
<ul
className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
@ -21,5 +23,17 @@ export default function List({ group, services, layout, useEqualHeights }) {
/>
))}
</ul>
{subgroups
.filter((subgroup) => subgroup != [])
.map((subgroup) => (
<Group
group={subgroup}
services={subgroup}
layout={layout}
useEqualHeights={useEqualHeights}
isSubgroup={true}
/>
))}
</>
);
}

View File

@ -292,6 +292,7 @@ function Home({ initialSettings }) {
<ServicesGroup
key={group.name}
group={group.name}
subgroups={group.subgroups}
services={group}
layout={settings.layout?.[group.name]}
fiveColumns={settings.fiveColumns}
@ -317,6 +318,7 @@ function Home({ initialSettings }) {
<ServicesGroup
key={group.name}
group={group.name}
subgroups={group.subgroups}
services={group}
layout={settings.layout?.[group.name]}
fiveColumns={settings.fiveColumns}

View File

@ -142,9 +142,11 @@ export async function servicesResponse() {
mergedGroupsNames.forEach((groupName) => {
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) {

View File

@ -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) => ({
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]],
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;
}
});
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) {