refactor(site): show audit log retention and Premium paywall on observability settings (#27947)

The Audit Logging section on deployment observability settings only
showed a badge or an info alert, with no actual setting underneath.

When audit logging is entitled, show the Audit Logs Retention option.
When it is not, show the shared Premium paywall instead of the inline
alert.
This commit is contained in:
Jake Howell
2026-08-17 07:19:37 +00:00
committed by GitHub
parent 41d2ecec0b
commit 0350bfd2ea
3 changed files with 59 additions and 51 deletions
@@ -1,6 +1,6 @@
import type { FC } from "react";
import { useAuthenticated } from "#/hooks/useAuthenticated";
import { useDashboard } from "#/modules/dashboard/useDashboard";
import { useFeatureVisibility } from "#/modules/dashboard/useFeatureVisibility";
import { useDeploymentConfig } from "#/modules/management/DeploymentConfigProvider";
import { pageTitle } from "#/utils/page";
import { ObservabilitySettingsPageView } from "./ObservabilitySettingsPageView";
@@ -8,7 +8,7 @@ import { ObservabilitySettingsPageView } from "./ObservabilitySettingsPageView";
const ObservabilitySettingsPage: FC = () => {
const { deploymentConfig } = useDeploymentConfig();
const { entitlements } = useDashboard();
const { multiple_organizations: hasPremiumLicense } = useFeatureVisibility();
const { permissions } = useAuthenticated();
return (
<>
@@ -17,7 +17,7 @@ const ObservabilitySettingsPage: FC = () => {
<ObservabilitySettingsPageView
options={deploymentConfig.options}
featureAuditLogEnabled={entitlements.features.audit_log.enabled}
isPremium={hasPremiumLicense}
canViewPremium={permissions.viewAllLicenses}
/>
</>
);
@@ -1,22 +1,39 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, within } from "storybook/test";
import type { SerpentGroup } from "#/api/typesGenerated";
import { MockPermissions } from "#/testHelpers/entities";
import { ObservabilitySettingsPageView } from "./ObservabilitySettingsPageView";
const group: SerpentGroup = {
const introspectionGroup: SerpentGroup = {
name: "Introspection",
description: "",
};
const retentionGroup: SerpentGroup = {
name: "Retention",
description: "",
};
const meta: Meta<typeof ObservabilitySettingsPageView> = {
title: "pages/DeploymentSettingsPage/ObservabilitySettingsPageView",
component: ObservabilitySettingsPageView,
args: {
options: [
{
name: "Audit Logs Retention",
description:
"How long audit log entries are retained. Set to 0 to disable (keep indefinitely).",
value: 0,
group: retentionGroup,
flag: "audit-logs-retention",
env: "CODER_AUDIT_LOGS_RETENTION",
yaml: "audit_logs",
hidden: false,
},
{
name: "Verbose",
value: true,
group,
group: introspectionGroup,
flag: "verbose",
flag_shorthand: "v",
hidden: false,
@@ -40,13 +57,13 @@ const meta: Meta<typeof ObservabilitySettingsPageView> = {
description:
"Serve prometheus metrics on the address defined by prometheus address.",
value: true,
group: { ...group },
group: { ...introspectionGroup },
flag: "prometheus-enable",
hidden: false,
},
],
featureAuditLogEnabled: true,
isPremium: false,
canViewPremium: MockPermissions.viewAllLicenses,
},
};
@@ -56,38 +73,45 @@ type Story = StoryObj<typeof ObservabilitySettingsPageView>;
export const Page: Story = {};
export const OSS: Story = {
args: { featureAuditLogEnabled: false, isPremium: false },
args: { featureAuditLogEnabled: false },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const alert = canvas.getByRole("alert");
await expect(alert).toBeVisible();
await expect(within(alert).getByText("Premium")).toBeVisible();
await expect(canvas.getByText("Audit Logging")).toBeVisible();
await expect(
within(alert).getByRole("link", {
name: "Read the Audit Logs documentation",
}),
canvas.getByRole("link", { name: "Start trial for free" }),
).toHaveAttribute("href", "/deployment/premium");
await expect(
canvas.getByRole("link", { name: "Learn more about premium" }),
).toBeVisible();
await expect(canvas.queryByText("Enterprise")).not.toBeInTheDocument();
await expect(
canvas.queryByText("Audit Logs Retention"),
).not.toBeInTheDocument();
},
};
export const Premium: Story = {
args: { featureAuditLogEnabled: true, isPremium: true },
export const OSSWithoutLicenseAccess: Story = {
args: { featureAuditLogEnabled: false, canViewPremium: false },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.queryByRole("alert")).not.toBeInTheDocument();
await expect(canvas.getByText("Premium")).toBeVisible();
await expect(
canvas.getByText(/contact your deployment administrator/i),
).toBeVisible();
await expect(
canvas.queryByRole("link", { name: "Start trial for free" }),
).not.toBeInTheDocument();
},
};
export const EnterpriseAuditLogs: Story = {
args: { featureAuditLogEnabled: true, isPremium: false },
export const Entitled: Story = {
args: { featureAuditLogEnabled: true },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.queryByRole("alert")).not.toBeInTheDocument();
await expect(canvas.getByText("Enterprise")).toBeVisible();
await expect(
canvas.queryByRole("link", { name: "Start trial for free" }),
).not.toBeInTheDocument();
await expect(canvas.getByText("Audit Logs Retention")).toBeVisible();
},
};
@@ -1,8 +1,6 @@
import type { FC } from "react";
import type { SerpentOption } from "#/api/typesGenerated";
import { Alert } from "#/components/Alert/Alert";
import { Badges, PremiumBadge } from "#/components/Badges/Badges";
import { PaywallSmall } from "#/components/Paywall/PaywallSmall";
import { PaywallPremium } from "#/components/Paywall/PaywallPremium";
import {
SettingsHeader,
SettingsHeaderDescription,
@@ -16,12 +14,12 @@ import OptionsTable from "../OptionsTable";
type ObservabilitySettingsPageViewProps = {
options: SerpentOption[];
featureAuditLogEnabled: boolean;
isPremium: boolean;
canViewPremium: boolean;
};
export const ObservabilitySettingsPageView: FC<
ObservabilitySettingsPageViewProps
> = ({ options, featureAuditLogEnabled, isPremium }) => {
> = ({ options, featureAuditLogEnabled, canViewPremium }) => {
return (
<div className="flex flex-col gap-12">
<div>
@@ -40,30 +38,16 @@ export const ObservabilitySettingsPageView: FC<
</SettingsHeaderDescription>
</SettingsHeader>
{featureAuditLogEnabled || isPremium ? (
<Badges>{<PremiumBadge />}</Badges>
{featureAuditLogEnabled ? (
<OptionsTable
options={options.filter((o) => o.name === "Audit Logs Retention")}
/>
) : (
<>
<Alert severity="info">
Audit logging lets auditors monitor user operations across your
deployment. It requires a Premium license.{" "}
<a
href={docs("/admin/security/audit-logs")}
target="_blank"
rel="noreferrer"
className="text-content-link font-medium"
>
Read the Audit Logs documentation
</a>
.
</Alert>
<br />
<PaywallSmall
message="Audit Logs"
canViewPremium
description="A Premium license is required for access to Audit Log monitoring."
/>
</>
<PaywallPremium
message="Audit Logging"
description="Audit logging lets auditors monitor user operations across your deployment. You need a Premium license to use this feature."
canViewPremium={canViewPremium}
/>
)}
</div>