5e09ba1d58
Reading a log file meant copying the configured path out of Settings and pasting it into a file manager. The Logs directory row now carries an Open button beside Browse that reveals the folder directly. The new src/platform/filemanager package holds the platform split — explorer on Windows, xdg-open on Linux, an "unsupported" error elsewhere — and starts the handler without waiting on it, since Explorer exits non-zero even after it opens the window and blocking would stall the UI thread. A missing path, a path that is a file, and a handler that will not start are all reported to the user; the logs directory does not exist until the first run, so that case is reachable. The button opens whatever the field currently holds rather than the saved config, so an edit can be checked before Save. Resolving a relative directory against the application folder is the store's rule, so resolveConfiguredDir is now exported as storage.ResolveConfiguredDir instead of being duplicated in the UI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43 lines
1.3 KiB
Go
43 lines
1.3 KiB
Go
// Package filemanager opens a directory in the desktop file manager, so the
|
|
// UI can reveal a configured folder (logs, jobs) without knowing which handler
|
|
// the platform uses.
|
|
package filemanager
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
)
|
|
|
|
// Open shows dir in the platform file manager. A missing path, a path that is
|
|
// not a directory, and a handler that fails to start are all returned as
|
|
// errors so the caller can surface them instead of appearing to do nothing.
|
|
func Open(dir string) error {
|
|
info, err := os.Stat(dir)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return fmt.Errorf("folder does not exist: %s", dir)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !info.IsDir() {
|
|
return fmt.Errorf("not a folder: %s", dir)
|
|
}
|
|
name, args := openCommand(dir)
|
|
if name == "" {
|
|
return fmt.Errorf("opening a folder is not supported on %s", runtime.GOOS)
|
|
}
|
|
command := exec.Command(name, args...)
|
|
if err := command.Start(); err != nil {
|
|
return err
|
|
}
|
|
// The handler hands the request to the desktop shell and exits on its own —
|
|
// Windows Explorer even exits non-zero after opening the window — so its
|
|
// status carries no information. Wait runs only to release the process
|
|
// handle, and never blocks the caller.
|
|
go func() { _ = command.Wait() }()
|
|
return nil
|
|
}
|