diff --git a/ui-v2/app/components/auth-form/index.hbs b/ui-v2/app/components/auth-form/index.hbs
index c9ec424984f4..e83e3f05cebb 100644
--- a/ui-v2/app/components/auth-form/index.hbs
+++ b/ui-v2/app/components/auth-form/index.hbs
@@ -93,7 +93,7 @@
@nspace={{or value.Namespace nspace}}
@type={{if value.Name 'oidc' 'secret'}}
@value={{if value.Name value.Name value}}
- @onchange={{action onsubmit}}
+ @onchange={{queue (action dispatch "RESET") (action onsubmit)}}
@onerror={{queue (action (mut error) value="error.errors.firstObject") (action dispatch "ERROR")}}
/>
diff --git a/ui-v2/app/components/empty-state/index.hbs b/ui-v2/app/components/empty-state/index.hbs
index d42fa7ccc9cb..8af5c2716302 100644
--- a/ui-v2/app/components/empty-state/index.hbs
+++ b/ui-v2/app/components/empty-state/index.hbs
@@ -8,11 +8,24 @@
{{yield}}
{{/yield-slot}}
-
- {{#yield-slot name="body"}}
+ {{#yield-slot name="body"}}
+
{{yield}}
- {{/yield-slot}}
-
+ {{#if (and (env 'CONSUL_ACLS_ENABLED') allowLogin)}}
+
+
+ {{#if token.AccessorID}}
+ Log in with a different token
+ {{else}}
+ Log in
+ {{/if}}
+
+ {{/if}}
+
+ {{/yield-slot}}
{{#yield-slot name="actions"}}
{{yield}}
diff --git a/ui-v2/app/components/hashicorp-consul/index.hbs b/ui-v2/app/components/hashicorp-consul/index.hbs
index 2ca5f255ed59..8854661586fb 100644
--- a/ui-v2/app/components/hashicorp-consul/index.hbs
+++ b/ui-v2/app/components/hashicorp-consul/index.hbs
@@ -127,14 +127,15 @@
{{#let components.AuthForm components.AuthProfile as |AuthForm AuthProfile|}}
Log in
-
+
+
Log in to Consul
@@ -151,6 +152,22 @@
+
+
+
+ Log in with a different token
+
+
+
+
+
+
+
+
+ Continue without logging in
+
+
+
Logout
diff --git a/ui-v2/app/components/hashicorp-consul/index.js b/ui-v2/app/components/hashicorp-consul/index.js
index 72f5f9f90e14..47d05bbb0438 100644
--- a/ui-v2/app/components/hashicorp-consul/index.js
+++ b/ui-v2/app/components/hashicorp-consul/index.js
@@ -28,6 +28,10 @@ export default Component.extend({
close: function() {
this.authForm.reset();
},
+ reauthorize: function(e) {
+ this.modal.close();
+ this.onchange(e);
+ },
change: function(e) {
const win = this.dom.viewport();
const $root = this.dom.root();
diff --git a/ui-v2/app/components/modal-dialog/index.hbs b/ui-v2/app/components/modal-dialog/index.hbs
index 97e12e5bf384..9a11341d8874 100644
--- a/ui-v2/app/components/modal-dialog/index.hbs
+++ b/ui-v2/app/components/modal-dialog/index.hbs
@@ -6,13 +6,25 @@
Close
- {{yield}}
+
+ {{yield (hash
+ close=(action "close")
+ )}}
+
- {{yield}}
+
+ {{yield (hash
+ close=(action "close")
+ )}}
+
- {{yield}}
+
+ {{yield (hash
+ close=(action "close")
+ )}}
+
diff --git a/ui-v2/app/controllers/application.js b/ui-v2/app/controllers/application.js
index 47349bcca518..36aedf2854b4 100644
--- a/ui-v2/app/controllers/application.js
+++ b/ui-v2/app/controllers/application.js
@@ -6,9 +6,6 @@ import transitionable from 'consul-ui/utils/routing/transitionable';
export default Controller.extend({
router: service('router'),
- http: service('repository/type/event-source'),
- dataSource: service('data-source/service'),
- client: service('client/http'),
store: service('store'),
feedback: service('feedback'),
actions: {
@@ -23,12 +20,11 @@ export default Controller.extend({
// used for the feedback service.
this.feedback.execute(
() => {
- // TODO: Centralize this elsewhere
- this.client.abort();
- this.http.resetCache();
- this.dataSource.resetCache();
- this.store.init();
-
+ // TODO: Currently we clear cache from the ember-data store
+ // ideally this would be a static method of the abstract Repository class
+ // once we move to proper classes for services take another look at this.
+ this.store.clear();
+ //
const params = {};
if (e.data) {
const token = e.data;
@@ -42,22 +38,24 @@ export default Controller.extend({
}
}
}
+ const container = getOwner(this);
const routeName = this.router.currentRoute.name;
- const route = getOwner(this).lookup(`route:${routeName}`);
- const router = this.router;
+ const route = container.lookup(`route:${routeName}`);
// Refresh the application route
- return getOwner(this)
+ return container
.lookup('route:application')
.refresh()
- .promise.then(() => {
- // We use transitionable here as refresh doesn't work if you are on an error page
- // which is highly likely to happen here (403s)
- if (routeName !== router.currentRouteName || typeof params.nspace !== 'undefined') {
+ .promise.then(res => {
+ // Use transitionable if we need to change a section of the URL
+ if (
+ routeName !== this.router.currentRouteName ||
+ typeof params.nspace !== 'undefined'
+ ) {
return route.transitionTo(
- ...transitionable(router.currentRoute, params, getOwner(this))
+ ...transitionable(this.router.currentRoute, params, container)
);
} else {
- return route.refresh();
+ return res;
}
});
},
diff --git a/ui-v2/app/services/client/http.js b/ui-v2/app/services/client/http.js
index f1bd40ced055..b5f75acd6268 100644
--- a/ui-v2/app/services/client/http.js
+++ b/ui-v2/app/services/client/http.js
@@ -69,19 +69,27 @@ export default Service.extend({
settings: service('settings'),
init: function() {
this._super(...arguments);
+ this._listeners = this.dom.listeners();
const maxConnections = env('CONSUL_HTTP_MAX_CONNECTIONS');
set(this, 'connections', getObjectPool(dispose, maxConnections));
if (typeof maxConnections !== 'undefined') {
set(this, 'maxConnections', maxConnections);
- const doc = this.dom.document();
// when the user hides the tab, abort all connections
- doc.addEventListener('visibilitychange', e => {
- if (e.target.hidden) {
- this.connections.purge();
- }
+ this._listeners.add(this.dom.document(), {
+ visibilitychange: e => {
+ if (e.target.hidden) {
+ this.connections.purge();
+ }
+ },
});
}
},
+ willDestroy: function() {
+ this._listeners.remove();
+ this.connections.purge();
+ set(this, 'connections', undefined);
+ this._super(...arguments);
+ },
url: function() {
return url(...arguments);
},
@@ -235,14 +243,18 @@ export default Service.extend({
this.connections.purge();
},
whenAvailable: function(e) {
- const doc = this.dom.document();
// if we are using a connection limited protocol and the user has hidden the tab (hidden browser/tab switch)
// any aborted errors should restart
+ const doc = this.dom.document();
if (typeof this.maxConnections !== 'undefined' && doc.hidden) {
- return new Promise(function(resolve) {
- doc.addEventListener('visibilitychange', function listen(event) {
- doc.removeEventListener('visibilitychange', listen);
- resolve(e);
+ return new Promise(resolve => {
+ const remove = this._listeners.add(doc, {
+ visibilitychange: function(event) {
+ remove();
+ // we resolve with the event that comes from
+ // whenAvailable not visibilitychange
+ resolve(e);
+ },
});
});
}
diff --git a/ui-v2/app/services/data-source/service.js b/ui-v2/app/services/data-source/service.js
index 3cff3fa75b57..85cea5c5e84a 100644
--- a/ui-v2/app/services/data-source/service.js
+++ b/ui-v2/app/services/data-source/service.js
@@ -18,22 +18,17 @@ export default Service.extend({
init: function() {
this._super(...arguments);
- if (cache === null) {
- this.resetCache();
- }
+ cache = new Map();
+ sources = new Map();
+ usage = new MultiMap(Set);
this._listeners = this.dom.listeners();
},
resetCache: function() {
- Object.entries(sources || {}).forEach(function([key, item]) {
- item.close();
- });
cache = new Map();
- sources = new Map();
- usage = new MultiMap(Set);
},
willDestroy: function() {
this._listeners.remove();
- Object.entries(sources || {}).forEach(function([key, item]) {
+ sources.forEach(function(item) {
item.close();
});
cache = null;
@@ -61,10 +56,15 @@ export default Service.extend({
close: e => {
const source = e.target;
source.removeEventListener('close', close);
- cache.set(uri, {
- currentEvent: source.getCurrentEvent(),
- cursor: source.configuration.cursor,
- });
+ const event = source.getCurrentEvent();
+ const cursor = source.configuration.cursor;
+ // only cache data if we have any
+ if (typeof event !== 'undefined' && typeof cursor !== 'undefined') {
+ cache.set(uri, {
+ currentEvent: source.getCurrentEvent(),
+ cursor: source.configuration.cursor,
+ });
+ }
// the data is cached delete the EventSource
sources.delete(uri);
},
diff --git a/ui-v2/app/services/store.js b/ui-v2/app/services/store.js
index 668a525a9d8d..b3ee89e5eb6c 100644
--- a/ui-v2/app/services/store.js
+++ b/ui-v2/app/services/store.js
@@ -1,6 +1,21 @@
import Store from 'ember-data/store';
+import { inject as service } from '@ember/service';
export default Store.extend({
+ // TODO: This should eventually go on a static method
+ // of the abstract Repository class
+ http: service('repository/type/event-source'),
+ dataSource: service('data-source/service'),
+ client: service('client/http'),
+ clear: function() {
+ // Aborting the client will close all open http type sources
+ this.client.abort();
+ // once they are closed clear their caches
+ this.http.resetCache();
+ this.dataSource.resetCache();
+ this.init();
+ },
+ //
// TODO: These only exist for ACLs, should probably make sure they fail
// nicely if you aren't on ACLs for good DX
// cloning immediately refreshes the view
diff --git a/ui-v2/app/styles/base/color/base-variables.scss b/ui-v2/app/styles/base/color/base-variables.scss
index accc1466d404..359e88b6726a 100644
--- a/ui-v2/app/styles/base/color/base-variables.scss
+++ b/ui-v2/app/styles/base/color/base-variables.scss
@@ -58,16 +58,7 @@ $cyan-600: #009fd9;
$cyan-700: #0077a3;
$cyan-800: #005574;
$cyan-900: #003346;
-$gray-1: #191a1c;
-$gray-2: #323538;
-$gray-3: #4c4f54;
-$gray-4: #656a70;
-$gray-5: #7f858d;
-$gray-6: #9a9ea5;
-$gray-7: #b4b8bc;
-$gray-8: #d0d2d5;
-$gray-9: #ebecee;
-$gray-10: #f3f4f6;
+$gray-010: #fbfbfc;
$gray-050: #f7f8fa;
$gray-100: #ebeef2;
$gray-200: #dce0e6;
diff --git a/ui-v2/app/styles/components/empty-state/index.scss b/ui-v2/app/styles/components/empty-state/index.scss
index 8f7d52ec6a8f..0b7babf04708 100644
--- a/ui-v2/app/styles/components/empty-state/index.scss
+++ b/ui-v2/app/styles/components/empty-state/index.scss
@@ -16,3 +16,6 @@
%empty-state > ul > li {
@extend %with-popover-menu;
}
+%empty-state label {
+ @extend %primary-button;
+}
diff --git a/ui-v2/app/styles/components/empty-state/layout.scss b/ui-v2/app/styles/components/empty-state/layout.scss
index a8b28364a67f..f2baee0dd7e1 100644
--- a/ui-v2/app/styles/components/empty-state/layout.scss
+++ b/ui-v2/app/styles/components/empty-state/layout.scss
@@ -1,15 +1,28 @@
+%empty-state,
+%empty-state > div {
+ display: flex;
+ flex-direction: column;
+}
%empty-state-header {
padding: 0;
margin: 0;
}
%empty-state {
- width: 320px;
+ margin-top: 0 !important;
+ padding-bottom: 2.8em;
+}
+%empty-state > * {
+ width: 370px;
margin: 0 auto;
}
+%empty-state label {
+ margin: 0 auto !important;
+}
%empty-state-header {
margin-bottom: -3px;
}
%empty-state header {
+ margin-top: 1.8em;
margin-bottom: 0.5em;
}
%empty-state > ul {
diff --git a/ui-v2/app/styles/components/empty-state/skin.scss b/ui-v2/app/styles/components/empty-state/skin.scss
index c3c64a3c66a8..33837f60acf0 100644
--- a/ui-v2/app/styles/components/empty-state/skin.scss
+++ b/ui-v2/app/styles/components/empty-state/skin.scss
@@ -1,5 +1,6 @@
%empty-state {
color: $gray-500;
+ background-color: $gray-010;
}
%empty-state > ul {
border-color: $gray-300;
@@ -34,12 +35,16 @@
%empty-state[class*='status-5'] header::before {
@extend %with-alert-circle-outline-mask;
}
-%empty-state .docs-link > *::before {
- @extend %with-docs-mask, %as-pseudo;
+%empty-state li[class*='-link'] > *::after {
+ @extend %as-pseudo;
+ margin-left: 5px;
+}
+%empty-state .docs-link > *::after {
+ @extend %with-docs-mask;
}
-%empty-state .back-link > *::before {
- @extend %with-chevron-left-mask, %as-pseudo;
+%empty-state .back-link > *::after {
+ @extend %with-chevron-left-mask;
}
-%empty-state .learn-link > *::before {
- @extend %with-learn-mask, %as-pseudo;
+%empty-state .learn-link > *::after {
+ @extend %with-learn-mask;
}
diff --git a/ui-v2/app/templates/dc/acls/-authorization.hbs b/ui-v2/app/templates/dc/acls/-authorization.hbs
index 8617be5769c6..ac570f3b2a59 100644
--- a/ui-v2/app/templates/dc/acls/-authorization.hbs
+++ b/ui-v2/app/templates/dc/acls/-authorization.hbs
@@ -1,4 +1,4 @@
-
+
You are not authorized
diff --git a/ui-v2/app/templates/dc/acls/-disabled.hbs b/ui-v2/app/templates/dc/acls/-disabled.hbs
index bd54f7fc4054..d680d8bf83af 100644
--- a/ui-v2/app/templates/dc/acls/-disabled.hbs
+++ b/ui-v2/app/templates/dc/acls/-disabled.hbs
@@ -4,7 +4,7 @@
- ACLs are not enabled. We strongly encourage the use of ACLs in production environments for the best security practices.
+ ACLs are not enabled in this Consul cluster. We strongly encourage the use of ACLs in production environments for the best security practices.
diff --git a/ui-v2/app/templates/dc/acls/index.hbs b/ui-v2/app/templates/dc/acls/index.hbs
index 46a7620546a2..8434a58b69c1 100644
--- a/ui-v2/app/templates/dc/acls/index.hbs
+++ b/ui-v2/app/templates/dc/acls/index.hbs
@@ -128,9 +128,24 @@
-
- There are no ACLs.
-
+
+
+ No ACLs
+
+
+
+ There don't seem to be any ACLs yet, or you may not have access to view ACLs yet.
+
+
+
+
+ Read the documentation
+
+
+ Follow the guide
+
+
+
diff --git a/ui-v2/app/templates/dc/acls/policies/index.hbs b/ui-v2/app/templates/dc/acls/policies/index.hbs
index 10e85407ceab..c5716ab6e8c6 100644
--- a/ui-v2/app/templates/dc/acls/policies/index.hbs
+++ b/ui-v2/app/templates/dc/acls/policies/index.hbs
@@ -101,9 +101,24 @@
-
- There are no Policies.
-
+
+
+ Welcome to Policies
+
+
+
+ There don't seem to be any policies, or you may not have access to view policies yet.
+
+
+
+
+ Documentation on policies
+
+
+ Read the guide
+
+
+
diff --git a/ui-v2/app/templates/dc/acls/roles/index.hbs b/ui-v2/app/templates/dc/acls/roles/index.hbs
index b809f33f14ee..d618a20967f0 100644
--- a/ui-v2/app/templates/dc/acls/roles/index.hbs
+++ b/ui-v2/app/templates/dc/acls/roles/index.hbs
@@ -96,9 +96,24 @@
-
- There are no Roles.
-
+
+
+ Welcome to Roles
+
+
+
+ There don't seem to be any roles, or you may not have access to view roles yet.
+
+
+
+
+ Documentation on roles
+
+
+ Read the guide
+
+
+
diff --git a/ui-v2/app/templates/dc/intentions/index.hbs b/ui-v2/app/templates/dc/intentions/index.hbs
index 3abb77ded19c..395026a4f67f 100644
--- a/ui-v2/app/templates/dc/intentions/index.hbs
+++ b/ui-v2/app/templates/dc/intentions/index.hbs
@@ -26,9 +26,24 @@
/>
-
- There are no intentions.
-
+
+
+ Welcome to Intentions
+
+
+
+ There don't seem to be any intentions, or you may not have access to view intentions yet.
+
+
+
+
+ Documentation on intentions
+
+
+ Read the guide
+
+
+
diff --git a/ui-v2/app/templates/dc/kv/index.hbs b/ui-v2/app/templates/dc/kv/index.hbs
index 46943e49c923..5b62de6fe4fa 100644
--- a/ui-v2/app/templates/dc/kv/index.hbs
+++ b/ui-v2/app/templates/dc/kv/index.hbs
@@ -87,9 +87,24 @@
-
- There are no Key / Value pairs.
-
+
+
+ Welcome to Key/Value
+
+
+
+ You don't have any K/V pairs, or you may not have access to view K/V pairs yet.
+
+
+
+
+ Documentation on K/V
+
+
+ Read the guide
+
+
+
diff --git a/ui-v2/app/templates/dc/nodes/index.hbs b/ui-v2/app/templates/dc/nodes/index.hbs
index d2da186cee7f..a90a8b42b118 100644
--- a/ui-v2/app/templates/dc/nodes/index.hbs
+++ b/ui-v2/app/templates/dc/nodes/index.hbs
@@ -64,9 +64,24 @@
{{/if}}
{{#if (and (eq healthy.length 0) (eq unhealthy.length 0)) }}
-
- There are no nodes.
-
+
+
+ Welcome to Nodes
+
+
+
+ There don't seem to be any nodes, or you may not have access to view nodes yet.
+
+
+
+
+ Documentation on nodes
+
+
+ Read the guide
+
+
+
{{/if}}
\ No newline at end of file
diff --git a/ui-v2/app/templates/dc/nspaces/index.hbs b/ui-v2/app/templates/dc/nspaces/index.hbs
index 5528af2e3449..02d0ad587fd1 100644
--- a/ui-v2/app/templates/dc/nspaces/index.hbs
+++ b/ui-v2/app/templates/dc/nspaces/index.hbs
@@ -90,9 +90,24 @@
-
- There are no Namespaces.
-
+
+
+ Welcome to Namespaces
+
+
+
+ There don't seem to be any namespaces, or you may not have access to view namespaces yet.
+
+
+
+
+ Documentation on namespaces
+
+
+ Read the guide
+
+
+
diff --git a/ui-v2/app/templates/dc/services/index.hbs b/ui-v2/app/templates/dc/services/index.hbs
index e3f300af530e..9707904f7a7c 100644
--- a/ui-v2/app/templates/dc/services/index.hbs
+++ b/ui-v2/app/templates/dc/services/index.hbs
@@ -33,9 +33,24 @@
-
- There are no services.
-
+
+
+ Welcome to Services
+
+
+
+ There don't seem to be any registered services, or you may not have access to view services yet.
+
+
+
+
+ Documentation on services
+
+
+ Read the guide
+
+
+