1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 19:08:21 +00:00

Change edit tags dialog UI (#5655)

* fix warnings

* 01 tags icon always show

* 02 tag list footer UI

* 03 change select color popover style

* 04 Add virtual tag

* 05 handle key event

* 06 add createRepoTags API

* 07 optimize codes

* 08 optimize codes

* optimize python code

* change create tags success callback

---------

Co-authored-by: wang <40563566+loveclever@users.noreply.github.com>
This commit is contained in:
Michael An
2023-10-09 21:27:44 +08:00
committed by GitHub
parent 39d490a253
commit e90a64cc90
19 changed files with 802 additions and 266 deletions

View File

@@ -1,158 +0,0 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Button, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import toaster from '../toast';
import RepoTag from '../../models/repo-tag';
import TagColor from './tag-color';
import TagName from './tag-name';
import '../../css/repo-tag.css';
const tagListItemPropTypes = {
item: PropTypes.object.isRequired,
repoID: PropTypes.string.isRequired,
onDeleteTag : PropTypes.func.isRequired
};
class TagListItem extends React.Component {
constructor(props) {
super(props);
this.state = {
isTagHighlighted: false
};
}
onMouseOver = () => {
this.setState({
isTagHighlighted: true
});
};
onMouseOut = () => {
this.setState({
isTagHighlighted: false
});
};
deleteTag = () => {
this.props.onDeleteTag(this.props.item);
};
render() {
const { isTagHighlighted } = this.state;
const { item, repoID } = this.props;
return (
<li
className={`tag-list-item px-4 d-flex justify-content-between align-items-center ${isTagHighlighted ? 'hl' : ''}`}
onMouseOver={this.onMouseOver}
onMouseOut={this.onMouseOut}
>
<TagColor repoID={repoID} tag={item} />
<TagName repoID={repoID} tag={item} />
<button
className={`tag-delete-icon sf2-icon-delete border-0 px-0 bg-transparent cursor-pointer ${isTagHighlighted ? '' : 'invisible'}`}
onClick={this.deleteTag}
aria-label={gettext('Delete')}
title={gettext('Delete')}
></button>
</li>
);
}
}
TagListItem.propTypes = tagListItemPropTypes;
const listTagPropTypes = {
repoID: PropTypes.string.isRequired,
onListTagCancel: PropTypes.func.isRequired,
onCreateRepoTag: PropTypes.func.isRequired
};
class ListTagDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
repotagList: []
};
}
componentDidMount() {
let repoID = this.props.repoID;
seafileAPI.listRepoTags(repoID).then(res => {
let repotagList = [];
res.data.repo_tags.forEach(item => {
let repo_tag = new RepoTag(item);
repotagList.push(repo_tag);
});
this.setState({
repotagList: repotagList
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
toggle = () => {
this.props.onListTagCancel();
};
createNewTag = (e) => {
e.preventDefault();
this.props.onCreateRepoTag();
};
onDeleteTag = (tag) => {
const { repoID } = this.props;
const { id: targetTagID } = tag;
seafileAPI.deleteRepoTag(repoID, targetTagID).then((res) => {
this.setState({
repotagList: this.state.repotagList.filter(tag => tag.id != targetTagID)
});
}).catch((error) => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
};
render() {
return (
<Fragment>
<ModalHeader toggle={this.toggle}>{gettext('Tags')}</ModalHeader>
<ModalBody className="px-0">
<ul className="tag-list tag-list-container">
{this.state.repotagList.map((repoTag, index) => {
return (
<TagListItem
key={index}
item={repoTag}
repoID={this.props.repoID}
onDeleteTag={this.onDeleteTag}
/>
);
})}
</ul>
<a
href="#"
className="add-tag-link px-4 py-2 d-flex align-items-center"
onClick={this.createNewTag}
>
<span className="sf2-icon-plus mr-2"></span>
{gettext('Create a new tag')}
</a>
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={this.toggle}>{gettext('Close')}</Button>
</ModalFooter>
</Fragment>
);
}
}
ListTagDialog.propTypes = listTagPropTypes;
export default ListTagDialog;

View File

@@ -23,6 +23,14 @@ class TagColor extends React.Component {
};
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.tag.color !== this.props.tag.color) {
this.setState({
tagColor: nextProps.tag.color,
});
}
}
togglePopover = () => {
this.setState({
isPopoverOpen: !this.state.isPopoverOpen
@@ -59,7 +67,7 @@ class TagColor extends React.Component {
<div>
<span
id={`tag-${id}-color`}
className="tag-color cursor-pointer w-4 h-4 rounded-circle d-flex align-items-center justify-content-center"
className="tag-color cursor-pointer rounded-circle d-flex align-items-center justify-content-center"
style={{backgroundColor: tagColor}}
onClick={this.togglePopover}
>
@@ -70,7 +78,7 @@ class TagColor extends React.Component {
isOpen={isPopoverOpen}
placement="bottom"
toggle={this.togglePopover}
className="mw-100"
className="tag-color-popover mw-100"
>
<PopoverBody className="p-2">
<div className="d-flex justify-content-between">

View File

@@ -22,6 +22,14 @@ class TagName extends React.Component {
this.input = React.createRef();
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.tag.name !== this.props.tag.name) {
this.setState({
tagName: nextProps.tag.name,
});
}
}
toggleMode = () => {
this.setState({
isEditing: !this.state.isEditing
@@ -51,6 +59,10 @@ class TagName extends React.Component {
this.toggleMode();
this.updateTagName(e);
}
else if (e.key == 'Escape') {
e.nativeEvent.stopImmediatePropagation();
this.toggleMode();
}
};
onInputBlur = (e) => {