diff --git a/cmd/server/main-server.go b/cmd/server/main-server.go
index 74b350277..0fd1a2234 100644
--- a/cmd/server/main-server.go
+++ b/cmd/server/main-server.go
@@ -175,7 +175,6 @@ func main() {
log.Printf("error setting auth key: %v\n", err)
return
}
-
err = service.ValidateServiceMap()
if err != nil {
log.Printf("error validating service map: %v\n", err)
@@ -186,6 +185,11 @@ func main() {
log.Printf("error ensuring wave home dir: %v\n", err)
return
}
+ err = wavebase.EnsureWaveDBDir()
+ if err != nil {
+ log.Printf("error ensuring wave db dir: %v\n", err)
+ return
+ }
waveLock, err := wavebase.AcquireWaveLock()
if err != nil {
log.Printf("error acquiring wave lock (another instance of Wave is likely running): %v\n", err)
@@ -197,7 +201,6 @@ func main() {
log.Printf("error releasing wave lock: %v\n", err)
}
}()
-
log.Printf("wave version: %s (%s)\n", WaveVersion, BuildTime)
log.Printf("wave home dir: %s\n", wavebase.GetWaveHomeDir())
err = filestore.InitFilestore()
@@ -210,6 +213,10 @@ func main() {
log.Printf("error initializing wstore: %v\n", err)
return
}
+ migrateErr := wstore.TryMigrateOldHistory()
+ if migrateErr != nil {
+ log.Printf("error migrating old history: %v\n", migrateErr)
+ }
go func() {
err := shellutil.InitCustomShellStartupFiles()
if err != nil {
diff --git a/db/migrations-wstore/000004_history.down.sql b/db/migrations-wstore/000004_history.down.sql
new file mode 100644
index 000000000..556e9b40a
--- /dev/null
+++ b/db/migrations-wstore/000004_history.down.sql
@@ -0,0 +1 @@
+DROP TABLE history_migrated;
\ No newline at end of file
diff --git a/db/migrations-wstore/000004_history.up.sql b/db/migrations-wstore/000004_history.up.sql
new file mode 100644
index 000000000..6b0f2a684
--- /dev/null
+++ b/db/migrations-wstore/000004_history.up.sql
@@ -0,0 +1,9 @@
+CREATE TABLE history_migrated (
+ historyid varchar(36) PRIMARY KEY,
+ ts bigint NOT NULL,
+ remotename varchar(200) NOT NULL,
+ haderror boolean NOT NULL,
+ cmdstr text NOT NULL,
+ exitcode int NULL DEFAULT NULL,
+ durationms int NULL DEFAULT NULL
+);
diff --git a/emain/emain.ts b/emain/emain.ts
index b20f3d065..2e62d0ae1 100644
--- a/emain/emain.ts
+++ b/emain/emain.ts
@@ -65,7 +65,7 @@ const waveHome = getWaveHomeDir();
const oldConsoleLog = console.log;
const loggerTransports: winston.transport[] = [
- new winston.transports.File({ filename: path.join(getWaveHomeDir(), "waveterm-app.log"), level: "info" }),
+ new winston.transports.File({ filename: path.join(getWaveHomeDir(), "waveapp.log"), level: "info" }),
];
if (isDev) {
loggerTransports.push(new winston.transports.Console());
diff --git a/frontend/app/asset/dots-anim-4.svg b/frontend/app/asset/dots-anim-4.svg
new file mode 100644
index 000000000..028aaf349
--- /dev/null
+++ b/frontend/app/asset/dots-anim-4.svg
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/frontend/app/block/block.less b/frontend/app/block/block.less
index b4718cde4..bc13f890a 100644
--- a/frontend/app/block/block.less
+++ b/frontend/app/block/block.less
@@ -174,6 +174,15 @@
overflow: hidden;
padding-right: 4px;
}
+
+ .connecting-svg {
+ position: relative;
+ top: 5px;
+ left: 9px;
+ svg {
+ fill: var(--warning-color);
+ }
+ }
}
.block-frame-textelems-wrapper {
diff --git a/frontend/app/block/blockutil.tsx b/frontend/app/block/blockutil.tsx
index 33ba28736..a5f22b9ea 100644
--- a/frontend/app/block/blockutil.tsx
+++ b/frontend/app/block/blockutil.tsx
@@ -9,6 +9,7 @@ import * as util from "@/util/util";
import clsx from "clsx";
import * as jotai from "jotai";
import * as React from "react";
+import DotsSvg from "../asset/dots-anim-4.svg";
export const colorRegex = /^((#[0-9a-f]{6,8})|([a-z]+))$/;
@@ -225,11 +226,16 @@ export const ConnectionButton = React.memo(
} else {
titleText = "Connected to " + connection;
let iconName = "arrow-right-arrow-left";
+ let iconSvg = null;
if (connStatus?.status == "connecting") {
color = "var(--warning-color)";
titleText = "Connecting to " + connection;
- iconName = "rotate";
- shouldSpin = true;
+ shouldSpin = false;
+ iconSvg = (
+
+
+
+ );
} else if (connStatus?.status == "error") {
color = "var(--error-color)";
titleText = "Error connecting to " + connection;
@@ -242,12 +248,16 @@ export const ConnectionButton = React.memo(
titleText = "Disconnected from " + connection;
showDisconnectedSlash = true;
}
- connIconElem = (
-
- );
+ if (iconSvg != null) {
+ connIconElem = iconSvg;
+ } else {
+ connIconElem = (
+
+ );
+ }
}
return (
diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts
index 3013f3de0..0993c2cdd 100644
--- a/frontend/types/gotypes.d.ts
+++ b/frontend/types/gotypes.d.ts
@@ -36,6 +36,7 @@ declare global {
type Client = WaveObj & {
windowids: string[];
tosagreed?: number;
+ historymigrated?: boolean;
};
// wshrpc.CommandAppendIJsonData
diff --git a/pkg/filestore/blockstore_dbsetup.go b/pkg/filestore/blockstore_dbsetup.go
index 3580ebd65..11bf1fd11 100644
--- a/pkg/filestore/blockstore_dbsetup.go
+++ b/pkg/filestore/blockstore_dbsetup.go
@@ -51,7 +51,7 @@ func InitFilestore() error {
func GetDBName() string {
waveHome := wavebase.GetWaveHomeDir()
- return filepath.Join(waveHome, FilestoreDBName)
+ return filepath.Join(waveHome, wavebase.WaveDBDir, FilestoreDBName)
}
func MakeDB(ctx context.Context) (*sqlx.DB, error) {
diff --git a/pkg/util/shellutil/shellutil.go b/pkg/util/shellutil/shellutil.go
index f755dd8fa..ac3cfdf22 100644
--- a/pkg/util/shellutil/shellutil.go
+++ b/pkg/util/shellutil/shellutil.go
@@ -36,9 +36,9 @@ const WaveAppPathVarName = "WAVETERM_APP_PATH"
const AppPathBinDir = "bin"
const (
- ZshIntegrationDir = "zsh-integration"
- BashIntegrationDir = "bash-integration"
- PwshIntegrationDir = "pwsh-integration"
+ ZshIntegrationDir = "shell/zsh"
+ BashIntegrationDir = "shell/bash"
+ PwshIntegrationDir = "shell/pwsh"
WaveHomeBinDir = "bin"
ZshStartup_Zprofile = `
diff --git a/pkg/wavebase/wavebase.go b/pkg/wavebase/wavebase.go
index 76545da5e..5cb50aaa9 100644
--- a/pkg/wavebase/wavebase.go
+++ b/pkg/wavebase/wavebase.go
@@ -25,12 +25,13 @@ import (
var WaveVersion = "0.0.0"
var BuildTime = "0"
-const DefaultWaveHome = "~/.w2"
-const DevWaveHome = "~/.w2-dev"
+const DefaultWaveHome = "~/.waveterm"
+const DevWaveHome = "~/.waveterm-dev"
const WaveHomeVarName = "WAVETERM_HOME"
const WaveDevVarName = "WAVETERM_DEV"
-const WaveLockFile = "waveterm.lock"
+const WaveLockFile = "wave.lock"
const DomainSocketBaseName = "wave.sock"
+const WaveDBDir = "db"
const JwtSecret = "waveterm" // TODO generate and store this
var baseLock = &sync.Mutex{}
@@ -90,6 +91,10 @@ func EnsureWaveHomeDir() error {
return CacheEnsureDir(GetWaveHomeDir(), "wavehome", 0700, "wave home directory")
}
+func EnsureWaveDBDir() error {
+ return CacheEnsureDir(filepath.Join(GetWaveHomeDir(), WaveDBDir), "wavedb", 0700, "wave db directory")
+}
+
func CacheEnsureDir(dirName string, cacheKey string, perm os.FileMode, dirDesc string) error {
baseLock.Lock()
ok := ensureDirCache[cacheKey]
diff --git a/pkg/waveobj/wtype.go b/pkg/waveobj/wtype.go
index 6e53cf1cf..9494c995a 100644
--- a/pkg/waveobj/wtype.go
+++ b/pkg/waveobj/wtype.go
@@ -112,11 +112,12 @@ func (update *WaveObjUpdate) UnmarshalJSON(data []byte) error {
}
type Client struct {
- OID string `json:"oid"`
- Version int `json:"version"`
- WindowIds []string `json:"windowids"`
- Meta MetaMapType `json:"meta"`
- TosAgreed int64 `json:"tosagreed,omitempty"`
+ OID string `json:"oid"`
+ Version int `json:"version"`
+ WindowIds []string `json:"windowids"`
+ Meta MetaMapType `json:"meta"`
+ TosAgreed int64 `json:"tosagreed,omitempty"`
+ HistoryMigrated bool `json:"historymigrated,omitempty"`
}
func (*Client) GetOType() string {
diff --git a/pkg/wstore/wstore_dboldmigration.go b/pkg/wstore/wstore_dboldmigration.go
new file mode 100644
index 000000000..0fcbff5c1
--- /dev/null
+++ b/pkg/wstore/wstore_dboldmigration.go
@@ -0,0 +1,112 @@
+// Copyright 2024, Command Line Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+package wstore
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "time"
+
+ "github.com/jmoiron/sqlx"
+ "github.com/wavetermdev/thenextwave/pkg/wavebase"
+ "github.com/wavetermdev/thenextwave/pkg/waveobj"
+)
+
+const OldDBName = "~/.waveterm/waveterm.db"
+
+func GetOldDBName() string {
+ return wavebase.ExpandHomeDir(OldDBName)
+}
+
+func MakeOldDB(ctx context.Context) (*sqlx.DB, error) {
+ dbName := GetOldDBName()
+ rtn, err := sqlx.Open("sqlite3", fmt.Sprintf("file:%s?mode=ro&_busy_timeout=5000", dbName))
+ if err != nil {
+ return nil, err
+ }
+ rtn.DB.SetMaxOpenConns(1)
+ return rtn, nil
+}
+
+type OldHistoryType struct {
+ HistoryId string
+ Ts int64
+ RemoteName string
+ HadError bool
+ CmdStr string
+ ExitCode int
+ DurationMs int64
+}
+
+func GetAllOldHistory() ([]*OldHistoryType, error) {
+ query := `
+ SELECT
+ h.historyid,
+ h.ts,
+ COALESCE(r.remotecanonicalname, '') as remotename,
+ h.haderror,
+ h.cmdstr,
+ COALESCE(h.exitcode, 0) as exitcode,
+ COALESCE(h.durationms, 0) as durationms
+ FROM history h, remote r
+ WHERE h.remoteid = r.remoteid
+ AND NOT h.ismetacmd
+ `
+ db, err := MakeOldDB(context.Background())
+ if err != nil {
+ return nil, err
+ }
+ defer db.Close()
+ var rtn []*OldHistoryType
+ err = db.Select(&rtn, query)
+ if err != nil {
+ return nil, err
+ }
+ return rtn, nil
+}
+
+func ReplaceOldHistory(ctx context.Context, hist []*OldHistoryType) error {
+ return WithTx(ctx, func(tx *TxWrap) error {
+ query := `DELETE FROM history_migrated`
+ tx.Exec(query)
+ query = `INSERT INTO history_migrated (historyid, ts, remotename, haderror, cmdstr, exitcode, durationms)
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
+ for _, hobj := range hist {
+ tx.Exec(query, hobj.HistoryId, hobj.Ts, hobj.RemoteName, hobj.HadError, hobj.CmdStr, hobj.ExitCode, hobj.DurationMs)
+ }
+ return nil
+ })
+}
+
+func TryMigrateOldHistory() error {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancelFn()
+ client, err := DBGetSingleton[*waveobj.Client](ctx)
+ if err != nil {
+ return err
+ }
+ if client.HistoryMigrated {
+ return nil
+ }
+ log.Printf("trying to migrate old wave history\n")
+ client.HistoryMigrated = true
+ err = DBUpdate(ctx, client)
+ if err != nil {
+ return err
+ }
+ hist, err := GetAllOldHistory()
+ if err != nil {
+ return err
+ }
+ if len(hist) == 0 {
+ return nil
+ }
+ err = ReplaceOldHistory(ctx, hist)
+ if err != nil {
+ return err
+ }
+ log.Printf("migrated %d old wave history records\n", len(hist))
+ return nil
+}
diff --git a/pkg/wstore/wstore_dbsetup.go b/pkg/wstore/wstore_dbsetup.go
index b6258da8d..fa255ed87 100644
--- a/pkg/wstore/wstore_dbsetup.go
+++ b/pkg/wstore/wstore_dbsetup.go
@@ -43,7 +43,7 @@ func InitWStore() error {
func GetDBName() string {
waveHome := wavebase.GetWaveHomeDir()
- return filepath.Join(waveHome, WStoreDBName)
+ return filepath.Join(waveHome, wavebase.WaveDBDir, WStoreDBName)
}
func MakeDB(ctx context.Context) (*sqlx.DB, error) {