Skip to content

Commit

Permalink
[Graph] Save modal (#44261)
Browse files Browse the repository at this point in the history
* create graph listing page

* clean up app folder

* remove inline loading menu

* also add badge to workspace route

* fix tests

* fix graph spaces functional test

* generate documentation for new breadcrumb property

* fix test subject names

* remove unused translations

* start implementing save modal flow for Graph

* fix spaces functional test

* wip save modal

* wip save modal

* add and style save modal

* add placeholder to description field

* disable dirty check on breadcrumb navigation and fix delete function

* improve onClick typing on breadcrumb

* fix newline error and use new types in dashboard app controller

* fix translation errors

* fix i18n translation for real

* code review

* fix i18n phrases

* remove fragments

* remove unnecessary max-width and add commentary

* move to async syntax

* clean up implementation

* use description instead of title

* fix snapshot

* adress review comments and set width for all save modals

* fix bug and improve typing

* fix classname
  • Loading branch information
flash1293 authored Sep 5, 2019
1 parent 1b76070 commit f080218
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';

import { docTitle } from 'ui/doc_title/doc_title';

// @ts-ignore
import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
import { showSaveModal, SaveResult } from 'ui/saved_objects/show_saved_object_save_modal';

import { showShareContextMenu, ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
Expand Down Expand Up @@ -604,7 +603,7 @@ export class DashboardAppController {
* @return {Promise}
* @resolved {String} - The id of the doc
*/
function save(saveOptions: SaveOptions): Promise<{ id?: string } | { error: Error }> {
function save(saveOptions: SaveOptions): Promise<SaveResult> {
return saveDashboard(angular.toJson, timefilter, dashboardStateManager, saveOptions)
.then(function(id) {
if (id) {
Expand Down Expand Up @@ -695,7 +694,7 @@ export class DashboardAppController {
isTitleDuplicateConfirmed,
onTitleDuplicate,
};
return save(saveOptions).then((response: { id?: string } | { error: Error }) => {
return save(saveOptions).then((response: SaveResult) => {
// If the save wasn't successful, put the original values back.
if (!(response as { id: string }).id) {
dashboardStateManager.setTitle(currentTitle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ import 'uiExports/visualize';
import { i18n } from '@kbn/i18n';

import { capabilities } from 'ui/capabilities';
// @ts-ignore
import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
// @ts-ignore
import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';

import chrome from 'ui/chrome';
import { getVisualizeLoader } from 'ui/visualize/loader';
Expand Down
1 change: 1 addition & 0 deletions src/legacy/ui/public/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@import './exit_full_screen/index';
@import './field_editor/index';
@import './notify/index';
@import './saved_objects/index';
@import './share/index';
@import './style_compile/index';

Expand Down
1 change: 1 addition & 0 deletions src/legacy/ui/public/saved_objects/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '../../../../plugins/kibana_react/public/saved_objects/index';
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,25 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { I18nContext } from 'ui/i18n';

export function showSaveModal(saveModal) {
/**
* Represents the result of trying to persist the saved object.
* Contains `error` prop if something unexpected happened (e.g. network error).
* Contains an `id` if persisting was successful. If `id` and
* `error` are undefined, persisting was not successful, but the
* modal can still recover (e.g. the name of the saved object was already taken).
*/
export type SaveResult = { id?: string } | { error: Error };

function isSuccess(result: SaveResult): result is { id?: string } {
return 'id' in result;
}

interface MinimalSaveModalProps {
onSave: (...args: any[]) => Promise<SaveResult>;
onClose: () => void;
}

export function showSaveModal(saveModal: React.ReactElement<MinimalSaveModalProps>) {
const container = document.createElement('div');
const closeModal = () => {
ReactDOM.unmountComponentAtNode(container);
Expand All @@ -30,21 +48,19 @@ export function showSaveModal(saveModal) {

const onSave = saveModal.props.onSave;

const onSaveConfirmed = (...args) => {
onSave(...args).then(({ id, error }) => {
if (id || error) {
closeModal();
}
});
const onSaveConfirmed: MinimalSaveModalProps['onSave'] = async (...args) => {
const response = await onSave(...args);
// close modal if we either hit an error or the saved object got an id
if (Boolean(isSuccess(response) ? response.id : response.error)) {
closeModal();
}
return response;
};
document.body.appendChild(container);
const element = React.cloneElement(
saveModal,
{
onSave: onSaveConfirmed,
onClose: closeModal
}
);
const element = React.cloneElement(saveModal, {
onSave: onSaveConfirmed,
onClose: closeModal,
});

ReactDOM.render(<I18nContext>{element}</I18nContext>, container);
}

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

1 change: 1 addition & 0 deletions src/plugins/kibana_react/public/saved_objects/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import './saved_object_save_modal';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.kbnSavedObjectSaveModal {
width: $euiSizeXXL * 10;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ import {
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

interface OnSaveProps {
export interface OnSaveProps {
newTitle: string;
newCopyOnSave: boolean;
isTitleDuplicateConfirmed: boolean;
Expand Down Expand Up @@ -72,14 +73,14 @@ export class SavedObjectSaveModal extends React.Component<Props, State> {
};

public render() {
const { isTitleDuplicateConfirmed, hasTitleDuplicate, title, isLoading } = this.state;
const { isTitleDuplicateConfirmed, hasTitleDuplicate, title } = this.state;

return (
<EuiOverlayMask>
<form onSubmit={this.onFormSubmit}>
<EuiModal
data-test-subj="savedObjectSaveModal"
className="dshSaveModal"
className="kbnSavedObjectSaveModal"
onClose={this.props.onClose}
>
<EuiModalHeader>
Expand Down Expand Up @@ -136,22 +137,7 @@ export class SavedObjectSaveModal extends React.Component<Props, State> {
/>
</EuiButtonEmpty>

<EuiButton
fill
data-test-subj="confirmSaveSavedObjectButton"
isLoading={isLoading}
isDisabled={title.length === 0}
type="submit"
>
{this.props.confirmButtonLabel ? (
this.props.confirmButtonLabel
) : (
<FormattedMessage
id="kibana-react.savedObjects.saveModal.confirmSaveButtonLabel"
defaultMessage="Confirm Save"
/>
)}
</EuiButton>
{this.renderConfirmButton()}
</EuiModalFooter>
</EuiModal>
</form>
Expand Down Expand Up @@ -204,6 +190,34 @@ export class SavedObjectSaveModal extends React.Component<Props, State> {
this.saveSavedObject();
};

private renderConfirmButton = () => {
const { isLoading, title, hasTitleDuplicate } = this.state;

let confirmLabel: string | React.ReactNode = hasTitleDuplicate
? i18n.translate('kibana-react.savedObjects.saveModal.confirmSaveButtonLabel', {
defaultMessage: 'Confirm save',
})
: i18n.translate('kibana-react.savedObjects.saveModal.saveButtonLabel', {
defaultMessage: 'Save',
});

if (this.props.confirmButtonLabel) {
confirmLabel = this.props.confirmButtonLabel;
}

return (
<EuiButton
fill
data-test-subj="confirmSaveSavedObjectButton"
isLoading={isLoading}
isDisabled={title.length === 0}
type="submit"
>
{confirmLabel}
</EuiButton>
);
};

private renderDuplicateTitleCallout = () => {
if (!this.state.hasTitleDuplicate) {
return;
Expand All @@ -230,10 +244,14 @@ export class SavedObjectSaveModal extends React.Component<Props, State> {
objectType: this.props.objectType,
confirmSaveLabel: (
<strong>
<FormattedMessage
id="kibana-react.savedObjects.saveModal.duplicateTitleDescription.confirmSaveText"
defaultMessage="Confirm Save"
/>
{this.props.confirmButtonLabel
? this.props.confirmButtonLabel
: i18n.translate(
'kibana-react.savedObjects.saveModal.duplicateTitleDescription.confirmSaveText',
{
defaultMessage: 'Confirm save',
}
)}
</strong>
),
}}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
<kbn-top-nav name="workspacesTopNav" config="topNavMenu">
</kbn-top-nav>

<div class="gphGraph__menus" ng-show="menus.showSave || menus.showSettings">
<graph-save ng-show="menus.showSave"></graph-save>
<div class="gphGraph__menus" ng-show="menus.showSettings">
<graph-settings ng-show="menus.showSettings"></graph-settings>
</div>

Expand Down

This file was deleted.

Loading

0 comments on commit f080218

Please sign in to comment.