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

[Enterprise Search] Set up initial KibanaPageTemplate #102170

Merged
merged 10 commits into from
Jun 16, 2021

Conversation

cee-chen
Copy link
Member

@cee-chen cee-chen commented Jun 15, 2021

Summary

Despite my best attempts to make this a smaller PR, it's still on the larger side and should definitely be reviewed commit-by-commit.

  • High-level overview of the KibanaPageTemplate migration and why we're doing it/what we get out of it:
    • Visual consistency with other plugins/teams on Kibana (primarily around the solution nav and page headers)
    • Out of the box mobile responsiveness - we can (eventually) delete all our custom nav CSS/logic etc, including breakpoints, is mobile open state, a11y, etc. 🎉
    • Fixes that really annoying bug where if the telemetry callout is at the top of the page, the entire nav gets incorrectly offset (my personal favorite item on this list)
    • Per-view flexibility - we actually get even more flexibility to change certain layout props this way (e.g. per-page layout classes, if needed, as well as everything in EuiPageTemplate's props
    • Simpler & DRYer API - going forward, we won't need to manually include FlashMessages per-view, and things like page chrome & telemetry can now quickly be passed as simple props instead of requiring a component import
  • What this PR does:
    • Sets up a shared <EnterpriseSearchPageTemplate /> which will replace the old <Layout /> component and provides some nicer/DRYer APIs for things like a loading state, empty state, flash messages, and a built-in read only mode callout
    • Sets up product-specific <AppSearchPageTemplate /> and <WorkplaceSearchPageTemplate /> components which manage their own solution navs and provide some nicer/DRYer APIs for things like page chrome and page telemetry
    • Updates several navigation/routing helpers to work with plain objects (used by EuiSideNav items) instead of only React components
    • Adds some new test_helpers for inspecting nested page headers within page templates
    • Updates only the Users & Roles view to use the new page template
      • Why this view? Because it's one shared by both AS & WS and made for a pretty nice example of how views get cleaned/DRY'ed out with the new page template, and I figured @scottybollinger might as well get this now during his Role Mappings work to prevent future merge conflicts
  • What this PR does NOT do:
    • Affect any view that's not the Users & Roles / Role Mappings view
    • Set up any sub/nested navigation - that will be in future PRs
    • Delete any of the current custom Layout or SideNav components - that will be its own separate PR at the end of everything to allow granularly migrating batches of views at a time instead of all at once

Example code of what all views should generally look like, going forward:

export const SomePage: React.FC = () => {
  return (
    <AppSearchPageTemplate
      pageChrome={['Engines', 'some-engine', 'Some page']} // automatically sets AS breadcrumbs & page title
      pageViewTelemetry="some_page" // automatically fires a telemetry viewed event
      pageHeader={{
        pageTitle: 'Some page',
        description: <p>What the page does</p>,
        rightSideItems: [<EuiButton />],
      }}
    >
       Flash messages and read only mode state comes for free!
    </AppSearchPageTemplate>
  )
}

export const AnotherPage: React.FC = () => {
  const { dataLoading, hasItems } = useValues(SomeLogic);

  return (
    <WorkplaceSearchPageTemplate
      pageHeader={{ pageTitle: 'Another page' }}
      isLoading={dataLoading} // automatically renders a Loading component in place of the child content
      isEmptyState={!hasItems}
      emptyState={<EmptyState />} // e.g. some custom EuiCallOut - only renders in place of child content if isEmptyState is true
    >
       Non-empty content goes here!
    </AppSearchPageTemplate>
  )
}

Screenshots

AS

WS

Checklist

@cee-chen cee-chen added Feature:Plugins release_note:skip Skip the PR/issue when compiling release notes v7.14.0 auto-backport Deprecated - use backport:version if exact versions are needed labels Jun 15, 2021
@cee-chen
Copy link
Member Author

@elasticmachine merge upstream

@scottybollinger
Copy link
Contributor

@constancecchen I haven't pushed it up yet but deleting the role_mappings_heading.tsx component is going to break my feature. Both sections are identical and share the same heading. The design calls for identical sections and I opted to not have a EuiPageHeader on this page for that reason.

@cee-chen
Copy link
Member Author

Oooh, thanks Scotty, I totally missed that there's multiple headers on the same page. Super good call, let me rethink this and potentially run this by the EUI team for ideas.

FWIW there is a semantic and accessibility cost to losing the page header - your heading hierarchy gets messed up (e.g., no single parent h1 on the page) so we should definitely think carefully about changing that pattern (I assume that's the point of the KibanaPageTemplate).

That being said it's also totally possible to just pass in custom rendered JSX to pageHeader so I can definitely just do that if needed.

Copy link
Contributor

@byronhulcher byronhulcher left a comment

Choose a reason for hiding this comment

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

I'm rubber-stamping this so that it can be merged after @elastic/workplace-search-frontend's review + approval since we are lacking @elastic/app-search-frontend reviewers until next Monday. I have not reviewed or QA'd this code. This was discussed in a recent App Search sync with @richkuz. I trust @constancecchen has represented the interests of the App Search team on this PR.

@constancecchen did me a solid and reviewed another PR of mine before I went away on PTO so I did a high level review and QA below and re-affirmed this approval

@cee-chen
Copy link
Member Author

@byronhulcher If you have time after your Process Crawls work today to take a quick look at the API code example in the PR description and leave any developer experience feedback/requests that definitely would be appreciated, but if not please feel free to come back to this after your PTO and I can make any change requests retroactively/in a later PR 👍

@cee-chen
Copy link
Member Author

Also, no idea what's going on with CI but those files aren't related to this PR 👊

@cee-chen
Copy link
Member Author

@elasticmachine merge upstream

+ misc tech debt - create AS components/layout/index.ts for imports
- Update react_router_helpers to pass back props as a plain JS obj instead of only working with React components (+ update react components to use new simpler helper)

- Convert SideNavLink active logic to a plain JS helper
NYI: sub navigations (future separate PRs)
- primarily useful for rightSideItems, which often contain conditional logic
Minor refactors:
+ remove unnecessary type union
+ fix un-i18n'ed product names
+ add full stop to documentation sentence
+ add semantic HTML tags around various page landmarks (header, section)
@cee-chen
Copy link
Member Author

Apologies for the force push, in light of Scotty's comment I thought it best to start over on the Role Mappings conversion and limit the amount of diffs in that commit. @scottybollinger take a look at 4b1d526 and let me know what you think! Here's new screenshots of the views:

WS

AS

I think the only change in there now that I'm not sure will conflict with your current work is me removing the ProductName type union. If you really need that LMK and I'll add it back in, but specify our already i18n'd product name constants.

Copy link
Contributor

@byronhulcher byronhulcher left a comment

Choose a reason for hiding this comment

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

I did a quick review of this and also poked around locally. Code looks good and I didn't notice anything broken in QA. I left some non-blocking comments.

@@ -0,0 +1,36 @@
/*
Copy link
Contributor

@byronhulcher byronhulcher Jun 15, 2021

Choose a reason for hiding this comment

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

Should the filename of be closer to the exported component's name?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't feel super strongly either way, since this is namespaced (folder-wise... folder-spaced?) to app_search/ I don't think it's too confusing, but I know there's IDE implications to file-finding or showing tab names 🤷

FWIW I was kinda copying Workplace Search's folder architecture pattern here (they already have a layout/nav.tsx and layout/kibana_header_actions.tsx which we also now have our own version of), so I thought layout/page_template.tsx made sense as well 🤔

Definitely doesn't bother me either way though, so happy to revisit later if it's annoying down the road or if we want to circle back and do a vote

import { KibanaLogic } from '../kibana';
import { generateReactRouterProps, ReactRouterProps } from '../react_router_helpers';

interface Params {
Copy link
Contributor

@byronhulcher byronhulcher Jun 15, 2021

Choose a reason for hiding this comment

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

Should this interface have a more specific name?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've been using more generic type names (e.g. Props, Params) if they're not getting exported or reused externally. If they're used in other files, that's when I namespace them (e.g. PageTemplateProps, ReactRouterProps).

But otherwise it's to me it's kinda like not having to namespace isDocumentsLoading vs isAnalyticsLoading - the isLoading var name is scoped to the file or view, so it doesn't need to be overly specific.

The day I ever start using generic single letter variable names is the day you can hit me over the head with a shovel tho, gotta draw that line somewhere :trollface:

id: 'engines',
name: ENGINES_TITLE,
...generateNavLink({ to: ENGINES_PATH, isRoot: true }),
items: [], // TODO: Engine nav
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the plan for this TODO?

Copy link
Member Author

Choose a reason for hiding this comment

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

Upcoming PR!

Comment on lines +28 to +37
/*
* EnterpriseSearchPageTemplate is a light wrapper for KibanaPageTemplate (which
* is a light wrapper for EuiPageTemplate). It should contain only concerns shared
* between both AS & WS, which should have their own AppSearchPageTemplate &
* WorkplaceSearchPageTemplate sitting on top of this template (:nesting_dolls:),
* which in turn manages individual product-specific concerns (e.g. side navs, telemetry, etc.)
*
* @see https://github.com/elastic/kibana/tree/master/src/plugins/kibana_react/public/page_template
* @see https://elastic.github.io/eui/#/layout/page
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

+1000000000000 for this comment, you love to see it

import {
KibanaPageTemplate,
KibanaPageTemplateProps,
} from '../../../../../../../src/plugins/kibana_react/public';
Copy link
Contributor

@byronhulcher byronhulcher Jun 15, 2021

Choose a reason for hiding this comment

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

I'd prefer an absolute path if we can use one for this, I think this would read a lot better as src/plugins/kibana_react/public/ as if it was a yarn installed third-party module

Copy link
Member Author

@cee-chen cee-chen Jun 15, 2021

Choose a reason for hiding this comment

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

+++, but I don't think we can sadly :( I copied this from the Observability folks and AFAIK Kibana's aliases mostly involve src/core and not src/plugins. Definitely would love to make that request though - I might ping the DevOps folks in a little bit!

Copy link
Contributor

@cchaos cchaos left a comment

Choose a reason for hiding this comment

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

😻 Thanks for implementing this. I love your writeup and glad to see that this effort opens your application up for even more possibilities/flexibilities.

One quick thing about the side-nav. The pattern is to not have those root level items actually be clickable/navigable. Instead we want to be consistent throughout and keep them solely to describe sections. I couldn't completely deter this functionality in EUI because it would break a lot of existing implementations but you can work around it by simply creating an empty first item like this:

items = [
  {
    name: '',
    items: [
      {
        name: 'Item 1',
        id: '',
      },
      ...etc
    ]
  }
]

@cee-chen
Copy link
Member Author

Ahhh I was wondering about that Caroline!! I just assumed that's how it was supposed to work, LOL. Probably should have pinged you at some point 🤦‍♀️ Awesome, testing this out now. Just to check, is id: '' okay as well (since the ID prop is required?)

Copy link
Contributor

@scottybollinger scottybollinger left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for the great comments and test helpers! 🎉

- but shenanigans it a bit to take our i18n'd shared product names (requires as const assertion)

- done to reduce merge conflicts for Scotty / make his life (hopefully) a bit easier between ent-search and Kibana
@cee-chen cee-chen enabled auto-merge (squash) June 16, 2021 20:01
@spalger
Copy link
Contributor

spalger commented Jun 16, 2021

jenkins, test this

(restarting due to jenkins upgrade)

@cee-chen
Copy link
Member Author

Thanks Spencer!! 🎊

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
enterpriseSearch 1438 1454 +16

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
enterpriseSearch 2.1MB 2.1MB +7.2KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
enterpriseSearch 14.3KB 14.5KB +238.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@cee-chen cee-chen merged commit 66c9d80 into elastic:master Jun 16, 2021
kibanamachine added a commit to kibanamachine/kibana that referenced this pull request Jun 16, 2021
* Set up shared EnterpriseSearchPageTemplate component

* Set up product-specific page templates + setPageChrome

+ misc tech debt - create AS components/layout/index.ts for imports

* Set up navigation helpers for EuiSideNav usage

- Update react_router_helpers to pass back props as a plain JS obj instead of only working with React components (+ update react components to use new simpler helper)

- Convert SideNavLink active logic to a plain JS helper

* Set up top-level product navigations

NYI: sub navigations (future separate PRs)

* Set up test_helpers for inspecting pageHeaders

- primarily useful for rightSideItems, which often contain conditional logic

* Initial example: Convert RoleMappings views to new page template

Minor refactors:
+ remove unnecessary type union
+ fix un-i18n'ed product names
+ add full stop to documentation sentence
+ add semantic HTML tags around various page landmarks (header, section)

* EUI feedback: add empty root parent section

* Revert Role Mappings union type removal

- but shenanigans it a bit to take our i18n'd shared product names (requires as const assertion)

- done to reduce merge conflicts for Scotty / make his life (hopefully) a bit easier between ent-search and Kibana

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
@kibanamachine
Copy link
Contributor

💚 Backport successful

Status Branch Result
7.x

This backport PR will be merged automatically after passing CI.

@cee-chen cee-chen deleted the kibana-page-template-1 branch June 16, 2021 22:26
kibanamachine added a commit that referenced this pull request Jun 17, 2021
)

* Set up shared EnterpriseSearchPageTemplate component

* Set up product-specific page templates + setPageChrome

+ misc tech debt - create AS components/layout/index.ts for imports

* Set up navigation helpers for EuiSideNav usage

- Update react_router_helpers to pass back props as a plain JS obj instead of only working with React components (+ update react components to use new simpler helper)

- Convert SideNavLink active logic to a plain JS helper

* Set up top-level product navigations

NYI: sub navigations (future separate PRs)

* Set up test_helpers for inspecting pageHeaders

- primarily useful for rightSideItems, which often contain conditional logic

* Initial example: Convert RoleMappings views to new page template

Minor refactors:
+ remove unnecessary type union
+ fix un-i18n'ed product names
+ add full stop to documentation sentence
+ add semantic HTML tags around various page landmarks (header, section)

* EUI feedback: add empty root parent section

* Revert Role Mappings union type removal

- but shenanigans it a bit to take our i18n'd shared product names (requires as const assertion)

- done to reduce merge conflicts for Scotty / make his life (hopefully) a bit easier between ent-search and Kibana

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Constance <constancecchen@users.noreply.github.com>
jloleysens added a commit to jloleysens/kibana that referenced this pull request Jun 17, 2021
…egrations-to-global-search

* 'master' of github.com:elastic/kibana: (46 commits)
  [Lens] Add some more documentation for dynamic coloring (elastic#101369)
  hide not searchable results when no term (elastic#102401)
  [Lens] Fix Formula functional test with multiple suggestions (elastic#102378)
  Fix trusted apps modified by field displayed as a date field (elastic#102377)
  [Lens] Docs for time shift (elastic#102048)
  update readme of logs-metrics-ui (elastic#101968)
  Refactor observability plugin breadcrumbs (elastic#102290)
  [Index Patterns] Move rollup config to index pattern management v2 (elastic#102285)
  [Security Solution][Endpoint] Isolate Action should only be available to Platinum+ licenses (elastic#102374)
  [build] Updates Ironbank templates (elastic#102407)
  Update security best practices document (elastic#100814)
  [Enterprise Search] Set up initial KibanaPageTemplate  (elastic#102170)
  [Reporting/Docs] Add section to troubleshooting guide to explain the StatusCodeError logs (elastic#102278)
  [DOCS] Updating Elastic Security Overview topic  (elastic#101922)
  [Uptime] refactor Synthetics Integration package UI (elastic#102080)
  [Task Manager] Log at different levels based on the state (elastic#101751)
  [APM] Fixing time comparison types (elastic#101423)
  [RAC] Update alert documents in lifecycle rule type helper (elastic#101598)
  [ML] Functional tests - fix and re-activate alerting flyout test (elastic#102368)
  [Reporting] remove unused reference to path.data config (elastic#102267)
  ...

# Conflicts:
#	x-pack/plugins/fleet/kibana.json
majagrubic pushed a commit to majagrubic/kibana that referenced this pull request Jun 18, 2021
* Set up shared EnterpriseSearchPageTemplate component

* Set up product-specific page templates + setPageChrome

+ misc tech debt - create AS components/layout/index.ts for imports

* Set up navigation helpers for EuiSideNav usage

- Update react_router_helpers to pass back props as a plain JS obj instead of only working with React components (+ update react components to use new simpler helper)

- Convert SideNavLink active logic to a plain JS helper

* Set up top-level product navigations

NYI: sub navigations (future separate PRs)

* Set up test_helpers for inspecting pageHeaders

- primarily useful for rightSideItems, which often contain conditional logic

* Initial example: Convert RoleMappings views to new page template

Minor refactors:
+ remove unnecessary type union
+ fix un-i18n'ed product names
+ add full stop to documentation sentence
+ add semantic HTML tags around various page landmarks (header, section)

* EUI feedback: add empty root parent section

* Revert Role Mappings union type removal

- but shenanigans it a bit to take our i18n'd shared product names (requires as const assertion)

- done to reduce merge conflicts for Scotty / make his life (hopefully) a bit easier between ent-search and Kibana

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed Feature:Plugins release_note:skip Skip the PR/issue when compiling release notes v7.14.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants