Checkpoint: Ajout du support XLSX natif via la librairie SheetJS (xlsx). Un helper fileToRows() unifie la lecture CSV et XLSX : pour XLSX, lecture via arrayBuffer + XLSX.read + sheet_to_json ; pour CSV, détection du séparateur et split classique. Le parsing ISI-APP fonctionne désormais identiquement sur les deux formats. Les métadonnées d'import incluent le format détecté (isi-app ou classique).
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
// Design: Corporate Modernism — Itinova Budget SI
|
// Design: Corporate Modernism — Itinova Budget SI
|
||||||
|
|
||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
import * as XLSX from 'xlsx';
|
||||||
import {
|
import {
|
||||||
Upload,
|
Upload,
|
||||||
X,
|
X,
|
||||||
@@ -21,6 +22,25 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
|
// ─── Helper : lecture fichier → tableau de lignes (CSV ou XLSX) ────────────────
|
||||||
|
async function fileToRows(file: File): Promise<string[][]> {
|
||||||
|
const isXlsx = file.name.match(/\.(xlsx|xls)$/i);
|
||||||
|
if (isXlsx) {
|
||||||
|
const buffer = await file.arrayBuffer();
|
||||||
|
const wb = XLSX.read(buffer, { type: 'array', cellDates: true });
|
||||||
|
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||||
|
// sheet_to_json avec header:1 retourne un tableau de tableaux
|
||||||
|
const rows = XLSX.utils.sheet_to_json<string[]>(ws, { header: 1, defval: '' });
|
||||||
|
return rows.map(r => r.map(c => String(c ?? '').trim()));
|
||||||
|
} else {
|
||||||
|
// CSV : détection du séparateur
|
||||||
|
const text = await file.text();
|
||||||
|
const lines = text.split('\n').filter(l => l.trim());
|
||||||
|
const sep = lines[0].includes(';') ? ';' : ',';
|
||||||
|
return lines.map(l => l.split(sep).map(c => c.trim().replace(/"/g, '').replace(/[\r\n]/g, '')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export interface Etablissement {
|
export interface Etablissement {
|
||||||
@@ -274,17 +294,15 @@ export function ImportModal({ open, onClose }: ImportModalProps) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = await file.text();
|
// Lecture unifiée CSV + XLSX via SheetJS
|
||||||
const lines = text.split('\n').filter(l => l.trim());
|
const rows = await fileToRows(file);
|
||||||
if (lines.length < 2) {
|
if (rows.length < 2) {
|
||||||
setInventaireStatus('error');
|
setInventaireStatus('error');
|
||||||
setInventaireMsg('Fichier vide ou format invalide (moins de 2 lignes)');
|
setInventaireMsg('Fichier vide ou format invalide (moins de 2 lignes)');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Détection du séparateur
|
const rawHeaders = rows[0].map(h => h.toLowerCase().replace(/[\r\n]/g, ''));
|
||||||
const sep = lines[0].includes(';') ? ';' : ',';
|
|
||||||
const rawHeaders = lines[0].split(sep).map(h => h.trim().toLowerCase().replace(/"/g, '').replace(/[\r\n]/g, ''));
|
|
||||||
|
|
||||||
// ── Format ISI-APP : extraction par libellé et entité ──────────────────
|
// ── Format ISI-APP : extraction par libellé et entité ──────────────────
|
||||||
// Colonne "libellé" : contient le code poste (ex: 1083MAS-F4833)
|
// Colonne "libellé" : contient le code poste (ex: 1083MAS-F4833)
|
||||||
@@ -344,8 +362,7 @@ export function ImportModal({ open, onClose }: ImportModalProps) {
|
|||||||
|
|
||||||
// Extraction des établissements uniques depuis l'inventaire
|
// Extraction des établissements uniques depuis l'inventaire
|
||||||
const etabMap = new Map<string, { nom: string; groupe?: string; ville?: string }>();
|
const etabMap = new Map<string, { nom: string; groupe?: string; ville?: string }>();
|
||||||
for (const line of lines.slice(1)) {
|
for (const cols of rows.slice(1)) {
|
||||||
const cols = line.split(sep).map(c => c.trim().replace(/"/g, '').replace(/[\r\n]/g, ''));
|
|
||||||
|
|
||||||
let code = '';
|
let code = '';
|
||||||
let nom = '';
|
let nom = '';
|
||||||
@@ -412,11 +429,12 @@ export function ImportModal({ open, onClose }: ImportModalProps) {
|
|||||||
saveEtablissements(merged);
|
saveEtablissements(merged);
|
||||||
|
|
||||||
// Enregistrement des métadonnées du fichier importé
|
// Enregistrement des métadonnées du fichier importé
|
||||||
|
const nbLignes = rows.length - 1;
|
||||||
localStorage.setItem('budgetsi_inventaire_import', JSON.stringify({
|
localStorage.setItem('budgetsi_inventaire_import', JSON.stringify({
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
date: new Date().toISOString(),
|
date: new Date().toISOString(),
|
||||||
size: file.size,
|
size: file.size,
|
||||||
nbLignes: lines.length - 1,
|
nbLignes,
|
||||||
nbEtablissements: etabMap.size,
|
nbEtablissements: etabMap.size,
|
||||||
nbFixes: useIsiFormat ? nbFixes : null,
|
nbFixes: useIsiFormat ? nbFixes : null,
|
||||||
nbPortables: useIsiFormat ? nbPortables : null,
|
nbPortables: useIsiFormat ? nbPortables : null,
|
||||||
@@ -424,7 +442,7 @@ export function ImportModal({ open, onClose }: ImportModalProps) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const details = [
|
const details = [
|
||||||
`${lines.length - 1} poste${lines.length > 2 ? 's' : ''}`,
|
`${nbLignes} poste${nbLignes > 1 ? 's' : ''}`,
|
||||||
`${etabMap.size} établissement${etabMap.size > 1 ? 's' : ''} détectés`,
|
`${etabMap.size} établissement${etabMap.size > 1 ? 's' : ''} détectés`,
|
||||||
nbNouveaux > 0 ? `${nbNouveaux} nouveau${nbNouveaux > 1 ? 'x' : ''}` : null,
|
nbNouveaux > 0 ? `${nbNouveaux} nouveau${nbNouveaux > 1 ? 'x' : ''}` : null,
|
||||||
nbMisAJour > 0 ? `${nbMisAJour} mis à jour` : null,
|
nbMisAJour > 0 ? `${nbMisAJour} mis à jour` : null,
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vaul": "^1.1.2",
|
"vaul": "^1.1.2",
|
||||||
"wouter": "^3.3.5",
|
"wouter": "^3.3.5",
|
||||||
|
"xlsx": "^0.18.5",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
72
pnpm-lock.yaml
generated
72
pnpm-lock.yaml
generated
@@ -166,6 +166,9 @@ importers:
|
|||||||
wouter:
|
wouter:
|
||||||
specifier: ^3.3.5
|
specifier: ^3.3.5
|
||||||
version: 3.7.1(patch_hash=4e16e6ff3fde7d6c1024d3e0c8605dc9eb6afb690d0d49958c2f449091813072)(react@19.2.1)
|
version: 3.7.1(patch_hash=4e16e6ff3fde7d6c1024d3e0c8605dc9eb6afb690d0d49958c2f449091813072)(react@19.2.1)
|
||||||
|
xlsx:
|
||||||
|
specifier: ^0.18.5
|
||||||
|
version: 0.18.5
|
||||||
zod:
|
zod:
|
||||||
specifier: ^4.1.12
|
specifier: ^4.1.12
|
||||||
version: 4.1.12
|
version: 4.1.12
|
||||||
@@ -1786,6 +1789,10 @@ packages:
|
|||||||
add@2.0.6:
|
add@2.0.6:
|
||||||
resolution: {integrity: sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==}
|
resolution: {integrity: sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==}
|
||||||
|
|
||||||
|
adler-32@1.3.1:
|
||||||
|
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
aria-hidden@1.2.6:
|
aria-hidden@1.2.6:
|
||||||
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -1848,6 +1855,10 @@ packages:
|
|||||||
ccount@2.0.1:
|
ccount@2.0.1:
|
||||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||||
|
|
||||||
|
cfb@1.2.2:
|
||||||
|
resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
chai@5.3.3:
|
chai@5.3.3:
|
||||||
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -1893,6 +1904,10 @@ packages:
|
|||||||
react: ^18 || ^19 || ^19.0.0-rc
|
react: ^18 || ^19 || ^19.0.0-rc
|
||||||
react-dom: ^18 || ^19 || ^19.0.0-rc
|
react-dom: ^18 || ^19 || ^19.0.0-rc
|
||||||
|
|
||||||
|
codepage@1.15.0:
|
||||||
|
resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@@ -1938,6 +1953,11 @@ packages:
|
|||||||
cose-base@2.2.0:
|
cose-base@2.2.0:
|
||||||
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
|
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
|
||||||
|
|
||||||
|
crc-32@1.2.2:
|
||||||
|
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
cssesc@3.0.0:
|
cssesc@3.0.0:
|
||||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -2316,6 +2336,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
frac@1.1.2:
|
||||||
|
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
fraction.js@4.3.7:
|
fraction.js@4.3.7:
|
||||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||||
|
|
||||||
@@ -3179,6 +3203,10 @@ packages:
|
|||||||
space-separated-tokens@2.0.2:
|
space-separated-tokens@2.0.2:
|
||||||
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
||||||
|
|
||||||
|
ssf@0.11.2:
|
||||||
|
resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
stackback@0.0.2:
|
stackback@0.0.2:
|
||||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||||
|
|
||||||
@@ -3517,11 +3545,24 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
wmf@1.0.2:
|
||||||
|
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
word@0.3.0:
|
||||||
|
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
wouter@3.7.1:
|
wouter@3.7.1:
|
||||||
resolution: {integrity: sha512-od5LGmndSUzntZkE2R5CHhoiJ7YMuTIbiXsa0Anytc2RATekgv4sfWRAxLEULBrp7ADzinWQw8g470lkT8+fOw==}
|
resolution: {integrity: sha512-od5LGmndSUzntZkE2R5CHhoiJ7YMuTIbiXsa0Anytc2RATekgv4sfWRAxLEULBrp7ADzinWQw8g470lkT8+fOw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=16.8.0'
|
react: '>=16.8.0'
|
||||||
|
|
||||||
|
xlsx@0.18.5:
|
||||||
|
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
yallist@3.1.1:
|
yallist@3.1.1:
|
||||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||||
|
|
||||||
@@ -5027,6 +5068,8 @@ snapshots:
|
|||||||
|
|
||||||
add@2.0.6: {}
|
add@2.0.6: {}
|
||||||
|
|
||||||
|
adler-32@1.3.1: {}
|
||||||
|
|
||||||
aria-hidden@1.2.6:
|
aria-hidden@1.2.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@@ -5102,6 +5145,11 @@ snapshots:
|
|||||||
|
|
||||||
ccount@2.0.1: {}
|
ccount@2.0.1: {}
|
||||||
|
|
||||||
|
cfb@1.2.2:
|
||||||
|
dependencies:
|
||||||
|
adler-32: 1.3.1
|
||||||
|
crc-32: 1.2.2
|
||||||
|
|
||||||
chai@5.3.3:
|
chai@5.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
assertion-error: 2.0.1
|
assertion-error: 2.0.1
|
||||||
@@ -5154,6 +5202,8 @@ snapshots:
|
|||||||
- '@types/react'
|
- '@types/react'
|
||||||
- '@types/react-dom'
|
- '@types/react-dom'
|
||||||
|
|
||||||
|
codepage@1.15.0: {}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
@@ -5188,6 +5238,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
layout-base: 2.0.1
|
layout-base: 2.0.1
|
||||||
|
|
||||||
|
crc-32@1.2.2: {}
|
||||||
|
|
||||||
cssesc@3.0.0: {}
|
cssesc@3.0.0: {}
|
||||||
|
|
||||||
csstype@3.1.3: {}
|
csstype@3.1.3: {}
|
||||||
@@ -5622,6 +5674,8 @@ snapshots:
|
|||||||
|
|
||||||
forwarded@0.2.0: {}
|
forwarded@0.2.0: {}
|
||||||
|
|
||||||
|
frac@1.1.2: {}
|
||||||
|
|
||||||
fraction.js@4.3.7: {}
|
fraction.js@4.3.7: {}
|
||||||
|
|
||||||
framer-motion@12.23.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
|
framer-motion@12.23.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
|
||||||
@@ -6837,6 +6891,10 @@ snapshots:
|
|||||||
|
|
||||||
space-separated-tokens@2.0.2: {}
|
space-separated-tokens@2.0.2: {}
|
||||||
|
|
||||||
|
ssf@0.11.2:
|
||||||
|
dependencies:
|
||||||
|
frac: 1.1.2
|
||||||
|
|
||||||
stackback@0.0.2: {}
|
stackback@0.0.2: {}
|
||||||
|
|
||||||
statuses@2.0.1: {}
|
statuses@2.0.1: {}
|
||||||
@@ -7176,6 +7234,10 @@ snapshots:
|
|||||||
siginfo: 2.0.0
|
siginfo: 2.0.0
|
||||||
stackback: 0.0.2
|
stackback: 0.0.2
|
||||||
|
|
||||||
|
wmf@1.0.2: {}
|
||||||
|
|
||||||
|
word@0.3.0: {}
|
||||||
|
|
||||||
wouter@3.7.1(patch_hash=4e16e6ff3fde7d6c1024d3e0c8605dc9eb6afb690d0d49958c2f449091813072)(react@19.2.1):
|
wouter@3.7.1(patch_hash=4e16e6ff3fde7d6c1024d3e0c8605dc9eb6afb690d0d49958c2f449091813072)(react@19.2.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
mitt: 3.0.1
|
mitt: 3.0.1
|
||||||
@@ -7183,6 +7245,16 @@ snapshots:
|
|||||||
regexparam: 3.0.0
|
regexparam: 3.0.0
|
||||||
use-sync-external-store: 1.6.0(react@19.2.1)
|
use-sync-external-store: 1.6.0(react@19.2.1)
|
||||||
|
|
||||||
|
xlsx@0.18.5:
|
||||||
|
dependencies:
|
||||||
|
adler-32: 1.3.1
|
||||||
|
cfb: 1.2.2
|
||||||
|
codepage: 1.15.0
|
||||||
|
crc-32: 1.2.2
|
||||||
|
ssf: 0.11.2
|
||||||
|
wmf: 1.0.2
|
||||||
|
word: 0.3.0
|
||||||
|
|
||||||
yallist@3.1.1: {}
|
yallist@3.1.1: {}
|
||||||
|
|
||||||
yallist@5.0.0: {}
|
yallist@5.0.0: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user