Custom link colour option for top banner (#214241)

This PR resolves [Link color in banner shown in blue and not the defined
color](https://github.com/elastic/kibana/issues/206266) issue.

Now there is a new option added that applies custom color specifically
for links, and can be fully customized.

- Updated documentation
  - in Cloud
  - advanced-settings
  - configuration
- Added to plugins
  - kibana_usage
  - telemetry
- Implemented new 'linkColor' property for the banners
- Updated functional tests
This commit is contained in:
Paulina Shakirova 2025-03-25 20:26:35 +01:00 committed by GitHub
parent 1d91061ec4
commit 637c61aedd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 98 additions and 25 deletions

View file

@ -212,6 +212,9 @@ $$$banners-textcontent$$$`banners:textContent`
$$$banners-textcolor$$$`banners:textColor`
: The color for the banner text for this space. Defaults to the value of the `xpack.banners.textColor` configuration property.
$$$banners-linkcolor$$$`banners:linkColor`
: The color for the banner link text for this space. Defaults to the value of the `xpack.banners.linkColor` configuration property.
$$$banners-backgroundcolor$$$`banners:backgroundColor`
: The color of the banner background for this space. Defaults to the value of the `xpack.banners.backgroundColor` configuration property.

View file

@ -390,6 +390,9 @@ Banners are disabled by default. You need to manually configure them in order to
`xpack.banners.textColor`
: The color for the banner text. Defaults to `#8A6A0A`.
`xpack.banners.linkColor`
: The color for the banner link text. Defaults to `#0B64DD`.
`xpack.banners.backgroundColor`
: The color of the banner background. Defaults to `#FFF9E8`.

View file

@ -29,6 +29,9 @@ Banners are a [subscription feature](https://www.elastic.co/subscriptions).
`xpack.banners.textColor`
: The color for the banner text. Defaults to `#8A6A0A`.
`xpack.banners.linkColor`
: The color for the banner link text. Defaults to `#0B64DD`.
`xpack.banners.backgroundColor`
: The color of the banner background. Defaults to `#FFF9E8`.

View file

@ -67,6 +67,7 @@ export const AUTOCOMPLETE_VALUE_SUGGESTION_METHOD_ID = 'autocomplete:valueSugges
export const BANNERS_PLACEMENT_ID = 'banners:placement';
export const BANNERS_TEXT_CONTENT_ID = 'banners:textContent';
export const BANNERS_TEXT_COLOR_ID = 'banners:textColor';
export const BANNERS_LINK_COLOR_ID = 'banners:linkColor';
export const BANNERS_BACKGROUND_COLOR_ID = 'banners:backgroundColor';
// Discover settings

View file

@ -515,6 +515,10 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
type: 'text',
_meta: { description: 'Non-default value of setting.' },
},
'banners:linkColor': {
type: 'text',
_meta: { description: 'Non-default value of setting.' },
},
'banners:backgroundColor': {
type: 'text',
_meta: { description: 'Non-default value of setting.' },

View file

@ -140,6 +140,7 @@ export interface UsageStats {
dateFormat: string;
'banners:placement': string;
'banners:textColor': string;
'banners:linkColor': string;
'banners:backgroundColor': string;
'labs:canvas:enable_ui': boolean;
'labs:canvas:byValueEmbeddable': boolean;

View file

@ -11331,6 +11331,12 @@
"description": "Non-default value of setting."
}
},
"banners:linkColor": {
"type": "text",
"_meta": {
"description": "Non-default value of setting."
}
},
"banners:backgroundColor": {
"type": "text",
"_meta": {

View file

@ -10,9 +10,10 @@ The options are
- `placement`
The placement of the banner. The allowed values are:
- `disabled` - The banner will be disabled
- `top` - The banner will be displayed in the header
The placement of the banner. The allowed values are:
- `disabled` - The banner will be disabled
- `top` - The banner will be displayed in the header
- `textContent`
@ -22,6 +23,10 @@ The text content that will be displayed inside the banner, either plain text or
The color of the banner's text. Must be a valid hex color
- `linkColor`
The color of the banner's link's text. Must be a valid hex color
- `backgroundColor`
The color for the banner's background. Must be a valid hex color
@ -29,10 +34,12 @@ The color for the banner's background. Must be a valid hex color
### Configuration example
`kibana.yml`
```yaml
xpack.banners:
placement: 'top'
textContent: 'Production environment - Proceed with **special levels** of caution'
textColor: '#FF0000'
linkColor: '#0B64DD'
backgroundColor: '#CC2211'
```
```

View file

@ -16,5 +16,6 @@ export interface BannerConfiguration {
placement: BannerPlacement;
textContent: string;
textColor: string;
linkColor: string;
backgroundColor: string;
}

View file

@ -1,7 +0,0 @@
.kbnUserBanner__container {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: $euiFontSizeS;
}

View file

@ -6,25 +6,33 @@
*/
import React, { FC } from 'react';
import { css } from '@emotion/react';
import { useEuiFontSize } from '@elastic/eui';
import { Markdown } from '@kbn/shared-ux-markdown';
import { BannerConfiguration } from '../../common';
import './banner.scss';
interface BannerProps {
bannerConfig: BannerConfiguration;
}
export const Banner: FC<BannerProps> = ({ bannerConfig }) => {
const { textContent, textColor, backgroundColor } = bannerConfig;
const { textContent, textColor, linkColor, backgroundColor } = bannerConfig;
const customLinkColor = linkColor || 'inherit';
const bannerStyle = css({
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: useEuiFontSize('s').fontSize,
backgroundColor,
color: textColor,
'& a': {
color: customLinkColor,
},
});
return (
<div
className="kbnUserBanner__container"
style={{
backgroundColor,
color: textColor,
}}
>
<div css={bannerStyle}>
<div className="eui-textTruncate" data-test-subj="bannerInnerWrapper">
<Markdown readOnly>{textContent}</Markdown>
</div>

View file

@ -17,6 +17,7 @@ const createBannerConfig = (parts: Partial<BannerConfiguration> = {}): BannerCon
placement: 'disabled',
textContent: 'foo',
textColor: '#FFFFFF',
linkColor: '#0B64DD',
backgroundColor: '#000000',
...parts,
});

View file

@ -23,6 +23,14 @@ const configSchema = schema.object({
},
defaultValue: '#8A6A0A',
}),
linkColor: schema.string({
validate: (color) => {
if (!isHexColor(color)) {
return `must be an hex color`;
}
},
defaultValue: '#0B64DD',
}),
backgroundColor: schema.string({
validate: (color) => {
if (!isHexColor(color)) {

View file

@ -23,6 +23,7 @@ describe('BannersPlugin', () => {
textContent: 'foo',
backgroundColor: '#000000',
textColor: '#FFFFFF',
linkColor: '#0B64DD',
disableSpaceBanners: false,
};
pluginInitContext = coreMock.createPluginInitializerContext();

View file

@ -49,10 +49,11 @@ const isValidLicense = (license: ILicense): boolean => {
};
const getBannerConfig = async (client: IUiSettingsClient): Promise<BannerConfiguration> => {
const [placement, textContent, textColor, backgroundColor] = await Promise.all([
const [placement, textContent, textColor, linkColor, backgroundColor] = await Promise.all([
client.get<BannerPlacement>('banners:placement'),
client.get<string>('banners:textContent'),
client.get<string>('banners:textColor'),
client.get<string>('banners:linkColor'),
client.get<string>('banners:backgroundColor'),
]);
@ -60,6 +61,7 @@ const getBannerConfig = async (client: IUiSettingsClient): Promise<BannerConfigu
placement,
textContent,
textColor,
linkColor,
backgroundColor,
};
};

View file

@ -13,6 +13,7 @@ const createConfig = (parts: Partial<BannersConfigType> = {}): BannersConfigType
placement: 'disabled',
backgroundColor: '#0000',
textColor: '#FFFFFF',
linkColor: '#0B64DD',
textContent: 'some global banner text',
disableSpaceBanners: false,
...parts,
@ -35,6 +36,7 @@ describe('registerSettings', () => {
value: 'some global banner text',
}),
'banners:textColor': expect.any(Object),
'banners:linkColor': expect.any(Object),
'banners:backgroundColor': expect.any(Object),
});
});
@ -50,6 +52,7 @@ describe('registerSettings', () => {
placement: 'top',
backgroundColor: '#FF00CC',
textColor: '#AAFFEE',
linkColor: '#0B64DD',
textContent: 'Some text',
});
@ -66,6 +69,9 @@ describe('registerSettings', () => {
'banners:textColor': expect.objectContaining({
value: config.textColor,
}),
'banners:linkColor': expect.objectContaining({
value: config.linkColor,
}),
'banners:backgroundColor': expect.objectContaining({
value: config.backgroundColor,
}),

View file

@ -92,6 +92,29 @@ export const registerSettings = (uiSettings: UiSettingsServiceSetup, config: Ban
},
}),
},
'banners:linkColor': {
name: i18n.translate('xpack.banners.settings.linkColor.title', {
defaultMessage: 'Banner link color',
}),
description: i18n.translate('xpack.banners.settings.linkColor.description', {
defaultMessage: 'Set the color of the banner link. {subscriptionLink}',
values: {
subscriptionLink,
},
}),
category: ['banner'],
order: 4,
type: 'color',
value: config.linkColor,
requiresPageReload: true,
schema: schema.string({
validate: (color) => {
if (!isHexColor(color)) {
return `'banners:linkColor' must be an hex color`;
}
},
}),
},
'banners:backgroundColor': {
name: i18n.translate('xpack.banners.settings.backgroundColor.title', {
defaultMessage: 'Banner background color',
@ -103,7 +126,7 @@ export const registerSettings = (uiSettings: UiSettingsServiceSetup, config: Ban
},
}),
category: ['banner'],
order: 4,
order: 5,
type: 'color',
value: config.backgroundColor,
requiresPageReload: true,

View file

@ -11,7 +11,9 @@ export class BannersPageObject extends FtrService {
private readonly find = this.ctx.getService('find');
isTopBannerVisible() {
return this.find.existsByCssSelector('.header__topBanner .kbnUserBanner__container');
return this.find.existsByCssSelector(
'.header__topBanner [data-test-subj="bannerInnerWrapper"]'
);
}
async getTopBannerText() {
@ -19,7 +21,7 @@ export class BannersPageObject extends FtrService {
return '';
}
const bannerContainer = await this.find.byCssSelector(
'.header__topBanner .kbnUserBanner__container'
'.header__topBanner [data-test-subj="bannerInnerWrapper"]'
);
return bannerContainer.getVisibleText();
}