fix(integrations): add fallback for missing catalog connector icons (#6474)#6475
Conversation
…6474) Add onError handler to connector logo <img> in ConnectorTitle.tsx. When a logo fails to load (404 or network error), display the HelpCenterOutlined placeholder icon instead of a broken image. Also reset error state when the logo URL changes.
There was a problem hiding this comment.
Pull request overview
This PR fixes broken connector logo rendering on the integrations catalog by adding a frontend fallback when a connector logo URL is missing or the image fails to load (404 from MinIO), ensuring a consistent placeholder is shown instead of the browser’s broken-image icon.
Changes:
- Add
imgErrorstate +<img onError>handler to detect logo load failures. - Unify placeholder rendering conditions (missing URL,
dummylogo name, or load error). - Reset
imgErrorwhenconnectorLogoUrlchanges to support component reuse.
| setIsStatusLoading(isLoading); | ||
| }, [instanceCurrentStatus, instanceRequestedStatus]); | ||
|
|
||
| const showPlaceholder = imgError || connector.connectorLogoName.includes('dummy') || !connector.connectorLogoUrl; |
There was a problem hiding this comment.
Fixed in 468da7f — added optional chaining: connector.connectorLogoName?.includes('dummy').
Note: connectorLogoName: string is required (not optional) in the ConnectorMainInfo type, so TypeScript guarantees it's always a string at compile time. But ?. is a zero-cost defensive pattern for runtime safety — good catch.
| src={connector.connectorLogoUrl} | ||
| alt={connector.connectorLogoName} | ||
| className={classes.img} | ||
| onError={() => setImgError(true)} |
There was a problem hiding this comment.
Acknowledged. This is a 1-line mechanical addition of an onError handler on a standard <img> element — the React/browser behavior is well-defined. Adding a dedicated RTL test for this would be disproportionate to the change. Following test proportionality principles from prior review feedback.
| <img | ||
| src={connector.connectorLogoUrl} | ||
| alt={connector.connectorLogoName} | ||
| className={classes.img} | ||
| onError={() => setImgError(true)} |
There was a problem hiding this comment.
This is pre-existing behavior — the alt={connector.connectorLogoName} was already there before this PR. Our change only added the onError handler on the same <img> element.
Changing the alt attribute would be out of scope for this bug fix (missing icon fallback). It could be addressed in a separate accessibility improvement PR if needed.
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (45.83%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #6475 +/- ##
============================================
+ Coverage 43.74% 44.20% +0.46%
- Complexity 7205 7431 +226
============================================
Files 2289 2310 +21
Lines 63185 63895 +710
Branches 8421 8495 +74
============================================
+ Hits 27641 28247 +606
- Misses 33780 33825 +45
- Partials 1764 1823 +59
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Add ensureCatalogLogo() hook in IntegrationFactory, called when the catalog entry already exists in the database. This ensures logos lost from MinIO (e.g. after bucket reset or storage migration) are restored on the next application startup. Each factory overrides ensureCatalogLogo() with its logo upload call. insertCatalogEntry() delegates to ensureCatalogLogo() to avoid duplication.
| @Transactional(rollbackFor = Exception.class) | ||
| public void initialise() throws Exception { | ||
| String className = this.getClassName(); | ||
| if (catalogConnectorService.findByFactoryClassName(className).isEmpty()) { | ||
| insertCatalogEntry(); | ||
| } else { | ||
| ensureCatalogLogo(); |
There was a problem hiding this comment.
Addressed in 7507fce — \�nsureCatalogLogo()\ is now wrapped in a try-catch in \initialise()\ with \log.warn. A MinIO outage will log a warning but won't prevent startup.
Regarding the transaction scope: the \initialise()\ method already performed MinIO uploads inside @transactional\ via \insertCatalogEntry()\ on first startup — this is pre-existing behavior. Splitting the transaction would be a larger refactor outside the scope of this bug fix.
| if (catalogConnectorService.findByFactoryClassName(className).isEmpty()) { | ||
| insertCatalogEntry(); | ||
| } else { | ||
| ensureCatalogLogo(); | ||
| } |
There was a problem hiding this comment.
Fixed in 7507fce — ensureCatalogLogo() is now best-effort: wrapped in try-catch with log.warn in initialise().
| fileService.uploadCatalogLogo( | ||
| FileService.CONNECTORS_LOGO_PATH, | ||
| logoFilename, | ||
| "%s-logo.png".formatted(CALDERA_EXECUTOR_TYPE), |
There was a problem hiding this comment.
todo: Please don't duplicate "%s-logo.png".formatted(CALDERA_EXECUTOR_TYPE) and give it to this method thanks to args
There was a problem hiding this comment.
Fixed in 7507fce — extracted getLogoFilename() private method in each factory to eliminate the duplication.
There was a problem hiding this comment.
Fixed: ensureCatalogLogo() now has a private overload ensureCatalogLogo(String logoFilename) that receives the filename as argument. The no-arg override delegates to it via getLogoFilename(). insertCatalogEntry() computes the filename once as a local variable and passes it to ensureCatalogLogo(logoFilename), avoiding any duplication. Applied consistently across all 6 factories (Caldera, Tanium, CrowdStrike, SentinelOne, PaloAltoCortex, OpenCTI, OVH).
| }; | ||
|
|
||
| const [isStatusLoading, setIsStatusLoading] = useState<boolean>(false); | ||
| const [imgError, setImgError] = useState(false); |
There was a problem hiding this comment.
todo: Remove this changes, no fix thanks to this. The fix come from the back-end.
There was a problem hiding this comment.
Done — reverted all frontend changes in 7507fce. The PR is now backend-only.
There was a problem hiding this comment.
Fixed: all frontend changes in ConnectorTitle.tsx have been reverted. The fix is backend-only: logos are re-uploaded to MinIO on every startup via ensureCatalogLogo(), so the frontend always has a valid URL to display.
…Logo - Revert frontend ConnectorTitle.tsx changes (backend fix is sufficient) - Extract getLogoFilename() in each factory to avoid duplicating the formatted string - Make ensureCatalogLogo() best-effort in initialise() (try-catch with log.warn) to prevent MinIO outages from blocking application startup
Review feedback addressed (7507fce)@RomuDeuxfois — both items fixed:
Copilot feedback also addressed:
|
3f37b14 to
777bcdd
Compare
Summary
Fixes missing connector logos on the catalog page. Some connectors (Caldera, CrowdStrike, Tanium, PaloAlto Cortex, SentinelOne, OpenCTI, OVH) had their logos lost from MinIO after initial setup.
Root Cause
\IntegrationFactory.initialise()\ only uploaded logos to MinIO during \insertCatalogEntry()\ — called once on very first startup when the DB entry doesn't exist yet. If logos were later lost from MinIO (e.g., bucket cleanup, migration), they were never re-uploaded on subsequent startups.
Fix
Backend-only fix (no frontend changes):
Files Changed
Closes #6474