From 7e1a75574a1af153d76d718f2f042a89c045b081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20UNGER?= Date: Wed, 5 Feb 2025 11:18:52 +0100 Subject: [PATCH 1/8] implement command history --- db.go | 51 +++++++++++++++++++++- frontend/src/components/CommandLine.svelte | 48 ++++++++++++++++++-- frontend/src/stores/commandHistoryStore.js | 3 ++ frontend/wailsjs/go/main/Database.d.ts | 4 ++ frontend/wailsjs/go/main/Database.js | 8 ++++ model.go | 2 +- 6 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 frontend/src/stores/commandHistoryStore.js diff --git a/db.go b/db.go index 9237caf7..795c4cef 100644 --- a/db.go +++ b/db.go @@ -98,6 +98,18 @@ func (d *Database) SetupDatabase(path string) error { return err } + _, err = d.db.Exec(` + CREATE TABLE IF NOT EXISTS command_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + command TEXT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP + ) + `) + if err != nil { + fmt.Println("Error creating command_history table:", err) + return err + } + // Insert or update the database version _, err = d.db.Exec(`INSERT OR REPLACE INTO metadata (key, value) VALUES ('database_version', ?)`, DatabaseVersion) if err != nil { @@ -125,7 +137,7 @@ func (d *Database) OpenDatabase(path string) error { } // Check if the required tables exist - requiredTables := []string{"position", "analysis", "comment", "metadata"} + requiredTables := []string{"position", "analysis", "comment", "metadata", "command_history"} for _, table := range requiredTables { var tableName string err = d.db.QueryRow(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, table).Scan(&tableName) @@ -1746,3 +1758,40 @@ func (p *Position) MatchesPlayer2OutfieldBlot(filter string) bool { } return false } + +// SaveCommand saves a command to the command_history table +func (d *Database) SaveCommand(command string) error { + d.mu.Lock() + defer d.mu.Unlock() + + _, err := d.db.Exec(`INSERT INTO command_history (command) VALUES (?)`, command) + if err != nil { + fmt.Println("Error saving command:", err) + return err + } + return nil +} + +// LoadCommandHistory loads the command history from the command_history table +func (d *Database) LoadCommandHistory() ([]string, error) { + d.mu.Lock() + defer d.mu.Unlock() + + rows, err := d.db.Query(`SELECT command FROM command_history ORDER BY timestamp ASC`) + if err != nil { + fmt.Println("Error loading command history:", err) + return nil, err + } + defer rows.Close() + + var history []string + for rows.Next() { + var command string + if err = rows.Scan(&command); err != nil { + fmt.Println("Error scanning command:", err) + return nil, err + } + history = append(history, command) + } + return history, nil +} diff --git a/frontend/src/components/CommandLine.svelte b/frontend/src/components/CommandLine.svelte index 5bbcad25..604fc391 100644 --- a/frontend/src/components/CommandLine.svelte +++ b/frontend/src/components/CommandLine.svelte @@ -5,6 +5,8 @@ import { positionsStore } from '../stores/positionStore'; import { showMetModalStore, showTakePoint2LastModalStore, showTakePoint2LiveModalStore, showTakePoint4LastModalStore, showTakePoint4LiveModalStore, showGammonValue1ModalStore, showGammonValue2ModalStore, showGammonValue4ModalStore, showMetadataModalStore, showTakePoint2ModalStore, showTakePoint4ModalStore } from '../stores/uiStore'; import { databaseLoadedStore } from '../stores/databaseStore'; // Ensure the import path is correct + import { commandHistoryStore } from '../stores/commandHistoryStore'; // Import command history store + import { LoadCommandHistory, SaveCommand } from '../../wailsjs/go/main/Database.js'; // Import database functions export let onToggleHelp; export let onNewDatabase; @@ -29,7 +31,12 @@ let databaseLoaded = false; databaseLoadedStore.subscribe(value => databaseLoaded = value); - showCommandStore.subscribe(value => { + let commandHistory = []; + let historyIndex = -1; + + commandHistoryStore.subscribe(value => commandHistory = value); + + showCommandStore.subscribe(async value => { if (value) { previousModeStore.set($statusBarModeStore); statusBarModeStore.set('COMMAND'); @@ -38,6 +45,11 @@ inputEl?.focus(); }, 0); window.addEventListener('click', handleClickOutside); + + // Load command history from the database + const history = await LoadCommandHistory(); + commandHistoryStore.set((history || []).reverse()); // Reverse the order of history + historyIndex = -1; // Start at the end of the history } else { statusBarModeStore.set($previousModeStore); // Restore the previous mode window.removeEventListener('click', handleClickOutside); @@ -48,13 +60,43 @@ event.stopPropagation(); if ($showCommandStore) { - if (event.code === 'Backspace' && inputEl.value === '') { + if (event.code === 'ArrowUp') { + if (historyIndex < commandHistory.length - 1) { + historyIndex++; + commandTextStore.set(commandHistory[historyIndex]); + // Move cursor to the end without delay + requestAnimationFrame(() => { + inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length); + }); + } + } else if (event.code === 'ArrowDown') { + if (historyIndex > 0) { + historyIndex--; + commandTextStore.set(commandHistory[historyIndex]); + // Move cursor to the end without delay + requestAnimationFrame(() => { + inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length); + }); + } else { + historyIndex = -1; + commandTextStore.set(''); + } + } else if (event.code === 'Backspace' && inputEl.value === '') { showCommandStore.set(false); } else if (event.code === 'Escape') { showCommandStore.set(false); } else if (event.code === 'Enter') { const command = inputEl.value.trim(); console.log('Command entered:', command); // Debugging log + if (command) { + commandHistoryStore.update(history => { + history = history || []; // Ensure history is an array + history.unshift(command); // Add the new command to the beginning + return history; + }); + historyIndex = -1; // Reset the history index + SaveCommand(command); // Save the command to the database + } const match = command.match(/^(\d+)$/); if (match) { const positionNumber = parseInt(match[1], 10); @@ -229,7 +271,7 @@ } else if (command === 'tp4') { showTakePoint4ModalStore.set(true); // Show TakePoint4 modal } - showCommandStore.set(false); + showCommandStore.set(false); // Hide the command line after processing the command } else if (event.ctrlKey && event.code === 'KeyH') { onToggleHelp(); } diff --git a/frontend/src/stores/commandHistoryStore.js b/frontend/src/stores/commandHistoryStore.js new file mode 100644 index 00000000..e4d93931 --- /dev/null +++ b/frontend/src/stores/commandHistoryStore.js @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const commandHistoryStore = writable([]); diff --git a/frontend/wailsjs/go/main/Database.d.ts b/frontend/wailsjs/go/main/Database.d.ts index 6457e9ed..ddf8c97e 100755 --- a/frontend/wailsjs/go/main/Database.d.ts +++ b/frontend/wailsjs/go/main/Database.d.ts @@ -18,6 +18,8 @@ export function LoadAllPositions():Promise>; export function LoadAnalysis(arg1:number):Promise; +export function LoadCommandHistory():Promise>; + export function LoadComment(arg1:number):Promise; export function LoadMetadata():Promise<{[key: string]: string}>; @@ -32,6 +34,8 @@ export function PositionExists(arg1:main.Position):Promise<{[key: string]: any}> export function SaveAnalysis(arg1:number,arg2:main.PositionAnalysis):Promise; +export function SaveCommand(arg1:string):Promise; + export function SaveComment(arg1:number,arg2:string):Promise; export function SaveMetadata(arg1:{[key: string]: string}):Promise; diff --git a/frontend/wailsjs/go/main/Database.js b/frontend/wailsjs/go/main/Database.js index c5dbc878..ab7a283f 100755 --- a/frontend/wailsjs/go/main/Database.js +++ b/frontend/wailsjs/go/main/Database.js @@ -34,6 +34,10 @@ export function LoadAnalysis(arg1) { return window['go']['main']['Database']['LoadAnalysis'](arg1); } +export function LoadCommandHistory() { + return window['go']['main']['Database']['LoadCommandHistory'](); +} + export function LoadComment(arg1) { return window['go']['main']['Database']['LoadComment'](arg1); } @@ -62,6 +66,10 @@ export function SaveAnalysis(arg1, arg2) { return window['go']['main']['Database']['SaveAnalysis'](arg1, arg2); } +export function SaveCommand(arg1) { + return window['go']['main']['Database']['SaveCommand'](arg1); +} + export function SaveComment(arg1, arg2) { return window['go']['main']['Database']['SaveComment'](arg1, arg2); } diff --git a/model.go b/model.go index 310d58d3..970b9592 100644 --- a/model.go +++ b/model.go @@ -33,7 +33,7 @@ const ( ) const ( - DatabaseVersion = "1.0.0" + DatabaseVersion = "1.1.0" ) type Point struct { From f70e342c15cf06092003bb53f62cdfca35eddf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20UNGER?= Date: Wed, 5 Feb 2025 14:29:46 +0100 Subject: [PATCH 2/8] add db migration 1.0 to 1.1 logic and command --- db.go | 82 +++++++++++++++++++++- frontend/src/components/CommandLine.svelte | 12 +++- frontend/wailsjs/go/main/Database.d.ts | 2 + frontend/wailsjs/go/main/Database.js | 4 ++ 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/db.go b/db.go index 795c4cef..50b16042 100644 --- a/db.go +++ b/db.go @@ -136,8 +136,20 @@ func (d *Database) OpenDatabase(path string) error { return err } - // Check if the required tables exist - requiredTables := []string{"position", "analysis", "comment", "metadata", "command_history"} + // Check the database version + var dbVersion string + err = d.db.QueryRow(`SELECT value FROM metadata WHERE key = 'database_version'`).Scan(&dbVersion) + if err != nil { + fmt.Println("Error querying database version:", err) + return err + } + + // Check if the required tables exist based on the database version + requiredTables := []string{"position", "analysis", "comment", "metadata"} + if dbVersion >= "1.1.0" { + requiredTables = append(requiredTables, "command_history") + } + for _, table := range requiredTables { var tableName string err = d.db.QueryRow(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, table).Scan(&tableName) @@ -1764,7 +1776,19 @@ func (d *Database) SaveCommand(command string) error { d.mu.Lock() defer d.mu.Unlock() - _, err := d.db.Exec(`INSERT INTO command_history (command) VALUES (?)`, command) + // Check if the database version is 1.1.0 or higher + var dbVersion string + err := d.db.QueryRow(`SELECT value FROM metadata WHERE key = 'database_version'`).Scan(&dbVersion) + if err != nil { + fmt.Println("Error querying database version:", err) + return err + } + + if dbVersion < "1.1.0" { + return fmt.Errorf("database version is lower than 1.1.0, current version: %s", dbVersion) + } + + _, err = d.db.Exec(`INSERT INTO command_history (command) VALUES (?)`, command) if err != nil { fmt.Println("Error saving command:", err) return err @@ -1777,6 +1801,18 @@ func (d *Database) LoadCommandHistory() ([]string, error) { d.mu.Lock() defer d.mu.Unlock() + // Check if the database version is 1.1.0 or higher + var dbVersion string + err := d.db.QueryRow(`SELECT value FROM metadata WHERE key = 'database_version'`).Scan(&dbVersion) + if err != nil { + fmt.Println("Error querying database version:", err) + return nil, err + } + + if dbVersion < "1.1.0" { + return nil, fmt.Errorf("database version is lower than 1.1.0, current version: %s", dbVersion) + } + rows, err := d.db.Query(`SELECT command FROM command_history ORDER BY timestamp ASC`) if err != nil { fmt.Println("Error loading command history:", err) @@ -1795,3 +1831,43 @@ func (d *Database) LoadCommandHistory() ([]string, error) { } return history, nil } + +func (d *Database) Migrate_1_0_0_to_1_1_0() error { + d.mu.Lock() + defer d.mu.Unlock() + + // Check current database version + var dbVersion string + err := d.db.QueryRow(`SELECT value FROM metadata WHERE key = 'database_version'`).Scan(&dbVersion) + if err != nil { + fmt.Println("Error querying database version:", err) + return err + } + + if dbVersion != "1.0.0" { + return fmt.Errorf("database version is not 1.0.0, current version: %s", dbVersion) + } + + // Create the command_history table + _, err = d.db.Exec(` + CREATE TABLE IF NOT EXISTS command_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + command TEXT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP + ) + `) + if err != nil { + fmt.Println("Error creating command_history table:", err) + return err + } + + // Update the database version to 1.1.0 + _, err = d.db.Exec(`UPDATE metadata SET value = ? WHERE key = 'database_version'`, "1.1.0") + if err != nil { + fmt.Println("Error updating database version:", err) + return err + } + + fmt.Println("Database successfully migrated from version 1.0.0 to 1.1.0") + return nil +} diff --git a/frontend/src/components/CommandLine.svelte b/frontend/src/components/CommandLine.svelte index 604fc391..a9012e2b 100644 --- a/frontend/src/components/CommandLine.svelte +++ b/frontend/src/components/CommandLine.svelte @@ -1,7 +1,7 @@