diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/package_icon.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/package_icon.tsx index 8ba597a0d377e..de0dd75f635cf 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/package_icon.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/package_icon.tsx @@ -3,78 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useMemo, useState } from 'react'; -import { ICON_TYPES, EuiIcon, EuiIconProps } from '@elastic/eui'; -import { PackageInfo, PackageListItem } from '../../../../common/types/models'; -import { useLinks } from '../sections/epm/hooks'; -import { epmRouteService } from '../../../../common/services'; -import { sendRequest } from '../hooks/use_request'; -import { GetInfoResponse } from '../types'; -type Package = PackageInfo | PackageListItem; +import React from 'react'; +import { EuiIcon, EuiIconProps } from '@elastic/eui'; +import { usePackageIconType, UsePackageIconType } from '../hooks'; -const CACHED_ICONS = new Map(); - -export const PackageIcon: React.FunctionComponent<{ - packageName: string; - version?: string; - icons?: Package['icons']; -} & Omit> = ({ packageName, version, icons, ...euiIconProps }) => { - const iconType = usePackageIcon(packageName, version, icons); +export const PackageIcon: React.FunctionComponent> = ({ packageName, version, icons, tryApi, ...euiIconProps }) => { + const iconType = usePackageIconType({ packageName, version, icons, tryApi }); return ; }; - -const usePackageIcon = (packageName: string, version?: string, icons?: Package['icons']) => { - const { toImage } = useLinks(); - const [iconType, setIconType] = useState(''); // FIXME: use `empty` icon during initialization - see: https://github.com/elastic/kibana/issues/60622 - const pkgKey = `${packageName}-${version ?? ''}`; - - // Generates an icon path or Eui Icon name based on an icon list from the package - // or by using the package name against logo icons from Eui - const fromInput = useMemo(() => { - return (iconList?: Package['icons']) => { - const svgIcons = iconList?.filter(iconDef => iconDef.type === 'image/svg+xml'); - const localIconSrc = Array.isArray(svgIcons) && svgIcons[0]?.src; - if (localIconSrc) { - CACHED_ICONS.set(pkgKey, toImage(localIconSrc)); - setIconType(CACHED_ICONS.get(pkgKey) as string); - return; - } - - const euiLogoIcon = ICON_TYPES.find(key => key.toLowerCase() === `logo${packageName}`); - if (euiLogoIcon) { - CACHED_ICONS.set(pkgKey, euiLogoIcon); - setIconType(euiLogoIcon); - return; - } - - CACHED_ICONS.set(pkgKey, 'package'); - setIconType('package'); - }; - }, [packageName, pkgKey, toImage]); - - useEffect(() => { - if (CACHED_ICONS.has(pkgKey)) { - setIconType(CACHED_ICONS.get(pkgKey) as string); - return; - } - - // Use API to see if package has icons defined - if (!icons && version) { - fromPackageInfo(pkgKey) - .catch(() => undefined) // ignore API errors - .then(fromInput); - } else { - fromInput(icons); - } - }, [icons, toImage, packageName, version, fromInput, pkgKey]); - - return iconType; -}; - -const fromPackageInfo = async (pkgKey: string) => { - const { data } = await sendRequest({ - path: epmRouteService.getInfoPath(pkgKey), - method: 'get', - }); - return data?.response?.icons; -}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/index.ts index 5e0695bd3e305..66c7333150fb7 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/index.ts @@ -9,6 +9,7 @@ export { useCore, CoreContext } from './use_core'; export { useConfig, ConfigContext } from './use_config'; export { useSetupDeps, useStartDeps, DepsContext } from './use_deps'; export { useLink } from './use_link'; +export { usePackageIconType, UsePackageIconType } from './use_package_icon_type'; export { usePagination, Pagination } from './use_pagination'; export { useDebounce } from './use_debounce'; export * from './use_request'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts new file mode 100644 index 0000000000000..5f231b5cc9ec9 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useEffect, useState } from 'react'; +import { ICON_TYPES } from '@elastic/eui'; +import { PackageInfo, PackageListItem } from '../../../../common/types/models'; +import { useLinks } from '../sections/epm/hooks'; +import { sendGetPackageInfoByKey } from './index'; + +type Package = PackageInfo | PackageListItem; + +export interface UsePackageIconType { + packageName: Package['name']; + version: Package['version']; + icons?: Package['icons']; + tryApi?: boolean; // should it call API to try to find missing icons? +} + +const CACHED_ICONS = new Map(); + +export const usePackageIconType = ({ + packageName, + version, + icons: paramIcons, + tryApi = false, +}: UsePackageIconType) => { + const { toImage } = useLinks(); + const [iconList, setIconList] = useState(); + const [iconType, setIconType] = useState(''); // FIXME: use `empty` icon during initialization - see: https://github.com/elastic/kibana/issues/60622 + const pkgKey = `${packageName}-${version}`; + + // Generates an icon path or Eui Icon name based on an icon list from the package + // or by using the package name against logo icons from Eui + useEffect(() => { + if (CACHED_ICONS.has(pkgKey)) { + setIconType(CACHED_ICONS.get(pkgKey) || ''); + return; + } + const svgIcons = (paramIcons || iconList)?.filter(iconDef => iconDef.type === 'image/svg+xml'); + const localIconSrc = Array.isArray(svgIcons) && svgIcons[0]?.src; + if (localIconSrc) { + CACHED_ICONS.set(pkgKey, toImage(localIconSrc)); + setIconType(CACHED_ICONS.get(pkgKey) || ''); + return; + } + + const euiLogoIcon = ICON_TYPES.find(key => key.toLowerCase() === `logo${packageName}`); + if (euiLogoIcon) { + CACHED_ICONS.set(pkgKey, euiLogoIcon); + setIconType(euiLogoIcon); + return; + } + + if (tryApi && !paramIcons && !iconList) { + sendGetPackageInfoByKey(pkgKey) + .catch(error => undefined) // Ignore API errors + .then(res => { + CACHED_ICONS.delete(pkgKey); + setIconList(res?.data?.response?.icons); + }); + } + + CACHED_ICONS.set(pkgKey, 'package'); + setIconType('package'); + }, [paramIcons, pkgKey, toImage, iconList, packageName, iconType, tryApi]); + + return iconType; +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx index 0b48020c3cac1..cc7fc89ab8a80 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_select_package.tsx @@ -130,7 +130,15 @@ export const StepSelectPackage: React.FunctionComponent<{ return { label: title || name, key: pkgkey, - prepend: , + prepend: ( + + ), checked: selectedPkgKey === pkgkey ? 'on' : undefined, }; })} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx index 49285707457e1..87155afdc21be 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/datasources/datasources_table.tsx @@ -150,6 +150,7 @@ export const DatasourcesTable: React.FunctionComponent = ({ packageName={datasource.package.name} version={datasource.package.version} size="m" + tryApi={true} /> )} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icon_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icon_panel.tsx index 7ce386ed56f5f..684b158b5da86 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icon_panel.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icon_panel.tsx @@ -16,7 +16,8 @@ export function IconPanel({ iconType }: { iconType: IconType }) { text-align: center; vertical-align: middle; padding: ${props => props.theme.eui.spacerSizes.xl}; - svg { + svg, + img { height: ${props => props.theme.eui.euiKeyPadMenuSize}; width: ${props => props.theme.eui.euiKeyPadMenuSize}; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx index 4bc90c6a0f8fd..3239d7b90e3c3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { EuiPage, EuiPageBody, EuiPageProps, ICON_TYPES } from '@elastic/eui'; +import { EuiPage, EuiPageBody, EuiPageProps } from '@elastic/eui'; import React, { Fragment, useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import styled from 'styled-components'; @@ -12,7 +12,7 @@ import { PackageInfo } from '../../../../types'; import { useSetPackageInstallStatus } from '../../hooks'; import { Content } from './content'; import { Header } from './header'; -import { sendGetPackageInfoByKey } from '../../../../hooks'; +import { sendGetPackageInfoByKey, usePackageIconType } from '../../../../hooks'; export const DEFAULT_PANEL: DetailViewPanelName = 'overview'; @@ -62,8 +62,8 @@ const FullWidthContent = styled(EuiPage)` type LayoutProps = PackageInfo & Pick & Pick; export function DetailLayout(props: LayoutProps) { - const { name, restrictWidth } = props; - const iconType = ICON_TYPES.find(key => key.toLowerCase() === `logo${name}`); + const { name: packageName, version, icons, restrictWidth } = props; + const iconType = usePackageIconType({ packageName, version, icons }); return (