diff --git a/coderd/inboxnotifications.go b/coderd/inboxnotifications.go index df6ebe9d25aaf..6da047241d790 100644 --- a/coderd/inboxnotifications.go +++ b/coderd/inboxnotifications.go @@ -31,30 +31,30 @@ const ( var fallbackIcons = map[uuid.UUID]string{ // workspace related notifications - notifications.TemplateWorkspaceCreated: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceManuallyUpdated: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceDeleted: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceAutobuildFailed: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceDormant: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceAutoUpdated: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceMarkedForDeletion: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceManualBuildFailed: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceOutOfMemory: codersdk.FallbackIconWorkspace, - notifications.TemplateWorkspaceOutOfDisk: codersdk.FallbackIconWorkspace, + notifications.TemplateWorkspaceCreated: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceManuallyUpdated: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceDeleted: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceAutobuildFailed: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceDormant: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceAutoUpdated: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceMarkedForDeletion: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceManualBuildFailed: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceOutOfMemory: codersdk.InboxNotificationFallbackIconWorkspace, + notifications.TemplateWorkspaceOutOfDisk: codersdk.InboxNotificationFallbackIconWorkspace, // account related notifications - notifications.TemplateUserAccountCreated: codersdk.FallbackIconAccount, - notifications.TemplateUserAccountDeleted: codersdk.FallbackIconAccount, - notifications.TemplateUserAccountSuspended: codersdk.FallbackIconAccount, - notifications.TemplateUserAccountActivated: codersdk.FallbackIconAccount, - notifications.TemplateYourAccountSuspended: codersdk.FallbackIconAccount, - notifications.TemplateYourAccountActivated: codersdk.FallbackIconAccount, - notifications.TemplateUserRequestedOneTimePasscode: codersdk.FallbackIconAccount, + notifications.TemplateUserAccountCreated: codersdk.InboxNotificationFallbackIconAccount, + notifications.TemplateUserAccountDeleted: codersdk.InboxNotificationFallbackIconAccount, + notifications.TemplateUserAccountSuspended: codersdk.InboxNotificationFallbackIconAccount, + notifications.TemplateUserAccountActivated: codersdk.InboxNotificationFallbackIconAccount, + notifications.TemplateYourAccountSuspended: codersdk.InboxNotificationFallbackIconAccount, + notifications.TemplateYourAccountActivated: codersdk.InboxNotificationFallbackIconAccount, + notifications.TemplateUserRequestedOneTimePasscode: codersdk.InboxNotificationFallbackIconAccount, // template related notifications - notifications.TemplateTemplateDeleted: codersdk.FallbackIconTemplate, - notifications.TemplateTemplateDeprecated: codersdk.FallbackIconTemplate, - notifications.TemplateWorkspaceBuildsFailedReport: codersdk.FallbackIconTemplate, + notifications.TemplateTemplateDeleted: codersdk.InboxNotificationFallbackIconTemplate, + notifications.TemplateTemplateDeprecated: codersdk.InboxNotificationFallbackIconTemplate, + notifications.TemplateWorkspaceBuildsFailedReport: codersdk.InboxNotificationFallbackIconTemplate, } func ensureNotificationIcon(notif codersdk.InboxNotification) codersdk.InboxNotification { @@ -64,7 +64,7 @@ func ensureNotificationIcon(notif codersdk.InboxNotification) codersdk.InboxNoti fallbackIcon, ok := fallbackIcons[notif.TemplateID] if !ok { - fallbackIcon = codersdk.FallbackIconOther + fallbackIcon = codersdk.InboxNotificationFallbackIconOther } notif.Icon = fallbackIcon diff --git a/coderd/inboxnotifications_internal_test.go b/coderd/inboxnotifications_internal_test.go index 6dd36fcffe145..e7d9a85d3e74f 100644 --- a/coderd/inboxnotifications_internal_test.go +++ b/coderd/inboxnotifications_internal_test.go @@ -20,12 +20,12 @@ func TestInboxNotifications_ensureNotificationIcon(t *testing.T) { templateID uuid.UUID expectedIcon string }{ - {"WorkspaceCreated", "", notifications.TemplateWorkspaceCreated, codersdk.FallbackIconWorkspace}, - {"UserAccountCreated", "", notifications.TemplateUserAccountCreated, codersdk.FallbackIconAccount}, - {"TemplateDeleted", "", notifications.TemplateTemplateDeleted, codersdk.FallbackIconTemplate}, - {"TestNotification", "", notifications.TemplateTestNotification, codersdk.FallbackIconOther}, + {"WorkspaceCreated", "", notifications.TemplateWorkspaceCreated, codersdk.InboxNotificationFallbackIconWorkspace}, + {"UserAccountCreated", "", notifications.TemplateUserAccountCreated, codersdk.InboxNotificationFallbackIconAccount}, + {"TemplateDeleted", "", notifications.TemplateTemplateDeleted, codersdk.InboxNotificationFallbackIconTemplate}, + {"TestNotification", "", notifications.TemplateTestNotification, codersdk.InboxNotificationFallbackIconOther}, {"TestExistingIcon", "https://cdn.coder.com/icon_notif.png", notifications.TemplateTemplateDeleted, "https://cdn.coder.com/icon_notif.png"}, - {"UnknownTemplate", "", uuid.New(), codersdk.FallbackIconOther}, + {"UnknownTemplate", "", uuid.New(), codersdk.InboxNotificationFallbackIconOther}, } for _, tt := range tests { diff --git a/coderd/inboxnotifications_test.go b/coderd/inboxnotifications_test.go index d9ee0ee936a94..82ae539518ae0 100644 --- a/coderd/inboxnotifications_test.go +++ b/coderd/inboxnotifications_test.go @@ -137,7 +137,7 @@ func TestInboxNotification_Watch(t *testing.T) { require.Equal(t, memberClient.ID, notif.Notification.UserID) // check for the fallback icon logic - require.Equal(t, codersdk.FallbackIconWorkspace, notif.Notification.Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconWorkspace, notif.Notification.Icon) }) t.Run("OK - change format", func(t *testing.T) { @@ -557,11 +557,11 @@ func TestInboxNotifications_List(t *testing.T) { require.Len(t, notifs.Notifications, 10) require.Equal(t, "https://dev.coder.com/icon.png", notifs.Notifications[0].Icon) - require.Equal(t, codersdk.FallbackIconWorkspace, notifs.Notifications[9].Icon) - require.Equal(t, codersdk.FallbackIconWorkspace, notifs.Notifications[8].Icon) - require.Equal(t, codersdk.FallbackIconAccount, notifs.Notifications[7].Icon) - require.Equal(t, codersdk.FallbackIconTemplate, notifs.Notifications[6].Icon) - require.Equal(t, codersdk.FallbackIconOther, notifs.Notifications[4].Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconWorkspace, notifs.Notifications[9].Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconWorkspace, notifs.Notifications[8].Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconAccount, notifs.Notifications[7].Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconTemplate, notifs.Notifications[6].Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconOther, notifs.Notifications[4].Icon) }) t.Run("OK with template filter", func(t *testing.T) { @@ -607,7 +607,7 @@ func TestInboxNotifications_List(t *testing.T) { require.Len(t, notifs.Notifications, 5) require.Equal(t, "Notification 8", notifs.Notifications[0].Title) - require.Equal(t, codersdk.FallbackIconWorkspace, notifs.Notifications[0].Icon) + require.Equal(t, codersdk.InboxNotificationFallbackIconWorkspace, notifs.Notifications[0].Icon) }) t.Run("OK with target filter", func(t *testing.T) { diff --git a/codersdk/inboxnotification.go b/codersdk/inboxnotification.go index ba68351c39bfe..1501f701f4272 100644 --- a/codersdk/inboxnotification.go +++ b/codersdk/inboxnotification.go @@ -11,10 +11,10 @@ import ( ) const ( - FallbackIconWorkspace = "DEFAULT_ICON_WORKSPACE" - FallbackIconAccount = "DEFAULT_ICON_ACCOUNT" - FallbackIconTemplate = "DEFAULT_ICON_TEMPLATE" - FallbackIconOther = "DEFAULT_ICON_OTHER" + InboxNotificationFallbackIconWorkspace = "DEFAULT_ICON_WORKSPACE" + InboxNotificationFallbackIconAccount = "DEFAULT_ICON_ACCOUNT" + InboxNotificationFallbackIconTemplate = "DEFAULT_ICON_TEMPLATE" + InboxNotificationFallbackIconOther = "DEFAULT_ICON_OTHER" ) type InboxNotification struct { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 602fb582f07c9..b812bcb46bc03 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -839,18 +839,6 @@ export interface ExternalAuthUser { readonly name: string; } -// From codersdk/inboxnotification.go -export const FallbackIconAccount = "DEFAULT_ICON_ACCOUNT"; - -// From codersdk/inboxnotification.go -export const FallbackIconOther = "DEFAULT_ICON_OTHER"; - -// From codersdk/inboxnotification.go -export const FallbackIconTemplate = "DEFAULT_ICON_TEMPLATE"; - -// From codersdk/inboxnotification.go -export const FallbackIconWorkspace = "DEFAULT_ICON_WORKSPACE"; - // From codersdk/deployment.go export interface Feature { readonly entitlement: Entitlement; @@ -1124,6 +1112,18 @@ export interface InboxNotificationAction { readonly url: string; } +// From codersdk/inboxnotification.go +export const InboxNotificationFallbackIconAccount = "DEFAULT_ICON_ACCOUNT"; + +// From codersdk/inboxnotification.go +export const InboxNotificationFallbackIconOther = "DEFAULT_ICON_OTHER"; + +// From codersdk/inboxnotification.go +export const InboxNotificationFallbackIconTemplate = "DEFAULT_ICON_TEMPLATE"; + +// From codersdk/inboxnotification.go +export const InboxNotificationFallbackIconWorkspace = "DEFAULT_ICON_WORKSPACE"; + // From codersdk/insights.go export type InsightsReportInterval = "day" | "week"; diff --git a/site/src/components/Avatar/Avatar.tsx b/site/src/components/Avatar/Avatar.tsx index f5492158b4aad..46316950c80b6 100644 --- a/site/src/components/Avatar/Avatar.tsx +++ b/site/src/components/Avatar/Avatar.tsx @@ -28,7 +28,7 @@ const avatarVariants = cva( }, variant: { default: null, - icon: null, + icon: "[&_svg]:size-full", }, }, defaultVariants: { diff --git a/site/src/modules/notifications/NotificationsInbox/InboxAvatar.stories.tsx b/site/src/modules/notifications/NotificationsInbox/InboxAvatar.stories.tsx new file mode 100644 index 0000000000000..85199a335d662 --- /dev/null +++ b/site/src/modules/notifications/NotificationsInbox/InboxAvatar.stories.tsx @@ -0,0 +1,46 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { InboxAvatar } from "./InboxAvatar"; + +const meta: Meta = { + title: "modules/notifications/NotificationsInbox/InboxAvatar", + component: InboxAvatar, +}; + +export default meta; +type Story = StoryObj; + +export const Custom: Story = { + args: { + icon: "/icon/git.svg", + }, +}; + +export const EmptyIcon: Story = { + args: { + icon: "", + }, +}; + +export const FallbackWorkspace: Story = { + args: { + icon: "DEFAULT_ICON_WORKSPACE", + }, +}; + +export const FallbackAccount: Story = { + args: { + icon: "DEFAULT_ICON_ACCOUNT", + }, +}; + +export const FallbackTemplate: Story = { + args: { + icon: "DEFAULT_ICON_TEMPLATE", + }, +}; + +export const FallbackOther: Story = { + args: { + icon: "DEFAULT_ICON_OTHER", + }, +}; diff --git a/site/src/modules/notifications/NotificationsInbox/InboxAvatar.tsx b/site/src/modules/notifications/NotificationsInbox/InboxAvatar.tsx new file mode 100644 index 0000000000000..9be8e2b9f74ad --- /dev/null +++ b/site/src/modules/notifications/NotificationsInbox/InboxAvatar.tsx @@ -0,0 +1,54 @@ +import { + InboxNotificationFallbackIconAccount, + InboxNotificationFallbackIconOther, + InboxNotificationFallbackIconTemplate, + InboxNotificationFallbackIconWorkspace, +} from "api/typesGenerated"; +import { Avatar } from "components/Avatar/Avatar"; +import { + InfoIcon, + LaptopIcon, + LayoutTemplateIcon, + UserIcon, +} from "lucide-react"; +import type { FC } from "react"; +import type React from "react"; + +const InboxNotificationFallbackIcons = [ + InboxNotificationFallbackIconAccount, + InboxNotificationFallbackIconWorkspace, + InboxNotificationFallbackIconTemplate, + InboxNotificationFallbackIconOther, +] as const; + +type InboxNotificationFallbackIcon = + (typeof InboxNotificationFallbackIcons)[number]; + +const fallbackIcons: Record = { + DEFAULT_ICON_WORKSPACE: , + DEFAULT_ICON_ACCOUNT: , + DEFAULT_ICON_TEMPLATE: , + DEFAULT_ICON_OTHER: , +}; + +type InboxAvatarProps = { + icon: string; +}; + +export const InboxAvatar: FC = ({ icon }) => { + if (icon === "") { + return {fallbackIcons.DEFAULT_ICON_OTHER}; + } + + if (isInboxNotificationFallbackIcon(icon)) { + return {fallbackIcons[icon]}; + } + + return ; +}; + +function isInboxNotificationFallbackIcon( + icon: string, +): icon is InboxNotificationFallbackIcon { + return (InboxNotificationFallbackIcons as readonly string[]).includes(icon); +} diff --git a/site/src/modules/notifications/NotificationsInbox/InboxItem.stories.tsx b/site/src/modules/notifications/NotificationsInbox/InboxItem.stories.tsx index 681fd0ca71d32..c9ed8bb632e03 100644 --- a/site/src/modules/notifications/NotificationsInbox/InboxItem.stories.tsx +++ b/site/src/modules/notifications/NotificationsInbox/InboxItem.stories.tsx @@ -61,6 +61,7 @@ export const Markdown: Story = { url: "https://dev.coder.com/workspaces?filter=template%3Acoder-with-ai", }, ], + icon: "DEFAULT_ICON_TEMPLATE", }, }, }; diff --git a/site/src/modules/notifications/NotificationsInbox/InboxItem.tsx b/site/src/modules/notifications/NotificationsInbox/InboxItem.tsx index 3b8471f84a94d..e1817bf3b99ce 100644 --- a/site/src/modules/notifications/NotificationsInbox/InboxItem.tsx +++ b/site/src/modules/notifications/NotificationsInbox/InboxItem.tsx @@ -1,13 +1,12 @@ import type { InboxNotification } from "api/typesGenerated"; -import { Avatar } from "components/Avatar/Avatar"; import { Button } from "components/Button/Button"; import { Link } from "components/Link/Link"; import { SquareCheckBig } from "lucide-react"; import type { FC } from "react"; import Markdown from "react-markdown"; import { Link as RouterLink } from "react-router-dom"; -import { cn } from "utils/cn"; import { relativeTime } from "utils/time"; +import { InboxAvatar } from "./InboxAvatar"; type InboxItemProps = { notification: InboxNotification; @@ -25,7 +24,7 @@ export const InboxItem: FC = ({ tabIndex={-1} >
- +
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index f80171122826c..2efd3580c1f94 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -4261,7 +4261,7 @@ export const MockNotification: TypesGen.InboxNotification = { template_id: MockTemplate.id, targets: [], title: "User account created", - icon: "user", + icon: "DEFAULT_ICON_ACCOUNT", }; export const MockNotifications: TypesGen.InboxNotification[] = [