[8.8] Fixing User Profiles/Kibana.yml config light mode precedence logic (#158177) (#158210)

# Backport

This will backport the following commits from `main` to `8.8`:
- [Fixing User Profiles/Kibana.yml config light mode precedence logic
(#158177)](https://github.com/elastic/kibana/pull/158177)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT
[{"author":{"name":"Kurt","email":"kc13greiner@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-05-22T17:48:22Z","message":"Fixing
User Profiles/Kibana.yml config light mode precedence logic
(#158177)\n\n## Summary\r\n\r\nAfter changing the UserSettingService to
calculate darkmode and return\r\n`boolean | undefined` , the Rendering
service `darkMode` logic needed to\r\nbe updated to work when a User
chooses 'Light' which provides a 'false'\r\nvalue to the Rendering
service.\r\n\r\n## Testing\r\n\r\nFor Space Setting:\r\n\r\n1. Set Space
Adv. Setting to darkMode: true\r\n2. Set User Profile Setting to
'Light'\r\n3. Observe that Light mode takes precedence\r\n\r\nFor Config
setting:\r\n\r\n1. Set User Profile Setting to 'Dark'\r\n2. In
`kibana.yml` set `uiSettings.overrides.theme:darkMode: false`\r\n3.
Observe that Light mode takes
precedence","sha":"613b2d5034fc703e1fb3c596e4ca2a648566b4c6","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:Security","v8.9.0","v8.8.1"],"number":158177,"url":"https://github.com/elastic/kibana/pull/158177","mergeCommit":{"message":"Fixing
User Profiles/Kibana.yml config light mode precedence logic
(#158177)\n\n## Summary\r\n\r\nAfter changing the UserSettingService to
calculate darkmode and return\r\n`boolean | undefined` , the Rendering
service `darkMode` logic needed to\r\nbe updated to work when a User
chooses 'Light' which provides a 'false'\r\nvalue to the Rendering
service.\r\n\r\n## Testing\r\n\r\nFor Space Setting:\r\n\r\n1. Set Space
Adv. Setting to darkMode: true\r\n2. Set User Profile Setting to
'Light'\r\n3. Observe that Light mode takes precedence\r\n\r\nFor Config
setting:\r\n\r\n1. Set User Profile Setting to 'Dark'\r\n2. In
`kibana.yml` set `uiSettings.overrides.theme:darkMode: false`\r\n3.
Observe that Light mode takes
precedence","sha":"613b2d5034fc703e1fb3c596e4ca2a648566b4c6"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/158177","number":158177,"mergeCommit":{"message":"Fixing
User Profiles/Kibana.yml config light mode precedence logic
(#158177)\n\n## Summary\r\n\r\nAfter changing the UserSettingService to
calculate darkmode and return\r\n`boolean | undefined` , the Rendering
service `darkMode` logic needed to\r\nbe updated to work when a User
chooses 'Light' which provides a 'false'\r\nvalue to the Rendering
service.\r\n\r\n## Testing\r\n\r\nFor Space Setting:\r\n\r\n1. Set Space
Adv. Setting to darkMode: true\r\n2. Set User Profile Setting to
'Light'\r\n3. Observe that Light mode takes precedence\r\n\r\nFor Config
setting:\r\n\r\n1. Set User Profile Setting to 'Dark'\r\n2. In
`kibana.yml` set `uiSettings.overrides.theme:darkMode: false`\r\n3.
Observe that Light mode takes
precedence","sha":"613b2d5034fc703e1fb3c596e4ca2a648566b4c6"}},{"branch":"8.8","label":"v8.8.1","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Kurt <kc13greiner@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2023-05-22 14:53:57 -04:00 committed by GitHub
parent cfef093567
commit 670772197d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 182 additions and 16 deletions

View file

@ -209,7 +209,7 @@ function renderDarkModeTestCases(
});
describe('Dark Mode', () => {
it('UserSettings value should override the space setting', async () => {
it('UserSettings darkMode === true should override the space setting', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(true)
);
@ -235,6 +235,32 @@ function renderDarkModeTestCases(
});
});
it('UserSettings darkMode === false should override the space setting', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(false)
);
getSettingValueMock.mockImplementation((settingName: string) => {
if (settingName === 'theme:darkMode') {
return true;
}
return settingName;
});
const settings = { 'theme:darkMode': { userValue: false } };
uiSettings.client.getUserProvided.mockResolvedValue(settings);
const [render] = await getRender();
await render(createKibanaRequest(), uiSettings);
expect(getStylesheetPathsMock).toHaveBeenCalledWith({
darkMode: false,
themeVersion: 'v8',
basePath: '/mock-server-basepath',
buildNum: expect.any(Number),
});
});
it('Space setting value should be used if UsersSettings value is undefined', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(undefined)
@ -258,6 +284,102 @@ function renderDarkModeTestCases(
buildNum: expect.any(Number),
});
});
it('config `theme:darkMode: true` setting should override User Settings theme `darkMode === false', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(false)
);
getSettingValueMock.mockImplementation((settingName: string) => {
if (settingName === 'theme:darkMode') {
return true;
}
return settingName;
});
const settings = { 'theme:darkMode': { userValue: true, isOverridden: true } };
uiSettings.client.getUserProvided.mockResolvedValue(settings);
const [render] = await getRender();
await render(createKibanaRequest(), uiSettings);
expect(getStylesheetPathsMock).toHaveBeenCalledWith({
darkMode: true,
themeVersion: 'v8',
basePath: '/mock-server-basepath',
buildNum: expect.any(Number),
});
});
it('config `theme:darkMode: false` setting should override User Settings theme `darkMode === true', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(true)
);
getSettingValueMock.mockImplementation((settingName: string) => {
if (settingName === 'theme:darkMode') {
return false;
}
return settingName;
});
const settings = { 'theme:darkMode': { userValue: false, isOverridden: true } };
uiSettings.client.getUserProvided.mockResolvedValue(settings);
const [render] = await getRender();
await render(createKibanaRequest(), uiSettings);
expect(getStylesheetPathsMock).toHaveBeenCalledWith({
darkMode: false,
themeVersion: 'v8',
basePath: '/mock-server-basepath',
buildNum: expect.any(Number),
});
});
it('config `theme:darkMode: false` setting should override User Settings theme `darkMode === undefined', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(undefined)
);
getSettingValueMock.mockImplementation((settingName: string) => {
if (settingName === 'theme:darkMode') {
return false;
}
return settingName;
});
const settings = { 'theme:darkMode': { userValue: false, isOverridden: true } };
uiSettings.client.getUserProvided.mockResolvedValue(settings);
const [render] = await getRender();
await render(createKibanaRequest(), uiSettings);
expect(getStylesheetPathsMock).toHaveBeenCalledWith({
darkMode: false,
themeVersion: 'v8',
basePath: '/mock-server-basepath',
buildNum: expect.any(Number),
});
});
it('config `theme:darkMode: true` setting should override User Settings theme `darkMode === undefined', async () => {
mockRenderingSetupDeps.userSettings.getUserSettingDarkMode.mockReturnValueOnce(
Promise.resolve(undefined)
);
getSettingValueMock.mockImplementation((settingName: string) => {
if (settingName === 'theme:darkMode') {
return true;
}
return settingName;
});
const settings = { 'theme:darkMode': { userValue: true, isOverridden: true } };
uiSettings.client.getUserProvided.mockResolvedValue(settings);
const [render] = await getRender();
await render(createKibanaRequest(), uiSettings);
expect(getStylesheetPathsMock).toHaveBeenCalledWith({
darkMode: true,
themeVersion: 'v8',
basePath: '/mock-server-basepath',
buildNum: expect.any(Number),
});
});
});
});
}

View file

@ -167,7 +167,9 @@ export class RenderingService {
let darkMode: boolean;
if (userSettingDarkMode) {
const isThemeOverridden = settings.user['theme:darkMode']?.isOverridden ?? false;
if (userSettingDarkMode !== undefined && !isThemeOverridden) {
darkMode = userSettingDarkMode;
} else {
darkMode = getSettingValue('theme:darkMode', settings, Boolean);

View file

@ -310,7 +310,7 @@ describe('useUserProfileForm', () => {
);
});
it('should be disabled if the theme has been set in the config', () => {
it('should be disabled if the theme has been set to `darkMode: true` in the config', () => {
const data: UserProfileData = {};
const nonCloudUser = mockAuthenticatedUser({ elastic_cloud_user: false });
@ -336,5 +336,32 @@ describe('useUserProfileForm', () => {
expect(darkModeButton).toBeTruthy();
expect(darkModeButton.getDOMNode()).toHaveProperty('disabled');
});
it('should be disabled if the theme has been set to `darkMode: false` in the config', () => {
const data: UserProfileData = {};
const nonCloudUser = mockAuthenticatedUser({ elastic_cloud_user: false });
coreStart.settings.client.get.mockReturnValueOnce(false);
coreStart.settings.client.isOverridden.mockReturnValueOnce(true);
const testWrapper = mount(
<Providers
services={coreStart}
theme$={theme$}
history={history}
authc={authc}
securityApiClients={{
userProfiles: new UserProfileAPIClient(coreStart.http),
users: new UserAPIClient(coreStart.http),
}}
>
<UserProfile user={nonCloudUser} data={data} />
</Providers>
);
const darkModeButton = testWrapper.find('EuiButtonGroup[data-test-subj="darkModeButton"]');
expect(darkModeButton).toBeTruthy();
expect(darkModeButton.getDOMNode()).toHaveProperty('disabled');
});
});
});

View file

@ -144,10 +144,12 @@ function UserDetailsEditor({ user }: { user: AuthenticatedUser }) {
function UserSettingsEditor({
formik,
isDarkModeOverride,
isThemeOverridden,
isOverriddenThemeDarkMode,
}: {
formik: ReturnType<typeof useUserProfileForm>;
isDarkModeOverride: boolean;
isThemeOverridden: boolean;
isOverriddenThemeDarkMode: boolean;
}) {
if (!formik.values.data) {
return null;
@ -155,8 +157,12 @@ function UserSettingsEditor({
let idSelected = formik.values.data.userSettings.darkMode;
if (isDarkModeOverride) {
idSelected = 'dark';
if (isThemeOverridden) {
if (isOverriddenThemeDarkMode) {
idSelected = 'dark';
} else {
idSelected = 'light';
}
}
return (
@ -180,7 +186,7 @@ function UserSettingsEditor({
>
<FormRow
name="data.userSettings.darkMode"
helpText={renderHelpText(isDarkModeOverride)}
helpText={renderHelpText(isThemeOverridden)}
label={
<FormLabel for="data.userSettings.darkMode">
<FormattedMessage
@ -201,7 +207,7 @@ function UserSettingsEditor({
buttonSize="m"
data-test-subj="darkModeButton"
idSelected={idSelected}
isDisabled={isDarkModeOverride}
isDisabled={isThemeOverridden}
options={[
{
id: '',
@ -546,7 +552,9 @@ export const UserProfile: FunctionComponent<UserProfileProps> = ({ user, data })
const isCloudUser = user.elastic_cloud_user;
const isDarkModeOverride = determineIfDarkModeOverride(services.settings.client);
const { isThemeOverridden, isOverriddenThemeDarkMode } = determineIfThemeOverridden(
services.settings.client
);
const rightSideItems = [
{
@ -675,7 +683,11 @@ export const UserProfile: FunctionComponent<UserProfileProps> = ({ user, data })
onShowPasswordForm={() => setShowChangePasswordForm(true)}
/>
{isCloudUser ? null : (
<UserSettingsEditor formik={formik} isDarkModeOverride={isDarkModeOverride} />
<UserSettingsEditor
formik={formik}
isThemeOverridden={isThemeOverridden}
isOverriddenThemeDarkMode={isOverriddenThemeDarkMode}
/>
)}
</Form>
</EuiPageTemplate>
@ -910,9 +922,12 @@ function renderHelpText(isOverridden: boolean) {
}
}
function determineIfDarkModeOverride(settingsClient: IUiSettingsClient) {
const isThemeOverridden = settingsClient.isOverridden('theme:darkMode');
const isOverriddenThemeDarkMode = settingsClient.get<boolean>('theme:darkMode');
return isThemeOverridden && isOverriddenThemeDarkMode;
function determineIfThemeOverridden(settingsClient: IUiSettingsClient): {
isThemeOverridden: boolean;
isOverriddenThemeDarkMode: boolean;
} {
return {
isThemeOverridden: settingsClient.isOverridden('theme:darkMode'),
isOverriddenThemeDarkMode: settingsClient.get<boolean>('theme:darkMode'),
};
}