From c36c612938d623721587c5c01eb2b8cde9743e61 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 24 Feb 2025 17:09:25 +0100 Subject: [PATCH 1/4] fix: hide app icon if not found --- .../src/modules/resources/AppLink/AppLink.tsx | 5 ++- .../modules/resources/AppLink/BaseIcon.tsx | 6 ++- .../pages/WorkspacePage/Workspace.stories.tsx | 38 +++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/site/src/modules/resources/AppLink/AppLink.tsx b/site/src/modules/resources/AppLink/AppLink.tsx index 15ccfb3d0ed71..22d45fa534304 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..9b4a91cfe7357 100644 --- a/site/src/modules/resources/AppLink/BaseIcon.tsx +++ b/site/src/modules/resources/AppLink/BaseIcon.tsx @@ -4,14 +4,18 @@ import type { FC } from "react"; interface BaseIconProps { app: WorkspaceApp; + onError?: () => void; } -export const BaseIcon: FC = ({ app }) => { +export const BaseIcon: FC = ({ app, onError }) => { return app.icon ? ( {`${app.display_name} { + onError?.(); + }} /> ) : ( diff --git a/site/src/pages/WorkspacePage/Workspace.stories.tsx b/site/src/pages/WorkspacePage/Workspace.stories.tsx index 6efbeef76ee25..5f5f73e1363bd 100644 --- a/site/src/pages/WorkspacePage/Workspace.stories.tsx +++ b/site/src/pages/WorkspacePage/Workspace.stories.tsx @@ -80,6 +80,44 @@ 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, + display_name: "Default Icon", + }, + { + ...Mocks.MockWorkspaceApp, + display_name: "Broken Icon", + icon: "/foobar/broken.png", + }, + { + ...Mocks.MockWorkspaceApp, + display_name: "Icon OK", + icon: "/favicon.ico", + }, + ], + }, + ], + }, + ], + }, + }, + }, +}; + export const Favorite: Story = { args: { ...Running.args, From afe1b64083bd5906cb786e102ac0c8e6054211cf Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 25 Feb 2025 10:53:37 +0100 Subject: [PATCH 2/4] fix: onIconPathError --- site/src/modules/resources/AppLink/AppLink.tsx | 2 +- site/src/modules/resources/AppLink/BaseIcon.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/src/modules/resources/AppLink/AppLink.tsx b/site/src/modules/resources/AppLink/AppLink.tsx index 22d45fa534304..e9d5f7d59561b 100644 --- a/site/src/modules/resources/AppLink/AppLink.tsx +++ b/site/src/modules/resources/AppLink/AppLink.tsx @@ -69,7 +69,7 @@ export const AppLink: FC = ({ app, workspace, agent }) => { // longer block access to apps if they are unhealthy/initializing. let canClick = true; let icon = !iconError && ( - setIconError(true)} /> + setIconError(true)} /> ); let primaryTooltip = ""; diff --git a/site/src/modules/resources/AppLink/BaseIcon.tsx b/site/src/modules/resources/AppLink/BaseIcon.tsx index 9b4a91cfe7357..4a7d58099eda5 100644 --- a/site/src/modules/resources/AppLink/BaseIcon.tsx +++ b/site/src/modules/resources/AppLink/BaseIcon.tsx @@ -4,17 +4,17 @@ import type { FC } from "react"; interface BaseIconProps { app: WorkspaceApp; - onError?: () => void; + onIconPathError?: () => void; } -export const BaseIcon: FC = ({ app, onError }) => { +export const BaseIcon: FC = ({ app, onIconPathError }) => { return app.icon ? ( {`${app.display_name} { - onError?.(); + onIconPathError?.(); }} /> ) : ( From 04f6a39e7e4f22a75bf2d4ead7d90eb1629234ea Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 25 Feb 2025 11:01:14 +0100 Subject: [PATCH 3/4] console.warn --- site/src/modules/resources/AppLink/BaseIcon.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/src/modules/resources/AppLink/BaseIcon.tsx b/site/src/modules/resources/AppLink/BaseIcon.tsx index 4a7d58099eda5..1f2885a49a02f 100644 --- a/site/src/modules/resources/AppLink/BaseIcon.tsx +++ b/site/src/modules/resources/AppLink/BaseIcon.tsx @@ -14,6 +14,9 @@ export const BaseIcon: FC = ({ app, onIconPathError }) => { src={app.icon} style={{ pointerEvents: "none" }} onError={() => { + console.warn( + `Application icon for "${app.id}" has invalid source "${app.icon}".`, + ); onIconPathError?.(); }} /> From 1251285d4a4b8afddf378c1e4d615af02c0fe560 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 25 Feb 2025 11:21:19 +0100 Subject: [PATCH 4/4] fix: json --- site/src/pages/WorkspacePage/Workspace.stories.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/site/src/pages/WorkspacePage/Workspace.stories.tsx b/site/src/pages/WorkspacePage/Workspace.stories.tsx index 5f5f73e1363bd..05a209ab35555 100644 --- a/site/src/pages/WorkspacePage/Workspace.stories.tsx +++ b/site/src/pages/WorkspacePage/Workspace.stories.tsx @@ -96,18 +96,17 @@ export const AppIcons: Story = { 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", }, - { - ...Mocks.MockWorkspaceApp, - display_name: "Icon OK", - icon: "/favicon.ico", - }, ], }, ],