Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SUSE Manager overviews #2725

Merged
merged 17 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
sudo apt-get install -y git python3 python3-pip
python3 -m pip install codespell
- name: codespell
run: codespell -S priv*,*package*json,deps*,*node_modules*,*svg,*.git,*.app -L enque,daa
run: codespell -S priv*,*package*json,deps*,*node_modules*,*svg,*.git,*.app -L enque,daa,afterall

generate-docs:
name: Generate project documentation
Expand Down
73 changes: 73 additions & 0 deletions assets/js/common/AdvisoryIcon/AdvisoryIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import { startCase } from 'lodash';
import {
EOS_SHIELD_OUTLINED,
EOS_CRITICAL_BUG_OUTLINED,
EOS_QUESTION_MARK_FILLED,
EOS_ADD_BOX_OUTLINED,
} from 'eos-icons-react';

import Tooltip from '@common/Tooltip';
import { computedIconCssClass } from '@lib/icon';

function Icon({ type, centered = false, hoverOpacity = true, size = 'l' }) {
const hoverOpacityClassName = hoverOpacity
? 'hover:opacity-75'
: 'hover:opacity-100';

switch (type) {
case 'security_advisory':
return (
<EOS_SHIELD_OUTLINED
className={`${hoverOpacityClassName} ${computedIconCssClass(
'fill-red-500',
centered
)} inline-block`}
size={size}
/>
);
case 'bugfix':
return (
<EOS_CRITICAL_BUG_OUTLINED
className={`${hoverOpacityClassName} ${computedIconCssClass(
'fill-yellow-500',
centered
)} inline-block`}
size={size}
/>
);
case 'enhancement':
return (
<EOS_ADD_BOX_OUTLINED
className={`${hoverOpacityClassName} ${computedIconCssClass(
'fill-yellow-500',
centered
)} inline-block`}
size={size}
/>
);
default:
return (
<EOS_QUESTION_MARK_FILLED
className={`${hoverOpacityClassName} ${computedIconCssClass(
'fill-gray-500',
centered
)} inline-block`}
size={size}
/>
);
}
}

export default function AdvisoryIcon({ type, centered, hoverOpacity, size }) {
return (
<Tooltip content={startCase(type || 'unknown')}>
<Icon
type={type}
centered={centered}
hoverOpacity={hoverOpacity}
size={size}
/>
</Tooltip>
);
}
65 changes: 65 additions & 0 deletions assets/js/common/AdvisoryIcon/AdvisoryIcon.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';

import AdvisoryIcon from '.';

export default {
title: 'Components/AdvisoryIcon',
components: AdvisoryIcon,
argTypes: {
type: {
description: 'The type of advisory',
options: ['security_advisory', 'bugfix', 'enhancement', 'NONEXISTENT'],
control: {
type: 'radio',
},
},
centered: {
description: 'Center the icon',
control: {
type: 'boolean',
},
},
hoverOpacity: {
description: 'Change opacity on hover',
control: {
type: 'boolean',
},
},
size: {
description: 'Size of the icon',
options: ['xs', 's', 'm', 'l', 'xl', 'xxl', 'xxxl'],
control: {
type: 'radio',
},
},
},

render: (args) => <AdvisoryIcon {...args} />,
};

export const SecurityAdvisory = {
args: {
type: 'security_advisory',
centered: false,
hoverOpacity: true,
size: 'l',
},
};

export const Bugfix = {
args: {
type: 'bugfix',
},
};

export const Enhancement = {
args: {
type: 'enhancement',
},
};

export const Unknown = {
args: {
type: '',
},
};
49 changes: 49 additions & 0 deletions assets/js/common/AdvisoryIcon/AdvisoryIcon.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom';

import AdvisoryIcon from '.';

describe('AdvisoryIcon', () => {
it('renders the correct SVG for an advisory type', () => {
const expectedComponents = new Map([
['security_advisory', 'EOS_SHIELD_OUTLINED'],
['bugfix', 'EOS_CRITICAL_BUG_OUTLINED'],
['enhancement', 'EOS_ADD_BOX_OUTLINED'],
]);

expectedComponents.forEach((componentName, type) => {
const { container } = render(<AdvisoryIcon type={type} />);

const iconEl = container.querySelector('svg');

const fiberKey = Object.keys(iconEl).filter((key) =>
key.startsWith('__reactFiber$')
)[0];
expect(fiberKey).toBeDefined();

const svgRCInstance = iconEl[fiberKey].return;

const svgRCName = svgRCInstance.elementType.name;
expect(svgRCName).toBe(componentName);
});
});

it('renders a fallback for an unknown advisory type', () => {
const componentName = 'EOS_QUESTION_MARK_FILLED';

const { container } = render(<AdvisoryIcon type={undefined} />);

const iconEl = container.querySelector('svg');

const fiberKey = Object.keys(iconEl).filter((key) =>
key.startsWith('__reactFiber$')
)[0];
expect(fiberKey).toBeDefined();

const svgRCInstance = iconEl[fiberKey].return;

const svgRCName = svgRCInstance.elementType.name;
expect(svgRCName).toBe(componentName);
});
});
3 changes: 3 additions & 0 deletions assets/js/common/AdvisoryIcon/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import AdvisoryIcon from './AdvisoryIcon';

export default AdvisoryIcon;
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ function AvailableSoftwareUpdates({
className,
settingsConfigured = false,
softwareUpdatesSettingsLoading,
onBackToSettings = noop,
softwareUpdatesLoading,
relevantPatches,
upgradablePackages,
tooltip,
onBackToSettings = noop,
onNavigateToPatches = noop,
onNavigateToPackages = noop,
}) {
if (softwareUpdatesSettingsLoading) {
return <Loading className={containerClassNames} />;
Expand Down Expand Up @@ -60,6 +62,7 @@ function AvailableSoftwareUpdates({
tooltip={tooltip}
loading={softwareUpdatesLoading}
icon={<EOS_HEALING size="xl" />}
onNavigate={onNavigateToPatches}
>
{relevantPatches}
</Indicator>
Expand All @@ -69,6 +72,7 @@ function AvailableSoftwareUpdates({
tooltip={tooltip}
loading={softwareUpdatesLoading}
icon={<EOS_PACKAGE_UPGRADE_OUTLINED size="xl" />}
onNavigate={onNavigateToPackages}
>
{upgradablePackages}
</Indicator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ export default {
type: 'function',
},
},
onNavigateToPatches: {
description:
'Callback function to trigger when the "Relevant Patches" area is clicked',
control: {
type: 'function',
},
},
onNavigateToPackages: {
description:
'Callback function to trigger when the "Upgradable Packages" area is clicked',
control: {
type: 'function',
},
},
softwareUpdatesSettingsLoading: {
control: {
type: 'boolean',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('AvailableSoftwareUpdates component', () => {

expect(screen.getByText('0')).toBeVisible();
expect(screen.getByText(upgradablePackages)).toBeVisible();
expect(screen.getAllByTestId('eos-svg-component')).toHaveLength(2);
expect(screen.getAllByTestId('eos-svg-component')).toHaveLength(4);
});

it('renders critical counters', () => {
Expand All @@ -38,7 +38,7 @@ describe('AvailableSoftwareUpdates component', () => {

expect(screen.getByText(relevantPatches)).toBeVisible();
expect(screen.getByText(upgradablePackages)).toBeVisible();
expect(screen.getAllByTestId('eos-svg-component')).toHaveLength(3);
expect(screen.getAllByTestId('eos-svg-component')).toHaveLength(5);
});

it('renders Unknown status', async () => {
Expand Down
31 changes: 26 additions & 5 deletions assets/js/common/AvailableSoftwareUpdates/Indicator.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import React from 'react';
import classNames from 'classnames';
import {
// EOS_KEYBOARD_ARROW_RIGHT_FILLED,
EOS_KEYBOARD_ARROW_RIGHT_FILLED,
EOS_ERROR_OUTLINED,
} from 'eos-icons-react';

import Tooltip from '@common/Tooltip';

function Indicator({ title, critical, tooltip, icon, loading, children }) {
function Indicator({
title,
critical,
tooltip,
icon,
loading,
children,
onNavigate,
}) {
const unknown = children === undefined;

if (loading) {
Expand All @@ -24,7 +32,20 @@ function Indicator({ title, critical, tooltip, icon, loading, children }) {

return (
<Tooltip isEnabled={unknown} content={tooltip} wrap={false}>
<div className="flex flex-row items-center border border-gray-200 p-2 rounded-md grow">
<div
role="button"
tabIndex={0}
className={classNames(
'flex flex-row items-center border border-gray-200 p-2 rounded-md grow',
{ 'cursor-pointer': !unknown }
)}
onClick={onNavigate}
onKeyDown={({ code }) => {
if (code === 'Enter') {
onNavigate();
}
}}
>
<div className="px-2">{icon}</div>
<div>
<p className="font-bold">{title}</p>
Expand All @@ -50,14 +71,14 @@ function Indicator({ title, critical, tooltip, icon, loading, children }) {
</div>
</div>
<div className="flex grow justify-end">
{/* {!unknown && (
{!unknown && (
<div>
<EOS_KEYBOARD_ARROW_RIGHT_FILLED
size="l"
className="fill-gray-400"
/>
</div>
)} */}
)}
</div>
</div>
</Tooltip>
Expand Down
Loading