241 lines
6.9 KiB
JavaScript
241 lines
6.9 KiB
JavaScript
/**
|
|
* 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.
|
|
*/
|
|
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
|
|
import DashboardComponent from '../../containers/DashboardComponent';
|
|
import DragDroppable from '../dnd/DragDroppable';
|
|
import EditableTitle from '../../../components/EditableTitle';
|
|
import AnchorLink from '../../../components/AnchorLink';
|
|
import { componentShape } from '../../util/propShapes';
|
|
|
|
export const RENDER_TAB = 'RENDER_TAB';
|
|
export const RENDER_TAB_CONTENT = 'RENDER_TAB_CONTENT';
|
|
|
|
const propTypes = {
|
|
id: PropTypes.string.isRequired,
|
|
parentId: PropTypes.string.isRequired,
|
|
component: componentShape.isRequired,
|
|
parentComponent: componentShape.isRequired,
|
|
index: PropTypes.number.isRequired,
|
|
depth: PropTypes.number.isRequired,
|
|
renderType: PropTypes.oneOf([RENDER_TAB, RENDER_TAB_CONTENT]).isRequired,
|
|
onDropOnTab: PropTypes.func,
|
|
editMode: PropTypes.bool.isRequired,
|
|
filters: PropTypes.object.isRequired,
|
|
|
|
// grid related
|
|
availableColumnCount: PropTypes.number,
|
|
columnWidth: PropTypes.number,
|
|
onResizeStart: PropTypes.func,
|
|
onResize: PropTypes.func,
|
|
onResizeStop: PropTypes.func,
|
|
|
|
// redux
|
|
handleComponentDrop: PropTypes.func.isRequired,
|
|
updateComponents: PropTypes.func.isRequired,
|
|
setDirectPathToChild: PropTypes.func.isRequired,
|
|
};
|
|
|
|
const defaultProps = {
|
|
availableColumnCount: 0,
|
|
columnWidth: 0,
|
|
onDropOnTab() {},
|
|
onResizeStart() {},
|
|
onResize() {},
|
|
onResizeStop() {},
|
|
};
|
|
|
|
export default class Tab extends React.PureComponent {
|
|
constructor(props) {
|
|
super(props);
|
|
this.handleChangeText = this.handleChangeText.bind(this);
|
|
this.handleDrop = this.handleDrop.bind(this);
|
|
this.handleTopDropTargetDrop = this.handleTopDropTargetDrop.bind(this);
|
|
this.handleChangeTab = this.handleChangeTab.bind(this);
|
|
}
|
|
|
|
handleChangeTab({ pathToTabIndex }) {
|
|
this.props.setDirectPathToChild(pathToTabIndex);
|
|
}
|
|
|
|
handleChangeText(nextTabText) {
|
|
const { updateComponents, component } = this.props;
|
|
if (nextTabText && nextTabText !== component.meta.text) {
|
|
updateComponents({
|
|
[component.id]: {
|
|
...component,
|
|
meta: {
|
|
...component.meta,
|
|
text: nextTabText,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
handleDrop(dropResult) {
|
|
this.props.handleComponentDrop(dropResult);
|
|
this.props.onDropOnTab(dropResult);
|
|
}
|
|
|
|
handleTopDropTargetDrop(dropResult) {
|
|
if (dropResult) {
|
|
this.props.handleComponentDrop({
|
|
...dropResult,
|
|
destination: {
|
|
...dropResult.destination,
|
|
// force appending as the first child if top drop target
|
|
index: 0,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
renderTabContent() {
|
|
const {
|
|
component: tabComponent,
|
|
parentComponent: tabParentComponent,
|
|
depth,
|
|
availableColumnCount,
|
|
columnWidth,
|
|
onResizeStart,
|
|
onResize,
|
|
onResizeStop,
|
|
editMode,
|
|
isComponentVisible,
|
|
} = this.props;
|
|
|
|
return (
|
|
<div className="dashboard-component-tabs-content">
|
|
{/* Make top of tab droppable */}
|
|
{editMode && (
|
|
<DragDroppable
|
|
component={tabComponent}
|
|
parentComponent={tabParentComponent}
|
|
orientation="column"
|
|
index={0}
|
|
depth={depth}
|
|
onDrop={this.handleTopDropTargetDrop}
|
|
editMode
|
|
className="empty-droptarget"
|
|
>
|
|
{({ dropIndicatorProps }) =>
|
|
dropIndicatorProps && (
|
|
<div className="drop-indicator drop-indicator--top" />
|
|
)
|
|
}
|
|
</DragDroppable>
|
|
)}
|
|
{tabComponent.children.map((componentId, componentIndex) => (
|
|
<DashboardComponent
|
|
key={componentId}
|
|
id={componentId}
|
|
parentId={tabComponent.id}
|
|
depth={depth} // see isValidChild.js for why tabs don't increment child depth
|
|
index={componentIndex}
|
|
onDrop={this.handleDrop}
|
|
availableColumnCount={availableColumnCount}
|
|
columnWidth={columnWidth}
|
|
onResizeStart={onResizeStart}
|
|
onResize={onResize}
|
|
onResizeStop={onResizeStop}
|
|
isComponentVisible={isComponentVisible}
|
|
onChangeTab={this.handleChangeTab}
|
|
/>
|
|
))}
|
|
{/* Make bottom of tab droppable */}
|
|
{editMode && (
|
|
<DragDroppable
|
|
component={tabComponent}
|
|
parentComponent={tabParentComponent}
|
|
orientation="column"
|
|
index={tabComponent.children.length}
|
|
depth={depth}
|
|
onDrop={this.handleDrop}
|
|
editMode
|
|
className="empty-droptarget"
|
|
>
|
|
{({ dropIndicatorProps }) =>
|
|
dropIndicatorProps && (
|
|
<div className="drop-indicator drop-indicator--bottom" />
|
|
)
|
|
}
|
|
</DragDroppable>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderTab() {
|
|
const {
|
|
component,
|
|
parentComponent,
|
|
index,
|
|
depth,
|
|
editMode,
|
|
filters,
|
|
isFocused,
|
|
} = this.props;
|
|
|
|
return (
|
|
<DragDroppable
|
|
component={component}
|
|
parentComponent={parentComponent}
|
|
orientation="column"
|
|
index={index}
|
|
depth={depth}
|
|
onDrop={this.handleDrop}
|
|
editMode={editMode}
|
|
>
|
|
{({ dropIndicatorProps, dragSourceRef }) => (
|
|
<div className="dragdroppable-tab" ref={dragSourceRef}>
|
|
<EditableTitle
|
|
title={component.meta.text}
|
|
canEdit={editMode && isFocused}
|
|
onSaveTitle={this.handleChangeText}
|
|
showTooltip={false}
|
|
/>
|
|
{!editMode && (
|
|
<AnchorLink
|
|
anchorLinkId={component.id}
|
|
filters={filters}
|
|
showShortLinkButton
|
|
placement={index >= 5 ? 'left' : 'right'}
|
|
/>
|
|
)}
|
|
|
|
{dropIndicatorProps && <div {...dropIndicatorProps} />}
|
|
</div>
|
|
)}
|
|
</DragDroppable>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const { renderType } = this.props;
|
|
return renderType === RENDER_TAB
|
|
? this.renderTab()
|
|
: this.renderTabContent();
|
|
}
|
|
}
|
|
|
|
Tab.propTypes = propTypes;
|
|
Tab.defaultProps = defaultProps;
|