mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
Merge pull request #2144 from weaveworks/2133-scope-component
Allow Scope UI to be installed as a Node module
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -56,3 +56,4 @@ vendor/github.com/ugorji/go/codec/codecgen/bin/*
|
||||
client/build-external/*
|
||||
prog/staticui/*
|
||||
prog/externalui/*
|
||||
client/pkg
|
||||
|
||||
3
Makefile
3
Makefile
@@ -167,6 +167,9 @@ ui-upload: client/build-external/index.html
|
||||
AWS_SECRET_ACCESS_KEY=$$UI_BUCKET_KEY_SECRET \
|
||||
aws s3 cp client/build-external/ s3://static.weave.works/scope-ui/ --recursive --exclude '*.html'
|
||||
|
||||
ui-build-pkg:
|
||||
cd client && npm run build-pkg && npm run s3-publish
|
||||
|
||||
clean:
|
||||
$(GO) clean ./...
|
||||
# Don't actually rmi the build images - rm'ing the .uptodate files is enough to ensure
|
||||
|
||||
@@ -75,7 +75,8 @@ deployment:
|
||||
)) &&
|
||||
docker push ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope &&
|
||||
docker push ${DOCKER_ORGANIZATION:-$DOCKER_USER}/scope:$(./tools/image-tag) &&
|
||||
(test -z "${UI_BUCKET_KEY_ID}" || make ui-upload)
|
||||
(test -z "${UI_BUCKET_KEY_ID}" || make ui-upload) &&
|
||||
make ui-build-pkg
|
||||
)
|
||||
- |
|
||||
test -z "${QUAY_USER}" || (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"extends": "airbnb",
|
||||
"parser": "babel-eslint",
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jest": true,
|
||||
|
||||
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@@ -2,3 +2,4 @@ node_modules
|
||||
build/
|
||||
coverage/
|
||||
test/*png
|
||||
weave-scope.tgz
|
||||
|
||||
@@ -104,7 +104,7 @@ class App extends React.Component {
|
||||
const isIframe = window !== window.top;
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<div className="scope-app">
|
||||
{showingDebugToolbar() && <DebugToolbar />}
|
||||
|
||||
{showingHelp && <HelpPanel />}
|
||||
|
||||
@@ -9,10 +9,8 @@ import Term from 'xterm';
|
||||
import { clickCloseTerminal } from '../actions/app-actions';
|
||||
import { getNeutralColor } from '../utils/color-utils';
|
||||
import { setDocumentTitle } from '../utils/title-utils';
|
||||
import { getPipeStatus, basePath, doResizeTty } from '../utils/web-api-utils';
|
||||
import { getPipeStatus, doResizeTty, wsUrl } from '../utils/web-api-utils';
|
||||
|
||||
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const wsUrl = `${wsProto}://${location.host}${basePath(location.pathname)}`;
|
||||
const log = debug('scope:terminal');
|
||||
|
||||
const DEFAULT_COLS = 80;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
const PREFIX = 'Weave Scope';
|
||||
const PREFIX = document.title || 'Weave Scope';
|
||||
const SEPARATOR = ' - ';
|
||||
|
||||
export function setDocumentTitle(title) {
|
||||
|
||||
@@ -58,8 +58,14 @@ export function basePathSlash(urlPath) {
|
||||
return `${basePath(urlPath)}/`;
|
||||
}
|
||||
|
||||
const API_PATH = basePathSlash(window.location.pathname) === '/'
|
||||
? 'api'
|
||||
: `/api${window.location.pathname}/api`;
|
||||
|
||||
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const wsUrl = `${wsProto}://${location.host}${basePath(location.pathname)}`;
|
||||
export const wsUrl = basePathSlash(window.location.pathname) === '/'
|
||||
? `${wsProto}://${location.host}${basePath(window.location.pathname)}`
|
||||
: `${wsProto}://${location.host}/api${basePath(window.location.pathname)}`;
|
||||
|
||||
function createWebsocket(topologyUrl, optionsQuery, dispatch) {
|
||||
if (socket) {
|
||||
@@ -136,7 +142,7 @@ export function getAllNodes(getState, dispatch) {
|
||||
export function getTopologies(options, dispatch) {
|
||||
clearTimeout(topologyTimer);
|
||||
const optionsQuery = buildOptionsQuery(options);
|
||||
const url = `api/topology?${optionsQuery}`;
|
||||
const url = `${API_PATH}/topology?${optionsQuery}`;
|
||||
reqwest({
|
||||
url,
|
||||
success: (res) => {
|
||||
@@ -171,13 +177,13 @@ export function getNodeDetails(topologyUrlsById, currentTopologyId, options, nod
|
||||
const obj = nodeMap.last();
|
||||
if (obj && topologyUrlsById.has(obj.topologyId)) {
|
||||
const topologyUrl = topologyUrlsById.get(obj.topologyId);
|
||||
let urlComponents = [topologyUrl, '/', encodeURIComponent(obj.id)];
|
||||
let urlComponents = [API_PATH, '/', trimStart(topologyUrl, '/api'), '/', encodeURIComponent(obj.id)];
|
||||
if (currentTopologyId === obj.topologyId) {
|
||||
// Only forward filters for nodes in the current topology
|
||||
const optionsQuery = buildOptionsQuery(options);
|
||||
urlComponents = urlComponents.concat(['?', optionsQuery]);
|
||||
}
|
||||
const url = urlComponents.join('').substr(1);
|
||||
const url = urlComponents.join('');
|
||||
|
||||
reqwest({
|
||||
url,
|
||||
@@ -204,7 +210,7 @@ export function getNodeDetails(topologyUrlsById, currentTopologyId, options, nod
|
||||
|
||||
export function getApiDetails(dispatch) {
|
||||
clearTimeout(apiDetailsTimer);
|
||||
const url = 'api';
|
||||
const url = API_PATH;
|
||||
reqwest({
|
||||
url,
|
||||
success: (res) => {
|
||||
@@ -225,7 +231,7 @@ export function getApiDetails(dispatch) {
|
||||
|
||||
export function doControlRequest(nodeId, control, dispatch) {
|
||||
clearTimeout(controlErrorTimer);
|
||||
const url = `api/control/${encodeURIComponent(control.probeId)}/`
|
||||
const url = `${API_PATH}/control/${encodeURIComponent(control.probeId)}/`
|
||||
+ `${encodeURIComponent(control.nodeId)}/${control.id}`;
|
||||
reqwest({
|
||||
method: 'POST',
|
||||
@@ -261,7 +267,7 @@ export function doControlRequest(nodeId, control, dispatch) {
|
||||
|
||||
|
||||
export function doResizeTty(pipeId, control, cols, rows) {
|
||||
const url = `api/control/${encodeURIComponent(control.probeId)}/`
|
||||
const url = `${API_PATH}/control/${encodeURIComponent(control.probeId)}/`
|
||||
+ `${encodeURIComponent(control.nodeId)}/${control.id}`;
|
||||
|
||||
return reqwest({
|
||||
@@ -276,7 +282,7 @@ export function doResizeTty(pipeId, control, cols, rows) {
|
||||
|
||||
|
||||
export function deletePipe(pipeId, dispatch) {
|
||||
const url = `api/pipe/${encodeURIComponent(pipeId)}`;
|
||||
const url = `${API_PATH}/pipe/${encodeURIComponent(pipeId)}`;
|
||||
reqwest({
|
||||
method: 'DELETE',
|
||||
url,
|
||||
@@ -292,7 +298,7 @@ export function deletePipe(pipeId, dispatch) {
|
||||
|
||||
|
||||
export function getPipeStatus(pipeId, dispatch) {
|
||||
const url = `api/pipe/${encodeURIComponent(pipeId)}/check`;
|
||||
const url = `${API_PATH}/pipe/${encodeURIComponent(pipeId)}/check`;
|
||||
reqwest({
|
||||
method: 'GET',
|
||||
url,
|
||||
|
||||
@@ -115,63 +115,52 @@ $label-background-color: fade-out($background-average-color, .3);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Space out content a bit */
|
||||
body {
|
||||
background: $body-background-color;
|
||||
color: $text-color;
|
||||
line-height: 150%;
|
||||
font-family: $base-font;
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 20px;
|
||||
padding-top: 6px;
|
||||
margin-bottom: 14px;
|
||||
letter-spacing: 0;
|
||||
font-weight: 400;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 34px;
|
||||
line-height: 40px;
|
||||
padding-top: 8px;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.hide {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.app {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.scope-app {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
background: $body-background-color;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
color: $text-color;
|
||||
font-family: $base-font;
|
||||
font-size: 13px;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
line-height: 150%;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 20px;
|
||||
padding-top: 6px;
|
||||
margin-bottom: 14px;
|
||||
letter-spacing: 0;
|
||||
font-weight: 400;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 34px;
|
||||
line-height: 40px;
|
||||
padding-top: 8px;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
|
||||
3
client/index.js
Normal file
3
client/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
exports.reducer = require('./dist/reducers/root').default;
|
||||
exports.Scope = require('./dist/components/app').default;
|
||||
exports.ActionTypes = require('./dist/constants/action-types').default;
|
||||
@@ -5,7 +5,9 @@
|
||||
"repository": "weaveworks/scope",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"babel-plugin-lodash": "^3.2.10",
|
||||
"babel-polyfill": "6.16.0",
|
||||
"classnames": "2.2.5",
|
||||
"d3-array": "1.0.2",
|
||||
@@ -39,15 +41,16 @@
|
||||
"reselect": "2.5.4",
|
||||
"timely": "0.1.0",
|
||||
"whatwg-fetch": "2.0.1",
|
||||
"react-addons-perf": "15.4.1",
|
||||
"xterm": "2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "6.5.3",
|
||||
"babel-cli": "^6.18.0",
|
||||
"babel-core": "6.18.2",
|
||||
"babel-eslint": "7.1.1",
|
||||
"babel-jest": "17.0.2",
|
||||
"babel-loader": "6.2.8",
|
||||
"babel-plugin-lodash": "3.2.10",
|
||||
"babel-preset-es2015": "6.18.0",
|
||||
"babel-preset-react": "6.16.0",
|
||||
"clean-webpack-plugin": "0.1.14",
|
||||
@@ -67,7 +70,6 @@
|
||||
"json-loader": "0.5.4",
|
||||
"node-sass": "3.13.1",
|
||||
"postcss-loader": "1.2.0",
|
||||
"react-addons-perf": "15.4.1",
|
||||
"redux-devtools": "3.3.1",
|
||||
"redux-devtools-dock-monitor": "1.1.1",
|
||||
"redux-devtools-log-monitor": "1.1.1",
|
||||
@@ -88,6 +90,8 @@
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.production.config.js",
|
||||
"build-external": "EXTERNAL=true webpack --config webpack.production.config.js",
|
||||
"build-pkg": "babel app/scripts --ignore __tests__ --out-dir pkg && cp package.json pkg/ && cp -R app/styles pkg/",
|
||||
"bundle": "npm pack pkg && mv weave-scope-$npm_package_version.tgz weave-scope.tgz",
|
||||
"start": "node server.js",
|
||||
"start-production": "NODE_ENV=production node server.js",
|
||||
"test": "jest",
|
||||
@@ -95,7 +99,8 @@
|
||||
"lint": "eslint app",
|
||||
"clean": "rm build/app.js",
|
||||
"noprobe": "../scope stop && ../scope launch --no-probe --app.window 8760h",
|
||||
"loadreport": "npm run noprobe && sleep 1 && curl -X POST -H \"Content-Type: application/json\" http://$BACKEND_HOST/api/report -d"
|
||||
"loadreport": "npm run noprobe && sleep 1 && curl -X POST -H \"Content-Type: application/json\" http://$BACKEND_HOST/api/report -d",
|
||||
"s3-publish": "aws s3 cp weave-scope.tgz s3://weaveworks-npm-modules/weave-scope/ --acl public-read"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
|
||||
Reference in New Issue
Block a user