Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sidebar banner when new release is available #147

Merged
merged 19 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
17 changes: 17 additions & 0 deletions src/app/common/modals/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,17 @@ class ClientSettingsModal extends React.Component<{}, {}> {
commandRtnHandler(prtn, this.errorMessage);
}

@boundMethod
handleChangeReleaseCheck(val: boolean): void {
let prtn: Promise<CommandRtnType> = null;
if (val) {
prtn = GlobalCommandRunner.releaseCheckAutoOn(false);
} else {
prtn = GlobalCommandRunner.releaseCheckAutoOff(false);
}
commandRtnHandler(prtn, this.errorMessage);
}

getFontSizes(): any {
let availableFontSizes: { label: string; value: number }[] = [];
for (let s = MinFontSize; s <= MaxFontSize; s++) {
Expand Down Expand Up @@ -764,6 +775,12 @@ class ClientSettingsModal extends React.Component<{}, {}> {
<Toggle checked={!cdata.clientopts.notelemetry} onChange={this.handleChangeTelemetry} />
</div>
</div>
<div className="settings-field">
<div className="settings-label">Check for Updates Automatically</div>
<div className="settings-input">
<Toggle checked={!cdata.clientopts.noreleasecheck} onChange={this.handleChangeReleaseCheck} />
</div>
</div>
<div className="settings-field">
<div className="settings-label">OpenAI Token</div>
<div className="settings-input">
Expand Down
7 changes: 7 additions & 0 deletions src/app/sidebar/sidebar.less
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,11 @@
top: -3px;
}
}

.updateBanner {
margin-bottom: 10px;
background-color: white;
color: black;
text-align: center;
}
}
9 changes: 9 additions & 0 deletions src/app/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ class MainSideBar extends React.Component<{}, {}> {
}
let isCollapsed = this.collapsed.get();
let mainView = GlobalModel.activeMainView.get();
let clientData = GlobalModel.clientData.get();
return (
<div className={cn("main-sidebar", { collapsed: isCollapsed }, { "is-dev": GlobalModel.isDev })}>
<div className="title-bar-drag" />
Expand Down Expand Up @@ -242,6 +243,14 @@ class MainSideBar extends React.Component<{}, {}> {
</div>
<div className="middle hideScrollbarUntillHover">{this.getSessions()}</div>
<div className="bottom">
<If condition = {clientData?.releaseinfo?.releaseavailable}>
esimkowitz marked this conversation as resolved.
Show resolved Hide resolved
<div
className="item hoverEffect unselectable updateBanner"
onClick={() => openLink("https://www.waveterm.dev/download")}
>
Update Available!
</div>
</If>
<If condition={GlobalModel.isDev}>
<div className="item hoverEffect unselectable" onClick={this.handlePluginsClick}>
<AppsIcon className="icon" />
Expand Down
8 changes: 8 additions & 0 deletions src/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4312,6 +4312,14 @@ class CommandRunner {
return GlobalModel.submitCommand("telemetry", "on", null, { nohist: "1" }, interactive);
}

releaseCheckAutoOff(interactive: boolean): Promise<CommandRtnType> {
return GlobalModel.submitCommand("releasecheck", "autooff", null, { nohist: "1" }, interactive);
}

releaseCheckAutoOn(interactive: boolean): Promise<CommandRtnType> {
return GlobalModel.submitCommand("releasecheck", "autoon", null, { nohist: "1" }, interactive);
}

setTermFontSize(fsize: number, interactive: boolean): Promise<CommandRtnType> {
let kwargs = {
nohist: "1",
Expand Down
8 changes: 8 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,9 +454,16 @@ type FeOptsType = {

type ClientOptsType = {
notelemetry: boolean;
noreleasecheck: boolean;
acceptedtos: number;
};

type ReleaseInfoType = {
releaseavailable: boolean;
installedversion: string;
latestversion: string;
};

type ClientDataType = {
clientid: string;
userid: string;
Expand All @@ -465,6 +472,7 @@ type ClientDataType = {
cmdstoretype: "session" | "screen";
dbversion: number;
openaiopts?: OpenAIOptsType;
releaseinfo?: ReleaseInfoType;
};

type OpenAIOptsType = {
Expand Down
5 changes: 3 additions & 2 deletions wavesrv/cmd/main-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/wavetermdev/waveterm/waveshell/pkg/server"
"github.com/wavetermdev/waveterm/wavesrv/pkg/cmdrunner"
"github.com/wavetermdev/waveterm/wavesrv/pkg/pcloud"
"github.com/wavetermdev/waveterm/wavesrv/pkg/releasechecker"
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
"github.com/wavetermdev/waveterm/wavesrv/pkg/rtnstate"
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
Expand Down Expand Up @@ -715,7 +716,6 @@ func sendTelemetryWrapper() {
}
log.Printf("[error] in sendTelemetryWrapper: %v\n", r)
debug.PrintStack()
return
}()
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()
Expand All @@ -729,10 +729,11 @@ func telemetryLoop() {
var lastSent time.Time
time.Sleep(InitialTelemetryWait)
for {
dur := time.Now().Sub(lastSent)
dur := time.Since(lastSent)
if lastSent.IsZero() || dur >= TelemetryInterval {
lastSent = time.Now()
sendTelemetryWrapper()
releasechecker.CheckNewRelease(false)
esimkowitz marked this conversation as resolved.
Show resolved Hide resolved
}
time.Sleep(TelemetryTick)
}
Expand Down
1 change: 1 addition & 0 deletions wavesrv/db/migrations/000025_releaseinfo.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE client DROP COLUMN releaseinfo;
1 change: 1 addition & 0 deletions wavesrv/db/migrations/000025_releaseinfo.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE client ADD COLUMN releaseinfo json NOT NULL DEFAULT '{}';
1 change: 1 addition & 0 deletions wavesrv/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
)

require (
github.com/google/go-github/v57 v57.0.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
go.uber.org/atomic v1.7.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions wavesrv/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/golang-migrate/migrate/v4 v4.16.2 h1:8coYbMKUyInrFk1lfGfRovTLAW7PhWp8qQDT2iKfuoA=
github.com/golang-migrate/migrate/v4 v4.16.2/go.mod h1:pfcJX4nPHaVdc5nmdCikFBWtm+UBpiZjRNNsyBbp0/o=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs=
github.com/google/go-github/v57 v57.0.0/go.mod h1:s0omdnye0hvK/ecLvpsGfJMiRt85PimQh4oygmLIxHw=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
Expand Down Expand Up @@ -51,6 +54,7 @@ golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
84 changes: 84 additions & 0 deletions wavesrv/pkg/cmdrunner/cmdrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/wavetermdev/waveterm/wavesrv/pkg/comp"
"github.com/wavetermdev/waveterm/wavesrv/pkg/dbutil"
"github.com/wavetermdev/waveterm/wavesrv/pkg/pcloud"
"github.com/wavetermdev/waveterm/wavesrv/pkg/releasechecker"
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote/openai"
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
Expand Down Expand Up @@ -207,6 +208,10 @@ func init() {
registerCmdFn("telemetry:send", TelemetrySendCommand)
registerCmdFn("telemetry:show", TelemetryShowCommand)

registerCmdFn("releasecheck", ReleaseCheckCommand)
registerCmdFn("releasecheck:autoon", ReleaseCheckOnCommand)
registerCmdFn("releasecheck:autooff", ReleaseCheckOffCommand)

registerCmdFn("history", HistoryCommand)
registerCmdFn("history:viewall", HistoryViewAllCommand)
registerCmdFn("history:purge", HistoryPurgeCommand)
Expand Down Expand Up @@ -3716,6 +3721,7 @@ func ClientShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "userid", clientData.UserId))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "clientid", clientData.ClientId))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "telemetry", boolToStr(clientData.ClientOpts.NoTelemetry, "off", "on")))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "release-check", boolToStr(clientData.ClientOpts.NoReleaseCheck, "off", "on")))
buf.WriteString(fmt.Sprintf(" %-15s %d\n", "db-version", dbVersion))
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "client-version", clientVersion))
buf.WriteString(fmt.Sprintf(" %-15s %s %s\n", "server-version", scbase.WaveVersion, scbase.BuildTime))
Expand Down Expand Up @@ -3832,6 +3838,84 @@ func TelemetrySendCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
return sstore.InfoMsgUpdate("telemetry sent"), nil
}

func setNoReleaseCheck(ctx context.Context, clientData *sstore.ClientData, noReleaseCheckValue bool) error {
clientOpts := clientData.ClientOpts
clientOpts.NoReleaseCheck = noReleaseCheckValue
err := sstore.SetClientOpts(ctx, clientOpts)
if err != nil {
return fmt.Errorf("error trying to update client releaseCheck setting: %v", err)
}
log.Printf("client no-release-check setting updated to %v\n", noReleaseCheckValue)
return nil
}

func ReleaseCheckOnCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
clientData, err := sstore.EnsureClientData(ctx)
if err != nil {
return nil, fmt.Errorf("cannot retrieve client data: %v", err)
}
if !clientData.ClientOpts.NoReleaseCheck {
return sstore.InfoMsgUpdate("release check is already on"), nil
}
err = setNoReleaseCheck(ctx, clientData, false)
if err != nil {
return nil, err
}
go func() {
releasechecker.CheckNewRelease(false)
esimkowitz marked this conversation as resolved.
Show resolved Hide resolved
}()
clientData, err = sstore.EnsureClientData(ctx)
if err != nil {
return nil, fmt.Errorf("cannot retrieve updated client data: %v", err)
}
update := sstore.InfoMsgUpdate("automatic release checking is now on")
update.ClientData = clientData
return update, nil
}

func ReleaseCheckOffCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
clientData, err := sstore.EnsureClientData(ctx)
if err != nil {
return nil, fmt.Errorf("cannot retrieve client data: %v", err)
}
if clientData.ClientOpts.NoReleaseCheck {
return sstore.InfoMsgUpdate("release check is already off"), nil
}
err = setNoReleaseCheck(ctx, clientData, true)
if err != nil {
return nil, err
}
clientData, err = sstore.EnsureClientData(ctx)
if err != nil {
return nil, fmt.Errorf("cannot retrieve updated client data: %v", err)
}
update := sstore.InfoMsgUpdate("automatic release checking is now off")
update.ClientData = clientData
return update, nil
}

func ReleaseCheckCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
rslt, err := releasechecker.CheckNewRelease(true)

if err != nil {
return nil, fmt.Errorf("error checking for new release: %v", err)
}

if rslt == releasechecker.Failure {
return nil, fmt.Errorf("error checking for new release, see log for details")
}

clientData, err := sstore.EnsureClientData(ctx)
if err != nil {
return nil, fmt.Errorf("cannot retrieve updated client data: %v", err)
}

rsp := fmt.Sprintf("installed version: %s; latest release version: %s", clientData.ReleaseInfo.InstalledVersion, clientData.ReleaseInfo.LatestVersion)
update := sstore.InfoMsgUpdate(rsp)
update.ClientData = clientData
return update, nil
}

func formatTermOpts(termOpts sstore.TermOpts) string {
if termOpts.Cols == 0 {
return "???"
Expand Down
80 changes: 80 additions & 0 deletions wavesrv/pkg/releasechecker/releasechecker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package releasechecker

import (
"context"
"log"

"github.com/google/go-github/v57/github"
"golang.org/x/mod/semver"

"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
)

type ReleaseCheckResult int

const (
NotNeeded ReleaseCheckResult = 0
Success ReleaseCheckResult = 1
Failure ReleaseCheckResult = 2
Disabled ReleaseCheckResult = 3
)

func CheckNewRelease(force bool) (ReleaseCheckResult, error) {
// Check for the latest release in the DB
// latestRelease, err := dbutil.g
ctx := context.Background()
esimkowitz marked this conversation as resolved.
Show resolved Hide resolved
clientData, err := sstore.EnsureClientData(ctx)
if !force && clientData.ClientOpts.NoReleaseCheck {
log.Print("[releasechecker] Release check disabled by user preference")
return Disabled, nil
}

log.Printf("[releasechecker] Existing ReleaseInfo values: %v", clientData.ReleaseInfo)

if !force && err == nil && clientData.ReleaseInfo.ReleaseAvailable && semver.Compare(scbase.WaveVersion, clientData.ReleaseInfo.InstalledVersion) != 0 {
// We have already notified the frontend about a new release and the record is fresh. There is no need to check again.
log.Print("[releasechecker] Release check not needed")
return NotNeeded, nil
}
// Initialize an unauthenticated client
client := github.NewClient(nil)
// Get the latest release from the repository
release, rsp, err := client.Repositories.GetLatestRelease(ctx, "wavetermdev", "waveterm")

releaseInfoLatest := sstore.ReleaseInfoType{
ReleaseAvailable: false,
InstalledVersion: scbase.WaveVersion,
LatestVersion: scbase.WaveVersion,
}

if err != nil {
log.Printf("[releasechecker] Error getting latest release: %v", err)
return Failure, err
}

if rsp.StatusCode != 200 {
log.Printf("[releasechecker] Response from Github is not success: %v", rsp)
return Failure, nil
}

releaseInfoLatest.LatestVersion = *release.TagName
if semver.Compare(releaseInfoLatest.InstalledVersion, releaseInfoLatest.LatestVersion) < 0 {
log.Printf("[releasechecker] New release available: %s", releaseInfoLatest.LatestVersion)
releaseInfoLatest.ReleaseAvailable = true
}

// Update the release info in the DB
log.Printf("[releasechecker] Updating release info: %v", releaseInfoLatest)
err = sstore.SetReleaseInfo(ctx, releaseInfoLatest)
if err != nil {
log.Printf("[releasechecker] Error updating release info: %v", err)
return Failure, err
}
update := &sstore.ModelUpdate{
ClientData: clientData,
}
sstore.MainBus.SendUpdate(update)

return Success, nil
}
2 changes: 1 addition & 1 deletion wavesrv/pkg/sstore/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/golang-migrate/migrate/v4"
)

const MaxMigration = 24
const MaxMigration = 25
const MigratePrimaryScreenVersion = 9
const CmdScreenSpecialMigration = 13
const CmdLineSpecialMigration = 20
Expand Down
Loading