diff --git a/front/package.json b/front/package.json index 8ccbb7fd65f..121875c34e1 100644 --- a/front/package.json +++ b/front/package.json @@ -85,6 +85,7 @@ "react": "^18.2.0", "react-beautiful-dnd": "^13.1.1", "react-countdown": "^2.3.5", + "react-datasheet-grid": "^4.11.4", "react-dom": "^18.2.0", "react-flatpickr": "^3.10.13", "react-hook-form": "^7.50.0", @@ -100,7 +101,6 @@ "react-rnd": "^10.4.1", "react-router-dom": "^6.22.0", "react-select": "^5.8.0", - "react-spreadsheet": "^0.9.4", "react-tether": "^3.0.3", "react-transition-group": "^4.4.5", "redux": "^5.0.1", diff --git a/front/src/modules/rollingStock/components/RollingStockEditor/CurveSpreadsheet.tsx b/front/src/modules/rollingStock/components/RollingStockEditor/CurveSpreadsheet.tsx index 36a2161fe58..90a6c84e811 100644 --- a/front/src/modules/rollingStock/components/RollingStockEditor/CurveSpreadsheet.tsx +++ b/front/src/modules/rollingStock/components/RollingStockEditor/CurveSpreadsheet.tsx @@ -1,10 +1,15 @@ -import React, { type Dispatch, type SetStateAction, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import type { Dispatch, SetStateAction } from 'react'; +import { DataSheetGrid, keyColumn, intColumn, floatColumn } from 'react-datasheet-grid'; +import 'react-datasheet-grid/dist/style.css'; import { useTranslation } from 'react-i18next'; -import Spreadsheet, { createEmptyMatrix } from 'react-spreadsheet'; -import type { CellBase, Matrix } from 'react-spreadsheet'; -import type { ConditionalEffortCurveForm, EffortCurveForms } from 'modules/rollingStock/types'; +import type { + ConditionalEffortCurveForm, + DataSheetCurve, + EffortCurveForms, +} from 'modules/rollingStock/types'; import { replaceElementAtIndex } from 'utils/array'; import { msToKmh } from 'utils/physics'; @@ -14,9 +19,9 @@ type CurveSpreadsheetProps = { selectedCurve: ConditionalEffortCurveForm; selectedCurveIndex: number; selectedTractionModeCurves: ConditionalEffortCurveForm[]; - effortCurves: EffortCurveForms | null; + effortCurves: EffortCurveForms; setEffortCurves: Dispatch>; - selectedTractionMode: string | null; + selectedTractionMode: string; isDefaultCurve: boolean; }; @@ -30,45 +35,38 @@ const CurveSpreadsheet = ({ isDefaultCurve, }: CurveSpreadsheetProps) => { const { t } = useTranslation('rollingstock'); + const columns = useMemo( + () => [ + { ...keyColumn('speed', intColumn), title: t('speed') }, + { ...keyColumn('effort', floatColumn), title: t('effort') }, + ], + [t] + ); - const spreadsheetCurve = useMemo(() => { - const { speeds, max_efforts } = selectedCurve.curve; - const filledMatrix: ( - | { - value: string; - } - | undefined - )[][] = - speeds && max_efforts - ? max_efforts.map((effort, index) => [ - { - value: - speeds[index] !== undefined ? Math.round(msToKmh(speeds[index]!)).toString() : '', - }, - // Effort needs to be displayed in kN - { value: effort !== undefined ? Math.round(effort / 1000).toString() : '' }, - ]) - : []; - const numberOfRows = filledMatrix.length < 8 ? 8 - filledMatrix.length : 1; - return filledMatrix.concat(createEmptyMatrix>(numberOfRows, 2)); - }, [selectedCurve]); + const [needsSort, setNeedsSort] = useState(false); - const updateRollingStockCurve = (e: Matrix<{ value: string }>) => { - if (!selectedTractionMode || !effortCurves) return; - const formattedCurve = formatCurve(e); + const handleBlur = useCallback(() => { + setNeedsSort(true); + }, []); + const updateRollingStockCurve = (newCurve: DataSheetCurve[]) => { + // Format the new curve + const formattedCurve = formatCurve(newCurve); + + // Create the updated selected curve const updatedSelectedCurve = { ...selectedCurve, curve: formattedCurve, }; - // replace the updated curve + // Replace the updated curve in the selected traction mode curves const updatedCurves = replaceElementAtIndex( selectedTractionModeCurves, selectedCurveIndex, updatedSelectedCurve ); + // Update the effort curves const updatedEffortCurve = { ...effortCurves, [selectedTractionMode]: { @@ -77,30 +75,56 @@ const CurveSpreadsheet = ({ ...(isDefaultCurve ? { default_curve: formattedCurve } : {}), }, }; + setEffortCurves(updatedEffortCurve); }; - const orderSpreadsheetValues = () => { - const orderedValuesByVelocity = spreadsheetCurve.sort((a, b) => { - // if a row has a max_effort, but no speed, it should appear at the top of the table - if (b[0] && b[0].value === '') return 1; - return Number(a[0]?.value) - Number(b[0]?.value); - }); - updateRollingStockCurve(orderedValuesByVelocity); - }; + const spreadsheetCurve = useMemo(() => { + const { speeds, max_efforts } = selectedCurve.curve; + + const filledDataSheet: DataSheetCurve[] = max_efforts.map((effort, index) => ({ + speed: speeds[index] !== null ? Math.round(msToKmh(speeds[index]!)) : null, + // Effort needs to be displayed in kN + effort: effort && effort !== null ? effort / 1000 : null, + })); + + // Add an empty line for input only if last line is not already empty + if ( + filledDataSheet.length === 0 || + filledDataSheet[filledDataSheet.length - 1].speed !== null || + filledDataSheet[filledDataSheet.length - 1].effort !== null + ) { + filledDataSheet.push({ speed: null, effort: null }); + } + + return filledDataSheet; + }, [selectedCurve]); + + useEffect(() => { + if (needsSort) { + const sortedSpreadsheetValues = spreadsheetCurve + .filter((item) => item.speed !== null || item.effort !== null) + .sort((a, b) => { + if (a.speed === null) return -1; + if (b.speed === null) return 1; + return Number(a.speed) - Number(b.speed); + }); + + updateRollingStockCurve(sortedSpreadsheetValues); + setNeedsSort(false); + } + }, [needsSort]); return (
- { - updateRollingStockCurve(e); - }} - onBlur={orderSpreadsheetValues} - onKeyDown={(e) => { - if (e.key === 'Enter') orderSpreadsheetValues(); - }} - columnLabels={[t('speed'), t('effort')]} + updateRollingStockCurve(e as DataSheetCurve[])} + rowHeight={30} + addRowsComponent={false} + onBlur={handleBlur} + onSelectionChange={handleBlur} />
); diff --git a/front/src/modules/rollingStock/components/RollingStockEditor/RollingStockEditorCurves.tsx b/front/src/modules/rollingStock/components/RollingStockEditor/RollingStockEditorCurves.tsx index f6dd91aaca4..ea2cd4d29f3 100644 --- a/front/src/modules/rollingStock/components/RollingStockEditor/RollingStockEditorCurves.tsx +++ b/front/src/modules/rollingStock/components/RollingStockEditor/RollingStockEditorCurves.tsx @@ -15,7 +15,7 @@ import CurveSpreadsheet from 'modules/rollingStock/components/RollingStockEditor import { STANDARD_COMFORT_LEVEL, THERMAL_TRACTION_IDENTIFIER } from 'modules/rollingStock/consts'; import { getElectricalProfilesAndPowerRestrictions } from 'modules/rollingStock/helpers/rollingStockEditor'; import { - filterUndefinedValueInCurve, + filterNullValueInCurve, orderElectricalProfils, orderSelectorList, } from 'modules/rollingStock/helpers/utils'; @@ -176,7 +176,7 @@ const RollingStockEditorCurves = ({ ...selectedModeCurves, curves: matchingCurves.map((condCurve) => ({ ...condCurve, - curve: filterUndefinedValueInCurve(condCurve.curve), + curve: filterNullValueInCurve(condCurve.curve), })), }, } as EffortCurves['modes']; @@ -211,7 +211,8 @@ const RollingStockEditorCurves = ({ {selectedTractionMode && selectedCurve && selectedCurveIndex !== null && - selectedTractionModeCurves && ( + selectedTractionModeCurves && + effortCurves && (
) => - sheetValues.filter( - ([a, b]) => - (a?.value && !emptyStringRegex.test(a.value)) || (b?.value && !emptyStringRegex.test(b.value)) - ); -/** For each cell, filter non digit characters */ -const removeNonDigitCharacters = (rows: Matrix<{ value: string }>) => - rows.map((row) => row.map((cell) => onlyDigit((cell?.value || '').replaceAll(',', '.')))); - -const formatToEffortCurve = (rows: Matrix) => +const formatCurve = (rows: DataSheetCurve[]) => rows.reduce( (result, row) => { - result.speeds.push(row[0] !== '' ? kmhToMs(Number(row[0])) : undefined); + result.speeds.push(row.speed !== null ? kmhToMs(Number(row.speed)) : null); // Back-end needs effort in newton - result.max_efforts.push(row[1] !== '' ? Number(row[1]) * 1000 : undefined); + result.max_efforts.push(row.effort !== null ? Number(row.effort) * 1000 : null); + return result; }, { max_efforts: [], speeds: [] } ); -/** - * Given a spreadsheet, return an EffortCurve - * - remove rows which have at least 1 empty cell - * - remove non digit characters in each cell - * - convert rows data to EffortCurve - */ -export default function formatCurve(sheetValues: Matrix<{ value: string }>) { - const validRows = filterUnvalidRows(sheetValues); - const numericRows = removeNonDigitCharacters(validRows); - return formatToEffortCurve(numericRows); -} +export default formatCurve; diff --git a/front/src/modules/rollingStock/helpers/utils.ts b/front/src/modules/rollingStock/helpers/utils.ts index 2de0e5d97e9..a98fdc6464e 100644 --- a/front/src/modules/rollingStock/helpers/utils.ts +++ b/front/src/modules/rollingStock/helpers/utils.ts @@ -32,11 +32,11 @@ import { kmhToMs, msToKmh } from 'utils/physics'; import { getTranslationKey } from 'utils/strings'; import type { ValueOf } from 'utils/types'; -export const filterUndefinedValueInCurve = (curve: EffortCurveForm) => +export const filterNullValueInCurve = (curve: EffortCurveForm) => curve.speeds.reduce( (result, speed, index) => { const maxEffort = curve.max_efforts[index]; - if (speed !== undefined && maxEffort !== undefined) { + if (speed !== null && maxEffort !== null) { result.speeds.push(speed); result.max_efforts.push(maxEffort); } @@ -132,11 +132,11 @@ export const rollingStockEditorQueryArg = ( ...acc, [mode]: { ...currentRsEffortCurve[mode], - default_curve: filterUndefinedValueInCurve(currentRsEffortCurve[mode].default_curve), + default_curve: filterNullValueInCurve(currentRsEffortCurve[mode].default_curve), curves: [ ...currentRsEffortCurve[mode].curves.map((curve) => ({ ...curve, - curve: filterUndefinedValueInCurve(curve.curve), + curve: filterNullValueInCurve(curve.curve), })), ], }, @@ -259,7 +259,7 @@ export const checkRollingStockFormValidity = ( Object.entries(effortCurves || {}).forEach(([mode, { curves }]) => { curves.forEach( ({ curve, cond: { comfort, electrical_profile_level, power_restriction_code } }) => { - const filteredCurve = filterUndefinedValueInCurve(curve); + const filteredCurve = filterNullValueInCurve(curve); if (isInvalidCurve(filteredCurve)) { const formattedComfort = formatCurveCondition(comfort, t, 'comfortTypes'); diff --git a/front/src/modules/rollingStock/types.ts b/front/src/modules/rollingStock/types.ts index 85b512f36a8..f19f40311fe 100644 --- a/front/src/modules/rollingStock/types.ts +++ b/front/src/modules/rollingStock/types.ts @@ -122,10 +122,15 @@ export type ElectricalProfileByMode = { thermal: null[]; }; +export type DataSheetCurve = { + speed: number | null; + effort: number | null; +}; + // Effort curve with values number or undefined export type EffortCurveForm = { - max_efforts: Array; - speeds: Array; + max_efforts: Array; + speeds: Array; }; export type ConditionalEffortCurveForm = { diff --git a/front/src/styles/scss/applications/rollingStockEditor/_rollingStockForm.scss b/front/src/styles/scss/applications/rollingStockEditor/_rollingStockForm.scss index 5e5c8d162dd..9b022ffdbe9 100644 --- a/front/src/styles/scss/applications/rollingStockEditor/_rollingStockForm.scss +++ b/front/src/styles/scss/applications/rollingStockEditor/_rollingStockForm.scss @@ -223,19 +223,12 @@ .rollingstock-editor-spreadsheet { width: 40%; - height: 20.75rem; - overflow: auto; - tr:not(:first-child) .Spreadsheet__header, - tr:first-child .Spreadsheet__header:first-child { - width: 2rem; - border: solid 1px var(--coolgray3); - } - tr:not(:first-child) .Spreadsheet__header { - background-color: var(--white); - } - tr:first-child .Spreadsheet__header { + height: auto; + border-radius: 0.3rem; + .dsg-cell-header { color: var(--blue); white-space: normal !important; + background-color: var(--coolgray1); } } diff --git a/front/src/utils/strings.ts b/front/src/utils/strings.ts index c6f27dbaece..78b98cb7d63 100644 --- a/front/src/utils/strings.ts +++ b/front/src/utils/strings.ts @@ -33,8 +33,6 @@ export function snakeToCamel(str: string) { return str.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr: string) => chr.toUpperCase()); } -export const emptyStringRegex = /^\s+$/; - export function getTranslationKey(translationList: string | undefined, item: string): string { return `${translationList ? `${translationList}.` : ''}${item}`; } diff --git a/front/tests/009-rollingstock-editor.spec.ts b/front/tests/009-rollingstock-editor.spec.ts index 71e97dee060..3942bef9381 100644 --- a/front/tests/009-rollingstock-editor.spec.ts +++ b/front/tests/009-rollingstock-editor.spec.ts @@ -84,16 +84,16 @@ test.describe('Rollingstock editor page', () => { // Complete the speed effort curves Not specified - const velocityCellRow0 = playwrightRollingstockEditorPage.getVelocityCellByRow('0'); + const velocityCellRow0 = playwrightRollingstockEditorPage.getVelocityCellByRow(1); await playwrightRollingstockEditorPage.setSpreedsheetCell('0', velocityCellRow0); - const effortCellRow0 = playwrightRollingstockEditorPage.getEffortCellByRow('0'); + const effortCellRow0 = playwrightRollingstockEditorPage.getEffortCellByRow(1); await playwrightRollingstockEditorPage.setSpreedsheetCell('900', effortCellRow0); - const velocityCellRow1 = playwrightRollingstockEditorPage.getVelocityCellByRow('1'); + const velocityCellRow1 = playwrightRollingstockEditorPage.getVelocityCellByRow(2); await playwrightRollingstockEditorPage.setSpreedsheetCell('5', velocityCellRow1); - const effortCellRow1 = playwrightRollingstockEditorPage.getEffortCellByRow('1'); + const effortCellRow1 = playwrightRollingstockEditorPage.getEffortCellByRow(2); await playwrightRollingstockEditorPage.setSpreedsheetCell('800', effortCellRow1); // Select and complete the speed effort curves C0 @@ -113,16 +113,16 @@ test.describe('Rollingstock editor page', () => { await playwrightRollingstockEditorPage.setSpreedsheetCell('800', effortCellRow1); - const velocityCellRow2 = playwrightRollingstockEditorPage.getVelocityCellByRow('2'); + const velocityCellRow2 = playwrightRollingstockEditorPage.getVelocityCellByRow(3); await playwrightRollingstockEditorPage.setSpreedsheetCell('10', velocityCellRow2); - const effortCellRow2 = playwrightRollingstockEditorPage.getEffortCellByRow('2'); + const effortCellRow2 = playwrightRollingstockEditorPage.getEffortCellByRow(3); await playwrightRollingstockEditorPage.setSpreedsheetCell('900', effortCellRow2); - const velocityCellRow3 = playwrightRollingstockEditorPage.getVelocityCellByRow('3'); + const velocityCellRow3 = playwrightRollingstockEditorPage.getVelocityCellByRow(4); await playwrightRollingstockEditorPage.setSpreedsheetCell('20', velocityCellRow3); - const effortCellRow3 = playwrightRollingstockEditorPage.getEffortCellByRow('3'); + const effortCellRow3 = playwrightRollingstockEditorPage.getEffortCellByRow(4); await playwrightRollingstockEditorPage.setSpreedsheetCell('800', effortCellRow3); await playwrightRollingstockEditorPage.clickOnRollingstockDetailsButton(); diff --git a/front/tests/pages/rollingstock-editor-page-model.ts b/front/tests/pages/rollingstock-editor-page-model.ts index 2c912afaef5..8fb69d7689e 100644 --- a/front/tests/pages/rollingstock-editor-page-model.ts +++ b/front/tests/pages/rollingstock-editor-page-model.ts @@ -24,7 +24,7 @@ export class PlaywrightRollingstockEditorPage extends PlaywrightCommonPage { this.getSubmitRollingstockButton = page.getByTestId('submit-rollingstock-button'); this.getRollingstockDetailsButton = page.getByTestId('tab-rollingstock-details'); this.getSpeedEffortCurvesButton = page.getByTestId('tab-rollingstock-curves'); - this.getRollingStockSpreedsheet = page.locator('.Spreadsheet__table'); + this.getRollingStockSpreedsheet = page.locator('.dsg-container'); this.getRollingStockSearchInput = page.locator('#searchfilter'); this.getRollingStockEditorList = page.getByTestId('rollingstock-editor-list'); } @@ -58,12 +58,12 @@ export class PlaywrightRollingstockEditorPage extends PlaywrightCommonPage { return this.page.getByTestId(testId); } - getVelocityCellByRow(row: string) { - return this.getRollingStockSpreedsheet.locator(`[row="${row}"]`).locator('td').first(); + getVelocityCellByRow(row: number) { + return this.getRollingStockSpreedsheet.locator('.dsg-row').nth(row).locator('.dsg-cell').nth(1); } - getEffortCellByRow(row: string) { - return this.getRollingStockSpreedsheet.locator(`[row="${row}"]`).locator('td').last(); + getEffortCellByRow(row: number) { + return this.getRollingStockSpreedsheet.locator('.dsg-row').nth(row).locator('.dsg-cell').last(); } async setSpreedsheetCell(value: string, cell: Locator) { @@ -77,7 +77,7 @@ export class PlaywrightRollingstockEditorPage extends PlaywrightCommonPage { ); } - async setSpreedsheetRow(data: { row: string; velocity: string; effort: string }[]) { + async setSpreedsheetRow(data: { row: number; velocity: string; effort: string }[]) { await Promise.all( data.map(async ({ row, effort, velocity }) => { const velocityCell = this.getVelocityCellByRow(row); diff --git a/front/yarn.lock b/front/yarn.lock index 66c986ef53f..dbc55e79fcb 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -3298,6 +3298,18 @@ resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a" integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== +"@tanstack/react-virtual@^3.0.0-beta.18": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.1.3.tgz#4ef2a7dd819a7dd2b634d50cbd6ba498f06529ec" + integrity sha512-YCzcbF/Ws/uZ0q3Z6fagH+JVhx4JLvbSflgldMgLsuvB8aXjZLLb3HvrEVxY480F9wFlBiXlvQxOyXb5ENPrNA== + dependencies: + "@tanstack/virtual-core" "3.1.3" + +"@tanstack/virtual-core@3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.1.3.tgz#77ced625f19ec9350f6e460f142b3be9bff03866" + integrity sha512-Y5B4EYyv1j9V8LzeAoOVeTg0LI7Fo5InYKgAjkY1Pu9GjtUwX/EKxNcU7ng3sKr99WEf+bPTcktAeybyMOYo+g== + "@testing-library/dom@^9.0.0", "@testing-library/dom@^9.3.4": version "9.3.4" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-9.3.4.tgz#50696ec28376926fec0a1bf87d9dbac5e27f60ce" @@ -4893,7 +4905,7 @@ array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.2.5, array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -5066,11 +5078,6 @@ babel-plugin-polyfill-regenerator@^0.5.5: dependencies: "@babel/helper-define-polyfill-provider" "^0.5.0" -bahttext@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bahttext/-/bahttext-1.1.0.tgz#5b704ed65ff978f12267b7b6e1509eaafdbfdd1c" - integrity sha512-3g7DbmCwYhLnnN5hJFB+Mtbst4q2gfXpAdqOMK6tz6FmgtlrhX1n1uhuzkIhEr+WcnFR6eRvebIE5msGuEtA7Q== - bail@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -5086,11 +5093,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bessel@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bessel/-/bessel-1.0.2.tgz#828812291e0b62e94959cdea43fac186e8a7202d" - integrity sha512-Al3nHGQGqDYqqinXhQzmwmcRToe/3WyBv4N8aZc5Pef8xw2neZlR9VPi84Sa23JtgWcucu18HxVZrnI0fn2etw== - better-opn@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-3.0.2.tgz#f96f35deaaf8f34144a4102651babcf00d1d8817" @@ -5492,13 +5494,6 @@ check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -chevrotain@^7.0.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-7.1.2.tgz#40e634c0b74fcb552118bf67f42f5820b84881fd" - integrity sha512-9bQsXVQ7UAvzMs7iUBBJ9Yv//exOy7bIR3PByOEk4M64vIE/LsiOiX7VIkMF/vEMlrSStwsaE884Bp9CpjtC5g== - dependencies: - regexp-to-ast "0.5.0" - "chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.1, chokidar@^3.5.3: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" @@ -7370,16 +7365,6 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-formula-parser@^1.0.19: - version "1.0.19" - resolved "https://registry.yarnpkg.com/fast-formula-parser/-/fast-formula-parser-1.0.19.tgz#3b22dd6c4385bd12e7928dab8968b1298ed44a77" - integrity sha512-8Roq7V1XjuYj3cWZ9tILyqBHGjS7NkejRaHxSWePu0qjIcvimZwe6WfeA9che03dgWrykZqrw691qg3lwiIkMg== - dependencies: - bahttext "^1.1.0" - bessel "^1.0.2" - chevrotain "^7.0.1" - jstat "^1.9.3" - fast-glob@^3.2.7, fast-glob@^3.2.9: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -9153,11 +9138,6 @@ jsonpointer@^5.0.1: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== -jstat@^1.9.3: - version "1.9.6" - resolved "https://registry.yarnpkg.com/jstat/-/jstat-1.9.6.tgz#60e801b0d4c26e37aab0f375d1859fe9d60e10c0" - integrity sha512-rPBkJbK2TnA8pzs93QcDDPlKcrtZWuuCo2dVR0TFLOJSxhqfWOVCSp8aV3/oSbn+4uY4yw1URtLpHQedtmXfug== - "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" @@ -11428,6 +11408,17 @@ react-countdown@^2.3.5: dependencies: prop-types "^15.7.2" +react-datasheet-grid@^4.11.4: + version "4.11.4" + resolved "https://registry.yarnpkg.com/react-datasheet-grid/-/react-datasheet-grid-4.11.4.tgz#cd3cfc77a1c2cd72c094f0527236771ba3d5c372" + integrity sha512-fWSOOHCPAv1Qkdk3+Io/Z8b02NC+V1Q/4FIAbhEAv9GmwaBAu/B68pySstY7eIDbgVLxnDLiAq8oCt98HZ8FHg== + dependencies: + "@tanstack/react-virtual" "^3.0.0-beta.18" + classnames "^2.3.1" + fast-deep-equal "^3.1.3" + react-resize-detector "^7.1.2" + throttle-debounce "^3.0.1" + react-docgen-typescript@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c" @@ -11628,6 +11619,13 @@ react-remove-scroll@2.5.5: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" +react-resize-detector@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-7.1.2.tgz#8ef975dd8c3d56f9a5160ac382ef7136dcd2d86c" + integrity sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw== + dependencies: + lodash "^4.17.21" + react-rnd@^10.4.1: version "10.4.1" resolved "https://registry.yarnpkg.com/react-rnd/-/react-rnd-10.4.1.tgz#9e1c3f244895d7862ef03be98b2a620848c3fba1" @@ -11667,16 +11665,6 @@ react-select@^5.8.0: react-transition-group "^4.3.0" use-isomorphic-layout-effect "^1.1.2" -react-spreadsheet@^0.9.4: - version "0.9.4" - resolved "https://registry.yarnpkg.com/react-spreadsheet/-/react-spreadsheet-0.9.4.tgz#c80358e5aa0312742c12127e5b89ae25ed9c82d8" - integrity sha512-BVvABaSbxkz33nsR3qdXzDEjUmLTUmV01+Co6PS1a9KTFu63c+rJng1dP3GAGOeAF/BhA2M9224H6PPeyCjZJA== - dependencies: - array.prototype.flatmap "^1.2.5" - classnames "^2.3.1" - fast-formula-parser "^1.0.19" - use-context-selector "^1.3.7" - react-style-singleton@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" @@ -11880,11 +11868,6 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regexp-to-ast@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz#56c73856bee5e1fef7f73a00f1473452ab712a24" - integrity sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw== - regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" @@ -13016,6 +12999,11 @@ throttle-debounce@^2.1.0: resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2" integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ== +throttle-debounce@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" + integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== + through2@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -13543,11 +13531,6 @@ use-callback-ref@^1.3.0: dependencies: tslib "^2.0.0" -use-context-selector@^1.3.7: - version "1.4.1" - resolved "https://registry.yarnpkg.com/use-context-selector/-/use-context-selector-1.4.1.tgz#eb96279965846b72915d7f899b8e6ef1d768b0ae" - integrity sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA== - use-isomorphic-layout-effect@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"