Add support bundle feature for issue reporting

- Add /api/v1/support/debug-logging endpoints to toggle debug log level
  - Add /api/v1/support/bundle endpoint to generate ZIP with system info and logs
  - Debug logging state persists across restarts via Settings database
  - Add debug logging indicator banner in Layout with real-time duration timer
  - Add Support & Troubleshooting section to System Information page
  - Privacy protection:
    - Filter sensitive settings (emails, keys, tokens, URLs, configs)
    - Sanitize paths to remove usernames
    - Remove hostname from collected data
    - Replace IP addresses with [IP] and emails with [EMAIL] in logs
  - Add privacy info panel explaining what data is/isn't collected
  - Require debug logging to be enabled before downloading support bundle
This commit is contained in:
maziggy
2026-01-05 09:54:31 +01:00
parent 4f2fa7685a
commit 50fd0c018b
13 changed files with 9289 additions and 8671 deletions
+42
View File
@@ -2580,3 +2580,45 @@ export const firmwareApi = {
getUploadStatus: (printerId: number) =>
request<FirmwareUploadStatus>(`/firmware/updates/${printerId}/upload/status`),
};
// Support types
export interface DebugLoggingState {
enabled: boolean;
enabled_at: string | null;
duration_seconds: number | null;
}
// Support API
export const supportApi = {
getDebugLoggingState: () =>
request<DebugLoggingState>('/support/debug-logging'),
setDebugLogging: (enabled: boolean) =>
request<DebugLoggingState>('/support/debug-logging', {
method: 'POST',
body: JSON.stringify({ enabled }),
}),
downloadSupportBundle: async () => {
const response = await fetch(`${API_BASE}/support/bundle`);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.detail || `HTTP ${response.status}`);
}
// Get filename from Content-Disposition header or use default
const disposition = response.headers.get('Content-Disposition');
const filenameMatch = disposition?.match(/filename=(.+)/);
const filename = filenameMatch ? filenameMatch[1] : 'bambuddy-support.zip';
// Download the blob
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
},
};