From 79d262dd12e2cd64679b5d5a14aa0c7060fa85e8 Mon Sep 17 00:00:00 2001 From: Joe Farro Date: Fri, 27 Oct 2017 00:18:25 -0400 Subject: [PATCH] Embed UI config (#107) * Query service embeds config in index.html - Merge embedded config with default config - Use gaTrackingID from embedded config for Google Analytics tracking Signed-off-by: Joe Farro * Add changelog entry for PR 107 Signed-off-by: Joe Farro --- CHANGELOG.md | 5 +++++ package.json | 1 + public/index.html | 15 ++++++++++--- src/actions/jaeger-api.js | 6 ----- src/api/jaeger.js | 3 --- src/components/App/Page.js | 4 ++-- src/components/App/index.js | 2 -- src/constants/default-config.js | 6 +++-- src/reducers/config.js | 39 +++++---------------------------- src/types/config.js | 1 + src/utils/config/get-config.js | 37 +++++++++++++++++++++++++++++++ src/utils/metrics.js | 8 ++++--- yarn.lock | 4 ++++ 13 files changed, 76 insertions(+), 55 deletions(-) create mode 100644 src/utils/config/get-config.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e43a65b505..b80e91f8ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changes +### [#107](https://github.com/jaegertracing/jaeger-ui/pull/107) Embed UI config + +The query service can embed custom UI configuration into `index.html`, speeding up the initial page load and allowing custom Google Analytics tracking IDs without requiring the UI bundle to be regenerated. This also lays the ground work for other UI configuration scenarios, in the future. + + ### [#97](https://github.com/jaegertracing/jaeger-ui/pull/97) Change to Apache license v.2 and add DCO / CONTRIBUTING.md diff --git a/package.json b/package.json index ddb37a0dda..a18a961969 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "cytoscape-dagre": "^2.0.0", "d3-scale": "^1.0.6", "dagre": "^0.7.4", + "deep-freeze": "^0.0.1", "flow-bin": "^0.53.1", "fuzzy": "^0.1.3", "global": "^4.3.2", diff --git a/public/index.html b/public/index.html index 2e2cb4230f..c55b9c64bf 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,6 @@ - @@ -11,9 +10,19 @@ - - Jaeger UI +
diff --git a/src/actions/jaeger-api.js b/src/actions/jaeger-api.js index c9cfe19e87..275a61c802 100644 --- a/src/actions/jaeger-api.js +++ b/src/actions/jaeger-api.js @@ -15,12 +15,6 @@ import { createAction } from 'redux-actions'; import JaegerAPI from '../api/jaeger'; -/** - * async wrapper to get the api object in case we're in demo mode. - */ - -export const fetchConfig = createAction('@JAEGER_API/FETCH_CONFIG', () => JaegerAPI.fetchConfig()); - export const fetchTrace = createAction( '@JAEGER_API/FETCH_TRACE', id => JaegerAPI.fetchTrace(id), diff --git a/src/api/jaeger.js b/src/api/jaeger.js index 0965c89025..f1e1b23276 100644 --- a/src/api/jaeger.js +++ b/src/api/jaeger.js @@ -47,9 +47,6 @@ export const DEFAULT_DEPENDENCY_LOOKBACK = moment.duration(1, 'weeks').asMillise const JaegerAPI = { apiRoot: DEFAULT_API_ROOT, - fetchConfig() { - return getJSON(`${this.apiRoot}config`).catch(err => ({ error: err })); - }, fetchTrace(id) { return getJSON(`${this.apiRoot}traces/${id}`); }, diff --git a/src/components/App/Page.js b/src/components/App/Page.js index b1462f5bdc..ef09fca9ed 100644 --- a/src/components/App/Page.js +++ b/src/components/App/Page.js @@ -28,7 +28,7 @@ import './Page.css'; type PageProps = { location: Location, children: React.Node, - config: { data: Config }, + config: Config, }; class Page extends React.Component { @@ -49,7 +49,7 @@ class Page extends React.Component { render() { const { children, config } = this.props; - const menu = config && config.data && config.data.menu; + const menu = config && config.menu; return (
diff --git a/src/components/App/index.js b/src/components/App/index.js index a3c6dfe424..c734fba205 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -25,7 +25,6 @@ import NotFound from './NotFound'; import { ConnectedDependencyGraphPage } from '../DependencyGraph'; import { ConnectedSearchTracePage } from '../SearchTracePage'; import { ConnectedTracePage } from '../TracePage'; -import { fetchConfig } from '../../actions/jaeger-api'; import JaegerAPI, { DEFAULT_API_ROOT } from '../../api/jaeger'; import configureStore from '../../utils/configure-store'; import prefixUrl from '../../utils/prefix-url'; @@ -39,7 +38,6 @@ export default class JaegerUIApp extends Component { super(props); this.store = configureStore(history); JaegerAPI.apiRoot = DEFAULT_API_ROOT; - this.store.dispatch(fetchConfig()); } render() { diff --git a/src/constants/default-config.js b/src/constants/default-config.js index 884f070103..4570544801 100644 --- a/src/constants/default-config.js +++ b/src/constants/default-config.js @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -export default { +import deepFreeze from 'deep-freeze'; + +export default deepFreeze({ menu: [ { label: 'About Jaeger', @@ -44,4 +46,4 @@ export default { ], }, ], -}; +}); diff --git a/src/reducers/config.js b/src/reducers/config.js index e8fb20f401..7d903e8016 100644 --- a/src/reducers/config.js +++ b/src/reducers/config.js @@ -12,40 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { handleActions } from 'redux-actions'; +import getConfig from '../utils/config/get-config'; -import { fetchConfig } from '../actions/jaeger-api'; -import defaultConfig from '../constants/default-config'; - -const initialState = { - data: {}, - loading: false, - error: null, -}; - -function fetchStarted(state) { - return { ...state, loading: true }; -} - -function fetchDone(state, { payload }) { - const data = payload; - // fetchConfig action creator is set to handle rejected promises - if (data.error) { - const { message, stack } = data.error; - return { ...state, error: { message, stack }, loading: false, data: defaultConfig }; +export default function reduceConfig(state) { + if (state === undefined) { + return getConfig(); } - return { ...state, data, error: null, loading: false }; + return state; } - -function fetchErred(state, { payload: error }) { - return { ...state, error: error.message, loading: false, data: defaultConfig }; -} - -export default handleActions( - { - [`${fetchConfig}_PENDING`]: fetchStarted, - [`${fetchConfig}_FULFILLED`]: fetchDone, - [`${fetchConfig}_REJECTED`]: fetchErred, - }, - initialState -); diff --git a/src/types/config.js b/src/types/config.js index 30ec5b071a..1691f325d8 100644 --- a/src/types/config.js +++ b/src/types/config.js @@ -25,5 +25,6 @@ export type ConfigMenuGroup = { }; export type Config = { + gaTrackingID?: ?string, menu: (ConfigMenuGroup | ConfigMenuItem)[], }; diff --git a/src/utils/config/get-config.js b/src/utils/config/get-config.js new file mode 100644 index 0000000000..0288bd4fec --- /dev/null +++ b/src/utils/config/get-config.js @@ -0,0 +1,37 @@ +// @flow + +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import defaultConfig from '../../constants/default-config'; + +let haveWarned = false; + +/** + * Merge the embedded config from the query service (if present) with the + * default config from `../../constants/default-config`. + */ +export default function getConfig() { + const getJaegerUiConfig = window.getJaegerUiConfig; + if (typeof getJaegerUiConfig !== 'function') { + if (!haveWarned) { + // eslint-disable-next-line no-console + console.warn('Embedded config not available'); + haveWarned = true; + } + return { ...defaultConfig }; + } + const embedded = getJaegerUiConfig() || {}; + return { ...defaultConfig, ...embedded }; +} diff --git a/src/utils/metrics.js b/src/utils/metrics.js index 67da14517d..6b443137af 100644 --- a/src/utils/metrics.js +++ b/src/utils/metrics.js @@ -14,10 +14,12 @@ import ReactGA from 'react-ga'; +import getConfig from './config/get-config'; + export function init() { - if (process.env.NODE_ENV === 'production' && process.env.REACT_APP_GA_TRACKING_ID) { - const GA_CODE = process.env.REACT_APP_GA_TRACKING_ID; - ReactGA.initialize(GA_CODE); + const config = getConfig(); + if (process.env.NODE_ENV === 'production' && config.gaTrackingID) { + ReactGA.initialize(config.gaTrackingID); } } diff --git a/yarn.lock b/yarn.lock index a21d04b5e1..1900d101a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2095,6 +2095,10 @@ deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-freeze@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"