mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Changes edit view to json read-only view (#112034)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
25bf795099
commit
8cf0efe2f1
47 changed files with 1365 additions and 1335 deletions
|
@ -241,6 +241,7 @@ export class DocLinksService {
|
|||
kibanaSearchSettings: `${KIBANA_DOCS}advanced-options.html#kibana-search-settings`,
|
||||
visualizationSettings: `${KIBANA_DOCS}advanced-options.html#kibana-visualization-settings`,
|
||||
timelionSettings: `${KIBANA_DOCS}advanced-options.html#kibana-timelion-settings`,
|
||||
savedObjectsApiList: `${KIBANA_DOCS}saved-objects-api.html#saved-objects-api`,
|
||||
},
|
||||
ml: {
|
||||
guide: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/index.html`,
|
||||
|
|
|
@ -27,9 +27,6 @@ export const createDashboardSavedObjectType = ({
|
|||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/objects/savedDashboards/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/dashboards#/view/${encodeURIComponent(obj.id)}`,
|
||||
|
|
|
@ -20,9 +20,6 @@ export const searchSavedObjectType: SavedObjectsType = {
|
|||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/objects/savedSearches/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/discover#/view/${encodeURIComponent(obj.id)}`,
|
||||
|
|
|
@ -62,12 +62,11 @@ export const mountManagementSection = async ({
|
|||
<I18nProvider>
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path={'/:service/:id'} exact={true}>
|
||||
<Route path={'/:type/:id'} exact={true}>
|
||||
<RedirectToHomeIfUnauthorized>
|
||||
<Suspense fallback={<EuiLoadingSpinner />}>
|
||||
<SavedObjectsEditionPage
|
||||
coreStart={coreStart}
|
||||
serviceRegistry={serviceRegistry}
|
||||
setBreadcrumbs={setBreadcrumbs}
|
||||
history={history}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SavedObjectEdition should render normally 1`] = `
|
||||
<Provider
|
||||
services={
|
||||
Object {
|
||||
"uiSettings": Object {
|
||||
"get": [MockFunction],
|
||||
"get$": [MockFunction],
|
||||
"getAll": [MockFunction],
|
||||
"getUpdate$": [MockFunction],
|
||||
"getUpdateErrors$": [MockFunction],
|
||||
"isCustom": [MockFunction],
|
||||
"isDeclared": [MockFunction],
|
||||
"isDefault": [MockFunction],
|
||||
"isOverridden": [MockFunction],
|
||||
"remove": [MockFunction],
|
||||
"set": [MockFunction],
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
className="savedObjectsManagementObjectView"
|
||||
data-test-subject="savedObjectsEdit"
|
||||
direction="column"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<Header
|
||||
canDelete={false}
|
||||
canViewInApp={true}
|
||||
onDeleteClick={[Function]}
|
||||
title="MyDashboard*"
|
||||
viewUrl="/app/dashboards#/view/1"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={true}
|
||||
>
|
||||
<Inspect
|
||||
object={
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"title": "MyDashboard*",
|
||||
},
|
||||
"id": "1",
|
||||
"meta": Object {
|
||||
"icon": "dashboardApp",
|
||||
"inAppUrl": Object {
|
||||
"path": "/app/dashboards#/view/1",
|
||||
"uiCapabilitiesPath": "management.kibana.dashboard",
|
||||
},
|
||||
"title": "MyDashboard*",
|
||||
},
|
||||
"type": "dashboard",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Provider>
|
||||
`;
|
|
@ -11,17 +11,7 @@ exports[`Intro component renders correctly 1`] = `
|
|||
>
|
||||
<EuiPageHeader
|
||||
bottomBorder={true}
|
||||
pageTitle={
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit {title}"
|
||||
id="savedObjectsManagement.view.editItemTitle"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
pageTitle="Inspect saved object"
|
||||
rightSideItems={
|
||||
Array [
|
||||
<EuiButton
|
||||
|
@ -35,7 +25,7 @@ exports[`Intro component renders correctly 1`] = `
|
|||
id="savedObjectsManagement.view.viewItemButtonLabel"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
"title": "saved object",
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
@ -48,13 +38,9 @@ exports[`Intro component renders correctly 1`] = `
|
|||
size="s"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Delete {title}"
|
||||
defaultMessage="Delete"
|
||||
id="savedObjectsManagement.view.deleteItemButtonLabel"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
}
|
||||
}
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>,
|
||||
]
|
||||
|
@ -64,17 +50,7 @@ exports[`Intro component renders correctly 1`] = `
|
|||
className="euiPageHeader euiPageHeader--bottomBorder euiPageHeader--responsive euiPageHeader--center"
|
||||
>
|
||||
<EuiPageHeaderContent
|
||||
pageTitle={
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit {title}"
|
||||
id="savedObjectsManagement.view.editItemTitle"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
pageTitle="Inspect saved object"
|
||||
responsive={true}
|
||||
rightSideItems={
|
||||
Array [
|
||||
|
@ -89,7 +65,7 @@ exports[`Intro component renders correctly 1`] = `
|
|||
id="savedObjectsManagement.view.viewItemButtonLabel"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
"title": "saved object",
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
@ -102,13 +78,9 @@ exports[`Intro component renders correctly 1`] = `
|
|||
size="s"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Delete {title}"
|
||||
defaultMessage="Delete"
|
||||
id="savedObjectsManagement.view.deleteItemButtonLabel"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
}
|
||||
}
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>,
|
||||
]
|
||||
|
@ -136,17 +108,7 @@ exports[`Intro component renders correctly 1`] = `
|
|||
<h1
|
||||
className="euiTitle euiTitle--large"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit {title}"
|
||||
id="savedObjectsManagement.view.editItemTitle"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
}
|
||||
}
|
||||
>
|
||||
Edit search
|
||||
</FormattedMessage>
|
||||
Inspect saved object
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</div>
|
||||
|
@ -234,11 +196,11 @@ exports[`Intro component renders correctly 1`] = `
|
|||
id="savedObjectsManagement.view.viewItemButtonLabel"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
"title": "saved object",
|
||||
}
|
||||
}
|
||||
>
|
||||
View search
|
||||
View saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</span>
|
||||
|
@ -316,15 +278,11 @@ exports[`Intro component renders correctly 1`] = `
|
|||
className="euiButton__text"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Delete {title}"
|
||||
defaultMessage="Delete"
|
||||
id="savedObjectsManagement.view.deleteItemButtonLabel"
|
||||
values={
|
||||
Object {
|
||||
"title": "search",
|
||||
}
|
||||
}
|
||||
values={Object {}}
|
||||
>
|
||||
Delete search
|
||||
Delete
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Inspect component renders correctly 1`] = `
|
||||
<CodeEditor
|
||||
aria-label="inspect MyIndexPattern*"
|
||||
languageId="xjson"
|
||||
options={
|
||||
Object {
|
||||
"automaticLayout": false,
|
||||
"fontSize": 12,
|
||||
"lineNumbers": "on",
|
||||
"minimap": Object {
|
||||
"enabled": false,
|
||||
},
|
||||
"overviewRulerBorder": false,
|
||||
"readOnly": true,
|
||||
"renderIndentGuides": false,
|
||||
"scrollBeyondLastLine": false,
|
||||
"scrollbar": Object {
|
||||
"alwaysConsumeMouseWheel": false,
|
||||
},
|
||||
"wordWrap": "on",
|
||||
"wrappingIndent": "indent",
|
||||
}
|
||||
}
|
||||
value="{
|
||||
\\"id\\": \\"1\\",
|
||||
\\"type\\": \\"index-pattern\\",
|
||||
\\"attributes\\": {
|
||||
\\"title\\": \\"MyIndexPattern*\\"
|
||||
},
|
||||
\\"references\\": []
|
||||
}"
|
||||
/>
|
||||
`;
|
|
@ -1,80 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Intro component renders correctly 1`] = `
|
||||
<Intro>
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Proceed with caution!"
|
||||
id="savedObjectsManagement.view.howToModifyObjectTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="euiCallOut euiCallOut--warning"
|
||||
>
|
||||
<div
|
||||
className="euiCallOutHeader"
|
||||
>
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Proceed with caution!"
|
||||
id="savedObjectsManagement.view.howToModifyObjectTitle"
|
||||
values={Object {}}
|
||||
>
|
||||
Proceed with caution!
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be."
|
||||
id="savedObjectsManagement.view.howToModifyObjectDescription"
|
||||
values={Object {}}
|
||||
>
|
||||
Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
</Intro>
|
||||
`;
|
|
@ -1,353 +1,541 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`NotFoundErrors component renders correctly for index-pattern type 1`] = `
|
||||
<NotFoundErrors
|
||||
type="index-pattern"
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
>
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
className="euiCallOutHeader"
|
||||
>
|
||||
<div
|
||||
className="euiCallOutHeader"
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<EuiIcon
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="The index pattern associated with this object no longer exists."
|
||||
id="savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
The index pattern associated with this object no longer exists.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={Object {}}
|
||||
>
|
||||
If you know what this error means, go ahead and fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
</NotFoundErrors>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="The index pattern associated with this object no longer exists."
|
||||
id="savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
The index pattern associated with this object no longer exists.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, you can use the {savedObjectsApis} to fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={
|
||||
Object {
|
||||
"savedObjectsApis": <EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
</EuiLink>,
|
||||
}
|
||||
}
|
||||
>
|
||||
If you know what this error means, you can use the
|
||||
<EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
aria-label="Saved objects APIs"
|
||||
className="euiLink euiLink--primary"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
<EuiIcon
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
size="s"
|
||||
type="popout"
|
||||
>
|
||||
<span
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
data-euiicon-type="popout"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<EuiScreenReaderOnly>
|
||||
<span
|
||||
className="euiScreenReaderOnly"
|
||||
>
|
||||
<EuiI18n
|
||||
default="(opens in a new tab or window)"
|
||||
token="euiLink.newTarget.screenReaderOnlyText"
|
||||
>
|
||||
(opens in a new tab or window)
|
||||
</EuiI18n>
|
||||
</span>
|
||||
</EuiScreenReaderOnly>
|
||||
</a>
|
||||
</EuiLink>
|
||||
to fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
`;
|
||||
|
||||
exports[`NotFoundErrors component renders correctly for index-pattern-field type 1`] = `
|
||||
<NotFoundErrors
|
||||
type="index-pattern-field"
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
>
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
className="euiCallOutHeader"
|
||||
>
|
||||
<div
|
||||
className="euiCallOutHeader"
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<EuiIcon
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="A field associated with this object no longer exists in the index pattern."
|
||||
id="savedObjectsManagement.view.fieldDoesNotExistErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
A field associated with this object no longer exists in the index pattern.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={Object {}}
|
||||
>
|
||||
If you know what this error means, go ahead and fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
</NotFoundErrors>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="A field associated with this object no longer exists in the index pattern."
|
||||
id="savedObjectsManagement.view.fieldDoesNotExistErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
A field associated with this object no longer exists in the index pattern.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, you can use the {savedObjectsApis} to fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={
|
||||
Object {
|
||||
"savedObjectsApis": <EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
</EuiLink>,
|
||||
}
|
||||
}
|
||||
>
|
||||
If you know what this error means, you can use the
|
||||
<EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
aria-label="Saved objects APIs"
|
||||
className="euiLink euiLink--primary"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
<EuiIcon
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
size="s"
|
||||
type="popout"
|
||||
>
|
||||
<span
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
data-euiicon-type="popout"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<EuiScreenReaderOnly>
|
||||
<span
|
||||
className="euiScreenReaderOnly"
|
||||
>
|
||||
<EuiI18n
|
||||
default="(opens in a new tab or window)"
|
||||
token="euiLink.newTarget.screenReaderOnlyText"
|
||||
>
|
||||
(opens in a new tab or window)
|
||||
</EuiI18n>
|
||||
</span>
|
||||
</EuiScreenReaderOnly>
|
||||
</a>
|
||||
</EuiLink>
|
||||
to fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
`;
|
||||
|
||||
exports[`NotFoundErrors component renders correctly for search type 1`] = `
|
||||
<NotFoundErrors
|
||||
type="search"
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
>
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
className="euiCallOutHeader"
|
||||
>
|
||||
<div
|
||||
className="euiCallOutHeader"
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<EuiIcon
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="The saved search associated with this object no longer exists."
|
||||
id="savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
The saved search associated with this object no longer exists.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={Object {}}
|
||||
>
|
||||
If you know what this error means, go ahead and fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
</NotFoundErrors>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="The saved search associated with this object no longer exists."
|
||||
id="savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
The saved search associated with this object no longer exists.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, you can use the {savedObjectsApis} to fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={
|
||||
Object {
|
||||
"savedObjectsApis": <EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
</EuiLink>,
|
||||
}
|
||||
}
|
||||
>
|
||||
If you know what this error means, you can use the
|
||||
<EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
aria-label="Saved objects APIs"
|
||||
className="euiLink euiLink--primary"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
<EuiIcon
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
size="s"
|
||||
type="popout"
|
||||
>
|
||||
<span
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
data-euiicon-type="popout"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<EuiScreenReaderOnly>
|
||||
<span
|
||||
className="euiScreenReaderOnly"
|
||||
>
|
||||
<EuiI18n
|
||||
default="(opens in a new tab or window)"
|
||||
token="euiLink.newTarget.screenReaderOnlyText"
|
||||
>
|
||||
(opens in a new tab or window)
|
||||
</EuiI18n>
|
||||
</span>
|
||||
</EuiScreenReaderOnly>
|
||||
</a>
|
||||
</EuiLink>
|
||||
to fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
`;
|
||||
|
||||
exports[`NotFoundErrors component renders correctly for unknown type 1`] = `
|
||||
<NotFoundErrors
|
||||
type="unknown"
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
iconType="alert"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
>
|
||||
<div
|
||||
className="euiCallOut euiCallOut--danger"
|
||||
className="euiCallOutHeader"
|
||||
>
|
||||
<div
|
||||
className="euiCallOutHeader"
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<EuiIcon
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
type="alert"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="euiCallOutHeader__icon"
|
||||
color="inherit"
|
||||
data-euiicon-type="alert"
|
||||
size="m"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<span
|
||||
className="euiCallOutHeader__title"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
<FormattedMessage
|
||||
defaultMessage="There is a problem with this saved object"
|
||||
id="savedObjectsManagement.view.savedObjectProblemErrorMessage"
|
||||
values={Object {}}
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={Object {}}
|
||||
>
|
||||
If you know what this error means, go ahead and fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
There is a problem with this saved object
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
</NotFoundErrors>
|
||||
<EuiText
|
||||
color="default"
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiText euiText--small"
|
||||
>
|
||||
<EuiTextColor
|
||||
color="default"
|
||||
component="div"
|
||||
>
|
||||
<div
|
||||
className="euiTextColor euiTextColor--default"
|
||||
style={Object {}}
|
||||
>
|
||||
<div />
|
||||
<div>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you know what this error means, you can use the {savedObjectsApis} to fix it — otherwise click the delete button above."
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
values={
|
||||
Object {
|
||||
"savedObjectsApis": <EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
</EuiLink>,
|
||||
}
|
||||
}
|
||||
>
|
||||
If you know what this error means, you can use the
|
||||
<EuiLink
|
||||
aria-label="Saved objects APIs"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
target="_blank"
|
||||
>
|
||||
<a
|
||||
aria-label="Saved objects APIs"
|
||||
className="euiLink euiLink--primary"
|
||||
href="https://www.elastic.co/guide/en/kibana/mocked-test-branch/saved-objects-api.html#saved-objects-api"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Saved objects APIs
|
||||
<EuiIcon
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
size="s"
|
||||
type="popout"
|
||||
>
|
||||
<span
|
||||
aria-label="External link"
|
||||
className="euiLink__externalIcon"
|
||||
data-euiicon-type="popout"
|
||||
size="s"
|
||||
/>
|
||||
</EuiIcon>
|
||||
<EuiScreenReaderOnly>
|
||||
<span
|
||||
className="euiScreenReaderOnly"
|
||||
>
|
||||
<EuiI18n
|
||||
default="(opens in a new tab or window)"
|
||||
token="euiLink.newTarget.screenReaderOnlyText"
|
||||
>
|
||||
(opens in a new tab or window)
|
||||
</EuiI18n>
|
||||
</span>
|
||||
</EuiScreenReaderOnly>
|
||||
</a>
|
||||
</EuiLink>
|
||||
to fix it — otherwise click the delete button above.
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
</div>
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
`;
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { Field } from './field';
|
||||
import { FieldState, FieldType } from '../../types';
|
||||
|
||||
describe('Field component', () => {
|
||||
const mountField = (props: {
|
||||
type: FieldType;
|
||||
name: string;
|
||||
value: any;
|
||||
disabled: boolean;
|
||||
state?: FieldState;
|
||||
onChange: (name: string, state: FieldState) => void;
|
||||
}) =>
|
||||
mount(
|
||||
<I18nProvider>
|
||||
<Field {...props} />
|
||||
</I18nProvider>
|
||||
).find('Field');
|
||||
|
||||
const defaultProps = {
|
||||
type: 'text' as FieldType,
|
||||
name: 'field',
|
||||
value: '',
|
||||
disabled: false,
|
||||
state: undefined,
|
||||
onChange: (name: string, state: FieldState) => undefined,
|
||||
};
|
||||
|
||||
it('uses the field name as the label', () => {
|
||||
let mounted = mountField({ ...defaultProps, name: 'some.name' });
|
||||
expect(mounted.find('EuiFormLabel').text()).toMatchInlineSnapshot(`"some.name"`);
|
||||
|
||||
mounted = mountField({ ...defaultProps, name: 'someother.name' });
|
||||
expect(mounted.find('EuiFormLabel').text()).toMatchInlineSnapshot(`"someother.name"`);
|
||||
});
|
||||
|
||||
it('renders a EuiCodeEditor for json type', () => {
|
||||
const mounted = mountField({ ...defaultProps, type: 'json' });
|
||||
expect(mounted.exists('EuiCodeEditor')).toEqual(true);
|
||||
});
|
||||
|
||||
it('renders a EuiCodeEditor for array type', () => {
|
||||
const mounted = mountField({ ...defaultProps, type: 'array' });
|
||||
expect(mounted.exists('EuiCodeEditor')).toEqual(true);
|
||||
});
|
||||
|
||||
it('renders a EuiSwitch for boolean type', () => {
|
||||
const mounted = mountField({ ...defaultProps, type: 'boolean' });
|
||||
expect(mounted.exists('EuiSwitch')).toEqual(true);
|
||||
});
|
||||
|
||||
it('display correct label for boolean type depending on value', () => {
|
||||
let mounted = mountField({ ...defaultProps, type: 'boolean', value: true });
|
||||
expect(mounted.find('EuiSwitch').text()).toMatchInlineSnapshot(`"On"`);
|
||||
|
||||
mounted = mountField({ ...defaultProps, type: 'boolean', value: false });
|
||||
expect(mounted.find('EuiSwitch').text()).toMatchInlineSnapshot(`"Off"`);
|
||||
});
|
||||
|
||||
it('renders a EuiFieldNumber for number type', () => {
|
||||
const mounted = mountField({ ...defaultProps, type: 'number' });
|
||||
expect(mounted.exists('EuiFieldNumber')).toEqual(true);
|
||||
});
|
||||
|
||||
it('renders a EuiFieldText for text type', () => {
|
||||
const mounted = mountField({ ...defaultProps, type: 'text' });
|
||||
expect(mounted.exists('EuiFieldText')).toEqual(true);
|
||||
});
|
||||
|
||||
it('renders a EuiFieldText as fallback', () => {
|
||||
const mounted = mountField({ ...defaultProps, type: 'unknown-type' as any });
|
||||
expect(mounted.exists('EuiFieldText')).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { EuiFieldNumber, EuiFieldText, EuiFormRow, EuiSwitch, EuiCodeEditor } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { FieldState, FieldType } from '../../types';
|
||||
|
||||
interface FieldProps {
|
||||
type: FieldType;
|
||||
name: string;
|
||||
value: any;
|
||||
disabled: boolean;
|
||||
state?: FieldState;
|
||||
onChange: (name: string, state: FieldState) => void;
|
||||
}
|
||||
|
||||
export class Field extends PureComponent<FieldProps> {
|
||||
render() {
|
||||
const { name } = this.props;
|
||||
|
||||
return (
|
||||
<EuiFormRow fullWidth={true} label={name}>
|
||||
{this.renderField()}
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
onCodeEditorChange(targetValue: any) {
|
||||
const { name, onChange } = this.props;
|
||||
let invalid = false;
|
||||
try {
|
||||
JSON.parse(targetValue);
|
||||
} catch (e) {
|
||||
invalid = true;
|
||||
}
|
||||
onChange(name, {
|
||||
value: targetValue,
|
||||
invalid,
|
||||
});
|
||||
}
|
||||
|
||||
onFieldChange(targetValue: any) {
|
||||
const { name, type, onChange } = this.props;
|
||||
|
||||
let newParsedValue = targetValue;
|
||||
let invalid = false;
|
||||
if (type === 'number') {
|
||||
try {
|
||||
newParsedValue = Number(newParsedValue);
|
||||
} catch (e) {
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
onChange(name, {
|
||||
value: newParsedValue,
|
||||
invalid,
|
||||
});
|
||||
}
|
||||
|
||||
renderField() {
|
||||
const { type, name, state, disabled } = this.props;
|
||||
const currentValue = state?.value ?? this.props.value;
|
||||
|
||||
switch (type) {
|
||||
case 'number':
|
||||
return (
|
||||
<EuiFieldNumber
|
||||
name={name}
|
||||
id={this.fieldId}
|
||||
value={currentValue}
|
||||
onChange={(e) => this.onFieldChange(e.target.value)}
|
||||
disabled={disabled}
|
||||
data-test-subj={`savedObjects-editField-${name}`}
|
||||
/>
|
||||
);
|
||||
case 'boolean':
|
||||
return (
|
||||
<EuiSwitch
|
||||
name={name}
|
||||
id={this.fieldId}
|
||||
label={
|
||||
!!currentValue ? (
|
||||
<FormattedMessage id="savedObjectsManagement.field.onLabel" defaultMessage="On" />
|
||||
) : (
|
||||
<FormattedMessage id="savedObjectsManagement.field.offLabel" defaultMessage="Off" />
|
||||
)
|
||||
}
|
||||
checked={!!currentValue}
|
||||
onChange={(e) => this.onFieldChange(e.target.checked)}
|
||||
disabled={disabled}
|
||||
data-test-subj={`savedObjects-editField-${name}`}
|
||||
/>
|
||||
);
|
||||
case 'json':
|
||||
case 'array':
|
||||
return (
|
||||
<div data-test-subj={`savedObjects-editField-${name}`}>
|
||||
<EuiCodeEditor
|
||||
name={`savedObjects-editField-${name}-aceEditor`}
|
||||
mode="json"
|
||||
theme="textmate"
|
||||
value={currentValue}
|
||||
onChange={(value: any) => this.onCodeEditorChange(value)}
|
||||
width="100%"
|
||||
height="auto"
|
||||
minLines={6}
|
||||
maxLines={30}
|
||||
isReadOnly={disabled}
|
||||
setOptions={{
|
||||
showLineNumbers: true,
|
||||
tabSize: 2,
|
||||
useSoftTabs: true,
|
||||
}}
|
||||
editorProps={{
|
||||
$blockScrolling: Infinity,
|
||||
}}
|
||||
showGutter={true}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<EuiFieldText
|
||||
id={this.fieldId}
|
||||
name={name}
|
||||
value={currentValue}
|
||||
onChange={(e) => this.onFieldChange(e.target.value)}
|
||||
disabled={disabled}
|
||||
data-test-subj={`savedObjects-editField-${name}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private get fieldId() {
|
||||
const { name } = this.props;
|
||||
return `savedObjects-editField-${name}`;
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
EuiForm,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { set } from '@elastic/safer-lodash-set';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { SavedObjectsClientContract } from '../../../../../../core/public';
|
||||
import { SavedObjectLoader } from '../../../../../saved_objects/public';
|
||||
import { Field } from './field';
|
||||
import { ObjectField, FieldState, SubmittedFormData } from '../../types';
|
||||
import { createFieldList } from '../../../lib';
|
||||
import { SavedObjectWithMetadata } from '../../../types';
|
||||
|
||||
interface FormProps {
|
||||
object: SavedObjectWithMetadata;
|
||||
service: SavedObjectLoader;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
editionEnabled: boolean;
|
||||
onSave: (form: SubmittedFormData) => Promise<void>;
|
||||
}
|
||||
|
||||
interface FormState {
|
||||
fields: ObjectField[];
|
||||
fieldStates: Record<string, FieldState>;
|
||||
submitting: boolean;
|
||||
}
|
||||
|
||||
export class Form extends Component<FormProps, FormState> {
|
||||
constructor(props: FormProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
fields: [],
|
||||
fieldStates: {},
|
||||
submitting: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { object, service } = this.props;
|
||||
|
||||
const fields = createFieldList(object, service);
|
||||
|
||||
this.setState({
|
||||
fields,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { editionEnabled, service } = this.props;
|
||||
const { fields, fieldStates, submitting } = this.state;
|
||||
const isValid = this.isFormValid();
|
||||
return (
|
||||
<EuiForm data-test-subj="savedObjectEditForm" role="form">
|
||||
{fields.map((field) => (
|
||||
<Field
|
||||
key={`${field.type}-${field.name}`}
|
||||
type={field.type}
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
state={fieldStates[field.name]}
|
||||
disabled={!editionEnabled}
|
||||
onChange={this.handleFieldChange}
|
||||
/>
|
||||
))}
|
||||
<EuiSpacer size={'l'} />
|
||||
<EuiFlexGroup responsive={false} gutterSize={'m'}>
|
||||
{editionEnabled && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
fill={true}
|
||||
aria-label={i18n.translate('savedObjectsManagement.view.saveButtonAriaLabel', {
|
||||
defaultMessage: 'Save { title } object',
|
||||
values: {
|
||||
title: service.type,
|
||||
},
|
||||
})}
|
||||
onClick={this.onSubmit}
|
||||
disabled={!isValid || submitting}
|
||||
data-test-subj="savedObjectEditSave"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.saveButtonLabel"
|
||||
defaultMessage="Save { title } object"
|
||||
values={{ title: service.type }}
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
aria-label={i18n.translate('savedObjectsManagement.view.cancelButtonAriaLabel', {
|
||||
defaultMessage: 'Cancel',
|
||||
})}
|
||||
onClick={this.onCancel}
|
||||
data-test-subj="savedObjectEditCancel"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiForm>
|
||||
);
|
||||
}
|
||||
|
||||
handleFieldChange = (name: string, newState: FieldState) => {
|
||||
this.setState({
|
||||
fieldStates: {
|
||||
...this.state.fieldStates,
|
||||
[name]: newState,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
isFormValid() {
|
||||
const { fieldStates } = this.state;
|
||||
return !Object.values(fieldStates).some((state) => state.invalid === true);
|
||||
}
|
||||
|
||||
onCancel = () => {
|
||||
window.history.back();
|
||||
};
|
||||
|
||||
onSubmit = async () => {
|
||||
const { object, onSave } = this.props;
|
||||
const { fields, fieldStates } = this.state;
|
||||
|
||||
if (!this.isFormValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
submitting: true,
|
||||
});
|
||||
|
||||
const source = cloneDeep(object.attributes as any);
|
||||
fields.forEach((field) => {
|
||||
let value = fieldStates[field.name]?.value ?? field.value;
|
||||
|
||||
if (field.type === 'array' && typeof value === 'string') {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
|
||||
set(source, field.name, value);
|
||||
});
|
||||
|
||||
// we extract the `references` field that does not belong to attributes
|
||||
const { references, ...attributes } = source;
|
||||
|
||||
await onSave({ attributes, references });
|
||||
|
||||
this.setState({
|
||||
submitting: false,
|
||||
});
|
||||
};
|
||||
}
|
|
@ -19,6 +19,7 @@ describe('Intro component', () => {
|
|||
type: string;
|
||||
viewUrl: string;
|
||||
onDeleteClick: () => void;
|
||||
title?: string;
|
||||
}) =>
|
||||
mount(
|
||||
<I18nProvider>
|
||||
|
@ -42,32 +43,11 @@ describe('Intro component', () => {
|
|||
expect(mounted).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('displays correct title depending on canEdit', () => {
|
||||
let mounted = mountHeader({
|
||||
...defaultProps,
|
||||
canEdit: true,
|
||||
});
|
||||
expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Edit search"`);
|
||||
|
||||
mounted = mountHeader({
|
||||
...defaultProps,
|
||||
canEdit: false,
|
||||
});
|
||||
expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"View search"`);
|
||||
});
|
||||
|
||||
it('displays correct title depending on type', () => {
|
||||
let mounted = mountHeader({
|
||||
...defaultProps,
|
||||
type: 'some-type',
|
||||
});
|
||||
expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Edit some-type"`);
|
||||
|
||||
mounted = mountHeader({
|
||||
...defaultProps,
|
||||
type: 'another-type',
|
||||
});
|
||||
expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Edit another-type"`);
|
||||
it('displays correct title if one is provided', () => {
|
||||
let mounted = mountHeader({ ...defaultProps, title: 'my saved search' });
|
||||
expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Inspect my saved search"`);
|
||||
mounted = mountHeader({ ...defaultProps, title: 'my other saved search' });
|
||||
expect(mounted.find('h1').text()).toMatchInlineSnapshot(`"Inspect my other saved search"`);
|
||||
});
|
||||
|
||||
it('only displays delete button if canDelete is true', () => {
|
||||
|
|
|
@ -9,43 +9,24 @@
|
|||
import React from 'react';
|
||||
import { EuiButton, EuiPageHeader } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
interface HeaderProps {
|
||||
canEdit: boolean;
|
||||
canDelete: boolean;
|
||||
canViewInApp: boolean;
|
||||
type: string;
|
||||
viewUrl: string;
|
||||
onDeleteClick: () => void;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const renderConditionalTitle = (canEdit: boolean, type: string) =>
|
||||
canEdit ? (
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.editItemTitle"
|
||||
defaultMessage="Edit {title}"
|
||||
values={{ title: type }}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.viewItemTitle"
|
||||
defaultMessage="View {title}"
|
||||
values={{ title: type }}
|
||||
/>
|
||||
);
|
||||
|
||||
export const Header = ({
|
||||
canEdit,
|
||||
canDelete,
|
||||
canViewInApp,
|
||||
type,
|
||||
viewUrl,
|
||||
onDeleteClick,
|
||||
}: HeaderProps) => {
|
||||
export const Header = ({ canDelete, canViewInApp, viewUrl, onDeleteClick, title }: HeaderProps) => {
|
||||
return (
|
||||
<EuiPageHeader
|
||||
bottomBorder
|
||||
pageTitle={renderConditionalTitle(canEdit, type)}
|
||||
pageTitle={i18n.translate('savedObjectsManagement.view.inspectItemTitle', {
|
||||
defaultMessage: 'Inspect {title}',
|
||||
values: { title: title || 'saved object' },
|
||||
})}
|
||||
rightSideItems={[
|
||||
canViewInApp && (
|
||||
<EuiButton
|
||||
|
@ -57,7 +38,7 @@ export const Header = ({
|
|||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.viewItemButtonLabel"
|
||||
defaultMessage="View {title}"
|
||||
values={{ title: type }}
|
||||
values={{ title: title || 'saved object' }}
|
||||
/>
|
||||
</EuiButton>
|
||||
),
|
||||
|
@ -71,8 +52,7 @@ export const Header = ({
|
|||
>
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.deleteItemButtonLabel"
|
||||
defaultMessage="Delete {title}"
|
||||
values={{ title: type }}
|
||||
defaultMessage="Delete"
|
||||
/>
|
||||
</EuiButton>
|
||||
),
|
||||
|
|
|
@ -7,6 +7,5 @@
|
|||
*/
|
||||
|
||||
export { Header } from './header';
|
||||
export { Inspect } from './inspect';
|
||||
export { NotFoundErrors } from './not_found_errors';
|
||||
export { Intro } from './intro';
|
||||
export { Form } from './form';
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ShallowWrapper } from 'enzyme';
|
||||
import { shallowWithI18nProvider } from '@kbn/test/jest';
|
||||
import { Inspect, InspectProps } from './inspect';
|
||||
import { SavedObjectWithMetadata } from '../../../../common';
|
||||
|
||||
describe('Inspect component', () => {
|
||||
let defaultProps: { object: SavedObjectWithMetadata };
|
||||
const shallowRender = (overrides: Partial<SavedObjectWithMetadata> = {}) => {
|
||||
return shallowWithI18nProvider(
|
||||
<Inspect {...defaultProps} {...overrides} />
|
||||
) as unknown as ShallowWrapper<InspectProps>;
|
||||
};
|
||||
beforeEach(() => {
|
||||
defaultProps = {
|
||||
object: {
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: `MyIndexPattern*`,
|
||||
},
|
||||
meta: {
|
||||
title: `MyIndexPattern*`,
|
||||
icon: 'indexPatternApp',
|
||||
editUrl: '#/management/kibana/indexPatterns/patterns/1',
|
||||
inAppUrl: {
|
||||
path: '/management/kibana/indexPatterns/patterns/1',
|
||||
uiCapabilitiesPath: 'management.kibana.indexPatterns',
|
||||
},
|
||||
},
|
||||
references: [],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('renders correctly', async () => {
|
||||
const component = shallowRender();
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.update();
|
||||
const codeEditorComponent = component.find('CodeEditor');
|
||||
expect(codeEditorComponent).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not include `meta` in the value that's rendered", async () => {
|
||||
const component = shallowRender();
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.update();
|
||||
const codeEditorComponent = component.find('CodeEditor');
|
||||
// find could return nothing
|
||||
const editorValue = codeEditorComponent
|
||||
? (codeEditorComponent.prop('value') as unknown as string)
|
||||
: '';
|
||||
// we assert against the expected object props rather than asserting that 'meta' is removed
|
||||
expect(Object.keys(JSON.parse(editorValue))).toEqual([
|
||||
'id',
|
||||
'type',
|
||||
'attributes',
|
||||
'references',
|
||||
]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { XJsonLang } from '@kbn/monaco';
|
||||
import { omit } from 'lodash';
|
||||
import { EuiButtonEmpty, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
import { CodeEditor } from '../../../../../kibana_react/public';
|
||||
import { SavedObjectWithMetadata } from '../../../../common';
|
||||
|
||||
export interface InspectProps {
|
||||
object: SavedObjectWithMetadata<any>;
|
||||
}
|
||||
const codeEditorAriaLabel = (title: string) =>
|
||||
i18n.translate('savedObjectsManagement.view.inspectCodeEditorAriaLabel', {
|
||||
defaultMessage: 'inspect { title }',
|
||||
values: {
|
||||
title,
|
||||
},
|
||||
});
|
||||
const copyToClipboardLabel = i18n.translate('savedObjectsManagement.view.copyToClipboardLabel', {
|
||||
defaultMessage: 'Copy to clipboard',
|
||||
});
|
||||
|
||||
export const Inspect: FC<InspectProps> = ({ object }) => {
|
||||
const title = object.meta.title || 'saved object';
|
||||
|
||||
const objectAsJsonString = useMemo(() => JSON.stringify(omit(object, 'meta'), null, 2), [object]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<div className="eui-textRight">
|
||||
<EuiCopy textToCopy={objectAsJsonString}>
|
||||
{(copy) => (
|
||||
<EuiButtonEmpty
|
||||
aria-label={copyToClipboardLabel}
|
||||
size="s"
|
||||
flush="right"
|
||||
iconType="copyClipboard"
|
||||
onClick={copy}
|
||||
>
|
||||
{copyToClipboardLabel}
|
||||
</EuiButtonEmpty>
|
||||
)}
|
||||
</EuiCopy>
|
||||
<EuiSpacer size="s" />
|
||||
</div>
|
||||
<CodeEditor
|
||||
languageId={XJsonLang.ID}
|
||||
value={objectAsJsonString}
|
||||
aria-label={codeEditorAriaLabel(title)}
|
||||
options={{
|
||||
automaticLayout: false,
|
||||
fontSize: 12,
|
||||
lineNumbers: 'on',
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
overviewRulerBorder: false,
|
||||
readOnly: true,
|
||||
scrollbar: {
|
||||
alwaysConsumeMouseWheel: false,
|
||||
},
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: 'on',
|
||||
wrappingIndent: 'indent',
|
||||
renderIndentGuides: false,
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { Intro } from './intro';
|
||||
|
||||
describe('Intro component', () => {
|
||||
it('renders correctly', () => {
|
||||
const mounted = mount(
|
||||
<I18nProvider>
|
||||
<Intro />
|
||||
</I18nProvider>
|
||||
);
|
||||
expect(mounted.find('Intro')).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export const Intro = () => {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.howToModifyObjectTitle"
|
||||
defaultMessage="Proceed with caution!"
|
||||
/>
|
||||
}
|
||||
iconType="alert"
|
||||
color="warning"
|
||||
>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.howToModifyObjectDescription"
|
||||
defaultMessage="Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be."
|
||||
/>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
|
@ -10,44 +10,49 @@ import React from 'react';
|
|||
import { mount } from 'enzyme';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { NotFoundErrors } from './not_found_errors';
|
||||
import { docLinksServiceMock } from '../../../../../../core/public/mocks';
|
||||
|
||||
describe('NotFoundErrors component', () => {
|
||||
const mountError = (type: string) =>
|
||||
mount(
|
||||
<I18nProvider>
|
||||
<NotFoundErrors type={type} />
|
||||
<NotFoundErrors type={type} docLinks={docLinksServiceMock.createStartContract().links} />
|
||||
</I18nProvider>
|
||||
).find('NotFoundErrors');
|
||||
|
||||
it('renders correctly for search type', () => {
|
||||
const mounted = mountError('search');
|
||||
expect(mounted).toMatchSnapshot();
|
||||
const callOut = mounted.find('EuiCallOut');
|
||||
expect(callOut).toMatchSnapshot();
|
||||
expect(mounted.text()).toMatchInlineSnapshot(
|
||||
`"There is a problem with this saved objectThe saved search associated with this object no longer exists.If you know what this error means, go ahead and fix it — otherwise click the delete button above."`
|
||||
`"There is a problem with this saved objectThe saved search associated with this object no longer exists.If you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."`
|
||||
);
|
||||
});
|
||||
|
||||
it('renders correctly for index-pattern type', () => {
|
||||
const mounted = mountError('index-pattern');
|
||||
expect(mounted).toMatchSnapshot();
|
||||
const callOut = mounted.find('EuiCallOut');
|
||||
expect(callOut).toMatchSnapshot();
|
||||
expect(mounted.text()).toMatchInlineSnapshot(
|
||||
`"There is a problem with this saved objectThe index pattern associated with this object no longer exists.If you know what this error means, go ahead and fix it — otherwise click the delete button above."`
|
||||
`"There is a problem with this saved objectThe index pattern associated with this object no longer exists.If you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."`
|
||||
);
|
||||
});
|
||||
|
||||
it('renders correctly for index-pattern-field type', () => {
|
||||
const mounted = mountError('index-pattern-field');
|
||||
expect(mounted).toMatchSnapshot();
|
||||
const callOut = mounted.find('EuiCallOut');
|
||||
expect(callOut).toMatchSnapshot();
|
||||
expect(mounted.text()).toMatchInlineSnapshot(
|
||||
`"There is a problem with this saved objectA field associated with this object no longer exists in the index pattern.If you know what this error means, go ahead and fix it — otherwise click the delete button above."`
|
||||
`"There is a problem with this saved objectA field associated with this object no longer exists in the index pattern.If you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."`
|
||||
);
|
||||
});
|
||||
|
||||
it('renders correctly for unknown type', () => {
|
||||
const mounted = mountError('unknown');
|
||||
expect(mounted).toMatchSnapshot();
|
||||
const callOut = mounted.find('EuiCallOut');
|
||||
expect(callOut).toMatchSnapshot();
|
||||
expect(mounted.text()).toMatchInlineSnapshot(
|
||||
`"There is a problem with this saved objectIf you know what this error means, go ahead and fix it — otherwise click the delete button above."`
|
||||
`"There is a problem with this saved objectIf you know what this error means, you can use the Saved objects APIs(opens in a new tab or window) to fix it — otherwise click the delete button above."`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
|
||||
import React from 'react';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiLink } from '@elastic/eui';
|
||||
import { DocLinksStart } from '../../../../../../core/public';
|
||||
|
||||
interface NotFoundErrors {
|
||||
type: string;
|
||||
docLinks: DocLinksStart['links'];
|
||||
}
|
||||
const savedObjectsApisLinkText = i18n.translate(
|
||||
'savedObjectsManagement.view.howToFixErrorDescriptionLinkText',
|
||||
{
|
||||
defaultMessage: 'Saved objects APIs',
|
||||
}
|
||||
);
|
||||
|
||||
export const NotFoundErrors = ({ type }: NotFoundErrors) => {
|
||||
export const NotFoundErrors = ({ type, docLinks }: NotFoundErrors) => {
|
||||
const getMessage = () => {
|
||||
switch (type) {
|
||||
case 'search':
|
||||
|
@ -58,7 +68,18 @@ export const NotFoundErrors = ({ type }: NotFoundErrors) => {
|
|||
<div>
|
||||
<FormattedMessage
|
||||
id="savedObjectsManagement.view.howToFixErrorDescription"
|
||||
defaultMessage="If you know what this error means, go ahead and fix it — otherwise click the delete button above."
|
||||
defaultMessage="If you know what this error means, you can use the {savedObjectsApis} to fix it — otherwise click the delete button above."
|
||||
values={{
|
||||
savedObjectsApis: (
|
||||
<EuiLink
|
||||
aria-label={savedObjectsApisLinkText}
|
||||
href={`${docLinks.management.savedObjectsApiList}`}
|
||||
target="_blank"
|
||||
>
|
||||
{savedObjectsApisLinkText}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</EuiCallOut>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.savedObjectsManagementObjectView {
|
||||
height: 100%;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
jest.doMock('lodash', () => {
|
||||
const original = jest.requireActual('lodash');
|
||||
return {
|
||||
...original,
|
||||
get: (func: Function) => {
|
||||
function get(this: any, args: any[]) {
|
||||
return func.apply(this, args);
|
||||
}
|
||||
return get;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const bulkGetObjectsMock = jest.fn();
|
||||
jest.doMock('../../lib/bulk_get_objects', () => ({
|
||||
bulkGetObjects: bulkGetObjectsMock,
|
||||
}));
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { bulkGetObjectsMock } from './saved_object_view.test.mocks';
|
||||
|
||||
import React from 'react';
|
||||
import { ShallowWrapper } from 'enzyme';
|
||||
import { shallowWithI18nProvider } from '@kbn/test/jest';
|
||||
|
||||
import {
|
||||
httpServiceMock,
|
||||
overlayServiceMock,
|
||||
notificationServiceMock,
|
||||
savedObjectsServiceMock,
|
||||
applicationServiceMock,
|
||||
uiSettingsServiceMock,
|
||||
scopedHistoryMock,
|
||||
docLinksServiceMock,
|
||||
} from '../../../../../core/public/mocks';
|
||||
|
||||
import {
|
||||
SavedObjectEdition,
|
||||
SavedObjectEditionProps,
|
||||
SavedObjectEditionState,
|
||||
} from './saved_object_view';
|
||||
|
||||
const resolvePromises = () => new Promise((resolve) => process.nextTick(resolve));
|
||||
|
||||
describe('SavedObjectEdition', () => {
|
||||
let defaultProps: SavedObjectEditionProps;
|
||||
let http: ReturnType<typeof httpServiceMock.createStartContract>;
|
||||
let overlays: ReturnType<typeof overlayServiceMock.createStartContract>;
|
||||
let notifications: ReturnType<typeof notificationServiceMock.createStartContract>;
|
||||
let savedObjects: ReturnType<typeof savedObjectsServiceMock.createStartContract>;
|
||||
let uiSettings: ReturnType<typeof uiSettingsServiceMock.createStartContract>;
|
||||
let history: ReturnType<typeof scopedHistoryMock.create>;
|
||||
let applications: ReturnType<typeof applicationServiceMock.createStartContract>;
|
||||
let docLinks: ReturnType<typeof docLinksServiceMock.createStartContract>;
|
||||
|
||||
const shallowRender = (overrides: Partial<SavedObjectEditionProps> = {}) => {
|
||||
return shallowWithI18nProvider(
|
||||
<SavedObjectEdition {...defaultProps} {...overrides} />
|
||||
) as unknown as ShallowWrapper<
|
||||
SavedObjectEditionProps,
|
||||
SavedObjectEditionState,
|
||||
SavedObjectEdition
|
||||
>;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
http = httpServiceMock.createStartContract();
|
||||
overlays = overlayServiceMock.createStartContract();
|
||||
notifications = notificationServiceMock.createStartContract();
|
||||
savedObjects = savedObjectsServiceMock.createStartContract();
|
||||
uiSettings = uiSettingsServiceMock.createStartContract();
|
||||
history = scopedHistoryMock.create();
|
||||
docLinks = docLinksServiceMock.createStartContract();
|
||||
applications = applicationServiceMock.createStartContract();
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
savedObjectsManagement: {
|
||||
read: true,
|
||||
edit: false,
|
||||
delete: false,
|
||||
},
|
||||
};
|
||||
|
||||
http.post.mockResolvedValue([]);
|
||||
|
||||
defaultProps = {
|
||||
id: '1',
|
||||
savedObjectType: 'dashboard',
|
||||
http,
|
||||
capabilities: applications.capabilities,
|
||||
overlays,
|
||||
notifications,
|
||||
savedObjectsClient: savedObjects.client,
|
||||
history,
|
||||
uiSettings,
|
||||
docLinks: docLinks.links,
|
||||
};
|
||||
|
||||
bulkGetObjectsMock.mockImplementation(() => [{}]);
|
||||
});
|
||||
|
||||
it('should render normally', async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
id: '1',
|
||||
type: 'dashboard',
|
||||
attributes: {
|
||||
title: `MyDashboard*`,
|
||||
},
|
||||
meta: {
|
||||
title: `MyDashboard*`,
|
||||
icon: 'dashboardApp',
|
||||
inAppUrl: {
|
||||
path: '/app/dashboards#/view/1',
|
||||
uiCapabilitiesPath: 'management.kibana.dashboard',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
);
|
||||
const component = shallowRender();
|
||||
// Ensure all promises resolve
|
||||
await resolvePromises();
|
||||
// Ensure the state changes are reflected
|
||||
component.update();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should add danger toast when bulk get fails', async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
error: {
|
||||
message: 'Not found',
|
||||
},
|
||||
},
|
||||
])
|
||||
);
|
||||
const component = shallowRender({ notFoundType: 'does_not_exist' });
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
|
||||
expect(notifications.toasts.addDanger).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should add danger toast when bulk get throws', async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() => Promise.reject(new Error('fail')));
|
||||
const component = shallowRender({ notFoundType: 'does_not_exist' });
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
|
||||
expect(notifications.toasts.addDanger).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should pass the correct props to the child components', async () => {
|
||||
const savedObjectItem = {
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: `MyIndexPattern*`,
|
||||
},
|
||||
meta: {
|
||||
title: `MyIndexPattern*`,
|
||||
icon: 'indexPatternApp',
|
||||
editUrl: '#/management/kibana/indexPatterns/patterns/1',
|
||||
inAppUrl: {
|
||||
path: '/management/kibana/indexPatterns/patterns/1',
|
||||
uiCapabilitiesPath: 'management.kibana.indexPatterns',
|
||||
},
|
||||
hiddenType: false,
|
||||
},
|
||||
};
|
||||
bulkGetObjectsMock.mockImplementation(() => Promise.resolve([savedObjectItem]));
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
savedObjectsManagement: {
|
||||
read: true,
|
||||
edit: false,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
const component = shallowRender({
|
||||
capabilities: applications.capabilities,
|
||||
});
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
const headerComponent = component.find('Header');
|
||||
expect(headerComponent.prop('canViewInApp')).toBe(true);
|
||||
expect(headerComponent.prop('canDelete')).toBe(true);
|
||||
expect(headerComponent.prop('viewUrl')).toEqual('/management/kibana/indexPatterns/patterns/1');
|
||||
const inspectComponent = component.find('Inspect');
|
||||
expect(inspectComponent.prop('object')).toEqual(savedObjectItem);
|
||||
});
|
||||
|
||||
it("does not render Inspect if there isn't an object", async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() => Promise.resolve([]));
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
savedObjectsManagement: {
|
||||
read: true,
|
||||
edit: false,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
const component = shallowRender({
|
||||
capabilities: applications.capabilities,
|
||||
});
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
const inspectComponent = component.find('Inspect');
|
||||
expect(inspectComponent).toEqual({});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
const savedObjectItem = {
|
||||
id: '1',
|
||||
type: 'index-pattern',
|
||||
attributes: {
|
||||
title: `MyIndexPattern*`,
|
||||
},
|
||||
meta: {
|
||||
title: `MyIndexPattern*`,
|
||||
icon: 'indexPatternApp',
|
||||
editUrl: '#/management/kibana/indexPatterns/patterns/1',
|
||||
inAppUrl: {
|
||||
path: '/management/kibana/indexPatterns/patterns/1',
|
||||
uiCapabilitiesPath: 'management.kibana.indexPatterns',
|
||||
},
|
||||
hiddenType: false,
|
||||
},
|
||||
};
|
||||
|
||||
it('should display a confirmation message on deleting the saved object', async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() => Promise.resolve([savedObjectItem]));
|
||||
const mockSavedObjectsClient = {
|
||||
...defaultProps.savedObjectsClient,
|
||||
delete: jest.fn().mockImplementation(() => ({})),
|
||||
};
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
savedObjectsManagement: {
|
||||
read: true,
|
||||
edit: false,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
overlays.openConfirm.mockResolvedValue(false);
|
||||
const component = shallowRender({
|
||||
capabilities: applications.capabilities,
|
||||
savedObjectsClient: mockSavedObjectsClient,
|
||||
overlays,
|
||||
});
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
component.instance().delete();
|
||||
expect(overlays.openConfirm).toHaveBeenCalledWith(
|
||||
'This action permanently removes the object from Kibana.',
|
||||
{
|
||||
buttonColor: 'danger',
|
||||
confirmButtonText: 'Delete',
|
||||
title: `Delete '${savedObjectItem.meta.title}'?`,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should route back if action is confirm and user accepted', async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() => Promise.resolve([savedObjectItem]));
|
||||
const mockSavedObjectsClient = {
|
||||
...defaultProps.savedObjectsClient,
|
||||
delete: jest.fn().mockImplementation(() => ({})),
|
||||
};
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
savedObjectsManagement: {
|
||||
read: true,
|
||||
edit: false,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
overlays.openConfirm.mockResolvedValue(true);
|
||||
const component = shallowRender({
|
||||
capabilities: applications.capabilities,
|
||||
savedObjectsClient: mockSavedObjectsClient,
|
||||
overlays,
|
||||
});
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
component.instance().delete();
|
||||
expect(overlays.openConfirm).toHaveBeenCalledTimes(1);
|
||||
expect(history.location.pathname).toEqual('/');
|
||||
});
|
||||
|
||||
it('should not enable delete if the saved object is hidden', async () => {
|
||||
bulkGetObjectsMock.mockImplementation(() =>
|
||||
Promise.resolve([{ ...savedObjectItem, meta: { hiddenType: true } }])
|
||||
);
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
catalogue: {},
|
||||
savedObjectsManagement: {
|
||||
read: true,
|
||||
edit: false,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
const component = shallowRender({
|
||||
capabilities: applications.capabilities,
|
||||
});
|
||||
|
||||
await resolvePromises();
|
||||
|
||||
component.update();
|
||||
expect(component.find('Header').prop('canDelete')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
|
||||
import { get } from 'lodash';
|
||||
import { KibanaContextProvider } from '../../../../kibana_react/public';
|
||||
import {
|
||||
Capabilities,
|
||||
SavedObjectsClientContract,
|
||||
|
@ -16,27 +18,27 @@ import {
|
|||
NotificationsStart,
|
||||
ScopedHistory,
|
||||
HttpSetup,
|
||||
IUiSettingsClient,
|
||||
DocLinksStart,
|
||||
} from '../../../../../core/public';
|
||||
import { ISavedObjectsManagementServiceRegistry } from '../../services';
|
||||
import { Header, NotFoundErrors, Intro, Form } from './components';
|
||||
import { canViewInApp, bulkGetObjects } from '../../lib';
|
||||
import { SubmittedFormData } from '../types';
|
||||
import { Header, Inspect, NotFoundErrors } from './components';
|
||||
import { bulkGetObjects } from '../../lib/bulk_get_objects';
|
||||
import { SavedObjectWithMetadata } from '../../types';
|
||||
|
||||
interface SavedObjectEditionProps {
|
||||
import './saved_object_view.scss';
|
||||
export interface SavedObjectEditionProps {
|
||||
id: string;
|
||||
savedObjectType: string;
|
||||
http: HttpSetup;
|
||||
serviceName: string;
|
||||
serviceRegistry: ISavedObjectsManagementServiceRegistry;
|
||||
capabilities: Capabilities;
|
||||
overlays: OverlayStart;
|
||||
notifications: NotificationsStart;
|
||||
notFoundType?: string;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
history: ScopedHistory;
|
||||
uiSettings: IUiSettingsClient;
|
||||
docLinks: DocLinksStart['links'];
|
||||
}
|
||||
|
||||
interface SavedObjectEditionState {
|
||||
export interface SavedObjectEditionState {
|
||||
type: string;
|
||||
object?: SavedObjectWithMetadata<any>;
|
||||
}
|
||||
|
@ -45,7 +47,6 @@ const unableFindSavedObjectNotificationMessage = i18n.translate(
|
|||
'savedObjectsManagement.objectView.unableFindSavedObjectNotificationMessage',
|
||||
{ defaultMessage: 'Unable to find saved object' }
|
||||
);
|
||||
|
||||
export class SavedObjectEdition extends Component<
|
||||
SavedObjectEditionProps,
|
||||
SavedObjectEditionState
|
||||
|
@ -53,8 +54,7 @@ export class SavedObjectEdition extends Component<
|
|||
constructor(props: SavedObjectEditionProps) {
|
||||
super(props);
|
||||
|
||||
const { serviceRegistry, serviceName } = props;
|
||||
const type = serviceRegistry.get(serviceName)!.service.type;
|
||||
const { savedObjectType: type } = props;
|
||||
|
||||
this.state = {
|
||||
object: undefined,
|
||||
|
@ -85,54 +85,46 @@ export class SavedObjectEdition extends Component<
|
|||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { capabilities, notFoundType, serviceRegistry, http, serviceName, savedObjectsClient } =
|
||||
this.props;
|
||||
const { type } = this.state;
|
||||
const { object } = this.state;
|
||||
const { edit: canEdit, delete: canDelete } = capabilities.savedObjectsManagement as Record<
|
||||
string,
|
||||
boolean
|
||||
>;
|
||||
const canView = canViewInApp(capabilities, type) && Boolean(object?.meta.inAppUrl?.path);
|
||||
const service = serviceRegistry.get(serviceName)!.service;
|
||||
canViewInApp(capabilities: Capabilities, obj?: SavedObjectWithMetadata<any>) {
|
||||
return obj && obj.meta.inAppUrl
|
||||
? get(capabilities, obj?.meta.inAppUrl?.uiCapabilitiesPath, false) &&
|
||||
Boolean(obj?.meta.inAppUrl?.path)
|
||||
: false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { capabilities, notFoundType, http, uiSettings, docLinks } = this.props;
|
||||
const { object } = this.state;
|
||||
const { delete: canDelete } = capabilities.savedObjectsManagement as Record<string, boolean>;
|
||||
const canView = this.canViewInApp(capabilities, object);
|
||||
return (
|
||||
<div data-test-subj="savedObjectsEdit">
|
||||
<Header
|
||||
canEdit={canEdit}
|
||||
canDelete={canDelete && !object?.meta.hiddenType}
|
||||
canViewInApp={canView}
|
||||
type={type}
|
||||
onDeleteClick={() => this.delete()}
|
||||
viewUrl={http.basePath.prepend(object?.meta.inAppUrl?.path || '')}
|
||||
/>
|
||||
<EuiSpacer size="l" />
|
||||
{notFoundType && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<NotFoundErrors type={notFoundType} />
|
||||
</>
|
||||
)}
|
||||
{canEdit && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<Intro />
|
||||
</>
|
||||
)}
|
||||
{object && (
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
<Form
|
||||
object={object}
|
||||
savedObjectsClient={savedObjectsClient}
|
||||
service={service}
|
||||
editionEnabled={canEdit}
|
||||
onSave={this.saveChanges}
|
||||
<KibanaContextProvider services={{ uiSettings }}>
|
||||
<EuiFlexGroup
|
||||
direction="column"
|
||||
data-test-subject="savedObjectsEdit"
|
||||
className="savedObjectsManagementObjectView"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<Header
|
||||
canDelete={canDelete && !object?.meta.hiddenType}
|
||||
canViewInApp={canView}
|
||||
onDeleteClick={() => this.delete()}
|
||||
viewUrl={http.basePath.prepend(object?.meta.inAppUrl?.path || '')}
|
||||
title={object?.meta.title}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
{notFoundType && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<NotFoundErrors type={notFoundType} docLinks={docLinks} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
{object && (
|
||||
<EuiFlexItem grow={true}>
|
||||
<Inspect object={object} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -167,15 +159,6 @@ export class SavedObjectEdition extends Component<
|
|||
}
|
||||
}
|
||||
|
||||
saveChanges = async ({ attributes, references }: SubmittedFormData) => {
|
||||
const { savedObjectsClient, notifications } = this.props;
|
||||
const { object, type } = this.state;
|
||||
|
||||
await savedObjectsClient.update(object!.type, object!.id, attributes, { references });
|
||||
notifications.toasts.addSuccess(`Updated '${attributes.title}' ${type} object`);
|
||||
this.redirectToListing();
|
||||
};
|
||||
|
||||
redirectToListing() {
|
||||
this.props.history.push('/');
|
||||
}
|
||||
|
|
|
@ -192,7 +192,6 @@ exports[`SavedObjectsTable should render normally 1`] = `
|
|||
Object {
|
||||
"id": "2",
|
||||
"meta": Object {
|
||||
"editUrl": "/management/kibana/objects/savedSearches/2",
|
||||
"icon": "search",
|
||||
"inAppUrl": Object {
|
||||
"path": "/discover/2",
|
||||
|
@ -205,7 +204,6 @@ exports[`SavedObjectsTable should render normally 1`] = `
|
|||
Object {
|
||||
"id": "3",
|
||||
"meta": Object {
|
||||
"editUrl": "/management/kibana/objects/savedDashboards/3",
|
||||
"icon": "dashboardApp",
|
||||
"inAppUrl": Object {
|
||||
"path": "/dashboard/3",
|
||||
|
@ -218,7 +216,6 @@ exports[`SavedObjectsTable should render normally 1`] = `
|
|||
Object {
|
||||
"id": "4",
|
||||
"meta": Object {
|
||||
"editUrl": "/management/kibana/objects/savedVisualizations/4",
|
||||
"icon": "visualizeApp",
|
||||
"inAppUrl": Object {
|
||||
"path": "/edit/4",
|
||||
|
|
|
@ -146,7 +146,6 @@ exports[`Table prevents saved objects from being deleted 1`] = `
|
|||
Object {
|
||||
"actions": Array [
|
||||
Object {
|
||||
"available": [Function],
|
||||
"data-test-subj": "savedObjectsTableAction-inspect",
|
||||
"description": "Inspect this saved object",
|
||||
"icon": "inspect",
|
||||
|
@ -362,7 +361,6 @@ exports[`Table should render normally 1`] = `
|
|||
Object {
|
||||
"actions": Array [
|
||||
Object {
|
||||
"available": [Function],
|
||||
"data-test-subj": "savedObjectsTableAction-inspect",
|
||||
"description": "Inspect this saved object",
|
||||
"icon": "inspect",
|
||||
|
|
|
@ -11,7 +11,6 @@ import { importFileMock, resolveImportErrorsMock } from './flyout.test.mocks';
|
|||
import React from 'react';
|
||||
import { shallowWithI18nProvider } from '@kbn/test/jest';
|
||||
import { coreMock, httpServiceMock } from '../../../../../../core/public/mocks';
|
||||
import { serviceRegistryMock } from '../../../services/service_registry.mock';
|
||||
import { Flyout, FlyoutProps, FlyoutState } from './flyout';
|
||||
import { ShallowWrapper } from 'enzyme';
|
||||
import { dataPluginMock } from '../../../../../data/public/mocks';
|
||||
|
@ -49,7 +48,6 @@ describe('Flyout', () => {
|
|||
} as any,
|
||||
http,
|
||||
allowedTypes: ['search', 'index-pattern', 'visualization'],
|
||||
serviceRegistry: serviceRegistryMock.create(),
|
||||
search,
|
||||
basePath,
|
||||
};
|
||||
|
|
|
@ -43,7 +43,6 @@ import {
|
|||
processImportResponse,
|
||||
ProcessedImportResponse,
|
||||
} from '../../../lib';
|
||||
import { ISavedObjectsManagementServiceRegistry } from '../../../services';
|
||||
import { FailedImportConflict, RetryDecision } from '../../../lib/resolve_import_errors';
|
||||
import { OverwriteModal } from './overwrite_modal';
|
||||
import { ImportModeControl, ImportMode } from './import_mode_control';
|
||||
|
@ -53,7 +52,6 @@ const CREATE_NEW_COPIES_DEFAULT = false;
|
|||
const OVERWRITE_ALL_DEFAULT = true;
|
||||
|
||||
export interface FlyoutProps {
|
||||
serviceRegistry: ISavedObjectsManagementServiceRegistry;
|
||||
allowedTypes: string[];
|
||||
close: () => void;
|
||||
done: () => void;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import './import_summary.scss';
|
||||
import _ from 'lodash';
|
||||
import React, { Fragment, FC, useMemo } from 'react';
|
||||
import {
|
||||
|
@ -30,6 +29,7 @@ import type {
|
|||
IBasePath,
|
||||
} from 'kibana/public';
|
||||
import { getDefaultTitle, getSavedObjectLabel, FailedImport } from '../../../lib';
|
||||
import './import_summary.scss';
|
||||
|
||||
const DEFAULT_ICON = 'apps';
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ export class Relationships extends Component<RelationshipsProps, RelationshipsSt
|
|||
icon: 'inspect',
|
||||
'data-test-subj': 'relationshipsTableAction-inspect',
|
||||
onClick: (object: SavedObjectWithMetadata) => goInspectObject(object),
|
||||
available: (object: SavedObjectWithMetadata) => !!object.meta.editUrl,
|
||||
available: (object: SavedObjectWithMetadata) => !!(object.type && object.id),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -243,7 +243,6 @@ export class Table extends PureComponent<TableProps, TableState> {
|
|||
type: 'icon',
|
||||
icon: 'inspect',
|
||||
onClick: (object) => goInspectObject(object),
|
||||
available: (object) => !!object.meta.editUrl,
|
||||
'data-test-subj': 'savedObjectsTableAction-inspect',
|
||||
},
|
||||
{
|
||||
|
|
|
@ -28,7 +28,6 @@ import {
|
|||
applicationServiceMock,
|
||||
} from '../../../../../core/public/mocks';
|
||||
import { dataPluginMock } from '../../../../data/public/mocks';
|
||||
import { serviceRegistryMock } from '../../services/service_registry.mock';
|
||||
import { actionServiceMock } from '../../services/action_service.mock';
|
||||
import { columnServiceMock } from '../../services/column_service.mock';
|
||||
import {
|
||||
|
@ -122,7 +121,6 @@ describe('SavedObjectsTable', () => {
|
|||
|
||||
defaultProps = {
|
||||
allowedTypes,
|
||||
serviceRegistry: serviceRegistryMock.create(),
|
||||
actionRegistry: actionServiceMock.createStart(),
|
||||
columnRegistry: columnServiceMock.createStart(),
|
||||
savedObjectsClient: savedObjects.client,
|
||||
|
@ -159,7 +157,6 @@ describe('SavedObjectsTable', () => {
|
|||
meta: {
|
||||
title: `MySearch`,
|
||||
icon: 'search',
|
||||
editUrl: '/management/kibana/objects/savedSearches/2',
|
||||
inAppUrl: {
|
||||
path: '/discover/2',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
|
@ -172,7 +169,6 @@ describe('SavedObjectsTable', () => {
|
|||
meta: {
|
||||
title: `MyDashboard`,
|
||||
icon: 'dashboardApp',
|
||||
editUrl: '/management/kibana/objects/savedDashboards/3',
|
||||
inAppUrl: {
|
||||
path: '/dashboard/3',
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
|
@ -185,7 +181,6 @@ describe('SavedObjectsTable', () => {
|
|||
meta: {
|
||||
title: `MyViz`,
|
||||
icon: 'visualizeApp',
|
||||
editUrl: '/management/kibana/objects/savedVisualizations/4',
|
||||
inAppUrl: {
|
||||
path: '/edit/4',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
|
|
@ -37,7 +37,6 @@ import {
|
|||
} from '../../lib';
|
||||
import { SavedObjectWithMetadata } from '../../types';
|
||||
import {
|
||||
ISavedObjectsManagementServiceRegistry,
|
||||
SavedObjectsManagementActionServiceStart,
|
||||
SavedObjectsManagementColumnServiceStart,
|
||||
} from '../../services';
|
||||
|
@ -58,7 +57,6 @@ interface ExportAllOption {
|
|||
|
||||
export interface SavedObjectsTableProps {
|
||||
allowedTypes: string[];
|
||||
serviceRegistry: ISavedObjectsManagementServiceRegistry;
|
||||
actionRegistry: SavedObjectsManagementActionServiceStart;
|
||||
columnRegistry: SavedObjectsManagementColumnServiceStart;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
|
@ -540,7 +538,6 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
|
|||
close={this.hideImportFlyout}
|
||||
done={this.finishImport}
|
||||
http={this.props.http}
|
||||
serviceRegistry={this.props.serviceRegistry}
|
||||
indexPatterns={this.props.indexPatterns}
|
||||
newIndexPatternUrl={newIndexPatternUrl}
|
||||
allowedTypes={this.props.allowedTypes}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.savedObjectsManagementEditionPage {
|
||||
height: 100%
|
||||
}
|
|
@ -12,26 +12,24 @@ import { parse } from 'query-string';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { CoreStart, ChromeBreadcrumb, ScopedHistory } from 'src/core/public';
|
||||
import { RedirectAppLinks } from '../../../kibana_react/public';
|
||||
import { ISavedObjectsManagementServiceRegistry } from '../services';
|
||||
import { SavedObjectEdition } from './object_view';
|
||||
import './saved_objects_edition_page.scss';
|
||||
|
||||
const SavedObjectsEditionPage = ({
|
||||
coreStart,
|
||||
serviceRegistry,
|
||||
setBreadcrumbs,
|
||||
history,
|
||||
}: {
|
||||
coreStart: CoreStart;
|
||||
serviceRegistry: ISavedObjectsManagementServiceRegistry;
|
||||
setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void;
|
||||
history: ScopedHistory;
|
||||
}) => {
|
||||
const { service: serviceName, id } = useParams<{ service: string; id: string }>();
|
||||
const { type, id } = useParams<{ type: string; id: string }>();
|
||||
const capabilities = coreStart.application.capabilities;
|
||||
const dockLinks = coreStart.docLinks.links;
|
||||
|
||||
const { search } = useLocation();
|
||||
const query = parse(search);
|
||||
const service = serviceRegistry.get(serviceName);
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumbs([
|
||||
|
@ -42,27 +40,31 @@ const SavedObjectsEditionPage = ({
|
|||
href: '/',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('savedObjectsManagement.breadcrumb.edit', {
|
||||
defaultMessage: 'Edit {savedObjectType}',
|
||||
values: { savedObjectType: service?.service.type ?? 'object' },
|
||||
text: i18n.translate('savedObjectsManagement.breadcrumb.inspect', {
|
||||
defaultMessage: 'Inspect {savedObjectType}',
|
||||
values: { savedObjectType: type },
|
||||
}),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, service]);
|
||||
}, [setBreadcrumbs, type]);
|
||||
|
||||
return (
|
||||
<RedirectAppLinks application={coreStart.application}>
|
||||
<RedirectAppLinks
|
||||
application={coreStart.application}
|
||||
className="savedObjectsManagementEditionPage"
|
||||
>
|
||||
<SavedObjectEdition
|
||||
id={id}
|
||||
savedObjectType={type}
|
||||
http={coreStart.http}
|
||||
serviceName={serviceName}
|
||||
serviceRegistry={serviceRegistry}
|
||||
savedObjectsClient={coreStart.savedObjects.client}
|
||||
overlays={coreStart.overlays}
|
||||
notifications={coreStart.notifications}
|
||||
capabilities={capabilities}
|
||||
notFoundType={query.notFound as string}
|
||||
uiSettings={coreStart.uiSettings}
|
||||
history={history}
|
||||
docLinks={dockLinks}
|
||||
/>
|
||||
</RedirectAppLinks>
|
||||
);
|
||||
|
|
|
@ -75,13 +75,11 @@ const SavedObjectsTablePage = ({
|
|||
spacesApi ? spacesApi.ui.components.getSpacesContextProvider : getEmptyFunctionComponent,
|
||||
[spacesApi]
|
||||
);
|
||||
|
||||
return (
|
||||
<ContextWrapper>
|
||||
<SavedObjectsTable
|
||||
initialQuery={initialQuery}
|
||||
allowedTypes={allowedTypes}
|
||||
serviceRegistry={serviceRegistry}
|
||||
actionRegistry={actionRegistry}
|
||||
columnRegistry={columnRegistry}
|
||||
taggingApi={taggingApi}
|
||||
|
@ -94,12 +92,10 @@ const SavedObjectsTablePage = ({
|
|||
applications={coreStart.application}
|
||||
perPageConfig={itemsPerPage}
|
||||
goInspectObject={(savedObject) => {
|
||||
const { editUrl } = savedObject.meta;
|
||||
if (editUrl) {
|
||||
return coreStart.application.navigateToUrl(
|
||||
coreStart.http.basePath.prepend(`/app${editUrl}`)
|
||||
);
|
||||
}
|
||||
const savedObjectEditUrl = savedObject.meta.editUrl
|
||||
? `/app${savedObject.meta.editUrl}`
|
||||
: `/app/management/kibana/objects/${savedObject.type}/${savedObject.id}`;
|
||||
coreStart.application.navigateToUrl(coreStart.http.basePath.prepend(savedObjectEditUrl));
|
||||
}}
|
||||
canGoInApp={(savedObject) => {
|
||||
const { inAppUrl } = savedObject.meta;
|
||||
|
|
|
@ -20,9 +20,6 @@ export const visualizationSavedObjectType: SavedObjectsType = {
|
|||
getTitle(obj) {
|
||||
return obj.attributes.title;
|
||||
},
|
||||
getEditUrl(obj) {
|
||||
return `/management/kibana/objects/savedVisualizations/${encodeURIComponent(obj.id)}`;
|
||||
},
|
||||
getInAppUrl(obj) {
|
||||
return {
|
||||
path: `/app/visualize#/edit/${encodeURIComponent(obj.id)}`,
|
||||
|
|
|
@ -180,8 +180,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
icon: 'discoverApp',
|
||||
title: 'OneRecord',
|
||||
hiddenType: false,
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
|
@ -200,8 +198,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
icon: 'dashboardApp',
|
||||
title: 'Dashboard',
|
||||
hiddenType: false,
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedDashboards/b70c7ae0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
|
@ -220,8 +216,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
icon: 'visualizeApp',
|
||||
title: 'VisualizationFromSavedSearch',
|
||||
hiddenType: false,
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -232,8 +226,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
icon: 'visualizeApp',
|
||||
title: 'Visualization',
|
||||
hiddenType: false,
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
|
|
@ -21,7 +21,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: schema.object({
|
||||
title: schema.string(),
|
||||
icon: schema.string(),
|
||||
editUrl: schema.string(),
|
||||
editUrl: schema.maybe(schema.string()),
|
||||
inAppUrl: schema.object({
|
||||
path: schema.string(),
|
||||
uiCapabilitiesPath: schema.string(),
|
||||
|
@ -103,8 +103,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
title: 'VisualizationFromSavedSearch',
|
||||
icon: 'visualizeApp',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -147,8 +145,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'VisualizationFromSavedSearch',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -192,8 +188,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Visualization',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -209,8 +203,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'VisualizationFromSavedSearch',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -234,8 +226,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Visualization',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -251,8 +241,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'VisualizationFromSavedSearch',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/a42c0580-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -296,8 +284,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'discoverApp',
|
||||
title: 'OneRecord',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
|
@ -313,8 +299,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'dashboardApp',
|
||||
title: 'Dashboard',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedDashboards/b70c7ae0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'dashboard.show',
|
||||
|
@ -340,8 +324,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'discoverApp',
|
||||
title: 'OneRecord',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
|
@ -385,8 +367,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'discoverApp',
|
||||
title: 'OneRecord',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
|
@ -402,8 +382,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'visualizeApp',
|
||||
title: 'Visualization',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'visualize.show',
|
||||
|
@ -429,8 +407,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
meta: {
|
||||
icon: 'discoverApp',
|
||||
title: 'OneRecord',
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
inAppUrl: {
|
||||
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
|
||||
uiCapabilitiesPath: 'discover.show',
|
||||
|
@ -475,8 +451,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
{
|
||||
id: 'add810b0-3224-11e8-a572-ffca06da1357',
|
||||
meta: {
|
||||
editUrl:
|
||||
'/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
icon: 'visualizeApp',
|
||||
inAppUrl: {
|
||||
path: '/app/visualize#/edit/add810b0-3224-11e8-a572-ffca06da1357',
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['common', 'settings', 'savedObjects']);
|
||||
const browser = getService('browser');
|
||||
const find = getService('find');
|
||||
|
||||
const setFieldValue = async (fieldName: string, value: string) => {
|
||||
return testSubjects.setValue(`savedObjects-editField-${fieldName}`, value);
|
||||
};
|
||||
|
||||
const getFieldValue = async (fieldName: string) => {
|
||||
return testSubjects.getAttribute(`savedObjects-editField-${fieldName}`, 'value');
|
||||
};
|
||||
|
||||
const setAceEditorFieldValue = async (fieldName: string, fieldValue: string) => {
|
||||
const editorId = `savedObjects-editField-${fieldName}-aceEditor`;
|
||||
await find.clickByCssSelector(`#${editorId}`);
|
||||
return browser.execute(
|
||||
(editor: string, value: string) => {
|
||||
return (window as any).ace.edit(editor).setValue(value);
|
||||
},
|
||||
editorId,
|
||||
fieldValue
|
||||
);
|
||||
};
|
||||
|
||||
const getAceEditorFieldValue = async (fieldName: string) => {
|
||||
const editorId = `savedObjects-editField-${fieldName}-aceEditor`;
|
||||
await find.clickByCssSelector(`#${editorId}`);
|
||||
return browser.execute((editor: string) => {
|
||||
return (window as any).ace.edit(editor).getValue() as string;
|
||||
}, editorId);
|
||||
};
|
||||
|
||||
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();
|
||||
// Allow some time for the transition/animations to occur before assuming the click is done
|
||||
await delay(10);
|
||||
};
|
||||
|
||||
describe('saved objects edition page', () => {
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load(
|
||||
'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object'
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await esArchiver.unload(
|
||||
'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object'
|
||||
);
|
||||
});
|
||||
|
||||
it('allows to update the saved object when submitting', async () => {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaSavedObjects();
|
||||
|
||||
let objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Dashboard')).to.be(true);
|
||||
|
||||
await PageObjects.common.navigateToUrl(
|
||||
'management',
|
||||
'kibana/objects/savedDashboards/i-exist',
|
||||
{
|
||||
shouldUseHashForSubUrl: false,
|
||||
}
|
||||
);
|
||||
|
||||
await testSubjects.existOrFail('savedObjectEditSave');
|
||||
|
||||
expect(await getFieldValue('title')).to.eql('A Dashboard');
|
||||
|
||||
await setFieldValue('title', 'Edited Dashboard');
|
||||
await setFieldValue('description', 'Some description');
|
||||
|
||||
await focusAndClickButton('savedObjectEditSave');
|
||||
|
||||
objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Dashboard')).to.be(false);
|
||||
expect(objects.includes('Edited Dashboard')).to.be(true);
|
||||
|
||||
await PageObjects.common.navigateToUrl(
|
||||
'management',
|
||||
'kibana/objects/savedDashboards/i-exist',
|
||||
{
|
||||
shouldUseHashForSubUrl: false,
|
||||
}
|
||||
);
|
||||
|
||||
expect(await getFieldValue('title')).to.eql('Edited Dashboard');
|
||||
expect(await getFieldValue('description')).to.eql('Some description');
|
||||
});
|
||||
|
||||
it('allows to delete a saved object', async () => {
|
||||
await PageObjects.common.navigateToUrl(
|
||||
'management',
|
||||
'kibana/objects/savedDashboards/i-exist',
|
||||
{
|
||||
shouldUseHashForSubUrl: false,
|
||||
}
|
||||
);
|
||||
|
||||
await focusAndClickButton('savedObjectEditDelete');
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
|
||||
const objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Dashboard')).to.be(false);
|
||||
});
|
||||
|
||||
it('preserves the object references when saving', async () => {
|
||||
const testVisualizationUrl =
|
||||
'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed';
|
||||
const visualizationRefs = [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: 'logstash-*',
|
||||
},
|
||||
];
|
||||
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaSavedObjects();
|
||||
|
||||
const objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Pie')).to.be(true);
|
||||
|
||||
await PageObjects.common.navigateToUrl('management', testVisualizationUrl, {
|
||||
shouldUseHashForSubUrl: false,
|
||||
});
|
||||
|
||||
await testSubjects.existOrFail('savedObjectEditSave');
|
||||
|
||||
let displayedReferencesValue = await getAceEditorFieldValue('references');
|
||||
|
||||
expect(JSON.parse(displayedReferencesValue)).to.eql(visualizationRefs);
|
||||
|
||||
await focusAndClickButton('savedObjectEditSave');
|
||||
|
||||
await PageObjects.savedObjects.getRowTitles();
|
||||
|
||||
await PageObjects.common.navigateToUrl('management', testVisualizationUrl, {
|
||||
shouldUseHashForSubUrl: false,
|
||||
});
|
||||
|
||||
// Parsing to avoid random keys ordering issues in raw string comparison
|
||||
expect(JSON.parse(await getAceEditorFieldValue('references'))).to.eql(visualizationRefs);
|
||||
|
||||
await setAceEditorFieldValue('references', JSON.stringify([], undefined, 2));
|
||||
|
||||
await focusAndClickButton('savedObjectEditSave');
|
||||
|
||||
await PageObjects.savedObjects.getRowTitles();
|
||||
|
||||
await PageObjects.common.navigateToUrl('management', testVisualizationUrl, {
|
||||
shouldUseHashForSubUrl: false,
|
||||
});
|
||||
|
||||
displayedReferencesValue = await getAceEditorFieldValue('references');
|
||||
|
||||
expect(JSON.parse(displayedReferencesValue)).to.eql([]);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
export default function savedObjectsManagementApp({ loadTestFile }: FtrProviderContext) {
|
||||
describe('saved objects management', function savedObjectsManagementAppTestSuite() {
|
||||
this.tags('ciGroup7');
|
||||
loadTestFile(require.resolve('./edit_saved_object'));
|
||||
loadTestFile(require.resolve('./inspect_saved_objects'));
|
||||
loadTestFile(require.resolve('./show_relationships'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['common', 'settings', 'savedObjects']);
|
||||
const find = getService('find');
|
||||
|
||||
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();
|
||||
// Allow some time for the transition/animations to occur before assuming the click is done
|
||||
await delay(10);
|
||||
};
|
||||
const textIncludesAll = (text: string, items: string[]) => {
|
||||
const bools = items.map((item) => !!text.includes(item));
|
||||
return bools.every((currBool) => currBool === true);
|
||||
};
|
||||
|
||||
describe('saved objects edition page', () => {
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load(
|
||||
'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object'
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await esArchiver.unload(
|
||||
'test/functional/fixtures/es_archiver/saved_objects_management/edit_saved_object'
|
||||
);
|
||||
});
|
||||
|
||||
it('allows to view the saved object', async () => {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaSavedObjects();
|
||||
const objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Dashboard')).to.be(true);
|
||||
await PageObjects.common.navigateToUrl('management', 'kibana/objects/dashboard/i-exist', {
|
||||
shouldUseHashForSubUrl: false,
|
||||
});
|
||||
const inspectContainer = await find.byClassName('kibanaCodeEditor');
|
||||
const visibleContainerText = await inspectContainer.getVisibleText();
|
||||
// ensure that something renders visibly
|
||||
expect(
|
||||
textIncludesAll(visibleContainerText, [
|
||||
'A Dashboard',
|
||||
'title',
|
||||
'id',
|
||||
'type',
|
||||
'attributes',
|
||||
'references',
|
||||
])
|
||||
).to.be(true);
|
||||
});
|
||||
|
||||
it('allows to delete a saved object', async () => {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaSavedObjects();
|
||||
let objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Dashboard')).to.be(true);
|
||||
await PageObjects.savedObjects.clickInspectByTitle('A Dashboard');
|
||||
await PageObjects.common.navigateToUrl('management', 'kibana/objects/dashboard/i-exist', {
|
||||
shouldUseHashForSubUrl: false,
|
||||
});
|
||||
await focusAndClickButton('savedObjectEditDelete');
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
|
||||
objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Dashboard')).to.be(false);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -4369,14 +4369,11 @@
|
|||
"savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "保存後に{originVerb}から{origin}",
|
||||
"savedObjects.saveModalOrigin.returnToOriginLabel": "戻る",
|
||||
"savedObjects.saveModalOrigin.saveAndReturnLabel": "保存して戻る",
|
||||
"savedObjectsManagement.breadcrumb.edit": "{savedObjectType}を編集",
|
||||
"savedObjectsManagement.breadcrumb.index": "保存されたオブジェクト",
|
||||
"savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel": "削除",
|
||||
"savedObjectsManagement.deleteConfirm.modalDescription": "このアクションはオブジェクトをKibanaから永久に削除します。",
|
||||
"savedObjectsManagement.deleteConfirm.modalTitle": "「{title}」を削除しますか?",
|
||||
"savedObjectsManagement.deleteSavedObjectsConfirmModalDescription": "この操作は次の保存されたオブジェクトを削除します:",
|
||||
"savedObjectsManagement.field.offLabel": "オフ",
|
||||
"savedObjectsManagement.field.onLabel": "オン",
|
||||
"savedObjectsManagement.importSummary.createdCountHeader": "{createdCount}件の新規項目",
|
||||
"savedObjectsManagement.importSummary.createdOutcomeLabel": "作成済み",
|
||||
"savedObjectsManagement.importSummary.errorCountHeader": "{errorCount}件のエラー",
|
||||
|
@ -4478,21 +4475,10 @@
|
|||
"savedObjectsManagement.objectsTable.unableFindSavedObjectNotificationMessage": "保存されたオブジェクトが見つかりません",
|
||||
"savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage": "保存されたオブジェクトが見つかりません",
|
||||
"savedObjectsManagement.objectView.unableFindSavedObjectNotificationMessage": "保存されたオブジェクトが見つかりません",
|
||||
"savedObjectsManagement.view.cancelButtonAriaLabel": "キャンセル",
|
||||
"savedObjectsManagement.view.cancelButtonLabel": "キャンセル",
|
||||
"savedObjectsManagement.view.deleteItemButtonLabel": "{title}を削除",
|
||||
"savedObjectsManagement.view.editItemTitle": "{title}の編集",
|
||||
"savedObjectsManagement.view.fieldDoesNotExistErrorMessage": "このオブジェクトに関連付けられたフィールドは、現在このインデックスパターンに存在しません。",
|
||||
"savedObjectsManagement.view.howToFixErrorDescription": "このエラーの原因がわかる場合は修正してください。わからない場合は上の削除ボタンをクリックしてください。",
|
||||
"savedObjectsManagement.view.howToModifyObjectDescription": "オブジェクトの編集は上級ユーザー向けです。オブジェクトのプロパティが検証されておらず、無効なオブジェクトはエラー、データ損失、またはそれ以上の問題の原因となります。コードを熟知した人に指示されていない限り、この設定は変更しない方が無難です。",
|
||||
"savedObjectsManagement.view.howToModifyObjectTitle": "十分ご注意ください!",
|
||||
"savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "このオブジェクトに関連付けられたインデックスパターンは現在存在しません。",
|
||||
"savedObjectsManagement.view.saveButtonAriaLabel": "{ title }オブジェクトを保存",
|
||||
"savedObjectsManagement.view.saveButtonLabel": "{ title }オブジェクトを保存",
|
||||
"savedObjectsManagement.view.savedObjectProblemErrorMessage": "この保存されたオブジェクトに問題があります",
|
||||
"savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "このオブジェクトに関連付けられた保存された検索は現在存在しません。",
|
||||
"savedObjectsManagement.view.viewItemButtonLabel": "{title}を表示",
|
||||
"savedObjectsManagement.view.viewItemTitle": "{title}を表示",
|
||||
"security.checkup.dismissButtonText": "閉じる",
|
||||
"security.checkup.dontShowAgain": "今後表示しない",
|
||||
"security.checkup.insecureClusterMessage": "1 ビットを失わないでください。Elastic では無料でデータを保護できます。",
|
||||
|
|
|
@ -4409,14 +4409,11 @@
|
|||
"savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "保存后{originVerb}至{origin}",
|
||||
"savedObjects.saveModalOrigin.returnToOriginLabel": "返回",
|
||||
"savedObjects.saveModalOrigin.saveAndReturnLabel": "保存并返回",
|
||||
"savedObjectsManagement.breadcrumb.edit": "编辑 {savedObjectType}",
|
||||
"savedObjectsManagement.breadcrumb.index": "已保存对象",
|
||||
"savedObjectsManagement.deleteConfirm.modalDeleteButtonLabel": "删除",
|
||||
"savedObjectsManagement.deleteConfirm.modalDescription": "此操作会将对象从 Kibana 永久移除。",
|
||||
"savedObjectsManagement.deleteConfirm.modalTitle": "删除“{title}”?",
|
||||
"savedObjectsManagement.deleteSavedObjectsConfirmModalDescription": "此操作将删除以下已保存对象:",
|
||||
"savedObjectsManagement.field.offLabel": "关闭",
|
||||
"savedObjectsManagement.field.onLabel": "开启",
|
||||
"savedObjectsManagement.importSummary.createdCountHeader": "{createdCount} 个新",
|
||||
"savedObjectsManagement.importSummary.createdOutcomeLabel": "已创建",
|
||||
"savedObjectsManagement.importSummary.errorCountHeader": "{errorCount} 个错误",
|
||||
|
@ -4523,21 +4520,10 @@
|
|||
"savedObjectsManagement.objectsTable.unableFindSavedObjectNotificationMessage": "找不到已保存对象",
|
||||
"savedObjectsManagement.objectsTable.unableFindSavedObjectsNotificationMessage": "找不到已保存对象",
|
||||
"savedObjectsManagement.objectView.unableFindSavedObjectNotificationMessage": "找不到已保存对象",
|
||||
"savedObjectsManagement.view.cancelButtonAriaLabel": "取消",
|
||||
"savedObjectsManagement.view.cancelButtonLabel": "取消",
|
||||
"savedObjectsManagement.view.deleteItemButtonLabel": "删除“{title}”",
|
||||
"savedObjectsManagement.view.editItemTitle": "编辑“{title}”",
|
||||
"savedObjectsManagement.view.fieldDoesNotExistErrorMessage": "与此对象关联的字段在该索引模式中已不存在。",
|
||||
"savedObjectsManagement.view.howToFixErrorDescription": "如果您清楚此错误的含义,请修复该错误 — 否则单击上面的删除按钮。",
|
||||
"savedObjectsManagement.view.howToModifyObjectDescription": "修改对象仅适用于高级用户。对象属性未得到验证,无效的对象可能会导致错误、数据丢失或更坏的情况发生。除非熟悉该代码的人让您来这里,否则您可能不应到访此处。",
|
||||
"savedObjectsManagement.view.howToModifyObjectTitle": "谨慎操作!",
|
||||
"savedObjectsManagement.view.indexPatternDoesNotExistErrorMessage": "与此对象关联的索引模式已不存在。",
|
||||
"savedObjectsManagement.view.saveButtonAriaLabel": "保存 { title } 对象",
|
||||
"savedObjectsManagement.view.saveButtonLabel": "保存 { title } 对象",
|
||||
"savedObjectsManagement.view.savedObjectProblemErrorMessage": "此已保存对象有问题",
|
||||
"savedObjectsManagement.view.savedSearchDoesNotExistErrorMessage": "与此对象关联的已保存搜索已不存在。",
|
||||
"savedObjectsManagement.view.viewItemButtonLabel": "查看“{title}”",
|
||||
"savedObjectsManagement.view.viewItemTitle": "查看“{title}”",
|
||||
"security.checkup.dismissButtonText": "关闭",
|
||||
"security.checkup.dontShowAgain": "不再显示",
|
||||
"security.checkup.insecureClusterMessage": "不要丢失一位。使用 Elastic,免费保护您的数据。",
|
||||
|
|
|
@ -14,6 +14,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
const PageObjects = getPageObjects(['common', 'settings', 'security', 'error', 'savedObjects']);
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
let version: string = '';
|
||||
const find = getService('find');
|
||||
|
||||
describe('feature controls saved objects management', () => {
|
||||
before(async () => {
|
||||
|
@ -108,12 +109,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
expect(actual).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit visualization', () => {
|
||||
// From https://github.com/elastic/kibana/issues/59588 edit view became read-only json view
|
||||
// test description changed from "edit" to "inspect"
|
||||
// Skipping the test to allow code owners to delete or modify the test.
|
||||
describe('inspect visualization', () => {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToUrl(
|
||||
'management',
|
||||
'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed',
|
||||
'kibana/objects/visualization/75c3e060-1e7c-11e9-8488-65449e65d0ed',
|
||||
{
|
||||
shouldLoginIfPrompted: false,
|
||||
shouldUseHashForSubUrl: false,
|
||||
|
@ -125,11 +128,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await testSubjects.existOrFail('savedObjectEditDelete');
|
||||
});
|
||||
|
||||
it('shows save button', async () => {
|
||||
// no longer a feature
|
||||
it.skip('shows save button', async () => {
|
||||
await testSubjects.existOrFail('savedObjectEditSave');
|
||||
});
|
||||
|
||||
it('has inputs without readonly attributes', async () => {
|
||||
// no longer a feature
|
||||
it.skip('has inputs without readonly attributes', async () => {
|
||||
const form = await testSubjects.find('savedObjectEditForm');
|
||||
const inputs = await form.findAllByCssSelector('input');
|
||||
expect(inputs.length).to.be.greaterThan(0);
|
||||
|
@ -223,17 +228,30 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('edit visualization', () => {
|
||||
// From https://github.com/elastic/kibana/issues/59588 edit view became read-only json view
|
||||
// test description changed from "edit" to "inspect"
|
||||
// Skipping the test to allow code owners to delete or modify the test.
|
||||
describe('inspect visualization', () => {
|
||||
before(async () => {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaSavedObjects();
|
||||
const objects = await PageObjects.savedObjects.getRowTitles();
|
||||
expect(objects.includes('A Pie')).to.be(true);
|
||||
await PageObjects.savedObjects.clickInspectByTitle('A Pie');
|
||||
await PageObjects.common.navigateToUrl(
|
||||
'management',
|
||||
'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed',
|
||||
'kibana/objects/visualization/75c3e060-1e7c-11e9-8488-65449e65d0ed',
|
||||
{
|
||||
shouldLoginIfPrompted: false,
|
||||
shouldUseHashForSubUrl: false,
|
||||
}
|
||||
);
|
||||
await testSubjects.existOrFail('savedObjectsEdit');
|
||||
});
|
||||
|
||||
it('allows viewing the object', async () => {
|
||||
const inspectContainer = await find.byClassName('kibanaCodeEditor');
|
||||
const visibleContainerText = await inspectContainer.getVisibleText();
|
||||
expect(visibleContainerText.includes('A Pie'));
|
||||
});
|
||||
|
||||
it('does not show delete button', async () => {
|
||||
|
@ -244,7 +262,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await testSubjects.missingOrFail('savedObjectEditSave');
|
||||
});
|
||||
|
||||
it('has inputs with only readonly attributes', async () => {
|
||||
// No longer a feature
|
||||
it.skip('has inputs with only readonly attributes', async () => {
|
||||
const form = await testSubjects.find('savedObjectEditForm');
|
||||
const inputs = await form.findAllByCssSelector('input');
|
||||
expect(inputs.length).to.be.greaterThan(0);
|
||||
|
@ -309,11 +328,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('edit visualization', () => {
|
||||
describe('inspect visualization', () => {
|
||||
it('redirects to management home', async () => {
|
||||
await PageObjects.common.navigateToUrl(
|
||||
'management',
|
||||
'kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed',
|
||||
'kibana/objects/visualization/75c3e060-1e7c-11e9-8488-65449e65d0ed',
|
||||
{
|
||||
shouldLoginIfPrompted: false,
|
||||
ensureCurrentUrl: false,
|
||||
|
|
|
@ -14,7 +14,6 @@ const getSpacePrefix = (spaceId: string) => {
|
|||
|
||||
export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects([
|
||||
'common',
|
||||
'security',
|
||||
|
@ -22,9 +21,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
'spaceSelector',
|
||||
'settings',
|
||||
]);
|
||||
const find = getService('find');
|
||||
|
||||
const spaceId = 'space_1';
|
||||
|
||||
const textIncludesAll = (text: string, items: string[]) => {
|
||||
const bools = items.map((item) => !!text.includes(item));
|
||||
return bools.every((currBool) => currBool === true);
|
||||
};
|
||||
|
||||
describe('spaces integration', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load(
|
||||
|
@ -54,9 +59,19 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
|
||||
await PageObjects.common.waitUntilUrlIncludes(getSpacePrefix(spaceId));
|
||||
|
||||
expect(await testSubjects.getAttribute(`savedObjects-editField-title`, 'value')).to.eql(
|
||||
'A Pie'
|
||||
);
|
||||
const inspectContainer = await find.byClassName('kibanaCodeEditor');
|
||||
const visibleContainerText = await inspectContainer.getVisibleText();
|
||||
expect(
|
||||
textIncludesAll(visibleContainerText, [
|
||||
'A Pie',
|
||||
'title',
|
||||
'id',
|
||||
'type',
|
||||
'attributes',
|
||||
'references',
|
||||
])
|
||||
).to.be(true);
|
||||
expect(visibleContainerText.includes('A Pie'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue