Backup AI usage history on reset
This commit is contained in:
parent
4df04970ea
commit
1294a66f56
3 changed files with 34 additions and 5 deletions
|
|
@ -55,7 +55,7 @@ export class AIAPI {
|
||||||
return apiFetchJSON(`${this.baseUrl}/ai/cost/reset`, {
|
return apiFetchJSON(`${this.baseUrl}/ai/cost/reset`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
}) as Promise<{ ok: boolean }>;
|
}) as Promise<{ ok: boolean; backup_file?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start OAuth flow for Claude Pro/Max subscription
|
// Start OAuth flow for Claude Pro/Max subscription
|
||||||
|
|
|
||||||
|
|
@ -187,10 +187,14 @@ export const AICostDashboard: Component = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetHistory = async () => {
|
const resetHistory = async () => {
|
||||||
if (!confirm('Reset AI usage history? This clears the stored token/cost history.')) return;
|
if (!confirm('Reset AI usage history? A backup will be created in the Pulse config directory.')) return;
|
||||||
try {
|
try {
|
||||||
await AIAPI.resetCostHistory();
|
const result = await AIAPI.resetCostHistory();
|
||||||
notificationStore.success('AI usage history reset');
|
if (result.backup_file) {
|
||||||
|
notificationStore.success(`AI usage history reset (backup: ${result.backup_file})`);
|
||||||
|
} else {
|
||||||
|
notificationStore.success('AI usage history reset');
|
||||||
|
}
|
||||||
await loadSummary(days());
|
await loadSummary(days());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('[AICostDashboard] Failed to reset AI cost history:', err);
|
logger.error('[AICostDashboard] Failed to reset AI cost history:', err);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -2460,13 +2462,36 @@ func (h *AISettingsHandler) HandleResetAICostHistory(w http.ResponseWriter, r *h
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backupFile := ""
|
||||||
|
if h.persistence != nil {
|
||||||
|
configDir := h.persistence.DataDir()
|
||||||
|
if strings.TrimSpace(configDir) != "" {
|
||||||
|
usagePath := filepath.Join(configDir, "ai_usage_history.json")
|
||||||
|
if _, err := os.Stat(usagePath); err == nil {
|
||||||
|
ts := time.Now().UTC().Format("20060102-150405")
|
||||||
|
backupFile = fmt.Sprintf("ai_usage_history.json.bak-%s", ts)
|
||||||
|
backupPath := filepath.Join(configDir, backupFile)
|
||||||
|
if err := os.Rename(usagePath, backupPath); err != nil {
|
||||||
|
log.Error().Err(err).Str("path", usagePath).Msg("Failed to backup AI usage history before reset")
|
||||||
|
http.Error(w, "Failed to backup AI usage history", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := h.aiService.ClearCostHistory(); err != nil {
|
if err := h.aiService.ClearCostHistory(); err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to clear AI cost history")
|
log.Error().Err(err).Msg("Failed to clear AI cost history")
|
||||||
http.Error(w, "Failed to clear AI cost history", http.StatusInternalServerError)
|
http.Error(w, "Failed to clear AI cost history", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := utils.WriteJSONResponse(w, map[string]any{"ok": true}); err != nil {
|
resp := map[string]any{"ok": true}
|
||||||
|
if backupFile != "" {
|
||||||
|
resp["backup_file"] = backupFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := utils.WriteJSONResponse(w, resp); err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to write clear cost history response")
|
log.Error().Err(err).Msg("Failed to write clear cost history response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue