From f709e08d6dd5a3e1bf11aa56fc7b08621c5afa1e Mon Sep 17 00:00:00 2001 From: Jill Guyonnet Date: Wed, 18 Dec 2024 17:30:48 +0100 Subject: [PATCH] [Fleet][EUI Visual Refresh] Replace hardcoded colors with tokens (#204717) ## Summary Closes https://github.com/elastic/kibana/issues/202003 This PR replaces hardcoded custom colours with EUI tokens. Found occurrences in Fleet plugin codebase: - hex colours (`#[A-Fa-f0-9]{6}`) - colour names (`red`, `green`...). - [x] Agent activity flyout - [x] Multiple hardcoded colours changed to semantic tokens - [x] Missing security requirements page - [x] Border colour - [x] Multisteps integration installation - [x] There was an old styling polyfill that looks like it can be removed, the result is visually very similar. Note that [the proposal to introduce numberless steps was rejected based on accessibility concerns](https://github.com/elastic/eui/discussions/5836#discussioncomment-6480047). - [x] Agent donut chart - [x] Legacy component no longer in use - removed - [x] Quickstart package card styling - [x] Card border colour (cf. implementation in https://github.com/elastic/kibana/pull/179573) Not covered: - [Test custom space in Cypress test](https://github.com/elastic/kibana/blob/6cd2cd6cf83fcf18b7ab66ac3f38f11ab9d69f8a/x-pack/plugins/fleet/cypress/tasks/spaces.ts#L26) - [Mock useEuiTheme in Jest test](https://github.com/elastic/kibana/blob/6cd2cd6cf83fcf18b7ab66ac3f38f11ab9d69f8a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/installation_status.test.tsx#L26) - [Story](https://github.com/elastic/kibana/blob/6cd2cd6cf83fcf18b7ab66ac3f38f11ab9d69f8a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/integration_preference.stories.tsx#L24) - [Custom tag colours](https://github.com/elastic/kibana/blob/6cd2cd6cf83fcf18b7ab66ac3f38f11ab9d69f8a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts#L36-L57): note that these are defined in the backend. ## Screenshots Note: I'm struggling to test the integrations quick start (tested the colour by manually applying it on the normal Integrations page), any advice on this would be welcome. ### Before (`main` branch), Amsterdam theme Agent activity flyout, showing in progress and error activity items: agent-activity-1-amsterdam-main Agent activity flyout, showing a successful activity item: agent-activity-2-amsterdam-main Missing security requirements page: es-requirements-amsterdam-main Multisteps integration installation (step 1): multisteps-1-amsterdam-main Multisteps integration installation (step 2): multisteps-2-amsterdam-main For reference, the old agent donut chard component: ![old-fleet-ui](https://github.com/user-attachments/assets/6b309d8a-5417-45cb-bb6c-58d1d88009f5) ### After #### Amsterdam Agent activity flyout, showing in progress and error activity items: agent-activity-1-amsterdam-branch Agent activity flyout, showing a successful activity item: agent-activity-2-amsterdam-branch Missing security requirements page: es-requirements-amsterdam-branch Multisteps integration installation (step 1): multisteps-1-amsterdam-branch Multisteps integration installation (step 2): multisteps-2-amsterdam-branch #### Borealis Agent activity flyout, showing in progress and error activity items: agent-activity-1-borealis-branch Agent activity flyout, showing a successful activity item: agent-activity-2-borealis-branch Missing security requirements page: es-requirements-borealis-branch Multisteps integration installation (step 1): multisteps-1-borealis-branch Multisteps integration installation (step 2): multisteps-2-borealis-branch --- .../components/horizontal_page_steps.tsx | 26 +------- .../agent_activity_flyout/activity_item.tsx | 38 +++++------ .../agent_activity_flyout/helpers.tsx | 2 - .../upgrade_in_progress_activity_item.tsx | 15 +++-- .../components/view_errors.tsx | 9 ++- .../es_requirements_page.tsx | 22 ++++--- .../agents/components/donut_chart.tsx | 66 ------------------- .../sections/epm/components/package_card.tsx | 26 ++++---- 8 files changed, 59 insertions(+), 145 deletions(-) delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/donut_chart.tsx diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/horizontal_page_steps.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/horizontal_page_steps.tsx index 752b49431dadb..a00ef9118b857 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/horizontal_page_steps.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/horizontal_page_steps.tsx @@ -7,31 +7,7 @@ import React from 'react'; import { EuiStepsHorizontal } from '@elastic/eui'; import type { EuiStepsHorizontalProps } from '@elastic/eui'; -import styled from 'styled-components'; -// polyfill until https://github.com/elastic/eui/discussions/5836 implemented -const NumberlessHorizontalSteps = styled(EuiStepsHorizontal)` - .euiStepNumber { - color: transparent; - width: 16px; - height: 16px; - outline-color: #07c; - } - .euiStepHorizontal::before { - width: calc(50% - 8px); - top: 32px; - } - .euiStepHorizontal::after { - width: calc(50% - 8px); - top: 32px; - } - .euiStepHorizontal { - padding: 25px 16px 16px; - } - .euiStepHorizontal[data-step-status='incomplete'] .euiStepHorizontal__title { - color: #69707d; - } -`; const getStepStatus = (currentStep: number, stepIndex: number, currentStepComplete: boolean) => { if (currentStep === stepIndex) { if (currentStepComplete) return 'complete'; @@ -58,5 +34,5 @@ export const PageSteps: React.FC<{ }; }) as EuiStepsHorizontalProps['steps']; - return ; + return ; }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/activity_item.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/activity_item.tsx index 06300480dfa50..f95e81de6d3d1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/activity_item.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/activity_item.tsx @@ -16,25 +16,22 @@ import { EuiText, EuiPanel, EuiSpacer, + useEuiTheme, } from '@elastic/eui'; import type { ActionStatus } from '../../../../../types'; import { ViewErrors } from '../view_errors'; -import { - formattedTime, - getAction, - inProgressDescription, - inProgressTitle, - inProgressTitleColor, -} from './helpers'; +import { formattedTime, getAction, inProgressDescription, inProgressTitle } from './helpers'; import { ViewAgentsButton } from './view_agents_button'; export const ActivityItem: React.FunctionComponent<{ action: ActionStatus; onClickViewAgents: (action: ActionStatus) => void; }> = ({ action, onClickViewAgents }) => { + const theme = useEuiTheme(); + const completeTitle = action.type === 'POLICY_CHANGE' && action.nbAgentsActioned === 0 ? ( @@ -104,18 +101,21 @@ export const ActivityItem: React.FunctionComponent<{ IN_PROGRESS: { icon: , title: {inProgressTitle(action)}, - titleColor: inProgressTitleColor, + titleColor: theme.euiTheme.colors.textPrimary, description: {inProgressDescription(action.creationTime)}, }, ROLLOUT_PASSED: { icon: action.nbAgentsFailed > 0 ? ( - + ) : ( - + ), title: completeTitle, - titleColor: action.nbAgentsFailed > 0 ? 'red' : 'green', + titleColor: + action.nbAgentsFailed > 0 + ? theme.euiTheme.colors.textDanger + : theme.euiTheme.colors.textSuccess, description: action.nbAgentsFailed > 0 ? ( failedDescription @@ -124,9 +124,9 @@ export const ActivityItem: React.FunctionComponent<{ ), }, COMPLETE: { - icon: , + icon: , title: completeTitle, - titleColor: 'green', + titleColor: theme.euiTheme.colors.textSuccess, description: action.type === 'POLICY_REASSIGN' && action.newPolicyId ? ( @@ -160,14 +160,14 @@ export const ActivityItem: React.FunctionComponent<{ ), }, FAILED: { - icon: , + icon: , title: completeTitle, - titleColor: 'red', + titleColor: theme.euiTheme.colors.textDanger, description: failedDescription, }, CANCELLED: { - icon: , - titleColor: 'grey', + icon: , + titleColor: theme.euiTheme.colors.textSubdued, title: ( , - titleColor: 'grey', + icon: , + titleColor: theme.euiTheme.colors.textSubdued, title: ( void; }> = ({ action, abortUpgrade, onClickViewAgents }) => { const { docLinks } = useStartServices(); + const theme = useEuiTheme(); + const [isAborting, setIsAborting] = useState(false); const onClickAbortUpgrade = useCallback(async () => { try { @@ -69,7 +67,10 @@ export const UpgradeInProgressActivityItem: React.FunctionComponent<{ {isScheduled ? : } - + {isScheduled && action.startTime ? ( = ({ action }) => { const coreStart = useStartServices(); + const theme = useEuiTheme(); const getLogsButton = (agentId: string, timestamp: string) => { const start = moment(timestamp).subtract(5, 'm').toISOString(); @@ -70,7 +71,11 @@ export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ }), render: (error: string) => ( - + {error} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/es_requirements_page.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/es_requirements_page.tsx index 969f9357a21db..3128b05f3af85 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/es_requirements_page.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/es_requirements_page.tsx @@ -20,9 +20,10 @@ import { EuiCode, EuiCodeBlock, EuiLink, + useEuiTheme, } from '@elastic/eui'; -import styled from 'styled-components'; +import { css } from '@emotion/react'; import { WithoutHeaderLayout } from '../../../layouts'; import type { GetFleetStatusResponse } from '../../../types'; @@ -50,20 +51,21 @@ export const RequirementItem: React.FunctionComponent<{ ); }; -const borderColor = '#d3dae6'; - -const StyledPageBody = styled(EuiPageBody)` - border: 1px solid ${borderColor}; - border-radius: 5px; -`; - export const MissingESRequirementsPage: React.FunctionComponent<{ missingRequirements: GetFleetStatusResponse['missing_requirements']; }> = ({ missingRequirements }) => { const { docLinks } = useStartServices(); + const theme = useEuiTheme(); + return ( - + - + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/donut_chart.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/donut_chart.tsx deleted file mode 100644 index 6f3d865b22843..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/donut_chart.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect, useRef } from 'react'; -import d3 from 'd3'; -import { EuiFlexItem } from '@elastic/eui'; - -interface DonutChartProps { - data: { - [key: string]: number; - }; - height: number; - width: number; -} - -export const DonutChart = ({ height, width, data }: DonutChartProps) => { - const chartElement = useRef(null); - - useEffect(() => { - if (chartElement.current !== null) { - // we must remove any existing paths before painting - d3.selectAll('g').remove(); - const svgElement = d3 - .select(chartElement.current) - .append('g') - .attr('transform', `translate(${width / 2}, ${height / 2})`); - const color = d3.scale - .ordinal() - // @ts-ignore - .domain(data) - .range(['#017D73', '#98A2B3', '#BD271E', '#F5A700']); - const pieGenerator = d3.layout - .pie() - .value(({ value }: any) => value) - // these start/end angles will reverse the direction of the pie, - // which matches our design - .startAngle(2 * Math.PI) - .endAngle(0); - - svgElement - .selectAll('g') - // @ts-ignore - .data(pieGenerator(d3.entries(data))) - .enter() - .append('path') - .attr( - 'd', - // @ts-ignore attr does not expect a param of type Arc but it behaves as desired - d3.svg - .arc() - .innerRadius(width * 0.36) - .outerRadius(Math.min(width, height) / 2) - ) - .attr('fill', (d: any) => color(d.data.key) as any); - } - }, [data, height, width]); - return ( - - - - ); -}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx index 52a3a90ae641e..2bf1f58a6e12b 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import styled from 'styled-components'; import { EuiBadge, EuiButton, @@ -15,6 +14,7 @@ import { EuiFlexItem, EuiSpacer, EuiToolTip, + useEuiTheme, } from '@elastic/eui'; import { css } from '@emotion/react'; @@ -43,15 +43,6 @@ import { export type PackageCardProps = IntegrationCardItem; -// Min-height is roughly 3 lines of content. -// This keeps the cards from looking overly unbalanced because of content differences. -const Card = styled(EuiCard)<{ isquickstart?: boolean; $maxCardHeight?: number }>` - min-height: 127px; - border-color: ${({ isquickstart }) => (isquickstart ? '#ba3d76' : null)}; - ${({ $maxCardHeight }) => - $maxCardHeight ? `max-height: ${$maxCardHeight}px; overflow: hidden;` : ''}; -`; - export function PackageCard({ description, name, @@ -78,6 +69,8 @@ export function PackageCard({ descriptionLineClamp, maxCardHeight, }: PackageCardProps) { + const theme = useEuiTheme(); + let releaseBadge: React.ReactNode | null = null; if (release && release !== 'ga') { releaseBadge = ( @@ -202,8 +195,10 @@ export function PackageCard({ tourOffset={10} > - } onClick={onClickProp ?? onCardClick} - $maxCardHeight={maxCardHeight} > {showLabels && extraLabelsBadges ? extraLabelsBadges : null} @@ -258,7 +256,7 @@ export function PackageCard({ showInstallationStatus={showInstallationStatus} /> - + );