From a66fb66c5d4f68e49b8aac9ab47902dec8a5e252 Mon Sep 17 00:00:00 2001 From: Danesh Mariapan <161300025+dmariapan-shimmer@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:26:45 +0800 Subject: [PATCH 1/2] Added Upload file functionality --- ShimmerCapture/index.html | 105 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/ShimmerCapture/index.html b/ShimmerCapture/index.html index be36ecb..6939272 100644 --- a/ShimmerCapture/index.html +++ b/ShimmerCapture/index.html @@ -226,6 +226,106 @@ } }; + // For Upload CSV + const csvFileInput = document.createElement('input'); + csvFileInput.type = 'file'; + csvFileInput.accept = '.csv,text/csv'; + csvFileInput.style.display = 'none'; + document.body.appendChild(csvFileInput); + + const apiBaseUrlInput = document.getElementById('apiBaseUrlInput'); + const API_BASE_URL_KEY = 'shimmerApiBaseUrl'; + apiBaseUrlInput.value = localStorage.getItem(API_BASE_URL_KEY) || ''; + + function getApiBaseUrl() { + return apiBaseUrlInput.value.trim().replace(/\/$/, ''); + } + + async function uploadCsvFile(file) { + if (!file) return; + + try { + document.getElementById('status').textContent = 'Getting upload URL...'; + const apiBaseUrl = getApiBaseUrl(); + if (!apiBaseUrl) { + throw new Error('Enter the Shimmer API base URL first.'); + } + localStorage.setItem(API_BASE_URL_KEY, apiBaseUrl); + + const customPath = document.getElementById('s3FilePathInput')?.value.trim(); + let s3FilePath; + if (customPath) { + s3FilePath = customPath.endsWith('.csv') ? customPath : `${customPath}/${file.name}`; + } else { + s3FilePath = file.name || `shimmer_${Date.now()}.csv`; + } + + const response = await fetch(`${apiBaseUrl}/api/trial/s3/presigned_url_upload`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ S3FilePath: s3FilePath }) + }); + + const data = await response.json().catch(() => null); + if (!response.ok) { + let errText = data?.Error || data?.error; + if (!errText && data?.errors && typeof data.errors === 'object') { + errText = Object.entries(data.errors) + .map(([k, v]) => `${k}: ${(Array.isArray(v) ? v.join(', ') : v)}`) + .join(' | '); + } + if (!errText && data?.title) errText = data.title; + if (!errText) errText = `HTTP ${response.status}`; + throw new Error(`Failed to get pre-signed URL: ${errText}`); + } + + console.log('Presigned response:', data); + const isSuccess = data?.IsSuccess ?? data?.isSuccess; + const entity = data?.Entity ?? data?.entity; + const uploadUrl = entity?.UploadUrl ?? entity?.uploadUrl; + + if (isSuccess === false) { + throw new Error(data?.Error || data?.error || 'API returned failure'); + } + if (!uploadUrl) { + throw new Error('No upload URL returned from API'); + } + + document.getElementById('status').textContent = 'Uploading...'; + + const upload = await fetch(uploadUrl, { + method: 'PUT', + headers: { + 'Content-Type': file.type || 'text/csv' + }, + body: file + }); + + if (!upload.ok) { + throw new Error('Upload failed'); + } + + document.getElementById('status').textContent = 'Upload success'; + } catch (err) { + console.error(err); + document.getElementById('status').textContent = 'Upload failed'; + alert(err.message); + } + } + + csvFileInput.onchange = async () => { + const [file] = csvFileInput.files || []; + csvFileInput.value = ''; + if (!file) return; + await uploadCsvFile(file); + }; + + document.getElementById('uploadBtn').onclick = () => { + csvFileInput.click(); + }; + // -------- Build signal list -------- // -------- Build signal list (name + kind) -------- @@ -397,6 +497,11 @@

Shimmer Capture (Shimmer3R BLE)

+ + + + + From 62b71b442a3774e02e463575feaa95035c134a9b Mon Sep 17 00:00:00 2001 From: Danesh Mariapan <161300025+dmariapan-shimmer@users.noreply.github.com> Date: Tue, 9 Jun 2026 16:10:45 +0800 Subject: [PATCH 2/2] - Added upload filesize cap 5MB - Added section for upload elements --- ShimmerCapture/index.html | 67 +++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/ShimmerCapture/index.html b/ShimmerCapture/index.html index 6939272..be0b168 100644 --- a/ShimmerCapture/index.html +++ b/ShimmerCapture/index.html @@ -244,6 +244,12 @@ async function uploadCsvFile(file) { if (!file) return; + const maxUploadBytes = 5 * 1024 * 1024; + if (file.size > maxUploadBytes) { + document.getElementById('status').textContent = 'File too large to upload! (>5MB)'; + return; + } + try { document.getElementById('status').textContent = 'Getting upload URL...'; const apiBaseUrl = getApiBaseUrl(); @@ -466,15 +472,48 @@ chart.update(); } - - - shimmer.onStatus = (msg) => document.getElementById('log').textContent = msg;