Skip to content

Commit 0a77695

Browse files
committed
Dashboard: promote candidates, fix tray icon, fix status dropdown alignment, remove dead formatConflictSummary
1 parent c8517dd commit 0a77695

10 files changed

Lines changed: 122 additions & 26 deletions

File tree

packages/dashboard/src-tauri/Cargo.lock

Lines changed: 53 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dashboard/src-tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ md5 = "0.7"
2727
tauri-plugin-updater = "2"
2828
tauri-plugin-process = "2"
2929
tauri-plugin-dialog = "2"
30+
image = { version = "0.25.6", default-features = false, features = ["png"] }
3031

3132
[features]
3233
custom-protocol = ["tauri/custom-protocol"]
2.24 KB
Loading

packages/dashboard/src-tauri/src/commands.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,16 @@ pub fn delete_user_memory_candidate(
410410
db::delete_user_memory_candidate(&conn, id).map_err(|e| e.to_string())
411411
}
412412

413+
#[tauri::command]
414+
pub fn promote_user_memory_candidate(
415+
state: State<'_, AppState>,
416+
id: i64,
417+
) -> Result<(), String> {
418+
let path = state.get_db_path()?;
419+
let conn = db::open_readwrite(&path).map_err(|e| e.to_string())?;
420+
db::promote_user_memory_candidate(&conn, id).map_err(|e| e.to_string())
421+
}
422+
413423
// ── Health commands ─────────────────────────────────────────
414424

415425
#[tauri::command]

packages/dashboard/src-tauri/src/db.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,31 @@ pub fn delete_user_memory_candidate(conn: &Connection, id: i64) -> Result<(), ru
17661766
Ok(())
17671767
}
17681768

1769+
pub fn promote_user_memory_candidate(conn: &Connection, id: i64) -> Result<(), rusqlite::Error> {
1770+
let now = chrono::Utc::now().timestamp_millis();
1771+
1772+
// Read the candidate content
1773+
let content: String = conn.query_row(
1774+
"SELECT content FROM user_memory_candidates WHERE id = ?1",
1775+
rusqlite::params![id],
1776+
|row| row.get(0),
1777+
)?;
1778+
1779+
// Insert as a stable user memory
1780+
conn.execute(
1781+
"INSERT INTO user_memories (content, status, promoted_at, source_candidate_ids, created_at, updated_at) VALUES (?1, 'active', ?2, ?3, ?2, ?2)",
1782+
rusqlite::params![content, now, format!("[{}]", id)],
1783+
)?;
1784+
1785+
// Delete the candidate
1786+
conn.execute(
1787+
"DELETE FROM user_memory_candidates WHERE id = ?1",
1788+
rusqlite::params![id],
1789+
)?;
1790+
1791+
Ok(())
1792+
}
1793+
17691794
// ── Database health ───────────────────────────────────────
17701795

17711796
pub fn get_db_health(db_path: &PathBuf) -> DbHealth {

packages/dashboard/src-tauri/src/main.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ fn main() {
8585
commands::dismiss_user_memory,
8686
commands::delete_user_memory,
8787
commands::delete_user_memory_candidate,
88+
commands::promote_user_memory_candidate,
8889
// Health
8990
commands::get_db_health,
9091
])
@@ -121,8 +122,13 @@ fn main() {
121122
}
122123
});
123124

124-
if let Some(icon) = app.default_window_icon().cloned() {
125-
tray_builder = tray_builder.icon(icon);
125+
{
126+
let png_bytes = include_bytes!("../icons/tray-icon.png");
127+
let img = image::load_from_memory(png_bytes).expect("failed to decode tray icon PNG");
128+
let rgba = img.to_rgba8();
129+
let (w, h) = rgba.dimensions();
130+
let icon = tauri::image::Image::new_owned(rgba.into_raw(), w, h);
131+
tray_builder = tray_builder.icon(icon).icon_as_template(true);
126132
}
127133

128134
tray_builder.build(app)?;

packages/dashboard/src-tauri/tauri.conf.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
"transparent": false
2424
}
2525
],
26-
"trayIcon": {
27-
"iconPath": "icons/tray-icon.png",
28-
"iconAsTemplate": true
29-
},
3026
"security": {
3127
"csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:"
3228
},

packages/dashboard/src/components/UserMemories/UserMemories.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
dismissUserMemory,
77
deleteUserMemory,
88
deleteUserMemoryCandidate,
9+
promoteUserMemoryCandidate,
910
formatRelativeTime,
1011
truncate,
1112
} from "../../lib/api";
@@ -66,6 +67,19 @@ export default function UserMemories() {
6667
}
6768
};
6869

70+
const handlePromoteCandidate = async (id: number) => {
71+
try {
72+
setError(null);
73+
await promoteUserMemoryCandidate(id);
74+
refetchCandidates();
75+
refetchMemories();
76+
} catch (e: unknown) {
77+
setError(
78+
`Failed to promote candidate: ${e instanceof Error ? e.message : String(e)}`,
79+
);
80+
}
81+
};
82+
6983
const statusPillClass = (status: string) => {
7084
switch (status) {
7185
case "active":
@@ -128,6 +142,7 @@ export default function UserMemories() {
128142
value={statusFilter()}
129143
onChange={setStatusFilter}
130144
placeholder="All status"
145+
align="left"
131146
options={[
132147
{ value: "", label: "All status" },
133148
{ value: "active", label: "Active" },
@@ -282,6 +297,12 @@ export default function UserMemories() {
282297
"margin-top": "8px",
283298
}}
284299
>
300+
<button
301+
class="btn sm"
302+
onClick={() => handlePromoteCandidate(candidate.id)}
303+
>
304+
Promote
305+
</button>
285306
<button
286307
class="btn sm danger"
287308
onClick={() => handleDeleteCandidate(candidate.id)}

packages/dashboard/src/lib/api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ export async function deleteUserMemoryCandidate(id: number): Promise<void> {
228228
return invoke("delete_user_memory_candidate", { id });
229229
}
230230

231+
export async function promoteUserMemoryCandidate(id: number): Promise<void> {
232+
return invoke("promote_user_memory_candidate", { id });
233+
}
234+
231235
// ── Utilities ───────────────────────────────────────────────
232236

233237
export function formatTimestamp(ts: number): string {

packages/plugin/src/shared/conflict-detector.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -277,22 +277,6 @@ function readOmoDisabledHooks(directory: string): Set<string> {
277277
return disabled;
278278
}
279279

280-
/**
281-
* Generate a user-facing summary of conflicts for display in dialogs/notifications.
282-
*/
283-
export function formatConflictSummary(result: ConflictResult): string {
284-
if (!result.hasConflict) return "";
285-
286-
const lines = [
287-
"⚠️ Magic Context is disabled due to conflicting configuration:\n",
288-
...result.reasons.map((r) => ` • ${r}`),
289-
"",
290-
"Run `bunx @cortexkit/opencode-magic-context doctor` to fix,",
291-
"or resolve these conflicts manually in your OpenCode config.",
292-
];
293-
return lines.join("\n");
294-
}
295-
296280
/**
297281
* Generate a short conflict summary for ignored message display.
298282
*/

0 commit comments

Comments
 (0)