blob: 0bbc327767558ea5283000a1793ad359c56b13c2 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.
*/
/* eslint-env browser */
import React from 'react';
import { FormControl, FormGroup } from 'react-bootstrap';
import { RadioChangeEvent } from 'src/common/components';
import { Radio } from 'src/common/components/Radio';
import Button from 'src/components/Button';
import { t, CategoricalColorNamespace, JsonResponse } from '@superset-ui/core';
import ModalTrigger from 'src/components/ModalTrigger';
import Checkbox from 'src/components/Checkbox';
import {
SAVE_TYPE_OVERWRITE,
SAVE_TYPE_NEWDASHBOARD,
} from 'src/dashboard/util/constants';
type SaveType = typeof SAVE_TYPE_OVERWRITE | typeof SAVE_TYPE_NEWDASHBOARD;
type SaveModalProps = {
addSuccessToast: (arg: string) => void;
addDangerToast: (arg: string) => void;
dashboardId: number;
dashboardTitle: string;
dashboardInfo: Record<string, any>;
expandedSlices: Record<string, any>;
layout: Record<string, any>;
saveType: SaveType;
triggerNode: JSX.Element;
customCss: string;
colorNamespace?: string;
colorScheme?: string;
onSave: (data: any, id: number | string, saveType: SaveType) => void;
canOverwrite: boolean;
shouldPersistRefreshFrequency: boolean;
refreshFrequency: number;
lastModifiedTime: number;
};
type SaveModalState = {
saveType: SaveType;
newDashName: string;
duplicateSlices: boolean;
};
const defaultProps = {
saveType: SAVE_TYPE_OVERWRITE,
colorNamespace: undefined,
colorScheme: undefined,
shouldPersistRefreshFrequency: false,
};
class SaveModal extends React.PureComponent<SaveModalProps, SaveModalState> {
static defaultProps = defaultProps;
modal: ModalTrigger | null;
onSave: (
data: Record<string, any>,
dashboardId: number | string,
saveType: SaveType,
) => Promise<JsonResponse>;
constructor(props: SaveModalProps) {
super(props);
this.state = {
saveType: props.saveType,
newDashName: `${props.dashboardTitle} [copy]`,
duplicateSlices: false,
};
this.modal = null;
this.handleSaveTypeChange = this.handleSaveTypeChange.bind(this);
this.handleNameChange = this.handleNameChange.bind(this);
this.saveDashboard = this.saveDashboard.bind(this);
this.setModalRef = this.setModalRef.bind(this);
this.toggleDuplicateSlices = this.toggleDuplicateSlices.bind(this);
this.onSave = this.props.onSave.bind(this);
}
setModalRef(ref: ModalTrigger | null) {
this.modal = ref;
}
toggleDuplicateSlices(): void {
this.setState(prevState => ({
duplicateSlices: !prevState.duplicateSlices,
}));
}
handleSaveTypeChange(event: RadioChangeEvent) {
this.setState({
saveType: (event.target as HTMLInputElement).value as SaveType,
});
}
handleNameChange(event: React.FormEvent<FormControl>) {
this.setState({
newDashName: (event.target as HTMLInputElement).value,
saveType: SAVE_TYPE_NEWDASHBOARD,
});
}
saveDashboard() {
const { saveType, newDashName } = this.state;
const {
dashboardTitle,
dashboardInfo,
layout: positions,
customCss,
colorNamespace,
colorScheme,
expandedSlices,
dashboardId,
refreshFrequency: currentRefreshFrequency,
shouldPersistRefreshFrequency,
lastModifiedTime,
} = this.props;
const scale = CategoricalColorNamespace.getScale(
colorScheme,
colorNamespace,
);
const labelColors = colorScheme ? scale.getColorMap() : {};
// check refresh frequency is for current session or persist
const refreshFrequency = shouldPersistRefreshFrequency
? currentRefreshFrequency
: dashboardInfo.metadata.refresh_frequency; // eslint-disable camelcase
const data = {
positions,
css: customCss,
color_namespace: colorNamespace,
color_scheme: colorScheme,
label_colors: labelColors,
expanded_slices: expandedSlices,
dashboard_title:
saveType === SAVE_TYPE_NEWDASHBOARD ? newDashName : dashboardTitle,
duplicate_slices: this.state.duplicateSlices,
refresh_frequency: refreshFrequency,
last_modified_time: lastModifiedTime,
};
if (saveType === SAVE_TYPE_NEWDASHBOARD && !newDashName) {
this.props.addDangerToast(
t('You must pick a name for the new dashboard'),
);
} else {
this.onSave(data, dashboardId, saveType).then((resp: JsonResponse) => {
if (
saveType === SAVE_TYPE_NEWDASHBOARD &&
resp &&
resp.json &&
resp.json.id
) {
window.location.href = `/superset/dashboard/${resp.json.id}/`;
}
});
this.modal?.close();
}
}
render() {
return (
<ModalTrigger
ref={this.setModalRef}
triggerNode={this.props.triggerNode}
modalTitle={t('Save dashboard')}
modalBody={
<FormGroup>
<Radio
value={SAVE_TYPE_OVERWRITE}
onChange={this.handleSaveTypeChange}
checked={this.state.saveType === SAVE_TYPE_OVERWRITE}
disabled={!this.props.canOverwrite}
>
{t('Overwrite Dashboard [%s]', this.props.dashboardTitle)}
</Radio>
<hr />
<Radio
value={SAVE_TYPE_NEWDASHBOARD}
onChange={this.handleSaveTypeChange}
checked={this.state.saveType === SAVE_TYPE_NEWDASHBOARD}
>
{t('Save as:')}
</Radio>
<FormControl
type="text"
placeholder={t('[dashboard name]')}
value={this.state.newDashName}
onFocus={this.handleNameChange}
onChange={this.handleNameChange}
/>
<div className="m-l-25 m-t-5">
<Checkbox
checked={this.state.duplicateSlices}
onChange={() => this.toggleDuplicateSlices()}
/>
<span className="m-l-5">{t('also copy (duplicate) charts')}</span>
</div>
</FormGroup>
}
modalFooter={
<div>
<Button
data-test="modal-save-dashboard-button"
buttonStyle="primary"
onClick={this.saveDashboard}
>
{t('Save')}
</Button>
</div>
}
/>
);
}
}
export default SaveModal;