Merge "namespace_browser: Do not refresh the details sidebar if selection has not changed."
diff --git a/Makefile b/Makefile
index 3ecf090..42d5cee 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,8 @@
GO_FILES = $(shell find go -name "*.go")
VDL_FILES = $(shell find go -name "*.vdl")
+default: build
+
# Creating the bundle JS file.
public/bundle.js: $(BROWSERIFY_FILES) node_modules src/components/help/content/*.md
:;jshint src # lint all src JavaScript files.
@@ -93,7 +95,7 @@
# Continuously watch for changes to .js, .html or .css files.
# Rebundles the appropriate bundles when local files change.
watch:
- watch -n 1 make
+ watch -n 1 make build
# Continuously reruns the tests as they change.
watch-test: go/bin
diff --git a/src/components/browse/item-card-list/item-card/index.css b/src/components/browse/item-card-list/item-card/index.css
index 68f5629..ada4671 100644
--- a/src/components/browse/item-card-list/item-card/index.css
+++ b/src/components/browse/item-card-list/item-card/index.css
@@ -1,5 +1 @@
@import "common-style/card.css";
-
-.item.inaccessible {
- opacity: 0.5;
-}
diff --git a/src/components/browse/item-card-list/item-card/index.js b/src/components/browse/item-card-list/item-card/index.js
index 3b3c022..a824df7 100644
--- a/src/components/browse/item-card-list/item-card/index.js
+++ b/src/components/browse/item-card-list/item-card/index.js
@@ -37,16 +37,11 @@
}
// Prepare tooltip and service icon information for the item.
- var isAccessible = true;
var itemTooltip = item.objectName;
var iconCssClass = '.service-type-icon';
var iconAttributes = {};
if (item.isServer) {
- isAccessible = item.serverInfo.isAccessible;
- if (!isAccessible) {
- itemTooltip += ' - Service seems to be offline or inaccessible';
- }
iconAttributes.attributes = {
title: item.serverInfo.typeInfo.typeName,
icon: getServiceIcon(item.serverInfo.typeInfo.key)
@@ -63,8 +58,7 @@
// Put the item card's pieces together.
var itemClassNames = 'item.card' +
- (selected ? '.selected' : '') +
- (!isAccessible ? '.inaccessible' : '');
+ (selected ? '.selected' : '');
var cardLabel = (showShortName ? item.mountedName : item.objectName) ||
'<root>';
diff --git a/src/components/browse/item-details/display-item-details.js b/src/components/browse/item-details/display-item-details.js
index 1f975a5..ee79778 100644
--- a/src/components/browse/item-details/display-item-details.js
+++ b/src/components/browse/item-details/display-item-details.js
@@ -1,5 +1,3 @@
-var mercury = require('mercury');
-
var methodNameToVarHashKey = require('./methodNameToVarHashKey');
var methodStart = require('./method-start.js');
var methodEnd = require('./method-end.js');
@@ -10,6 +8,7 @@
var bookmarkService = require('../../../services/bookmarks/service');
var smartService = require('../../../services/smart/service');
+
var log = require('../../../lib/log')(
'components:browse:item-details:display-item-details'
);
@@ -33,10 +32,13 @@
lastRequestedName = name;
+ state.put('error', null);
+ state.itemName.set(name);
+
// Whether we have finished loading yet.
var isLoaded = false;
// How long to wait before showing loading if things have not loaded yet
- var SHOW_LOADING_THRESHOLD = 500;
+ var SHOW_LOADING_THRESHOLD = 250;
setTimeout(function maybeShowLoadingIndicator() {
if (isLoaded || !isCurrentlySelected()) {
return;
@@ -44,12 +46,16 @@
state.showLoadingIndicator.set(true);
}, SHOW_LOADING_THRESHOLD);
- var resultsPromise = Promise.all([
+ var getItem = Promise.all([
+ //TODO(aghassemi) If isBookmarked fails, we are not showing anything
+ //ideally, we only remove the bookmark related UI and still show the rest.
bookmarkService.isBookmarked(name),
namespaceService.getNamespaceItem(name)
]);
- resultsPromise.then(function(results) {
+ var isBookmarked;
+ var itemObs;
+ getItem.then(function loadSignature(results) {
/*
* Since async call, by the time we are here, a different name
* might be selected.
@@ -59,6 +65,22 @@
return;
}
+ isBookmarked = results[0];
+ itemObs = results[1];
+ state.put('item', itemObs);
+ state.isBookmarked.set(isBookmarked);
+
+ if (itemObs().isServer) {
+ return namespaceService.getSignature(name);
+ } else {
+ return null;
+ }
+ }).then(function setStateAndFinishLoading(signatureResult) {
+
+ if (!isCurrentlySelected()) {
+ return;
+ }
+
// Log the name to the smart service as a potential shortcut, since it was
// successfully visited.
smartService.update('learner-shortcut', {
@@ -67,45 +89,37 @@
log.error('Error while updating shortcut learner', err);
});
- var isBookmarked = results[0];
- var itemObs = results[1];
-
// Indicate we finished loading
setIsLoaded();
- state.put('item', itemObs);
+ state.put('signature', signatureResult);
- state.isBookmarked.set(isBookmarked);
+ if (!itemObs().isServer || !signatureResult) {
+ return;
+ }
- mercury.watch(itemObs, function(item) {
- if (!item.isServer) {
- return;
- }
+ // Go through each signature method, preparing the state needed for its
+ // form to be rendered and deciding if the method should be recommended.
+ signatureResult.forEach(function(methodData, methodName) {
+ var methodKey = methodNameToVarHashKey(methodName);
+ var form = methodForm();
+ state.methodForm.put(methodKey, form.state);
+ events.methodForm.put(methodKey, form.events);
- // Go through each signature method, preparing the state needed for its
- // form to be rendered and deciding if the method should be recommended.
- var signatureResult = item.serverInfo.signature;
- signatureResult.forEach(function(methodData, methodName) {
- var methodKey = methodNameToVarHashKey(methodName);
- var form = methodForm();
- state.methodForm.put(methodKey, form.state);
- events.methodForm.put(methodKey, form.events);
+ // Hook up the new form's method start, end, and toast events.
+ form.events.methodStart(
+ methodStart.bind(null, state, methodName)
+ );
+ form.events.methodEnd(
+ methodEnd.bind(null, state, methodName)
+ );
+ form.events.toast = events.toast;
- // Hook up the new form's method start, end, and toast events.
- form.events.methodStart(
- methodStart.bind(null, state, methodName)
- );
- form.events.methodEnd(
- methodEnd.bind(null, state, methodName)
- );
- form.events.toast = events.toast;
-
- // Finally, allow the form to gather the info it needs to display.
- form.events.displayMethodForm({
- itemName: name,
- signature: signatureResult,
- methodName: methodName
- });
+ // Finally, allow the form to gather the info it needs to display.
+ form.events.displayMethodForm({
+ itemName: name,
+ signature: signatureResult,
+ methodName: methodName
});
});
}).catch(function(err) {
@@ -118,6 +132,7 @@
type: 'error'
});
state.put('item', null);
+ state.put('error', err);
setIsLoaded();
});
@@ -135,4 +150,4 @@
function isCurrentlySelected() {
return (name === lastRequestedName);
}
-}
\ No newline at end of file
+}
diff --git a/src/components/browse/item-details/index.js b/src/components/browse/item-details/index.js
index f65307e..8019460 100644
--- a/src/components/browse/item-details/index.js
+++ b/src/components/browse/item-details/index.js
@@ -1,12 +1,13 @@
var mercury = require('mercury');
var insertCss = require('insert-css');
-var methodNameToVarHashKey = require('./methodNameToVarHashKey.js');
+var methodNameToVarHashKey = require('./methodNameToVarHashKey');
var displayItemDetails = require('./display-item-details');
var bookmark = require('./bookmark');
-var methodForm = require('./method-form/index.js');
+var methodForm = require('./method-form/index');
+var ErrorBox = require('../../error/error-box/index');
var css = require('./index.css');
var h = mercury.h;
@@ -22,13 +23,38 @@
var state = mercury.varhash({
/*
- * namespace item to display details for
+ * objectName for the item we are showing details of.
+ * We keep this in addition to item.objectName since item object may not be
+ * present (when in the middle of loading or when failed to load).
+ * Keeping itemName separate allows us to render a header with add/remove
+ * bookmark actions even when item is loading or has failed to load.
+ * @type {string}
+ */
+ itemName: mercury.value(null),
+
+ /*
+ * namespace item to display details for.
* @see services/namespace/item
* @type {namespaceitem}
*/
item: mercury.value(null),
/*
+ * Any fatal error while getting the details.
+ * Note: will be displayed to user.
+ * @type Error
+ */
+ error: mercury.value(null),
+
+ /*
+ * signature for the item.
+ * It's a map with extra information.
+ * @see services/namespace/signature-adapter
+ * @type {signature}
+ */
+ signature: mercury.value(null),
+
+ /*
* Which tab to display; 0 is for service details
* TODO(alexfandrianto): Once we have more info to display, add more tabs.
* We are currently combining service details, methods, and outputs.
@@ -101,13 +127,16 @@
var detailsContent = renderDetailsContent(state, events);
var methodsContent;
- if (state.item.isServer && state.item.serverInfo.isAccessible) {
+ if (state.item.isServer) {
methodsContent = renderMethodsContent(state, events);
}
-
tabContent = [detailsContent, methodsContent];
+ } else if (state.error) {
+ var errorTitle = 'Unable to connect to ' + state.itemName;
+ tabContent = ErrorBox.render(errorTitle, state.error.toString());
}
+ var headerContent = renderHeaderContent(state, events);
return [h('paper-tabs.tabs', {
attributes: {
'selected': state.selectedTabIndex,
@@ -125,7 +154,7 @@
'selected': state.selectedTabIndex
}
}, [
- h('div.tab-content', tabContent),
+ h('div.tab-content', [headerContent, tabContent]),
])
];
}
@@ -134,7 +163,6 @@
* Renders an action bar on top of the details panel page.
*/
function renderActions(state, events) {
- var item = state.item;
// Bookmark action
var isBookmarked = state.isBookmarked;
@@ -153,7 +181,7 @@
},
'ev-click': mercury.event(events.bookmark, {
bookmark: !isBookmarked,
- name: item.objectName
+ name: state.itemName
})
})
);
@@ -161,6 +189,24 @@
return h('div.icon-group.item-actions', [bookmarkAction]);
}
+
+/*
+ * Renders the header which includes actions and name field.
+ * Header is always displayed, even during loading time or when we fail
+ * to load details for an item.
+ * Note: we should be able to render header without loading signature any
+ * information about the item other than name and whether it is bookmarked.
+ */
+function renderHeaderContent(state, events) {
+ var actions = renderActions(state, events);
+ var headerItems = [
+ actions,
+ renderFieldItem('Name', (state.itemName || '<root>')),
+ ];
+
+ return headerItems;
+}
+
/*
* Renders details about the current service object.
* Note: Currently renders in the same tab as renderMethodsContent.
@@ -176,18 +222,14 @@
typeName = 'Intermediary Name';
}
- var actions = renderActions(state, events);
-
var displayItems = [
- actions,
- renderFieldItem('Name', (item.objectName || '<root>')),
renderFieldItem('Type', typeName, typeDescription)
];
- if (item.isServer) {
+ if (item.isServer && state.signature) {
// Display each service description and show it.
var serviceDescs = [];
- var descs = state.item.serverInfo.signature.pkgNameDescriptions;
+ var descs = state.signature.pkgNameDescriptions;
Object.keys(descs).forEach(function(pkgName) {
var desc = descs[pkgName];
@@ -238,8 +280,8 @@
* making RPCs to the associated service.
*/
function renderMethodSignatures(state, events) {
- var sig = state.item.serverInfo.signature;
- if (!sig) {
+ var sig = state.signature;
+ if (!sig || sig.size === 0) {
return h('div', h('span', 'No method signature'));
}
@@ -294,7 +336,7 @@
var outputTable = h('table', {
attributes: {
'summary': 'Table showing the outputs of methods run on' +
- 'the service. The results are shown in reverse order.'
+ 'the service. The results are shown in reverse order.'
}
}, outputRows);
return h('div.method-output', outputTable);
@@ -327,4 +369,4 @@
state.selectedTabIndex.set(data.index);
});
events.bookmark(bookmark.bind(null, state, events));
-}
+}
\ No newline at end of file
diff --git a/src/components/browse/item-details/method-end.js b/src/components/browse/item-details/method-end.js
index b9171c6..03e8112 100644
--- a/src/components/browse/item-details/method-end.js
+++ b/src/components/browse/item-details/method-end.js
@@ -22,7 +22,7 @@
return;
}
- var sig = state.item().serverInfo.signature;
+ var sig = state.signature;
// Otherwise, we'll have to learn from the results and draw them, if possible.
var numInArgs = sig.get(method).inArgs.length;
@@ -76,7 +76,7 @@
* Learn from the method inputs to be able to suggest them in the future.
*/
function learnMethodInput(state, method, args) {
- var sig = state.item().serverInfo.signature;
+ var sig = state.signature;
args.forEach(function(value, i) {
var argName = sig.get(method).inArgs[i].name;
var input = {
@@ -97,7 +97,7 @@
* Learn from this invocation to be able to suggest them in the future.
*/
function learnMethodInvocation(state, method, args) {
- var sig = state.item().serverInfo.signature;
+ var sig = state.signature;
var input = {
methodName: method,
signature: sig,
diff --git a/src/components/browse/items/visualize-view/index.js b/src/components/browse/items/visualize-view/index.js
index 370ed28..ae097f6 100644
--- a/src/components/browse/items/visualize-view/index.js
+++ b/src/components/browse/items/visualize-view/index.js
@@ -25,8 +25,7 @@
}
// Maximum number of levels that are automatically shown
-// TODO(aghassemi) Switch to globbing <namespace>/... instead
-var MAX_AUTO_LOAD_DEPTH = 3;
+var MAX_AUTO_LOAD_DEPTH = 5;
function TreeWidget(browseState, browseEvents) {
this.browseState = browseState;
@@ -161,8 +160,7 @@
label: item.mountedName,
level: node.level + 1,
shape: shape,
- color: color,
- isGlobbable: item.isGlobbable
+ color: color
};
});
var newEdges = nodesToAdd.map(function(item) {
@@ -174,9 +172,6 @@
});
newNodes.forEach(function(item) {
// recurse if within the MAX_AUTO_LOAD_DEPTH
- if (!item.isGlobbable) {
- return;
- }
if (item.level - self.rootNode.level < MAX_AUTO_LOAD_DEPTH) {
self.loadSubNodes(item);
} else {
diff --git a/src/components/common-style/defaults.css b/src/components/common-style/defaults.css
index f9195a9..74c71f6 100644
--- a/src/components/common-style/defaults.css
+++ b/src/components/common-style/defaults.css
@@ -91,4 +91,4 @@
*/
.margin-left-xxsmall {
margin-left: var(--size-space-xxsmall);
-}
\ No newline at end of file
+}
diff --git a/src/components/error/error-box/index.css b/src/components/error/error-box/index.css
new file mode 100644
index 0000000..9979e67
--- /dev/null
+++ b/src/components/error/error-box/index.css
@@ -0,0 +1,28 @@
+@import "common-style/sizes.css";
+@import "common-style/theme.css";
+
+.error-box-title {
+ display: flex;
+ width: 100%;
+ font-size: var(--size-font-xlarge);
+ color: var(--color-text-secondary);
+}
+
+.error-box-details {
+ width: 100%;
+ font-size: var(--size-font-xsmall);
+ color: var(--color-text-hint);
+ padding: var(--size-space-xxsmall);
+ padding-top: var(--size-space-large);
+}
+
+.error-box {
+ overflow: hidden;
+ word-break: break-word
+}
+
+.error-box-icon {
+ padding-right: var(--size-space-xxsmall);
+ margin-left: -var(--size-space-xxsmall);
+ color: var(--color-error);
+}
\ No newline at end of file
diff --git a/src/components/error/error-box/index.js b/src/components/error/error-box/index.js
new file mode 100644
index 0000000..67064e3
--- /dev/null
+++ b/src/components/error/error-box/index.js
@@ -0,0 +1,30 @@
+var mercury = require('mercury');
+var insertCss = require('insert-css');
+
+var css = require('./index.css');
+
+var h = mercury.h;
+
+module.exports.render = render;
+
+/*
+ * Renders an error in a box with details section
+ * @param message {string} errTitle short error title
+ * @param details {string} details Error details
+ */
+function render(errTitle, details) {
+ insertCss(css);
+
+ var titleView = h('div.error-box-title', [
+ h('core-icon.error-box-icon', {
+ attributes: {
+ icon: 'error'
+ }
+ }),
+ h('span', errTitle)
+ ]);
+
+ var detailsView = h('div.error-box-details', h('span', details));
+
+ return h('div.error-box', [titleView, detailsView]);
+}
\ No newline at end of file
diff --git a/src/components/error/index.css b/src/components/error/index.css
new file mode 100644
index 0000000..c5bfab0
--- /dev/null
+++ b/src/components/error/index.css
@@ -0,0 +1,5 @@
+@import "common-style/sizes.css";
+
+.error-page {
+ padding: var(--size-space-normal);
+}
\ No newline at end of file
diff --git a/src/components/error/index.js b/src/components/error/index.js
index b7544f9..03bcf99 100644
--- a/src/components/error/index.js
+++ b/src/components/error/index.js
@@ -1,4 +1,10 @@
var mercury = require('mercury');
+var insertCss = require('insert-css');
+
+var ErrorBox = require('./error-box/index');
+
+var css = require('./index.css');
+
var h = mercury.h;
module.exports = create;
@@ -23,8 +29,8 @@
}
function render(state) {
- // TODO(aghassemi)
- return [
- h('p', state.message)
- ];
+ insertCss(css);
+
+ var errorTitle = 'Something went wrong :(';
+ return h('div.error-page', ErrorBox.render(errorTitle, state.message));
}
\ No newline at end of file
diff --git a/src/components/main-content/index.js b/src/components/main-content/index.js
index acc5c03..f86411a 100644
--- a/src/components/main-content/index.js
+++ b/src/components/main-content/index.js
@@ -1,8 +1,10 @@
var mercury = require('mercury');
var insertCss = require('insert-css');
+
var Browse = require('../browse/index');
var Help = require('../help/index');
var ErrorPage = require('../error/index');
+
var css = require('./index.css');
var h = mercury.h;
diff --git a/src/components/user-account/index.css b/src/components/user-account/index.css
new file mode 100644
index 0000000..7ca09fe
--- /dev/null
+++ b/src/components/user-account/index.css
@@ -0,0 +1,10 @@
+@import "common-style/theme.css";
+@import "common-style/sizes.css";
+
+.account-name {
+ position: absolute;
+ right: var(--size-space-xxsmall);
+ top: var(--size-space-xxsmall);
+ color: var(--color-text-secondary);
+ font-size: var(--size-font-xsmall);
+}
\ No newline at end of file
diff --git a/src/components/user-account/index.js b/src/components/user-account/index.js
index 24e8cfc..587b98a 100644
--- a/src/components/user-account/index.js
+++ b/src/components/user-account/index.js
@@ -1,7 +1,14 @@
var mercury = require('mercury');
+var insertCss = require('insert-css');
+
var namespaceService = require('../../services/namespace/service');
+var css = require('./index.css');
+
+var h = mercury.h;
+
module.exports = create;
+module.exports.render = render;
/*
* User Account
@@ -24,3 +31,16 @@
state: state
};
}
+
+function render(state) {
+ insertCss(css);
+
+ return h('core-tooltip.account-name', {
+ attributes: {
+ 'label': 'You are logged in as:',
+ 'position': 'bottom'
+ }
+ },
+ h('span', state.accountName)
+ );
+}
\ No newline at end of file
diff --git a/src/components/viewport/index.css b/src/components/viewport/index.css
index 69ade76..de96220 100644
--- a/src/components/viewport/index.css
+++ b/src/components/viewport/index.css
@@ -27,14 +27,6 @@
color: var(--color-white);
}
-.account-name {
- position: absolute;
- right: var(--size-space-xxsmall);
- top: var(--size-space-xxsmall);
- color: var(--color-text-secondary);
- font-size: var(--size-font-xsmall);
-}
-
/*
* Wrap the paper-toast in a fixed div. This allows us to show multiple toasts.
*/
diff --git a/src/components/viewport/index.js b/src/components/viewport/index.js
index fcd1d1d..30b18f8 100644
--- a/src/components/viewport/index.js
+++ b/src/components/viewport/index.js
@@ -4,6 +4,7 @@
var Sidebar = require('../sidebar/index');
var MainContent = require('../main-content/index');
var ReportBug = require('../bug-report/index');
+var UserAccount = require('../user-account/index');
var css = require('./index.css');
@@ -125,15 +126,8 @@
'ev-click': mercury.event(events.viewport.openSidebar)
}),
h('h2.title', state.viewport.title),
- MainContent.renderHeader(state,events),
- h('core-tooltip.account-name', {
- attributes: {
- 'label': 'You are logged in as:',
- 'position': 'left'
- }
- },
- h('span', state.userAccount.accountName)
- )
+ MainContent.renderHeader(state, events),
+ UserAccount.render(state.userAccount)
]);
}
diff --git a/src/services/namespace/item.js b/src/services/namespace/item.js
index 8d50dbb..dfc7127 100644
--- a/src/services/namespace/item.js
+++ b/src/services/namespace/item.js
@@ -34,23 +34,16 @@
}
/*
- * Creates an observable struct representing information about a server such as
- * type information, signature, etc...
+ * Creates an observable struct representing type information about a server.
*
* @param {mercury.struct} obj.typeInfo. Struct representing the type of the
* server. ServerTypeInfo includes key, name, description, icon, etc..
* @see #createServerTypeInfo method for details on typeInfo.
- * @param {object} obj.signature object representing the method signature of the
- * server.
- * @param {boolean} obj.isAccessible Whether the server instance is online and
- * accessible by the user.
* @return {mercury.struct}
*/
function createServerInfo(obj) {
return mercury.struct({
typeInfo: obj.typeInfo,
- signature: mercury.value(obj.signature),
- isAccessible: mercury.value(obj.isAccessible)
});
}
diff --git a/src/services/namespace/service.js b/src/services/namespace/service.js
index 0408f82..b9ea31b 100644
--- a/src/services/namespace/service.js
+++ b/src/services/namespace/service.js
@@ -21,6 +21,11 @@
util: namespaceUtil,
};
+//TODO(aghassemi) What's a good timeout? It should be shorter than this.
+//Can we use ML to dynamically change the timeout?
+//Should this be a user settings?
+var RPC_TIMEOUT = 30 * 1000;
+
/*
* Lazy getter and initializer for Veyron runtime
*/
@@ -58,7 +63,7 @@
* the changes.
*
* The observable result has an events property which is an EventEmitter
- * and emits 'end', 'streamError' and 'itemError' events.
+ * and emits 'end' and 'streamError' events.
*
* @param {string} pattern Glob pattern
* @return {Promise.<mercury.array>} Promise of an observable array
@@ -95,35 +100,29 @@
}).then(function updateResult(globStream) {
var itemPromises = [];
- globStream.on('data', function createItem(result) {
+ globStream.on('data', function createItem(globResult) {
// Create an item as glob results come in and add the item to result
- var createItemPromise = createNamespaceItem(result)
- .then(function(item) {
- // TODO(aghassemi) namespace glob can return duplicate results, this
- // temporary fix keeps the one that's a server. Is this correct?
- // If a name can be more than one thing, UI needs change too.
- var existingItem = globItemsObservArr.filter(function(curItem) {
- return curItem().objectName === item().objectName;
- }).get(0);
- if (existingItem) {
- // override the old one if new item is a server
- if (item().isServer) {
- var index = globItemsObservArr.indexOf(existingItem);
- globItemsObservArr.put(index, item);
- }
- } else {
- globItemsObservArr.push(item);
- }
- }).catch(function(err) {
- globCache.del(cacheKey);
- immutableResult.events.emit('itemError', {
- name: result.name,
- error: err
- });
- log.error('Failed to create item for "' + result.name + '"', err);
- });
+ var result = createNamespaceItem(globResult);
+ var item = result.item;
+ var onFinishPromise = result.onFinish;
- itemPromises.push(createItemPromise);
+ // TODO(aghassemi) namespace glob can return duplicate results, this
+ // temporary fix keeps the one that's a server. Is this correct?
+ // If a name can be more than one thing, UI needs change too.
+ var existingItem = globItemsObservArr.filter(function(curItem) {
+ return curItem().objectName === item().objectName;
+ }).get(0);
+ if (existingItem) {
+ // override the old one if new item is a server
+ if (item().isServer) {
+ var index = globItemsObservArr.indexOf(existingItem);
+ globItemsObservArr.put(index, item);
+ }
+ } else {
+ globItemsObservArr.push(item);
+ }
+
+ itemPromises.push(onFinishPromise);
});
globStream.on('end', function() {
@@ -169,9 +168,6 @@
resultsObs.events.on('streamError', function(err) {
reject(err);
});
- resultsObs.events.on('itemError', function(err) {
- reject(err);
- });
resultsObs.events.on('end', function() {
var results = resultsObs();
if (results.length === 0) {
@@ -239,7 +235,7 @@
return Promise.resolve(cacheHit);
}
return getRuntime().then(function invokeSignatureMethod(rt) {
- var ctx = veyron.context.Context();
+ var ctx = veyron.context.Context().withTimeout(RPC_TIMEOUT);
var client = rt.newClient();
return client.signature(ctx, objectName);
}).then(function cacheAndReturnSignature(signatures) {
@@ -306,11 +302,11 @@
*/
function makeRPC(name, methodName, args) {
return getRuntime().then(function bindToName(rt) {
- var ctx = veyron.context.Context();
+ var ctx = veyron.context.Context().withTimeout(RPC_TIMEOUT);
return rt.bindTo(ctx, name);
}).then(function callMethod(service) {
log.debug('Calling', methodName, 'on', name, 'with', args);
- var ctx = veyron.context.Context();
+ var ctx = veyron.context.Context().withTimeout(RPC_TIMEOUT);
args.unshift(ctx);
return service[methodName].apply(null, args);
}).then(function returnResult(result) {
@@ -325,60 +321,62 @@
* "bar/baz/foo"
* @param {MountEntry} mountEntry The mount entry from glob results.
* @param {Array<string>} List of server addresses this name points to, if any.
- * @return {mercury.struct}
+ * @return item: {mercury.struct} onFinish: {Promise<bool>} Promise indicating
+ * we have loaded all the information including the async ones for the item.
*/
function createNamespaceItem(mountEntry) {
var name = mountEntry.name;
+
// mounted name relative to parent
var mountedName = namespaceUtil.basename(name);
var servers = mountEntry.servers;
- // Find out if the object referenced by name is globbable and get
- // server related information about it.
+ // get server related information.
var isServer = servers.length > 0;
- return Promise.all([
- (!isServer ? Promise.resolve(true) : isGlobbable(name)),
- (isServer ? getServerInfo(name, mountEntry) : Promise.resolve(null))
- ]).then(function(results) {
- return itemFactory.createItem({
- objectName: name,
- mountedName: mountedName,
- isGlobbable: results[0],
- isServer: isServer,
- serverInfo: results[1]
- });
+ var serverInfo = null;
+ if (isServer) {
+ serverInfo = getServerInfo(name, mountEntry);
+ }
+
+ var item = itemFactory.createItem({
+ objectName: name,
+ mountedName: mountedName,
+ isGlobbable: false,
+ isServer: isServer,
+ serverInfo: serverInfo
});
+
+ // find out if the object referenced by name is globbable asynchronously and
+ // update the state when it comes back
+ var onFinishPromise = isGlobbable(name).then(function(isGlobbable) {
+ item.isGlobbable.set(isGlobbable);
+ return true;
+ }).catch(function() {
+ return true;
+ });
+
+ return {
+ item: item,
+ onFinish: onFinishPromise
+ };
}
/*
* Creates an observable struct representing information about a server such as
- * type information, signature, etc...
+ * type information
* @see item.js for details.
* @param {string} objectName Object name to get serverInfo for.
* @param {MountEntry} mountEntry mount entry to item to get serverInfo for.
* @return {mercury.struct}
*/
function getServerInfo(objectName, mountEntry) {
- var signature;
- var isAccessible;
- return getSignature(objectName).then(function gotSignature(sig) {
- signature = sig;
- isAccessible = true;
- return getServerTypeInfo(sig, mountEntry);
- }, function failedToGetSignature(err) {
- signature = adaptSignature([]);
- //TODO(aghassemi): We should at least be able to tell if inaccessible
- //because not authorized vs other reasons.
- isAccessible = false;
- return createUnknownServiceTypeInfo();
- }).then(function(serverTypeInfo) {
- return itemFactory.createServerInfo({
- typeInfo: serverTypeInfo,
- signature: signature,
- isAccessible: isAccessible
- });
+ var typeInfo = getServerTypeInfo(mountEntry);
+ var serverInfo = itemFactory.createServerInfo({
+ typeInfo: typeInfo
});
+
+ return serverInfo;
}
/*
@@ -387,11 +385,10 @@
* would have information such as a key, human readable name and description for
* the type of server.
* @see item.js for details.
- * @param {Signature} signature signature to get serverTypeInfo for.
* @param {MountEntry} mountEntry mount entry to get serverTypeInfo for.
* @return {mercury.struct}
*/
-function getServerTypeInfo(signature, mountEntry) {
+function getServerTypeInfo(mountEntry) {
// Currently we only support detecting mounttables which is
// based on a "MT" flag that comes from the Glob API. Mounttables are special
// in a sense that we fundamentally "know" they are a mounttable.
@@ -418,4 +415,4 @@
typeName: 'Service',
description: null
});
-}
+}
\ No newline at end of file
diff --git a/test/integration/services/namespace/service.js b/test/integration/services/namespace/service.js
index eadb332..57ef3c4 100644
--- a/test/integration/services/namespace/service.js
+++ b/test/integration/services/namespace/service.js
@@ -363,8 +363,6 @@
} else if(vals.isGlobbable === false) {
assertIsNotGlobbable(t, item);
}
- assertHasSignature(t, item);
- assertIsAccessible(t, item);
if (vals.type === 'unknown') {
assertUnknownServiceTypeInfo(t, item);
@@ -410,14 +408,6 @@
t.equal(item.isGlobbable, false, item.mountedName + ': is not globbable');
}
-function assertHasSignature(t, item) {
- t.ok(item.serverInfo.signature, item.mountedName + ': has a signature');
-}
-
-function assertIsAccessible(t, item) {
- t.ok(item.serverInfo.isAccessible, item.mountedName + ': is accessible');
-}
-
function assertIsImmutable(t, observable) {
t.ok(observable.set === undefined, 'is immutable');
}