Skip to content

Commit

Permalink
Merge branch 'master' of github.com:hashicorp/consul into WinService
Browse files Browse the repository at this point in the history
  • Loading branch information
MagnumOpus21 committed Jun 18, 2018
2 parents e5ad1dd + 31b6e10 commit bf26498
Show file tree
Hide file tree
Showing 101 changed files with 2,264 additions and 86 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ FEATURES:
IMPROVEMENTS:

* agent: A Consul user-agent string is now sent to providers when making retry-join requests [GH-4013](https://github.com/hashicorp/consul/pull/4013)
* client: Add metrics for failed RPCs [PR-4220](https://github.com/hashicorp/consul/pull/4220)

BUG FIXES:

Expand Down
1 change: 1 addition & 0 deletions agent/consul/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ TRY:

// Move off to another server, and see if we can retry.
c.logger.Printf("[ERR] consul: %q RPC failed to server %s: %v", method, server.Addr, rpcErr)
metrics.IncrCounterWithLabels([]string{"client", "rpc", "failed"}, 1, []metrics.Label{{Name: "server", Value: server.Name}})
c.routers.NotifyFailedServer(server)
if retry := canRetry(args, rpcErr); !retry {
return rpcErr
Expand Down
3 changes: 2 additions & 1 deletion scripts/consul-builder/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ RUN apt-get update -y && \
zip \
zlib1g-dev \
nodejs \
npm && \
npm \
rsync && \
gem install bundler && \
npm install --global yarn && \
npm install --global ember-cli
Expand Down
2 changes: 2 additions & 0 deletions ui-v2/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
/yarn-error.log
/testem.log

/public/consul-api-double

15 changes: 15 additions & 0 deletions ui-v2/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,18 @@ format:
yarn run format:js

.PHONY: server dist lint format

.DEFAULT_GOAL=all
.PHONY: deps test all build start
all: deps
deps: node_modules yarn.lock package.json
node_modules:
yarn
build:
yarn run build
start:
yarn run start
test:
yarn run test
test-view:
yarn run test:view
229 changes: 216 additions & 13 deletions ui-v2/app/components/tabular-collection.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,67 @@
import Component from 'ember-collection/components/ember-collection';
import needsRevalidate from 'ember-collection/utils/needs-revalidate';
import identity from 'ember-collection/utils/identity';
import Grid from 'ember-collection/layouts/grid';
import SlotsMixin from 'ember-block-slots';
import style from 'ember-computed-style';
import qsaFactory from 'consul-ui/utils/qsa-factory';

import { computed, get, set } from '@ember/object';
/**
* Heavily extended `ember-collection` component
* This adds support for z-index calculations to enable
* Popup menus to pop over either rows above or below
* the popup.
* Additionally adds calculations for figuring out what the height
* of the tabular component should be depending on the other elements
* in the page.
* Currently everything is here together for clarity, but to be split up
* in the future
*/

const $$ = document.querySelectorAll.bind(document);
// ember doesn't like you using `$` hence `$$`
const $$ = qsaFactory();
// basic pseudo CustomEvent interface
// TODO: use actual custom events once I've reminded
// myself re: support/polyfills
const createSizeEvent = function(detail) {
return {
detail: { width: window.innerWidth, height: window.innerHeight },
};
};
// need to copy Cell in wholesale as there is no way to import it
// there is no change made to `Cell` here, its only here as its
// private in `ember-collection`
// TODO: separate both Cell and ZIndexedGrid out
class Cell {
constructor(key, item, index, style) {
this.key = key;
this.hidden = false;
this.item = item;
this.index = index;
this.style = style;
}
}
// this is an amount of rows in the table NOT items
// unlikely to have 10000 DOM rows ever :)
const maxZIndex = 10000;
// Adds z-index styling to the default Grid
class ZIndexedGrid extends Grid {
formatItemStyle(index, w, h) {
let style = super.formatItemStyle(...arguments);
style += 'z-index: ' + (10000 - index);
formatItemStyle(index, w, h, checked) {
let style = super.formatItemStyle(index, w, h);
// count backwards from maxZIndex
let zIndex = maxZIndex - index;
// apart from the row that contains an opened dropdown menu
// this one should be highest z-index, so use max plus 1
if (checked == index) {
zIndex = maxZIndex + 1;
}
style += 'z-index: ' + zIndex;
return style;
}
}
// TODO instead of degrading gracefully
// basic DOM closest utility to cope with no support
// TODO: instead of degrading gracefully
// add a while polyfill for closest
const closest = function(sel, el) {
try {
Expand All @@ -28,6 +70,32 @@ const closest = function(sel, el) {
return;
}
};
const sibling = function(el, name) {
let sibling = el;
while ((sibling = sibling.nextSibling)) {
if (sibling.nodeType === 1) {
if (sibling.nodeName.toLowerCase() === name) {
return sibling;
}
}
}
};
/**
* The tabular-collection can contain 'actions' the UI for which
* uses dropdown 'action groups', so a group of different actions.
* State makes use of native HTML state using radiogroups
* to ensure that only a single dropdown can be open at one time.
* Therefore we listen to change events to do anything extra when
* a dropdown is opened (the change function is bound to the instance of
* the `tabular-component` on init, hoisted here for visibility)
*
* The extra functionality we have here is to detect whether the opened
* dropdown menu would be cut off or not if it 'dropped down'.
* If it would be cut off we use CSS to 'drop it up' instead.
* We also set this row to have the max z-index here, and mark this
* row as the 'checked row' for when a scroll/grid re-calculation is
* performed
*/
const change = function(e) {
if (e instanceof MouseEvent) {
return;
Expand All @@ -37,6 +105,23 @@ const change = function(e) {
const value = e.currentTarget.value;
if (value != get(this, 'checked')) {
set(this, 'checked', value);
// 'actions_close' would mean that all menus have been closed
// therefore we don't need to calculate
if (e.currentTarget.getAttribute('id') !== 'actions_close') {
const $tr = closest('tr', e.currentTarget);
const $group = sibling(e.currentTarget, 'ul');
const $footer = [...$$('footer[role="contentinfo"]')][0];
const groupRect = $group.getBoundingClientRect();
const footerRect = $footer.getBoundingClientRect();
const groupBottom = groupRect.top + $group.clientHeight;
const footerTop = footerRect.top;
if (groupBottom > footerTop) {
$group.classList.add('above');
} else {
$group.classList.remove('above');
}
$tr.style.zIndex = maxZIndex + 1;
}
} else {
set(this, 'checked', null);
}
Expand All @@ -62,7 +147,7 @@ export default Component.extend(SlotsMixin, {
this._super(...arguments);
this.change = change.bind(this);
this.confirming = [];
// TODO: This should auto calculate properly from the CSS
// TODO: The row height should auto calculate properly from the CSS
this['cell-layout'] = new ZIndexedGrid(get(this, 'width'), 50);
this.handler = () => {
this.resize(createSizeEvent());
Expand All @@ -79,23 +164,34 @@ export default Component.extend(SlotsMixin, {
},
didInsertElement: function() {
this._super(...arguments);
// TODO: Consider moving all DOM lookups here
// this seems to be the earliest place I can get them
window.addEventListener('resize', this.handler);
this.handler();
this.didAppear();
},
willDestroyElement: function() {
window.removeEventListener('resize', this.handler);
},
didAppear: function() {
this.handler();
},
resize: function(e) {
const $footer = [...$$('#wrapper > footer')][0];
const $thead = [...$$('main > div')][0];
if ($thead) {
// TODO: This should auto calculate properly from the CSS
this.set('height', Math.max(0, new Number(e.detail.height - ($footer.clientHeight + 218))));
this['cell-layout'] = new ZIndexedGrid($thead.clientWidth, 50);
const $tbody = [...$$('tbody', this.element)][0];
const $appContent = [...$$('main > div')][0];
if ($appContent) {
const rect = $tbody.getBoundingClientRect();
const $footer = [...$$('footer[role="contentinfo"]')][0];
const space = rect.top + $footer.clientHeight;
const height = new Number(e.detail.height - space);
this.set('height', Math.max(0, height));
// TODO: The row height should auto calculate properly from the CSS
this['cell-layout'] = new ZIndexedGrid($appContent.clientWidth, 50);
this.updateItems();
this.updateScrollPosition();
}
},
// `ember-collection` bug workaround
// https://github.com/emberjs/ember-collection/issues/138
_needsRevalidate: function() {
if (this.isDestroyed || this.isDestroying) {
return;
Expand All @@ -106,8 +202,115 @@ export default Component.extend(SlotsMixin, {
needsRevalidate(this);
}
},
// need to overwrite this completely so I can pass through the checked index
// unfortunately the nicest way I could think to do this is to copy this in wholesale
// to add an extra argument for `formatItemStyle` in 3 places
// tradeoff between changing as little code as possible in the original code
updateCells: function() {
if (!this._items) {
return;
}
const numItems = get(this._items, 'length');
if (this._cellLayout.length !== numItems) {
this._cellLayout.length = numItems;
}

var priorMap = this._cellMap;
var cellMap = Object.create(null);

var index = this._cellLayout.indexAt(
this._scrollLeft,
this._scrollTop,
this._clientWidth,
this._clientHeight
);
var count = this._cellLayout.count(
this._scrollLeft,
this._scrollTop,
this._clientWidth,
this._clientHeight
);
var items = this._items;
var bufferBefore = Math.min(index, this._buffer);
index -= bufferBefore;
count += bufferBefore;
count = Math.min(count + this._buffer, get(items, 'length') - index);
var i, style, itemIndex, itemKey, cell;

var newItems = [];

for (i = 0; i < count; i++) {
itemIndex = index + i;
itemKey = identity(items.objectAt(itemIndex));
if (priorMap) {
cell = priorMap[itemKey];
}
if (cell) {
// additional `checked` argument
style = this._cellLayout.formatItemStyle(
itemIndex,
this._clientWidth,
this._clientHeight,
this.checked
);
set(cell, 'style', style);
set(cell, 'hidden', false);
set(cell, 'key', itemKey);
cellMap[itemKey] = cell;
} else {
newItems.push(itemIndex);
}
}

for (i = 0; i < this._cells.length; i++) {
cell = this._cells[i];
if (!cellMap[cell.key]) {
if (newItems.length) {
itemIndex = newItems.pop();
let item = items.objectAt(itemIndex);
itemKey = identity(item);
// additional `checked` argument
style = this._cellLayout.formatItemStyle(
itemIndex,
this._clientWidth,
this._clientHeight,
this.checked
);
set(cell, 'style', style);
set(cell, 'key', itemKey);
set(cell, 'index', itemIndex);
set(cell, 'item', item);
set(cell, 'hidden', false);
cellMap[itemKey] = cell;
} else {
set(cell, 'hidden', true);
set(cell, 'style', 'height: 0; display: none;');
}
}
}

for (i = 0; i < newItems.length; i++) {
itemIndex = newItems[i];
let item = items.objectAt(itemIndex);
itemKey = identity(item);
// additional `checked` argument
style = this._cellLayout.formatItemStyle(
itemIndex,
this._clientWidth,
this._clientHeight,
this.checked
);
cell = new Cell(itemKey, item, itemIndex, style);
cellMap[itemKey] = cell;
this._cells.pushObject(cell);
}
this._cellMap = cellMap;
},
actions: {
click: function(e) {
// click on row functionality
// so if you click the actual row but not a link
// find the first link and fire that instead
const name = e.target.nodeName.toLowerCase();
switch (name) {
case 'input':
Expand Down
8 changes: 6 additions & 2 deletions ui-v2/app/controllers/dc/acls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ export default Controller.extend(WithFiltering, {
});
}),
filter: function(item, { s = '', type = '' }) {
const sLower = s.toLowerCase();
return (
get(item, 'Name')
(get(item, 'Name')
.toLowerCase()
.indexOf(s.toLowerCase()) !== -1 &&
.indexOf(sLower) !== -1 ||
get(item, 'ID')
.toLowerCase()
.indexOf(sLower) !== -1) &&
(type === '' || get(item, 'Type') === type)
);
},
Expand Down
2 changes: 2 additions & 0 deletions ui-v2/app/controllers/dc/kv/folder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Controller from './index';
export default Controller.extend();
18 changes: 18 additions & 0 deletions ui-v2/app/controllers/dc/kv/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Controller from '@ember/controller';
import { get } from '@ember/object';
import WithFiltering from 'consul-ui/mixins/with-filtering';
import rightTrim from 'consul-ui/utils/right-trim';
export default Controller.extend(WithFiltering, {
queryParams: {
s: {
as: 'filter',
replace: true,
},
},
filter: function(item, { s = '' }) {
const key = rightTrim(get(item, 'Key'), '/')
.split('/')
.pop();
return key.toLowerCase().indexOf(s.toLowerCase()) !== -1;
},
});
Loading

0 comments on commit bf26498

Please sign in to comment.