diff --git a/config-overrides.js b/config-overrides.js index 2505a89bc0..122b24445a 100644 --- a/config-overrides.js +++ b/config-overrides.js @@ -17,6 +17,7 @@ module.exports = { test: /\.svg$/, include: [ path.resolve(srcRoot, 'assets/icons'), + path.resolve(srcRoot, 'assets/illustrations'), path.resolve(uiKitRoot, 'assets/icons'), uiKitIconsRoot, ], diff --git a/src/assets/illustrations/dark/403.svg b/src/assets/illustrations/dark/403.svg index 4957e7f89a..2b274d123a 100644 --- a/src/assets/illustrations/dark/403.svg +++ b/src/assets/illustrations/dark/403.svg @@ -1 +1,18 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/illustrations/dark/error.svg b/src/assets/illustrations/dark/error.svg index 1a0e30c62a..97d9685dff 100644 --- a/src/assets/illustrations/dark/error.svg +++ b/src/assets/illustrations/dark/error.svg @@ -1,4 +1,4 @@ - + diff --git a/src/assets/illustrations/dark/thumbsUp.svg b/src/assets/illustrations/dark/thumbsUp.svg index 862417453a..43c7f27a9b 100644 --- a/src/assets/illustrations/dark/thumbsUp.svg +++ b/src/assets/illustrations/dark/thumbsUp.svg @@ -1,4 +1,5 @@ - + diff --git a/src/assets/illustrations/light/403.svg b/src/assets/illustrations/light/403.svg index ed22a3f03c..3c0eb53a8e 100644 --- a/src/assets/illustrations/light/403.svg +++ b/src/assets/illustrations/light/403.svg @@ -1 +1,16 @@ - \ No newline at end of file + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/illustrations/light/error.svg b/src/assets/illustrations/light/error.svg index 8c33e645f3..7dc979ab55 100644 --- a/src/assets/illustrations/light/error.svg +++ b/src/assets/illustrations/light/error.svg @@ -1,4 +1,4 @@ - + diff --git a/src/assets/illustrations/light/thumbsUp.svg b/src/assets/illustrations/light/thumbsUp.svg index 862417453a..43c7f27a9b 100644 --- a/src/assets/illustrations/light/thumbsUp.svg +++ b/src/assets/illustrations/light/thumbsUp.svg @@ -1,4 +1,5 @@ - + diff --git a/src/components/EmptyFilter/EmptyFilter.tsx b/src/components/EmptyFilter/EmptyFilter.tsx index 59ec31059c..f7bba88207 100644 --- a/src/components/EmptyFilter/EmptyFilter.tsx +++ b/src/components/EmptyFilter/EmptyFilter.tsx @@ -18,7 +18,7 @@ export const EmptyFilter = ({ message = i18n('default_message'), showAll = i18n('default_button_label'), onShowAll, - image = , + image = , }: EmptyFilterProps) => ( { +import './Illustration.scss'; + +export interface IllustrationProps { name: string; + width?: number; + height?: number; className?: string; } -type IllustrationStore = Record Promise<{default: any}>>>; +type IllustrationStore = Record Promise<{default: IconData}>>>; const store: IllustrationStore = { light: { @@ -24,23 +30,42 @@ const store: IllustrationStore = { }, }; -const b = cn('kv-illustration'); +const b = cn('ydb-illustration'); -export const Illustration = ({name, className, ...props}: IllustrationProps) => { +export const Illustration = ({name, className, width, height}: IllustrationProps) => { const theme = useThemeValue(); - const [src, setSrc] = React.useState(''); - const srcGetter = store[theme] && store[theme][name]; + + // When a function is stored in useState, typeof returns 'object' + // SVGR loads SVG files as React components (functions) + // However, in the Icon component, these are treated as objects and incorrectly rendered as sprite elements (bug) + // To fix this, we need to wrap the icon data in an additional object, so its initial type is preserved + const [{iconData}, setIconData] = React.useState<{iconData?: IconData}>({}); React.useEffect(() => { - if (typeof srcGetter === 'function') { - srcGetter() - .then((svg) => setSrc(svg.default)) - .catch((e) => { - console.error(e); - setSrc(''); - }); - } - }, [srcGetter]); - - return src ? {name} : null; + const loadIcon = async () => { + try { + const iconLoader = store[theme]?.[name]; + + if (iconLoader && typeof iconLoader === 'function') { + const module = await iconLoader(); + setIconData({iconData: module.default}); + } + } catch (err) { + console.error('Failed to load illustration:', name, err); + setIconData({}); + } + }; + + loadIcon(); + }, [name, theme]); + + if (isNil(iconData)) { + return null; + } + + return ( + + + + ); }; diff --git a/src/containers/Nodes/NodesTable.tsx b/src/containers/Nodes/NodesTable.tsx index 65615f4dc9..bdd5b907b9 100644 --- a/src/containers/Nodes/NodesTable.tsx +++ b/src/containers/Nodes/NodesTable.tsx @@ -73,7 +73,7 @@ export function NodesTable({ const renderEmptyDataMessage = () => { if (problemFilter !== 'All' || uptimeFilter !== NodesUptimeFilterValues.All) { - return ; + return ; } return i18n('empty.default'); diff --git a/src/containers/Tenant/Diagnostics/Network/Network.tsx b/src/containers/Tenant/Diagnostics/Network/Network.tsx index f1281ac752..7d5aeaf13a 100644 --- a/src/containers/Tenant/Diagnostics/Network/Network.tsx +++ b/src/containers/Tenant/Diagnostics/Network/Network.tsx @@ -302,7 +302,7 @@ function Nodes({nodes, isRight, showId, showRacks, clickedNode, onClickNode}: No }); if (filter === ProblemFilterValues.PROBLEMS && problemNodesCount === 0) { - return ; + return ; } else { return result; } diff --git a/src/containers/Tenant/Healthcheck/Healthcheck.tsx b/src/containers/Tenant/Healthcheck/Healthcheck.tsx index 2b3133c0c7..4ff29f8de5 100644 --- a/src/containers/Tenant/Healthcheck/Healthcheck.tsx +++ b/src/containers/Tenant/Healthcheck/Healthcheck.tsx @@ -76,7 +76,7 @@ export function Healthcheck({ if (selfCheckResult === SelfCheckResult.GOOD && (!leavesIssues || !leavesIssues.length)) { return ( - + {HEALTHCHECK_RESULT_TO_TEXT[selfCheckResult]} ); diff --git a/src/containers/Tenants/Tenants.tsx b/src/containers/Tenants/Tenants.tsx index 55570ec074..0908b10d17 100644 --- a/src/containers/Tenants/Tenants.tsx +++ b/src/containers/Tenants/Tenants.tsx @@ -313,7 +313,7 @@ export const Tenants = ({additionalTenantsProps, scrollContainerRef}: TenantsPro } if (filteredTenants.length === 0 && problemFilter !== ProblemFilterValues.ALL) { - return ; + return ; } return (