Files
govoplan-core/webui/src/components/WizardDirectory.tsx
T

68 lines
2.0 KiB
TypeScript

import { Link } from "react-router";
import type { AuthInfo, WizardDirectoryEntry } from "../types";
import { usePlatformLanguage } from "../i18n/LanguageContext";
import { hasAnyScope, hasScope } from "../utils/permissions";
import Card from "./Card";
export type WizardDirectoryProps = {
entries: WizardDirectoryEntry[];
auth: AuthInfo;
emptyText?: string;
};
function canOpenWizard(auth: AuthInfo, entry: WizardDirectoryEntry): boolean {
if (entry.available === false) return false;
if (entry.allOf?.some((scope) => !hasScope(auth, scope))) return false;
if (entry.anyOf?.length && !hasAnyScope(auth, entry.anyOf)) return false;
return true;
}
export default function WizardDirectory({
entries,
auth,
emptyText = "No guided workflows are available."
}: WizardDirectoryProps) {
const { translateText } = usePlatformLanguage();
const visibleEntries = entries.filter(
(entry) =>
!entry.anyOf?.length
|| hasAnyScope(auth, entry.anyOf)
|| entry.available === false
);
if (!visibleEntries.length) {
return <p className="muted">{translateText(emptyText)}</p>;
}
return (
<div className="wizard-directory-grid">
{visibleEntries.map((entry) => {
const available = canOpenWizard(auth, entry);
return (
<Card
key={`${entry.moduleId}:${entry.id}`}
title={entry.label}
actions={
available
? (
<Link className="btn btn-primary" to={entry.to}>
{translateText(entry.actionLabel ?? "Open")}
</Link>
)
: null
}
>
{entry.description && <p>{translateText(entry.description)}</p>}
{!available && entry.unavailableReason && (
<p className="muted small-note">
{translateText(entry.unavailableReason)}
</p>
)}
</Card>
);
})}
</div>
);
}