diff --git a/frontend/src/metadata/components/popover/view-popover/index.css b/frontend/src/metadata/components/popover/view-popover/index.css
index 8316c503ed..fa320fee90 100644
--- a/frontend/src/metadata/components/popover/view-popover/index.css
+++ b/frontend/src/metadata/components/popover/view-popover/index.css
@@ -1,4 +1,3 @@
-.sf-metadata-rename-view-popover .popover,
.sf-metadata-addview-popover .popover {
min-width: 280px;
padding: 0.5rem 0;
@@ -23,18 +22,6 @@
font-size: 0.875rem;
}
-.sf-metadata-rename-view-popover .sf-metadata-rename-view-popover-header {
- width: 100%;
- height: 1.5rem;
- padding: 0 1rem;
- display: flex;
- align-items: center;
- justify-content: left;
- color: #666;
- opacity: 1;
- font-size: 0.875rem;
-}
-
.sf-metadata-addview-popover
.sf-metadata-addview-popover-body {
width: 100%;
@@ -58,10 +45,6 @@
fill: #666;
}
-.sf-metadata-rename-view-popover-body {
- padding: 0 0.5rem;
-}
-
.dropdown-item:hover .metadata-view-icon {
color: #fff;
fill: #fff;
diff --git a/frontend/src/metadata/components/popover/view-popover/index.js b/frontend/src/metadata/components/popover/view-popover/index.js
index 39ad3c2597..b8760c19c6 100644
--- a/frontend/src/metadata/components/popover/view-popover/index.js
+++ b/frontend/src/metadata/components/popover/view-popover/index.js
@@ -1,2 +1 @@
-export { default as Rename } from './rename';
export { default as AddView } from './add-view';
diff --git a/frontend/src/metadata/components/popover/view-popover/rename/index.js b/frontend/src/metadata/components/popover/view-popover/rename/index.js
deleted file mode 100644
index 99d080393d..0000000000
--- a/frontend/src/metadata/components/popover/view-popover/rename/index.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import React, { useCallback, useRef, useState } from 'react';
-import PropTypes from 'prop-types';
-import { Alert, Input } from 'reactstrap';
-import { CustomizePopover } from '@seafile/sf-metadata-ui-component';
-import { gettext } from '../../../../../utils/constants';
-import { isValidViewName } from '../../../../utils/validate';
-import { isEnter } from '../../../../utils/hotkey';
-
-import '../index.css';
-
-const Rename = ({ value, target, otherViewsName, toggle, onSubmit }) => {
- const [inputValue, setInputValue] = useState(value || '');
- const [errorMessage, setErrorMessage] = useState('');
- const inputRef = useRef(null);
-
- const onChange = useCallback((e) => {
- setInputValue(e.target.value);
- }, []);
-
- const onToggle = useCallback(() => {
- toggle();
- }, [toggle]);
-
- const handleSubmit = useCallback((event) => {
- event.preventDefault();
- event.stopPropagation();
- const { isValid, message } = isValidViewName(inputValue, otherViewsName);
- if (!isValid) {
- setErrorMessage(message);
- inputRef.current.focus();
- return;
- }
- if (message === value) {
- onToggle();
- return;
- }
- onSubmit(message);
- }, [value, inputValue, otherViewsName, onSubmit, onToggle]);
-
- const onKeyDown = useCallback((event) => {
- if (isEnter(event)) {
- handleSubmit(event);
- }
- }, [handleSubmit]);
-
- return (
-
-
- {gettext('Rename view')}
-
-
-
-
- {errorMessage && (
{errorMessage})}
-
-
- );
-};
-
-Rename.propTypes = {
- value: PropTypes.string,
- target: PropTypes.string.isRequired,
- otherViewsName: PropTypes.array,
- toggle: PropTypes.func.isRequired,
- onSubmit: PropTypes.func.isRequired,
-};
-
-export default Rename;
diff --git a/frontend/src/metadata/metadata-tree-view/index.css b/frontend/src/metadata/metadata-tree-view/index.css
index 8fa06bed82..6eeabedcc4 100644
--- a/frontend/src/metadata/metadata-tree-view/index.css
+++ b/frontend/src/metadata/metadata-tree-view/index.css
@@ -59,11 +59,12 @@
}
.metadata-tree-view .sf-metadata-view-input {
- width: 100%;
+ width: 95%;
height: 24px;
position: relative;
font-size: 14px;
margin-top: 2px;
+ box-shadow: none;
}
.metadata-tree-view .metadata-views-icon {
diff --git a/frontend/src/metadata/metadata-tree-view/index.js b/frontend/src/metadata/metadata-tree-view/index.js
index 2e4a2df1f8..aea3221b79 100644
--- a/frontend/src/metadata/metadata-tree-view/index.js
+++ b/frontend/src/metadata/metadata-tree-view/index.js
@@ -149,6 +149,13 @@ const MetadataTreeView = ({ userPerm, currentPath }) => {
}
}, [handleInputSubmit]);
+ useEffect(() => {
+ if (showInput && inputRef.current) {
+ inputRef.current.focus();
+ inputRef.current.select();
+ }
+ }, [showInput]);
+
return (
<>
diff --git a/frontend/src/metadata/metadata-tree-view/view-item/index.js b/frontend/src/metadata/metadata-tree-view/view-item/index.js
index bad7b638ad..e2a53914cc 100644
--- a/frontend/src/metadata/metadata-tree-view/view-item/index.js
+++ b/frontend/src/metadata/metadata-tree-view/view-item/index.js
@@ -1,13 +1,16 @@
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { Input } from 'reactstrap';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { gettext } from '../../../utils/constants';
import Icon from '../../../components/icon';
import ItemDropdownMenu from '../../../components/dropdown-menu/item-dropdown-menu';
-import { Rename } from '../../components/popover/view-popover';
import { Utils, isMobile } from '../../../utils/utils';
import { useMetadata } from '../../hooks';
import { VIEW_TYPE_ICON } from '../../constants';
+import { isValidViewName } from '../../utils/validate';
+import { isEnter } from '../../utils/hotkey';
+import toaster from '../../../components/toast';
import './index.css';
@@ -25,7 +28,11 @@ const ViewItem = ({
const [highlight, setHighlight] = useState(false);
const [freeze, setFreeze] = useState(false);
const [isDropShow, setDropShow] = useState(false);
- const [isShowRenamePopover, setRenamePopoverShow] = useState(false);
+ const [isRenaming, setRenaming] = useState(false);
+ const [inputValue, setInputValue] = useState(view.name || '');
+
+ const inputRef = useRef(null);
+
const { viewsMap } = useMetadata();
const otherViewsName = Object.values(viewsMap).filter(v => v._id !== view._id).map(v => v.name);
@@ -78,7 +85,7 @@ const ViewItem = ({
const operationClick = useCallback((operationKey) => {
if (operationKey === 'rename') {
- setRenamePopoverShow(true);
+ setRenaming(true);
return;
}
@@ -93,13 +100,9 @@ const ViewItem = ({
}
}, [onDelete, onCopy]);
- const closeRenamePopover = useCallback(() => {
- setRenamePopoverShow(false);
- }, []);
-
const renameView = useCallback((name, failCallback) => {
onUpdate({ name }, () => {
- setRenamePopoverShow(false);
+ setRenaming(false);
document.title = `${name} - Seafile`;
}, (error) => {
failCallback(error);
@@ -143,6 +146,57 @@ const ViewItem = ({
onMove && onMove(dragData.view_id, view._id);
}, [canDrop, view, onMove]);
+ const onChange = useCallback((e) => {
+ setInputValue(e.target.value);
+ }, []);
+
+ const handleSubmit = useCallback((event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ const { isValid, message } = isValidViewName(inputValue, otherViewsName);
+ if (!isValid) {
+ toaster.danger(message);
+ return;
+ }
+ if (message === view.name) {
+ setRenaming(false);
+ return;
+ }
+ renameView(message);
+ }, [view, inputValue, otherViewsName, renameView]);
+
+ const onKeyDown = useCallback((event) => {
+ if (isEnter(event)) {
+ handleSubmit(event);
+ unfreezeItem();
+ }
+ }, [handleSubmit, unfreezeItem]);
+
+ useEffect(() => {
+ if (isRenaming && inputRef.current) {
+ inputRef.current.focus();
+ inputRef.current.select();
+ }
+ }, [isRenaming]);
+
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (inputRef.current && !inputRef.current.contains(event.target)) {
+ handleSubmit(event);
+ }
+ };
+
+ if (isRenaming) {
+ document.addEventListener('mousedown', handleClickOutside);
+ } else {
+ document.removeEventListener('mousedown', handleClickOutside);
+ }
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, [isRenaming, handleSubmit]);
+
return (
<>
- {view.name}
+ {isRenaming ? (
+ setRenaming(false)}
+ onKeyDown={onKeyDown}
+ />
+ ) : view.name}
@@ -183,9 +247,6 @@ const ViewItem = ({
)}
- {isShowRenamePopover && (
-
- )}
>
);
};