Skip to content

Commit

Permalink
Fix UI glitch on SOM delete confirmation modal (#87623)
Browse files Browse the repository at this point in the history
* extract delete confirm modal

* extract the export modal

* add data-test-subj to confirm modal

* add comment on why we can't use EuiConfirmModal
pgayvallet authored Jan 11, 2021
1 parent 66c8b2a commit a0d33dc
Showing 10 changed files with 582 additions and 400 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import { mountWithIntl } from '@kbn/test/jest';
import { SavedObjectWithMetadata } from '../../../../common';
import { DeleteConfirmModal } from './delete_confirm_modal';

const createObject = (): SavedObjectWithMetadata => ({
id: 'foo',
type: 'bar',
attributes: {},
references: [],
meta: {},
});

describe('DeleteConfirmModal', () => {
let onConfirm: jest.Mock;
let onCancel: jest.Mock;

beforeEach(() => {
onConfirm = jest.fn();
onCancel = jest.fn();
});

it('displays a loader if `isDeleting` is true', () => {
const wrapper = mountWithIntl(
<DeleteConfirmModal
isDeleting={true}
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={[]}
/>
);
expect(wrapper.find('EuiLoadingElastic')).toHaveLength(1);
expect(wrapper.find('EuiModal')).toHaveLength(0);
});

it('lists the objects to delete', () => {
const objs = [createObject(), createObject(), createObject()];
const wrapper = mountWithIntl(
<DeleteConfirmModal
isDeleting={false}
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={objs}
/>
);
expect(wrapper.find('.euiTableRow')).toHaveLength(3);
});

it('calls `onCancel` when clicking on the cancel button', () => {
const wrapper = mountWithIntl(
<DeleteConfirmModal
isDeleting={false}
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={[]}
/>
);
wrapper.find('EuiButtonEmpty').simulate('click');

expect(onCancel).toHaveBeenCalledTimes(1);
expect(onConfirm).not.toHaveBeenCalled();
});

it('calls `onDelete` when clicking on the delete button', () => {
const wrapper = mountWithIntl(
<DeleteConfirmModal
isDeleting={false}
onConfirm={onConfirm}
onCancel={onCancel}
selectedObjects={[]}
/>
);
wrapper.find('EuiButton').simulate('click');

expect(onConfirm).toHaveBeenCalledTimes(1);
expect(onCancel).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { FC } from 'react';
import {
EuiInMemoryTable,
EuiLoadingElastic,
EuiToolTip,
EuiIcon,
EuiOverlayMask,
EuiModal,
EuiModalHeader,
EuiModalHeaderTitle,
EuiModalBody,
EuiModalFooter,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiButton,
EuiSpacer,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { SavedObjectWithMetadata } from '../../../../common';
import { getSavedObjectLabel } from '../../../lib';

export interface DeleteConfirmModalProps {
isDeleting: boolean;
onConfirm: () => void;
onCancel: () => void;
selectedObjects: SavedObjectWithMetadata[];
}

export const DeleteConfirmModal: FC<DeleteConfirmModalProps> = ({
isDeleting,
onConfirm,
onCancel,
selectedObjects,
}) => {
if (isDeleting) {
return (
<EuiOverlayMask>
<EuiLoadingElastic size="xl" />
</EuiOverlayMask>
);
}

// can't use `EuiConfirmModal` here as the confirm modal body is wrapped
// inside a `<p>` element, causing UI glitches with the table.
return (
<EuiOverlayMask>
<EuiModal initialFocus="soDeleteConfirmModalConfirmBtn" onClose={onCancel}>
<EuiModalHeader>
<EuiModalHeaderTitle>
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModalTitle"
defaultMessage="Delete saved objects"
/>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<p>
<FormattedMessage
id="savedObjectsManagement.deleteSavedObjectsConfirmModalDescription"
defaultMessage="This action will delete the following saved objects:"
/>
</p>
<EuiSpacer size="m" />
<EuiInMemoryTable
items={selectedObjects}
columns={[
{
field: 'type',
name: i18n.translate(
'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName',
{ defaultMessage: 'Type' }
),
width: '50px',
render: (type, object) => (
<EuiToolTip position="top" content={getSavedObjectLabel(type)}>
<EuiIcon type={object.meta.icon || 'apps'} />
</EuiToolTip>
),
},
{
field: 'id',
name: i18n.translate(
'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName',
{ defaultMessage: 'Id' }
),
},
{
field: 'meta.title',
name: i18n.translate(
'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName',
{ defaultMessage: 'Title' }
),
},
]}
pagination={true}
sorting={false}
/>
</EuiModalBody>
<EuiModalFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onCancel} data-test-subj="confirmModalCancelButton">
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
id="soDeleteConfirmModalConfirmBtn"
fill
color="danger"
onClick={onConfirm}
data-test-subj="confirmModalConfirmButton"
>
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
defaultMessage="Delete"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiModalFooter>
</EuiModal>
</EuiOverlayMask>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import { mountWithIntl } from '@kbn/test/jest';
import { ExportModal } from './export_modal';

describe('ExportModal', () => {
let onExport: jest.Mock;
let onCancel: jest.Mock;
let onSelectedOptionsChange: jest.Mock;
let onIncludeReferenceChange: jest.Mock;

const options = [
{ id: '1', label: 'option 1' },
{ id: '2', label: 'option 2' },
];
const selectedOptions = {
1: true,
2: false,
};

beforeEach(() => {
onExport = jest.fn();
onCancel = jest.fn();
onSelectedOptionsChange = jest.fn();
onIncludeReferenceChange = jest.fn();
});

it('Displays a checkbox for each option', () => {
const wrapper = mountWithIntl(
<ExportModal
onExport={onExport}
onCancel={onCancel}
onSelectedOptionsChange={onSelectedOptionsChange}
filteredItemCount={42}
options={options}
selectedOptions={selectedOptions}
includeReferences={false}
onIncludeReferenceChange={onIncludeReferenceChange}
/>
);

expect(wrapper.find('EuiCheckbox')).toHaveLength(2);
});

it('calls `onCancel` when clicking on the cancel button', () => {
const wrapper = mountWithIntl(
<ExportModal
onExport={onExport}
onCancel={onCancel}
onSelectedOptionsChange={onSelectedOptionsChange}
filteredItemCount={42}
options={options}
selectedOptions={selectedOptions}
includeReferences={false}
onIncludeReferenceChange={onIncludeReferenceChange}
/>
);
wrapper.find('EuiButtonEmpty').simulate('click');

expect(onCancel).toHaveBeenCalledTimes(1);
expect(onExport).not.toHaveBeenCalled();
});

it('calls `onExport` when clicking on the export button', () => {
const wrapper = mountWithIntl(
<ExportModal
onExport={onExport}
onCancel={onCancel}
onSelectedOptionsChange={onSelectedOptionsChange}
filteredItemCount={42}
options={options}
selectedOptions={selectedOptions}
includeReferences={false}
onIncludeReferenceChange={onIncludeReferenceChange}
/>
);
wrapper.find('EuiButton').simulate('click');

expect(onExport).toHaveBeenCalledTimes(1);
expect(onCancel).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { FC } from 'react';
import {
EuiOverlayMask,
EuiModal,
EuiModalHeader,
EuiModalHeaderTitle,
EuiModalBody,
EuiModalFooter,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiButton,
EuiSpacer,
EuiFormRow,
EuiCheckboxGroup,
EuiSwitch,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

export interface ExportModalProps {
onExport: () => void;
onCancel: () => void;
onSelectedOptionsChange: (newSelectedOptions: Record<string, boolean>) => void;
filteredItemCount: number;
options: Array<{ id: string; label: string }>;
selectedOptions: Record<string, boolean>;
includeReferences: boolean;
onIncludeReferenceChange: (newIncludeReference: boolean) => void;
}

export const ExportModal: FC<ExportModalProps> = ({
onCancel,
onExport,
onSelectedOptionsChange,
options,
filteredItemCount,
selectedOptions,
includeReferences,
onIncludeReferenceChange,
}) => {
return (
<EuiOverlayMask>
<EuiModal onClose={onCancel}>
<EuiModalHeader>
<EuiModalHeaderTitle>
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle"
defaultMessage="Export {filteredItemCount, plural, one{# object} other {# objects}}"
values={{
filteredItemCount,
}}
/>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiFormRow
label={
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription"
defaultMessage="Select which types to export"
/>
}
labelType="legend"
>
<EuiCheckboxGroup
options={options}
idToSelectedMap={selectedOptions}
onChange={(optionId) => {
onSelectedOptionsChange({
...selectedOptions,
...{
[optionId]: !selectedOptions[optionId],
},
});
}}
/>
</EuiFormRow>
<EuiSpacer size="m" />
<EuiSwitch
name="includeReferencesDeep"
label={
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
defaultMessage="Include related objects"
/>
}
checked={includeReferences}
onChange={() => onIncludeReferenceChange(!includeReferences)}
/>
</EuiModalBody>
<EuiModalFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onCancel}>
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onExport}>
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
defaultMessage="Export all"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiModalFooter>
</EuiModal>
</EuiOverlayMask>
);
};
Original file line number Diff line number Diff line change
@@ -21,3 +21,5 @@ export { Header } from './header';
export { Table } from './table';
export { Flyout } from './flyout';
export { Relationships } from './relationships';
export { DeleteConfirmModal } from './delete_confirm_modal';
export { ExportModal } from './export_modal';
Original file line number Diff line number Diff line change
@@ -325,7 +325,7 @@ describe('SavedObjectsTable', () => {
(component.find('Header') as any).prop('onExportAll')();
component.update();

expect(component.find('EuiModal')).toMatchSnapshot();
expect(component.find('ExportModal')).toMatchSnapshot();
});

it('should export all', async () => {
@@ -504,7 +504,7 @@ describe('SavedObjectsTable', () => {
await component.instance().onDelete();
component.update();

expect(component.find('EuiConfirmModal')).toMatchSnapshot();
expect(component.find('DeleteConfirmModal')).toMatchSnapshot();
});

it('should delete selected objects', async () => {
Original file line number Diff line number Diff line change
@@ -21,32 +21,8 @@ import React, { Component } from 'react';
import { debounce } from 'lodash';
// @ts-expect-error
import { saveAs } from '@elastic/filesaver';
import {
EuiSpacer,
Query,
EuiInMemoryTable,
EuiIcon,
EuiConfirmModal,
EuiLoadingElastic,
EuiOverlayMask,
EUI_MODAL_CONFIRM_BUTTON,
EuiCheckboxGroup,
EuiToolTip,
EuiPageContent,
EuiSwitch,
EuiModal,
EuiModalHeader,
EuiModalBody,
EuiModalFooter,
EuiButtonEmpty,
EuiButton,
EuiModalHeaderTitle,
EuiFormRow,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { EuiSpacer, Query, EuiPageContent } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
SavedObjectsClientContract,
SavedObjectsFindOptions,
@@ -62,7 +38,6 @@ import {
parseQuery,
getSavedObjectCounts,
getRelationships,
getSavedObjectLabel,
fetchExportObjects,
fetchExportByTypeAndSearch,
findObjects,
@@ -77,7 +52,14 @@ import {
SavedObjectsManagementActionServiceStart,
SavedObjectsManagementColumnServiceStart,
} from '../../services';
import { Header, Table, Flyout, Relationships } from './components';
import {
Header,
Table,
Flyout,
Relationships,
DeleteConfirmModal,
ExportModal,
} from './components';
import { DataPublicPluginStart } from '../../../../../plugins/data/public';

interface ExportAllOption {
@@ -554,114 +536,24 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb

renderDeleteConfirmModal() {
const { isShowingDeleteConfirmModal, isDeleting, selectedSavedObjects } = this.state;

if (!isShowingDeleteConfirmModal) {
return null;
}

let modal;

if (isDeleting) {
// Block the user from interacting with the table while its contents are being deleted.
modal = <EuiLoadingElastic size="xl" />;
} else {
const onCancel = () => {
this.setState({ isShowingDeleteConfirmModal: false });
};

const onConfirm = () => {
this.delete();
};

modal = (
<EuiConfirmModal
title={
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModalTitle"
defaultMessage="Delete saved objects"
/>
}
onCancel={onCancel}
onConfirm={onConfirm}
buttonColor="danger"
cancelButtonText={
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
defaultMessage="Cancel"
/>
}
confirmButtonText={
isDeleting ? (
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel"
defaultMessage="Deleting…"
/>
) : (
<FormattedMessage
id="savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
defaultMessage="Delete"
/>
)
}
defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON}
>
<p>
<FormattedMessage
id="savedObjectsManagement.deleteSavedObjectsConfirmModalDescription"
defaultMessage="This action will delete the following saved objects:"
/>
</p>
<EuiInMemoryTable
items={selectedSavedObjects}
columns={[
{
field: 'type',
name: i18n.translate(
'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName',
{ defaultMessage: 'Type' }
),
width: '50px',
render: (type, object) => (
<EuiToolTip position="top" content={getSavedObjectLabel(type)}>
<EuiIcon type={object.meta.icon || 'apps'} />
</EuiToolTip>
),
},
{
field: 'id',
name: i18n.translate(
'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName',
{ defaultMessage: 'Id' }
),
},
{
field: 'meta.title',
name: i18n.translate(
'savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName',
{ defaultMessage: 'Title' }
),
},
]}
pagination={true}
sorting={false}
/>
</EuiConfirmModal>
);
}

return <EuiOverlayMask>{modal}</EuiOverlayMask>;
return (
<DeleteConfirmModal
isDeleting={isDeleting}
onConfirm={() => {
this.delete();
}}
onCancel={() => {
this.setState({ isShowingDeleteConfirmModal: false });
}}
selectedObjects={selectedSavedObjects}
/>
);
}

changeIncludeReferencesDeep = () => {
this.setState((state) => ({
isIncludeReferencesDeepChecked: !state.isIncludeReferencesDeepChecked,
}));
};

closeExportAllModal = () => {
this.setState({ isShowingExportAllOptionsModal: false });
};

renderExportAllOptionsModal() {
const {
isShowingExportAllOptionsModal,
@@ -676,85 +568,26 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
}

return (
<EuiOverlayMask>
<EuiModal onClose={this.closeExportAllModal}>
<EuiModalHeader>
<EuiModalHeaderTitle>
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalTitle"
defaultMessage="Export {filteredItemCount, plural, one{# object} other {# objects}}"
values={{
filteredItemCount,
}}
/>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiFormRow
label={
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModalDescription"
defaultMessage="Select which types to export"
/>
}
labelType="legend"
>
<EuiCheckboxGroup
options={exportAllOptions}
idToSelectedMap={exportAllSelectedOptions}
onChange={(optionId) => {
const newExportAllSelectedOptions = {
...exportAllSelectedOptions,
...{
[optionId]: !exportAllSelectedOptions[optionId],
},
};

this.setState({
exportAllSelectedOptions: newExportAllSelectedOptions,
});
}}
/>
</EuiFormRow>
<EuiSpacer size="m" />
<EuiSwitch
name="includeReferencesDeep"
label={
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.includeReferencesDeepLabel"
defaultMessage="Include related objects"
/>
}
checked={isIncludeReferencesDeepChecked}
onChange={this.changeIncludeReferencesDeep}
/>
</EuiModalBody>
<EuiModalFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={this.closeExportAllModal}>
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={this.onExportAll}>
<FormattedMessage
id="savedObjectsManagement.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
defaultMessage="Export all"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiModalFooter>
</EuiModal>
</EuiOverlayMask>
<ExportModal
onExport={this.onExportAll}
onCancel={() => {
this.setState({ isShowingExportAllOptionsModal: false });
}}
onSelectedOptionsChange={(newOptions) => {
this.setState({
exportAllSelectedOptions: newOptions,
});
}}
filteredItemCount={filteredItemCount}
options={exportAllOptions}
selectedOptions={exportAllSelectedOptions}
includeReferences={isIncludeReferencesDeepChecked}
onIncludeReferenceChange={(newIncludeReferences) => {
this.setState({
isIncludeReferencesDeepChecked: newIncludeReferences,
});
}}
/>
);
}

1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
@@ -3198,7 +3198,6 @@
"savedObjectsManagement.objects.savedObjectsTitle": "保存されたオブジェクト",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "キャンセル",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel": "削除",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel": "削除中…",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName": "Id",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName": "タイトル",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName": "型",
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
@@ -3202,7 +3202,6 @@
"savedObjectsManagement.objects.savedObjectsTitle": "已保存对象",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel": "取消",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel": "删除",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel": "正在删除……",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.idColumnName": "ID",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.titleColumnName": "标题",
"savedObjectsManagement.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName": "类型",

0 comments on commit a0d33dc

Please sign in to comment.