110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
import { BrowserLink } from "@metis/core/client";
|
|
import { Button } from "@repo/shadcn-ui/components/button";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import {
|
|
applicationApi,
|
|
applicationKeys,
|
|
} from "../../../application-configurations/shared/api/application-api";
|
|
import { softwareApi, softwareKeys } from "../../../software-installations/shared/api/software-api";
|
|
|
|
/** Las APIs públicas existentes devuelven el conjunto completo de la compañía; no consulta uso global transversal. */
|
|
export function ApplicationResourceUsage({
|
|
companyId,
|
|
resourceId,
|
|
}: {
|
|
companyId: string;
|
|
resourceId: string;
|
|
}) {
|
|
const { t } = useTranslation("companies");
|
|
const [open, setOpen] = useState(false);
|
|
const installations = useQuery({
|
|
queryKey: softwareKeys.company(companyId),
|
|
queryFn: () => softwareApi.get(companyId),
|
|
enabled: open,
|
|
retry: false,
|
|
});
|
|
const configurations = useQuery({
|
|
queryKey: applicationKeys.company(companyId),
|
|
queryFn: () => applicationApi.get(companyId),
|
|
enabled: open,
|
|
retry: false,
|
|
});
|
|
const installed =
|
|
installations.data?.configurations.filter(
|
|
(item) => item.companyId === companyId && item.values.resourceId === resourceId
|
|
) ?? [];
|
|
const configured =
|
|
configurations.data?.configurations.filter(
|
|
(item) => item.companyId === companyId && item.values.resourceId === resourceId
|
|
) ?? [];
|
|
|
|
return (
|
|
<section aria-label={t("resourceUsage.title")} className="flex flex-col gap-3">
|
|
<Button aria-expanded={open} onClick={() => setOpen(!open)} variant="outline">
|
|
{t("resourceUsage.title")}
|
|
</Button>
|
|
{open && (
|
|
<>
|
|
<p className="text-sm text-muted-foreground">{t("resourceUsage.notice")}</p>
|
|
{[
|
|
{
|
|
query: installations,
|
|
label: t("software.title"),
|
|
items: installed.map((item) => ({
|
|
id: item.id,
|
|
href: `/companies/${companyId}/assets/${item.values.assetId}`,
|
|
state: item.values.state,
|
|
version: item.values.version,
|
|
})),
|
|
},
|
|
{
|
|
query: configurations,
|
|
label: t("applications.title"),
|
|
items: configured.map((item) => ({
|
|
id: item.id,
|
|
href: `/companies/${companyId}/work-profiles/${item.values.profileId}/application-configurations`,
|
|
state: item.values.state,
|
|
version: item.values.version,
|
|
})),
|
|
},
|
|
].map((source) => (
|
|
<div key={source.label}>
|
|
<h4 className="font-medium">
|
|
{source.label}: {source.query.isSuccess ? source.items.length : "—"}
|
|
</h4>
|
|
{source.query.isFetching && <p role="status">{t("loading")}</p>}
|
|
{source.query.isError && (
|
|
<div role="alert">
|
|
<p>{t("resourceUsage.error")}</p>
|
|
<Button
|
|
onClick={async () => {
|
|
await source.query.refetch();
|
|
}}
|
|
variant="outline"
|
|
>
|
|
{t("resourceUsage.retry")}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
{source.query.isSuccess && (
|
|
<ul className="max-h-60 overflow-y-auto divide-y">
|
|
{source.items.map((item) => (
|
|
<li className="py-2 text-sm" key={item.id}>
|
|
<BrowserLink href={item.href}>
|
|
{t(`mail.${item.state}`)} · {item.version ?? "—"}
|
|
</BrowserLink>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
))}
|
|
</>
|
|
)}
|
|
</section>
|
|
);
|
|
}
|