in frontend/apps/quantgrid/src/app/context/ViewportContext/GridBuilder.ts [387:723]
public buildGridTableData(tableData: TableData, zIndex: number): GridData {
const data: GridData = {};
const { table, diff } = tableData;
const { tableName } = table;
const isTableHorizontal = table.getIsTableDirectionHorizontal();
const tableDimensions = this.getTableDimensions(
tableName,
table.getIsTableDirectionHorizontal()
);
const { startCol: tableStartCol, startRow: tableStartRow } =
tableDimensions;
const totalSize = table.getTotalSize();
const allDataMainDirectionStart = isTableHorizontal
? tableStartCol + table.getTableFieldsHeaderHeight() + totalSize
: tableStartRow +
table.getTableNameHeaderHeight() +
table.getTableFieldsHeaderHeight() +
totalSize;
const allDataSecondaryDirectionStart = isTableHorizontal
? tableStartRow + table.getTableNameHeaderHeight()
: tableStartCol;
const buildChunk = (chunk: ColumnChunk, chunkIndex: number) => {
let minDirectionIndex = Number.MAX_SAFE_INTEGER;
let maxDirectionIndex = Number.MIN_SAFE_INTEGER;
const cachedOverrideValues: Record<number, CachedOverrideRow> = {};
// Add cells that have data in chunks
for (const chunkKey of Object.keys(chunk)) {
if (chunkKey === dynamicFieldName) {
continue;
}
const field = table.fields.find((f) => f.key.fieldName === chunkKey);
const fieldIndex = table.fields
.filter((f) => f.key.fieldName !== dynamicFieldName)
.findIndex((f) => f.key.fieldName === chunkKey);
const dataFieldSecondaryDirectionStart = table.fields
.filter((f) => f.key.fieldName !== dynamicFieldName)
.map((field) => (isTableHorizontal ? 1 : field.getSize()))
.slice(0, fieldIndex)
.reduce((acc, curr) => acc + curr, allDataSecondaryDirectionStart);
const chunkData = chunk[chunkKey];
if (fieldIndex === -1 || !field) continue;
const accChunkOffset = chunkIndex * chunkSize;
for (
let innerChunkDataIndex = 0;
innerChunkDataIndex < chunkData.length;
innerChunkDataIndex++
) {
const resultedChunkDataIndex = innerChunkDataIndex + accChunkOffset;
const dataDirectionIndex =
innerChunkDataIndex + accChunkOffset + allDataMainDirectionStart;
minDirectionIndex = Math.min(minDirectionIndex, dataDirectionIndex);
maxDirectionIndex = Math.max(maxDirectionIndex, dataDirectionIndex);
const tableDirectionData: Record<string, string> = {};
Object.keys(chunk).forEach((fieldName) => {
tableDirectionData[fieldName] =
chunk[fieldName][innerChunkDataIndex];
});
const referenceTableName =
tableData.columnReferenceTableNames[chunkKey];
const type = tableData.types[chunkKey];
const fieldName = chunkKey;
const expression = field?.expressionMetadata?.text || '';
const isPeriodSeries = type === ColumnDataType.PERIOD_SERIES;
const isNested = tableData.nestedColumnNames.has(chunkKey);
const isKey = field?.isKey;
const isDim = field?.isDim;
const isDynamic = field?.isDynamic;
const note = field?.note?.text || '';
const { sort, isFiltered, numericFilter, isFieldUsedInSort } =
this.getApplyBlockGridParams(tableData, table, chunkKey);
const fieldSize = isTableHorizontal ? 1 : field.getSize();
const viewportErrorMessage = tableData?.fieldErrors[fieldName];
const fieldErrorMessage = getFieldErrors(
this.viewGridData.getParsingErrors(),
this.viewGridData.getCompilationErrors(),
viewportErrorMessage,
tableName,
fieldName
);
const isRightAligned = this.isValueRightAligned(isNested, type);
let overrideValue: OverrideValue = null;
let overrideIndex = null;
const {
overrideRow,
overrideIndex: index,
overrideSectionIndex,
} = getOverrideRow(
table,
chunkKey,
resultedChunkDataIndex,
tableDirectionData,
cachedOverrideValues
);
let isOverrideChanged = false;
if (overrideRow) {
overrideValue = overrideRow[fieldName];
overrideIndex = index;
isOverrideChanged =
!!overrideValue &&
!!diff?.overrides?.some(
(diffOverrideRow) =>
overrideValue && diffOverrideRow[fieldName] === overrideValue
);
}
const overrideErrorMessage =
overrideSectionIndex !== null &&
overrideSectionIndex !== undefined &&
getOverrideErrors(
this.viewGridData.getParsingErrors(),
this.viewGridData.getCompilationErrors(),
tableName,
fieldName,
overrideSectionIndex + 1
);
const dataIndex = resultedChunkDataIndex;
for (
let fieldInnerIndex = 0;
fieldInnerIndex < fieldSize;
fieldInnerIndex++
) {
const col = isTableHorizontal
? dataDirectionIndex
: dataFieldSecondaryDirectionStart + fieldInnerIndex;
const row = isTableHorizontal
? dataFieldSecondaryDirectionStart
: dataDirectionIndex;
const value = chunkData[innerChunkDataIndex];
const fieldStartCol = isTableHorizontal
? col
: dataFieldSecondaryDirectionStart;
const fieldEndCol = isTableHorizontal
? col
: dataFieldSecondaryDirectionStart + fieldSize - 1;
const finalValue =
fieldStartCol === col ||
[ColumnDataType.DOUBLE, ColumnDataType.INTEGER].includes(type)
? value
: '';
GridBuilder.setSafeDataCell(data, row, col, {
table: {
...tableDimensions,
tableName,
isTableNameHeaderHidden: table.getIsTableHeaderHidden(),
isTableFieldsHeaderHidden: table.getIsTableFieldsHidden(),
hasKeys: table.hasKeys(),
isTableHorizontal,
totalSize,
isManual: table.isManual(),
isNewAdded: !!diff?.table,
},
field: {
fieldName,
note,
expression,
isPeriodSeries,
isNested,
isKey,
isDim,
isDynamic,
isFiltered,
numericFilter,
type,
referenceTableName,
sort,
isFieldUsedInSort,
hasError: !!fieldErrorMessage,
errorMessage: fieldErrorMessage,
isChanged: !!diff?.fields.includes(fieldName),
},
isOverride: !!overrideValue,
isOverrideChanged,
overrideValue: overrideValue,
overrideIndex: overrideIndex !== null ? overrideIndex : undefined,
value: finalValue,
isUrl: isValidUrl(finalValue),
row,
col,
dataIndex,
isRightAligned,
startCol: fieldStartCol,
endCol: fieldEndCol,
zIndex,
isFieldHeader: false,
isTableHeader: false,
hasError: !!overrideErrorMessage,
errorMessage: overrideErrorMessage || undefined,
});
}
}
}
// TODO: Possible redraw problem
// Add cells that have no data in chunks
const noDataFieldNames = table.fields.filter(
(f) => !chunk[f.key.fieldName] && f.key.fieldName !== dynamicFieldName
);
for (const field of noDataFieldNames) {
const dataName = field.key.fieldName;
const noDynamicFields = table.fields.filter(
(f) => f.key.fieldName !== dynamicFieldName
);
const fieldIndex = noDynamicFields.findIndex(
(f) => f.key.fieldName === dataName
);
const dataFieldSecondaryDirectionStart = noDynamicFields
.filter((f) => f.key.fieldName !== dynamicFieldName)
.map((field) => (isTableHorizontal ? 1 : field.getSize()))
.slice(0, fieldIndex)
.reduce((acc, curr) => acc + curr, allDataSecondaryDirectionStart);
const type = tableData.types[dataName];
const { sort, isFiltered, numericFilter, isFieldUsedInSort } =
this.getApplyBlockGridParams(tableData, table, dataName);
const fieldSize = isTableHorizontal ? 1 : field.getSize();
const viewportErrorMessage = tableData?.fieldErrors[dataName];
const fieldErrorMessage = getFieldErrors(
this.viewGridData.getParsingErrors(),
this.viewGridData.getCompilationErrors(),
viewportErrorMessage,
tableName,
dataName
);
const referenceTableName =
tableData.columnReferenceTableNames[dataName];
for (
let directionIndex = minDirectionIndex;
directionIndex <= maxDirectionIndex;
directionIndex++
) {
for (
let fieldInnerIndex = 0;
fieldInnerIndex < field.getSize();
fieldInnerIndex++
) {
const col = isTableHorizontal
? directionIndex
: dataFieldSecondaryDirectionStart + fieldInnerIndex;
const row = isTableHorizontal
? dataFieldSecondaryDirectionStart
: directionIndex;
const fieldStartCol = isTableHorizontal
? col
: dataFieldSecondaryDirectionStart;
const fieldEndCol = isTableHorizontal
? col
: dataFieldSecondaryDirectionStart + fieldSize - 1;
GridBuilder.setSafeDataCell(data, row, col, {
table: {
...tableDimensions,
tableName,
isTableNameHeaderHidden: table.getIsTableHeaderHidden(),
isTableFieldsHeaderHidden: table.getIsTableFieldsHidden(),
hasKeys: table.hasKeys(),
isTableHorizontal,
totalSize,
isManual: table.isManual(),
isNewAdded: !!diff?.table,
},
isOverride: false,
field: {
fieldName: dataName,
note: field?.note?.text || '',
expression: field?.expressionMetadata?.text || '',
isPeriodSeries: type === ColumnDataType.PERIOD_SERIES,
isNested: tableData.nestedColumnNames.has(dataName),
isKey: field?.isKey,
isDim: field?.isDim,
isDynamic: field?.isDynamic,
hasError: !!fieldErrorMessage,
errorMessage: fieldErrorMessage,
isFiltered,
numericFilter,
isFieldUsedInSort,
sort,
type,
referenceTableName,
isChanged: !!diff?.fields.includes(dataName),
},
overrideIndex: undefined,
value: undefined,
row,
col,
dataIndex: directionIndex - minDirectionIndex,
startCol: fieldStartCol,
endCol: fieldEndCol,
zIndex,
isFieldHeader: false,
isTableHeader: false,
});
}
}
}
};
const existingIndexes = [
...Object.keys(tableData.fallbackChunks),
...Object.keys(tableData.chunks),
];
const indexes = Array.from(new Set(existingIndexes));
for (const index of indexes) {
const chunkIndex = +index;
buildChunk(
{
...tableData.chunks[chunkIndex],
...tableData.fallbackChunks[chunkIndex],
},
chunkIndex
);
}
return data;
}