Report if newer version are availible in /api (#1366)

* Report if newer version are availible in /api

* Render version update hint in UI, next to version

* Fix lint
This commit is contained in:
Tom Wilkie
2016-04-22 10:25:00 +01:00
parent 3ec7e0227b
commit 901f46c5fc
7 changed files with 57 additions and 10 deletions

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"strings"
"sync"
"github.com/PuerkitoBio/ghost/handlers"
"github.com/gorilla/mux"
@@ -132,17 +133,35 @@ func RegisterReportPostHandler(a Adder, router *mux.Router) {
}))
}
var newVersion = struct {
sync.Mutex
*xfer.NewVersionInfo
}{}
// NewVersion is called to expose new version information to /api
func NewVersion(version, downloadURL string) {
newVersion.Lock()
defer newVersion.Unlock()
newVersion.NewVersionInfo = &xfer.NewVersionInfo{
Version: version,
DownloadURL: downloadURL,
}
}
func apiHandler(rep Reporter) CtxHandlerFunc {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
report, err := rep.Report(ctx)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
newVersion.Lock()
defer newVersion.Unlock()
respondWith(w, http.StatusOK, xfer.Details{
ID: UniqueID,
Version: Version,
Hostname: hostname.Get(),
Plugins: report.Plugins,
ID: UniqueID,
Version: Version,
Hostname: hostname.Get(),
Plugins: report.Plugins,
NewVersion: newVersion.NewVersionInfo,
})
}
}

View File

@@ -53,6 +53,7 @@ function getStateFromStores() {
updatePaused: AppStore.isUpdatePaused(),
updatePausedAt: AppStore.getUpdatePausedAt(),
version: AppStore.getVersion(),
versionUpdate: AppStore.getVersionUpdate(),
plugins: AppStore.getPlugins(),
websocketClosed: AppStore.isWebsocketClosed()
};
@@ -183,7 +184,9 @@ export default class App extends React.Component {
activeOptions={this.state.activeTopologyOptions} />
</Sidebar>
<Footer {...this.state} />
<Footer hostname={this.state.hostname} plugins={this.state.plugins}
updatePaused={this.state.updatePaused} updatePausedAt={this.state.updatePausedAt}
version={this.state.version} versionUpdate={this.state.versionUpdate} />
</div>
);
}

View File

@@ -9,7 +9,7 @@ import { clickDownloadGraph, clickForceRelayout, clickPauseUpdate,
import { basePathSlash } from '../utils/web-api-utils';
export default function Footer(props) {
const { hostname, plugins, updatePaused, updatePausedAt, version } = props;
const { hostname, plugins, updatePaused, updatePausedAt, version, versionUpdate } = props;
const contrastMode = isContrastMode();
// link url to switch contrast with current UI state
@@ -38,10 +38,18 @@ export default function Footer(props) {
pauseLabel = 'Paused';
}
const versionUpdateTitle = versionUpdate
? `New version available: ${versionUpdate.version}. Click to download`
: '';
return (
<div className="footer">
<div className="footer-status">
{versionUpdate && <a className="footer-versionupdate"
title={versionUpdateTitle} href={versionUpdate.downloadUrl} target="_blank">
Update available: {versionUpdate.version}
</a>}
<span className="footer-label">Version</span>
{version}
<span className="footer-label">on</span>

View File

@@ -46,6 +46,7 @@ let highlightedEdgeIds = makeSet();
let highlightedNodeIds = makeSet();
let hostname = '...';
let version = '...';
let versionUpdate = null;
let plugins = [];
let mouseOverEdgeId = null;
let mouseOverNodeId = null;
@@ -276,11 +277,14 @@ export class AppStore extends Store {
return version;
}
getVersionUpdate() {
return versionUpdate;
}
getPlugins() {
return plugins;
}
isForceRelayout() {
return forceRelayout;
}
@@ -686,6 +690,7 @@ export class AppStore extends Store {
hostname = payload.hostname;
version = payload.version;
plugins = payload.plugins;
versionUpdate = payload.newVersion;
this.__emitChange();
break;
}

View File

@@ -188,9 +188,6 @@ h2 {
a {
color: @text-secondary-color;
.btn-opacity;
text-decoration: none;
font-weight: bold;
font-size: 90%;
cursor: pointer;
}
@@ -203,6 +200,11 @@ h2 {
margin: 0 0.25em;
}
&-versionupdate {
margin-right: 0.5em;
text-transform: uppercase;
}
&-icon {
margin-left: 0.5em;
padding: 4px 3px;

View File

@@ -17,4 +17,13 @@ type Details struct {
Version string `json:"version"`
Hostname string `json:"hostname"`
Plugins PluginSpecs `json:"plugins,omitempty"`
NewVersion *NewVersionInfo `json:"newVersion,omitempty"`
}
// NewVersionInfo is the struct exposed in /api when there is a new
// version of Scope available.
type NewVersionInfo struct {
Version string `json:"version"`
DownloadURL string `json:"downloadUrl"`
}

View File

@@ -184,6 +184,7 @@ func appMain(flags appFlags) {
} else if r.Outdated {
log.Infof("Scope version %s is available; please update at %s",
r.CurrentVersion, r.CurrentDownloadURL)
app.NewVersion(r.CurrentVersion, r.CurrentDownloadURL)
}
})