webui/src/components/common/TableBody.tsx
2026-01-20 21:48:51 +00:00

139 lines
5.3 KiB
TypeScript

import React, { Component } from "react";
import deepFind from "../../utils/deepfind";
import Column from "./columns";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBook, faBookJournalWhills, faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
import { Link } from "react-router-dom";
import ConfirmButton from "./ConfirmButton";
import { Buffer } from 'buffer';
import Button, { ButtonType } from "./Button";
import { DateView } from "./DateView";
export interface AuditParams{
entityName : string,
primaryKey : string
}
export interface TableBodyProps<T>{
data : T[] | undefined;
keyName : string;
columns : Column<T>[];
editPath? : string;
selectedRow? : T;
canEdit? : ( item : T ) => boolean;
canDelete? : ( item : T ) => boolean;
onDelete?: ( item? : T ) => void;
onAuditParams?: ( item : T ) => AuditParams;
onSelectRow? : ( item : T ) => void;
showSecondaryAudit : boolean;
}
class TableBody<T> extends Component<TableBodyProps<T>> {
resolvePath = ( path : string, args : string[]) => {
let modifiedPath = path;
let index : number = 0;
while ( index < args.length )
{
modifiedPath = modifiedPath.replace("{"+index+"}", args[index])
index++;
}
return modifiedPath;
}
renderCell = (item : T, column : Column<T>) => {
const {keyName} = this.props;
if (column.content) return column.content(item);
const foundItem = deepFind(item, column.path || column.key)
let columnContent : JSX.Element;
if (foundItem instanceof Date) {
columnContent = <DateView value={foundItem}/>
}
else if (typeof foundItem === "object"){
columnContent = <></>;
}
else {
columnContent = <>
{foundItem}
</>;
}
const linkPath = column.link;
if (linkPath !== undefined){
const resolvedlinkPath = this.resolvePath( linkPath, [ (item as any)[keyName] ] );
columnContent = <Link to={resolvedlinkPath}>{columnContent}</Link>;
}
return <>
{columnContent}
</>;
};
clickRow = ( value : T ) =>
{
const { onSelectRow } = this.props;
if (onSelectRow !== undefined)
onSelectRow( value );
}
createKey = (item : T, column : Column<T>) => {
const { keyName } = this.props;
return (item as any)[keyName] + '_' + (column.path || column.key);
};
handleAuditParams = ( item : T, primaryOnly : boolean ) => {
const { onAuditParams } = this.props;
if (onAuditParams !== undefined) {
var auditParams = onAuditParams(item);
let json = JSON.stringify(auditParams);
var params = Buffer.from(json).toString('base64') ;
var queryString = "";
if (primaryOnly===false)
queryString += "?primaryOnly=" + primaryOnly;
return "/audit/" + params + queryString;
}
return "";
}
render() {
const { data, keyName, selectedRow, columns, editPath, canEdit, canDelete, onDelete, onAuditParams, showSecondaryAudit } = this.props;
const showDelete:boolean = onDelete != null;
const showEdit:boolean = (editPath != null) && (editPath !== "");
const showAudit:boolean = onAuditParams !== undefined;
return (
<tbody>
{data?.map((item) => {
let classNames = "";
if (selectedRow === item)
{
classNames+="table-primary";
}
return (<tr className={classNames} key={(item as any)[keyName]}>
{columns.map((column) => (
<td key={this.createKey(item, column)} onClick={ () => this.clickRow(item)}>{this.renderCell(item, column)}</td>
))}
{showEdit && <td className="align-middle">{(canEdit === undefined || canEdit(item)) && <Button buttonType={ButtonType.primary} to={this.resolvePath( editPath!, [ (item as any)[keyName] ] )}><FontAwesomeIcon icon={faEdit}/></Button>}</td>}
{showDelete && <td className="align-middle">{(canDelete === undefined || canDelete(item)) && <ConfirmButton buttonType={ButtonType.primary} keyValue={item} onClick={onDelete} confirmMessage={"Press again to delete"} ><FontAwesomeIcon icon={faTrash}/></ConfirmButton>}</td>}
{showAudit && <td className="align-middle"><Link to={this.handleAuditParams(item, true)}><Button buttonType={ButtonType.primary}><FontAwesomeIcon icon={faBook}/></Button></Link></td>}
{showAudit && showSecondaryAudit && <td className="align-middle"><Link to={this.handleAuditParams(item, false)}><Button buttonType={ButtonType.secondary}><FontAwesomeIcon icon={faBookJournalWhills}/></Button></Link></td>}
</tr>)
})}
</tbody>
);
}
}
export default TableBody;