chore: Tab title to be empty when creating a new tab (#12773)
* Remove unwanted package lock * Edit on new and autofocus * Update test * Remove autofocus
This commit is contained in:
parent
9335b9c983
commit
409fc83ca9
|
|
@ -119,6 +119,7 @@ export const dashboardLayoutWithTabs = {
|
|||
parents: ['ROOT_ID', 'TABS_ID'],
|
||||
meta: {
|
||||
text: 'tab1',
|
||||
defaultText: 'tab1',
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -129,6 +130,7 @@ export const dashboardLayoutWithTabs = {
|
|||
parents: ['ROOT_ID', 'TABS_ID'],
|
||||
meta: {
|
||||
text: 'tab2',
|
||||
defaultText: 'tab2',
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ describe('Tabs', () => {
|
|||
const title = wrapper.find(EditableTitle);
|
||||
expect(title).toHaveLength(1);
|
||||
expect(title.find('.editable-title')).toHaveText(
|
||||
props.component.meta.text,
|
||||
props.component.meta.defaultText,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { Tooltip } from 'src/common/components/Tooltip';
|
|||
|
||||
interface EditableTitleProps {
|
||||
canEdit?: boolean;
|
||||
editing?: boolean;
|
||||
emptyText?: string;
|
||||
extraClasses?: Array<string> | string;
|
||||
multiLine?: boolean;
|
||||
|
|
@ -30,21 +31,25 @@ interface EditableTitleProps {
|
|||
onSaveTitle: (arg0: string) => {};
|
||||
showTooltip?: boolean;
|
||||
style?: object;
|
||||
title: string;
|
||||
title?: string;
|
||||
defaultTitle?: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export default function EditableTitle({
|
||||
canEdit = false,
|
||||
emptyText,
|
||||
editing = false,
|
||||
extraClasses,
|
||||
multiLine = false,
|
||||
noPermitTooltip,
|
||||
onSaveTitle,
|
||||
showTooltip = true,
|
||||
style,
|
||||
title,
|
||||
title = '',
|
||||
defaultTitle = '',
|
||||
placeholder = '',
|
||||
}: EditableTitleProps) {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [isEditing, setIsEditing] = useState(editing);
|
||||
const [currentTitle, setCurrentTitle] = useState(title);
|
||||
const [lastTitle, setLastTitle] = useState(title);
|
||||
const [
|
||||
|
|
@ -62,6 +67,12 @@ export default function EditableTitle({
|
|||
}
|
||||
}, [title]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEditing) {
|
||||
contentRef.current.focus();
|
||||
}
|
||||
}, [isEditing]);
|
||||
|
||||
function handleClick() {
|
||||
if (!canEdit || isEditing) {
|
||||
return;
|
||||
|
|
@ -110,6 +121,10 @@ export default function EditableTitle({
|
|||
if (event.key === ' ') {
|
||||
event.stopPropagation();
|
||||
}
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
handleBlur();
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(ev: any) {
|
||||
|
|
@ -127,10 +142,9 @@ export default function EditableTitle({
|
|||
}
|
||||
|
||||
let value: string | undefined;
|
||||
if (currentTitle) {
|
||||
value = currentTitle;
|
||||
} else if (!isEditing) {
|
||||
value = emptyText;
|
||||
value = currentTitle;
|
||||
if (!isEditing && !currentTitle) {
|
||||
value = defaultTitle || title;
|
||||
}
|
||||
|
||||
// Construct an inline style based on previously-saved height of the rendered label. Only
|
||||
|
|
@ -147,7 +161,6 @@ export default function EditableTitle({
|
|||
<textarea
|
||||
data-test="editable-title-input"
|
||||
ref={contentRef}
|
||||
required
|
||||
value={value}
|
||||
className={!title ? 'text-muted' : undefined}
|
||||
onKeyDown={handleKeyDown}
|
||||
|
|
@ -155,13 +168,13 @@ export default function EditableTitle({
|
|||
onBlur={handleBlur}
|
||||
onClick={handleClick}
|
||||
onKeyPress={handleKeyPress}
|
||||
placeholder={placeholder}
|
||||
style={editStyle}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
data-test="editable-title-input"
|
||||
ref={contentRef}
|
||||
required
|
||||
type={isEditing ? 'text' : 'button'}
|
||||
value={value}
|
||||
className={!title ? 'text-muted' : undefined}
|
||||
|
|
@ -170,6 +183,7 @@ export default function EditableTitle({
|
|||
onBlur={handleBlur}
|
||||
onClick={handleClick}
|
||||
onKeyPress={handleKeyPress}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
);
|
||||
if (showTooltip && !isEditing) {
|
||||
|
|
|
|||
|
|
@ -208,9 +208,12 @@ export default class Tab extends React.PureComponent {
|
|||
<div className="dragdroppable-tab" ref={dragSourceRef}>
|
||||
<EditableTitle
|
||||
title={component.meta.text}
|
||||
defaultTitle={component.meta.defaultText}
|
||||
placeholder={component.meta.placeholder}
|
||||
canEdit={editMode && isFocused}
|
||||
onSaveTitle={this.handleChangeText}
|
||||
showTooltip={false}
|
||||
editing={editMode && isFocused}
|
||||
/>
|
||||
{!editMode && (
|
||||
<AnchorLink
|
||||
|
|
|
|||
|
|
@ -109,9 +109,12 @@ class Tabs extends React.PureComponent {
|
|||
directPathToChild: props.directPathToChild,
|
||||
}),
|
||||
);
|
||||
const { children: tabIds } = props.component;
|
||||
const activeKey = tabIds[tabIndex];
|
||||
|
||||
this.state = {
|
||||
tabIndex,
|
||||
activeKey,
|
||||
};
|
||||
this.handleClickTab = this.handleClickTab.bind(this);
|
||||
this.handleDeleteComponent = this.handleDeleteComponent.bind(this);
|
||||
|
|
@ -121,10 +124,25 @@ class Tabs extends React.PureComponent {
|
|||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
const maxIndex = Math.max(0, nextProps.component.children.length - 1);
|
||||
const currTabsIds = this.props.component.children;
|
||||
const nextTabsIds = nextProps.component.children;
|
||||
|
||||
if (this.state.tabIndex > maxIndex) {
|
||||
this.setState(() => ({ tabIndex: maxIndex }));
|
||||
}
|
||||
|
||||
if (nextTabsIds.length) {
|
||||
const lastTabId = nextTabsIds[nextTabsIds.length - 1];
|
||||
// if a new tab is added focus on it immediately
|
||||
if (nextTabsIds.length > currTabsIds.length) {
|
||||
this.setState(() => ({ activeKey: lastTabId }));
|
||||
}
|
||||
// if a tab is removed focus on the first
|
||||
if (nextTabsIds.length < currTabsIds.length) {
|
||||
this.setState(() => ({ activeKey: nextTabsIds[0] }));
|
||||
}
|
||||
}
|
||||
|
||||
if (nextProps.isComponentVisible) {
|
||||
const nextFocusComponent = getLeafComponentIdFromPath(
|
||||
nextProps.directPathToChild,
|
||||
|
|
@ -191,6 +209,7 @@ class Tabs extends React.PureComponent {
|
|||
|
||||
handleClickTab(tabIndex) {
|
||||
const { component } = this.props;
|
||||
const { children: tabIds } = component;
|
||||
|
||||
if (tabIndex !== this.state.tabIndex) {
|
||||
const pathToTabIndex = getDirectPathToTabIndex(component, tabIndex);
|
||||
|
|
@ -202,6 +221,7 @@ class Tabs extends React.PureComponent {
|
|||
|
||||
this.props.onChangeTab({ pathToTabIndex });
|
||||
}
|
||||
this.setState(() => ({ activeKey: tabIds[tabIndex] }));
|
||||
}
|
||||
|
||||
handleDeleteComponent() {
|
||||
|
|
@ -250,10 +270,8 @@ class Tabs extends React.PureComponent {
|
|||
editMode,
|
||||
} = this.props;
|
||||
|
||||
const { tabIndex: selectedTabIndex } = this.state;
|
||||
const { children: tabIds } = tabsComponent;
|
||||
|
||||
const activeKey = tabIds[selectedTabIndex];
|
||||
const { tabIndex: selectedTabIndex, activeKey } = this.state;
|
||||
|
||||
return (
|
||||
<DragDroppable
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import shortid from 'shortid';
|
||||
import { t } from '@superset-ui/core';
|
||||
|
||||
import {
|
||||
CHART_TYPE,
|
||||
|
|
@ -50,7 +51,11 @@ const typeToDefaultMetaData = {
|
|||
[MARKDOWN_TYPE]: { width: GRID_DEFAULT_CHART_WIDTH, height: 50 },
|
||||
[ROW_TYPE]: { background: BACKGROUND_TRANSPARENT },
|
||||
[TABS_TYPE]: null,
|
||||
[TAB_TYPE]: { text: 'New tab' },
|
||||
[TAB_TYPE]: {
|
||||
text: '',
|
||||
defaultText: t('Tab title'),
|
||||
placeholder: t('Tab title'),
|
||||
},
|
||||
};
|
||||
|
||||
function uuid(type) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue