fixed bug with spreadsheet import
This commit is contained in:
2
frontend/.env
Normal file
2
frontend/.env
Normal file
@ -0,0 +1,2 @@
|
||||
VITE_OPENAPI_BASE_DEV=https://127.0.0.1:8000
|
||||
VITE_OPENAPI_BASE_TEST=https://mx-aare-test.psi.ch:8000
|
@ -1,16 +1,28 @@
|
||||
// fetch-and-generate-openapi.js
|
||||
import fs from 'fs';
|
||||
import https from 'https'; // Use https instead of http
|
||||
import https from 'https';
|
||||
import { exec } from 'child_process';
|
||||
import chokidar from 'chokidar';
|
||||
import path from 'path';
|
||||
import util from 'util';
|
||||
|
||||
const OPENAPI_URL = 'https://127.0.0.1:8000/openapi.json';
|
||||
const SCHEMA_PATH = path.resolve('./src/openapi.json');
|
||||
const OUTPUT_DIRECTORY = path.resolve('./openapi');
|
||||
const SSL_KEY_PATH = path.resolve('../backend/ssl/key.pem'); // Path to SSL key
|
||||
const SSL_CERT_PATH = path.resolve('../backend/ssl/cert.pem'); // Path to SSL certificate
|
||||
// Determine the environment
|
||||
const environment = process.env.NODE_ENV || 'development';
|
||||
const configFile = `config_${environment}.json`;
|
||||
|
||||
// Load the appropriate configuration
|
||||
let config;
|
||||
try {
|
||||
config = JSON.parse(fs.readFileSync(path.resolve('../', configFile), 'utf8'));
|
||||
} catch (error) {
|
||||
console.error(`❌ Error reading configuration file: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const OPENAPI_URL = config.OPENAPI_URL;
|
||||
const SCHEMA_PATH = path.resolve(config.SCHEMA_PATH);
|
||||
const OUTPUT_DIRECTORY = path.resolve(config.OUTPUT_DIRECTORY);
|
||||
const SSL_KEY_PATH = path.resolve(config.SSL_KEY_PATH);
|
||||
const SSL_CERT_PATH = path.resolve(config.SSL_CERT_PATH);
|
||||
|
||||
console.log(`Using SCHEMA_PATH: ${SCHEMA_PATH}`);
|
||||
console.log(`Using OUTPUT_DIRECTORY: ${OUTPUT_DIRECTORY}`);
|
||||
@ -70,7 +82,6 @@ async function fetchAndGenerate() {
|
||||
await fs.promises.rm(OUTPUT_DIRECTORY, { recursive: true, force: true });
|
||||
console.log(`✅ Output directory cleaned at ${OUTPUT_DIRECTORY}`);
|
||||
|
||||
// Verify directory removal
|
||||
if (fs.existsSync(OUTPUT_DIRECTORY)) {
|
||||
console.error(`❌ Output directory still exists: ${OUTPUT_DIRECTORY}`);
|
||||
} else {
|
||||
@ -81,7 +92,6 @@ async function fetchAndGenerate() {
|
||||
console.log(`Executing debug command: ${command}`);
|
||||
|
||||
const { stdout, stderr } = await execPromisified(command);
|
||||
console.log("🔍 Inside exec callback");
|
||||
if (stderr) {
|
||||
console.error(`⚠️ stderr while generating services: ${stderr}`);
|
||||
} else {
|
||||
@ -99,13 +109,13 @@ async function fetchAndGenerate() {
|
||||
}
|
||||
}
|
||||
|
||||
const backendDirectory = '/Users/gotthardg/PycharmProjects/heidi-v2/backend/app';
|
||||
const backendDirectory = path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app');
|
||||
console.log(`👀 Watching for changes in ${backendDirectory}`);
|
||||
const watcher = chokidar.watch(backendDirectory, { persistent: true, ignored: [SCHEMA_PATH, OUTPUT_DIRECTORY] });
|
||||
|
||||
watcher
|
||||
.on('add', debounce(fetchAndGenerate, debounceDelay))
|
||||
.on('change', debounce(fetchAndGenerate, debounceDelay)) // Corrected typo here
|
||||
.on('change', debounce(fetchAndGenerate, debounceDelay))
|
||||
.on('unlink', debounce(fetchAndGenerate, debounceDelay));
|
||||
|
||||
console.log(`👀 Watching for changes in ${backendDirectory}`);
|
33
frontend/package-lock.json
generated
33
frontend/package-lock.json
generated
@ -24,6 +24,7 @@
|
||||
"axios": "^1.7.7",
|
||||
"chokidar": "^4.0.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv": "^16.4.7",
|
||||
"exceljs": "^4.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"openapi-typescript-codegen": "^0.29.0",
|
||||
@ -41,6 +42,7 @@
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
@ -3434,6 +3436,25 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "src/bin/cross-env.js",
|
||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
|
||||
@ -3560,6 +3581,18 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer2": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
|
||||
|
@ -4,12 +4,14 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "node_modules/.bin/vite",
|
||||
"build": "node_modules/.bin/tsc -b && vite build",
|
||||
"lint": "node_modules/.bin/eslint .",
|
||||
"preview": "node_modules/.bin/vite preview",
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"start-dev": "cross-env NODE_ENV=dev vite",
|
||||
"start-test": "cross-env NODE_ENV=test vite",
|
||||
"watch:openapi": "node fetch-openapi.js"
|
||||
},
|
||||
},
|
||||
"dependencies": {
|
||||
"@aldabil/react-scheduler": "^2.9.5",
|
||||
"@bitnoi.se/react-scheduler": "^0.3.1",
|
||||
@ -27,6 +29,7 @@
|
||||
"axios": "^1.7.7",
|
||||
"chokidar": "^4.0.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv": "^16.4.7",
|
||||
"exceljs": "^4.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"openapi-typescript-codegen": "^0.29.0",
|
||||
@ -44,6 +47,7 @@
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
|
@ -39,7 +39,10 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({ sx = {}, onCancel, refreshS
|
||||
const [errorMessage, setErrorMessage] = React.useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
OpenAPI.BASE = 'https://127.0.0.1:8000';
|
||||
const isTestEnv = import.meta.env.MODE === 'test';
|
||||
OpenAPI.BASE = isTestEnv
|
||||
? import.meta.env.VITE_OPENAPI_BASE_TEST
|
||||
: import.meta.env.VITE_OPENAPI_BASE_DEV;
|
||||
|
||||
const getContacts = async () => {
|
||||
try {
|
||||
|
@ -1,14 +1,6 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Button,
|
||||
Typography,
|
||||
IconButton,
|
||||
Box,
|
||||
CircularProgress
|
||||
Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, IconButton, Box, CircularProgress
|
||||
} from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
@ -17,45 +9,39 @@ import logo from '../assets/Heidi-logo.png';
|
||||
import { OpenAPI, SpreadsheetService } from '../../openapi';
|
||||
import type { Body_upload_file_upload_post } from '../../openapi/models/Body_upload_file_upload_post';
|
||||
import SpreadsheetTable from './SpreadsheetTable';
|
||||
import Modal from './Modal'; // Ensure correct import paths
|
||||
import Modal from './Modal';
|
||||
import * as ExcelJS from 'exceljs';
|
||||
|
||||
interface UploadDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
selectedShipment: any; // Adjust the type based on your implementation
|
||||
selectedShipment: any;
|
||||
}
|
||||
|
||||
const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShipment }) => {
|
||||
const [uploadError, setUploadError] = useState<string | null>(null);
|
||||
const [fileSummary, setFileSummary] = useState<{
|
||||
data: any[];
|
||||
errors: { row: number, cell: number, value: any, message: string }[];
|
||||
raw_data: { row_num: number, data: any[] }[];
|
||||
dewars_count: number;
|
||||
dewars: string[];
|
||||
pucks_count: number;
|
||||
pucks: string[];
|
||||
samples_count: number;
|
||||
samples: string[];
|
||||
headers: string[];
|
||||
} | null>(null);
|
||||
const [fileBlob, setFileBlob] = useState<Blob | null>(null); // New state to store the file blob
|
||||
const [fileSummary, setFileSummary] = useState<any>(null);
|
||||
const [fileBlob, setFileBlob] = useState<Blob | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
OpenAPI.BASE = 'https://127.0.0.1:8000';
|
||||
const isTestEnv = import.meta.env.MODE === 'test';
|
||||
OpenAPI.BASE = isTestEnv
|
||||
? import.meta.env.VITE_OPENAPI_BASE_TEST
|
||||
: import.meta.env.VITE_OPENAPI_BASE_DEV;
|
||||
}, []);
|
||||
|
||||
const downloadUrl = `${OpenAPI.BASE}/download-template`;
|
||||
|
||||
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
setUploadError(null);
|
||||
setFileSummary(null);
|
||||
setFileBlob(file); // Store the file blob
|
||||
setFileBlob(file);
|
||||
setIsLoading(true);
|
||||
|
||||
if (!file.name.endsWith('.xlsx')) {
|
||||
@ -68,8 +54,8 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShip
|
||||
|
||||
try {
|
||||
const response = await SpreadsheetService.uploadFileUploadPost(formData);
|
||||
|
||||
const { headers, raw_data, errors } = response;
|
||||
|
||||
setFileSummary({
|
||||
data: raw_data,
|
||||
errors: errors,
|
||||
@ -82,6 +68,7 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShip
|
||||
samples_count: 23,
|
||||
samples: ['Sample1', 'Sample2']
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setIsModalOpen(true);
|
||||
} catch (error) {
|
||||
@ -115,7 +102,7 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShip
|
||||
<img src={logo} alt="Logo" style={{ width: 200, marginBottom: 16 }} />
|
||||
<Typography variant="subtitle1">Latest Spreadsheet Template Version 7</Typography>
|
||||
<Typography variant="body2" color="textSecondary">Last update: November 7, 2024</Typography>
|
||||
<Button variant="outlined" startIcon={<DownloadIcon />} href="http://127.0.0.1:8000/download-template" download sx={{ mt: 1 }}>
|
||||
<Button variant="outlined" startIcon={<DownloadIcon />} href={downloadUrl} download sx={{ mt: 1 }}>
|
||||
Download XLSX
|
||||
</Button>
|
||||
<Typography variant="subtitle1" sx={{ mt: 3 }}>Latest Spreadsheet Instructions Version 2.3</Typography>
|
||||
@ -165,8 +152,8 @@ const UploadDialog: React.FC<UploadDialogProps> = ({ open, onClose, selectedShip
|
||||
headers={fileSummary.headers}
|
||||
setRawData={(newRawData) => setFileSummary((prevSummary) => ({ ...prevSummary, raw_data: newRawData }))}
|
||||
onCancel={handleCancel}
|
||||
fileBlob={fileBlob} // Pass the original file blob
|
||||
selectedShipment={selectedShipment} // Pass the selected shipment ID
|
||||
fileBlob={fileBlob}
|
||||
selectedShipment={selectedShipment}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
@ -6,12 +6,8 @@ import { Dewar, OpenAPI, Shipment } from '../../openapi';
|
||||
import useShipments from '../hooks/useShipments';
|
||||
import { Grid, Container } from '@mui/material';
|
||||
|
||||
// Define props for Shipments View
|
||||
type ShipmentViewProps = React.PropsWithChildren<Record<string, never>>;
|
||||
|
||||
const API_BASE_URL = 'https://127.0.0.1:8000';
|
||||
OpenAPI.BASE = API_BASE_URL;
|
||||
|
||||
const ShipmentView: React.FC<ShipmentViewProps> = () => {
|
||||
const { shipments, error, defaultContactPerson, fetchAndSetShipments } = useShipments();
|
||||
const [selectedShipment, setSelectedShipment] = useState<Shipment | null>(null);
|
||||
@ -19,10 +15,13 @@ const ShipmentView: React.FC<ShipmentViewProps> = () => {
|
||||
const [isCreatingShipment, setIsCreatingShipment] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('Updated shipments:', shipments);
|
||||
}, [shipments]);
|
||||
const isTestEnv = import.meta.env.MODE === 'test';
|
||||
OpenAPI.BASE = isTestEnv
|
||||
? import.meta.env.VITE_OPENAPI_BASE_TEST
|
||||
: import.meta.env.VITE_OPENAPI_BASE_DEV;
|
||||
fetchAndSetShipments();
|
||||
}, []);
|
||||
|
||||
// Handlers for selecting shipment and canceling form
|
||||
const handleSelectShipment = (shipment: Shipment | null) => {
|
||||
setSelectedShipment(shipment);
|
||||
setIsCreatingShipment(false);
|
||||
@ -32,7 +31,6 @@ const ShipmentView: React.FC<ShipmentViewProps> = () => {
|
||||
setIsCreatingShipment(false);
|
||||
};
|
||||
|
||||
// Render the shipment content based on state
|
||||
const renderShipmentContent = () => {
|
||||
if (isCreatingShipment) {
|
||||
return (
|
||||
@ -60,7 +58,6 @@ const ShipmentView: React.FC<ShipmentViewProps> = () => {
|
||||
return <div>No shipment details available.</div>;
|
||||
};
|
||||
|
||||
// Render the main layout using Grid for layout
|
||||
return (
|
||||
<Container maxWidth={false} disableGutters sx={{ display: 'flex', height: '100vh' }}>
|
||||
<Grid container spacing={2} sx={{ height: '100vh' }}>
|
||||
|
Reference in New Issue
Block a user