2018-11-29 09:55:14 +00:00
|
|
|
import React, { Component, Fragment } from 'react';
|
2018-10-16 10:19:51 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2019-01-07 03:01:55 +00:00
|
|
|
import moment from 'moment';
|
2018-09-21 06:16:15 +00:00
|
|
|
import { seafileAPI } from '../../utils/seafile-api';
|
2019-03-21 06:29:09 +00:00
|
|
|
import { gettext, siteRoot, serviceURL } from '../../utils/constants';
|
2018-12-24 04:24:16 +00:00
|
|
|
import { Utils } from '../../utils/utils';
|
2018-12-28 03:12:24 +00:00
|
|
|
import Loading from '../../components/loading';
|
2019-01-22 11:52:05 +00:00
|
|
|
import Activity from '../../models/activity';
|
2019-02-13 03:19:40 +00:00
|
|
|
import ListCreatedFileDialog from '../../components/dialog/list-created-files-dialog';
|
|
|
|
import ModalPortal from '../../components/modal-portal';
|
2019-07-25 07:06:58 +00:00
|
|
|
|
2019-02-20 09:46:18 +00:00
|
|
|
import '../../css/files-activities.css';
|
2018-08-30 07:10:52 +00:00
|
|
|
|
2019-01-07 03:01:55 +00:00
|
|
|
moment.locale(window.app.config.lang);
|
|
|
|
|
2018-10-16 10:19:51 +00:00
|
|
|
const contentPropTypes = {
|
2018-12-28 03:12:24 +00:00
|
|
|
isLoadingMore: PropTypes.bool.isRequired,
|
|
|
|
items: PropTypes.array.isRequired,
|
2018-10-16 10:19:51 +00:00
|
|
|
};
|
|
|
|
|
2018-08-30 07:10:52 +00:00
|
|
|
class FileActivitiesContent extends Component {
|
|
|
|
|
|
|
|
render() {
|
2019-08-22 12:23:08 +00:00
|
|
|
const isDesktop = Utils.isDesktop();
|
2019-07-25 07:06:58 +00:00
|
|
|
let { items, isLoadingMore } = this.props;
|
|
|
|
|
|
|
|
const desktopThead = (
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th width="8%">{/* avatar */}</th>
|
|
|
|
<th width="15%">{gettext('User')}</th>
|
|
|
|
<th width="20%">{gettext('Operation')}</th>
|
|
|
|
<th width="37%">{gettext('File')} / {gettext('Library')}</th>
|
|
|
|
<th width="20%">{gettext('Time')}</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
);
|
|
|
|
|
|
|
|
const mobileThead = (
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th width="15%"></th>
|
|
|
|
<th width="53%"></th>
|
|
|
|
<th width="32%"></th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
);
|
|
|
|
|
2020-11-02 05:56:35 +00:00
|
|
|
return (
|
2018-12-28 03:12:24 +00:00
|
|
|
<Fragment>
|
2019-07-25 07:06:58 +00:00
|
|
|
<table className="table-hover table-thead-hidden">
|
|
|
|
{isDesktop ? desktopThead : mobileThead}
|
2019-02-28 10:09:21 +00:00
|
|
|
<tbody>
|
|
|
|
{items.map((item, index) => {
|
|
|
|
return (
|
2020-11-02 05:56:35 +00:00
|
|
|
<ActivityItem
|
2019-02-28 10:09:21 +00:00
|
|
|
key={index}
|
2019-08-22 12:23:08 +00:00
|
|
|
isDesktop={isDesktop}
|
2019-02-28 10:09:21 +00:00
|
|
|
item={item}
|
|
|
|
index={index}
|
|
|
|
items={items}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</tbody>
|
2018-12-28 03:12:24 +00:00
|
|
|
</table>
|
|
|
|
{isLoadingMore ? <span className="loading-icon loading-tip"></span> : ''}
|
|
|
|
</Fragment>
|
2020-11-02 05:56:35 +00:00
|
|
|
);
|
2018-08-30 07:10:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 10:19:51 +00:00
|
|
|
FileActivitiesContent.propTypes = contentPropTypes;
|
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
const activityPropTypes = {
|
|
|
|
item: PropTypes.object.isRequired,
|
|
|
|
index: PropTypes.number.isRequired,
|
2018-10-16 10:19:51 +00:00
|
|
|
items: PropTypes.array.isRequired,
|
2023-09-13 00:40:50 +00:00
|
|
|
isDesktop: PropTypes.bool.isRequired,
|
2018-10-16 10:19:51 +00:00
|
|
|
};
|
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
class ActivityItem extends Component {
|
2018-08-30 07:10:52 +00:00
|
|
|
|
2019-02-13 03:19:40 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
isListCreatedFiles: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
onListCreatedFilesToggle = () => {
|
2019-02-13 03:19:40 +00:00
|
|
|
this.setState({
|
|
|
|
isListCreatedFiles: !this.state.isListCreatedFiles,
|
|
|
|
});
|
2023-09-13 00:40:50 +00:00
|
|
|
};
|
2019-02-13 03:19:40 +00:00
|
|
|
|
2018-08-30 07:10:52 +00:00
|
|
|
render() {
|
2019-08-22 12:23:08 +00:00
|
|
|
const isDesktop = this.props.isDesktop;
|
2019-02-28 10:09:21 +00:00
|
|
|
let {item, index, items} = this.props;
|
2019-07-25 07:06:58 +00:00
|
|
|
let op, details, moreDetails = false;
|
2019-02-28 10:09:21 +00:00
|
|
|
let userProfileURL = `${siteRoot}profile/${encodeURIComponent(item.author_email)}/`;
|
2018-08-30 07:10:52 +00:00
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
let libURL = siteRoot + 'library/' + item.repo_id + '/' + encodeURIComponent(item.repo_name) + '/';
|
|
|
|
let libLink = <a href={libURL}>{item.repo_name}</a>;
|
|
|
|
let smallLibLink = <a className="small text-secondary" href={libURL}>{item.repo_name}</a>;
|
2018-08-30 07:10:52 +00:00
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
if (item.obj_type == 'repo') {
|
|
|
|
switch(item.op_type) {
|
|
|
|
case 'create':
|
|
|
|
op = gettext('Created library');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = libLink;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'rename':
|
|
|
|
op = gettext('Renamed library');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = <span>{item.old_repo_name} => {libLink}</span>;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'delete':
|
|
|
|
op = gettext('Deleted library');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = item.repo_name;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'recover':
|
|
|
|
op = gettext('Restored library');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = libLink;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'clean-up-trash':
|
2019-07-25 07:06:58 +00:00
|
|
|
op = gettext('Cleaned trash');
|
2019-02-28 10:09:21 +00:00
|
|
|
if (item.days == 0) {
|
2019-07-25 07:06:58 +00:00
|
|
|
details = gettext('Removed all items from trash.');
|
2019-02-28 10:09:21 +00:00
|
|
|
} else {
|
2019-07-25 07:06:58 +00:00
|
|
|
details = gettext('Removed items older than {n} days from trash.').replace('{n}', item.days);
|
2019-02-28 10:09:21 +00:00
|
|
|
}
|
2019-07-25 07:06:58 +00:00
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-03-11 09:38:47 +00:00
|
|
|
} else if (item.obj_type == 'draft') {
|
|
|
|
let fileURL = `${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`;
|
2023-09-13 00:40:50 +00:00
|
|
|
let fileLink = <a href={fileURL} target="_blank" rel="noreferrer">{item.name}</a>;
|
2019-03-11 09:38:47 +00:00
|
|
|
op = gettext('Publish draft');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = fileLink;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
} else if (item.obj_type == 'files') {
|
|
|
|
let fileURL = `${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`;
|
2019-03-21 06:29:09 +00:00
|
|
|
if (item.name.endsWith('(draft).md')) {
|
|
|
|
fileURL = serviceURL + '/drafts/' + item.draft_id + '/';
|
|
|
|
}
|
2019-02-28 10:09:21 +00:00
|
|
|
let fileLink = `<a href=${fileURL} target="_blank">${item.name}</a>`;
|
2019-03-21 06:29:09 +00:00
|
|
|
if (item.name.endsWith('(draft).md') && !item.draft_id) {
|
|
|
|
fileLink = item.name;
|
|
|
|
}
|
2019-02-28 10:09:21 +00:00
|
|
|
let fileCount = item.createdFilesCount - 1;
|
2019-07-25 07:06:58 +00:00
|
|
|
let firstLine = gettext('{file} and {n} other files')
|
|
|
|
.replace('{file}', fileLink)
|
|
|
|
.replace('{n}', fileCount);
|
2019-02-28 10:09:21 +00:00
|
|
|
op = gettext('Created {n} files').replace('{n}', item.createdFilesCount);
|
2019-07-25 07:06:58 +00:00
|
|
|
details = (
|
|
|
|
<Fragment>
|
|
|
|
<p className="m-0 d-inline" dangerouslySetInnerHTML={{__html: firstLine}}></p>
|
2021-09-23 09:26:26 +00:00
|
|
|
{isDesktop && <button type="button" onClick={this.onListCreatedFilesToggle} className="activity-details text-secondary ml-2 border-0 p-0 bg-transparent">{gettext('details')}</button>}
|
2019-07-25 07:06:58 +00:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
} else if (item.obj_type == 'file') {
|
2019-07-25 07:06:58 +00:00
|
|
|
const isDraft = item.name.endsWith('(draft).md');
|
|
|
|
const fileURL = isDraft ? serviceURL + '/drafts/' + item.draft_id + '/' :
|
|
|
|
`${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`;
|
2023-09-13 00:40:50 +00:00
|
|
|
let fileLink = <a href={fileURL} target="_blank" rel="noreferrer">{item.name}</a>;
|
2019-07-25 07:06:58 +00:00
|
|
|
if (isDraft && !item.draft_id) {
|
2019-03-21 06:29:09 +00:00
|
|
|
fileLink = item.name;
|
|
|
|
}
|
2019-07-25 07:06:58 +00:00
|
|
|
switch (item.op_type) {
|
2019-02-28 10:09:21 +00:00
|
|
|
case 'create':
|
2019-07-25 07:06:58 +00:00
|
|
|
op = isDraft ? gettext('Created draft') : gettext('Created file');
|
|
|
|
details = fileLink;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'delete':
|
2019-07-25 07:06:58 +00:00
|
|
|
op = isDraft ? gettext('Deleted draft') : gettext('Deleted file');
|
|
|
|
details = item.name;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'recover':
|
|
|
|
op = gettext('Restored file');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = fileLink;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'rename':
|
|
|
|
op = gettext('Renamed file');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = <span>{item.old_name} => {fileLink}</span>;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'move':
|
2023-09-13 00:40:50 +00:00
|
|
|
// eslint-disable-next-line
|
2019-07-25 07:06:58 +00:00
|
|
|
const filePathLink = <a href={fileURL}>{item.path}</a>;
|
2019-02-28 10:09:21 +00:00
|
|
|
op = gettext('Moved file');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = <span>{item.old_path} => {filePathLink}</span>;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'edit': // update
|
2019-07-25 07:06:58 +00:00
|
|
|
op = isDraft ? gettext('Updated draft') : gettext('Updated file');
|
|
|
|
details = fileLink;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
2018-08-30 07:10:52 +00:00
|
|
|
}
|
2019-02-28 10:09:21 +00:00
|
|
|
} else { // dir
|
|
|
|
let dirURL = siteRoot + 'library/' + item.repo_id + '/' + encodeURIComponent(item.repo_name) + Utils.encodePath(item.path);
|
2023-09-13 00:40:50 +00:00
|
|
|
let dirLink = <a href={dirURL} target="_blank" rel="noreferrer">{item.name}</a>;
|
2019-07-25 07:06:58 +00:00
|
|
|
switch (item.op_type) {
|
2019-02-28 10:09:21 +00:00
|
|
|
case 'create':
|
|
|
|
op = gettext('Created folder');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = dirLink;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'delete':
|
|
|
|
op = gettext('Deleted folder');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = item.name;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'recover':
|
|
|
|
op = gettext('Restored folder');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = dirLink;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'rename':
|
|
|
|
op = gettext('Renamed folder');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = <span>{item.old_name} => {dirLink}</span>;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
|
|
|
case 'move':
|
2023-09-13 00:40:50 +00:00
|
|
|
// eslint-disable-next-line
|
2019-07-25 07:06:58 +00:00
|
|
|
const dirPathLink = <a href={dirURL}>{item.path}</a>;
|
2019-02-28 10:09:21 +00:00
|
|
|
op = gettext('Moved folder');
|
2019-07-25 07:06:58 +00:00
|
|
|
details = <span>{item.old_path} => {dirPathLink}</span>;
|
|
|
|
moreDetails = true;
|
2019-02-28 10:09:21 +00:00
|
|
|
break;
|
2019-01-22 11:52:05 +00:00
|
|
|
}
|
2019-02-28 10:09:21 +00:00
|
|
|
}
|
2019-01-22 11:52:05 +00:00
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
let isShowDate = true;
|
|
|
|
if (index > 0) {
|
|
|
|
let lastEventTime = items[index - 1].time;
|
|
|
|
isShowDate = moment(item.time).isSame(lastEventTime, 'day') ? false : true;
|
|
|
|
}
|
2018-08-30 07:10:52 +00:00
|
|
|
|
|
|
|
return (
|
2019-02-13 03:19:40 +00:00
|
|
|
<Fragment>
|
2019-07-25 07:06:58 +00:00
|
|
|
{isShowDate &&
|
2019-02-28 10:09:21 +00:00
|
|
|
<tr>
|
2019-07-25 07:06:58 +00:00
|
|
|
<td colSpan={isDesktop ? 5 : 3} className="border-top-0">{moment(item.time).format('YYYY-MM-DD')}</td>
|
2019-02-28 10:09:21 +00:00
|
|
|
</tr>
|
|
|
|
}
|
2019-07-25 07:06:58 +00:00
|
|
|
{isDesktop ? (
|
|
|
|
<tr>
|
|
|
|
<td className="text-center">
|
|
|
|
<img src={item.avatar_url} alt="" width="32" height="32" className="avatar" />
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<a href={userProfileURL}>{item.author_name}</a>
|
|
|
|
</td>
|
|
|
|
<td>{op}</td>
|
|
|
|
<td>
|
|
|
|
{details}
|
|
|
|
{moreDetails && <br /> }
|
|
|
|
{moreDetails && smallLibLink}
|
|
|
|
</td>
|
|
|
|
<td className="text-secondary">
|
|
|
|
<time datetime={item.time} is="relative-time" title={moment(item.time).format('llll')}>{moment(item.time).fromNow()}</time>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
) : (
|
|
|
|
<tr>
|
2020-02-13 07:22:53 +00:00
|
|
|
<td className="text-center align-top">
|
2019-07-25 07:06:58 +00:00
|
|
|
<img src={item.avatar_url} alt="" width="32" height="32" className="avatar" />
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<a href={userProfileURL}>{item.author_name}</a>
|
2020-02-13 07:22:53 +00:00
|
|
|
<p className="m-0 text-secondary">{op}</p>
|
|
|
|
{details}
|
2019-07-25 07:06:58 +00:00
|
|
|
</td>
|
|
|
|
<td className="text-right align-top">
|
|
|
|
<span className="text-secondary mobile-activity-time">
|
|
|
|
<time datetime={item.time} is="relative-time" title={moment(item.time).format('llll')}>{moment(item.time).fromNow()}</time>
|
|
|
|
</span>
|
|
|
|
{moreDetails && <br /> }
|
|
|
|
{moreDetails && libLink}
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
)}
|
2019-02-13 03:19:40 +00:00
|
|
|
{this.state.isListCreatedFiles &&
|
|
|
|
<ModalPortal>
|
|
|
|
<ListCreatedFileDialog
|
2019-02-28 10:09:21 +00:00
|
|
|
activity={item}
|
2019-02-13 03:19:40 +00:00
|
|
|
toggleCancel={this.onListCreatedFilesToggle}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
}
|
|
|
|
</Fragment>
|
2018-08-30 07:10:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 10:09:21 +00:00
|
|
|
ActivityItem.propTypes = activityPropTypes;
|
2018-10-16 10:19:51 +00:00
|
|
|
|
2018-08-30 07:10:52 +00:00
|
|
|
class FilesActivities extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
2018-12-28 03:12:24 +00:00
|
|
|
errorMsg: '',
|
|
|
|
isFirstLoading: true,
|
|
|
|
isLoadingMore: false,
|
|
|
|
currentPage: 1,
|
|
|
|
hasMore: true,
|
2018-09-18 02:11:37 +00:00
|
|
|
items: [],
|
2018-08-30 07:10:52 +00:00
|
|
|
};
|
2019-01-08 06:51:13 +00:00
|
|
|
this.avatarSize = 72;
|
2019-01-21 07:38:34 +00:00
|
|
|
this.curPathList = [];
|
|
|
|
this.oldPathList = [];
|
2018-08-30 07:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
2018-12-28 03:12:24 +00:00
|
|
|
let currentPage = this.state.currentPage;
|
2019-01-08 06:51:13 +00:00
|
|
|
seafileAPI.listActivities(currentPage, this.avatarSize).then(res => {
|
2018-12-28 03:12:24 +00:00
|
|
|
// {"events":[...]}
|
2019-03-11 09:38:47 +00:00
|
|
|
let events = this.mergePublishEvents(res.data.events);
|
2019-02-13 03:19:40 +00:00
|
|
|
events = this.mergeFileCreateEvents(events);
|
2018-12-28 03:12:24 +00:00
|
|
|
this.setState({
|
2019-02-13 03:19:40 +00:00
|
|
|
items: events,
|
2018-12-28 03:12:24 +00:00
|
|
|
currentPage: currentPage + 1,
|
|
|
|
isFirstLoading: false,
|
|
|
|
hasMore: true,
|
|
|
|
});
|
2019-02-13 03:19:40 +00:00
|
|
|
if (this.state.items.length < 25) {
|
|
|
|
this.getMore();
|
|
|
|
}
|
2018-12-28 03:12:24 +00:00
|
|
|
}).catch(error => {
|
2019-12-05 07:45:16 +00:00
|
|
|
this.setState({
|
|
|
|
isFirstLoading: false,
|
|
|
|
errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403
|
|
|
|
});
|
2018-08-30 07:10:52 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-03-11 09:38:47 +00:00
|
|
|
mergePublishEvents = (events) => {
|
2023-09-13 00:40:50 +00:00
|
|
|
events.forEach((item) => {
|
2019-03-11 09:38:47 +00:00
|
|
|
if (item.op_type === 'publish') {
|
2019-01-21 07:38:34 +00:00
|
|
|
this.curPathList.push(item.path);
|
|
|
|
this.oldPathList.push(item.old_path);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
let actuallyEvents = [];
|
|
|
|
for (var i = 0; i < events.length; i++) {
|
|
|
|
if (events[i].obj_type === 'file') {
|
|
|
|
if (events[i].op_type === 'delete' && this.oldPathList.includes(events[i].path)) {
|
|
|
|
this.oldPathList.splice(this.oldPathList.indexOf(events[i].path), 1);
|
|
|
|
} else if (events[i].op_type === 'edit' && this.curPathList.includes(events[i].path)) {
|
|
|
|
this.curPathList.splice(this.curPathList.indexOf(events[i].path), 1);
|
|
|
|
} else if (events[i].op_type === 'rename' && this.oldPathList.includes(events[i].old_path)) {
|
|
|
|
this.oldPathList.splice(this.oldPathList.indexOf(events[i].old_path), 1);
|
2019-02-13 03:19:40 +00:00
|
|
|
} else {
|
|
|
|
actuallyEvents.push(events[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
actuallyEvents.push(events[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return actuallyEvents;
|
2023-09-13 00:40:50 +00:00
|
|
|
};
|
2019-02-13 03:19:40 +00:00
|
|
|
|
|
|
|
mergeFileCreateEvents = (events) => {
|
|
|
|
let actuallyEvents = [];
|
|
|
|
let multiFilesActivity = null;
|
|
|
|
for (var i = 0; i < events.length; i++) {
|
|
|
|
let isFulfilCondition = events[i].obj_type === 'file' &&
|
|
|
|
events[i].op_type === 'create' &&
|
|
|
|
events[i + 1] &&
|
|
|
|
events[i + 1].obj_type === 'file' &&
|
|
|
|
events[i + 1].op_type === 'create' &&
|
|
|
|
events[i + 1].repo_name === events[i].repo_name &&
|
|
|
|
events[i + 1].author_email === events[i].author_email;
|
|
|
|
if (multiFilesActivity != null) {
|
|
|
|
multiFilesActivity.createdFilesCount++;
|
|
|
|
multiFilesActivity.createdFilesList.push(events[i]);
|
|
|
|
if (isFulfilCondition) {
|
2019-01-21 07:38:34 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
2019-02-13 03:19:40 +00:00
|
|
|
actuallyEvents.push(multiFilesActivity);
|
|
|
|
multiFilesActivity = null;
|
2019-01-21 07:38:34 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-02-13 03:19:40 +00:00
|
|
|
if (isFulfilCondition) {
|
|
|
|
multiFilesActivity = new Activity(events[i]);
|
|
|
|
multiFilesActivity.obj_type = 'files';
|
|
|
|
multiFilesActivity.createdFilesCount++;
|
2019-02-28 06:34:54 +00:00
|
|
|
multiFilesActivity.createdFilesList.push(events[i]);
|
2019-02-13 03:19:40 +00:00
|
|
|
} else {
|
|
|
|
actuallyEvents.push(events[i]);
|
|
|
|
}
|
2019-01-21 07:38:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return actuallyEvents;
|
2023-09-13 00:40:50 +00:00
|
|
|
};
|
2019-01-21 07:38:34 +00:00
|
|
|
|
2018-08-30 07:10:52 +00:00
|
|
|
getMore() {
|
2018-12-28 03:12:24 +00:00
|
|
|
let currentPage = this.state.currentPage;
|
2019-01-08 06:51:13 +00:00
|
|
|
seafileAPI.listActivities(currentPage, this.avatarSize).then(res => {
|
2018-12-28 03:12:24 +00:00
|
|
|
// {"events":[...]}
|
2019-03-11 09:38:47 +00:00
|
|
|
let events = this.mergePublishEvents(res.data.events);
|
2019-02-13 03:19:40 +00:00
|
|
|
events = this.mergeFileCreateEvents(events);
|
2018-12-28 03:12:24 +00:00
|
|
|
this.setState({
|
|
|
|
isLoadingMore: false,
|
2019-02-13 03:19:40 +00:00
|
|
|
items: [...this.state.items, ...events],
|
2018-12-28 03:12:24 +00:00
|
|
|
currentPage: currentPage + 1,
|
2020-11-02 05:56:35 +00:00
|
|
|
hasMore: res.data.events.length === 0 ? false : true
|
2018-12-28 03:12:24 +00:00
|
|
|
});
|
2019-02-13 03:19:40 +00:00
|
|
|
if (this.state.items.length < 25 && this.state.hasMore) {
|
|
|
|
this.getMore();
|
|
|
|
}
|
2018-12-28 03:12:24 +00:00
|
|
|
}).catch(error => {
|
2019-12-05 07:45:16 +00:00
|
|
|
this.setState({
|
|
|
|
isLoadingMore: false,
|
|
|
|
errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403
|
|
|
|
});
|
2018-09-29 10:32:53 +00:00
|
|
|
});
|
2018-08-30 07:10:52 +00:00
|
|
|
}
|
|
|
|
|
2018-12-28 03:12:24 +00:00
|
|
|
handleScroll = (event) => {
|
2019-01-08 06:51:13 +00:00
|
|
|
if (!this.state.isLoadingMore && this.state.hasMore) {
|
|
|
|
const clientHeight = event.target.clientHeight;
|
|
|
|
const scrollHeight = event.target.scrollHeight;
|
|
|
|
const scrollTop = event.target.scrollTop;
|
|
|
|
const isBottom = (clientHeight + scrollTop + 1 >= scrollHeight);
|
|
|
|
if (isBottom) { // scroll to the bottom
|
|
|
|
this.setState({isLoadingMore: true}, () => {
|
|
|
|
this.getMore();
|
|
|
|
});
|
|
|
|
}
|
2018-08-30 07:10:52 +00:00
|
|
|
}
|
2023-09-13 00:40:50 +00:00
|
|
|
};
|
2018-08-30 07:10:52 +00:00
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
2018-11-26 09:53:18 +00:00
|
|
|
<div className="main-panel-center">
|
|
|
|
<div className="cur-view-container" id="activities">
|
|
|
|
<div className="cur-view-path">
|
|
|
|
<h3 className="sf-heading">{gettext('Activities')}</h3>
|
|
|
|
</div>
|
2019-05-28 07:16:27 +00:00
|
|
|
<div className="cur-view-content d-block" onScroll={this.handleScroll}>
|
2018-12-28 03:12:24 +00:00
|
|
|
{this.state.isFirstLoading && <Loading />}
|
2020-11-02 05:56:35 +00:00
|
|
|
{(!this.state.isFirstLoading && this.state.errorMsg) &&
|
2018-12-28 03:12:24 +00:00
|
|
|
<p className="error text-center">{this.state.errorMsg}</p>
|
|
|
|
}
|
2020-11-02 05:56:35 +00:00
|
|
|
{!this.state.isFirstLoading &&
|
2018-12-28 03:12:24 +00:00
|
|
|
<FileActivitiesContent items={this.state.items} isLoadingMore={this.state.isLoadingMore}/>
|
|
|
|
}
|
2018-11-26 06:00:32 +00:00
|
|
|
</div>
|
2018-08-30 07:10:52 +00:00
|
|
|
</div>
|
2018-11-26 09:53:18 +00:00
|
|
|
</div>
|
2018-08-30 07:10:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default FilesActivities;
|