diff --git a/console/src/api.ts b/console/src/api.ts index 77c9ca927..821469bc6 100644 --- a/console/src/api.ts +++ b/console/src/api.ts @@ -52,6 +52,7 @@ export async function fetchCatalogImage(): Promise { export async function fetchAllPatterns(): Promise<{ patterns: Pattern[]; catalogDescription?: string; + catalogLogo?: string; }> { const catalog = await fetchCatalog(); const patterns = await Promise.all( @@ -60,7 +61,15 @@ export async function fetchAllPatterns(): Promise<{ return { ...pattern, catalogKey: key }; }), ); - return { patterns, catalogDescription: catalog.catalog_description }; + return { + patterns, + catalogDescription: catalog.catalog_description, + catalogLogo: catalog.catalog_logo + ? /^https?:\/\//.test(catalog.catalog_logo) + ? catalog.catalog_logo + : `${PATTERN_UI_CATALOG_BASE_URL}/${catalog.catalog_logo}` + : undefined, + }; } export interface VaultJobStatus { diff --git a/console/src/components/PatternCatalogPage.css b/console/src/components/PatternCatalogPage.css index 13d482d75..d39e67705 100644 --- a/console/src/components/PatternCatalogPage.css +++ b/console/src/components/PatternCatalogPage.css @@ -1,3 +1,14 @@ +.patterns-operator__catalog-header { + display: flex; + align-items: center; + gap: 12px; +} + +.patterns-operator__catalog-logo { + max-height: 48px; + object-fit: contain; +} + .patterns-operator__card-field { margin-bottom: 4px; } diff --git a/console/src/components/PatternCatalogPage.tsx b/console/src/components/PatternCatalogPage.tsx index 79cc21ca0..962d2a7f8 100644 --- a/console/src/components/PatternCatalogPage.tsx +++ b/console/src/components/PatternCatalogPage.tsx @@ -166,6 +166,7 @@ export default function PatternCatalogPage() { const [installedPatterns, setInstalledPatterns] = React.useState>(new Set()); const [catalogImage, setCatalogImage] = React.useState(null); const [catalogDescription, setCatalogDescription] = React.useState(); + const [catalogLogo, setCatalogLogo] = React.useState(); const [selectedTiers, setSelectedTiers] = React.useState>(new Set(['maintained'])); const [tierSelectOpen, setTierSelectOpen] = React.useState(false); @@ -175,6 +176,7 @@ export default function PatternCatalogPage() { .then(([catalogData, installed, image]) => { setPatterns(catalogData.patterns); setCatalogDescription(catalogData.catalogDescription); + setCatalogLogo(catalogData.catalogLogo); setInstalledPatterns(new Set(installed)); setCatalogImage(image); setLoading(false); @@ -222,21 +224,30 @@ export default function PatternCatalogPage() { {t('Pattern Catalog')} - {catalogImage ? ( - - + <div className="patterns-operator__catalog-header"> + {catalogLogo && ( + <img + src={catalogLogo} + alt={t('Catalog logo')} + className="patterns-operator__catalog-logo" + /> + )} + {catalogImage ? ( + <Tooltip content={`${t('Catalog source')}: ${catalogImage}`}> + <Title + headingLevel="h1" + data-test="pattern-catalog-page-title" + style={{ display: 'inline-block' }} + > + {t('Pattern Catalog')} + + + ) : ( + {t('Pattern Catalog')} - - ) : ( - - {t('Pattern Catalog')} - - )} + )} + {catalogDescription && ( diff --git a/console/src/types.ts b/console/src/types.ts index 7af57d86f..3796a335d 100644 --- a/console/src/types.ts +++ b/console/src/types.ts @@ -2,6 +2,7 @@ export interface Catalog { generated_at: string; generator_version: string; catalog_description?: string; + catalog_logo?: string; patterns: string[]; }