Web: Client: create audit trail table view

This commit is contained in:
Dmitry Sychugov 2022-08-29 13:27:47 +05:00
parent 6311390801
commit 83666c5062
5 changed files with 434 additions and 0 deletions

View File

@ -0,0 +1,44 @@
import React, { useEffect, useRef } from "react";
import TableContainer from "@docspace/components/table-container";
import { inject, observer } from "mobx-react";
import TableRow from "./TableRow";
import TableHeader from "./TableHeader";
import TableBody from "@docspace/components/table-container/TableBody";
import { isMobile } from "react-device-detect";
const Table = ({ auditTrailUsers, sectionWidth, viewAs, setViewAs, theme }) => {
const ref = useRef(null);
useEffect(() => {
if (!sectionWidth) return;
if (sectionWidth < 1025 || isMobile) {
viewAs !== "row" && setViewAs("row");
} else {
viewAs !== "table" && setViewAs("table");
}
}, [sectionWidth]);
return auditTrailUsers && auditTrailUsers.length > 0 ? (
<TableContainer forwardedRef={ref}>
<TableHeader sectionWidth={sectionWidth} containerRef={ref} />
<TableBody>
{auditTrailUsers.map((item) => (
<TableRow theme={theme} key={item.id} item={item} />
))}
</TableBody>
</TableContainer>
) : (
<div></div>
);
};
export default inject(({ auth, setup }) => {
const { security, viewAs, setViewAs } = setup;
const { theme } = auth.settingsStore;
return {
auditTrailUsers: security.auditTrail.users,
theme,
viewAs,
setViewAs,
};
})(observer(Table));

View File

@ -0,0 +1,129 @@
import React from "react";
import TableHeader from "@docspace/components/table-container/TableHeader";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
const TABLE_VERSION = "4";
const TABLE_COLUMNS = `auditTableColumns_ver-${TABLE_VERSION}`;
const COLUMNS_SIZE = `auditColumnsSize_ver-${TABLE_VERSION}`;
class PeopleTableHeader extends React.Component {
constructor(props) {
super(props);
const { t } = props;
const defaultColumns = [
{
key: "User",
title: t("Common:User"),
resizable: true,
enable: true,
default: true,
sortBy: "AZ",
active: true,
minWidth: 180,
},
{
key: "Date",
title: t("Common:Date"),
enable: true,
resizable: true,
onChange: this.onColumnChange,
},
{
key: "Room",
title: t("Common:Room"),
enable: true,
resizable: true,
onChange: this.onColumnChange,
},
{
key: "Action",
title: t("Common:Action"),
enable: true,
resizable: true,
onChange: this.onColumnChange,
},
];
const columns = this.getColumns(defaultColumns);
this.state = { columns };
}
getColumns = (defaultColumns) => {
const storageColumns = localStorage.getItem(
`${TABLE_COLUMNS}=${this.props.userId}`
);
const columns = [];
if (storageColumns) {
const splitColumns = storageColumns.split(",");
for (let col of defaultColumns) {
const column = splitColumns.find((key) => key === col.key);
column ? (col.enable = true) : (col.enable = false);
columns.push(col);
}
return columns;
} else {
return defaultColumns;
}
};
onColumnChange = (key, e) => {
const { columns } = this.state;
const columnIndex = columns.findIndex((c) => c.key === key);
if (columnIndex === -1) return;
columns[columnIndex].enable = !columns[columnIndex].enable;
this.setState({ columns });
const tableColumns = columns.map((c) => c.enable && c.key);
localStorage.setItem(`${TABLE_COLUMNS}=${this.props.userId}`, tableColumns);
};
onIconClick = () => {
const { filter, setIsLoading, fetchPeople } = this.props;
const newFilter = filter.clone();
if (newFilter.sortOrder === "ascending") {
newFilter.sortOrder = "descending";
} else {
newFilter.sortOrder = "ascending";
}
setIsLoading(true);
fetchPeople(newFilter).finally(() => setIsLoading(false));
};
render() {
const { columns } = this.state;
const { containerRef, sectionWidth, userId } = this.props;
return (
<TableHeader
checkboxSize="48px"
containerRef={containerRef}
columns={columns}
columnStorageName={`${COLUMNS_SIZE}=${userId}`}
sectionWidth={sectionWidth}
checkboxMargin="12px"
/>
);
}
}
export default inject(({ auth }) => {
return {
userId: auth.userStore.user.id,
};
})(
withTranslation(["Home", "Common", "Translations"])(
observer(PeopleTableHeader)
)
);

View File

@ -0,0 +1,94 @@
import React from "react";
import { withRouter } from "react-router";
import TableRow from "@docspace/components/table-container/TableRow";
import TableCell from "@docspace/components/table-container/TableCell";
import Text from "@docspace/components/text";
import styled from "styled-components";
import moment from "moment";
const StyledPeopleRow = styled(TableRow)`
.table-container_cell {
height: 46px;
max-height: 46px;
}
.table-container_row-checkbox-wrapper {
padding-left: 4px;
min-width: 46px;
.table-container_row-checkbox {
margin-left: -4px;
padding: 16px 0px 16px 12px;
}
}
.link-with-dropdown-group {
margin-right: 12px;
}
.table-cell_username {
margin-right: 12px;
}
`;
const PeopleTableRow = (props) => {
const { item, contextOptionsProps } = props;
const { email, position } = item;
const DATE_FORMAT = "YYYY-MM-DD LT";
const to = moment(item.date).local();
const dateStr = to.format(DATE_FORMAT);
return (
<StyledPeopleRow key={item.id} {...contextOptionsProps}>
<TableCell>
<Text
type="page"
title={position}
fontSize="12px"
fontWeight={600}
truncate
>
{item.user}
</Text>
</TableCell>
<TableCell>
<Text
type="page"
title={position}
fontSize="12px"
fontWeight={600}
truncate
>
{dateStr}
</Text>
</TableCell>
<TableCell>
<Text
type="page"
title={email}
fontSize="12px"
fontWeight={600}
isTextOverflow
>
{item.room}
</Text>
</TableCell>
<TableCell>
<Text
type="page"
title={email}
fontSize="12px"
fontWeight={600}
isTextOverflow
>
{item.action}
</Text>
</TableCell>
</StyledPeopleRow>
);
};
export default withRouter(PeopleTableRow);

View File

@ -0,0 +1,10 @@
import React, { useEffect, useRef } from "react";
import TableContainer from "./TableContainer";
export const Table = (props) => {
const { sectionWidth } = props;
const ref = useRef(null);
return <TableContainer sectionWidth={sectionWidth} forwardedRef={ref} />;
};

View File

@ -0,0 +1,157 @@
import React, { useEffect, useState } from "react";
import { withRouter } from "react-router";
import { withTranslation } from "react-i18next";
import { setDocumentTitle } from "SRC_DIR/helpers/utils";
import Text from "@docspace/components/text";
import { inject } from "mobx-react";
import styled from "styled-components";
import TextInput from "@docspace/components/text-input";
import Button from "@docspace/components/button";
import { Consumer } from "@docspace/components/utils/context";
import StyledSaveCancelButtons from "@docspace/components/save-cancel-buttons";
import { Table } from "./TableView/TableView";
import AuditRowContainer from "./RowView/AuditRowContainer";
const MainContainer = styled.div`
width: 100%;
.audit-content {
max-width: 700px;
}
.save-cancel {
padding: 0;
position: static;
display: block;
}
.login-subheader {
font-size: 13px;
color: #657077;
}
.latest-text {
font-size: 13px;
padding: 20px 0;
}
.storage-label {
font-weight: 600;
}
.audit-wrapper {
margin-top: 16px;
margin-bottom: 24px;
.table-container_header {
position: absolute;
}
}
`;
const StyledTextInput = styled(TextInput)`
margin-top: 4px;
margin-bottom: 24px;
`;
const AuditTrail = (props) => {
const {
t,
getAuditTrail,
auditTrailUsers,
theme,
viewAs,
setLifetimeAuditSettings,
getLifetimeAuditSettings,
getAuditTrailReport,
} = props;
const [value, setValue] = useState("180");
const inputHandler = (e) => {
setValue(e.target.value);
};
useEffect(() => {
setDocumentTitle(t("AuditTrailNav"));
getAuditTrail();
getLifetimeAuditSettings();
}, []);
return (
<MainContainer>
<div className="audit-content">
<Text fontSize="13px" color="#657077">
{t("AuditSubheader")}
</Text>
<Text className="latest-text">{t("LoginLatestText")} </Text>
<label className="storage-label" htmlFor="storage-period">
{t("StoragePeriod")}
</label>
<StyledTextInput
onChange={inputHandler}
value={value}
size="big"
id="storage-period"
type="text"
/>
<div>
<StyledSaveCancelButtons
saveButtonLabel={t("Common:SaveButton")}
cancelButtonLabel={t("Common:CancelButton")}
className="save-cancel"
showReminder={true}
/>
</div>
<Text className="latest-text">{t("AuditDownloadText")}</Text>
</div>
<div className="audit-wrapper">
<Consumer>
{(context) =>
viewAs === "table" ? (
<>
<Table
theme={theme}
auditTrailUsers={auditTrailUsers}
sectionWidth={context.sectionWidth}
/>
</>
) : (
<>
<AuditRowContainer sectionWidth={context.sectionWidth} />
</>
)
}
</Consumer>
</div>
<Button
primary
isHovered
label="DownloadReport"
size="normal"
onClick={() => getAuditTrailReport()}
/>
</MainContainer>
);
};
export default inject(({ setup, auth }) => {
const {
getAuditTrail,
security,
viewAs,
getLifetimeAuditSettings,
setLifetimeAuditSettings,
getAuditTrailReport,
} = setup;
const { theme } = auth.settingsStore;
return {
getAuditTrail,
auditTrailUsers: security.auditTrail.users,
theme,
viewAs,
getLifetimeAuditSettings,
setLifetimeAuditSettings,
getAuditTrailReport,
};
})(withTranslation("Settings")(withRouter(AuditTrail)));