| /** |
| * 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; |