Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 158 additions & 4 deletions ShimmerCapture/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,112 @@
}
};

// 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;

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();
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) --------
Expand Down Expand Up @@ -366,15 +472,48 @@
chart.update();

}



shimmer.onStatus = (msg) => document.getElementById('log').textContent = msg;
</script>

<style>
body { font-family: sans-serif; margin: 20px; }
#toolbar { margin-bottom: 10px; }
#uploadSection {
margin-bottom: 12px;
padding: 10px 12px;
border: 1px solid #d8d8d8;
border-radius: 8px;
background: #fafafa;
display: flex;
flex-wrap: wrap;
align-items: end;
gap: 10px 12px;
}
.uploadField {
display: flex;
flex-direction: column;
gap: 4px;
min-width: 260px;
}
.uploadField label {
font-size: 0.85em;
color: #444;
}
.uploadField input {
padding: 6px 8px;
}
.uploadStatus {
flex: 1 1 100%;
min-width: 100%;
}
#status {
min-height: 20px;
padding: 6px 8px;
border: 1px solid #e1e1e1;
border-radius: 6px;
background: #fff;
color: #333;
}
#chart { width: 100%; height: 400px; }
button { margin-right: 6px; }
#signalList { margin-top: 8px; }
Expand Down Expand Up @@ -402,7 +541,22 @@ <h2>Shimmer Capture (Shimmer3R BLE)</h2>
<label class="exp"><input id="expPowerChk" type="checkbox"> Expansion Power</label>
</div>

<div id="status"></div>
<div id="uploadSection">
<div class="uploadField">
<label for="apiBaseUrlInput">ShimmerAPI Base URL</label>
<input id="apiBaseUrlInput" type="text" placeholder="e.g. localhost:5002">
</div>
<div class="uploadField">
<label for="s3FilePathInput">S3 File Path (Optional)</label>
<input id="s3FilePathInput" type="text" placeholder="e.g. Test-folder">
</div>
<button id="uploadBtn">Upload CSV File</button>
<div class="uploadField uploadStatus">
<label for="status">Status: </label>
<div id="status"></div>
</div>
</div>

<div id="signalList"></div>
<small id="signalNote" style="color:#666"></small>
<canvas id="chart"></canvas>
Expand Down