diff --git a/deploy/compose/compose.yml b/deploy/compose/compose.yml index 696cc125a7..2f2dc0abe9 100644 --- a/deploy/compose/compose.yml +++ b/deploy/compose/compose.yml @@ -50,7 +50,7 @@ services: - buzz-net postgres: - image: postgres:18-alpine + image: postgres:17-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-buzz} POSTGRES_USER: ${POSTGRES_USER:-buzz} @@ -69,7 +69,7 @@ services: - buzz-net redis: - image: redis:8-alpine + image: redis:7-alpine command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:?set REDIS_PASSWORD}"] environment: REDIS_PASSWORD: ${REDIS_PASSWORD:?set REDIS_PASSWORD} diff --git a/desktop/scripts/check-px-text.mjs b/desktop/scripts/check-px-text.mjs index ea70ca56d5..f0d4fd1f45 100644 --- a/desktop/scripts/check-px-text.mjs +++ b/desktop/scripts/check-px-text.mjs @@ -23,7 +23,7 @@ const rules = [ // glyph is a fixed display size sized to its avatar box (not readable message // text), so it stays as the lone documented `text-[6rem]` literal. const overrides = new Set([ - "src/features/settings/ui/ProfileSettingsCard.tsx:573", + "src/features/settings/ui/ProfileSettingsCard.tsx:572", "src/features/onboarding/ui/AvatarStep.tsx:89", ]); diff --git a/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx b/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx index e01a3e367d..fbf913fe8c 100644 --- a/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx +++ b/desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx @@ -17,6 +17,7 @@ import { rewriteRelayUrl } from "@/shared/lib/mediaUrl"; import { Button } from "@/shared/ui/button"; import { Input } from "@/shared/ui/input"; import { SettingsOptionGroup } from "@/features/settings/ui/SettingsOptionGroup"; +import { SettingsSectionHeader } from "@/features/settings/ui/SettingsSectionHeader"; /** * Custom emoji management (NIP-30, kind:30030). Each member owns their own set: @@ -124,13 +125,15 @@ export function CustomEmojiSettingsCard() { return (
-
-

Custom Emoji

-

- Add your own custom emoji for everyone on this relay to use. Type{" "} - :name: in messages and reactions. -

-
+ + Add your own custom emoji for everyone on this relay to use. Type{" "} + :name: in messages and reactions. + + } + />
-
-

Share compute

-

- Share this machine with your relay. When on, other members can run - their agents here. -

-
+ + Share this machine with your relay. When on, other members can run + their agents here. + + } + /> {error ? (

diff --git a/desktop/src/features/relay-members/ui/RelayMembersSettingsCard.tsx b/desktop/src/features/relay-members/ui/RelayMembersSettingsCard.tsx index 5a6f101cb5..49efc2bdc6 100644 --- a/desktop/src/features/relay-members/ui/RelayMembersSettingsCard.tsx +++ b/desktop/src/features/relay-members/ui/RelayMembersSettingsCard.tsx @@ -36,6 +36,7 @@ import { DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; import { Input } from "@/shared/ui/input"; +import { SettingsSectionHeader } from "@/features/settings/ui/SettingsSectionHeader"; import { VirtualizedList } from "@/shared/ui/VirtualizedList"; type AssignableRelayRole = Exclude; @@ -353,13 +354,15 @@ export function RelayMembersSettingsCard({ return (

-
-

Relay Access

-

- Manage who can connect to this relay. Owners can invite admins or - members; admins can invite members. -

-
+ + Manage who can connect to this relay. Owners can invite admins or + members; admins can invite members. + + } + />
diff --git a/desktop/src/features/settings/UpdateChecker.tsx b/desktop/src/features/settings/UpdateChecker.tsx index 1c43c20977..2deba6ed4a 100644 --- a/desktop/src/features/settings/UpdateChecker.tsx +++ b/desktop/src/features/settings/UpdateChecker.tsx @@ -4,20 +4,17 @@ import { SettingsOptionGroup, SettingsOptionRow, } from "./ui/SettingsOptionGroup"; +import { SettingsSectionHeader } from "./ui/SettingsSectionHeader"; export function UpdateChecker() { const { status, checkForUpdate, relaunch } = useUpdaterContext(); return ( -
-
-

- Software Updates -

-

- Keep Buzz up to date with the latest features and fixes. -

-
+
+ {status.state === "idle" && ( diff --git a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx index de2527bfcc..28611167cc 100644 --- a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx @@ -33,6 +33,7 @@ import type { UpdateChannelTemplateInput, } from "@/shared/api/types"; import { cn } from "@/shared/lib/cn"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; import { AlertDialog, AlertDialogAction, @@ -103,27 +104,26 @@ export function ChannelTemplatesSettingsCard() { return (
-
-
-

- Channel Templates -

-

+ Save reusable channel configurations and apply them when creating new channels. -

-
- -
+ + } + action={ + + } + /> {templatesQuery.isLoading ? (

diff --git a/desktop/src/features/settings/ui/DoctorSettingsPanel.tsx b/desktop/src/features/settings/ui/DoctorSettingsPanel.tsx index d78eab3f97..57e5ff8b82 100644 --- a/desktop/src/features/settings/ui/DoctorSettingsPanel.tsx +++ b/desktop/src/features/settings/ui/DoctorSettingsPanel.tsx @@ -18,6 +18,7 @@ import type { AcpRuntimeCatalogEntry } from "@/shared/api/types"; import { cn } from "@/shared/lib/cn"; import { Button } from "@/shared/ui/button"; import { SettingsOptionGroup } from "./SettingsOptionGroup"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; function StatusIcon({ availability, @@ -268,32 +269,28 @@ export function DoctorSettingsPanel() { } return ( -

-
-
-

Doctor

-

- Verify the ACP runtime commands available to the desktop app. -

-
- - -
+
+ { + setInstallResults({}); + void runtimesQuery.refetch(); + }} + size="sm" + type="button" + variant="outline" + > + + Re-run + + } + />
diff --git a/desktop/src/features/settings/ui/ExperimentalFeaturesCard.tsx b/desktop/src/features/settings/ui/ExperimentalFeaturesCard.tsx index 96ac8dedb6..4684829d32 100644 --- a/desktop/src/features/settings/ui/ExperimentalFeaturesCard.tsx +++ b/desktop/src/features/settings/ui/ExperimentalFeaturesCard.tsx @@ -1,6 +1,7 @@ import { desktopFeatures, useFeatureToggle } from "@/shared/features"; import type { FeatureDefinition } from "@/shared/features"; import { Switch } from "@/shared/ui/switch"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; function FeatureRow({ feature }: { feature: FeatureDefinition }) { const [enabled, toggle] = useFeatureToggle(feature.id); @@ -31,13 +32,15 @@ export function ExperimentalFeaturesCard() { return (
-
-

Experiments

-

- These features are functional but still being refined. Enable them to - try new capabilities early. -

-
+ + These features are functional but still being refined. Enable them + to try new capabilities early. + + } + />
{previewFeatures.map((f) => ( diff --git a/desktop/src/features/settings/ui/KeyboardShortcutsCard.tsx b/desktop/src/features/settings/ui/KeyboardShortcutsCard.tsx index 2e84f32a0b..4cf1276c26 100644 --- a/desktop/src/features/settings/ui/KeyboardShortcutsCard.tsx +++ b/desktop/src/features/settings/ui/KeyboardShortcutsCard.tsx @@ -4,6 +4,7 @@ import { type KeyboardShortcut, } from "@/shared/lib/keyboard-shortcuts"; import { SettingsOptionGroup, SettingsOptionRow } from "./SettingsOptionGroup"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; function KeyCombo({ shortcut }: { shortcut: KeyboardShortcut }) { const keys = getPlatformKeys(shortcut); @@ -32,14 +33,10 @@ export function KeyboardShortcutsCard() { return (
-
-

- Keyboard Shortcuts -

-

- All available keyboard shortcuts. Shortcuts are read-only. -

-
+
{[...categories.entries()].map(([category, shortcuts]) => ( diff --git a/desktop/src/features/settings/ui/MobilePairingCard.tsx b/desktop/src/features/settings/ui/MobilePairingCard.tsx index 6ae0850e33..fab4aa1589 100644 --- a/desktop/src/features/settings/ui/MobilePairingCard.tsx +++ b/desktop/src/features/settings/ui/MobilePairingCard.tsx @@ -27,6 +27,7 @@ import { DialogTitle, } from "@/shared/ui/dialog"; import { SettingsOptionGroup, SettingsOptionRow } from "./SettingsOptionGroup"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; type PairingStep = | "generating" @@ -321,14 +322,16 @@ export function MobilePairingCard({ return (
-
-

Mobile

-

- Connect the Buzz mobile app to this relay by scanning a QR code. The - connection is secured with end-to-end encryption and a verification - code. -

-
+ + Connect the Buzz mobile app to this relay by scanning a QR code. The + connection is secured with end-to-end encryption and a verification + code. + + } + /> diff --git a/desktop/src/features/settings/ui/NotificationSettingsCard.tsx b/desktop/src/features/settings/ui/NotificationSettingsCard.tsx index 72bb08326f..f2bbff3081 100644 --- a/desktop/src/features/settings/ui/NotificationSettingsCard.tsx +++ b/desktop/src/features/settings/ui/NotificationSettingsCard.tsx @@ -18,6 +18,7 @@ import { cn } from "@/shared/lib/cn"; import { Button } from "@/shared/ui/button"; import { Switch } from "@/shared/ui/switch"; import { SettingsOptionGroup, SettingsOptionRow } from "./SettingsOptionGroup"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; import { SoundPicker } from "./SoundPicker"; export function NotificationSettingsCard({ @@ -60,12 +61,10 @@ export function NotificationSettingsCard({ return (
-
-

Notifications

-

- Desktop alerts are on by default. Fine-tune what gets through below. -

-
+ {notificationPermission === "unsupported" diff --git a/desktop/src/features/settings/ui/PreventSleepSettingsCard.tsx b/desktop/src/features/settings/ui/PreventSleepSettingsCard.tsx index c502efd533..52c48f3841 100644 --- a/desktop/src/features/settings/ui/PreventSleepSettingsCard.tsx +++ b/desktop/src/features/settings/ui/PreventSleepSettingsCard.tsx @@ -1,6 +1,7 @@ import { usePreventSleepContext } from "@/features/agents/usePreventSleep"; import { Switch } from "@/shared/ui/switch"; import { SettingsOptionGroup, SettingsOptionRow } from "./SettingsOptionGroup"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; export function PreventSleepSettingsCard() { const { enabled, setEnabled, hasRunningAgents, expired, clearExpired } = @@ -8,12 +9,10 @@ export function PreventSleepSettingsCard() { return (
-
-

Agents

-

- Settings that affect how local managed agents run on this machine. -

-
+ diff --git a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx index c7c81476b4..147cfd7939 100644 --- a/desktop/src/features/settings/ui/ProfileSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ProfileSettingsCard.tsx @@ -21,6 +21,7 @@ import { cn } from "@/shared/lib/cn"; import { Input } from "@/shared/ui/input"; import { Spinner } from "@/shared/ui/spinner"; import { Textarea } from "@/shared/ui/textarea"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; type ProfileSettingsCardProps = { currentPubkey?: string; @@ -458,12 +459,10 @@ export function ProfileSettingsCard({ return (
-
-

Profile

-

- Update how your name, avatar, and bio appear across Buzz. -

-
+
{profileQuery.error instanceof Error ? ( diff --git a/desktop/src/features/settings/ui/SettingsPanels.tsx b/desktop/src/features/settings/ui/SettingsPanels.tsx index 78db770c33..c3055c30fc 100644 --- a/desktop/src/features/settings/ui/SettingsPanels.tsx +++ b/desktop/src/features/settings/ui/SettingsPanels.tsx @@ -43,6 +43,7 @@ import { NotificationSettingsCard } from "./NotificationSettingsCard"; import { PreventSleepSettingsCard } from "./PreventSleepSettingsCard"; import { ProfileSettingsCard } from "./ProfileSettingsCard"; import { UpdateChecker } from "../UpdateChecker"; +import { SettingsSectionHeader } from "./SettingsSectionHeader"; export type SettingsSection = | "profile" @@ -206,12 +207,10 @@ function ThemeSettingsCard() { return (
-
-

Appearance

-

- Choose a theme for Buzz. Light and dark mode is auto-detected. -

-
+
diff --git a/desktop/src/features/settings/ui/SettingsSectionHeader.tsx b/desktop/src/features/settings/ui/SettingsSectionHeader.tsx new file mode 100644 index 0000000000..c22a526cd8 --- /dev/null +++ b/desktop/src/features/settings/ui/SettingsSectionHeader.tsx @@ -0,0 +1,31 @@ +import type { ReactNode } from "react"; + +export function SettingsSectionHeader({ + action, + description, + title, +}: { + action?: ReactNode; + description: ReactNode; + title: ReactNode; +}) { + const copy = ( + <> +

{title}

+

+ {description} +

+ + ); + + if (action) { + return ( +
+
{copy}
+
{action}
+
+ ); + } + + return
{copy}
; +} diff --git a/desktop/tests/e2e/onboarding.spec.ts b/desktop/tests/e2e/onboarding.spec.ts index 2beff2786f..4f10b076f8 100644 --- a/desktop/tests/e2e/onboarding.spec.ts +++ b/desktop/tests/e2e/onboarding.spec.ts @@ -294,7 +294,6 @@ async function expectWelcomeComposerBannerCompletesAfterPersonaMention( await expect(banner).toContainText("Nice work."); await expect(banner).not.toContainText("Try mentioning"); await expect(channelIntro).toBeVisible(); - await expect(banner).toHaveCount(0, { timeout: 12_000 }); } async function getMockChannels(page: Page) { diff --git a/docker-compose.yml b/docker-compose.yml index c22ac2ad3a..19ff5c3877 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ name: buzz services: postgres: - image: postgres:18-alpine + image: postgres:17-alpine container_name: buzz-postgres environment: POSTGRES_USER: buzz @@ -31,7 +31,7 @@ services: restart: unless-stopped redis: - image: redis:8-alpine + image: redis:7-alpine container_name: buzz-redis ports: - "6379:6379"