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

[Next theme] Add modal to notify users of theme updates #4715

Merged
merged 11 commits into from
Aug 31, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Saved Object Service] Customize saved objects service status ([#4696](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4696))
- Remove minimum constraint on opensearch hosts to allow empty host ([#4701](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4701))
- [Discover] Update styles to compatible with OUI `next` theme ([#4644](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4644))
- [Home] Add modal to introduce the `next` theme ([#4715](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4715))
- Remove visualization editor sidebar background ([#4719](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4719))
- [Vis Colors] Remove customized colors from sample visualizations and dashboards ([#4741](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4741))
- [Decouple] Allow plugin manifest config to define semver compatible OpenSearch plugin and verify if it is installed on the cluster([#4612](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4612))
Expand Down
7 changes: 6 additions & 1 deletion config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
# The default application to load.
#opensearchDashboards.defaultAppId: "home"

# Set the value to true to disable the welcome screen
#home.disableWelcomeScreen: false

# Set the value to true to disable the new theme introduction modal
#home.disableNewThemeModal: false

# Setting for an optimized healthcheck that only uses the local OpenSearch node to do Dashboards healthcheck.
# This settings should be used for large clusters or for clusters with ingest heavy nodes.
# It allows Dashboards to only healthcheck using the local OpenSearch node rather than fan out requests across all nodes.
Expand Down Expand Up @@ -267,4 +273,3 @@

# Set the value of this setting to true to enable plugin augmentation on Dashboard
# vis_augmenter.pluginAugmentationEnabled: true

1 change: 1 addition & 0 deletions src/plugins/home/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { schema, TypeOf } from '@osd/config-schema';

export const configSchema = schema.object({
disableWelcomeScreen: schema.boolean({ defaultValue: false }),
disableNewThemeModal: schema.boolean({ defaultValue: false }),
});

export type ConfigSchema = TypeOf<typeof configSchema>;

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions src/plugins/home/public/application/components/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ import { FeatureCatalogueCategory } from '../../services';
import { getServices } from '../opensearch_dashboards_services';
import { AddData } from './add_data';
import { ManageData } from './manage_data';
import { NewThemeModal } from './new_theme_modal';
import { SolutionsSection } from './solutions_section';
import { Welcome } from './welcome';

const KEY_ENABLE_WELCOME = 'home:welcome:show';
const KEY_ENABLE_NEW_THEME_MODAL = 'home:newThemeModal:show';

export class Home extends Component {
constructor(props) {
Expand All @@ -56,6 +58,12 @@ export class Home extends Component {
props.localStorage.getItem(KEY_ENABLE_WELCOME) === 'false'
);

const isNewThemeModalEnabled = !(
getServices().uiSettings.get('theme:version') === 'v7' ||
getServices().homeConfig.disableNewThemeModal ||
props.localStorage.getItem(KEY_ENABLE_NEW_THEME_MODAL) === 'false'
);

const body = document.querySelector('body');
body.classList.add('isHomPage');

Expand All @@ -67,6 +75,7 @@ export class Home extends Component {
isLoading: isWelcomeEnabled,
isNewOpenSearchDashboardsInstance: false,
isWelcomeEnabled,
isNewThemeModalEnabled,
};
}

Expand Down Expand Up @@ -122,6 +131,15 @@ export class Home extends Component {
this._isMounted && this.setState({ isWelcomeEnabled: false });
};

dismissNewThemeModal = () => {
this.props.localStorage.setItem(KEY_ENABLE_NEW_THEME_MODAL, 'false');
this._isMounted && this.setState({ isNewThemeModalEnabled: false });
};

onCloseNewThemeModal = () => {
this.dismissNewThemeModal();
};

findDirectoryById = (id) => this.props.directories.find((directory) => directory.id === id);

getFeaturesByCategory = (category) =>
Expand All @@ -131,6 +149,7 @@ export class Home extends Component {

renderNormal() {
const { addBasePath, solutions, directories } = this.props;
const { isNewThemeModalEnabled } = this.state;

const devTools = this.findDirectoryById('console');
const addDataFeatures = this.getFeaturesByCategory(FeatureCatalogueCategory.DATA);
Expand Down Expand Up @@ -185,6 +204,10 @@ export class Home extends Component {

<EuiHorizontalRule margin="xl" aria-hidden="true" />

{isNewThemeModalEnabled && (
<NewThemeModal addBasePath={addBasePath} onClose={this.onCloseNewThemeModal} />
)}

<OverviewPageFooter addBasePath={addBasePath} path={HOME_APP_BASE_PATH} />
</div>
</main>
Expand Down
71 changes: 67 additions & 4 deletions src/plugins/home/public/application/components/home.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,27 @@ import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import { Home } from './home';
import { NewThemeModal } from './new_theme_modal';

import { FeatureCatalogueCategory } from '../../services';

const mockHomeConfig = jest.fn();
const mockUiSettings = jest.fn();

jest.mock('../opensearch_dashboards_services', () => ({
getServices: () => ({
getBasePath: () => 'path',
tutorialVariables: () => ({}),
homeConfig: { disableWelcomeScreen: false },
homeConfig: mockHomeConfig(),
chrome: {
setBreadcrumbs: () => {},
},
injectedMetadata: {
getBranding: () => ({}),
},
uiSettings: {
get: () => mockUiSettings(),
},
}),
}));

Expand Down Expand Up @@ -80,7 +87,7 @@ describe('home', () => {
},
localStorage: {
getItem: sinon.spy((path) => {
expect(path).toEqual('home:welcome:show');
expect(path).toMatch(/home:(welcome|newThemeModal):show/);
return 'false';
}),
setItem: sinon.mock(),
Expand All @@ -93,7 +100,17 @@ describe('home', () => {
};
});

async function renderHome(props = {}) {
async function renderHome(props = {}, homeConfig, uiSettings) {
if (homeConfig) {
mockHomeConfig.mockReturnValue(homeConfig);
} else {
mockHomeConfig.mockReturnValue({ disableWelcomeScreen: false, disableNewThemeModal: false });
}
if (uiSettings) {
mockUiSettings.mockReturnValue(uiSettings);
} else {
mockUiSettings.mockReturnValue('v8');
}
const component = shallow(<Home {...defaultProps} {...props} />);

// Ensure all promises resolve
Expand Down Expand Up @@ -284,7 +301,7 @@ describe('home', () => {
find: () => Promise.resolve({ total: 0 }),
});

sinon.assert.calledOnce(defaultProps.localStorage.getItem);
sinon.assert.calledWith(defaultProps.localStorage.getItem, 'home:welcome:show');

expect(component).toMatchSnapshot();
});
Expand Down Expand Up @@ -350,4 +367,50 @@ describe('home', () => {
expect(component).toMatchSnapshot();
});
});

describe('new theme modal', () => {
test('should show the new theme modal if not previously dismissed', async () => {
defaultProps.localStorage.getItem = sinon.spy(() => undefined);

const component = await renderHome();

sinon.assert.calledWith(defaultProps.localStorage.getItem, 'home:newThemeModal:show');

expect(component.find(NewThemeModal).exists()).toBeTruthy();
expect(component).toMatchSnapshot();
});
test('should not show the new theme modal if v7 theme in use', async () => {
defaultProps.localStorage.getItem = sinon.spy(() => undefined);

const component = await renderHome({}, undefined, 'v7');

sinon.assert.neverCalledWith(defaultProps.localStorage.getItem, 'home:newThemeModal:show');

expect(component.find(NewThemeModal).exists()).toBeFalsy();
});
test('should not show the new theme modal if disabled in config', async () => {
defaultProps.localStorage.getItem = sinon.spy(() => undefined);

const component = await renderHome(
{},
{
disableWelcomeScreen: true,
disableNewThemeModal: true,
}
);

sinon.assert.neverCalledWith(defaultProps.localStorage.getItem, 'home:newThemeModal:show');

expect(component.find(NewThemeModal).exists()).toBeFalsy();
});
test('should not show the new theme modal if previously dismissed', async () => {
defaultProps.localStorage.getItem = sinon.spy(() => 'false');

const component = await renderHome();

sinon.assert.calledWith(defaultProps.localStorage.getItem, 'home:newThemeModal:show');

expect(component.find(NewThemeModal).exists()).toBeFalsy();
});
});
});
Loading