Added ids and classes for services and bookmarks

This commit is contained in:
Yann Le Vagueres 2023-09-10 14:50:25 +02:00
parent a6d5530d6f
commit a30a4cab78
No known key found for this signature in database
GPG Key ID: EF41B255CD47BC5E
13 changed files with 56 additions and 49 deletions

View File

@ -13,6 +13,7 @@ export default function BookmarksGroup({ bookmarks, layout, disableCollapse }) {
<div
key={bookmarks.name}
className={classNames(
"bookmark-group",
layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/4 lg:basis-1/5 xl:basis-1/6",
layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1"
)}
@ -23,11 +24,11 @@ export default function BookmarksGroup({ bookmarks, layout, disableCollapse }) {
{layout?.header !== false && (
<Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group">
{layout?.icon && (
<div className="flex-shrink-0 mr-2 w-7 h-7">
<div className="flex-shrink-0 mr-2 w-7 h-7 bookmark-group-icon">
<ResolvedIcon icon={layout.icon} />
</div>
)}
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{bookmarks.name}</h2>
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium bookmark-group-name">{bookmarks.name}</h2>
<MdKeyboardArrowDown
className={classNames(
disableCollapse ? "hidden" : "",

View File

@ -9,7 +9,7 @@ export default function Item({ bookmark }) {
const { settings } = useContext(SettingsContext);
return (
<li key={bookmark.name}>
<li key={bookmark.name} id={bookmark.id} className="bookmark">
<a
href={bookmark.href}
title={bookmark.name}
@ -20,7 +20,7 @@ export default function Item({ bookmark }) {
)}
>
<div className="flex">
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md bookmark-icon">
{bookmark.icon &&
<div className="flex-shrink-0 w-5 h-5">
<ResolvedIcon icon={bookmark.icon} alt={bookmark.abbr} />
@ -28,9 +28,9 @@ export default function Item({ bookmark }) {
}
{!bookmark.icon && bookmark.abbr}
</div>
<div className="flex-1 flex items-center justify-between rounded-r-md">
<div className="flex-1 grow pl-3 py-2 text-xs">{bookmark.name}</div>
<div className="px-2 py-2 truncate text-theme-500 dark:text-theme-300 text-xs">{hostname}</div>
<div className="flex-1 flex items-center justify-between rounded-r-md bookmark-text">
<div className="flex-1 grow pl-3 py-2 text-xs bookmark-name">{bookmark.name}</div>
<div className="px-2 py-2 truncate text-theme-500 dark:text-theme-300 text-xs bookmark-hostname">{hostname}</div>
</div>
</div>
</a>

View File

@ -9,7 +9,7 @@ export default function List({ bookmarks, layout }) {
<ul
className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
"mt-3"
"mt-3 bookmark-list"
)}
>
{bookmarks.map((bookmark) => (

View File

@ -14,6 +14,7 @@ export default function ServicesGroup({ group, services, layout, fiveColumns, di
<div
key={services.name}
className={classNames(
"services-group",
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",
@ -25,11 +26,11 @@ export default function ServicesGroup({ group, services, layout, fiveColumns, di
{ layout?.header !== false &&
<Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group">
{layout?.icon &&
<div className="flex-shrink-0 mr-2 w-7 h-7">
<div className="flex-shrink-0 mr-2 w-7 h-7 service-group-icon">
<ResolvedIcon icon={layout.icon} />
</div>
}
<h2 className="flex text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2>
<h2 className="flex text-theme-800 dark:text-theme-300 text-xl font-medium service-group-name">{services.name}</h2>
<MdKeyboardArrowDown className={classNames(
disableCollapse ? 'hidden' : '',
'transition-all opacity-0 group-hover:opacity-100 ml-auto text-theme-800 dark:text-theme-300 text-xl',

View File

@ -29,28 +29,30 @@ export default function Item({ service, group }) {
}
};
return (
<li key={service.name}>
<li key={service.name} id={service.id} className="service" data-name={service.name || ""}>
<div
className={classNames(
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? '-' : ""}${settings.cardBlur}`,
hasLink && "cursor-pointer",
'transition-all h-15 mb-2 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative overflow-clip'
'transition-all h-15 mb-2 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative overflow-clip',
'service-card'
)}
>
<div className="flex select-none z-0">
<div className="flex select-none z-0 service-title">
{service.icon &&
(hasLink ? (
<a
href={service.href}
target={service.target ?? settings.target ?? "_blank"}
rel="noreferrer"
className="flex-shrink-0 flex items-center justify-center w-12 "
className="flex-shrink-0 flex items-center justify-center w-12 service-icon"
>
<ResolvedIcon icon={service.icon} />
</a>
) : (
<div className="flex-shrink-0 flex items-center justify-center w-12 ">
<div className="flex-shrink-0 flex items-center justify-center w-12 service-icon">
<ResolvedIcon icon={service.icon} />
</div>
))}
@ -60,25 +62,25 @@ export default function Item({ service, group }) {
href={service.href}
target={service.target ?? settings.target ?? "_blank"}
rel="noreferrer"
className="flex-1 flex items-center justify-between rounded-r-md "
className="flex-1 flex items-center justify-between rounded-r-md service-title-text"
>
<div className="flex-1 px-2 py-2 text-sm text-left z-10">
<div className="flex-1 px-2 py-2 text-sm text-left z-10 service-name">
{service.name}
<p className="text-theme-500 dark:text-theme-300 text-xs font-light">{service.description}</p>
<p className="text-theme-500 dark:text-theme-300 text-xs font-light service-description">{service.description}</p>
</div>
</a>
) : (
<div className="flex-1 flex items-center justify-between rounded-r-md ">
<div className="flex-1 px-2 py-2 text-sm text-left z-10">
<div className="flex-1 flex items-center justify-between rounded-r-md service-title-text">
<div className="flex-1 px-2 py-2 text-sm text-left z-10 service-name">
{service.name}
<p className="text-theme-500 dark:text-theme-300 text-xs font-light">{service.description}</p>
<p className="text-theme-500 dark:text-theme-300 text-xs font-light service-description">{service.description}</p>
</div>
</div>
)}
<div className="absolute top-0 right-0 w-1/2 flex flex-row justify-end gap-2 mr-2 z-30 pointer-events-none">
<div className="absolute top-0 right-0 flex flex-row justify-end gap-2 mr-2 z-30 pointer-events-none service-tags">
{service.ping && (
<div className="flex-shrink-0 flex items-center justify-center cursor-pointer">
<div className="flex-shrink-0 flex items-center justify-center service-tag service-ping">
<Ping group={group} service={service.name} />
<span className="sr-only">Ping status</span>
</div>
@ -88,7 +90,7 @@ export default function Item({ service, group }) {
<button
type="button"
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))}
className="flex-shrink-0 flex items-center justify-center cursor-pointer"
className="flex-shrink-0 flex items-center justify-center cursor-pointer pointer-events-auto service-tag service-container-stats"
>
<Status service={service} />
<span className="sr-only">View container stats</span>
@ -98,7 +100,7 @@ export default function Item({ service, group }) {
<button
type="button"
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))}
className="flex-shrink-0 flex items-center justify-center cursor-pointer"
className="flex-shrink-0 flex items-center justify-center cursor-pointer pointer-events-auto service-tag service-app"
>
<KubernetesStatus service={service} />
<span className="sr-only">View container stats</span>
@ -111,7 +113,8 @@ export default function Item({ service, group }) {
<div
className={classNames(
showStats || (statsOpen && !statsClosing) ? "max-h-[110px] opacity-100" : " max-h-[0] opacity-0",
"w-full overflow-hidden transition-all duration-300 ease-in-out"
"w-full overflow-hidden transition-all duration-300 ease-in-out",
"service-stats"
)}
>
{(showStats || statsOpen) && <Docker service={{ widget: { container: service.container, server: service.server } }} />}
@ -121,7 +124,8 @@ export default function Item({ service, group }) {
<div
className={classNames(
showStats || (statsOpen && !statsClosing) ? "max-h-[55px] opacity-100" : " max-h-[0] opacity-0",
"w-full overflow-hidden transition-all duration-300 ease-in-out"
"w-full overflow-hidden transition-all duration-300 ease-in-out",
"service-stats"
)}
>
{(showStats || statsOpen) && <Kubernetes service={{ widget: { namespace: service.namespace, app: service.app, podSelector: service.podSelector } }} />}

View File

@ -6,14 +6,14 @@ export default function KubernetesStatus({ service }) {
const { data, error } = useSWR(`/api/kubernetes/status/${service.namespace}/${service.app}?${podSelectorString}`);
if (error) {
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.error")}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status-error" title={t("docker.error")}>
<div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div>
</div>
}
if (data && data.status === "running") {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health ?? data.status}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status" title={data.health ?? data.status}>
<div className="text-[8px] font-bold text-emerald-500/80 uppercase">{data.health ?? data.status}</div>
</div>
);
@ -21,14 +21,14 @@ export default function KubernetesStatus({ service }) {
if (data && (data.status === "not found" || data.status === "down" || data.status === "partial")) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status-warning" title={data.status}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div>
</div>
);
}
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden k8s-status-unknown">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div>
</div>
);

View File

@ -9,7 +9,7 @@ export default function List({ group, services, layout }) {
<ul
className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
"mt-3"
"mt-3 services-list"
)}
>
{services.map((service) => (

View File

@ -9,7 +9,7 @@ export default function Ping({ group, service }) {
if (error) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-error">
<div className="text-[8px] font-bold text-rose-500 uppercase">{t("ping.error")}</div>
</div>
);
@ -17,7 +17,7 @@ export default function Ping({ group, service }) {
if (!data) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-ping">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("ping.ping")}</div>
</div>
);
@ -27,14 +27,14 @@ export default function Ping({ group, service }) {
if (data.status > 403) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusText}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-status-invalid" title={statusText}>
<div className="text-[8px] font-bold text-rose-500/80">{data.status}</div>
</div>
);
}
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusText}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden ping-status-valid" title={statusText}>
<div className="text-[8px] font-bold text-emerald-500/80">{t("common.ms", { value: data.latency, style: "unit", unit: "millisecond", maximumFractionDigits: 0 })}</div>
</div>
);

View File

@ -7,7 +7,7 @@ export default function Status({ service }) {
const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`);
if (error) {
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.error")}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-error" title={t("docker.error")}>
<div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div>
</div>
}
@ -18,7 +18,7 @@ export default function Status({ service }) {
if (data.status?.includes("running")) {
if (data.health === "starting") {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.starting")}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-starting" title={t("docker.starting")}>
<div className="text-[8px] font-bold text-blue-500/80 uppercase">{t("docker.starting")}</div>
</div>
);
@ -26,7 +26,7 @@ export default function Status({ service }) {
if (data.health === "unhealthy") {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={t("docker.unhealthy")}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-unhealthy" title={t("docker.unhealthy")}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{t("docker.unhealthy")}</div>
</div>
);
@ -39,7 +39,7 @@ export default function Status({ service }) {
}
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusLabel}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-status" title={statusLabel}>
<div className="text-[8px] font-bold text-emerald-500/80 uppercase">{statusLabel}</div>
</div>
);
@ -50,7 +50,7 @@ export default function Status({ service }) {
else if (data.status === "exited") statusLabel = t("docker.exited")
else statusLabel = data.status.replace("partial", t("docker.partial"))
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusLabel}>
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-status-warning" title={statusLabel}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{statusLabel}</div>
</div>
);
@ -58,7 +58,7 @@ export default function Status({ service }) {
}
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden docker-status-unknown">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div>
</div>
);

View File

@ -17,7 +17,7 @@ export default function Widget({ service }) {
}
return (
<div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1">
<div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1 service-missing">
<div className="font-thin text-sm">{t("widget.missing_type", { type: service.widget.type })}</div>
</div>
);

View File

@ -8,7 +8,8 @@ export default function Block({ value, label }) {
<div
className={classNames(
"bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center text-center p-1",
value === undefined ? "animate-pulse" : ""
value === undefined ? "animate-pulse" : "",
"service-block"
)}
>
<div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div>

View File

@ -36,5 +36,5 @@ export default function Container({ error = false, children, service }) {
}));
}
return <div className="relative flex flex-row w-full">{visibleChildren}</div>;
return <div className="relative flex flex-row w-full service-container">{visibleChildren}</div>;
}

View File

@ -240,7 +240,7 @@ function Home({ initialSettings }) {
const bookmarkGroups = bookmarks.filter(group => settings.layout?.[group.name] === undefined);
return <>
{layoutGroups.length > 0 && <div key="layoutGroups" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{layoutGroups.length > 0 && <div key="layoutGroups" id="layout-groups" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{layoutGroups.map((group) => (
group.services ?
(<ServicesGroup
@ -260,7 +260,7 @@ function Home({ initialSettings }) {
)
)}
</div>}
{serviceGroups?.length > 0 && <div key="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{serviceGroups?.length > 0 && <div key="services" id="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{serviceGroups.map((group) => (
<ServicesGroup
key={group.name}
@ -272,7 +272,7 @@ function Home({ initialSettings }) {
/>
))}
</div>}
{bookmarkGroups?.length > 0 && <div key="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{bookmarkGroups?.length > 0 && <div key="bookmarks" id="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{bookmarkGroups.map((group) => (
<BookmarksGroup
key={group.name}