В разы улучшена производительность и меьнше багов

This commit is contained in:
2025-07-15 18:11:02 +03:00
parent 40145206b2
commit 75141f5e88
5 changed files with 666 additions and 276 deletions

View File

@@ -22,6 +22,7 @@
"@radix-ui/react-toast": "^1.2.14",
"@reduxjs/toolkit": "^1.9.5",
"@types/react-grid-layout": "^1.3.5",
"@types/react-window": "^1.8.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"immer": "^10.1.1",
@@ -30,6 +31,7 @@
"react-beautiful-dnd": "^13.1.1",
"react-dom": "^18.2.0",
"react-grid-layout": "^1.5.2",
"react-window": "^1.8.11",
"redux": "^4.2.1",
"tailwind-merge": "^3.3.1",
"xlsx": "^0.18.5"

View File

@@ -1,5 +1,6 @@
import { produce } from 'immer'
import {
CSSProperties,
FC,
memo,
useCallback,
@@ -8,6 +9,7 @@ import {
useRef,
useState,
} from 'react'
import { VariableSizeGrid } from 'react-window'
import { useMultiSheetEngine } from '../../hooks/useMultiSheetEngine'
const ROW_COUNT = 90
@@ -29,6 +31,14 @@ interface DualSpreadsheetProps {
templateData?: Record<string, Record<string, any>>
}
// Кэшированные данные ячеек для оптимизации
interface CachedCellData {
displayValue: string
rawValue: string
isModified: boolean
hasRightContent: boolean
}
// --- Child Components ---
interface CellProps {
sheetType: SheetType
@@ -40,12 +50,14 @@ interface CellProps {
displayValue: string // Отображаемое значение (вычисленное)
rawValue: string // "Сырое" значение (формула)
isModified: boolean
hasRightContent: boolean // Есть ли содержимое в ячейках справа
onCellClick: (row: number, col: number) => void
onCellDoubleClick: (row: number, col: number) => void
onCellValueChange: (newValue: string) => void // Изменение значения во время редактирования
stopEditing: (save: boolean) => void
setActiveSheet: (type: SheetType) => void
activeCellRef: React.RefObject<HTMLInputElement>
style: CSSProperties // Добавляем style для react-window
}
const Cell = memo(
@@ -59,24 +71,23 @@ const Cell = memo(
displayValue,
rawValue,
isModified,
hasRightContent,
onCellClick,
onCellDoubleClick,
onCellValueChange,
stopEditing,
setActiveSheet,
activeCellRef,
style, // Добавляем style для react-window
}: CellProps) => {
const className = `border border-border ${isSelected ? 'bg-accent' : ''} ${
isModified ? 'bg-yellow-50' : ''
}`
const style = {
minWidth: `${columnWidth}px`,
width: `${columnWidth}px`,
height: `${ROW_HEIGHT}px`,
overflow: 'hidden',
const cellStyle: CSSProperties = {
...style,
overflow: 'visible',
padding: 0,
position: 'relative' as const,
}
const handleClick = useCallback(() => {
@@ -90,9 +101,9 @@ const Cell = memo(
)
return (
<td
<div
className={className}
style={style}
style={cellStyle}
onClick={handleClick}
onDoubleClick={handleDoubleClick}
>
@@ -116,17 +127,29 @@ const Cell = memo(
/>
) : (
<div
className="relative h-full w-full truncate px-2 py-1"
style={
isSelected
className="relative flex h-full w-full items-center px-2"
style={{
overflow: hasRightContent ? 'hidden' : 'visible',
whiteSpace: 'nowrap',
...(isSelected
? { boxShadow: 'inset 0 0 0 2px hsl(var(--primary))' }
: {}
}
: {}),
}}
>
<div
className="relative"
style={{
overflow: hasRightContent ? 'hidden' : 'visible',
textOverflow: hasRightContent ? 'ellipsis' : 'clip',
whiteSpace: 'nowrap',
maxWidth: hasRightContent ? `${columnWidth - 16}px` : 'none',
}}
>
{displayValue}
</div>
</div>
)}
</td>
</div>
)
},
)
@@ -236,15 +259,82 @@ const FormulaBar = memo(
},
)
// Рендер-проп для ячеек грида
const CellRenderer = ({
columnIndex,
rowIndex,
style,
data,
}: {
columnIndex: number
rowIndex: number
style: CSSProperties
data: any
}) => {
const {
sheetType,
widths,
selectedCell,
activeSheet,
isEditing,
editingValue,
cachedData,
handleCellClick,
handleCellDoubleClick,
handleCellChange,
stopEditing,
setActiveSheet,
activeCellInputRef,
} = data
const isCellSelected =
selectedCell?.row === rowIndex &&
selectedCell?.col === columnIndex &&
activeSheet === sheetType
const isCellEditing = isCellSelected && isEditing
const cellKey = `${rowIndex}-${columnIndex}`
const cellData = cachedData[cellKey]
const rawValue = isCellEditing ? editingValue : cellData?.rawValue || ''
const displayValue = isCellEditing
? '' // Не показывать вычисленное значение во время редактирования
: cellData?.displayValue || ''
return (
<Cell
style={style}
sheetType={sheetType}
rowIndex={rowIndex}
colIndex={columnIndex}
columnWidth={widths[columnIndex]}
isSelected={isCellSelected}
isEditing={isCellEditing}
displayValue={displayValue}
rawValue={rawValue}
isModified={cellData?.isModified || false}
hasRightContent={cellData?.hasRightContent || false}
onCellClick={handleCellClick}
onCellDoubleClick={handleCellDoubleClick}
onCellValueChange={handleCellChange}
stopEditing={stopEditing}
setActiveSheet={setActiveSheet}
activeCellRef={activeCellInputRef}
/>
)
}
// --- Main Component ---
const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
const { revision, ...multiSheetEngine } = useMultiSheetEngine({
const { revision, updateRevision, ...multiSheetEngine } = useMultiSheetEngine(
{
sheets: [
{ name: SHEET_NAMES.report, rows: ROW_COUNT, cols: COL_COUNT },
{ name: SHEET_NAMES.calculations, rows: ROW_COUNT, cols: COL_COUNT },
],
initialData: templateData || {},
})
},
)
const [activeSheet, setActiveSheet] = useState<SheetType>('report')
const [selectedCell, setSelectedCell] = useState<{
@@ -260,6 +350,10 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
calculations: Array(COL_COUNT).fill(96),
}),
)
const gridRefs = useRef<Record<SheetType, VariableSizeGrid | null>>({
report: null,
calculations: null,
})
const containerRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
report: null,
@@ -270,8 +364,22 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
report: null,
calculations: null,
})
const headerRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
report: null,
calculations: null,
})
const rowHeaderRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
report: null,
calculations: null,
})
const initialTemplateValues = useRef<Record<string, string>>({})
// Кэш для данных ячеек
const cellDataCache = useRef<Record<string, Record<string, CachedCellData>>>(
{},
)
const lastRevision = useRef<number>(-1)
// Загрузка данных шаблона один раз при инициализации
useEffect(() => {
const reportTemplate = templateData?.[SHEET_NAMES.report]
@@ -284,6 +392,95 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
// --- Синхронизация UI ---
// Синхронизация прокрутки грида при изменении выделенной ячейки
useEffect(() => {
if (selectedCell && activeSheet) {
const grid = gridRefs.current[activeSheet]
grid?.scrollToItem({
rowIndex: selectedCell.row,
columnIndex: selectedCell.col,
align: 'auto',
})
}
}, [selectedCell, activeSheet])
// Функция для получения кэшированных данных ячеек
const getCachedCellData = useCallback(
(sheetType: SheetType): Record<string, CachedCellData> => {
const cacheKey = `${sheetType}-${revision}`
// Если данные уже кэшированы для этой ревизии, возвращаем их
if (cellDataCache.current[cacheKey]) {
return cellDataCache.current[cacheKey]
}
const sheetName = SHEET_NAMES[sheetType]
const cachedData: Record<string, CachedCellData> = {}
// Предварительно получаем все значения для оптимизации
const allCellValues: Record<string, string> = {}
for (let row = 0; row < ROW_COUNT; row++) {
for (let col = 0; col < COL_COUNT; col++) {
const cellKey = `${row}-${col}`
const displayValue = String(
multiSheetEngine.getCellValue(sheetName, row, col) || '',
)
allCellValues[cellKey] = displayValue.trim()
}
}
// Вычисляем hasRightContent для всех ячеек сразу
const rightContentMap: Record<string, boolean> = {}
for (let row = 0; row < ROW_COUNT; row++) {
let hasContentOnRight = false
for (let col = COL_COUNT - 1; col >= 0; col--) {
const cellKey = `${row}-${col}`
rightContentMap[cellKey] = hasContentOnRight
if (allCellValues[cellKey]) {
hasContentOnRight = true
}
}
}
// Формируем кэшированные данные
for (let row = 0; row < ROW_COUNT; row++) {
for (let col = 0; col < COL_COUNT; col++) {
const cellKey = `${row}-${col}`
const rawValue = multiSheetEngine.getCellRawValue(sheetName, row, col)
const displayValue = allCellValues[cellKey]
const cellName = getColumnLabel(col) + (row + 1)
const templateValue = initialTemplateValues.current[cellName] ?? ''
const isModified =
sheetType === 'report' &&
templateValue !== '' &&
rawValue !== templateValue
cachedData[cellKey] = {
displayValue,
rawValue,
isModified,
hasRightContent: rightContentMap[cellKey],
}
}
}
// Очищаем старые кэши для экономии памяти
if (lastRevision.current !== revision) {
Object.keys(cellDataCache.current).forEach((key) => {
if (!key.endsWith(`-${revision}`)) {
delete cellDataCache.current[key]
}
})
lastRevision.current = revision
}
cellDataCache.current[cacheKey] = cachedData
return cachedData
},
[revision, multiSheetEngine, initialTemplateValues],
)
// Синхронизация строки формул
const formulaBarValue = useMemo(() => {
if (isEditing) {
@@ -309,11 +506,11 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
// Фокус на инпуте при начале редактирования
useEffect(() => {
if (isEditing) {
if (activeCellInputRef.current) {
activeCellInputRef.current.focus()
activeCellInputRef.current.select()
}
if (isEditing && activeCellInputRef.current) {
const input = activeCellInputRef.current
input.focus()
const length = input.value.length
input.setSelectionRange(length, length)
}
}, [isEditing])
@@ -341,13 +538,16 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
selectedCell.col,
editingValue,
)
// Немедленно обновляем интерфейс для быстрого отклика
updateRevision()
// Запускаем отложенный пересчет для формул
multiSheetEngine.debouncedRecalc()
}
setIsEditing(false)
setEditingValue('') // Очищаем временное значение
containerRefs.current[activeSheet]?.focus({ preventScroll: true })
},
[activeSheet, selectedCell, editingValue, multiSheetEngine],
[activeSheet, selectedCell, editingValue, multiSheetEngine, updateRevision],
)
const handleCellChange = useCallback(
@@ -359,16 +559,25 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
[isEditing],
)
// Оптимизированная функция очистки ячейки
const handleClearCell = useCallback(() => {
if (!selectedCell) return
const sheetName = SHEET_NAMES[activeSheet]
multiSheetEngine.setCellValue(
// Используем версию без немедленного пересчета для быстрой реакции
multiSheetEngine.setCellValueWithoutRecalc(
sheetName,
selectedCell.row,
selectedCell.col,
'',
)
}, [activeSheet, selectedCell, multiSheetEngine])
// Немедленно обновляем интерфейс для быстрого отклика
updateRevision()
// Запускаем отложенный пересчет
multiSheetEngine.debouncedRecalc()
}, [activeSheet, selectedCell, multiSheetEngine, updateRevision])
const moveSelection = useCallback(
(deltaRow: number, deltaCol: number) => {
@@ -457,6 +666,11 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
setColumnWidths(
produce((draft) => {
draft[sheetType][colIndex] = Math.max(60, newWidth)
// Принудительно пересчитываем layout грида
const grid = gridRefs.current[sheetType]
if (grid) {
grid.resetAfterColumnIndex(colIndex)
}
}),
)
},
@@ -507,10 +721,42 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
[stopEditing, moveSelection, activeSheet],
)
const onGridScroll = useCallback(
(
sheetType: SheetType,
{ scrollLeft, scrollTop }: { scrollLeft: number; scrollTop: number },
) => {
if (headerRefs.current[sheetType]) {
headerRefs.current[sheetType]!.scrollLeft = scrollLeft
}
if (rowHeaderRefs.current[sheetType]) {
rowHeaderRefs.current[sheetType]!.scrollTop = scrollTop
}
},
[],
)
// --- Render Functions ---
const renderSpreadsheet = (sheetType: SheetType) => {
const renderSpreadsheet = useCallback(
(sheetType: SheetType) => {
const widths = columnWidths[sheetType]
const sheetName = SHEET_NAMES[sheetType]
const cachedData = getCachedCellData(sheetType)
const itemData = {
sheetType,
widths,
selectedCell,
activeSheet,
isEditing,
editingValue,
cachedData,
handleCellClick,
handleCellDoubleClick,
handleCellChange,
stopEditing,
setActiveSheet,
activeCellInputRef,
}
return (
<div
@@ -519,6 +765,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
onKeyDown={handleKeyDown}
tabIndex={0}
>
{/* Header */}
<div className="flex-shrink-0 border-b bg-muted/50 px-3 py-1">
<div className="flex items-center space-x-2">
<div
@@ -531,15 +778,38 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
</h3>
</div>
</div>
<div className="flex-1 overflow-auto">
<table
className="w-full border-collapse"
style={{ tableLayout: 'fixed' }}
{/* Spreadsheet Body */}
<div className="flex flex-1">
{/* Row Headers */}
<div className="flex-shrink-0 bg-muted">
<div className="flex h-7 w-10 items-center justify-center border-b border-r border-border" />
<div
ref={(el) => (rowHeaderRefs.current[sheetType] = el)}
className="overflow-y-hidden"
style={{ height: 600 }} // This should be dynamic based on container size
>
<thead>
<tr>
<th className="h-7 w-10 border border-border bg-muted text-xs font-medium text-muted-foreground"></th>
{Array.from({ length: COL_COUNT }, (_, i) => {
<div>
{Array.from({ length: ROW_COUNT }).map((_, rowIndex) => (
<div
key={rowIndex}
className="flex h-7 w-10 items-center justify-center border-b border-r border-border text-xs font-medium text-muted-foreground"
>
{rowIndex + 1}
</div>
))}
</div>
</div>
</div>
<div className="flex-1 overflow-hidden">
{/* Column Headers */}
<div
ref={(el) => (headerRefs.current[sheetType] = el)}
className="overflow-x-hidden"
>
<div className="flex">
{Array.from({ length: COL_COUNT }).map((_, i) => {
const handleMouseDown = (e: React.MouseEvent) => {
e.preventDefault()
const startX = e.clientX
@@ -551,7 +821,10 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
}
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener(
'mousemove',
handleMouseMove,
)
document.removeEventListener('mouseup', handleMouseUp)
}
@@ -559,9 +832,9 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
document.addEventListener('mouseup', handleMouseUp)
}
return (
<th
<div
key={i}
className="relative h-7 border border-border bg-muted text-center text-xs font-medium text-muted-foreground"
className="relative flex h-7 flex-shrink-0 items-center justify-center border-b border-r border-border bg-muted text-center text-xs font-medium text-muted-foreground"
style={{ width: widths[i] }}
>
{getColumnLabel(i)}
@@ -569,105 +842,58 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
className="absolute right-0 top-0 h-full w-1 cursor-col-resize hover:bg-primary hover:bg-opacity-50"
onMouseDown={handleMouseDown}
/>
</th>
</div>
)
})}
</tr>
</thead>
<tbody>
{Array.from({ length: ROW_COUNT }).map((_, rowIndex) => (
<tr key={rowIndex}>
<td className="h-7 w-10 border border-border bg-muted text-center text-xs font-medium text-muted-foreground">
{rowIndex + 1}
</td>
{Array.from({ length: COL_COUNT }).map((_, colIndex) => {
const isCellSelected =
selectedCell?.row === rowIndex &&
selectedCell?.col === colIndex &&
activeSheet === sheetType
const isCellEditing = isCellSelected && isEditing
</div>
</div>
const rawValue = isCellEditing
? editingValue
: multiSheetEngine.getCellRawValue(
sheetName,
rowIndex,
colIndex,
)
const displayValue = isCellEditing
? '' // Не показывать вычисленное значение во время редактирования
: String(
multiSheetEngine.getCellValue(
sheetName,
rowIndex,
colIndex,
) || '',
)
const cellName = getColumnLabel(colIndex) + (rowIndex + 1)
const templateValue =
initialTemplateValues.current[cellName] ?? ''
const isModified =
sheetType === 'report' &&
templateValue !== '' &&
rawValue !== templateValue
return (
<Cell
key={colIndex}
sheetType={sheetType}
rowIndex={rowIndex}
colIndex={colIndex}
columnWidth={widths[colIndex]}
isSelected={isCellSelected}
isEditing={isCellEditing}
displayValue={displayValue}
rawValue={rawValue}
isModified={isModified}
onCellClick={handleCellClick}
onCellDoubleClick={handleCellDoubleClick}
onCellValueChange={handleCellChange}
stopEditing={stopEditing}
setActiveSheet={setActiveSheet}
activeCellRef={activeCellInputRef}
/>
)
})}
</tr>
))}
</tbody>
</table>
{/* Grid */}
<VariableSizeGrid
ref={(el) => (gridRefs.current[sheetType] = el)}
columnCount={COL_COUNT}
rowCount={ROW_COUNT}
columnWidth={(index: number) => widths[index]}
rowHeight={() => ROW_HEIGHT}
height={600} // This should be dynamic based on container size
width={800} // This should be dynamic based on container size
itemData={itemData}
onScroll={(e) => onGridScroll(sheetType, e)}
>
{CellRenderer}
</VariableSizeGrid>
</div>
</div>
</div>
)
}
// Используем revision в качестве зависимости, чтобы гарантировать перерисовку
// при изменении данных в движке.
const memoizedReportSheet = useMemo(
() => renderSpreadsheet('report'),
// eslint-disable-next-line react-hooks/exhaustive-deps
},
[
columnWidths.report,
activeSheet,
columnWidths,
getCachedCellData,
handleKeyDown,
handleColumnResize,
selectedCell,
activeSheet,
isEditing,
editingValue,
revision,
handleCellClick,
handleCellDoubleClick,
handleCellChange,
stopEditing,
setActiveSheet,
onGridScroll,
],
)
// Мемоизированные компоненты листов
const memoizedReportSheet = useMemo(
() => renderSpreadsheet('report'),
[renderSpreadsheet, revision], // Добавляем revision для перерендера
)
const memoizedCalculationsSheet = useMemo(
() => renderSpreadsheet('calculations'),
// eslint-disable-next-line react-hooks/exhaustive-deps
[
columnWidths.calculations,
activeSheet,
selectedCell,
isEditing,
editingValue,
revision,
],
[renderSpreadsheet, revision], // Добавляем revision для перерендера
)
return (

View File

@@ -30,6 +30,28 @@ export function useMultiSheetEngine({
const debouncedRecalcTimeoutRef = useRef<number | null>(null)
const isRecalculatingRef = useRef(false)
// Безопасная функция для вычислений
const safeRecalc = useCallback(() => {
if (!workbookRef.current || isRecalculatingRef.current) return
isRecalculatingRef.current = true
setIsCalculating(true)
try {
workbookRef.current.recalc()
} catch (error) {
console.warn('Ошибка при вычислении:', error)
} finally {
// Уменьшаем задержку для быстрого отклика
setTimeout(() => {
setIsCalculating(false)
isRecalculatingRef.current = false
// Увеличиваем ревизию, чтобы сообщить компонентам о необходимости обновления
setRevision((r) => r + 1)
}, 50) // Уменьшено с 150ms до 50ms
}
}, [])
// Инициализация workbook и листов
useEffect(() => {
if (!workbookRef.current) {
@@ -50,8 +72,7 @@ export function useMultiSheetEngine({
setRevision((r) => r + 1)
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []) // Зависимости убраны, чтобы инициализация проходила один раз
}, [initialData, safeRecalc, sheets]) // Восстанавливаем зависимости
// Синхронизация всех листов из движка
const syncAllSheetsFromEngine = useCallback(() => {
@@ -89,28 +110,6 @@ export function useMultiSheetEngine({
// setSheetCells(newSheetCells) // Удалено, так как sheetCells убрано
}, [sheets])
// Безопасная функция для вычислений
const safeRecalc = useCallback(() => {
if (!workbookRef.current || isRecalculatingRef.current) return
isRecalculatingRef.current = true
setIsCalculating(true)
try {
workbookRef.current.recalc()
} catch (error) {
console.warn('Ошибка при вычислении:', error)
} finally {
// Небольшая задержка для визуального индикатора
setTimeout(() => {
setIsCalculating(false)
isRecalculatingRef.current = false
// Увеличиваем ревизию, чтобы сообщить компонентам о необходимости обновления
setRevision((r) => r + 1)
}, 150)
}
}, [])
// Отложенный пересчет с дебаунсом
const debouncedRecalc = useCallback(() => {
if (!workbookRef.current || isRecalculatingRef.current) return
@@ -120,12 +119,17 @@ export function useMultiSheetEngine({
clearTimeout(debouncedRecalcTimeoutRef.current)
}
// Запускаем пересчет через 300ms
// Уменьшаем задержку для быстрого отклика
debouncedRecalcTimeoutRef.current = setTimeout(() => {
safeRecalc()
}, 300)
}, 100) // Уменьшено с 300ms до 100ms
}, [safeRecalc])
// Функция для немедленного обновления интерфейса без пересчета
const updateRevision = useCallback(() => {
setRevision((r) => r + 1)
}, [])
// Установка значения ячейки без немедленного пересчета
const setCellValueWithoutRecalc = useCallback(
(sheetName: string, row: number, col: number, value: string) => {
@@ -230,8 +234,6 @@ export function useMultiSheetEngine({
// Пересчет всех формул
const recalculate = useCallback(() => {
if (!workbookRef.current) return
safeRecalc()
}, [safeRecalc])
@@ -250,6 +252,7 @@ export function useMultiSheetEngine({
setCellValue,
setCellValueWithoutRecalc,
debouncedRecalc,
updateRevision, // Добавляем новую функцию
getCellValue,
getCellRawValue,
getModifiedCells,

View File

@@ -1,46 +1,45 @@
ц// Типы элементов интерфейса
export type ElementType = 'text' | 'select' | 'radio' | 'checkbox' | 'number' | 'textarea' | 'date';
// Типы элементов интерфейса
export type ElementType =
| 'text'
| 'select'
| 'radio'
| 'checkbox'
| 'number'
| 'textarea'
| 'date'
export interface ElementOption {
value: string;
label: string;
value: string
label: string
}
export interface TemplateElement {
id: string;
type: ElementType;
name: string;
label: string;
targetCell: string; // например "A1", "B5"
options?: ElementOption[]; // для select и radio
required?: boolean;
defaultValue?: string;
placeholder?: string;
id: string
type: ElementType
name: string
label: string
targetCell: string // например "A1", "B5"
options?: ElementOption[] // для select и radio
required?: boolean
defaultValue?: string
placeholder?: string
}
// Типы шаблонов
export interface Template {
id: string;
name: string;
description?: string;
excelFile?: File;
excelData?: Record<string, any>; // данные из Excel
elements: TemplateElement[];
createdAt: Date;
updatedAt: Date;
id: string
name: string
description?: string
excelFile?: File
excelData?: Record<string, any> // данные из Excel
elements: TemplateElement[]
createdAt: Date
updatedAt: Date
}
// Типы для работы с данными
export interface TemplateData {
templateId: string;
values: Record<string, any>; // elementId -> value
calculatedCells?: Record<string, any>; // cellName -> value
}
// Типы для экспорта
export interface ExportData {
templateId: string;
templateName: string;
excelFile: File;
cellUpdates: Record<string, any>; // cellName -> value
templateId: string
values: Record<string, any> // elementId -> value
calculatedCells?: Record<string, any> // cellName -> value
}

252
yarn.lock
View File

@@ -12,6 +12,11 @@
resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@babel/runtime@^7.0.0":
version "7.27.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6"
integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==
"@babel/runtime@^7.12.1", "@babel/runtime@^7.15.4", "@babel/runtime@^7.9.2":
version "7.22.5"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz"
@@ -19,11 +24,116 @@
dependencies:
regenerator-runtime "^0.13.11"
"@esbuild/android-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==
"@esbuild/android-arm@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d"
integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==
"@esbuild/android-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1"
integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==
"@esbuild/darwin-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz"
integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==
"@esbuild/darwin-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb"
integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==
"@esbuild/freebsd-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2"
integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==
"@esbuild/freebsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4"
integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==
"@esbuild/linux-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb"
integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==
"@esbuild/linux-arm@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a"
integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==
"@esbuild/linux-ia32@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a"
integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==
"@esbuild/linux-loong64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72"
integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==
"@esbuild/linux-mips64el@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289"
integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==
"@esbuild/linux-ppc64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7"
integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==
"@esbuild/linux-riscv64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09"
integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==
"@esbuild/linux-s390x@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829"
integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==
"@esbuild/linux-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
"@esbuild/netbsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462"
integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==
"@esbuild/openbsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691"
integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==
"@esbuild/sunos-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273"
integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==
"@esbuild/win32-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f"
integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==
"@esbuild/win32-ia32@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03"
integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==
"@esbuild/win32-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
@@ -121,16 +231,16 @@
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.15"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/sourcemap-codec@1.4.14":
version "1.4.14"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.15"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.18"
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz"
@@ -147,7 +257,7 @@
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -544,6 +654,51 @@
resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.67.tgz"
integrity sha512-zCT2mCkOBVNf5uJDcQ3A9KDoO1OEaGdfjsRTZTo7sejDd9AXLfJg+xgyCBBrK2jNS/uWcT21IvSv3LqKp4K8pA==
"@swc/core-darwin-x64@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.67.tgz#49da279b06232a388e9c9179db1cbff81d3dee18"
integrity sha512-hXTVsfTatPEec5gFVyjGj3NccKZsYj/OXyHn6XA+l3Q76lZzGm2ISHdku//XNwXu8OmJ0HhS7LPsC4XXwxXQhg==
"@swc/core-linux-arm-gnueabihf@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.67.tgz#668645ac62ea7beb4319d177f43cdefb0326cd90"
integrity sha512-l8AKL0RkDL5FRTeWMmjoz9zvAc37amxC+0rheaNwE+gZya7ObyNjnIYz5FwN+3y+z6JFU7LS2x/5f6iwruv6pg==
"@swc/core-linux-arm64-gnu@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.67.tgz#709bccc5ced37b64ab5ae479bf73fc2ab5ef0b48"
integrity sha512-S8zOB1AXEpb7kmtgMaFNeLAj01VOky4B0RNZ+uJWigdrDiFT67FeZzNHUNmNSOU0QM79G+Lie/xD/beqEw0vDg==
"@swc/core-linux-arm64-musl@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.67.tgz#9187378e17200b1ffb3d06b78c4a33f85dd12efb"
integrity sha512-Fex8J8ASrt13pmOr2xWh41tEeKWwXYGk3sV8L/aGHiYtIJEUi2f+RtMx3jp7LIdOD8pQptor7i5WBlfR9jhp8A==
"@swc/core-linux-x64-gnu@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.67.tgz#bcdaf46c430bc85a59ae9b38ab9bd540aa1fbd2d"
integrity sha512-9bz9/bMphrv5vDg0os/d8ve0QgFpDzJgZgHUaHiGwcmfnlgdOSAaYJLIvWdcGTjZuQeV4L0m+iru357D9TXEzA==
"@swc/core-linux-x64-musl@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.67.tgz#fbb63517cd72eaa3250726a4209c179ada520a57"
integrity sha512-ED0H6oLvQmhgo9zs8usmEA/lcZPGTu7K9og9K871b7HhHX0h/R+Xg2pb5KD7S/GyUHpfuopxjVROm+h6X1jMUA==
"@swc/core-win32-arm64-msvc@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.67.tgz#dadce08f9245c57e9c54c1bbcc815c4bd2077fba"
integrity sha512-J1yFDLgPFeRtA8t5E159OXX+ww1gbkFg70yr4OP7EsOkOD1uMkuTf9yK/woHfsaVJlUYjJHzw7MkUIEgQBucqQ==
"@swc/core-win32-ia32-msvc@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.67.tgz#be026a3a389e64c24fe67a329c04eccf744ac45e"
integrity sha512-bK11/KtasewqHxzkjKUBXRE9MSAidbZCxrgJUd49bItG2N/DHxkwMYu8Xkh5VDHdTYWv/2idYtf/VM9Yi+53qw==
"@swc/core-win32-x64-msvc@1.3.67":
version "1.3.67"
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.67.tgz#6fe2f3854d91b58f6e0b00f99366cfd84334b2ea"
integrity sha512-GxzUU3+NA3cPcYxCxtfSQIS2ySD7Z8IZmKTVaWA9GOUQbKLyCE8H5js31u39+0op/1gNgxOgYFDoj2lUyvLCqw==
"@swc/core@^1.3.61":
version "1.3.67"
resolved "https://registry.npmjs.org/@swc/core/-/core-1.3.67.tgz"
@@ -585,7 +740,7 @@
dependencies:
"@types/react" "*"
"@types/react-dom@*", "@types/react-dom@^16.8 || ^17.0 || ^18.0", "@types/react-dom@^18.0.11":
"@types/react-dom@^18.0.11":
version "18.2.6"
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.6.tgz"
integrity sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==
@@ -609,7 +764,14 @@
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react@*", "@types/react@^16.8 || ^17.0 || ^18.0", "@types/react@^18.0.37":
"@types/react-window@^1.8.8":
version "1.8.8"
resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.8.tgz#c20645414d142364fbe735818e1c1e0a145696e3"
integrity sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.37":
version "18.2.14"
resolved "https://registry.npmjs.org/@types/react/-/react-18.2.14.tgz"
integrity sha512-A0zjq+QN/O0Kpe30hA1GidzyFjatVvrpIvWLxD+xv67Vt91TWWgco9IvrJBkeyHm1trGaFS/FSGqPlhyeZRm0g==
@@ -649,7 +811,7 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.59.0":
"@typescript-eslint/parser@^5.59.0":
version "5.60.1"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.60.1.tgz"
integrity sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==
@@ -729,7 +891,7 @@ acorn-jsx@^5.3.2:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
acorn@^8.9.0:
version "8.9.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz"
integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==
@@ -833,7 +995,7 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
browserslist@^4.21.5, "browserslist@>= 4.21.0":
browserslist@^4.21.5:
version "4.21.9"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz"
integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==
@@ -1097,7 +1259,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz"
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
eslint@*, "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8.38.0, eslint@>=7:
eslint@^8.38.0:
version "8.44.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz"
integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==
@@ -1302,18 +1464,6 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
glob@^7.1.3:
version "7.2.3"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.1.6:
version "7.1.6"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz"
@@ -1326,6 +1476,18 @@ glob@7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.3:
version "7.2.3"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^13.19.0:
version "13.20.0"
resolved "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz"
@@ -1537,7 +1699,7 @@ lucide-react@^0.525.0:
resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz"
integrity sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==
memoize-one@^5.1.1:
"memoize-one@>=3.1.1 <6", memoize-one@^5.1.1:
version "5.2.1"
resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
@@ -1753,7 +1915,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8, postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.24, postcss@>=8.0.9:
postcss@^8.4.23, postcss@^8.4.24:
version "8.4.24"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz"
integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==
@@ -1772,7 +1934,7 @@ prettier-plugin-tailwindcss@^0.4.1:
resolved "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz"
integrity sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==
"prettier@^2.2 || ^3.0", prettier@2.8.8:
prettier@2.8.8:
version "2.8.8"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
@@ -1782,7 +1944,7 @@ process@^0.11.1:
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
prop-types@^15.7.2, prop-types@^15.8.1, prop-types@15.x:
prop-types@15.x, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -1819,7 +1981,7 @@ react-beautiful-dnd@^13.1.1:
redux "^4.0.4"
use-memo-one "^1.1.1"
"react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8.5 || ^17.0.0 || ^18.0.0", react-dom@^18.2.0, "react-dom@>= 16.3.0", react-dom@>=16.8, react-dom@>=16.8.0:
react-dom@^18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
@@ -1847,12 +2009,7 @@ react-grid-layout@^1.5.2:
react-resizable "^3.0.5"
resize-observer-polyfill "^1.5.1"
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^16.7.0:
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -1879,7 +2036,7 @@ react-redux@^7.2.0:
prop-types "^15.7.2"
react-is "^17.0.2"
"react-redux@^7.2.1 || ^8.0.2", react-redux@^8.1.1:
react-redux@^8.1.1:
version "8.1.1"
resolved "https://registry.npmjs.org/react-redux/-/react-redux-8.1.1.tgz"
integrity sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==
@@ -1941,7 +2098,15 @@ react-style-singleton@^2.2.2, react-style-singleton@^2.2.3:
get-nonce "^1.0.0"
tslib "^2.0.0"
"react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.3 || ^17 || ^18", "react@^16.8.5 || ^17.0.0 || ^18.0.0", "react@^16.9.0 || ^17.0.0 || ^18", react@^18.2.0, "react@>= 16.3", "react@>= 16.3.0", react@>=16.8, react@>=16.8.0:
react-window@^1.8.11:
version "1.8.11"
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.11.tgz#a857b48fa85bd77042d59cc460964ff2e0648525"
integrity sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==
dependencies:
"@babel/runtime" "^7.0.0"
memoize-one ">=3.1.1 <6"
react@^18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@@ -1967,7 +2132,7 @@ redux-thunk@^2.4.2:
resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz"
integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
redux@^4, "redux@^4 || ^5.0.0-beta.0", redux@^4.0.0, redux@^4.0.4, redux@^4.2.1:
redux@^4.0.0, redux@^4.0.4, redux@^4.2.1:
version "4.2.1"
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
@@ -2184,12 +2349,7 @@ tslib@^1.8.1:
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.0:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
tslib@^2.1.0:
tslib@^2.0.0, tslib@^2.1.0:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -2213,7 +2373,7 @@ type-fest@^0.20.2:
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
typescript@^5.0.2, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta":
typescript@^5.0.2:
version "5.1.6"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz"
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
@@ -2270,7 +2430,7 @@ util@^0.10.3:
dependencies:
inherits "2.0.3"
vite@^4, vite@^4.3.9:
vite@^4.3.9:
version "4.3.9"
resolved "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz"
integrity sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==