feat: enhance bug reporting by adding localStorage and config data capture, and fix submit button state
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
1) Aggiunti i pulsanti "Download" al MailViewer, PDF e Image viewer, per scaricare il file invece di aprirlo direttamente.2
|
1) Aggiunti i pulsanti "Download" al MailViewer, PDF e Image viewer, per scaricare il file invece di aprirlo direttamente.2
|
||||||
2) Refactor del sistema di bug report.
|
2) Refactor del sistema di bug report.
|
||||||
3) Rimosso temporaneamente il fetching dei dati macchina all'apertura della pagine delle impostazioni, per evitare problemi di performance.
|
3) Rimosso temporaneamente il fetching dei dati macchina all'apertura della pagine delle impostazioni, per evitare problemi di performance.
|
||||||
|
4) Fixato un bug dove, nel Bug Reporting, non si disattivaa il pulsante di invio, se tutti i campi erano compilati.
|
||||||
|
5) Aggiunto il supprto all'allegare i file di localStorage e config.ini al Bug Report, per investigare meglio i problemi legati all'ambiente dell'utente.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
TODO.md
2
TODO.md
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
# Existing Features
|
# Existing Features
|
||||||
- [ ] Add seperated "Updater" binary, that will start on User login (via Scheduled Task), with a silent install mode.
|
- [ ] Add seperated "Updater" binary, that will start on User login (via Scheduled Task), with a silent install mode.
|
||||||
- [ ] Attach localStorage, config file to the "Bug Reporter" ZIP file, to investigate the issue with the user enviroment.
|
- [x] Attach localStorage, config file to the "Bug Reporter" ZIP file, to investigate the issue with the user enviroment.
|
||||||
- [ ] Auto-send the "Bug Reporter" ZIP file to the support team, to investigate the issue with the user enviroment.
|
- [ ] Auto-send the "Bug Reporter" ZIP file to the support team, to investigate the issue with the user enviroment.
|
||||||
|
|
||||||
# Bugs
|
# Bugs
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ type BugReportInput struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
// ScreenshotData is the base64-encoded PNG screenshot (captured before dialog opens)
|
// ScreenshotData is the base64-encoded PNG screenshot (captured before dialog opens)
|
||||||
ScreenshotData string `json:"screenshotData"`
|
ScreenshotData string `json:"screenshotData"`
|
||||||
|
// LocalStorageData is the JSON-encoded localStorage data
|
||||||
|
LocalStorageData string `json:"localStorageData"`
|
||||||
|
// ConfigData is the JSON-encoded config.ini data
|
||||||
|
ConfigData string `json:"configData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitBugReportResult contains the result of submitting a bug report.
|
// SubmitBugReportResult contains the result of submitting a bug report.
|
||||||
@@ -120,10 +124,12 @@ func (a *App) CreateBugReportFolder() (*BugReportResult, error) {
|
|||||||
// - User-provided description (report.txt)
|
// - User-provided description (report.txt)
|
||||||
// - Screenshot (captured before dialog opens)
|
// - Screenshot (captured before dialog opens)
|
||||||
// - Currently loaded mail file (if any)
|
// - Currently loaded mail file (if any)
|
||||||
|
// - localStorage data (localStorage.json)
|
||||||
|
// - Config.ini data (config.json)
|
||||||
// - System information (hostname, OS version, hardware ID)
|
// - System information (hostname, OS version, hardware ID)
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// - input: User-provided bug report details including pre-captured screenshot
|
// - input: User-provided bug report details including pre-captured screenshot, localStorage, and config data
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// - *SubmitBugReportResult: Paths to the zip file and folder
|
// - *SubmitBugReportResult: Paths to the zip file and folder
|
||||||
@@ -168,6 +174,22 @@ func (a *App) SubmitBugReport(input BugReportInput) (*SubmitBugReportResult, err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save localStorage data if provided
|
||||||
|
if input.LocalStorageData != "" {
|
||||||
|
localStoragePath := filepath.Join(bugReportFolder, "localStorage.json")
|
||||||
|
if err := os.WriteFile(localStoragePath, []byte(input.LocalStorageData), 0644); err != nil {
|
||||||
|
Log("Failed to save localStorage data:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save config data if provided
|
||||||
|
if input.ConfigData != "" {
|
||||||
|
configPath := filepath.Join(bugReportFolder, "config.json")
|
||||||
|
if err := os.WriteFile(configPath, []byte(input.ConfigData), 0644); err != nil {
|
||||||
|
Log("Failed to save config data:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the report.txt file with user's description
|
// Create the report.txt file with user's description
|
||||||
reportContent := fmt.Sprintf(`EMLy Bug Report
|
reportContent := fmt.Sprintf(`EMLy Bug Report
|
||||||
================
|
================
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
import { Textarea } from "$lib/components/ui/textarea/index.js";
|
import { Textarea } from "$lib/components/ui/textarea/index.js";
|
||||||
import { CheckCircle, Copy, FolderOpen, Camera, Loader2 } from "@lucide/svelte";
|
import { CheckCircle, Copy, FolderOpen, Camera, Loader2 } from "@lucide/svelte";
|
||||||
import { toast } from "svelte-sonner";
|
import { toast } from "svelte-sonner";
|
||||||
import { TakeScreenshot, SubmitBugReport, OpenFolderInExplorer } from "$lib/wailsjs/go/main/App";
|
import { TakeScreenshot, SubmitBugReport, OpenFolderInExplorer, GetConfig } from "$lib/wailsjs/go/main/App";
|
||||||
|
import { browser } from "$app/environment";
|
||||||
|
|
||||||
// Bug report form state
|
// Bug report form state
|
||||||
let userName = $state("");
|
let userName = $state("");
|
||||||
@@ -19,16 +20,27 @@
|
|||||||
let screenshotData = $state("");
|
let screenshotData = $state("");
|
||||||
let isCapturing = $state(false);
|
let isCapturing = $state(false);
|
||||||
|
|
||||||
|
// Bug report system data
|
||||||
|
let localStorageData = $state("");
|
||||||
|
let configData = $state("");
|
||||||
|
|
||||||
// Bug report UI state
|
// Bug report UI state
|
||||||
let isSubmitting = $state(false);
|
let isSubmitting = $state(false);
|
||||||
let isSuccess = $state(false);
|
let isSuccess = $state(false);
|
||||||
let resultZipPath = $state("");
|
let resultZipPath = $state("");
|
||||||
|
let canSubmit: boolean = $derived(
|
||||||
|
bugDescription.trim().length > 0 && userName.trim().length > 0 && userEmail.trim().length > 0 && !isSubmitting && !isCapturing
|
||||||
|
);
|
||||||
|
|
||||||
// Bug report dialog effects
|
// Bug report dialog effects
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if ($bugReportDialogOpen) {
|
if ($bugReportDialogOpen) {
|
||||||
// Capture screenshot immediately when dialog opens
|
// Capture screenshot immediately when dialog opens
|
||||||
captureScreenshot();
|
captureScreenshot();
|
||||||
|
// Capture localStorage data
|
||||||
|
captureLocalStorage();
|
||||||
|
// Capture config.ini data
|
||||||
|
captureConfig();
|
||||||
} else {
|
} else {
|
||||||
// Reset form when dialog closes
|
// Reset form when dialog closes
|
||||||
resetBugReportForm();
|
resetBugReportForm();
|
||||||
@@ -48,11 +60,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function captureLocalStorage() {
|
||||||
|
if (!browser) return;
|
||||||
|
try {
|
||||||
|
const data: Record<string, string> = {};
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i);
|
||||||
|
if (key) {
|
||||||
|
data[key] = localStorage.getItem(key) || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localStorageData = JSON.stringify(data, null, 2);
|
||||||
|
console.log("localStorage data captured");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to capture localStorage:", err);
|
||||||
|
localStorageData = "Error capturing localStorage";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function captureConfig() {
|
||||||
|
try {
|
||||||
|
const config = await GetConfig();
|
||||||
|
configData = JSON.stringify(config, null, 2);
|
||||||
|
console.log("Config data captured");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to capture config:", err);
|
||||||
|
configData = "Error capturing config";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function resetBugReportForm() {
|
function resetBugReportForm() {
|
||||||
userName = "";
|
userName = "";
|
||||||
userEmail = "";
|
userEmail = "";
|
||||||
bugDescription = "";
|
bugDescription = "";
|
||||||
screenshotData = "";
|
screenshotData = "";
|
||||||
|
localStorageData = "";
|
||||||
|
configData = "";
|
||||||
isCapturing = false;
|
isCapturing = false;
|
||||||
isSubmitting = false;
|
isSubmitting = false;
|
||||||
isSuccess = false;
|
isSuccess = false;
|
||||||
@@ -74,7 +117,9 @@
|
|||||||
name: userName,
|
name: userName,
|
||||||
email: userEmail,
|
email: userEmail,
|
||||||
description: bugDescription,
|
description: bugDescription,
|
||||||
screenshotData: screenshotData
|
screenshotData: screenshotData,
|
||||||
|
localStorageData: localStorageData,
|
||||||
|
configData: configData
|
||||||
});
|
});
|
||||||
|
|
||||||
resultZipPath = result.zipPath;
|
resultZipPath = result.zipPath;
|
||||||
@@ -112,7 +157,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Dialog.Root bind:open={$bugReportDialogOpen}>
|
<Dialog.Root bind:open={$bugReportDialogOpen}>
|
||||||
<Dialog.Content class="sm:max-w-[500px] w-full max-h-[80vh] overflow-y-auto custom-scrollbar">
|
<Dialog.Content class="sm:max-w-125 w-full max-h-[80vh] overflow-y-auto custom-scrollbar">
|
||||||
{#if isSuccess}
|
{#if isSuccess}
|
||||||
<!-- Success State -->
|
<!-- Success State -->
|
||||||
<Dialog.Header>
|
<Dialog.Header>
|
||||||
@@ -186,7 +231,7 @@
|
|||||||
placeholder={m.bugreport_text_placeholder()}
|
placeholder={m.bugreport_text_placeholder()}
|
||||||
bind:value={bugDescription}
|
bind:value={bugDescription}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
class="min-h-[120px]"
|
class="min-h-30"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -225,7 +270,7 @@
|
|||||||
<button type="button" class={buttonVariants({ variant: "outline" })} disabled={isSubmitting} onclick={closeBugReportDialog}>
|
<button type="button" class={buttonVariants({ variant: "outline" })} disabled={isSubmitting} onclick={closeBugReportDialog}>
|
||||||
{m.bugreport_cancel()}
|
{m.bugreport_cancel()}
|
||||||
</button>
|
</button>
|
||||||
<Button type="submit" disabled={isSubmitting || isCapturing}>
|
<Button type="submit" disabled={!canSubmit}>
|
||||||
{#if isSubmitting}
|
{#if isSubmitting}
|
||||||
<Loader2 class="h-4 w-4 mr-2 animate-spin" />
|
<Loader2 class="h-4 w-4 mr-2 animate-spin" />
|
||||||
{m.bugreport_submitting()}
|
{m.bugreport_submitting()}
|
||||||
|
|||||||
Reference in New Issue
Block a user