mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 21:00:45 +00:00
CE-1955 Bulk load bugs & usability improvements
This commit is contained in:
@ -21,9 +21,10 @@
|
||||
|
||||
|
||||
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||
import {Checkbox, FormControlLabel, Radio} from "@mui/material";
|
||||
import {Checkbox, FormControlLabel, Radio, Tooltip} from "@mui/material";
|
||||
import Autocomplete from "@mui/material/Autocomplete";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Icon from "@mui/material/Icon";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import RadioGroup from "@mui/material/RadioGroup";
|
||||
@ -45,6 +46,27 @@ interface BulkLoadMappingFieldProps
|
||||
forceParentUpdate?: () => void,
|
||||
}
|
||||
|
||||
const xIconButtonSX =
|
||||
{
|
||||
border: `1px solid ${colors.grayLines.main} !important`,
|
||||
borderRadius: "0.5rem",
|
||||
textTransform: "none",
|
||||
fontSize: "1rem",
|
||||
fontWeight: "400",
|
||||
width: "30px",
|
||||
minWidth: "30px",
|
||||
height: "2rem",
|
||||
minHeight: "2rem",
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
marginRight: "0.5rem",
|
||||
marginTop: "0.5rem",
|
||||
color: colors.error.main,
|
||||
"&:hover": {color: colors.error.main},
|
||||
"&:focus": {color: colors.error.main},
|
||||
"&:focus:not(:hover)": {color: colors.error.main},
|
||||
};
|
||||
|
||||
const qController = Client.getInstance();
|
||||
|
||||
/***************************************************************************
|
||||
@ -212,7 +234,9 @@ export default function BulkLoadFileMappingField({bulkLoadField, isRequired, rem
|
||||
|
||||
<Box display="flex" alignItems="flex-start">
|
||||
{
|
||||
(!isRequired) && <IconButton onClick={() => removeFieldCallback()} sx={{pt: "0.75rem"}}><Icon fontSize="small">remove_circle</Icon></IconButton>
|
||||
(!isRequired) && <Tooltip placement="bottom" title="Remove this field from your mapping.">
|
||||
<Button sx={xIconButtonSX} onClick={() => removeFieldCallback()}><Icon>clear</Icon></Button>
|
||||
</Tooltip>
|
||||
}
|
||||
<Box pt="0.625rem">
|
||||
{bulkLoadField.getQualifiedLabel()}
|
||||
@ -265,7 +289,7 @@ export default function BulkLoadFileMappingField({bulkLoadField, isRequired, rem
|
||||
</Box>
|
||||
{
|
||||
bulkLoadField.error &&
|
||||
<Box fontSize={smallerFontSize} color={colors.error.main} ml="145px">
|
||||
<Box fontSize={smallerFontSize} color={colors.error.main} ml="145px" className="bulkLoadFieldError">
|
||||
{bulkLoadField.error}
|
||||
</Box>
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export default function BulkLoadFileMappingFields({bulkLoadMapping, fileDescript
|
||||
{
|
||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||
|
||||
const [forceRerender, setForceRerender] = useState(0);
|
||||
const [forceHierarchyAutoCompleteRerender, setForceHierarchyAutoCompleteRerender] = useState(0);
|
||||
|
||||
////////////////////////////////////////////
|
||||
// build list of fields that can be added //
|
||||
@ -98,8 +98,9 @@ export default function BulkLoadFileMappingFields({bulkLoadMapping, fileDescript
|
||||
|
||||
setAddFieldsDisableStates(newDisableStates);
|
||||
setTooltips(newTooltips);
|
||||
setForceHierarchyAutoCompleteRerender(forceHierarchyAutoCompleteRerender + 1);
|
||||
|
||||
}, [bulkLoadMapping]);
|
||||
}, [bulkLoadMapping, bulkLoadMapping.layout]);
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
@ -140,9 +141,6 @@ export default function BulkLoadFileMappingFields({bulkLoadMapping, fileDescript
|
||||
***************************************************************************/
|
||||
function removeField(bulkLoadField: BulkLoadField)
|
||||
{
|
||||
// addFieldsToggleStates[bulkLoadField.getQualifiedName()] = false;
|
||||
// setAddFieldsToggleStates(Object.assign({}, addFieldsToggleStates));
|
||||
|
||||
addFieldsDisableStates[bulkLoadField.getQualifiedName()] = false;
|
||||
setAddFieldsDisableStates(Object.assign({}, addFieldsDisableStates));
|
||||
|
||||
@ -160,7 +158,7 @@ export default function BulkLoadFileMappingFields({bulkLoadMapping, fileDescript
|
||||
bulkLoadMapping.removeField(bulkLoadField);
|
||||
forceUpdate();
|
||||
forceParentUpdate();
|
||||
setForceRerender(forceRerender + 1);
|
||||
setForceHierarchyAutoCompleteRerender(forceHierarchyAutoCompleteRerender + 1);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
@ -297,7 +295,7 @@ export default function BulkLoadFileMappingFields({bulkLoadMapping, fileDescript
|
||||
isModeSelectOne
|
||||
keepOpenAfterSelectOne
|
||||
handleSelectedOption={handleAddField}
|
||||
forceRerender={forceRerender}
|
||||
forceRerender={forceHierarchyAutoCompleteRerender}
|
||||
disabledStates={addFieldsDisableStates}
|
||||
tooltips={tooltips}
|
||||
/>
|
||||
|
@ -26,10 +26,12 @@ import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstan
|
||||
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
|
||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {Badge, Icon} from "@mui/material";
|
||||
import Autocomplete from "@mui/material/Autocomplete";
|
||||
import Box from "@mui/material/Box";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Tooltip from "@mui/material/Tooltip/Tooltip";
|
||||
import {useFormikContext} from "formik";
|
||||
import {DynamicFormFieldLabel} from "qqq/components/forms/DynamicForm";
|
||||
import QDynamicFormField from "qqq/components/forms/DynamicFormField";
|
||||
@ -126,6 +128,14 @@ const BulkLoadFileMappingForm = forwardRef(({processValues, tableMetaData, metaD
|
||||
}
|
||||
setFieldErrors(fieldErrors);
|
||||
|
||||
if(haveProfileErrors)
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
document.querySelector(".bulkLoadFieldError")?.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
|
||||
}, 250);
|
||||
}
|
||||
|
||||
return {maySubmit: !haveProfileErrors && !haveLocalErrors, values};
|
||||
}
|
||||
};
|
||||
@ -224,7 +234,11 @@ const BulkLoadFileMappingForm = forwardRef(({processValues, tableMetaData, metaD
|
||||
<BulkLoadFileMappingFields
|
||||
bulkLoadMapping={bulkLoadMapping}
|
||||
fileDescription={fileDescription}
|
||||
forceParentUpdate={() => forceUpdate()}
|
||||
forceParentUpdate={() =>
|
||||
{
|
||||
setRerenderHeader(rerenderHeader + 1);
|
||||
forceUpdate();
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@ -293,7 +307,7 @@ function BulkLoadMappingHeader({fileDescription, fileName, bulkLoadMapping, fiel
|
||||
***************************************************************************/
|
||||
function layoutChanged(event: any, newValue: any)
|
||||
{
|
||||
bulkLoadMapping.layout = newValue ? newValue.id : null;
|
||||
bulkLoadMapping.switchLayout(newValue ? newValue.id : null);
|
||||
fieldErrors.layout = null;
|
||||
forceParentUpdate();
|
||||
}
|
||||
@ -322,7 +336,7 @@ function BulkLoadMappingHeader({fileDescription, fileName, bulkLoadMapping, fiel
|
||||
<h5>File Details</h5>
|
||||
<Box ml="1rem">
|
||||
<ProcessViewForm fields={viewFields} values={viewValues} columns={2} />
|
||||
<BulkLoadMappingFilePreview fileDescription={fileDescription} />
|
||||
<BulkLoadMappingFilePreview fileDescription={fileDescription} bulkLoadMapping={bulkLoadMapping} />
|
||||
<Grid container pt="1rem">
|
||||
<Grid item xs={12} md={6}>
|
||||
<DynamicFormFieldLabel name={hasHeaderRowFormField.name} label={`${hasHeaderRowFormField.label} *`} />
|
||||
@ -347,6 +361,7 @@ function BulkLoadMappingHeader({fileDescription, fileName, bulkLoadMapping, fiel
|
||||
getOptionLabel={(option) => typeof (option) == "string" ? option : (option?.label ?? "")}
|
||||
isOptionEqualToValue={(option, value) => option == null && value == null || option.id == value.id}
|
||||
renderOption={(props, option, state) => (<li {...props}>{option?.label ?? ""}</li>)}
|
||||
disableClearable
|
||||
sx={{"& .MuiOutlinedInput-root": {padding: "0"}}}
|
||||
/>
|
||||
{
|
||||
@ -366,13 +381,14 @@ function BulkLoadMappingHeader({fileDescription, fileName, bulkLoadMapping, fiel
|
||||
|
||||
interface BulkLoadMappingFilePreviewProps
|
||||
{
|
||||
fileDescription: FileDescription;
|
||||
fileDescription: FileDescription,
|
||||
bulkLoadMapping?: BulkLoadMapping
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** private subcomponent - the file-preview section of the bulk load file mapping screen.
|
||||
***************************************************************************/
|
||||
function BulkLoadMappingFilePreview({fileDescription}: BulkLoadMappingFilePreviewProps): JSX.Element
|
||||
function BulkLoadMappingFilePreview({fileDescription, bulkLoadMapping}: BulkLoadMappingFilePreviewProps): JSX.Element
|
||||
{
|
||||
const rows: number[] = [];
|
||||
for (let i = 0; i < fileDescription.bodyValuesPreview[0].length; i++)
|
||||
@ -380,25 +396,135 @@ function BulkLoadMappingFilePreview({fileDescription}: BulkLoadMappingFilePrevie
|
||||
rows.push(i);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
function getValue(i: number, j: number)
|
||||
{
|
||||
const value = fileDescription.bodyValuesPreview[j][i];
|
||||
if (value == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// this was useful at one point in time when we had an object coming back for xlsx files with many different data types //
|
||||
// we'd see a .string attribute, which would have the value we'd want to show. not using it now, but keep in case //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// @ts-ignore
|
||||
if (value && value.string)
|
||||
{
|
||||
// @ts-ignore
|
||||
return (value.string);
|
||||
}
|
||||
return `${value}`;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
function getHeaderColor(count: number): string
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
return "blue";
|
||||
}
|
||||
|
||||
return "black";
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
function getCursor(count: number): string
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
return "pointer";
|
||||
}
|
||||
|
||||
return "default";
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
function getColumnTooltip(fields: BulkLoadField[])
|
||||
{
|
||||
return (<Box>
|
||||
This column is mapped to the field{fields.length == 1 ? "" : "s"}:
|
||||
<ul style={{marginLeft: "1rem"}}>
|
||||
{fields.map((field, i) => <li key={i}>{field.getQualifiedLabel()}</li>)}
|
||||
</ul>
|
||||
</Box>);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{"& table, & td": {border: "1px solid black", borderCollapse: "collapse", padding: "0 0.25rem", fontSize: "0.875rem", whiteSpace: "nowrap"}}}>
|
||||
<Box sx={{width: "100%", overflow: "auto"}}>
|
||||
<table cellSpacing="0" width="100%">
|
||||
<thead>
|
||||
<tr style={{backgroundColor: "#d3d3d3"}}>
|
||||
<tr style={{backgroundColor: "#d3d3d3", height: "1.75rem"}}>
|
||||
<td></td>
|
||||
{fileDescription.headerLetters.map((letter) => <td key={letter} style={{textAlign: "center"}}>{letter}</td>)}
|
||||
{fileDescription.headerLetters.map((letter, index) =>
|
||||
{
|
||||
const fields = bulkLoadMapping.getFieldsForColumnIndex(index);
|
||||
const count = fields.length;
|
||||
return (<td key={letter} style={{textAlign: "center", color: getHeaderColor(count), cursor: getCursor(count)}}>
|
||||
<>
|
||||
{
|
||||
count > 0 &&
|
||||
<Tooltip title={getColumnTooltip(fields)} placement="top" enterDelay={500}>
|
||||
<Box>
|
||||
{letter}
|
||||
<Badge badgeContent={count} variant={"standard"} color="secondary" sx={{marginTop: ".75rem"}}><Icon></Icon></Badge>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
}
|
||||
{
|
||||
count == 0 && <Box>{letter}</Box>
|
||||
}
|
||||
</>
|
||||
</td>);
|
||||
})}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={{backgroundColor: "#d3d3d3", textAlign: "center"}}>1</td>
|
||||
{fileDescription.headerValues.map((value) => <td key={value} style={{backgroundColor: fileDescription.hasHeaderRow ? "#ebebeb" : ""}}>{value}</td>)}
|
||||
|
||||
{fileDescription.headerValues.map((value, index) =>
|
||||
{
|
||||
const fields = bulkLoadMapping.getFieldsForColumnIndex(index);
|
||||
const count = fields.length;
|
||||
const tdStyle = {color: getHeaderColor(count), cursor: getCursor(count), backgroundColor: ""};
|
||||
|
||||
if(fileDescription.hasHeaderRow)
|
||||
{
|
||||
tdStyle.backgroundColor = "#ebebeb";
|
||||
|
||||
if(count > 0)
|
||||
{
|
||||
return <td key={value} style={tdStyle}>
|
||||
<Tooltip title={getColumnTooltip(fields)} placement="top" enterDelay={500}><Box>{value}</Box></Tooltip>
|
||||
</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
return <td key={value} style={tdStyle}>{value}</td>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return <td key={value} style={tdStyle}>{value}</td>
|
||||
}
|
||||
}
|
||||
)}
|
||||
</tr>
|
||||
{rows.map((i) => (
|
||||
<tr key={i}>
|
||||
<td style={{backgroundColor: "#d3d3d3", textAlign: "center"}}>{i + 2}</td>
|
||||
{fileDescription.headerLetters.map((letter, j) => <td key={j}>{fileDescription.bodyValuesPreview[j][i]}</td>)}
|
||||
{fileDescription.headerLetters.map((letter, j) => <td key={j}>{getValue(i, j)}</td>)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
|
||||
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
|
||||
export type ValueType = "defaultValue" | "column";
|
||||
@ -422,18 +423,23 @@ export class BulkLoadMapping
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
///////////////////////////////////////////////////////////
|
||||
// count how many copies of this field there are already //
|
||||
///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////
|
||||
// find the max index for this field already //
|
||||
///////////////////////////////////////////////
|
||||
let maxIndex = -1;
|
||||
for (let existingField of [...this.requiredFields, ...this.additionalFields])
|
||||
{
|
||||
if (existingField.getQualifiedName() == bulkLoadField.getQualifiedName())
|
||||
{
|
||||
index++;
|
||||
const thisIndex = existingField.wideLayoutIndexPath[0]
|
||||
if (thisIndex != null && thisIndex != undefined && thisIndex > maxIndex)
|
||||
{
|
||||
maxIndex = thisIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
index = maxIndex + 1;
|
||||
}
|
||||
|
||||
const cloneField = BulkLoadField.clone(bulkLoadField);
|
||||
cloneField.wideLayoutIndexPath = [index];
|
||||
@ -455,7 +461,7 @@ export class BulkLoadMapping
|
||||
const newAdditionalFields: BulkLoadField[] = [];
|
||||
for (let bulkLoadField of this.additionalFields)
|
||||
{
|
||||
if (bulkLoadField.getQualifiedName() != toRemove.getQualifiedName())
|
||||
if (bulkLoadField.getQualifiedNameWithWideSuffix() != toRemove.getQualifiedNameWithWideSuffix())
|
||||
{
|
||||
newAdditionalFields.push(bulkLoadField);
|
||||
}
|
||||
@ -463,6 +469,107 @@ export class BulkLoadMapping
|
||||
|
||||
this.additionalFields = newAdditionalFields;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public switchLayout(newLayout: string): void
|
||||
{
|
||||
const newAdditionalFields: BulkLoadField[] = [];
|
||||
let anyChanges = false;
|
||||
|
||||
if ("WIDE" != newLayout)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if going to a layout other than WIDE, make sure there aren't any fields with a wideLayoutIndexPath //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const namesWhereOneWideLayoutIndexHasBeenFound: { [name: string]: boolean } = {};
|
||||
for (let existingField of this.additionalFields)
|
||||
{
|
||||
if (existingField.wideLayoutIndexPath.length > 0)
|
||||
{
|
||||
const name = existingField.getQualifiedName();
|
||||
if (namesWhereOneWideLayoutIndexHasBeenFound[name])
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// in this case, we're on like the 2nd or 3rd instance of, say, Line Item: SKU - so - just discard it. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
anyChanges = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// else, this is the 1st instance of, say, Line Item: SKU - so mark that we've found it - and keep this field //
|
||||
// (that is, put it in the new array), but with no index path //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
namesWhereOneWideLayoutIndexHasBeenFound[name] = true;
|
||||
const newField = BulkLoadField.clone(existingField);
|
||||
newField.wideLayoutIndexPath = [];
|
||||
newAdditionalFields.push(newField)
|
||||
anyChanges = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// else, non-wide-path fields, just get added as-is //
|
||||
//////////////////////////////////////////////////////
|
||||
newAdditionalFields.push(existingField)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if going to WIDE layout, then any field from a child table needs a wide-layout-index-path //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
for (let existingField of this.additionalFields)
|
||||
{
|
||||
if (existingField.tableStructure.isMain)
|
||||
{
|
||||
////////////////////////////////////////////
|
||||
// fields from main table come over as-is //
|
||||
////////////////////////////////////////////
|
||||
newAdditionalFields.push(existingField)
|
||||
}
|
||||
else
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// fields from child tables get a wideLayoutIndexPath (and we're assuming just 1 for each) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const newField = BulkLoadField.clone(existingField);
|
||||
newField.wideLayoutIndexPath = [0];
|
||||
newAdditionalFields.push(newField)
|
||||
anyChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (anyChanges)
|
||||
{
|
||||
this.additionalFields = newAdditionalFields;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public getFieldsForColumnIndex(i: number): BulkLoadField[]
|
||||
{
|
||||
const rs: BulkLoadField[] = [];
|
||||
|
||||
for (let field of [...this.requiredFields, ...this.additionalFields])
|
||||
{
|
||||
if(field.valueType == "column" && field.columnIndex == i)
|
||||
{
|
||||
rs.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -517,21 +624,85 @@ export class FileDescription
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public getPreviewValues(columnIndex: number): string[]
|
||||
public getPreviewValues(columnIndex: number, fieldType?: QFieldType): string[]
|
||||
{
|
||||
if (columnIndex == undefined)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (this.hasHeaderRow)
|
||||
function getTypedValue(value: any): string
|
||||
{
|
||||
return (this.bodyValuesPreview[columnIndex]);
|
||||
}
|
||||
else
|
||||
if(value == null)
|
||||
{
|
||||
return ([this.headerValues[columnIndex], ...this.bodyValuesPreview[columnIndex]]);
|
||||
return "";
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// this was useful at one point in time when we had an object coming back for xlsx files with many different data types //
|
||||
// we'd see a .string attribute, which would have the value we'd want to show. not using it now, but keep in case //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if (value && value.string)
|
||||
{
|
||||
switch (fieldType)
|
||||
{
|
||||
case QFieldType.BOOLEAN:
|
||||
{
|
||||
return value.bool;
|
||||
}
|
||||
|
||||
case QFieldType.STRING:
|
||||
case QFieldType.TEXT:
|
||||
case QFieldType.HTML:
|
||||
case QFieldType.PASSWORD:
|
||||
{
|
||||
return value.string;
|
||||
}
|
||||
|
||||
case QFieldType.INTEGER:
|
||||
case QFieldType.LONG:
|
||||
{
|
||||
return value.integer;
|
||||
}
|
||||
case QFieldType.DECIMAL:
|
||||
{
|
||||
return value.decimal;
|
||||
}
|
||||
case QFieldType.DATE:
|
||||
{
|
||||
return value.date;
|
||||
}
|
||||
case QFieldType.TIME:
|
||||
{
|
||||
return value.time;
|
||||
}
|
||||
case QFieldType.DATE_TIME:
|
||||
{
|
||||
return value.dateTime;
|
||||
}
|
||||
case QFieldType.BLOB:
|
||||
return ""; // !!
|
||||
}
|
||||
}
|
||||
|
||||
return (`${value}`);
|
||||
}
|
||||
|
||||
const valueArray: string[] = [];
|
||||
|
||||
if (!this.hasHeaderRow)
|
||||
{
|
||||
const typedValue = getTypedValue(this.headerValues[columnIndex])
|
||||
valueArray.push(typedValue == null ? "" : `${typedValue}`);
|
||||
}
|
||||
|
||||
for (let value of this.bodyValuesPreview[columnIndex])
|
||||
{
|
||||
const typedValue = getTypedValue(value)
|
||||
valueArray.push(typedValue == null ? "" : `${typedValue}`);
|
||||
}
|
||||
|
||||
return (valueArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user