1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-07-15 16:04:01 +00:00
seahub/frontend/src/components/dialog/file-access-log.js
Michael An 08abceb14b
custom modal header close icon (#7240)
* seahub custom modal header

* add custom modal header

* special modal use custom close
2024-12-24 11:20:40 +08:00

143 lines
4.9 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import dayjs from 'dayjs';
import { Modal, ModalBody } from 'reactstrap';
import { Utils } from '../../utils/utils';
import { gettext, siteRoot } from '../../utils/constants';
import { fileAccessLogAPI } from '../../utils/file-access-log-api';
import toaster from '../toast';
import Loading from '../loading';
import EmptyTip from '../empty-tip';
import SeahubModalHeader from '@/components/common/seahub-modal-header';
import '../../css/file-access-log.css';
dayjs.locale(window.app.config.lang);
const propTypes = {
repoID: PropTypes.string.isRequired,
filePath: PropTypes.string.isRequired,
fileName: PropTypes.string.isRequired,
toggleDialog: PropTypes.func.isRequired
};
class FileAccessLog extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true, // first loading
isLoadingMore: false,
items: [],
page: 1,
perPage: 100,
hasNextPage: false
};
}
componentDidMount() {
this.listFileAccessLog(this.state.page);
}
listFileAccessLog = (page) => {
const { repoID, filePath } = this.props;
const { perPage, items } = this.state;
fileAccessLogAPI.listFileAccessLog(repoID, filePath, page, perPage).then((res) => {
const { data: newItems } = res.data;
this.setState({
isLoading: false,
isLoadingMore: false,
page: page,
hasNextPage: newItems.length < perPage ? false : true,
items: items.concat(newItems)
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
this.setState({
isLoading: false,
isLoadingMore: false,
hasNextPage: false
});
});
};
handleScroll = (event) => {
// isLoadingMore: to avoid repeated request
const { page, hasNextPage, isLoadingMore } = this.state;
if (hasNextPage && !isLoadingMore) {
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.listFileAccessLog(page + 1);
});
}
}
};
render() {
const {
isLoading, hasNextPage, items
} = this.state;
const { fileName } = this.props;
let title = gettext('{placeholder} Access Log');
title = title.replace('{placeholder}', '<span class="op-target text-truncate mx-1">' + Utils.HTMLescape(fileName) + '</span>');
return (
<Modal isOpen={true} toggle={this.props.toggleDialog} className="file-access-log-container">
<SeahubModalHeader toggle={this.props.toggleDialog}>
<span dangerouslySetInnerHTML={{ __html: title }} className="d-flex mw-100"></span>
</SeahubModalHeader>
<ModalBody className="file-access-log-content-container" onScroll={this.handleScroll}>
{isLoading ? <Loading /> : (
<>
{items.length > 0 ? (
<>
<table className="table-hover">
<thead>
<tr>
<th width="25%" className="pl10">{gettext('User')}</th>
<th width="15%">{gettext('Type')}</th>
<th width="40%">{gettext('IP')} / {gettext('Device Name')}</th>
<th width="20%">{gettext('Date')}</th>
</tr>
</thead>
<tbody>
{items.map((item, index) => {
return (
<tr key={index}>
<td className="pl10">
<img src={item.avatar_url} alt='' width="24" className="rounded-circle mr-2" />
{item.email ? <a href={`${siteRoot}profile/${encodeURIComponent(item.email)}/`} target="_blank" rel="noreferrer" className="align-middle">{item.name}</a> : <span>{gettext('Anonymous User')}</span>}
</td>
<td>{item.etype}</td>
<td className="pr-4">
{`${item.ip}${item.device ? '/' + item.device : ''}`}
</td>
<td>{dayjs(item.time).format('YYYY-MM-DD HH:mm:ss')}</td>
</tr>
);
})}
</tbody>
</table>
{hasNextPage && <Loading />}
</>
) : (
<EmptyTip text={gettext('This file has (apparently) not been accessed yet')} />
)}
</>
)}
</ModalBody>
</Modal>
);
}
}
FileAccessLog.propTypes = propTypes;
export default FileAccessLog;