diff --git a/site/src/modules/resources/AppLink/AppLink.tsx b/site/src/modules/resources/AppLink/AppLink.tsx index 15ccfb3d0ed71..e9d5f7d59561b 100644 --- a/site/src/modules/resources/AppLink/AppLink.tsx +++ b/site/src/modules/resources/AppLink/AppLink.tsx @@ -37,6 +37,7 @@ export const AppLink: FC = ({ app, workspace, agent }) => { const preferredPathBase = proxy.preferredPathAppURL; const appsHost = proxy.preferredWildcardHostname; const [fetchingSessionToken, setFetchingSessionToken] = useState(false); + const [iconError, setIconError] = useState(false); const theme = useTheme(); const username = workspace.owner_name; @@ -67,7 +68,9 @@ export const AppLink: FC = ({ app, workspace, agent }) => { // To avoid bugs in the healthcheck code locking users out of apps, we no // longer block access to apps if they are unhealthy/initializing. let canClick = true; - let icon = ; + let icon = !iconError && ( + setIconError(true)} /> + ); let primaryTooltip = ""; if (app.health === "initializing") { diff --git a/site/src/modules/resources/AppLink/BaseIcon.tsx b/site/src/modules/resources/AppLink/BaseIcon.tsx index d6cbf145d4071..1f2885a49a02f 100644 --- a/site/src/modules/resources/AppLink/BaseIcon.tsx +++ b/site/src/modules/resources/AppLink/BaseIcon.tsx @@ -4,14 +4,21 @@ import type { FC } from "react"; interface BaseIconProps { app: WorkspaceApp; + onIconPathError?: () => void; } -export const BaseIcon: FC = ({ app }) => { +export const BaseIcon: FC = ({ app, onIconPathError }) => { return app.icon ? ( {`${app.display_name} { + console.warn( + `Application icon for "${app.id}" has invalid source "${app.icon}".`, + ); + onIconPathError?.(); + }} /> ) : ( diff --git a/site/src/pages/WorkspacePage/Workspace.stories.tsx b/site/src/pages/WorkspacePage/Workspace.stories.tsx index 6efbeef76ee25..05a209ab35555 100644 --- a/site/src/pages/WorkspacePage/Workspace.stories.tsx +++ b/site/src/pages/WorkspacePage/Workspace.stories.tsx @@ -80,6 +80,43 @@ export const Running: Story = { }, }; +export const AppIcons: Story = { + args: { + ...Running.args, + workspace: { + ...Mocks.MockWorkspace, + latest_build: { + ...Mocks.MockWorkspace.latest_build, + resources: [ + { + ...Mocks.MockWorkspaceResource, + agents: [ + { + ...Mocks.MockWorkspaceAgent, + apps: [ + { + ...Mocks.MockWorkspaceApp, + id: "test-app-1", + slug: "test-app-1", + display_name: "Default Icon", + }, + { + ...Mocks.MockWorkspaceApp, + id: "test-app-2", + slug: "test-app-2", + display_name: "Broken Icon", + icon: "/foobar/broken.png", + }, + ], + }, + ], + }, + ], + }, + }, + }, +}; + export const Favorite: Story = { args: { ...Running.args,