mirror of https://github.com/status-im/consul.git
ui: modify content path (#5950)
* Add ui-content-path flag * tests complete, regex validator on string, index.html updated * cleaning up debugging stuff * ui: Enable ember environment configuration to be set via the go binary at runtime (#5934) * ui: Only inject {{.ContentPath}} if we are makeing a prod build... ...otherwise we just use the current rootURL This gets injected into a <base /> node which solves the assets path problem but not the ember problem * ui: Pull out the <base href=""> value and inject it into ember env See previous commit: The <base href=""> value is 'sometimes' injected from go at index serve time. We pass this value down to ember by overwriting the ember config that is injected via a <meta> tag. This has to be done before ember bootup. Sometimes (during testing and development, basically not production) this is injected with the already existing value, in which case this essentially changes nothing. The code here is slightly abstracted away from our specific usage to make it easier for anyone else to use, and also make sure we can cope with using this same method to pass variables down from the CLI through to ember in the future. * ui: We can't use <base /> move everything to javascript (#5941) Unfortuantely we can't seem to be able to use <base> and rootURL together as URL paths will get doubled up (`ui/ui/`). This moves all the things that we need to interpolate with .ContentPath to the `startup` javascript so we can conditionally print out `{{.ContentPath}}` in lots of places (now we can't use base) * fixed when we serve index.html * ui: For writing a ContentPath, we also need to cope with testing... (#5945) ...and potentially more environments Testing has more additional things in a separate index.html in `tests/` This make the entire thing a little saner and uses just javascriopt template literals instead of a pseudo handbrake synatx for our templating of these files. Intead of just templating the entire file this way, we still only template `{{content-for 'head'}}` and `{{content-for 'body'}}` in this way to ensure we support other plugins/addons * build: Loosen up the regex for retrieving the CONSUL_VERSION (#5946) * build: Loosen up the regex for retrieving the CONSUL_VERSION 1. Previously the `sed` replacement was searching for the CONSUL_VERSION comment at the start of a line, it no longer does this to allow for indentation. 2. Both `grep` and `sed` where looking for the omment at the end of the line. We've removed this restriction here. We don't need to remove it right now, but if we ever put the comment followed by something here the searching would break. 3. Added `xargs` for trimming the resulting version string. We aren't using this already in the rest of the scripts, but we are pretty sure this is available on most systems. * ui: Fix erroneous variable, and also force an ember cache clean on build 1. We referenced a variable incorrectly here, this fixes that. 2. We also made sure that every `make` target clears ember's `tmp` cache to ensure that its not using any caches that have since been edited everytime we call a `make` target. * added docs, fixed encoding * fixed go fmt * Update agent/config/config.go Co-Authored-By: R.B. Boyer <public@richardboyer.net> * Completed Suggestions * run gofmt on http.go * fix testsanitize * fix fullconfig/hcl by setting correct 'want' * ran gofmt on agent/config/runtime_test.go * Update website/source/docs/agent/options.html.md Co-Authored-By: Hans Hasselberg <me@hans.io> * Update website/source/docs/agent/options.html.md Co-Authored-By: kaitlincarter-hc <43049322+kaitlincarter-hc@users.noreply.github.com> * remove contentpath from redirectFS struct
This commit is contained in:
parent
0a3e3aa882
commit
d3d92d76f3
File diff suppressed because one or more lines are too long
|
@ -882,6 +882,7 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
|
||||||
TaggedAddresses: c.TaggedAddresses,
|
TaggedAddresses: c.TaggedAddresses,
|
||||||
TranslateWANAddrs: b.boolVal(c.TranslateWANAddrs),
|
TranslateWANAddrs: b.boolVal(c.TranslateWANAddrs),
|
||||||
UIDir: b.stringVal(c.UIDir),
|
UIDir: b.stringVal(c.UIDir),
|
||||||
|
UIContentPath: UIPathBuilder(b.stringVal(b.Flags.Config.UIContentPath)),
|
||||||
UnixSocketGroup: b.stringVal(c.UnixSocket.Group),
|
UnixSocketGroup: b.stringVal(c.UnixSocket.Group),
|
||||||
UnixSocketMode: b.stringVal(c.UnixSocket.Mode),
|
UnixSocketMode: b.stringVal(c.UnixSocket.Mode),
|
||||||
UnixSocketUser: b.stringVal(c.UnixSocket.User),
|
UnixSocketUser: b.stringVal(c.UnixSocket.User),
|
||||||
|
@ -907,6 +908,9 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
|
||||||
// reDatacenter defines a regexp for a valid datacenter name
|
// reDatacenter defines a regexp for a valid datacenter name
|
||||||
var reDatacenter = regexp.MustCompile("^[a-z0-9_-]+$")
|
var reDatacenter = regexp.MustCompile("^[a-z0-9_-]+$")
|
||||||
|
|
||||||
|
// validContentPath defines a regexp for a valid content path name.
|
||||||
|
var validContentPath = regexp.MustCompile(`^[A-Za-z0-9/_-]+$`)
|
||||||
|
var hasVersion = regexp.MustCompile(`^/v\d+/$`)
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
// check required params we cannot recover from first
|
// check required params we cannot recover from first
|
||||||
//
|
//
|
||||||
|
@ -915,11 +919,20 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
|
||||||
return fmt.Errorf("datacenter cannot be empty")
|
return fmt.Errorf("datacenter cannot be empty")
|
||||||
}
|
}
|
||||||
if !reDatacenter.MatchString(rt.Datacenter) {
|
if !reDatacenter.MatchString(rt.Datacenter) {
|
||||||
return fmt.Errorf("datacenter cannot be %q. Please use only [a-z0-9-_].", rt.Datacenter)
|
return fmt.Errorf("datacenter cannot be %q. Please use only [a-z0-9-_]", rt.Datacenter)
|
||||||
}
|
}
|
||||||
if rt.DataDir == "" && !rt.DevMode {
|
if rt.DataDir == "" && !rt.DevMode {
|
||||||
return fmt.Errorf("data_dir cannot be empty")
|
return fmt.Errorf("data_dir cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !validContentPath.MatchString(rt.UIContentPath) {
|
||||||
|
return fmt.Errorf("ui-content-path can only contain alphanumeric, -, _, or /. received: %s", rt.UIContentPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasVersion.MatchString(rt.UIContentPath) {
|
||||||
|
return fmt.Errorf("ui-content-path cannot have 'v[0-9]'. received: %s", rt.UIContentPath)
|
||||||
|
}
|
||||||
|
|
||||||
if !rt.DevMode {
|
if !rt.DevMode {
|
||||||
fi, err := os.Stat(rt.DataDir)
|
fi, err := os.Stat(rt.DataDir)
|
||||||
switch {
|
switch {
|
||||||
|
@ -976,7 +989,7 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
|
||||||
return fmt.Errorf("autopilot.max_trailing_logs cannot be %d. Must be greater than or equal to zero", rt.AutopilotMaxTrailingLogs)
|
return fmt.Errorf("autopilot.max_trailing_logs cannot be %d. Must be greater than or equal to zero", rt.AutopilotMaxTrailingLogs)
|
||||||
}
|
}
|
||||||
if rt.ACLDatacenter != "" && !reDatacenter.MatchString(rt.ACLDatacenter) {
|
if rt.ACLDatacenter != "" && !reDatacenter.MatchString(rt.ACLDatacenter) {
|
||||||
return fmt.Errorf("acl_datacenter cannot be %q. Please use only [a-z0-9-_].", rt.ACLDatacenter)
|
return fmt.Errorf("acl_datacenter cannot be %q. Please use only [a-z0-9-_]", rt.ACLDatacenter)
|
||||||
}
|
}
|
||||||
if rt.EnableUI && rt.UIDir != "" {
|
if rt.EnableUI && rt.UIDir != "" {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
|
@ -1672,3 +1685,17 @@ func isUnixAddr(a net.Addr) bool {
|
||||||
_, ok := a.(*net.UnixAddr)
|
_, ok := a.(*net.UnixAddr)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UIPathBuilder checks to see if there was a path set
|
||||||
|
// If so, adds beginning and trailing slashes to UI path
|
||||||
|
func UIPathBuilder(UIContentString string) string {
|
||||||
|
if UIContentString != "" {
|
||||||
|
var fmtedPath string
|
||||||
|
fmtedPath = strings.Trim(UIContentString, "/")
|
||||||
|
fmtedPath = "/" + fmtedPath + "/"
|
||||||
|
return fmtedPath
|
||||||
|
|
||||||
|
}
|
||||||
|
return "/ui/"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -265,6 +265,7 @@ type Config struct {
|
||||||
Telemetry Telemetry `json:"telemetry,omitempty" hcl:"telemetry" mapstructure:"telemetry"`
|
Telemetry Telemetry `json:"telemetry,omitempty" hcl:"telemetry" mapstructure:"telemetry"`
|
||||||
TranslateWANAddrs *bool `json:"translate_wan_addrs,omitempty" hcl:"translate_wan_addrs" mapstructure:"translate_wan_addrs"`
|
TranslateWANAddrs *bool `json:"translate_wan_addrs,omitempty" hcl:"translate_wan_addrs" mapstructure:"translate_wan_addrs"`
|
||||||
UI *bool `json:"ui,omitempty" hcl:"ui" mapstructure:"ui"`
|
UI *bool `json:"ui,omitempty" hcl:"ui" mapstructure:"ui"`
|
||||||
|
UIContentPath *string `json:"ui_content_path,omitempty" hcl:"ui_content_path" mapstructure:"ui_content_path"`
|
||||||
UIDir *string `json:"ui_dir,omitempty" hcl:"ui_dir" mapstructure:"ui_dir"`
|
UIDir *string `json:"ui_dir,omitempty" hcl:"ui_dir" mapstructure:"ui_dir"`
|
||||||
UnixSocket UnixSocket `json:"unix_sockets,omitempty" hcl:"unix_sockets" mapstructure:"unix_sockets"`
|
UnixSocket UnixSocket `json:"unix_sockets,omitempty" hcl:"unix_sockets" mapstructure:"unix_sockets"`
|
||||||
VerifyIncoming *bool `json:"verify_incoming,omitempty" hcl:"verify_incoming" mapstructure:"verify_incoming"`
|
VerifyIncoming *bool `json:"verify_incoming,omitempty" hcl:"verify_incoming" mapstructure:"verify_incoming"`
|
||||||
|
|
|
@ -106,6 +106,7 @@ func AddFlags(fs *flag.FlagSet, f *Flags) {
|
||||||
add(&f.Config.ServerMode, "server", "Switches agent to server mode.")
|
add(&f.Config.ServerMode, "server", "Switches agent to server mode.")
|
||||||
add(&f.Config.EnableSyslog, "syslog", "Enables logging to syslog.")
|
add(&f.Config.EnableSyslog, "syslog", "Enables logging to syslog.")
|
||||||
add(&f.Config.UI, "ui", "Enables the built-in static web UI server.")
|
add(&f.Config.UI, "ui", "Enables the built-in static web UI server.")
|
||||||
|
add(&f.Config.UIContentPath, "ui-content-path", "Sets the external UI path to a string. Defaults to: /ui/ ")
|
||||||
add(&f.Config.UIDir, "ui-dir", "Path to directory containing the web UI resources.")
|
add(&f.Config.UIDir, "ui-dir", "Path to directory containing the web UI resources.")
|
||||||
add(&f.HCL, "hcl", "hcl config fragment. Can be specified multiple times.")
|
add(&f.HCL, "hcl", "hcl config fragment. Can be specified multiple times.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1387,6 +1387,10 @@ type RuntimeConfig struct {
|
||||||
// flag: -ui-dir string
|
// flag: -ui-dir string
|
||||||
UIDir string
|
UIDir string
|
||||||
|
|
||||||
|
//UIContentPath is a string that sets the external
|
||||||
|
// path to a string. Default: /ui/
|
||||||
|
UIContentPath string
|
||||||
|
|
||||||
// UnixSocketGroup contains the group of the file permissions when
|
// UnixSocketGroup contains the group of the file permissions when
|
||||||
// Consul binds to UNIX sockets.
|
// Consul binds to UNIX sockets.
|
||||||
//
|
//
|
||||||
|
|
|
@ -743,6 +743,18 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||||
rt.DataDir = dataDir
|
rt.DataDir = dataDir
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "-ui-content-path",
|
||||||
|
args: []string{
|
||||||
|
`-ui-content-path=/a/b`,
|
||||||
|
`-data-dir=` + dataDir,
|
||||||
|
},
|
||||||
|
|
||||||
|
patch: func(rt *RuntimeConfig) {
|
||||||
|
rt.UIContentPath = "/a/b/"
|
||||||
|
rt.DataDir = dataDir
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// ports and addresses
|
// ports and addresses
|
||||||
|
@ -4760,6 +4772,7 @@ func TestFullConfig(t *testing.T) {
|
||||||
"wan": "78.63.37.19",
|
"wan": "78.63.37.19",
|
||||||
},
|
},
|
||||||
TranslateWANAddrs: true,
|
TranslateWANAddrs: true,
|
||||||
|
UIContentPath: "/ui/",
|
||||||
UIDir: "11IFzAUn",
|
UIDir: "11IFzAUn",
|
||||||
UnixSocketUser: "E0nB1DwA",
|
UnixSocketUser: "E0nB1DwA",
|
||||||
UnixSocketGroup: "8pFodrV8",
|
UnixSocketGroup: "8pFodrV8",
|
||||||
|
@ -5369,6 +5382,7 @@ func TestSanitize(t *testing.T) {
|
||||||
"StatsiteAddr": ""
|
"StatsiteAddr": ""
|
||||||
},
|
},
|
||||||
"TranslateWANAddrs": false,
|
"TranslateWANAddrs": false,
|
||||||
|
"UIContentPath": "",
|
||||||
"UIDir": "",
|
"UIDir": "",
|
||||||
"UnixSocketGroup": "",
|
"UnixSocketGroup": "",
|
||||||
"UnixSocketMode": "",
|
"UnixSocketMode": "",
|
||||||
|
@ -5709,6 +5723,41 @@ func TestReadPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_UIPathBuilder(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
path string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"Letters only string",
|
||||||
|
"hello",
|
||||||
|
"/hello/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alphanumeric",
|
||||||
|
"Hello1",
|
||||||
|
"/Hello1/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Hyphen and underscore",
|
||||||
|
"-_",
|
||||||
|
"/-_/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Many slashes",
|
||||||
|
"/hello/ui/1/",
|
||||||
|
"/hello/ui/1/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range cases {
|
||||||
|
actual := UIPathBuilder(tt.path)
|
||||||
|
require.Equal(t, tt.expected, actual)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func splitIPPort(hostport string) (net.IP, int) {
|
func splitIPPort(hostport string) (net.IP, int) {
|
||||||
h, p, err := net.SplitHostPort(hostport)
|
h, p, err := net.SplitHostPort(hostport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
|
@ -83,6 +87,66 @@ type HTTPServer struct {
|
||||||
// proto is filled by the agent to "http" or "https".
|
// proto is filled by the agent to "http" or "https".
|
||||||
proto string
|
proto string
|
||||||
}
|
}
|
||||||
|
type templatedFile struct {
|
||||||
|
templated *bytes.Reader
|
||||||
|
name string
|
||||||
|
mode os.FileMode
|
||||||
|
modTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTemplatedFile(buf *bytes.Buffer, raw http.File) *templatedFile {
|
||||||
|
info, _ := raw.Stat()
|
||||||
|
return &templatedFile{
|
||||||
|
templated: bytes.NewReader(buf.Bytes()),
|
||||||
|
name: info.Name(),
|
||||||
|
mode: info.Mode(),
|
||||||
|
modTime: info.ModTime(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Read(p []byte) (n int, err error) {
|
||||||
|
return t.templated.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
return t.templated.Seek(offset, whence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||||
|
return nil, errors.New("not a directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Stat() (os.FileInfo, error) {
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Name() string {
|
||||||
|
return t.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Size() int64 {
|
||||||
|
return int64(t.templated.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Mode() os.FileMode {
|
||||||
|
return t.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) ModTime() time.Time {
|
||||||
|
return t.modTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) IsDir() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *templatedFile) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type redirectFS struct {
|
type redirectFS struct {
|
||||||
fs http.FileSystem
|
fs http.FileSystem
|
||||||
|
@ -96,6 +160,25 @@ func (fs *redirectFS) Open(name string) (http.File, error) {
|
||||||
return file, err
|
return file, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type templatedIndexFS struct {
|
||||||
|
fs http.FileSystem
|
||||||
|
ContentPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *templatedIndexFS) Open(name string) (http.File, error) {
|
||||||
|
file, err := fs.fs.Open(name)
|
||||||
|
if err == nil && name == "/index.html" {
|
||||||
|
content, _ := ioutil.ReadAll(file)
|
||||||
|
file.Seek(0, 0)
|
||||||
|
t, _ := template.New("fmtedindex").Parse(string(content))
|
||||||
|
var out bytes.Buffer
|
||||||
|
err = t.Execute(&out, fs)
|
||||||
|
file = newTemplatedFile(&out, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, err
|
||||||
|
}
|
||||||
|
|
||||||
// endpoint is a Consul-specific HTTP handler that takes the usual arguments in
|
// endpoint is a Consul-specific HTTP handler that takes the usual arguments in
|
||||||
// but returns a response object and error, both of which are handled in a
|
// but returns a response object and error, both of which are handled in a
|
||||||
// common manner by Consul's HTTP server.
|
// common manner by Consul's HTTP server.
|
||||||
|
@ -207,7 +290,6 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler {
|
||||||
|
|
||||||
handleFuncMetrics(pattern, http.HandlerFunc(wrapper))
|
handleFuncMetrics(pattern, http.HandlerFunc(wrapper))
|
||||||
}
|
}
|
||||||
|
|
||||||
mux.HandleFunc("/", s.Index)
|
mux.HandleFunc("/", s.Index)
|
||||||
for pattern, fn := range endpoints {
|
for pattern, fn := range endpoints {
|
||||||
thisFn := fn
|
thisFn := fn
|
||||||
|
@ -227,7 +309,6 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler {
|
||||||
|
|
||||||
if s.IsUIEnabled() {
|
if s.IsUIEnabled() {
|
||||||
var uifs http.FileSystem
|
var uifs http.FileSystem
|
||||||
|
|
||||||
// Use the custom UI dir if provided.
|
// Use the custom UI dir if provided.
|
||||||
if s.agent.config.UIDir != "" {
|
if s.agent.config.UIDir != "" {
|
||||||
uifs = http.Dir(s.agent.config.UIDir)
|
uifs = http.Dir(s.agent.config.UIDir)
|
||||||
|
@ -235,10 +316,9 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler {
|
||||||
fs := assetFS()
|
fs := assetFS()
|
||||||
uifs = fs
|
uifs = fs
|
||||||
}
|
}
|
||||||
uifs = &redirectFS{fs: uifs}
|
uifs = &redirectFS{fs: &templatedIndexFS{fs: uifs, ContentPath: s.agent.config.UIContentPath}}
|
||||||
|
|
||||||
mux.Handle("/robots.txt", http.FileServer(uifs))
|
mux.Handle("/robots.txt", http.FileServer(uifs))
|
||||||
mux.Handle("/ui/", http.StripPrefix("/ui/", http.FileServer(uifs)))
|
mux.Handle(s.agent.config.UIContentPath, http.StripPrefix(s.agent.config.UIContentPath, http.FileServer(uifs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap the whole mux with a handler that bans URLs with non-printable
|
// Wrap the whole mux with a handler that bans URLs with non-printable
|
||||||
|
@ -489,7 +569,7 @@ func (s *HTTPServer) Index(resp http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the UI endpoint
|
// Redirect to the UI endpoint
|
||||||
http.Redirect(resp, req, "/ui/", http.StatusMovedPermanently) // 301
|
http.Redirect(resp, req, s.agent.config.UIContentPath, http.StatusMovedPermanently) // 301
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeBody is used to decode a JSON request body
|
// decodeBody is used to decode a JSON request body
|
||||||
|
|
|
@ -974,7 +974,7 @@ function ui_version {
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local ui_version="$(grep '<!-- CONSUL_VERSION: .* -->$' "$1" | sed 's/^<!-- CONSUL_VERSION: \(.*\) -->$/\1/')" || return 1
|
local ui_version="$(grep '<!-- CONSUL_VERSION: .* -->' "$1" | sed 's/<!-- CONSUL_VERSION: \(.*\) -->/\1/' | xargs)" || return 1
|
||||||
echo "$ui_version"
|
echo "$ui_version"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,13 @@ ROOT:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
deps: node_modules
|
deps: node_modules clean
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf ./tmp
|
||||||
|
|
||||||
|
build-ci: deps
|
||||||
|
yarn run build-ci --output-path=dist
|
||||||
|
|
||||||
build: deps
|
build: deps
|
||||||
yarn run build
|
yarn run build
|
||||||
|
@ -19,6 +25,9 @@ test: deps
|
||||||
test-view: deps
|
test-view: deps
|
||||||
yarn run test:view
|
yarn run test:view
|
||||||
|
|
||||||
|
test-parallel: deps
|
||||||
|
yarn test-parallel
|
||||||
|
|
||||||
lint: deps
|
lint: deps
|
||||||
yarn run lint:js
|
yarn run lint:js
|
||||||
|
|
||||||
|
@ -31,4 +40,4 @@ steps:
|
||||||
node_modules: yarn.lock package.json
|
node_modules: yarn.lock package.json
|
||||||
yarn install
|
yarn install
|
||||||
|
|
||||||
.PHONY: all deps build start test test-view lint format
|
.PHONY: all deps build start test test-view lint format clean
|
||||||
|
|
|
@ -6,51 +6,12 @@
|
||||||
<title>Consul by HashiCorp</title>
|
<title>Consul by HashiCorp</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
{{content-for "// all HTML content is populated via ./lib/startup/index"}}
|
||||||
{{content-for "head"}}
|
{{content-for "head"}}
|
||||||
<link rel="icon" type="image/png" href="{{rootURL}}assets/favicon-32x32.png" sizes="32x32">
|
|
||||||
<link rel="icon" type="image/png" href="{{rootURL}}assets/favicon-16x16.png" sizes="16x16">
|
|
||||||
|
|
||||||
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
|
||||||
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/consul-ui.css">
|
|
||||||
|
|
||||||
{{content-for "head-footer"}}
|
{{content-for "head-footer"}}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
|
||||||
<div style="margin: 0 auto;">
|
|
||||||
<h2>JavaScript Required</h2>
|
|
||||||
<p>Please enable JavaScript in your web browser to use Consul UI.</p>
|
|
||||||
</div>
|
|
||||||
</noscript>
|
|
||||||
{{content-for "body"}}
|
{{content-for "body"}}
|
||||||
<script src="{{rootURL}}assets/vendor.js"></script>
|
|
||||||
<script>
|
|
||||||
var appendScript = function(src) {
|
|
||||||
var $script = document.createElement('script');
|
|
||||||
$script.src = src;
|
|
||||||
document.body.appendChild($script);
|
|
||||||
}
|
|
||||||
if(!('TextDecoder' in window)) {
|
|
||||||
appendScript('{{rootURL}}assets/encoding-indexes.js');
|
|
||||||
appendScript('{{rootURL}}assets/encoding.js');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script src="{{rootURL}}assets/consul-ui.js"></script>
|
|
||||||
<script>
|
|
||||||
CodeMirror.modeURL = {
|
|
||||||
replace: function(n, mode) {
|
|
||||||
switch(mode) {
|
|
||||||
case 'javascript':
|
|
||||||
return '{{rootURL}}assets/codemirror/mode/javascript/javascript.js';
|
|
||||||
case 'ruby':
|
|
||||||
return '{{rootURL}}assets/codemirror/mode/ruby/ruby.js';
|
|
||||||
case 'yaml':
|
|
||||||
return '{{rootURL}}assets/codemirror/mode/yaml/yaml.js';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
{{content-for "body-footer"}}
|
{{content-for "body-footer"}}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -3,16 +3,17 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'startup',
|
name: 'startup',
|
||||||
contentFor: function(type, config) {
|
contentFor: function(type, config) {
|
||||||
const enterprise = config.CONSUL_BINARY_TYPE !== 'oss' && config.CONSUL_BINARY_TYPE !== '';
|
const vars = {
|
||||||
|
appName: config.modulePrefix,
|
||||||
|
environment: config.environment,
|
||||||
|
rootURL: config.environment === 'production' ? '{{.ContentPath}}' : config.rootURL,
|
||||||
|
config: config,
|
||||||
|
};
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'head':
|
case 'head':
|
||||||
return `<!-- CONSUL_VERSION: ${config.CONSUL_VERSION} -->`;
|
return require('./templates/head.html.js')(vars);
|
||||||
case 'body':
|
case 'body':
|
||||||
return `<svg width="168" height="53" xmlns="http://www.w3.org/2000/svg"><g fill="#919FA8" fill-rule="evenodd"><path d="M26.078 32.12a5.586 5.586 0 1 1 5.577-5.599 5.577 5.577 0 0 1-5.577 5.6M37.009 29.328a2.56 2.56 0 1 1 2.56-2.56 2.551 2.551 0 0 1-2.56 2.56M46.916 31.669a2.56 2.56 0 1 1 .051-.21c-.028.066-.028.13-.051.21M44.588 25.068a2.565 2.565 0 0 1-2.672-.992 2.558 2.558 0 0 1-.102-2.845 2.564 2.564 0 0 1 4.676.764c.072.328.081.667.027 1a2.463 2.463 0 0 1-1.925 2.073M53.932 31.402a2.547 2.547 0 0 1-2.95 2.076 2.559 2.559 0 0 1-2.064-2.965 2.547 2.547 0 0 1 2.948-2.077 2.57 2.57 0 0 1 2.128 2.716.664.664 0 0 0-.05.228M51.857 25.103a2.56 2.56 0 1 1 2.108-2.945c.034.218.043.439.027.658a2.547 2.547 0 0 1-2.135 2.287M49.954 40.113a2.56 2.56 0 1 1 .314-1.037c-.02.366-.128.721-.314 1.037M48.974 16.893a2.56 2.56 0 1 1 .97-3.487c.264.446.375.965.317 1.479a2.56 2.56 0 0 1-1.287 2.008"/><path d="M26.526 52.603c-14.393 0-26.06-11.567-26.06-25.836C.466 12.498 12.133.931 26.526.931a25.936 25.936 0 0 1 15.836 5.307l-3.167 4.117A20.962 20.962 0 0 0 17.304 8.23C10.194 11.713 5.7 18.9 5.714 26.763c-.014 7.862 4.48 15.05 11.59 18.534a20.962 20.962 0 0 0 21.89-2.127l3.168 4.123a25.981 25.981 0 0 1-15.836 5.31z"/>${
|
return require('./templates/body.html.js')(vars);
|
||||||
enterprise
|
|
||||||
? `<path data-enterprise-logo d="M61 42.083h3.975v.785H61.87v2.136h2.882v.784H61.87v2.31h3.114v.785H61v-6.8zm6.907 1.018V48.9h-.828v-6.817h1.2l2.94 5.84v-5.84h.829V48.9h-1.193L67.907 43.1zm7.826-.225h-2.012v-.784h4.911v.784h-2.02V48.9h-.879v-6.024zm4.564-.793h3.975v.785h-3.106v2.136h2.882v.784h-2.882v2.31h3.114v.785h-3.992l.009-6.8zm8.605 4.347h-1.657v2.503h-.87v-6.85h2.576c1.45 0 1.963.635 1.963 1.67v.984a1.435 1.435 0 0 1-1.077 1.585l1.756 2.57h-1.002l-1.69-2.462zm0-3.562h-1.657v2.778h1.657c.828 0 1.118-.234 1.118-.901v-.968c.024-.676-.265-.901-1.094-.901l-.024-.008zm4.488-.785h2.485c1.45 0 1.963.635 1.963 1.67v1.009c0 1.05-.505 1.668-1.963 1.668H94.3v2.47h-.87l-.04-6.817zm2.419.785h-1.54v2.803h1.54c.828 0 1.118-.234 1.118-.901v-1.001c0-.668-.282-.893-1.118-.893v-.008zm6.368 3.562h-1.656v2.503h-.87v-6.85h2.576c1.45 0 1.963.635 1.963 1.67v.984a1.435 1.435 0 0 1-1.077 1.585l1.756 2.57h-1.002l-1.69-2.462zm0-3.562h-1.656v2.778h1.656c.829 0 1.118-.234 1.118-.901v-.968c.017-.676-.265-.901-1.101-.901l-.017-.008zm5.392 6.032h-.828v-6.817h.828V48.9zm4.14.1a5.76 5.76 0 0 1-2.012-.359l.141-.717c.605.195 1.236.3 1.872.308 1.085 0 1.308-.283 1.308-1.06 0-.917 0-1-1.4-1.317-1.656-.368-1.83-.685-1.83-2.095 0-1.184.49-1.76 2.162-1.76a7.648 7.648 0 0 1 1.83.225l-.074.743a8.223 8.223 0 0 0-1.74-.192c-1.11 0-1.308.225-1.308 1.01 0 .942 0 .984 1.342 1.318 1.797.45 1.888.717 1.888 2.044.033 1.176-.315 1.852-2.178 1.852zm4.332-6.917h3.95v.785h-3.105v2.136h2.882v.784h-2.882v2.31H120v.785h-3.992l.033-6.8z" fill-rule="nonzero"/>`
|
|
||||||
: ''
|
|
||||||
}<path d="M61 30.15V17.948c0-4.962 2.845-7.85 9.495-7.85 2.484 0 5.048.326 7.252.895l-.561 4.433c-2.164-.406-4.688-.691-6.53-.691-3.486 0-4.608 1.22-4.608 4.108v10.412c0 2.888 1.122 4.108 4.607 4.108 1.843 0 4.367-.284 6.53-.691l.562 4.433c-2.204.57-4.768.895-7.252.895C63.845 38 61 35.112 61 30.15zm36.808.04c0 4.068-1.802 7.81-8.493 7.81-6.69 0-8.494-3.742-8.494-7.81v-5.002c0-4.067 1.803-7.81 8.494-7.81 6.69 0 8.493 3.743 8.493 7.81v5.003zm-4.887-5.165c0-2.237-1.002-3.416-3.606-3.416s-3.606 1.18-3.606 3.416v5.328c0 2.237 1.002 3.417 3.606 3.417s3.606-1.18 3.606-3.417v-5.328zm25.79 12.568h-4.887V23.764c0-1.057-.44-1.586-1.563-1.586-1.201 0-3.325.732-5.088 1.668v13.747h-4.887V17.785h3.726l.48 1.668c2.444-1.22 5.53-2.074 7.813-2.074 3.245 0 4.407 2.318 4.407 5.857v14.357zm18.26-5.775c0 3.823-1.162 6.182-7.052 6.182-2.083 0-4.927-.488-6.73-1.139l.68-3.782c1.643.488 3.807.854 5.81.854 2.164 0 2.484-.488 2.484-1.993 0-1.22-.24-1.83-3.405-2.603-4.768-1.18-5.329-2.4-5.329-6.223 0-3.986 1.723-5.735 7.292-5.735 1.803 0 4.166.244 5.85.691l-.482 3.945c-1.482-.284-3.846-.569-5.368-.569-2.124 0-2.484.488-2.484 1.708 0 1.587.12 1.709 2.764 2.4 5.449 1.464 5.97 2.196 5.97 6.264zm4.357-14.033h4.887v13.83c0 1.057.441 1.586 1.563 1.586 1.202 0 3.325-.733 5.088-1.668V17.785h4.888v19.808h-3.726l-.481-1.667c-2.444 1.22-5.529 2.074-7.812 2.074-3.246 0-4.407-2.318-4.407-5.857V17.785zM168 37.593h-4.888V9.691L168 9v28.593z"/></g></svg>`;
|
|
||||||
case 'root-class':
|
case 'root-class':
|
||||||
return 'ember-loading';
|
return 'ember-loading';
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
module.exports = ({ appName, environment, rootURL, config }) => `
|
||||||
|
<noscript>
|
||||||
|
<div style="margin: 0 auto;">
|
||||||
|
<h2>JavaScript Required</h2>
|
||||||
|
<p>Please enable JavaScript in your web browser to use Consul UI.</p>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
|
<svg width="168" height="53" xmlns="http://www.w3.org/2000/svg"><g fill="#919FA8" fill-rule="evenodd"><path d="M26.078 32.12a5.586 5.586 0 1 1 5.577-5.599 5.577 5.577 0 0 1-5.577 5.6M37.009 29.328a2.56 2.56 0 1 1 2.56-2.56 2.551 2.551 0 0 1-2.56 2.56M46.916 31.669a2.56 2.56 0 1 1 .051-.21c-.028.066-.028.13-.051.21M44.588 25.068a2.565 2.565 0 0 1-2.672-.992 2.558 2.558 0 0 1-.102-2.845 2.564 2.564 0 0 1 4.676.764c.072.328.081.667.027 1a2.463 2.463 0 0 1-1.925 2.073M53.932 31.402a2.547 2.547 0 0 1-2.95 2.076 2.559 2.559 0 0 1-2.064-2.965 2.547 2.547 0 0 1 2.948-2.077 2.57 2.57 0 0 1 2.128 2.716.664.664 0 0 0-.05.228M51.857 25.103a2.56 2.56 0 1 1 2.108-2.945c.034.218.043.439.027.658a2.547 2.547 0 0 1-2.135 2.287M49.954 40.113a2.56 2.56 0 1 1 .314-1.037c-.02.366-.128.721-.314 1.037M48.974 16.893a2.56 2.56 0 1 1 .97-3.487c.264.446.375.965.317 1.479a2.56 2.56 0 0 1-1.287 2.008"/><path d="M26.526 52.603c-14.393 0-26.06-11.567-26.06-25.836C.466 12.498 12.133.931 26.526.931a25.936 25.936 0 0 1 15.836 5.307l-3.167 4.117A20.962 20.962 0 0 0 17.304 8.23C10.194 11.713 5.7 18.9 5.714 26.763c-.014 7.862 4.48 15.05 11.59 18.534a20.962 20.962 0 0 0 21.89-2.127l3.168 4.123a25.981 25.981 0 0 1-15.836 5.31z"/>${
|
||||||
|
config.CONSUL_BINARY_TYPE !== 'oss' && config.CONSUL_BINARY_TYPE !== ''
|
||||||
|
? `<path data-enterprise-logo d="M61 42.083h3.975v.785H61.87v2.136h2.882v.784H61.87v2.31h3.114v.785H61v-6.8zm6.907 1.018V48.9h-.828v-6.817h1.2l2.94 5.84v-5.84h.829V48.9h-1.193L67.907 43.1zm7.826-.225h-2.012v-.784h4.911v.784h-2.02V48.9h-.879v-6.024zm4.564-.793h3.975v.785h-3.106v2.136h2.882v.784h-2.882v2.31h3.114v.785h-3.992l.009-6.8zm8.605 4.347h-1.657v2.503h-.87v-6.85h2.576c1.45 0 1.963.635 1.963 1.67v.984a1.435 1.435 0 0 1-1.077 1.585l1.756 2.57h-1.002l-1.69-2.462zm0-3.562h-1.657v2.778h1.657c.828 0 1.118-.234 1.118-.901v-.968c.024-.676-.265-.901-1.094-.901l-.024-.008zm4.488-.785h2.485c1.45 0 1.963.635 1.963 1.67v1.009c0 1.05-.505 1.668-1.963 1.668H94.3v2.47h-.87l-.04-6.817zm2.419.785h-1.54v2.803h1.54c.828 0 1.118-.234 1.118-.901v-1.001c0-.668-.282-.893-1.118-.893v-.008zm6.368 3.562h-1.656v2.503h-.87v-6.85h2.576c1.45 0 1.963.635 1.963 1.67v.984a1.435 1.435 0 0 1-1.077 1.585l1.756 2.57h-1.002l-1.69-2.462zm0-3.562h-1.656v2.778h1.656c.829 0 1.118-.234 1.118-.901v-.968c.017-.676-.265-.901-1.101-.901l-.017-.008zm5.392 6.032h-.828v-6.817h.828V48.9zm4.14.1a5.76 5.76 0 0 1-2.012-.359l.141-.717c.605.195 1.236.3 1.872.308 1.085 0 1.308-.283 1.308-1.06 0-.917 0-1-1.4-1.317-1.656-.368-1.83-.685-1.83-2.095 0-1.184.49-1.76 2.162-1.76a7.648 7.648 0 0 1 1.83.225l-.074.743a8.223 8.223 0 0 0-1.74-.192c-1.11 0-1.308.225-1.308 1.01 0 .942 0 .984 1.342 1.318 1.797.45 1.888.717 1.888 2.044.033 1.176-.315 1.852-2.178 1.852zm4.332-6.917h3.95v.785h-3.105v2.136h2.882v.784h-2.882v2.31H120v.785h-3.992l.033-6.8z" fill-rule="nonzero"/>`
|
||||||
|
: ``
|
||||||
|
}<path d="M61 30.15V17.948c0-4.962 2.845-7.85 9.495-7.85 2.484 0 5.048.326 7.252.895l-.561 4.433c-2.164-.406-4.688-.691-6.53-.691-3.486 0-4.608 1.22-4.608 4.108v10.412c0 2.888 1.122 4.108 4.607 4.108 1.843 0 4.367-.284 6.53-.691l.562 4.433c-2.204.57-4.768.895-7.252.895C63.845 38 61 35.112 61 30.15zm36.808.04c0 4.068-1.802 7.81-8.493 7.81-6.69 0-8.494-3.742-8.494-7.81v-5.002c0-4.067 1.803-7.81 8.494-7.81 6.69 0 8.493 3.743 8.493 7.81v5.003zm-4.887-5.165c0-2.237-1.002-3.416-3.606-3.416s-3.606 1.18-3.606 3.416v5.328c0 2.237 1.002 3.417 3.606 3.417s3.606-1.18 3.606-3.417v-5.328zm25.79 12.568h-4.887V23.764c0-1.057-.44-1.586-1.563-1.586-1.201 0-3.325.732-5.088 1.668v13.747h-4.887V17.785h3.726l.48 1.668c2.444-1.22 5.53-2.074 7.813-2.074 3.245 0 4.407 2.318 4.407 5.857v14.357zm18.26-5.775c0 3.823-1.162 6.182-7.052 6.182-2.083 0-4.927-.488-6.73-1.139l.68-3.782c1.643.488 3.807.854 5.81.854 2.164 0 2.484-.488 2.484-1.993 0-1.22-.24-1.83-3.405-2.603-4.768-1.18-5.329-2.4-5.329-6.223 0-3.986 1.723-5.735 7.292-5.735 1.803 0 4.166.244 5.85.691l-.482 3.945c-1.482-.284-3.846-.569-5.368-.569-2.124 0-2.484.488-2.484 1.708 0 1.587.12 1.709 2.764 2.4 5.449 1.464 5.97 2.196 5.97 6.264zm4.357-14.033h4.887v13.83c0 1.057.441 1.586 1.563 1.586 1.202 0 3.325-.733 5.088-1.668V17.785h4.888v19.808h-3.726l-.481-1.667c-2.444 1.22-5.529 2.074-7.812 2.074-3.246 0-4.407-2.318-4.407-5.857V17.785zM168 37.593h-4.888V9.691L168 9v28.593z"/></g></svg>
|
||||||
|
<script src="${rootURL}assets/vendor.js"></script>
|
||||||
|
${environment === 'test' ? `<script src="${rootURL}assets/test-support.js"></script>` : ``}
|
||||||
|
<script>
|
||||||
|
var appendScript = function(src) {
|
||||||
|
var $script = document.createElement('script');
|
||||||
|
$script.src = src;
|
||||||
|
document.body.appendChild($script);
|
||||||
|
}
|
||||||
|
if(!('TextDecoder' in window)) {
|
||||||
|
appendScript('${rootURL}assets/encoding-indexes.js');
|
||||||
|
appendScript('${rootURL}assets/encoding.js');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="${rootURL}assets/${appName}.js"></script>
|
||||||
|
<script>
|
||||||
|
CodeMirror.modeURL = {
|
||||||
|
replace: function(n, mode) {
|
||||||
|
switch(mode) {
|
||||||
|
case 'javascript':
|
||||||
|
return '${rootURL}assets/codemirror/mode/javascript/javascript.js';
|
||||||
|
case 'ruby':
|
||||||
|
return '${rootURL}assets/codemirror/mode/ruby/ruby.js';
|
||||||
|
case 'yaml':
|
||||||
|
return '${rootURL}assets/codemirror/mode/yaml/yaml.js';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
${environment === 'test' ? `<script src="${rootURL}assets/tests.js"></script>` : ``}
|
||||||
|
`;
|
|
@ -0,0 +1,37 @@
|
||||||
|
module.exports = ({ appName, environment, rootURL, config }) => `
|
||||||
|
<!-- CONSUL_VERSION: ${config.CONSUL_VERSION} -->
|
||||||
|
<script>
|
||||||
|
var setConfig = function(appName, config) {
|
||||||
|
var $meta = document.querySelector('meta[name="' + appName + '/config/environment"]');
|
||||||
|
var defaultConfig = JSON.parse(decodeURIComponent($meta.getAttribute('content')));
|
||||||
|
(
|
||||||
|
function set(blob, config) {
|
||||||
|
Object.keys(config).forEach(
|
||||||
|
function(key) {
|
||||||
|
var value = config[key];
|
||||||
|
if(Object.prototype.toString.call(value) === '[object Object]') {
|
||||||
|
set(blob[key], config[key]);
|
||||||
|
} else {
|
||||||
|
blob[key] = config[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)(defaultConfig, config);
|
||||||
|
$meta.setAttribute('content', encodeURIComponent(JSON.stringify(defaultConfig)));
|
||||||
|
}
|
||||||
|
setConfig(
|
||||||
|
'${appName}',
|
||||||
|
{
|
||||||
|
rootURL: '${rootURL}'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<link rel="icon" type="image/png" href="${rootURL}assets/favicon-32x32.png" sizes="32x32">
|
||||||
|
<link rel="icon" type="image/png" href="${rootURL}assets/favicon-16x16.png" sizes="16x16">
|
||||||
|
<link integrity="" rel="stylesheet" href="${rootURL}assets/vendor.css">
|
||||||
|
<link integrity="" rel="stylesheet" href="${rootURL}assets/${appName}.css">
|
||||||
|
${
|
||||||
|
environment === 'test' ? `<link rel="stylesheet" href="${rootURL}assets/test-support.css">` : ``
|
||||||
|
}
|
||||||
|
`;
|
|
@ -6,14 +6,9 @@
|
||||||
<title>ConsulUi Tests</title>
|
<title>ConsulUi Tests</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
{{content-for "head"}}
|
{{content-for "head"}}
|
||||||
{{content-for "test-head"}}
|
{{content-for "test-head"}}
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
|
||||||
<link rel="stylesheet" href="{{rootURL}}assets/consul-ui.css">
|
|
||||||
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
|
|
||||||
|
|
||||||
{{content-for "head-footer"}}
|
{{content-for "head-footer"}}
|
||||||
{{content-for "test-head-footer"}}
|
{{content-for "test-head-footer"}}
|
||||||
</head>
|
</head>
|
||||||
|
@ -22,10 +17,6 @@
|
||||||
{{content-for "test-body"}}
|
{{content-for "test-body"}}
|
||||||
|
|
||||||
<script src="/testem.js" integrity=""></script>
|
<script src="/testem.js" integrity=""></script>
|
||||||
<script src="{{rootURL}}assets/vendor.js"></script>
|
|
||||||
<script src="{{rootURL}}assets/test-support.js"></script>
|
|
||||||
<script src="{{rootURL}}assets/consul-ui.js"></script>
|
|
||||||
<script src="{{rootURL}}assets/tests.js"></script>
|
|
||||||
|
|
||||||
{{content-for "body-footer"}}
|
{{content-for "body-footer"}}
|
||||||
{{content-for "test-body-footer"}}
|
{{content-for "test-body-footer"}}
|
||||||
|
|
|
@ -465,6 +465,8 @@ will exit with an error at startup.
|
||||||
the Web UI resources for Consul. This will automatically enable the Web UI. The directory must be
|
the Web UI resources for Consul. This will automatically enable the Web UI. The directory must be
|
||||||
readable to the agent. Starting with Consul version 0.7.0 and later, the Web UI assets are included in the binary so this flag is no longer necessary; specifying only the `-ui` flag is enough to enable the Web UI. Specifying both the '-ui' and '-ui-dir' flags will result in an error.
|
readable to the agent. Starting with Consul version 0.7.0 and later, the Web UI assets are included in the binary so this flag is no longer necessary; specifying only the `-ui` flag is enough to enable the Web UI. Specifying both the '-ui' and '-ui-dir' flags will result in an error.
|
||||||
|
|
||||||
|
* <a name="_ui_content_path"></a><a href="#_ui_content_path">`-ui-content-path`</a> - This flag provides the option to change the path the Consul UI loads from and will be displayed in the browser. By default, the path is `/ui/`, for example `http://localhost:8500/ui/`. Only alphanumerics, `-`, and `_` are allowed in a custom path. `/v1/` is not allowed as it would overwrite the API endpoint.
|
||||||
|
|
||||||
## <a name="configuration_files"></a>Configuration Files
|
## <a name="configuration_files"></a>Configuration Files
|
||||||
|
|
||||||
In addition to the command-line options, configuration can be put into
|
In addition to the command-line options, configuration can be put into
|
||||||
|
|
Loading…
Reference in New Issue