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: dashboard links #5704

Merged
merged 11 commits into from
May 1, 2019
73 changes: 73 additions & 0 deletions ui-v2/app/components/templated-anchor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Component from '@ember/component';
import { get, set, computed } from '@ember/object';

const createWeak = function(wm = new WeakMap()) {
return {
get: function(ref, prop) {
let map = wm.get(ref);
if (map) {
return map[prop];
}
},
set: function(ref, prop, value) {
let map = wm.get(ref);
if (typeof map === 'undefined') {
map = {};
wm.set(ref, map);
}
map[prop] = value;
return map[prop];
},
};
};
const weak = createWeak();
// Covers alpha-capitalized dot separated API keys such as
// `{{Name}}`, `{{Service.Name}}` etc. but not `{{}}`
const templateRe = /{{([A-Za-z.0-9_-]+)}}/g;
export default Component.extend({
tagName: 'a',
attributeBindings: ['href', 'rel', 'target'],
rel: computed({
get: function(prop) {
return weak.get(this, prop);
},
set: function(prop, value) {
switch (value) {
case 'external':
value = `${value} noopener noreferrer`;
set(this, 'target', '_blank');
break;
}
return weak.set(this, prop, value);
},
}),
vars: computed({
get: function(prop) {
return weak.get(this, prop);
},
set: function(prop, value) {
weak.set(this, prop, value);
set(this, 'href', weak.get(this, 'template'));
},
}),
href: computed({
get: function(prop) {
return weak.get(this, prop);
},
set: function(prop, value) {
weak.set(this, 'template', value);
const vars = weak.get(this, 'vars');
if (typeof vars !== 'undefined' && typeof value !== 'undefined') {
value = value.replace(templateRe, function(match, group) {
try {
return get(vars, group) || '';
} catch (e) {
return '';
}
});
return weak.set(this, prop, value);
}
return '';
},
}),
});
14 changes: 14 additions & 0 deletions ui-v2/app/controllers/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ export default Controller.extend({
repo: service('settings'),
dom: service('dom'),
actions: {
key: function(e) {
switch (true) {
case e.keyCode === 13:
// disable ENTER
e.preventDefault();
}
},
change: function(e, value, item) {
const event = get(this, 'dom').normalizeEvent(e, value);
// TODO: Switch to using forms like the rest of the app
Expand All @@ -23,6 +30,13 @@ export default Controller.extend({
set(this, 'item.client.blocking', !blocking);
this.send('update', get(this, 'item'));
break;
case 'urls[service]':
if (typeof get(this, 'item.urls') === 'undefined') {
set(this, 'item.urls', {});
}
set(this, 'item.urls.service', target.value);
this.send('update', get(this, 'item'));
break;
}
},
},
Expand Down
3 changes: 3 additions & 0 deletions ui-v2/app/routes/dc/services/show.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { get } from '@ember/object';

export default Route.extend({
repo: service('repository/service'),
settings: service('settings'),
queryParams: {
s: {
as: 'filter',
Expand All @@ -13,8 +14,10 @@ export default Route.extend({
},
model: function(params) {
const repo = get(this, 'repo');
const settings = get(this, 'settings');
return hash({
item: repo.findBySlug(params.name, this.modelFor('dc').dc.Name),
urls: settings.findBySlug('urls'),
});
},
setupController: function(controller, model) {
Expand Down
3 changes: 3 additions & 0 deletions ui-v2/app/styles/components/anchors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
%main-content a[rel*='help'] {
@extend %with-info;
}
a[rel*='external'] {
@extend %with-exit;
}
%main-content label a[rel*='help'] {
color: $gray-400;
}
Expand Down
2 changes: 1 addition & 1 deletion ui-v2/app/styles/components/app-view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ main {
}
@media #{$--lt-spacious-page-header} {
%app-view header .actions {
margin-top: 5px;
margin-top: 9px;
}
}
// TODO: This should be its own component
Expand Down
13 changes: 7 additions & 6 deletions ui-v2/app/styles/components/app-view/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
float: right;
display: flex;
align-items: flex-start;
margin-top: 9px;
}
%app-view header dl {
float: left;
Expand All @@ -28,12 +29,7 @@
}
%app-view h2 {
padding-bottom: 0.2em;
margin-bottom: 1.1em;
}
%app-view fieldset h2,
%app-view fieldset p {
padding-bottom: 0;
margin-bottom: 0;
margin-bottom: 0.2em;
}
%app-view header .actions > *:not(:last-child) {
margin-right: 12px;
Expand Down Expand Up @@ -64,3 +60,8 @@
min-height: 1em;
margin-bottom: 0.4em;
}
// TODO: Think about an %app-form or similar
%app-content fieldset {
padding-bottom: 0.3em;
margin-bottom: 2em;
}
6 changes: 4 additions & 2 deletions ui-v2/app/styles/components/app-view/skin.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
%app-view h2 {
%app-view h2,
%app-view fieldset {
border-bottom: $decor-border-200;
}
%app-view fieldset h2 {
Expand All @@ -16,7 +17,8 @@
}
%app-view header > div > div:last-child,
%app-view header h1,
%app-view h2 {
%app-view h2,
%app-view fieldset {
border-color: $gray-200;
}
// We know that any sibling navs might have a top border
Expand Down
9 changes: 9 additions & 0 deletions ui-v2/app/styles/components/icons/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@
width: 16px;
height: 16px;
}
%with-exit::after {
@extend %pseudo-icon-bg-img;
top: 3px;
right: -8px;
background-image: $exit-svg;
background-color: $color-transparent;
width: 16px;
height: 16px;
}
/*TODO: All chevrons need merging */
%with-chevron-down::before {
@extend %pseudo-icon-bg-img;
Expand Down
1 change: 1 addition & 0 deletions ui-v2/app/styles/components/notice/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
position: relative;
padding: 1em;
padding-left: 45px;
margin-bottom: 1em;
}
%notice::before {
position: absolute;
Expand Down
16 changes: 12 additions & 4 deletions ui-v2/app/styles/core/typography.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
%button {
font-family: $typo-family-sans;
}
main p,
%modal-window p {
main p:not(:last-child),
%modal-window p:not(:last-child) {
margin-bottom: 1em;
}
%button,
Expand All @@ -11,6 +11,7 @@ main p,
%form-element [type='password'] {
line-height: 1.5;
}
h3,
%radio-group label {
line-height: 1.25;
}
Expand All @@ -34,6 +35,7 @@ h1,
font-weight: $typo-weight-bold;
}
h2,
h3,
%header-nav,
%healthchecked-resource header span,
%healthcheck-output dt,
Expand Down Expand Up @@ -75,17 +77,23 @@ td:first-child em,
%footer > * {
font-size: inherit;
}

h1 {
font-size: $typo-header-100;
}
h2,
h2 {
font-size: $typo-header-200;
}
h3 {
font-size: $typo-header-300;
}

%header-drop-nav .is-active,
%app-view h1 em {
font-size: $typo-size-500;
}
body,
%action-group-action,
fieldset h2,
pre code,
input,
textarea,
Expand Down
2 changes: 1 addition & 1 deletion ui-v2/app/styles/routes/dc/acls/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ td a.is-management::after {
.template-policy.template-list main header .actions,
.template-token.template-list main header .actions {
position: relative;
top: 50px;
top: 45px;
}
}

Expand Down
1 change: 1 addition & 0 deletions ui-v2/app/templates/components/templated-anchor.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{yield}}
34 changes: 17 additions & 17 deletions ui-v2/app/templates/dc/nodes/show.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@
}}
{{/block-slot}}
{{#block-slot 'actions'}}
{{#feedback-dialog type='inline'}}
{{#block-slot 'action' as |success error|}}
{{#copy-button success=(action success) error=(action error) clipboardText=item.Address title='copy IP address to clipboard'}}
{{item.Address}}
{{/copy-button}}
{{/block-slot}}
{{#block-slot 'success' as |transition|}}
<p class={{transition}}>
Copied IP Address!
</p>
{{/block-slot}}
{{#block-slot 'error' as |transition|}}
<p class={{transition}}>
Sorry, something went wrong!
</p>
{{/block-slot}}
{{/feedback-dialog}}
{{#feedback-dialog type='inline'}}
{{#block-slot 'action' as |success error|}}
{{#copy-button success=(action success) error=(action error) clipboardText=item.Address title='copy IP address to clipboard'}}
{{item.Address}}
{{/copy-button}}
{{/block-slot}}
{{#block-slot 'success' as |transition|}}
<p class={{transition}}>
Copied IP Address!
</p>
{{/block-slot}}
{{#block-slot 'error' as |transition|}}
<p class={{transition}}>
Sorry, something went wrong!
</p>
{{/block-slot}}
{{/feedback-dialog}}
{{/block-slot}}
{{#block-slot 'content'}}
{{#each
Expand Down
5 changes: 5 additions & 0 deletions ui-v2/app/templates/dc/services/show.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
selected=selectedTab
}}
{{/block-slot}}
{{#block-slot 'actions'}}
{{#if urls.service}}
{{#templated-anchor href=urls.service vars=(hash Service=(hash Name=item.Service.Service)) rel="external"}}Open Dashboard{{/templated-anchor}}
{{/if}}
{{/block-slot}}
{{#block-slot 'content'}}
{{#each
(compact
Expand Down
62 changes: 38 additions & 24 deletions ui-v2/app/templates/settings.hbs
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
{{#hashicorp-consul id="wrapper" dcs=dcs dc=dc}}
{{#app-view class="settings show"}}
{{#block-slot 'header'}}
<h1>
Settings
</h1>
{{/block-slot}}
{{#block-slot 'content'}}
<p>
These settings are specific to the Consul web UI. They are saved to local storage and persist through browser usage and visits.
</p>
<form>
<fieldset>
<h2>Blocking Queries</h2>
<p>Automatically get updated catalog information without refreshing the page. Any changes made to services and nodes would be reflected in real time.</p>
<div class="type-toggle">
<label>
<input type="checkbox" name="client[blocking]" checked={{if item.client.blocking 'checked' }} onchange={{action 'change'}} />
<span>{{if item.client.blocking 'On' 'Off' }}</span>
</label>
</div>
</fieldset>
</form>
{{/block-slot}}
{{/app-view}}
{{#app-view class="settings show"}}
{{#block-slot 'header'}}
<h1>
Settings
</h1>
{{/block-slot}}
{{#block-slot 'content'}}
<div class="notice info">
<h3>Local Storage</h3>
<p>
These settings are immediately saved to local storage and persisted through browser usage.
</p>
</div>
<form>
<fieldset>
<h2>Dashboard Links</h2>
<p>
Add a link to the service detail page in the UI to get quick access to a service-wide metrics dashboard. Enter the dashboard URL into the field below. You can use the placeholder {{Service.Name}} which will be replaced with the name of the service currently being viewed.
</p>
<label class="type-text">
<span>Link template for services</span>
<input type="text" name="urls[service]" value={{item.urls.service}} onchange={{action 'change'}} onkeypress={{action 'key'}} onkeydown={{action 'key'}} />
<em>e.g. https://grafana.example.com/d/1/consul-service-mesh&amp;orgid=1&amp;service-name={{ '{{Service.Name}}' }}</em>
</label>
</fieldset>
<fieldset>
<h2>Blocking Queries</h2>
<p>Keep catalog info up-to-date without refreshing the page. Any changes made to services and nodes would be reflected in real time.</p>
<div class="type-toggle">
<label>
<input type="checkbox" name="client[blocking]" checked={{if item.client.blocking 'checked' }} onchange={{action 'change'}} />
<span>{{if item.client.blocking 'On' 'Off' }}</span>
</label>
</div>
</fieldset>
</form>
{{/block-slot}}
{{/app-view}}
{{/hashicorp-consul}}
Loading