Skip to content

Commit

Permalink
Preparation for High Contrast Mode, Security domains
Browse files Browse the repository at this point in the history
  • Loading branch information
tsullivan committed Dec 2, 2024
1 parent 6c0cf0e commit 176a825
Show file tree
Hide file tree
Showing 28 changed files with 114 additions and 18 deletions.
4 changes: 2 additions & 2 deletions packages/kbn-mock-idp-plugin/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const plugin: PluginInitializer<
]);

ReactDOM.render(
<KibanaThemeProvider theme={coreStart.theme}>
<KibanaThemeProvider {...coreStart}>
<KibanaContextProvider services={coreStart}>
<I18nProvider>
<LoginPage />
Expand All @@ -69,7 +69,7 @@ export const plugin: PluginInitializer<
order: 4000 + 1, // Make sure it comes after the user menu
mount: (element: HTMLElement) => {
ReactDOM.render(
<KibanaThemeProvider theme={coreStart.theme}>
<KibanaThemeProvider {...coreStart}>
<KibanaContextProvider services={coreStart}>
<I18nProvider>
<RoleSwitcher />
Expand Down
4 changes: 3 additions & 1 deletion packages/kbn-mock-idp-plugin/public/reload_page_toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import React from 'react';
import type { I18nStart } from '@kbn/core-i18n-browser';
import type { ToastInput } from '@kbn/core-notifications-browser';
import type { ThemeServiceStart } from '@kbn/core-theme-browser';
import type { UserProfileService } from '@kbn/core-user-profile-browser';
import { toMountPoint } from '@kbn/react-kibana-mount';
import type { AuthenticatedUser } from '@kbn/security-plugin-types-common';

Expand All @@ -26,6 +27,7 @@ export const DATA_TEST_SUBJ_PAGE_RELOAD_BUTTON = 'pageReloadButton';
*/
export const createReloadPageToast = (options: {
user: Pick<AuthenticatedUser, 'roles'>;
userProfile: UserProfileService;
theme: ThemeServiceStart;
i18n: I18nStart;
}): ToastInput => {
Expand All @@ -43,7 +45,7 @@ export const createReloadPageToast = (options: {
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>,
{ i18n: options.i18n, theme: options.theme }
options
),
color: 'success',
toastLifeTimeMs: 0x7fffffff, // Do not auto-hide toast since page is in an unknown state
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-mock-idp-plugin/public/role_switcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const RoleSwitcher = () => {
services.notifications.toasts.add(
createReloadPageToast({
user: authenticateUserState.value,
userProfile: services.userProfile,
theme: services.theme,
i18n: services.i18n,
})
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-mock-idp-plugin/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"@kbn/mock-idp-utils",
"@kbn/cloud-plugin",
"@kbn/es",
"@kbn/core-user-profile-browser",
]
}
1 change: 1 addition & 0 deletions packages/kbn-user-profile-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type {
export type {
UserProfileData,
UserSettingsData,
ContrastModeValue,
DarkModeValue,
UserProfileAvatarData,
} from './src/types';
Expand Down
6 changes: 4 additions & 2 deletions packages/kbn-user-profile-components/src/services.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import React, { useContext } from 'react';
import type { I18nStart } from '@kbn/core-i18n-browser';
import type { NotificationsStart, ToastOptions } from '@kbn/core-notifications-browser';
import type { ThemeServiceStart } from '@kbn/core-theme-browser';
import type { UserProfileService } from '@kbn/core-user-profile-browser';
import type { toMountPoint } from '@kbn/react-kibana-mount';

import type { UserProfileAPIClient } from './types';
Expand Down Expand Up @@ -47,6 +48,7 @@ export interface UserProfilesKibanaDependencies {
core: {
notifications: NotificationsStart;
theme: ThemeServiceStart;
userProfile: UserProfileService;
i18n: I18nStart;
};
security: {
Expand All @@ -70,7 +72,7 @@ export const UserProfilesKibanaProvider: FC<PropsWithChildren<UserProfilesKibana
...services
}) => {
const {
core: { notifications, i18n, theme },
core: { notifications, ...startServices },
security: { userProfiles: userProfileApiClient },
toMountPoint: toMountPointUtility,
} = services;
Expand All @@ -86,7 +88,7 @@ export const UserProfilesKibanaProvider: FC<PropsWithChildren<UserProfilesKibana
notifications.toasts.addSuccess(
{
title,
text: text ? toMountPointUtility(text, { i18n, theme }) : undefined,
text: text ? toMountPointUtility(text, startServices) : undefined,
},
toastOptions
);
Expand Down
3 changes: 3 additions & 0 deletions packages/kbn-user-profile-components/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ export interface UserProfileAvatarData {

export type DarkModeValue = '' | 'dark' | 'light';

export type ContrastModeValue = '' | 'standard' | 'high';

/**
* User settings stored in the data object of the User Profile
*/
export interface UserSettingsData {
darkMode?: DarkModeValue;
contrastMode?: ContrastModeValue;
solutionNavOptOut?: boolean;
}

Expand Down
1 change: 1 addition & 0 deletions packages/kbn-user-profile-components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@kbn/react-kibana-mount",
"@kbn/core-i18n-browser",
"@kbn/test-jest-helpers",
"@kbn/core-user-profile-browser",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ describe('useUserProfileForm', () => {
"initials": "fn",
},
"userSettings": Object {
"contrastMode": "standard",
"darkMode": "",
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
EuiKeyPadMenuItem,
EuiPopover,
EuiSpacer,
EuiSwitch,
EuiText,
EuiToolTip,
useEuiTheme,
Expand All @@ -49,7 +50,11 @@ import {
useFormChangesContext,
} from '@kbn/security-form-components';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import type { DarkModeValue, UserProfileData } from '@kbn/user-profile-components';
import type {
ContrastModeValue,
DarkModeValue,
UserProfileData,
} from '@kbn/user-profile-components';
import { UserAvatar, useUpdateUserProfile } from '@kbn/user-profile-components';

import { createImageHandler, getRandomColor, VALID_HEX_COLOR } from './utils';
Expand Down Expand Up @@ -104,6 +109,7 @@ export interface UserProfileFormValues {
};
userSettings: {
darkMode: DarkModeValue;
contrastMode: ContrastModeValue;
};
};
avatarType: 'initials' | 'image';
Expand Down Expand Up @@ -230,7 +236,7 @@ const UserSettingsEditor: FunctionComponent<UserSettingsEditorProps> = ({
<FormLabel for="data.userSettings.darkMode">
<FormattedMessage
id="xpack.security.accountManagement.userProfile.userSettings.theme"
defaultMessage="Mode"
defaultMessage="Color mode"
/>
</FormLabel>
),
Expand Down Expand Up @@ -276,6 +282,24 @@ const UserSettingsEditor: FunctionComponent<UserSettingsEditorProps> = ({
);
};

const idSelectedContrast = formik.values.data.userSettings.contrastMode;
const contrastModeMenu = () => {
return (
<EuiSwitch
id="contrastMode"
label={i18n.translate(
'xpack.security.accountManagement.userProfile.highContrastModeButton',
{ defaultMessage: 'High contrast' }
)}
checked={idSelectedContrast === 'high'}
onChange={({ target }) => {
const value = target.checked ? 'high' : 'standard';
return formik.setFieldValue('data.userSettings.contrastMode', value);
}}
/>
);
};

return (
<EuiDescribedFormGroup
fullWidth
Expand All @@ -284,7 +308,7 @@ const UserSettingsEditor: FunctionComponent<UserSettingsEditorProps> = ({
<h2>
<FormattedMessage
id="xpack.security.accountManagement.userProfile.userSettingsTitle"
defaultMessage="Theme"
defaultMessage="Appearance"
/>
</h2>
}
Expand All @@ -298,6 +322,22 @@ const UserSettingsEditor: FunctionComponent<UserSettingsEditorProps> = ({
<FormRow name="data.userSettings.darkMode" fullWidth>
{themeMenu(isThemeOverridden)}
</FormRow>

<FormRow
name="data.userSettings.contrastMode"
fullWidth
label={
<FormLabel for="data.userSettings.contrastMode">
<FormattedMessage
id="xpack.security.accountManagement.userProfile.userSettings.contrastMode"
defaultMessage="Accessibility"
/>
</FormLabel>
}
hasChildLabel={false}
>
{contrastModeMenu()}
</FormRow>
</EuiDescribedFormGroup>
);
};
Expand Down Expand Up @@ -876,6 +916,7 @@ export function useUserProfileForm({ user, data }: UserProfileProps) {
},
userSettings: {
darkMode: data.userSettings?.darkMode || '',
contrastMode: data.userSettings?.contrastMode || 'standard',
},
}
: undefined,
Expand Down Expand Up @@ -928,7 +969,10 @@ export function useUserProfileForm({ user, data }: UserProfileProps) {
resetInitialValues(values);

let isRefreshRequired = false;
if (initialValues.data?.userSettings.darkMode !== values.data?.userSettings.darkMode) {
if (
initialValues.data?.userSettings.darkMode !== values.data?.userSettings.darkMode ||
initialValues.data?.userSettings.contrastMode !== values.data?.userSettings.contrastMode
) {
isRefreshRequired = true;
}
showSuccessNotification({ isRefreshRequired });
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/security/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ export const plugin: PluginInitializer<
> = (initializerContext: PluginInitializerContext) => new SecurityPlugin(initializerContext);

// services needed for rendering React using shared modules
export type StartServices = Pick<CoreStart, 'analytics' | 'i18n' | 'theme'>;
export type StartServices = Pick<CoreStart, 'analytics' | 'i18n' | 'theme' | 'userProfile'>;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { coreMock, scopedHistoryMock } from '@kbn/core/public/mocks';
import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks';
import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks';
import { themeServiceMock } from '@kbn/core-theme-browser-mocks';
import { userProfileServiceMock } from '@kbn/core-user-profile-browser-mocks';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { KibanaFeature } from '@kbn/features-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
Expand Down Expand Up @@ -196,6 +197,8 @@ function getProps({
const analyticsMock = analyticsServiceMock.createAnalyticsServiceStart();
const i18nMock = i18nServiceMock.createStartContract();
const themeMock = themeServiceMock.createStartContract();
const userProfileMock = userProfileServiceMock.createStart();

return {
action,
roleName: role?.name,
Expand All @@ -214,6 +217,7 @@ function getProps({
history: scopedHistoryMock.create(),
spacesApiUi,
buildFlavor,
userProfile: userProfileMock,
theme: themeMock,
i18n: i18nMock,
analytics: analyticsMock,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const waitForRender = async (
describe('<RolesGridPage />', () => {
let apiClientMock: jest.Mocked<PublicMethodsOf<RolesAPIClient>>;
let history: ReturnType<typeof scopedHistoryMock.create>;
const { theme, i18n, analytics, notifications } = coreMock.createStart();
const { userProfile, theme, i18n, analytics, notifications } = coreMock.createStart();

beforeEach(() => {
history = scopedHistoryMock.create();
Expand Down Expand Up @@ -93,6 +93,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
/>
);
const initialIconCount = wrapper.find(EuiIcon).length;
Expand All @@ -115,6 +116,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
/>
);
const initialIconCount = wrapper.find(EuiIcon).length;
Expand All @@ -139,6 +141,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
/>
);
await waitForRender(wrapper, (updatedWrapper) => {
Expand All @@ -157,6 +160,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
/>
);
const initialIconCount = wrapper.find(EuiIcon).length;
Expand Down Expand Up @@ -201,6 +205,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
/>
);
const initialIconCount = wrapper.find(EuiIcon).length;
Expand Down Expand Up @@ -332,6 +337,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
/>
);
const initialIconCount = wrapper.find(EuiIcon).length;
Expand Down Expand Up @@ -441,6 +447,7 @@ describe('<RolesGridPage />', () => {
buildFlavor={'traditional'}
analytics={analytics}
theme={theme}
userProfile={userProfile}
readOnly
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const RolesGridPage: FC<Props> = ({
buildFlavor,
cloudOrgUrl,
analytics,
userProfile,
theme,
i18n: i18nStart,
}) => {
Expand Down Expand Up @@ -409,6 +410,7 @@ export const RolesGridPage: FC<Props> = ({
notifications={notifications}
rolesAPIClient={rolesAPIClient}
buildFlavor={buildFlavor}
userProfile={userProfile}
theme={theme}
analytics={analytics}
i18n={i18nStart}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
I18nStart,
MountPoint,
ThemeServiceStart,
UserProfileService,
} from '@kbn/core/public';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
Expand All @@ -37,6 +38,7 @@ interface Deps {
analytics: Pick<AnalyticsServiceStart, 'reportEvent'>;
i18n: I18nStart;
theme: Pick<ThemeServiceStart, 'theme$'>;
userProfile: UserProfileService;
}

export const insecureClusterAlertText = (deps: Deps, onDismiss: (persist: boolean) => void) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
NotificationsStart,
ThemeServiceStart,
Toast,
UserProfileService,
} from '@kbn/core/public';

import { insecureClusterAlertText, insecureClusterAlertTitle } from './components';
Expand All @@ -33,6 +34,7 @@ interface StartDeps {
analytics: Pick<AnalyticsServiceStart, 'reportEvent'>;
i18n: I18nStart;
theme: Pick<ThemeServiceStart, 'theme$'>;
userProfile: UserProfileService;
}

const DEFAULT_SECURITY_CHECKUP_STATE = Object.freeze<SecurityCheckupState>({
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/security/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"@kbn/core-capabilities-server",
"@kbn/core-elasticsearch-server",
"@kbn/core-http-server-utils",
"@kbn/core-user-profile-browser-mocks",
],
"exclude": [
"target/**/*",
Expand Down
Loading

0 comments on commit 176a825

Please sign in to comment.