Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: New Empty States #7940

Merged
merged 10 commits into from
May 27, 2020
2 changes: 1 addition & 1 deletion ui-v2/app/components/auth-form/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -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")}}
/>
</State>
Expand Down
21 changes: 17 additions & 4 deletions ui-v2/app/components/empty-state/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,24 @@
{{yield}}
{{/yield-slot}}
</header>
<p>
{{#yield-slot name="body"}}
{{#yield-slot name="body"}}
<div>
{{yield}}
{{/yield-slot}}
</p>
{{#if (and (env 'CONSUL_ACLS_ENABLED') allowLogin)}}
<label for="login-toggle">
<DataSource
@src="settings://consul:token"
@onchange={{action (mut token) value="data"}}
/>
{{#if token.AccessorID}}
Log in with a different token
{{else}}
Log in
{{/if}}
</label>
{{/if}}
</div>
{{/yield-slot}}
{{#yield-slot name="actions"}}
<ul>
{{yield}}
Expand Down
21 changes: 19 additions & 2 deletions ui-v2/app/components/hashicorp-consul/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,15 @@
<AuthDialog
@dc={{dc.Name}}
@nspace={{nspace.Name}}
@onchange={{action onchange}} as |authDialog components|
@onchange={{action "reauthorize"}} as |authDialog components|
>
{{#let components.AuthForm components.AuthProfile as |AuthForm AuthProfile|}}
<BlockSlot @name="unauthorized">
<label tabindex="0" for="login-toggle" onkeypress={{action 'keypressClick'}}>
<span>Log in</span>
</label>
<ModalDialog @name="login-toggle" @onclose={{action 'close'}} @onopen={{action 'open'}}>
<ModalDialog @name="login-toggle" @onclose={{action 'close'}} @onopen={{action 'open'}} as |api|>
<Ref @target={{this}} @name="modal" @value={{api}} />
<BlockSlot @name="header">
<h2>Log in to Consul</h2>
</BlockSlot>
Expand All @@ -151,6 +152,22 @@
</ModalDialog>
</BlockSlot>
<BlockSlot @name="authorized">
<ModalDialog @name="login-toggle" @onclose={{action 'close'}} @onopen={{action 'open'}} as |api|>
<Ref @target={{this}} @name="modal" @value={{api}} />
<BlockSlot @name="header">
<h2>Log in with a different token</h2>
</BlockSlot>
<BlockSlot @name="body">
<AuthForm as |api|>
<Ref @target={{this}} @name="authForm" @value={{api}} />
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions" as |close|>
<button type="button" onclick={{action close}}>
Continue without logging in
</button>
</BlockSlot>
</ModalDialog>
<PopoverMenu @position="right">
<BlockSlot @name="trigger">
Logout
Expand Down
4 changes: 4 additions & 0 deletions ui-v2/app/components/hashicorp-consul/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
18 changes: 15 additions & 3 deletions ui-v2/app/components/modal-dialog/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@
<div>
<header>
<label for="modal_close">Close</label>
<YieldSlot @name="header">{{yield}}</YieldSlot>
<YieldSlot @name="header">
{{yield (hash
close=(action "close")
)}}
</YieldSlot>
</header>
<div>
<YieldSlot @name="body">{{yield}}</YieldSlot>
<YieldSlot @name="body">
{{yield (hash
close=(action "close")
)}}
</YieldSlot>
</div>
<footer>
<YieldSlot @name="actions" @params={{block-params (action "close")}}>{{yield}}</YieldSlot>
<YieldSlot @name="actions" @params={{block-params (action "close")}}>
{{yield (hash
close=(action "close")
)}}
</YieldSlot>
</footer>
</div>
</div>
Expand Down
34 changes: 16 additions & 18 deletions ui-v2/app/controllers/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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;
Expand All @@ -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;
}
});
},
Expand Down
32 changes: 22 additions & 10 deletions ui-v2/app/services/client/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
Expand Down Expand Up @@ -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);
},
});
});
}
Expand Down
26 changes: 13 additions & 13 deletions ui-v2/app/services/data-source/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
},
Expand Down
15 changes: 15 additions & 0 deletions ui-v2/app/services/store.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 1 addition & 10 deletions ui-v2/app/styles/base/color/base-variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be confusing in the future. Can we standardize all these variables to start with a 0? For example, $gray-8 -> $gray-08

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah originally the base files where imagined to be shared between product and marketing. Luckily the marketing teams grays used a gray-<single-digit> naming scheme and we chose a gray-<triple-digit>. Originally there was talk of marketing migrating to use our gray-scale/naming instead, it just never got there.

I think I'm gonna remove all the marketing ones for the moment at least. They don't get compiled in but for folks that don't know the history here it is confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commited the removal on the end of this here, gonna merge this!

$gray-050: #f7f8fa;
$gray-100: #ebeef2;
$gray-200: #dce0e6;
Expand Down
3 changes: 3 additions & 0 deletions ui-v2/app/styles/components/empty-state/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
%empty-state > ul > li {
@extend %with-popover-menu;
}
%empty-state label {
@extend %primary-button;
}
15 changes: 14 additions & 1 deletion ui-v2/app/styles/components/empty-state/layout.scss
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
17 changes: 11 additions & 6 deletions ui-v2/app/styles/components/empty-state/skin.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
%empty-state {
color: $gray-500;
background-color: $gray-010;
}
%empty-state > ul {
border-color: $gray-300;
Expand Down Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion ui-v2/app/templates/dc/acls/-authorization.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<EmptyState class="status-403">
<EmptyState class="status-403" @allowLogin={{true}}>
<BlockSlot @name="header">
<h2>You are not authorized</h2>
</BlockSlot>
Expand Down
Loading