refactor(ui): render the no-providers scan hint as a compact banner

- Add a "hint" variant to NoProvidersAdded (horizontal banner) so the
  Scans-page no-providers hint matches the not-connected hint
- Providers page keeps the default full-page "page" variant
This commit is contained in:
Pablo F.G
2026-07-16 16:02:04 +02:00
parent 375a8a5c55
commit 6b2bb712c1
3 changed files with 55 additions and 18 deletions
+53 -6
View File
@@ -11,10 +11,21 @@ const NO_PROVIDERS_ADDED_ACTION = {
LINK: "link",
} as const;
// "page" is the full-screen empty state (Providers page); "hint" is a compact
// horizontal banner that sits above other content (Scans page).
const NO_PROVIDERS_ADDED_VARIANT = {
PAGE: "page",
HINT: "hint",
} as const;
type NoProvidersAddedVariant =
(typeof NO_PROVIDERS_ADDED_VARIANT)[keyof typeof NO_PROVIDERS_ADDED_VARIANT];
interface NoProvidersAddedBaseProps {
containerClassName?: string;
// Tour anchor for the CTA; needed because this empty state replaces the table's AddProviderButton.
ctaTourId?: string;
variant?: NoProvidersAddedVariant;
}
interface NoProvidersAddedButtonProps extends NoProvidersAddedBaseProps {
@@ -33,14 +44,23 @@ type NoProvidersAddedProps =
| NoProvidersAddedButtonProps
| NoProvidersAddedLinkProps;
const renderCta = (props: NoProvidersAddedProps) => {
const renderCta = (
props: NoProvidersAddedProps,
variant: NoProvidersAddedVariant,
) => {
const isHint = variant === NO_PROVIDERS_ADDED_VARIANT.HINT;
const className = isHint
? "w-full justify-center md:w-fit"
: "w-full max-w-xs justify-center";
const size = isHint ? undefined : "lg";
if (props.action === NO_PROVIDERS_ADDED_ACTION.LINK) {
return (
<Button
asChild
aria-label="Open Add Provider modal"
className="w-full max-w-xs justify-center"
size="lg"
className={className}
size={size}
>
<Link href={props.href}>Add a Provider</Link>
</Button>
@@ -50,9 +70,9 @@ const renderCta = (props: NoProvidersAddedProps) => {
return (
<Button
aria-label="Open Add Provider modal"
className="w-full max-w-xs justify-center"
className={className}
data-tour-id={props.ctaTourId}
size="lg"
size={size}
onClick={props.onOpenWizard}
>
Add a Provider
@@ -61,6 +81,33 @@ const renderCta = (props: NoProvidersAddedProps) => {
};
export const NoProvidersAdded = (props: NoProvidersAddedProps) => {
const variant = props.variant ?? NO_PROVIDERS_ADDED_VARIANT.PAGE;
// Compact horizontal hint, matching NoProvidersConnected so both provider
// hints on the Scans page share one composition.
if (variant === NO_PROVIDERS_ADDED_VARIANT.HINT) {
return (
<Card variant="base">
<CardContent className="flex w-full flex-col items-start gap-6 md:flex-row md:items-center md:justify-between md:gap-8">
<div className="flex flex-col gap-3">
<div className="flex items-center justify-start gap-3">
<InfoIcon className="h-6 w-6 text-gray-800 dark:text-white" />
<h2 className="text-lg font-bold text-gray-800 dark:text-white">
No Providers Configured
</h2>
</div>
<p className="text-sm text-gray-600 dark:text-gray-300">
No providers have been configured. Start by setting up a provider.
</p>
</div>
<div className="w-full md:w-auto md:shrink-0">
{renderCta(props, variant)}
</div>
</CardContent>
</Card>
);
}
return (
<div
role="region"
@@ -87,7 +134,7 @@ export const NoProvidersAdded = (props: NoProvidersAddedProps) => {
</p>
</div>
{renderCta(props)}
{renderCta(props, variant)}
</CardContent>
</Card>
</div>
+1 -4
View File
@@ -119,10 +119,7 @@ export function ScansPageShell({
{/* Signals the navbar that this route's data has loaded (enables the replay icon). */}
<PageReady />
{showProvidersHint && (
<ScansProvidersEmptyState
thereIsNoProviders={thereAreNoProviders}
containerClassName="min-h-0"
/>
<ScansProvidersEmptyState thereIsNoProviders={thereAreNoProviders} />
)}
<div
role="group"
@@ -5,20 +5,13 @@ import { NoProvidersConnected } from "./no-providers-connected";
interface ScansProvidersEmptyStateProps {
thereIsNoProviders: boolean;
/** Overrides the NoProvidersAdded container height so it can sit as a compact top hint. */
containerClassName?: string;
}
export function ScansProvidersEmptyState({
thereIsNoProviders,
containerClassName,
}: ScansProvidersEmptyStateProps) {
return thereIsNoProviders ? (
<NoProvidersAdded
action="link"
href={ADD_PROVIDER_HREF}
containerClassName={containerClassName}
/>
<NoProvidersAdded action="link" href={ADD_PROVIDER_HREF} variant="hint" />
) : (
<NoProvidersConnected />
);