import * as React from “react”;
import { GridReadyEvent, CellValueChangedEvent, GetContextMenuItemsParams } from “ag-grid-community”;
import { Guid } from “@cassini/model”;
import { BoxCurveConfigurationRow } from “@model”;
import { AgGridWrapper } from “@cassini/components”;
import { CellValidator } from “./CellValidator”;
import { columnDefs, columnDefsTenorDisable } from “./column-definitions”;
import { boxCurveRowDefaults } from “…/utils”;
import { genericGridOptions } from “@utils”;
interface Props {
updatedBoxCurveData: any;
isHistorical: boolean;
handleUpdatedBoxCurveData: (data: any) => void;
handleIsEditing: (editing: boolean) => void;
handleIsContextMenuRowEdit: (IsContextMenuRowEdit: boolean) => void;
isLoadingBoxCurve: boolean;
isCheckedIndexInput: boolean;
enableTenorEditing: boolean;
}
interface CopiedRow {
tenor?: string;
rate?: number;
}
export const BoxCurveConfiguration: React.FC = (props: Props) => {
const { updatedBoxCurveData, handleUpdatedBoxCurveData, handleIsEditing, isHistorical, isLoadingBoxCurve, isCheckedIndexInput, enableTenorEditing, handleIsContextMenuRowEdit } = props;
const gridApi = React.useRef();
const gridColumnApi = React.useRef();
const [colDefs, setcolDefs] = React.useState(columnDefs);
// const traderViewCheckedRef = React.useRef(true);
console.log("BoxCurveConfiguration: " + isCheckedIndexInput);
React.useEffect(() => {
if (gridApi?.current) {
if (isLoadingBoxCurve) {
gridApi.current.showLoadingOverlay();
} else {
gridApi.current.hideOverlay();
}
}
}, [isLoadingBoxCurve]);
// React.useEffect(() => {
// traderViewCheckedRef.current = isCheckedIndexInput;
// }, [isCheckedIndexInput]);
React.useEffect(() => {
console.log("BoxCurveConfiguration useEffect: " + isCheckedIndexInput);
if(gridApi && gridApi.current){
if(isCheckedIndexInput){
const newupdatedBoxCurveData = updatedBoxCurveData.map((item: { rate: number; }) => {
return {
...item,
rate: -item.rate
};
});
gridApi.current.setRowData(newupdatedBoxCurveData);
}else {
gridApi.current.setRowData(updatedBoxCurveData);
}
}
}, [updatedBoxCurveData, isCheckedIndexInput]);
// The role can't edit the tenor column value without enableTenorEditing permission, but could edit not empty value tenor cell when doing add row action.
React.useEffect(() => {
if (enableTenorEditing) {
setcolDefs(columnDefs);
} else{
setcolDefs(columnDefsTenorDisable);
}
}, [enableTenorEditing]);
// NOTE: I cannot find a better way than this, changes to react state is not updated inside the context menu
React.useEffect(() => {
if (gridApi?.current) {
if (isHistorical) {
gridApi.current.isReadOnly = true;
} else {
gridApi.current.isReadOnly = false;
}
}
}, [isHistorical]);
const onGridReadyHandler = (gridParams: GridReadyEvent) => {
gridApi.current = gridParams.api!;
gridColumnApi.current = gridParams.columnApi!;
};
// TODO can this be moved to column definition?
const updateColumns = (event: CellValueChangedEvent) => {
const allData = gridApi.current.getModel().gridOptionsWrapper.gridOptions.rowData;
const activeRow = event.rowIndex;
if (event.colDef.field === "tenor") {
allData[activeRow].tenor = event.value;
allData[activeRow].end = event.value;
handleUpdatedBoxCurveData([...allData]);
handleIsEditing(true);
}
console.log("updateColumns: " + isCheckedIndexInput);
if (event.colDef.field === "rate") {
if(isCheckedIndexInput){
allData[activeRow].rate = -event.value;
}else {
allData[activeRow].rate = event.value;
}
handleUpdatedBoxCurveData([...allData]);
handleIsEditing(true);
}
};
// Cannot access component state inside the context menu
const contextMenu = (gridParams: GetContextMenuItemsParams) => {
gridApi.current = gridParams.api!;
const allData = gridApi.current.getModel().gridOptionsWrapper.gridOptions.rowData;
const {
fitFlag = boxCurveRowDefaults.fitFlag,
type = boxCurveRowDefaults.type,
freq1 = boxCurveRowDefaults.freq1,
freq2 = boxCurveRowDefaults.freq2,
rollPolicy = boxCurveRowDefaults.rollPolicy
} = allData[0];
return [
{
name: "Add Row",
disabled: gridApi.current.isReadOnly,
action: () => {
handleUpdatedBoxCurveData([
...allData,
{
fitFlag,
type,
freq1,
freq2,
rollPolicy,
OISIndex2: allData[0].OISIndex2,
OISIndex: allData[0].OISIndex,
id: Guid.newGuid()
}
]);
handleIsEditing(true);
handleIsContextMenuRowEdit(true);
}
},
{
name: "Remove Row",
disabled: allData.length <= 1 || gridApi.current.isReadOnly,
action: () => {
console.log("Remove Row: " + isCheckedIndexInput);
const updatedRows = allData.filter((row: BoxCurveConfigurationRow) => {
return row.id !== gridParams?.node?.data?.id;
});
handleUpdatedBoxCurveData(updatedRows);
handleIsEditing(true);
handleIsContextMenuRowEdit(true);
}
},
{
name: "Clear All",
disabled: gridApi.current.isReadOnly,
action: () => {
const rowData = [
{
...boxCurveRowDefaults,
OISIndex2: allData[0].OISIndex2,
OISIndex: allData[0].OISIndex,
id: Guid.newGuid()
}
];
handleUpdatedBoxCurveData(rowData);
gridApi.current.sizeColumnsToFit();
handleIsEditing(true);
handleIsContextMenuRowEdit(true);
}
},
"separator",
"copy",
"copyWithHeaders",
"export"
];
};
const getRowNodeId = (row: BoxCurveConfigurationRow) => {
return row.id;
};
const gridOptions = {
...genericGridOptions,
defaultColDef: {
flex: 1,
minWidth: 75
},
stopEditingWhenGridLosesFocus: true,
onCellValueChanged: (event: CellValueChangedEvent) => {
updateColumns(event);
},
getContextMenuItems: contextMenu,
suppressColumnVirtualisation: true,
onGridReady: onGridReadyHandler,
frameworkComponents: {
cellValidator: CellValidator
},
immutableData: false,
processDataFromClipboard: (params: any) => {
const currentGridData = gridApi.current.getModel().gridOptionsWrapper.gridOptions.rowData;
if (isEmptyLastRow(params.data)) {
params.data.splice(params.data.length - 1, 1);
}
const lastIndex = gridApi.current.getModel().rowsToDisplay.length - 1;
const focusedCell = gridApi.current.getFocusedCell();
const focusedIndex = focusedCell.rowIndex;
if (focusedIndex + params.data.length - 1 > lastIndex) {
const newRowData = processNewRows(
currentGridData,
focusedIndex,
lastIndex,
params.data,
focusedCell,
gridColumnApi.current
);
handleUpdatedBoxCurveData([...currentGridData, ...newRowData]);
}
return params.data;
},
overlayLoadingTemplate: "Loading..."
};
const isEmptyLastRow = (clipbordRows: any) => {
return clipbordRows[clipbordRows.length - 1][0] === "" && clipbordRows[clipbordRows.length - 1].length === 1;
};
const processNewRows = (
currentGridData: any,
focusedIndex: number,
lastIndex: number,
clipbordRows: any,
focusedCell: any,
gridColApi: any
) => {
const {
fitFlag = boxCurveRowDefaults.fitFlag,
type = boxCurveRowDefaults.type,
freq1 = boxCurveRowDefaults.freq1,
freq2 = boxCurveRowDefaults.freq2,
rollPolicy = boxCurveRowDefaults.rollPolicy
} = currentGridData[0];
const resultLastIndex = focusedIndex + (clipbordRows.length - 1);
const addRowCount = resultLastIndex - lastIndex;
const rowsToAdd = getRowsToAdd(addRowCount, clipbordRows);
const newRowData = rowsToAdd.map(newRow => {
let currColumn = focusedCell.column;
const row = newRow.reduce((result: CopiedRow, i: any) => {
const field = currColumn.colDef.field;
result[field] = i;
currColumn = gridColApi.getDisplayedColAfter(currColumn);
return result;
}, {});
return {
fitFlag,
type,
freq1,
freq2,
rollPolicy,
OISIndex2: currentGridData[0].OISIndex2,
OISIndex: currentGridData[0].OISIndex,
end: row.tenor,
id: Guid.newGuid(),
tenor: row.tenor,
rate: row.rate
};
});
return newRowData;
};
const getRowsToAdd = (addRowCount: number, clipbordRows: any) => {
let rowsToAdd = [];
let addedRows = 0;
let currIndex = clipbordRows.length - 1;
while (addedRows < addRowCount) {
const row = clipbordRows.splice(currIndex, 1)[0];
rowsToAdd.push(row);
addedRows++;
currIndex--;
}
rowsToAdd = rowsToAdd.reverse();
return [...rowsToAdd];
};
return (
<div className='box-curve-config' data-cy='box-curve-config-grid'>
<AgGridWrapper
columnDefs={colDefs}
rowData={updatedBoxCurveData}
gridOptions={gridOptions}
getRowNodeId={getRowNodeId}
/>
</div>
);
};
2023-09-25 15:28:02 UTC INFO [main] — /tmp/workspace/icg-msst-cassini-172868/icg-msst-cassini-172868-yield-curves-ui.feature-c160561-8884-cvm-r (depth 0)
2023-09-25 15:28:02 UTC INFO [main] — LERNA - Lerna
2023-09-25 15:28:02 UTC INFO [main] — Found file: /tmp/workspace/icg-msst-cassini-172868/icg-msst-cassini-172868-yield-curves-ui.feature-c160561-8884-cvm-r/lerna.json
2023-09-25 15:28:02 UTC INFO [main] — GIT - Git
2023-09-25 15:28:02 UTC INFO [main] — Found file: /tmp/workspace/icg-msst-cassini-172868/icg-msst-cassini-172868-yield-curves-ui.feature-c160561-8884-cvm-r/.git
2023-09-25 15:28:02 UTC INFO [main] — Found executable: /usr/bin/git
2023-09-25 15:28:02 UTC INFO [main] — ----------------------------------
2023-09-25 15:28:02 UTC INFO [main] — Detectors actions finished.
2023-09-25 15:28:02 UTC INFO [main] — ----------------------------------
2023-09-25 15:28:02 UTC INFO [main] — Project name: 172868/cassini/yield-curves-ui
2023-09-25 15:28:02 UTC INFO [main] — Project version: feature-c160561-888-2-afbb940
2023-09-25 15:28:02 UTC INFO [main] — ----------------------------------
2023-09-25 15:28:02 UTC INFO [main] — Signature Scanner tool will not be run.
2023-09-25 15:28:02 UTC INFO [main] — ----------------------------------
2023-09-25 15:28:02 UTC INFO [main] — Vulnerability Impact Analysis tool will not be run.
2023-09-25 15:28:02 UTC INFO [main] — ----------------------------------
2023-09-25 15:28:02 UTC INFO [main] — IaC Scanner tool will not be run.
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — Creating status file: /home/jenkins/blackduck/runs/2023-09-25-15-28-01-080/status/status.json
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — Status file has been deleted. To preserve status file, turn off cleanup actions.
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — ======== Detect Issues ========
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — DETECTORS:
2023-09-25 15:28:02 UTC INFO [main] — Detector Issue
2023-09-25 15:28:02 UTC INFO [main] — /tmp/workspace/icg-msst-cassini-172868/icg-msst-cassini-172868-yield-curves-ui.feature-c160561-8884-cvm-r
2023-09-25 15:28:02 UTC INFO [main] — Not Extractable: LERNA - Lerna
2023-09-25 15:28:02 UTC INFO [main] — No lerna executable was found.
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — DEPRECATIONS:
2023-09-25 15:28:02 UTC INFO [main] — detect.bom.aggregate.name
2023-09-25 15:28:02 UTC INFO [main] — This property is being removed. Use detect.bdio.file.name to control the name of the bdio file Detect generates. Currently detect.bdio.file.name has the same effects as this property. In the future, Detect will always operate in SUBPROJECT aggregation mode regardless of how it is configured; detect.bdio.file.name will only control the BDIO file name. This property will be removed in 8.0.0.
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — ======== Detect Status ========
2023-09-25 15:28:02 UTC INFO [main] —
2023-09-25 15:28:02 UTC INFO [main] — GIT: SUCCESS
2023-09-25 15:28:02 UTC INFO [main] — LERNA: FAILURE
2023-09-25 15:28:02 UTC INFO [main] — Overall Status: FAILURE_DETECTOR - Detect had one or more detector failures while extracting dependencies. Check that all projects build and your environment is configured correctly.