From 0350bfd2eaa212fbc8aa7d5e4f885776c968c8eb Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 17 Aug 2026 17:19:37 +1000 Subject: [PATCH] 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. --- .../ObservabilitySettingsPage.tsx | 6 +- .../ObservabilitySettingsPageView.stories.tsx | 64 +++++++++++++------ .../ObservabilitySettingsPageView.tsx | 40 ++++-------- 3 files changed, 59 insertions(+), 51 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx index 43a0985954..a538c22480 100644 --- a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPage.tsx @@ -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 = () => { ); diff --git a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.stories.tsx index 63de6b6355..1c397954c8 100644 --- a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.stories.tsx @@ -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 = { 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 = { 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; 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(); }, }; diff --git a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.tsx index 8b7aeadcbe..7667e09cdf 100644 --- a/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/ObservabilitySettingsPage/ObservabilitySettingsPageView.tsx @@ -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 (
@@ -40,30 +38,16 @@ export const ObservabilitySettingsPageView: FC< - {featureAuditLogEnabled || isPremium ? ( - {} + {featureAuditLogEnabled ? ( + o.name === "Audit Logs Retention")} + /> ) : ( - <> - - Audit logging lets auditors monitor user operations across your - deployment. It requires a Premium license.{" "} - - Read the Audit Logs documentation - - . - -
- - + )}