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 saved objects management edition view to react/typescript/eui #59490

Conversation

pgayvallet
Copy link
Contributor

@pgayvallet pgayvallet commented Mar 5, 2020

Summary

Preliminary work for #50308, this converts the saved objects edition/view page to react, typescript, EUI, and new platform APIs.

Extracted from my #59110 sandbox

before

SO_before

after

so_after_3

Checklist

Delete any items that are not applicable to this PR.

@pgayvallet pgayvallet added Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc Feature:New Platform v8.0.0 release_note:skip Skip the PR/issue when compiling release notes v7.7.0 labels Mar 5, 2020
@pgayvallet pgayvallet requested a review from a team as a code owner March 5, 2020 22:21
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-platform (Team:Platform)

@pgayvallet pgayvallet requested a review from a team March 5, 2020 22:22
Comment on lines +46 to +53
$scope.$$postDigest(() => {
const node = document.getElementById(REACT_OBJECTS_VIEW_DOM_ELEMENT_ID);
if (!node) {
return;
}

render(
<I18nContext>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure this $$postDigest approach is the best, or even useful, but I copied the way it's already done in src/legacy/core_plugins/kibana/public/management/sections/objects/_objects.js, and this angular->react bridge is meant to be temporary anyway.

Comment on lines 35 to +42
uiRoutes.when('/management/kibana/objects/:service/:id', {
template: objectViewHTML,
k7Breadcrumbs: getViewBreadcrumbs,
requireUICapability: 'management.kibana.objects',
});

function createReactView($scope, $routeParams) {
const { service: serviceName, id: objectId, notFound } = $routeParams;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TIL: src/legacy/ui/public/url/redirect_when_missing.js for the notFound undeclared route param.

if (confirmed) {
await savedObjectsClient.delete(type, id);
notifications.toasts.addSuccess(`Deleted '${object!.attributes.title}' ${type} object`);
window.location.hash = '/management/kibana/objects';
Copy link
Contributor Author

@pgayvallet pgayvallet Mar 5, 2020

Choose a reason for hiding this comment

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

So, I did not like doing that, however

  • I don't want any angular services here, so $location or kbnUrl (which was used before) is not an option
  • We have no core APIs to do that
  • The management kibana app is still using angular hash-based routing, meaning that even if core was exposing an API to change to url, this wouldn't work (we need to redirect to {basePath}/app/kibana#/management/kibana/objects)

Copy link
Contributor

@mattkime mattkime Mar 7, 2020

Choose a reason for hiding this comment

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

Have you looked at using react-router-dom to do the redirect? I think it will provide the right interface so that changes to the url structure won't break this.


edit - I think this is fine as an intermediate step but once this becomes a new platform management app we'll want to change this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mattkime I'm planning to do that in the next step, when I actually migrate these two pages to NP plugins (draft in #59110). ATM, the routes are still provided/handled by angular so imho it doesn't really make sense (if even possible?) to use react router to perform the redirect.

Comment on lines 73 to 75
if ((service as any).Class) {
addFieldsFromClass((service as any).Class, fields);
}
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 js code was accessing the SavedObjectLoader.Class property, but it's declared as private in the TS definition.

Comment on lines +38 to +45
const focusAndClickButton = async (buttonSubject: string) => {
const button = await testSubjects.find(buttonSubject);
await button.scrollIntoViewIfNecessary();
await delay(10);
await button.focus();
await delay(10);
await button.click();
};
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 don't know the exact cause, but only clicking on the buttons was very flaky (it seems the texteditor are catching the focus / blocking the click during the driver auto-scrolling to the button). I had to use that to remove the flakyness...

@pgayvallet pgayvallet changed the title migrate saved objects management edition view to react and typescript migrate saved objects management edition view to react/typescript/eui Mar 6, 2020
@pgayvallet pgayvallet requested a review from a team March 6, 2020 12:33
@gchaps
Copy link
Contributor

gchaps commented Mar 6, 2020

For consistency, please use init caps for the field names:

Name
Description
Hits
...

Also, use this capitalization for the button name:

Save search object

@pgayvallet
Copy link
Contributor Author

@elastic/kibana-design As said on slack

the main goal of the PR is to perform the react migration to be able to move that to a NP plugin. We don't plan to do any heavy UI changes in the short term on this page, but as I migrated the old kbn classes to Eui components, any feedback on that is very welcome

@pgayvallet
Copy link
Contributor Author

pgayvallet commented Mar 6, 2020

@gchaps

For consistency, please use init caps for the field names:

These are the exact field name from the saved object structure, not labels. Capitalizing that might not be a good idea, as copy/pasting the field name (to perform an ES query for example) would result in copying something wrong. WDYT?

@gchaps
Copy link
Contributor

gchaps commented Mar 6, 2020

@pgayvallet Ah, I see. My preference would be to use capitalization for the labels because to me it makes the UI look more polished. We do use capitalization for the labels when editing a field in an index pattern. However, as this is for advanced users "with intimate knowledge of the code" and they might want to copy the field name for use in their queries, it's ok to leave as is.

@rudolf rudolf mentioned this pull request Mar 9, 2020
5 tasks
@joshdover
Copy link
Contributor

@elastic/kibana-design Do you want to take a pass at this? Not sure if it's important enough since it is a "advanced" screen, but thought I'd flag it just in case.

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.

I made a design PR for you mainly just cleanup: pgayvallet#1

…object

Wrapping whole view in page content panel and removing legacy classes
@pgayvallet
Copy link
Contributor Author

retest

@pgayvallet pgayvallet requested a review from cchaos March 11, 2020 10:21
@pgayvallet
Copy link
Contributor Author

retest

Copy link
Contributor

@joshdover joshdover left a comment

Choose a reason for hiding this comment

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

What's the testing plan for these changes? I see you added e2e tests which is great. Are we going to hold off on unit tests until later?

Comment on lines -290 to -294
$location.path('/management/kibana/objects').search({
_a: rison.encode({
tab: serviceObj.title,
}),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this URL state unneeded now? I don't see it in the new implementation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From my understanding, it is. I think this was a forgotten thing from an older version, as the rison formatted search doesn't seems to be used (functionally or technically) in the SO management table view.

@pgayvallet
Copy link
Contributor Author

@joshdover

Are we going to hold off on unit tests until later?

If we want to add UT, we should probably do it in this PR. What kind of unit test would you like to see added here? snapshot testing of the introduced lower-level react components ?

@pgayvallet
Copy link
Contributor Author

@cchaos I think the asked changes are done. PTAL

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.

There are still a few unnecessary legacy classes that need to be removed in favor of EUI components.

/>
))}
</div>
<EuiFormRow fullWidth={true}>
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need a EuiFormRow if you're not providing an input as a direct descendent or a label. It will just cause extraneous wrappers.

const { name } = this.props;

return (
<div className="kuiFormSection">
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you remove these legacy kui classes? Instead, you can just use the <EuiFormRow label=""> wrapper around the field.

defaultMessage="Proceed with caution!"
/>
}
iconType="bolt"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
iconType="bolt"
iconType="alert"

@pgayvallet
Copy link
Contributor Author

@cchaos the remaning kui classes has been removed and suggested changes done.

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!

@pgayvallet
Copy link
Contributor Author

@joshdover added UT for new components. Only skipped the high-level form component as it's more efficiently covered by the existing FTs.

Copy link
Contributor

@joshdover joshdover left a comment

Choose a reason for hiding this comment

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

LGTM. Left some suggestions for some improvements, but nothing blocking this for merging. I'll leave it up to you whether these optional suggestions are worth it on this page.

});

it('renders a EuiFieldText as fallback', () => {
const mounted = mountField({ ...defaultProps, type: 'unkown' as any });
Copy link
Contributor

Choose a reason for hiding this comment

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

super nit, doesn't really matter (could also make more obvious that it's supposed to be an unexpected value by making it blah or something)

Suggested change
const mounted = mountField({ ...defaultProps, type: 'unkown' as any });
const mounted = mountField({ ...defaultProps, type: 'unknown' as any });

Comment on lines +106 to +110
!!currentValue ? (
<FormattedMessage id="kbn.management.objects.field.onLabel" defaultMessage="On" />
) : (
<FormattedMessage id="kbn.management.objects.field.offLabel" defaultMessage="Off" />
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Untested

* @param {array} parents The parent keys to the field
* @returns {array}
*/
const recursiveCreateFields = (key: string, value: any, parents: string[] = []): ObjectField[] => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this have a max depth safety mechanism to avoid recursing deeply nested objects if one were to exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Doesn't cost much to add. Also extracted the field generation logic and added tests

<Intro />
</>
)}
{object && (
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 use Suspense or show a spinner while this loads?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will keep this one as a later improvement

},
})}
onClick={this.onSubmit}
disabled={!isValid}
Copy link
Contributor

Choose a reason for hiding this comment

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

optional: Should this also be disabled while the save operation is running to avoid double-saves?

@kibanamachine
Copy link
Contributor

💛 Build succeeded, but was flaky


Test Failures

Kibana Pipeline / kibana-xpack-agent / X-Pack OpenID Connect API Integration Tests (Implicit Flow).x-pack/test/oidc_api_integration/apis/implicit_flow/oidc_auth·ts.apis OpenID Connect Implicit Flow authentication finishing handshake should succeed if both the OpenID Connect response and the cookie are provided

Link to Jenkins

Standard Out

Failed Tests Reporter:
  - Test has failed 3 times on tracked branches: https://github.com/elastic/kibana/issues/43938

[00:00:00]       │
[00:00:00]         └-: apis
[00:00:00]           └-> "before all" hook
[00:00:00]           └-: OpenID Connect Implicit Flow authentication
[00:00:00]             └-> "before all" hook
[00:00:00]             └-: finishing handshake
[00:00:00]               └-> "before all" hook
[00:00:00]               └-> should return an HTML page that will parse URL fragment
[00:00:00]                 └-> "before each" hook: global before each
[00:00:00]                 └-> "before each" hook
[00:00:00]                 └- ✓ pass  (51ms) "apis OpenID Connect Implicit Flow authentication finishing handshake should return an HTML page that will parse URL fragment"
[00:00:00]               └-> should fail if OpenID Connect response is not complemented with handshake cookie
[00:00:00]                 └-> "before each" hook: global before each
[00:00:00]                 └-> "before each" hook
[00:00:00]                 └- ✓ pass  (133ms) "apis OpenID Connect Implicit Flow authentication finishing handshake should fail if OpenID Connect response is not complemented with handshake cookie"
[00:00:00]               └-> should fail if state is not matching
[00:00:00]                 └-> "before each" hook: global before each
[00:00:00]                 └-> "before each" hook
[00:00:00]                 │ info [o.e.x.s.a.AuthenticationService] [kibana-ci-immutable-ubuntu-16-tests-xl-1584614707406488139] Authentication to realm oidc1 failed - Failed to authenticate user with OpenID Connect (Caused by org.elasticsearch.ElasticsearchSecurityException: Invalid state parameter [$someothervalue], while [7NkdMpkC-g3WVZ7SZReQdRW9sA-gAkoVVpgsmjiz9MA] was expected)
[00:00:00]                 └- ✓ pass  (199ms) "apis OpenID Connect Implicit Flow authentication finishing handshake should fail if state is not matching"
[00:00:00]               └-> should succeed if both the OpenID Connect response and the cookie are provided
[00:00:00]                 └-> "before each" hook: global before each
[00:00:00]                 └-> "before each" hook
[00:00:00]                 │ info [o.e.x.s.a.AuthenticationService] [kibana-ci-immutable-ubuntu-16-tests-xl-1584614707406488139] Authentication to realm oidc1 failed - Failed to authenticate user with OpenID Connect (Caused by org.elasticsearch.ElasticsearchSecurityException: Failed to get claims from the Userinfo Endpoint.)
[00:00:00]                 └- ✖ fail: "apis OpenID Connect Implicit Flow authentication finishing handshake should succeed if both the OpenID Connect response and the cookie are provided"
[00:00:00]                 │

Stack Trace

Error: expected 302 "Found", got 401 "Unauthorized"
    at Test._assertStatus (/dev/shm/workspace/kibana/node_modules/supertest/lib/test.js:268:12)
    at Test._assertFunction (/dev/shm/workspace/kibana/node_modules/supertest/lib/test.js:283:11)
    at Test.assert (/dev/shm/workspace/kibana/node_modules/supertest/lib/test.js:173:18)
    at assert (/dev/shm/workspace/kibana/node_modules/supertest/lib/test.js:131:12)
    at /dev/shm/workspace/kibana/node_modules/supertest/lib/test.js:128:5
    at Test.Request.callback (/dev/shm/workspace/kibana/node_modules/superagent/lib/node/index.js:718:3)
    at parser (/dev/shm/workspace/kibana/node_modules/superagent/lib/node/index.js:906:18)
    at IncomingMessage.res.on (/dev/shm/workspace/kibana/node_modules/superagent/lib/node/parsers/json.js:19:7)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

History

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

@pgayvallet pgayvallet merged commit 395d621 into elastic:master Mar 19, 2020
pgayvallet added a commit to pgayvallet/kibana that referenced this pull request Mar 19, 2020
…elastic#59490)

* migrate so management edition view to react

* fix bundle name + add forgotten data-test-subj

* add FTR tests for edition page

* EUIfy react components

* wrap form with EuiPanel + caps btns labels

* Wrapping whole view in page content panel and removing legacy classes

* improve delete confirmation modal

* update translations

* improve delete popin

* add unit test on view components

* remove kui classes & address comments

* extract createFieldList and add tests

* disable form submit during submition

Co-authored-by: cchaos <[email protected]>
pgayvallet added a commit that referenced this pull request Mar 20, 2020
…pt/eui (#59490) (#60621)

* migrate saved objects management edition view to react/typescript/eui (#59490)

* migrate so management edition view to react

* fix bundle name + add forgotten data-test-subj

* add FTR tests for edition page

* EUIfy react components

* wrap form with EuiPanel + caps btns labels

* Wrapping whole view in page content panel and removing legacy classes

* improve delete confirmation modal

* update translations

* improve delete popin

* add unit test on view components

* remove kui classes & address comments

* extract createFieldList and add tests

* disable form submit during submition

Co-authored-by: cchaos <[email protected]>

* update dataset and fix test description

Co-authored-by: cchaos <[email protected]>
gmmorris added a commit to gmmorris/kibana that referenced this pull request Mar 20, 2020
* master:
  [ML] Use a new ML endpoint to estimate a model memory (elastic#60376)
  [Logs UI] Correctly update the expanded log rate table rows (elastic#60306)
  fixes drag and drop flakiness (elastic#60625)
  Removing isEmptyState from embeddable input (elastic#60511)
  [Cross Cluster Replication] NP Shim (elastic#60121)
  Clear changes when canceling an edit to an alert (elastic#60518)
  Update workflow syntax (elastic#60626)
  Updating project assigner workflows to v2.0.0 of the action and back to default tokens (elastic#60577)
  migrate saved objects management edition view to react/typescript/eui (elastic#59490)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:New Platform release_note:skip Skip the PR/issue when compiling release notes Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v7.7.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants