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

New homepage #5613

Closed
wants to merge 67 commits into from
Closed

New homepage #5613

wants to merge 67 commits into from

Conversation

BSFishy
Copy link
Contributor

@BSFishy BSFishy commented Dec 14, 2023

Description

Implements the new homepage design. The scope of this change is limited to the structure of the page and configuration through saved objects. Better configuration and more features will be added in subsequent PRs.

Issues Resolved

Closes #4966
Closes #5251

Screenshot

Screenshot (199)

Testing the changes

Unit tests have been implemented for the section type API, to ensure that the service works as expected.

Check List

  • All tests pass
    • yarn test:jest
    • yarn test:jest_integration
  • New functionality includes testing.
  • New functionality has been documented.
  • Update CHANGELOG.md
  • Commits are signed per the DCO using --signoff

Copy link

codecov bot commented Dec 14, 2023

Codecov Report

Attention: 47 lines in your changes are missing coverage. Please review.

Comparison is base (058dfbc) 67.03% compared to head (9e0d5b3) 67.03%.
Report is 22 commits behind head on main.

Files Patch % Lines
.../home/public/services/section_type/section_type.ts 70.00% 12 Missing and 3 partials ⚠️
...on/components/homepage/sections/work_with_data.tsx 25.00% 9 Missing ⚠️
...tion/components/homepage/sections/learn_basics.tsx 30.00% 7 Missing ⚠️
src/plugins/home/public/plugin.ts 50.00% 4 Missing ⚠️
.../public/services/section_type/section_type.mock.ts 63.63% 4 Missing ⚠️
src/plugins/home/server/saved_objects/homepage.ts 25.00% 3 Missing ⚠️
...application/components/homepage/sections/utils.tsx 33.33% 2 Missing ⚠️
...ved_objects_management/public/register_services.ts 0.00% 1 Missing and 1 partial ⚠️
...gins/home/public/saved_homepage/_saved_homepage.ts 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5613      +/-   ##
==========================================
- Coverage   67.03%   67.03%   -0.01%     
==========================================
  Files        3296     3304       +8     
  Lines       63343    63456     +113     
  Branches    10087    10104      +17     
==========================================
+ Hits        42465    42536      +71     
- Misses      18429    18462      +33     
- Partials     2449     2458       +9     
Flag Coverage Δ
Linux_1 35.16% <7.29%> (-0.07%) ⬇️
Linux_2 55.18% <ø> (ø)
Linux_3 43.83% <7.52%> (-0.10%) ⬇️
Linux_4 35.42% <58.77%> (+0.09%) ⬆️
Windows_1 35.19% <7.29%> (-0.07%) ⬇️
Windows_2 55.15% <ø> (ø)
Windows_3 43.83% <7.52%> (-0.10%) ⬇️
Windows_4 35.42% <58.77%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

src/plugins/home/public/application/components/home_app.js Outdated Show resolved Hide resolved
export const homepageSavedObjectType: SavedObjectsType = {
name: 'homepage',
hidden: false,
namespaceType: 'single',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably look into if this is correct or if this value should be something different

Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
Signed-off-by: Matt Provost <[email protected]>
AMoo-Miki
AMoo-Miki previously approved these changes Jan 24, 2024
telemetry={telemetry}
/>
</Route>
{homeConfig.disableNextHomePage ? (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If disabled, shall we register the new homepage? From the consume logic, it is more like isNextHomePageDefaultIndexPage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was implemented like this after a discussion with @AMoo-Miki. I'm open to different naming, but I think disableNextHomePage is less confusing. The majority of users are going to just go to the default route, so it effectively functions the same

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, just concern on if we should register the useless route.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The route is not useless, as it needs to be viewable when "off" so that an admin or user can preview it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the confusion now. I've renamed it to something that better reflects its functionality.

Signed-off-by: Matt Provost <[email protected]>
Comment on lines +216 to +218
// TODO: is there a better way to check if the title is custom?
const title =
branding.applicationTitle !== 'OpenSearch Dashboards'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprisingly no. Different parts of the code consider the default title to be varying cases of this. Since this is what every other place is using, it should be safe enough.

Copy link
Member

@ashwin-pc ashwin-pc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say, for your first real contribution to OSD and considering the size of the PR and the number of not very well-documented features that you've touched here, this is a phenomenally well-written PR. All my comments are nitpicking stuff except for the navigation API change. I did not expect that. Great job! I even played around with the UI and found no issues no matter which way I pushed it. Did not see that coming.

@@ -0,0 +1,9 @@
.home-homepage-pageBody {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
.home-homepage-pageBody {
.homepagePage {

following BEM

<RedirectAppLinks application={application}>
<EuiButtonEmpty
flush="both"
href={getUrlForApp('management', { path: 'opensearch-dashboards/settings#defaultRoute' })}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to do this for all links since they are internal links and this is how you trigger SPA routing

Suggested change
href={getUrlForApp('management', { path: 'opensearch-dashboards/settings#defaultRoute' })}
onClick={() => navigateToApp('management', { path: 'opensearch-dashboards/settings#defaultRoute' })}

Comment on lines +27 to +28
const getUrlForApp = application.getUrlForApp;
const { show, save } = application.capabilities.advancedSettings ?? {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const getUrlForApp = application.getUrlForApp;
const { show, save } = application.capabilities.advancedSettings ?? {};
const { navigateToApp, capabilities } = application;
const { show, save } = capabilities.advancedSettings ?? {};

error$.next(undefined);

// TODO: make this debounce time configurable
const combinedSave$ = combineLatest([heroes$, sections$]).pipe(debounceTime(1000));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
const combinedSave$ = combineLatest([heroes$, sections$]).pipe(debounceTime(1000));
const combinedSections$ = combineLatest([heroes$, sections$]).pipe(debounceTime(1000));

const subscriptions = new Subscription();

this.fetchHomepageData()
.then((homepage) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
.then((homepage) => {
.then((homepageSavedObj) => {

id: (opts.id as string) || '',
defaults: {
heroes: [],
sections: [{ id: 'home:workWithData' }, { id: 'home:learnBasics' }],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was wondering how you'd initialize it. Nice!

Comment on lines +20 to +29
const Card: FC<{
imgSrc: string;
imgAlt: string;
title: string;
description: string;
footerButtonProps?: EuiButtonProps;
footerUrl: string;
footerText: string;
footerExternal?: boolean;
}> = ({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
const Card: FC<{
imgSrc: string;
imgAlt: string;
title: string;
description: string;
footerButtonProps?: EuiButtonProps;
footerUrl: string;
footerText: string;
footerExternal?: boolean;
}> = ({
interface CardProps {
imgSrc: string;
imgAlt: string;
title: string;
description: string;
footer: {
buttonProps?: EuiButtonProps;
url: string;
text: string;
external?: boolean;
};
}
const Card: FC<CardProps> = ({

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, i like this pattern. Nit, could use some tests

const sideItems: React.ReactNode[] = [
<EuiButtonEmpty
iconType="wrench"
href={getUrlForApp('dev_tools', { path: '#/console' })}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, use navigateToApp

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ashwin-pc, to expedite this, can you please make the suggestion and then accept it?

const homepage: SavedHomepage = await this.savedHomepageLoader.get(id);

if (!id) {
await homepage.save({});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if save() fail here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in getHomepage (The function that eventually calls this) he's called out about how errors need to be tested. I dont think he got to that in this iteration. I also see that he's throwing all the errors which mean that its up to the parent function to catch it and handle them. Dont think they are being handled here.

const homepage = sectionTypes.getHomepage();

const subscriptions = new Subscription();
subscriptions.add(homepage.heroes$.subscribe(setHeroes));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am confused on why we need to add subscriptions on sections and heroes here? Are these built for the functionalities of allowing users to add and delete sections or heroes in the future?

Because currently I see the implementation exposes the registerSection service API to allow other plugins to register sections or heroes, and it seems like for rendering something like the homepage, we can just fetch all the registered sections and heroes at the start of the application, and render the page all at once without the need of constant listening on them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the goal is to allow the user to modify these sections and customize the homepage. This PR does not have the editing capability just yet, but it does lay down the plumbing.

sections: SerializedSection[] | SerializedSection;
}

export function createSavedHomepageClass(services: SavedObjectOpenSearchDashboardsServices) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering why we need to introduce the saved object logic for implementing new homepage.

It seems like currently the concept of saved object within dashboard does not really associate with an entire page. And it also makes the homepage harder to maintain because of the possible saved object migrations.

I am wondering

  1. why can't we use a simpler route such as utilizing the configuiSettings for saving homepage instead of creating a new saved object such as below; and the _id here also stores the version so we do not need to worry about versioning.
{
        "_index": ".kibana_1",
        "_id": "config:2.12.0",
        "_score": 1,
        "_source": {
          "config": {
            "buildNum": 221231,
            "defaultIndex": "ff959d40-b880-11e8-a6d9-e546fe2bba5f"
          },
          "type": "config",
          "references": [],
          "migrationVersion": {
            "config": "7.9.0"
          },
          "updated_at": "2024-02-22T02:15:31.504Z"
        }
      }
  1. or why cant we save user specific configs using browser storage as the source of truth that is referenced in this PR Feat (core): Make theme settings user-specific and user-configurable #5652?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think i understood your comment about uiSettings. How does that work? How does that differ from Saved Objects?

Also Isnt the homepage just a glorified Dashboard? And that uses saved objects to figure out which embeddable to show and where. The homepage saved object does something similar too. Yes there will be a migration, but that will be needed wherever the user needs to be able to configure their own data.

As for briwser storage. The homepage needs to be tied to a user or workspace. It has to follow them no matter where they login. The PR you reference saves that in local storage which cannot do that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think at first i did not understand why we need to introduce the saved object concept into homepage, i thought it is just a page that needs to be rendered once when starting up the application. And then if we needed to save some user configuration, maybe we can just do something like uiSettings.set("useHomePage", true), and if we need to see which homepage users want to use, we do uiSettings.get("useHomePage")

So after looking at your explanations, it seems like we want to make the homepage more configurable to the user, and almost similar to the concept of a dashboard, where user can create their own homepage, add or remove different sections to it, and save it, and that is why we want to use saved object, correct? @ashwin-pc

}

export interface Homepage {
heroes$: Observable<HeroSection[] | undefined>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the hero, why would happen if multiple different plugin register hero for themselves, which hero should we display? In my understanding, we should just display one hero per screen?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think that was a requirement. Maybe based on how the homepage evolves we may restrict that. cc @kgcreative ?

@abbyhu2000
Copy link
Member

@ashwin-pc Could you also link me the issue for adding a toggle in advanced setting for the new home page?

Currently, i see we can toggle this feature in the yml file; do we wanna switch the toggle to advance setting toggle, or do we wanna keep both toggles? If we keep both, what if user toggle differently for two toggles?

@abbyhu2000 abbyhu2000 mentioned this pull request Mar 7, 2024
7 tasks
@ashwin-pc
Copy link
Member

closing the PR since #6065 has been merged. Thats the same PR, just that the toggle has moved from the yaml config to the advanced settings.

@ashwin-pc ashwin-pc closed this Mar 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[RFC] New Homepage Technical Design [Look and Feel] New Home Page Experience
8 participants