From 7e42d3a26f1e2374bddb6487be182f16860f6e68 Mon Sep 17 00:00:00 2001 From: billisdead Date: Tue, 23 Jun 2026 13:24:56 +0200 Subject: [PATCH] feat: add incident delete and clarify AI assistant settings Wire deleteIncident() into IncidentDetailScreen with a destructive confirm dialog. Expand the AI settings section with base URL + model fields and an explanatory card documenting the OpenAI-compatible use case (Ollama / OpenAI). Co-Authored-By: Claude Sonnet 4.6 --- app/incident/[id].tsx | 38 ++++++++++++++++++++++++++- app/settings.tsx | 60 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/app/incident/[id].tsx b/app/incident/[id].tsx index 8980e14..b229aa4 100644 --- a/app/incident/[id].tsx +++ b/app/incident/[id].tsx @@ -10,7 +10,7 @@ import { import { useLocalSearchParams, router, useNavigation } from "expo-router"; import * as Clipboard from "expo-clipboard"; import * as SecureStore from "expo-secure-store"; -import { getIncidentById, updateIncident } from "@/lib/db"; +import { getIncidentById, updateIncident, deleteIncident } from "@/lib/db"; import { renderMarkdown } from "@/lib/markdown"; import { pushIncidentToGit } from "@/lib/git"; import type { GitProvider } from "@/lib/git"; @@ -54,6 +54,25 @@ export default function IncidentDetailScreen() { } }, [id]); + async function handleDelete() { + if (!incident) return; + Alert.alert( + "Delete incident?", + "This action cannot be undone.", + [ + { text: "Cancel", style: "cancel" }, + { + text: "Delete", + style: "destructive", + onPress: async () => { + await deleteIncident(incident.id); + router.replace("/"); + }, + }, + ] + ); + } + async function handleResolve() { if (!incident) return; await updateIncident(incident.id, { status: "resolved" }); @@ -291,6 +310,23 @@ export default function IncidentDetailScreen() { Edit + + + + Delete Incident + + ); diff --git a/app/settings.tsx b/app/settings.tsx index 5e06173..4fc7593 100644 --- a/app/settings.tsx +++ b/app/settings.tsx @@ -17,6 +17,8 @@ const KEYS = { HOME_VIEW: "pref_home_view", AI_ENABLED: "pref_ai_enabled", AI_KEY: "pref_ai_key", + AI_BASE_URL: "pref_ai_base_url", + AI_MODEL: "pref_ai_model", MD_TEMPLATE: "md_template", GIT_PROVIDER: "git_provider", // Gitea @@ -75,6 +77,8 @@ export default function SettingsScreen() { const [homeView, setHomeView] = useState<"dashboard" | "capture">("dashboard"); const [aiEnabled, setAiEnabled] = useState(false); const [aiKey, setAiKey] = useState(""); + const [aiBaseUrl, setAiBaseUrl] = useState(""); + const [aiModel, setAiModel] = useState(""); const [mdTemplate, setMdTemplate] = useState(DEFAULT_TEMPLATE); const [saved, setSaved] = useState(false); @@ -97,12 +101,14 @@ export default function SettingsScreen() { useEffect(() => { (async () => { - const [im, hv, ai, key, tpl, gp, gu, gt, go, gr, ghu, ghown, ghrepo, glu, glt, glo, glr] = + const [im, hv, ai, key, aiUrl, aiMdl, tpl, gp, gu, gt, go, gr, ghu, ghown, ghrepo, glu, glt, glo, glr] = await Promise.all([ SecureStore.getItemAsync(KEYS.INPUT_MODE), SecureStore.getItemAsync(KEYS.HOME_VIEW), SecureStore.getItemAsync(KEYS.AI_ENABLED), SecureStore.getItemAsync(KEYS.AI_KEY), + SecureStore.getItemAsync(KEYS.AI_BASE_URL), + SecureStore.getItemAsync(KEYS.AI_MODEL), SecureStore.getItemAsync(KEYS.MD_TEMPLATE), SecureStore.getItemAsync(KEYS.GIT_PROVIDER), SecureStore.getItemAsync(KEYS.GITEA_URL), @@ -121,6 +127,8 @@ export default function SettingsScreen() { if (hv) setHomeView(hv as "dashboard" | "capture"); if (ai) setAiEnabled(ai === "true"); if (key) setAiKey(key); + if (aiUrl) setAiBaseUrl(aiUrl); + if (aiMdl) setAiModel(aiMdl); if (tpl) setMdTemplate(tpl); if (gp) setGitProvider(gp as GitProvider); if (gu) setGiteaUrl(gu); @@ -143,6 +151,8 @@ export default function SettingsScreen() { SecureStore.setItemAsync(KEYS.HOME_VIEW, homeView), SecureStore.setItemAsync(KEYS.AI_ENABLED, String(aiEnabled)), SecureStore.setItemAsync(KEYS.AI_KEY, aiKey), + SecureStore.setItemAsync(KEYS.AI_BASE_URL, aiBaseUrl), + SecureStore.setItemAsync(KEYS.AI_MODEL, aiModel), SecureStore.setItemAsync(KEYS.MD_TEMPLATE, mdTemplate), SecureStore.setItemAsync(KEYS.GIT_PROVIDER, gitProvider), SecureStore.setItemAsync(KEYS.GITEA_URL, giteaUrl), @@ -300,20 +310,52 @@ export default function SettingsScreen() { ]} /> - AI (optional) + AI — Root Cause Assistant + + + When enabled, a button appears on the capture form to suggest a root cause and fix + based on the incident title and symptom. Uses any OpenAI-compatible API — + set the base URL below to point at a local Ollama instance or leave empty + for OpenAI (api.openai.com). + + {aiEnabled && ( - + <> + + + + )} Git Repository