Skip to content

Commit

Permalink
[Next theme] Add modal to notify users of theme updates (#4715)
Browse files Browse the repository at this point in the history
* Feat (home): Add modal to introduce `next` theme changes

Copy and images provisional, for demo purposes only.

Signed-off-by: Josh Romero <[email protected]>

* revert unintended config change

Signed-off-by: Josh Romero <[email protected]>

* add changelog

Signed-off-by: Josh Romero <[email protected]>

* Disable new theme modal for functional tests

Signed-off-by: Josh Romero <[email protected]>

* add deep link to settings

and hide modal if v7 theme is in use

Signed-off-by: Josh Romero <[email protected]>

* add unit tests and fix imports

Signed-off-by: Josh Romero <[email protected]>

---------

Signed-off-by: Josh Romero <[email protected]>
  • Loading branch information
joshuarrrr authored Aug 31, 2023
1 parent 16b1e29 commit b846e80
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 5 deletions.
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

0 comments on commit b846e80

Please sign in to comment.