Features: Add group nesting/subgroups
This commit is contained in:
parent
5ee2ea559c
commit
4fa024bca6
@ -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">
|
<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
|
||||||
|
|
||||||
Services are defined as array entries on groups,
|
Services are defined as array entries on groups,
|
||||||
|
|||||||
@ -8,12 +8,14 @@ import ResolvedIcon from "components/resolvedicon";
|
|||||||
|
|
||||||
export default function ServicesGroup({
|
export default function ServicesGroup({
|
||||||
group,
|
group,
|
||||||
|
subgroups,
|
||||||
services,
|
services,
|
||||||
layout,
|
layout,
|
||||||
fiveColumns,
|
fiveColumns,
|
||||||
disableCollapse,
|
disableCollapse,
|
||||||
useEqualHeights,
|
useEqualHeights,
|
||||||
groupsInitiallyCollapsed,
|
groupsInitiallyCollapsed,
|
||||||
|
isSubgroup = false,
|
||||||
}) {
|
}) {
|
||||||
const panel = useRef();
|
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" ? "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?.style !== "row" && fiveColumns ? "3xl:basis-1/5" : "",
|
||||||
layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1",
|
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}>
|
<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>
|
<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>
|
</Disclosure.Panel>
|
||||||
</Transition>
|
</Transition>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -3,23 +3,37 @@ import classNames from "classnames";
|
|||||||
import { columnMap } from "../../utils/layout/columns";
|
import { columnMap } from "../../utils/layout/columns";
|
||||||
|
|
||||||
import Item from "components/services/item";
|
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 (
|
return (
|
||||||
<ul
|
<>
|
||||||
className={classNames(
|
<ul
|
||||||
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
|
className={classNames(
|
||||||
"mt-3 services-list",
|
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
|
||||||
)}
|
"mt-3 services-list",
|
||||||
>
|
)}
|
||||||
{services.map((service) => (
|
>
|
||||||
<Item
|
{services.map((service) => (
|
||||||
key={[service.container, service.app, service.name].filter((s) => s).join("-")}
|
<Item
|
||||||
service={service}
|
key={[service.container, service.app, service.name].filter((s) => s).join("-")}
|
||||||
group={group}
|
service={service}
|
||||||
useEqualHeights={layout?.useEqualHeights ?? useEqualHeights}
|
group={group}
|
||||||
/>
|
useEqualHeights={layout?.useEqualHeights ?? useEqualHeights}
|
||||||
))}
|
/>
|
||||||
</ul>
|
))}
|
||||||
|
</ul>
|
||||||
|
{subgroups
|
||||||
|
.filter((subgroup) => subgroup != [])
|
||||||
|
.map((subgroup) => (
|
||||||
|
<Group
|
||||||
|
group={subgroup}
|
||||||
|
services={subgroup}
|
||||||
|
layout={layout}
|
||||||
|
useEqualHeights={useEqualHeights}
|
||||||
|
isSubgroup={true}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -292,6 +292,7 @@ function Home({ initialSettings }) {
|
|||||||
<ServicesGroup
|
<ServicesGroup
|
||||||
key={group.name}
|
key={group.name}
|
||||||
group={group.name}
|
group={group.name}
|
||||||
|
subgroups={group.subgroups}
|
||||||
services={group}
|
services={group}
|
||||||
layout={settings.layout?.[group.name]}
|
layout={settings.layout?.[group.name]}
|
||||||
fiveColumns={settings.fiveColumns}
|
fiveColumns={settings.fiveColumns}
|
||||||
@ -317,6 +318,7 @@ function Home({ initialSettings }) {
|
|||||||
<ServicesGroup
|
<ServicesGroup
|
||||||
key={group.name}
|
key={group.name}
|
||||||
group={group.name}
|
group={group.name}
|
||||||
|
subgroups={group.subgroups}
|
||||||
services={group}
|
services={group}
|
||||||
layout={settings.layout?.[group.name]}
|
layout={settings.layout?.[group.name]}
|
||||||
fiveColumns={settings.fiveColumns}
|
fiveColumns={settings.fiveColumns}
|
||||||
|
|||||||
@ -142,9 +142,11 @@ export async function servicesResponse() {
|
|||||||
mergedGroupsNames.forEach((groupName) => {
|
mergedGroupsNames.forEach((groupName) => {
|
||||||
const discoveredDockerGroup = discoveredDockerServices.find((group) => group.name === groupName) || {
|
const discoveredDockerGroup = discoveredDockerServices.find((group) => group.name === groupName) || {
|
||||||
services: [],
|
services: [],
|
||||||
|
subgroups: [],
|
||||||
};
|
};
|
||||||
const discoveredKubernetesGroup = discoveredKubernetesServices.find((group) => group.name === groupName) || {
|
const discoveredKubernetesGroup = discoveredKubernetesServices.find((group) => group.name === groupName) || {
|
||||||
services: [],
|
services: [],
|
||||||
|
subgroups: [],
|
||||||
};
|
};
|
||||||
const configuredGroup = configuredServices.find((group) => group.name === groupName) || { services: [] };
|
const configuredGroup = configuredServices.find((group) => group.name === groupName) || { services: [] };
|
||||||
|
|
||||||
@ -153,6 +155,11 @@ export async function servicesResponse() {
|
|||||||
services: [...discoveredDockerGroup.services, ...discoveredKubernetesGroup.services, ...configuredGroup.services]
|
services: [...discoveredDockerGroup.services, ...discoveredKubernetesGroup.services, ...configuredGroup.services]
|
||||||
.filter((service) => service)
|
.filter((service) => service)
|
||||||
.sort(compareServices),
|
.sort(compareServices),
|
||||||
|
subgroups: [
|
||||||
|
...discoveredDockerGroup.subgroups,
|
||||||
|
...discoveredKubernetesGroup.subgroups,
|
||||||
|
...configuredGroup.subgroups,
|
||||||
|
].filter((subgroup) => subgroup),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (definedLayouts) {
|
if (definedLayouts) {
|
||||||
|
|||||||
@ -25,24 +25,22 @@ export async function servicesFromConfig() {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// map easy to write YAML objects into easy to consume JS arrays
|
const mappingFunc = (servicesGroup, servicesArr = servicesGroup[Object.keys(servicesGroup)[0]]) => ({
|
||||||
const servicesArray = services.map((servicesGroup) => ({
|
|
||||||
name: Object.keys(servicesGroup)[0],
|
name: Object.keys(servicesGroup)[0],
|
||||||
services: servicesGroup[Object.keys(servicesGroup)[0]].map((entries) => ({
|
services: servicesArr
|
||||||
name: Object.keys(entries)[0],
|
.filter((entry) => entry[Object.keys(entry)[0]].type != "group")
|
||||||
...entries[Object.keys(entries)[0]],
|
.map((entries, entryIndex) => ({
|
||||||
type: "service",
|
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]],
|
||||||
// add default weight to services based on their position in the configuration
|
})),
|
||||||
servicesArray.forEach((group, groupIndex) => {
|
subgroups: servicesArr
|
||||||
group.services.forEach((service, serviceIndex) => {
|
.filter((entry) => entry[Object.keys(entry)[0]].type == "group")
|
||||||
if (service.weight === undefined) {
|
.map((entries) => mappingFunc(entries, entries[Object.keys(entries)[0]].services)),
|
||||||
servicesArray[groupIndex].services[serviceIndex].weight = (serviceIndex + 1) * 100;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
// map easy to write YAML objects into easy to consume JS arrays
|
||||||
|
const servicesArray = services.map((servicesGroup) => mappingFunc(servicesGroup));
|
||||||
|
|
||||||
return servicesArray;
|
return servicesArray;
|
||||||
}
|
}
|
||||||
@ -134,6 +132,7 @@ export async function servicesFromDocker() {
|
|||||||
mappedServiceGroups.push({
|
mappedServiceGroups.push({
|
||||||
name: serverService.group,
|
name: serverService.group,
|
||||||
services: [],
|
services: [],
|
||||||
|
subgroups: [],
|
||||||
});
|
});
|
||||||
serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1];
|
serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1];
|
||||||
}
|
}
|
||||||
@ -317,6 +316,7 @@ export async function servicesFromKubernetes() {
|
|||||||
mappedServiceGroups.push({
|
mappedServiceGroups.push({
|
||||||
name: serverService.group,
|
name: serverService.group,
|
||||||
services: [],
|
services: [],
|
||||||
|
subgroups: [],
|
||||||
});
|
});
|
||||||
serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1];
|
serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1];
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ export async function servicesFromKubernetes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function cleanServiceGroups(groups) {
|
export function cleanServiceGroups(groups) {
|
||||||
return groups.map((serviceGroup) => ({
|
const cleanerFunc = (serviceGroup) => ({
|
||||||
name: serviceGroup.name,
|
name: serviceGroup.name,
|
||||||
services: serviceGroup.services.map((service) => {
|
services: serviceGroup.services.map((service) => {
|
||||||
const cleanedService = { ...service };
|
const cleanedService = { ...service };
|
||||||
@ -663,7 +663,9 @@ export function cleanServiceGroups(groups) {
|
|||||||
|
|
||||||
return cleanedService;
|
return cleanedService;
|
||||||
}),
|
}),
|
||||||
}));
|
subgroups: serviceGroup.subgroups.map((serviceGroup) => cleanerFunc(serviceGroup)),
|
||||||
|
});
|
||||||
|
return groups.map((serviceGroup) => cleanerFunc(serviceGroup));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServiceItem(group, service) {
|
export async function getServiceItem(group, service) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user