Skip to content

Commit

Permalink
Revert "remove clone for dashboard"
Browse files Browse the repository at this point in the history
This reverts commit 84f77fb.
  • Loading branch information
yuye-aws committed Sep 18, 2023
1 parent e5ed88b commit 133a380
Show file tree
Hide file tree
Showing 9 changed files with 497 additions and 2 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,79 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Any modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

/*
* 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 sinon from 'sinon';
import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';

import { DashboardCloneModal } from './clone_modal';

let onClone;
let onClose;

beforeEach(() => {
onClone = sinon.spy();
onClose = sinon.spy();
});

test('renders DashboardCloneModal', () => {
const component = shallowWithI18nProvider(
<DashboardCloneModal title="dash title" onClose={onClose} onClone={onClone} />
);
expect(component).toMatchSnapshot(); // eslint-disable-line
});

test('onClone', () => {
const component = mountWithI18nProvider(
<DashboardCloneModal title="dash title" onClose={onClose} onClone={onClone} />
);
findTestSubject(component, 'cloneConfirmButton').simulate('click');
sinon.assert.calledWith(onClone, 'dash title');
sinon.assert.notCalled(onClose);
});

test('onClose', () => {
const component = mountWithI18nProvider(
<DashboardCloneModal title="dash title" onClose={onClose} onClone={onClone} />
);
findTestSubject(component, 'cloneCancelButton').simulate('click');
sinon.assert.calledOnce(onClose);
sinon.assert.notCalled(onClone);
});

test('title', () => {
const component = mountWithI18nProvider(
<DashboardCloneModal title="dash title" onClose={onClose} onClone={onClone} />
);
const event = { target: { value: 'a' } };
component.find('input').simulate('change', event);
findTestSubject(component, 'cloneConfirmButton').simulate('click');
sinon.assert.calledWith(onClone, 'a');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Any modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

/*
* 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, { Fragment } from 'react';
import { i18n } from '@osd/i18n';
import { FormattedMessage } from '@osd/i18n/react';

import {
EuiButton,
EuiButtonEmpty,
EuiFieldText,
EuiModal,
EuiModalBody,
EuiModalFooter,
EuiModalHeader,
EuiModalHeaderTitle,
EuiSpacer,
EuiText,
EuiCallOut,
} from '@elastic/eui';

interface Props {
onClone: (
newTitle: string,
isTitleDuplicateConfirmed: boolean,
onTitleDuplicate: () => void
) => Promise<void>;
onClose: () => void;
title: string;
}

interface State {
newDashboardName: string;
isTitleDuplicateConfirmed: boolean;
hasTitleDuplicate: boolean;
isLoading: boolean;
}

export class DashboardCloneModal extends React.Component<Props, State> {
private isMounted = false;

constructor(props: Props) {
super(props);

this.state = {
newDashboardName: props.title,
isTitleDuplicateConfirmed: false,
hasTitleDuplicate: false,
isLoading: false,
};
}
componentDidMount() {
this.isMounted = true;
}

componentWillUnmount() {
this.isMounted = false;
}

onTitleDuplicate = () => {
this.setState({
isTitleDuplicateConfirmed: true,
hasTitleDuplicate: true,
});
};

cloneDashboard = async () => {
this.setState({
isLoading: true,
});

await this.props.onClone(
this.state.newDashboardName,
this.state.isTitleDuplicateConfirmed,
this.onTitleDuplicate
);

if (this.isMounted) {
this.setState({
isLoading: false,
});
}
};

onInputChange = (event: any) => {
this.setState({
newDashboardName: event.target.value,
isTitleDuplicateConfirmed: false,
hasTitleDuplicate: false,
});
};

renderDuplicateTitleCallout = () => {
if (!this.state.hasTitleDuplicate) {
return;
}

return (
<Fragment>
<EuiSpacer />
<EuiCallOut
size="s"
title={i18n.translate('dashboard.topNav.cloneModal.dashboardExistsTitle', {
defaultMessage: 'A dashboard with the title {newDashboardName} already exists.',
values: {
newDashboardName: `'${this.state.newDashboardName}'`,
},
})}
color="warning"
data-test-subj="titleDupicateWarnMsg"
>
<p>
<FormattedMessage
id="dashboard.topNav.cloneModal.dashboardExistsDescription"
defaultMessage="Click {confirmClone} to clone the dashboard with the duplicate title."
values={{
confirmClone: (
<strong>
<FormattedMessage
id="dashboard.topNav.cloneModal.confirmCloneDescription"
defaultMessage="Confirm Clone"
/>
</strong>
),
}}
/>
</p>
</EuiCallOut>
</Fragment>
);
};

render() {
return (
<EuiModal
data-test-subj="dashboardCloneModal"
className="dshCloneModal"
onClose={this.props.onClose}
>
<EuiModalHeader>
<EuiModalHeaderTitle>
<FormattedMessage
id="dashboard.topNav.cloneModal.cloneDashboardModalHeaderTitle"
defaultMessage="Clone dashboard"
/>
</EuiModalHeaderTitle>
</EuiModalHeader>

<EuiModalBody>
<EuiText>
<p>
<FormattedMessage
id="dashboard.topNav.cloneModal.enterNewNameForDashboardDescription"
defaultMessage="Please enter a new name for your dashboard."
/>
</p>
</EuiText>

<EuiSpacer />

<EuiFieldText
autoFocus
aria-label={i18n.translate('dashboard.cloneModal.cloneDashboardTitleAriaLabel', {
defaultMessage: 'Cloned Dashboard Title',
})}
data-test-subj="clonedDashboardTitle"
value={this.state.newDashboardName}
onChange={this.onInputChange}
isInvalid={this.state.hasTitleDuplicate}
/>

{this.renderDuplicateTitleCallout()}
</EuiModalBody>

<EuiModalFooter>
<EuiButtonEmpty data-test-subj="cloneCancelButton" onClick={this.props.onClose}>
<FormattedMessage
id="dashboard.topNav.cloneModal.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>

<EuiButton
fill
data-test-subj="cloneConfirmButton"
onClick={this.cloneDashboard}
isLoading={this.state.isLoading}
>
<FormattedMessage
id="dashboard.topNav.cloneModal.confirmButtonLabel"
defaultMessage="Confirm Clone"
/>
</EuiButton>
</EuiModalFooter>
</EuiModal>
);
}
}
Loading

0 comments on commit 133a380

Please sign in to comment.