Files
qqq-frontend-material-dashb…/src/qqq/models/processes/ProcessSummaryLine.tsx

246 lines
9.1 KiB
TypeScript

/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
import {ListItem} from "@mui/material";
import Box from "@mui/material/Box";
import Icon from "@mui/material/Icon";
import IconButton from "@mui/material/IconButton";
import ListItemText from "@mui/material/ListItemText";
import Tooltip from "@mui/material/Tooltip";
import React from "react";
import {Link} from "react-router-dom";
import ValueUtils from "qqq/utils/qqq/ValueUtils";
/*******************************************************************************
** Entity that corresponds to qqq backend's ProcessSummaryLine - with methods
** to help display properly in a process review screen.
*******************************************************************************/
export class ProcessSummaryLine
{
status: "OK" | "INFO" | "WARNING" | "ERROR";
count: number;
message: string;
primaryKeys: any[];
tableName: string;
recordId: any;
filter: any;
linkPreText: string;
linkText: string;
linkPostText: string;
bulletsOfText: any[];
constructor(processSummaryLine: any)
{
this.status = processSummaryLine.status;
this.count = processSummaryLine.count;
this.message = processSummaryLine.message;
this.primaryKeys = processSummaryLine.primaryKeys;
this.tableName = processSummaryLine.tableName;
this.recordId = processSummaryLine.recordId;
this.linkPreText = processSummaryLine.linkPreText;
this.linkText = processSummaryLine.linkText;
this.linkPostText = processSummaryLine.linkPostText;
this.bulletsOfText = processSummaryLine.bulletsOfText;
this.filter = processSummaryLine.filter;
}
getProcessSummaryListItem(i: number, table: QTableMetaData, qInstance: QInstance, isResultScreen: boolean = false): JSX.Element
{
if (this.tableName != undefined && (this.recordId != undefined || this.filter != undefined))
{
return (this.getProcessSummaryListItemForTableRecordOrFilterLink(i, table, qInstance, isResultScreen));
}
return (this.getProcessSummaryListItemForCountAndMessage(i, table, qInstance, isResultScreen));
}
private getProcessSummaryListItemForTableRecordOrFilterLink(i: number, table: QTableMetaData, qInstance: QInstance, isResultScreen: boolean = false): JSX.Element
{
const tablePath = qInstance.getTablePathByName(this.tableName);
return (
<ListItem key={i} sx={{pl: 4, my: 2}}>
<Box display="flex" alignItems="top">
<Icon fontSize="medium" sx={{mr: 1}} color={this.getColor()}>{this.getIcon(isResultScreen)}</Icon>
<ListItemText primaryTypographyProps={{fontSize: 16}}>
{this.linkPreText ?? ""}
{
this.recordId
? <Link to={`${tablePath}/${this.recordId}`}>{this.linkText}</Link>
: <Link to={`${tablePath}?filter=${JSON.stringify(this.filter)}`}>{this.linkText}</Link>
}
{this.linkPostText ?? ""}
</ListItemText>
</Box>
</ListItem>
);
}
private getProcessSummaryListItemForCountAndMessage(i: number, table: QTableMetaData, qInstance: QInstance, isResultScreen: boolean = false): JSX.Element
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// split up the message into words - then we'll display the last word by itself with a non-breaking space, no-wrap-glued to the button. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const messageWords = this.message ? this.message.split(" ") : [];
const lastWord = messageWords.length > 1 ? messageWords[messageWords.length - 1] : "";
if (messageWords.length > 1)
{
messageWords.splice(messageWords.length - 1, 1);
}
//////////////////////////////////////////////////////////////////////////////////////////////
// try to get a link to the records - but note, it may come back null for various reasons - //
// if it's null, then don't output a link tag. //
//////////////////////////////////////////////////////////////////////////////////////////////
const linkToRecords = this.getLinkToRecords(table, qInstance);
let linkTag = null;
if(linkToRecords)
{
linkTag = <Link target="_blank" to={linkToRecords}>
<Tooltip title="See these records in a new tab" sx={{py: 0}}>
<IconButton sx={{py: 0}}><Icon fontSize="small">open_in_new</Icon></IconButton>
</Tooltip>
</Link>
}
return (
<ListItem key={i} sx={{pl: 4, my: 2}}>
<Box display="flex" alignItems="top">
<Icon fontSize="medium" sx={{mr: 1}} color={this.getColor()}>{this.getIcon(isResultScreen)}</Icon>
<ListItemText primaryTypographyProps={{fontSize: 16}}>
{/* work hard to prevent the icon from falling down to the next line by itself... */}
{`${ValueUtils.getFormattedNumber(this.count)} ${messageWords.join(" ")} `}
{
(linkTag) ? (
<span style={{whiteSpace: "nowrap"}}>
{lastWord}&nbsp;{linkTag}
</span>
) : <span>{lastWord}</span>
}
{
this.bulletsOfText && <ul style={{marginLeft: "2rem"}}>
{
this.bulletsOfText.map((bullet, index) => <li key={index}>{bullet}</li>)
}
</ul>
}
</ListItemText>
</Box>
</ListItem>
);
}
private getColor(): "success" | "info" | "warning" | "error" | "secondary"
{
if (this.status === "OK")
{
return "success";
}
else if (this.status === "INFO")
{
return "info";
}
else if (this.status === "WARNING")
{
return "warning";
}
else if (this.status === "ERROR")
{
return "error";
}
else
{
return "secondary";
}
}
private getIcon(isResultScreen: boolean): string
{
if (this.status === "OK")
{
return isResultScreen ? "check" : "arrow_forward";
}
else if (this.status === "INFO")
{
return "info";
}
else if (this.status === "WARNING")
{
return "warning_amber";
}
else if (this.status === "ERROR")
{
return "report";
}
return "";
}
private getLinkToRecords(table: QTableMetaData, qInstance: QInstance): string | null
{
if(!table)
{
console.log("No table, so not returning a link to records");
return (null);
}
if(!table.primaryKeyField)
{
console.log("No table.primaryKeyField, so not returning a link to records");
return (null);
}
const tablePath = qInstance.getTablePath(table);
if(!tablePath)
{
console.log("No tablePath, so not returning a link to records");
return (null);
}
if(!this.primaryKeys)
{
console.log("No primaryKeys, so not returning a link to records");
return (null);
}
const filter = new QQueryFilter([new QFilterCriteria(table.primaryKeyField, QCriteriaOperator.IN, this.primaryKeys)]);
const path = `${tablePath}?filter=${JSON.stringify(filter)}`;
if(path.length > 2048)
{
console.log(`Path is too long [${path.length}], so not returning a link to records.`);
return (null);
}
return (path);
}
}