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

Migrate Index Management to new solutions nav #101548

Merged
merged 8 commits into from
Jun 23, 2021

Conversation

cjcenizal
Copy link
Contributor

@cjcenizal cjcenizal commented Jun 7, 2021

Partially addresses #100748

Notable changes:

  • I made the shared PageError component's error prop optional so we could use it to surface errors like missing permissions, which don't report an ES error.
  • Added a shared PageLoading component.
  • The index_table component tests are very brittle and I had to change them slightly to get them passing. Added comments to the code to mark brittle areas.
  • The "get index templates" API route didn't report errors, so I had to add that in.
  • Added actions to the index templates list empty prompt.
Screenshots

Indices

image

image

image

Data streams

image

image

image

Index templates

List

image

image

image

Wizard

image

image

image

image

image

image

image

image

image

Component templates

List

image

image

image

image

image

image

Wizard

image

image

image

image

@cjcenizal cjcenizal added the Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more label Jun 7, 2021
@cjcenizal cjcenizal force-pushed the index-management/migrate-nav branch 2 times, most recently from 88e1c24 to d2a446f Compare June 8, 2021 23:06
@cjcenizal cjcenizal force-pushed the index-management/migrate-nav branch 4 times, most recently from fc128ce to a13c70c Compare June 16, 2021 23:23
@cjcenizal cjcenizal added chore Feature:Index Management Index and index templates UI v7.14.0 v8.0.0 release_note:skip Skip the PR/issue when compiling release notes labels Jun 17, 2021
@cjcenizal cjcenizal force-pushed the index-management/migrate-nav branch from a13c70c to ece3512 Compare June 17, 2021 21:31
@@ -141,13 +145,13 @@ export const ComponentTemplateList: React.FunctionComponent<Props> = ({
let content: React.ReactNode;

if (isLoading) {
content = (
<SectionLoading data-test-subj="sectionLoading">
return (
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 know it looks weird but this is deliberate. I think we need to go back and rearchitect our apps later for consistent patterns both across apps and even within each app.

Copy link
Contributor

Choose a reason for hiding this comment

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

I've never been a big fan of this content var declared on top and assigned down.

Can we write this slightly differently, with simply an early return?

if (isLoading) {
  return (
    <PageLoading data-test-subj="sectionLoading">
      <FormattedMessage
        id="xpack.idxMgmt.home.componentTemplates.list.loadingMessage"
        defaultMessage="Loading component templates…"
      />
    </PageLoading>
  );
}

let content: React.ReactNode;

if (data?.length) {

...

Copy link
Contributor Author

@cjcenizal cjcenizal Jun 22, 2021

Choose a reason for hiding this comment

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

We could but it would require duplicating the wrapping <div className={APP_WRAPPER_CLASS} data-test-subj="componentTemplateList"> element in several places. I think we can find a more elegant solution later when we rearchitect our apps to adhere to a consistent pattern, so I'm going to defer this for now.

On second reading it sounds like you're advocating for moving the content var so it isn't declared before the early return, which SGTM.

Copy link
Contributor

Choose a reason for hiding this comment

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

It all goes to down to preferences but I never have to use this pattern of declaring an empty content and assign it in multiple place to finally render it down. I much prefer early return pattern

const SomeComponent = () => {
  if (this) {
    return <MyComp />;
  }
  
  if (that) {
    return <MyOtherComp />;
  }
  
  const renderMainContent = () => {
    if (someFlag) {
      return <div>Early return</div>;
    }
  
    return <div>Finally</div>;
  }
  
  // otherwise
  return <div className="someClassWeWantEverywhere">{renderMainContent()}</div>
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see what you're saying. Yes I prefer that, too. We'll apply this in the future when we rearchitect our apps to adhere to a consistent pattern.

);
} else if (!hasTemplates) {
content = (
<EuiEmptyPrompt
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This empty prompt didn't originally offer the user any actions, so I added those and updated the copy to mirror our other empty prompts.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! 👍

@@ -19,6 +20,6 @@ export const sendRequest = (config: SendRequestConfig): Promise<SendRequestRespo
return _sendRequest(httpService.httpClient, config);
};

export const useRequest = <T = any>(config: UseRequestConfig) => {
return _useRequest<T>(httpService.httpClient, config);
export const useRequest = <T = any, E = Error>(config: UseRequestConfig) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This allows us to pass API errors to PageError without a TS error.

@cjcenizal cjcenizal marked this pull request as ready for review June 17, 2021 23:09
@cjcenizal cjcenizal requested a review from a team as a code owner June 17, 2021 23:09
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-stack-management (Team:Stack Management)

@cjcenizal cjcenizal requested review from alisonelizabeth and sebelga and removed request for alisonelizabeth June 17, 2021 23:10
@@ -183,11 +187,22 @@ export const ComponentTemplateList: React.FunctionComponent<Props> = ({
} else if (data && data.length === 0) {
content = <EmptyPrompt history={history} />;
} else if (error) {
content = <LoadError onReloadClick={resendRequest} />;
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 removed this state because it didn't surface the underlying error, offered a "Try again" button which I don't think will be helpful in the typical error scenario, and was inconsistent with the other error states in this PR.

@cjcenizal cjcenizal force-pushed the index-management/migrate-nav branch from fe9b346 to a4f510a Compare June 21, 2021 21:53
Copy link
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

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

Great job @cjcenizal ! Tested locally and works as expected. I left a few non blocking comments in the code.

import React from 'react';
import { EuiEmptyPrompt, EuiLoadingSpinner, EuiText, EuiPageContent } from '@elastic/eui';

interface Props {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: you don't need to declare this interface. React.FunctionComponent already declare the children prop for us.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Fixed.

// but it looks like we're aware of how many Redux actions are dispatched in response to user interaction,
// so we "time" our assertion based on how many Redux actions we observe. This is brittle because it
// depends upon how our UI is architected, which will affect how many actions are dispatched.
// Expect this to break when we rearchitect the UI.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather put: "Expect to completely rewrite those tests when we rearchitect the UI"! 😄 This would be one of our tech debt. Actually I'd first rewrite the tests and follow our CIT best practices (no testing of implementation details!) and only after I would rearchitect the UI.

Copy link
Contributor Author

@cjcenizal cjcenizal Jun 22, 2021

Choose a reason for hiding this comment

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

Haha yep! I'm just marking the landmine with this comment, not prescribing how it should be addressed. I think an issue is a better place for that (more discoverable and collaborative). I'm going to raise this as a tech debt item we should address.

snapshot(namesText(rendered));
});
test('should show more when per page value is increased', () => {

test('should show more when per page value is increased', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we testing the EUI table component here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The indices table is implemented using individual EuiTable, EuiTablePagination, EuiTableRowCell, etc components. So unfortunately, no, this isn't testing EUI. It's testing our table implementation which EUI now provides an abstraction over with EuiBasicTable. More tech debt! 🎉

@@ -166,7 +166,7 @@ describe('<ComponentTemplateList />', () => {

expect(exists('componentTemplatesLoadError')).toBe(true);
expect(find('componentTemplatesLoadError').text()).toContain(
'Unable to load component templates. Try again.'
'Error loading component templatesInternal server error'
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that a space and a dot is missing after "templates".

Copy link
Contributor Author

@cjcenizal cjcenizal Jun 22, 2021

Choose a reason for hiding this comment

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

Nice spot! This is not a bug though, just an oddity due to the way the DOM API provides text values of child elements by concatenating each child element's text value without any delimiter. So it's smashing together the title element "Error loading component templates" with the description element "Internal server error". Will add a comment to clarify.

@@ -141,13 +145,13 @@ export const ComponentTemplateList: React.FunctionComponent<Props> = ({
let content: React.ReactNode;

if (isLoading) {
content = (
<SectionLoading data-test-subj="sectionLoading">
return (
Copy link
Contributor

Choose a reason for hiding this comment

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

I've never been a big fan of this content var declared on top and assigned down.

Can we write this slightly differently, with simply an early return?

if (isLoading) {
  return (
    <PageLoading data-test-subj="sectionLoading">
      <FormattedMessage
        id="xpack.idxMgmt.home.componentTemplates.list.loadingMessage"
        defaultMessage="Loading component templates…"
      />
    </PageLoading>
  );
}

let content: React.ReactNode;

if (data?.length) {

...

@@ -292,7 +292,7 @@ export const TemplateForm = ({
return (
<>
{/* Form header */}
{title}
<EuiPageHeader pageTitle={<span data-test-subj="pageTitle">{title}</span>} bottomBorder />
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we ask the EUI team to add a generic data-test-subj for us so we don't have to provide everywhere a <span> for the title? We should only have one page header per page right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. They already have a generic data-test-subj, but we're excluding the work of migrating our code and tests over to it from the scope of this work due to time pressure.

@@ -166,16 +170,16 @@ export const DataStreamList: React.FunctionComponent<RouteComponentProps<MatchPa

if (isLoading) {
content = (
<SectionLoading>
<PageLoading>
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here. It seems we did some copy/paste of this pattern 😊

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'm not sure what you're suggesting here, can you clarify? If it's the same comment as #101548 (comment) then I'll defer to this later when we rearchitect for a consistent pattern across apps.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes it was the same comment about early return. It's OK to leave it as is, goes down to preferences. 👍

if (!hasContent) {
const renderNoContent = () => {
if (indicesLoading) {
return (
Copy link
Contributor

Choose a reason for hiding this comment

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

Returning early here again would make the code easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean converting else if to if? From my reading of the code, it looks like it's already returning early.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, once you have an early return there is no need of else if. Just code styling thing, nothing important.

if (something) {
  return true;
}
return false;

// instead of

if (something) {
  return true;
} else {
  return false;
}

if (isLoading) {
return (
<SectionLoading>
// Track component loaded
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: wouldn't it be "templates" loaded?

Copy link
Contributor Author

@cjcenizal cjcenizal Jun 22, 2021

Choose a reason for hiding this comment

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

Hmm this is pre-existing so I can't be certain, but it looks like this code will execute when the component mounts, regardless of whether the templates are loading, loaded, or failed to load. So I have to assume that by "loaded" the original author meant "mounted". Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

No I meant that the tracking. UIM_TEMPLATE_LIST_LOAD is for "index template loaded" not "component templates loaded" 😊

);
} else if (!hasTemplates) {
content = (
<EuiEmptyPrompt
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! 👍

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
esUiShared 153 155 +2
indexManagement 518 514 -4
total -2

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
esUiShared 88 90 +2

Async chunks

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

id before after diff
indexManagement 1.3MB 1.3MB -2.0KB

Page load bundle

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

id before after diff
esUiShared 191.8KB 192.5KB +770.0B
Unknown metric groups

API count

id before after diff
esUiShared 90 92 +2

History

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

@cjcenizal cjcenizal merged commit 5df858a into elastic:master Jun 23, 2021
@cjcenizal cjcenizal deleted the index-management/migrate-nav branch June 23, 2021 00:16
cjcenizal added a commit to cjcenizal/kibana that referenced this pull request Jun 23, 2021
* Migrate index template and component template wizard pages to new nav.
* Convert index templates and component templates pages to new nav.
* Convert indices and data streams pages to new nav.
* Add PageLoading component to es_ui_shared.
* Refactor index table component tests.
* Add missing error reporting to get all templates API route handler.
# Conflicts:
#	x-pack/plugins/index_management/server/routes/api/templates/register_get_routes.ts
cjcenizal added a commit that referenced this pull request Jun 23, 2021
* Migrate index template and component template wizard pages to new nav.
* Convert index templates and component templates pages to new nav.
* Convert indices and data streams pages to new nav.
* Add PageLoading component to es_ui_shared.
* Refactor index table component tests.
* Add missing error reporting to get all templates API route handler.
# Conflicts:
#	x-pack/plugins/index_management/server/routes/api/templates/register_get_routes.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chore Feature:Index Management Index and index templates UI release_note:skip Skip the PR/issue when compiling release notes Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more v7.14.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants