diff --git a/.github/workflows/build-on-pr.yml b/.github/workflows/build-on-pr.yml new file mode 100644 index 0000000..d4c2ba5 --- /dev/null +++ b/.github/workflows/build-on-pr.yml @@ -0,0 +1,25 @@ +name: Build on Pull Request + +on: + pull_request: + branches: ['main'] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' # Use the Node.js version you're working with + cache: 'npm' # Use the Node.js version you're working with + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build diff --git a/package-lock.json b/package-lock.json index e6dc4b3..fb7752b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3857,11 +3857,10 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4781,18 +4780,17 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7321,7 +7319,6 @@ "version": "6.27.0", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", - "license": "MIT", "dependencies": { "@remix-run/router": "1.20.0", "react-router": "6.27.0" diff --git a/src/components/DataTable.tsx b/src/components/DataTable.tsx index 2e7d999..133f598 100644 --- a/src/components/DataTable.tsx +++ b/src/components/DataTable.tsx @@ -57,7 +57,7 @@ export default function DataTable({ ); return ( - + 0} diff --git a/src/components/FileUpload.tsx b/src/components/FileUpload.tsx new file mode 100644 index 0000000..fa86f4d --- /dev/null +++ b/src/components/FileUpload.tsx @@ -0,0 +1,106 @@ +import React, { useState } from 'react'; +import { Modal, Button, Notification, FileInput } from '@mantine/core'; +import '@/css/FileUpload.css'; + +interface FileUploadProps { + uploadUrl: string; +} + +const FileUpload: React.FC = ({ uploadUrl }) => { + const [showModal, setShowModal] = useState(false); + const [selectedFiles, setSelectedFiles] = useState([]); + const [error, setError] = useState(null); + + const handleFileChange = (files: File[]) => { + if (files.length > 0) { + setSelectedFiles((prevFiles) => [...prevFiles, ...files]); + } + }; + + const handleUpload = async () => { + if (selectedFiles.length > 0) { + const formData = new FormData(); + selectedFiles.forEach((file) => { + formData.append('files', file); + }); + + try { + const response = await fetch(uploadUrl, { + method: 'POST', + body: formData, + }); + + if (!response.ok) { + setError('Upload failed. Network response was not ok.'); + return; + } + + const data = await response.json(); + console.log('Upload successful:', data); + + setSelectedFiles([]); + handleClose(); + } catch (error) { + console.error('Upload failed:', error); + setError('An error occurred while uploading. Please try again.'); + } + } else { + setError('Please select files to upload.'); + } + }; + + const toggleModal = () => { + setShowModal(!showModal); + }; + + const handleClose = () => { + setShowModal(false); + setSelectedFiles([]); + setError(null); + }; + + return ( +
+ + + +
+ + {selectedFiles.length > 0 && ( +
+

Chosen Files:

+
    + {selectedFiles.map((file, index) => ( +
  • {file.name}
  • + ))} +
+
+ )} +
+ + + + {error && ( + setError(null)} style={{ marginTop: 10 }}> + {error} + + )} +
+
+ ); +}; + +export default FileUpload; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 4e0b40e..2b028c8 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,6 +1,7 @@ import "@mantine/core/styles.css"; import "@/css/Navbar.css"; import { NavLink } from "react-router-dom"; +import FileUpload from "@/components/FileUpload" const mainLinksData = [ { name: "Files", url: "/" }, @@ -25,6 +26,10 @@ export default function Navbar() { className="navbar-icon" /> {links} + + {/* Once POST API is out -- Currently WIP */} + + {/* Optionally render active link or other content here */}

{hytechName}

diff --git a/src/components/PreviewCard.tsx b/src/components/PreviewCard.tsx index 5a4976a..0a43646 100644 --- a/src/components/PreviewCard.tsx +++ b/src/components/PreviewCard.tsx @@ -226,7 +226,6 @@ export const SchemaTable = () => { handleSearch(e.target.value); }} /> - {" "} {/* Scrollable area with height limit */} diff --git a/src/components/SchemaSearch.tsx b/src/components/SchemaSearch.tsx new file mode 100644 index 0000000..9577c88 --- /dev/null +++ b/src/components/SchemaSearch.tsx @@ -0,0 +1,64 @@ +import React, { useState } from "react"; +import { Autocomplete, Button } from "@mantine/core"; +import "@/css/SchemaSearch.css"; + +interface SchemaSearch { + schemas: string[]; +} + +const SchemaSearch: React.FC = ({ schemas }) => { + const [value, setValue] = useState(""); + const [selectedSchema, setSelected] = useState([]); + + const filteredSchemas = schemas.filter((schema) => + schema.toLowerCase().includes(value.toLowerCase()), + ); + + const addSchema = (newSchema: string) => { + if (!selectedSchema.includes(newSchema)) { + setSelected([...selectedSchema, newSchema]); + } else { + alert("Schema already selected!"); + } + }; + + const clearSchema = () => { + setSelected([]); + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === "Enter" && filteredSchemas.length > 0) { + setValue(filteredSchemas[0]); + addSchema(filteredSchemas[0]); + } + }; + + return ( +
+ +
+ {selectedSchema.length > 0 && ( +
+ +
    + {selectedSchema.map((str, index) => ( +
  • {str}
  • + ))} +
+ +
+ )} +
+ ); +}; + +export default SchemaSearch; diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index ef6bde4..5b553d2 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; import { eventType, location } from "@/data/dataFilters"; import "@/css/SearchBar.css"; +import SchemaSearch from "@/components/SchemaSearch"; interface SearchBarWithFilterProps { setFilteredData: React.Dispatch< @@ -34,6 +35,8 @@ function SearchBarWithFilter({ setSearchFilters }: SearchBarWithFilterProps) { // return true; // }; + const schemas = ["Schema1", "Schema2", "Schema3", "Schema4"]; + // Filter logic // const handleSearch = () => { // const filtered = data.filter((item) => { @@ -171,6 +174,8 @@ function SearchBarWithFilter({ setSearchFilters }: SearchBarWithFilterProps) { placeholder="Filter by date" /> + + diff --git a/src/css/FileUpload.css b/src/css/FileUpload.css new file mode 100644 index 0000000..d02a437 --- /dev/null +++ b/src/css/FileUpload.css @@ -0,0 +1,30 @@ +button { + padding: 10px 10px; + margin: 3px 3px; + border: none; + border-radius: 5px; + background-color: #b39e63; + color: white; + cursor: pointer; + transition: background-color 0.3s; +} + +button:hover { + background-color: #d4bc79; +} + +ul { + list-style-type: none; + padding: 0; +} + +h3 { + margin-top: 20px; +} + +.files { + display: flex; + flex-direction: column; + text-align: center; + justify-content: center; +} \ No newline at end of file diff --git a/src/css/PreviewCard.css b/src/css/PreviewCard.css index 7d0a795..2c4e75e 100644 --- a/src/css/PreviewCard.css +++ b/src/css/PreviewCard.css @@ -23,3 +23,11 @@ height: auto; /* Maintains aspect ratio */ margin: 20px; } + +@media (max-width: 600px) { + .previewFileButtons { + display: flex; + flex-direction: column; + + } + } \ No newline at end of file diff --git a/src/css/Root.css b/src/css/Root.css index cfa9c85..ea633f3 100644 --- a/src/css/Root.css +++ b/src/css/Root.css @@ -8,18 +8,13 @@ background-color: #f0f0f0; width: 100%; position: fixed; - /*so table doesn't cover it - make sure it stays on top of other elements*/ z-index: 1000; } -.search-bar { - background-color: #e0e0e0; - border-radius: 0; -} - .main-content { display: flex; flex: 1; + overflow: hidden; height: 500px; padding-top: 50px; flex-direction: column; @@ -27,12 +22,19 @@ .results-container { display: flex; + flex: 1; + overflow: hidden; flex-direction: row; } +.table-contain-result { + flex-grow: 1; + overflow-y: auto; + padding-bottom: 10px; + } + .footer { text-align: center; background: #9b8b5de5; color: white; } - diff --git a/src/css/SchemaSearch.css b/src/css/SchemaSearch.css new file mode 100644 index 0000000..b0ccd00 --- /dev/null +++ b/src/css/SchemaSearch.css @@ -0,0 +1,10 @@ +.schema-autocomplete { + padding: 10px; + border-radius: 10px; + border: 1px solid #ddd; + background-color: #fff; + } +.cancel-button { + background-color: #978750; + +} \ No newline at end of file diff --git a/src/css/SearchBar.css b/src/css/SearchBar.css index 8e18898..d0cb8a7 100644 --- a/src/css/SearchBar.css +++ b/src/css/SearchBar.css @@ -1,27 +1,8 @@ -.results-container { - flex: 1; - display: flex; - flex-direction: column; - outline-color: #DEE2E6; - outline-width: 2px; - outline-style: solid; -} - - -.table-contain-result { - text-align: center; - flex: 1; -} - -.preview-contain-result { - text-align: center; -} - .Search { display: flex; max-width: 360px; font-size: 15px; - + overflow: auto; } diff --git a/src/data/sampledata.ts b/src/data/sampledata.ts index 2cf53ba..7f40535 100644 --- a/src/data/sampledata.ts +++ b/src/data/sampledata.ts @@ -13,6 +13,62 @@ export const data: MCAPFileInformation[] = [ notes: "car ran!", event_type: "acceleration", }, + { + id: "0723984238489-21312-4e75e6f76", + mcap_file_name: "file5.3.mcap", + matlab_file_name: "file5.3.mat", + aws_bucket: "bucket", + mcap_path: "/path/to/s3/object", + mat_path: "/path/to/s3/object", + vn_lat_lon_path: "/path/to/s3/object", + velocity_plot_path: "/path/to/s3/object", + date: "08-16-2024", + location: "rome", + notes: "car performed nice", + event_type: "autocross", + }, + { + id: "091823792-2321312-a081", + mcap_file_name: "file7.1.mcap", + matlab_file_name: "file7.1.mat", + aws_bucket: "bucket", + mcap_path: "/path/to/s3/object", + mat_path: "/path/to/s3/object", + vn_lat_lon_path: "/path/to/s3/object", + velocity_plot_path: "/path/to/s3/object", + date: "08-29-2024", + location: "MRDC", + notes: "car did jk turn on", + event_type: null, + }, + { + id: "07a0sdjwne-597f-4637-8b61-6134e75e6f76", + mcap_file_name: "file2.3.mcap", + matlab_file_name: "file2.3.mat", + aws_bucket: "bucket", + mcap_path: "/path/to/s3/object", + mat_path: "/path/to/s3/object", + vn_lat_lon_path: "/path/to/s3/object", + velocity_plot_path: "/path/to/s3/object", + date: "08-16-2024", + location: "rome", + notes: "car did not latch", + event_type: "autocross", + }, + { + id: "605deb4b-44a8-4801-9da6-a671c1d3eccd", + mcap_file_name: "file1.3.mcap", + matlab_file_name: "file1.3.mat", + aws_bucket: "bucket", + mcap_path: "/path/to/s3/object", + mat_path: "/path/to/s3/object", + vn_lat_lon_path: "/path/to/s3/object", + velocity_plot_path: "/path/to/s3/object", + date: "08-22-2024", + location: "MRDC", + notes: "car failed", + event_type: "acceleration", + }, { id: "fb48f265-a44a-4fd5-a873-26cd581950a0", mcap_file_name: "file2.mcap", @@ -96,4 +152,4 @@ export const data: MCAPFileInformation[] = [ location: "MRDC", notes: "car did not turn on", }, -]; +]; \ No newline at end of file