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

misc fixes #704

Merged
merged 3 commits into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions dbux-code/src/codeUtil/treeView/BaseTreeViewNodeProvider.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TreeItemCollapsibleState, EventEmitter, window, TreeView } from 'vscode';
import TriggerablePromise from '@dbux/common/src/util/TriggerablePromise';
import EmptyObject from '@dbux/common/src/util/EmptyObject';
import { newLogger } from '@dbux/common/src/log/logger';
import NestedError from '@dbux/common/src/NestedError';
Expand Down Expand Up @@ -50,6 +51,7 @@ export default class BaseTreeViewNodeProvider {
constructor(viewName, options = {}) {
this.treeViewName = viewName;
this.logger = newLogger(this.constructor.name);
this.refreshPromise = new TriggerablePromise(500);
const { showCollapseAll = false, createTreeView = true } = options;

// NOTE: view creation inside the data provider is not ideal,
Expand Down Expand Up @@ -113,6 +115,8 @@ export default class BaseTreeViewNodeProvider {

// NOTE: if we only want to update subtree, pass root of subtree to `fire`
this.repaint();

this.refreshPromise.startIfNotStarted();
}
catch (err) {
throw new NestedError(`${this.constructor.name}.refresh() failed`, err);
Expand Down Expand Up @@ -385,6 +389,12 @@ export default class BaseTreeViewNodeProvider {
}

getChildren = async (node) => {
const children = await this._getChildren(node);
this.refreshPromise.resolve(children);
return children;
}

_getChildren = async (node) => {
try {
if (node) {
this.handleBeforeChildren(node);
Expand Down Expand Up @@ -418,15 +428,19 @@ export default class BaseTreeViewNodeProvider {
/**
* Find a chlid node of given class from parent, or from roots if parent is `undefined`.
* @param {*} clazz A node class that extends `BaseTreeViewNode`
* @param {BaseTreeViewNode} parent
* @param {BaseTreeViewNode} parent
* @return {BaseTreeViewNode}
*/
getNodeByClass(clazz, parent = null) {
let children = this.rootNodes;
if (parent) {
children = parent.children;
}
getChildByClass(clazz, parent) {
Copy link
Owner

Choose a reason for hiding this comment

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

@MiccWan move to BaseTreeViewNode

return parent.children.find(node => node instanceof clazz);
}

return children.find(node => node instanceof clazz);
/**
* Find root of given class.
* @param {*} clazz A node class that extends `BaseTreeViewNode`
* @return {BaseTreeViewNode}
*/
getRootByClass(clazz) {
return this.rootNodes.find(node => node instanceof clazz);
}
}
19 changes: 15 additions & 4 deletions dbux-code/src/globalAnalysisView/GlobalAnalysisViewController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { newLogger } from '@dbux/common/src/log/logger';
import NestedError from '@dbux/common/src/NestedError';
import allApplications from '@dbux/data/src/applications/allApplications';
import traceSelection from '@dbux/data/src/traceSelection';
import searchController from '../search/searchController';
Expand Down Expand Up @@ -49,8 +50,18 @@ export default class GlobalAnalysisViewController {
* #########################################################################*/

async focusOnSearchResult() {
const searchResultNode = this.treeDataProvider.getNodeByClass(GlobalSearchNode);
await this.treeView.reveal(searchResultNode, { select: false, expand: 1 });
const searchResultNode = this.treeDataProvider.getRootByClass(GlobalSearchNode);
try {
Copy link
Owner

Choose a reason for hiding this comment

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

@MiccWan if (!this.treeView.visible) { return; }

/**
* NOTE: VSCode sometimes failed to reveal if `refresh` is executing simultaneously, which causes an error:
* `Error: TreeError [dbuxTraceDetailsView] Data tree node not found: [object Object]`.
* But currently VSCode API does not support thenable `refresh`.
*/
await this.treeView.reveal(searchResultNode, { select: false, expand: 1 });
}
catch (err) {
warn(new NestedError(`Failed to focus on search result`, err));
}
}

/** ###########################################################################
Expand All @@ -64,10 +75,10 @@ export default class GlobalAnalysisViewController {

async revealSelectedError() {
if (!this.children) {
const errorNode = this.treeDataProvider.getNodeByClass(GlobalErrorsNode);
const errorNode = this.treeDataProvider.getRootByClass(GlobalErrorsNode);
await this.treeView.reveal(errorNode, { select: false, expand: true });
}
const errorNode = this.treeDataProvider.getNodeByClass(GlobalErrorsNode);
const errorNode = this.treeDataProvider.getRootByClass(GlobalErrorsNode);
const selectedErrorNode = errorNode.getSelectedChild();
if (selectedErrorNode) {
await this.treeView.reveal(selectedErrorNode);
Expand Down
15 changes: 8 additions & 7 deletions dbux-code/src/search/searchController.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class SearchController {

constructor() {
this._emitter = new NanoEvents();
this.reset();
this.mode = SearchMode.None;
this.resetSearch();

allApplications.selection.onApplicationsChanged(this.handleApplicationSelectionChanged);
}
Expand Down Expand Up @@ -54,6 +55,11 @@ class SearchController {
return this.matches;
}

clearSearch(fromUser = false) {
this.resetSearch();
this._notifySearch(fromUser);
}

nextSearchMode() {
let nextMode = SearchMode.nextValue(this.mode);
if (nextMode === SearchMode.None) {
Expand All @@ -69,17 +75,12 @@ class SearchController {
return SearchTools[this.mode].getContext(dp, match);
}

clearSearch() {
resetSearch() {
this.searchTerm = '';
this.matches = EmptyArray;
this.contexts = EmptyArray;
}

reset() {
this.mode = SearchMode.None;
this.clearSearch();
}

/** ###########################################################################
* event handling
* #########################################################################*/
Expand Down
55 changes: 55 additions & 0 deletions dbux-common/src/util/TriggerablePromise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import sleep from './sleep';

export default class TriggerablePromise {
Copy link
Owner

Choose a reason for hiding this comment

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

rename to SyncPromise . These are generally used to let outside threads/actors wait for/synchronize against an asynchronous operation.

promise;

_resolve;
_reject;

constructor(timeout) {
this.timeout = timeout;
}

startIfNotStarted() {
if (!this.promise) {
this.start();
}
return this.promise;
}

start() {
const promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});

if (this.timeout) {
this.promise = Promise.race([promise, sleep(this.timeout).then(() => this.resolve())]);
}
else {
this.promise = promise;
}
}

resolve(arg) {
if (this.promise) {
this._handleFinish();
this._resolve(arg);
}
}

reject(arg) {
if (this.promise) {
this._handleFinish();
this._reject(arg);
}
}

wait() {
return this.promise;
}

_handleFinish() {
this.promise = null;
}
}
16 changes: 9 additions & 7 deletions dbux-graph-host/src/componentLib/HostComponentEndpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ class HostComponentEndpoint extends ComponentEndpoint {
await sleep(0);
}

if (this._updatePromise) {
await (this._updatePromise = this._updatePromise.then(noop));
while (this._updatePromise) {
await this._updatePromise;
}
}

Expand Down Expand Up @@ -263,15 +263,17 @@ class HostComponentEndpoint extends ComponentEndpoint {
}
}

_executeUpdate = async () => {
/**
* @returns {Promise}
*/
_executeUpdate = () => {
// debounce mechanism
this._waitingForUpdate = true;
await sleep(0);

// push out new update
const promise = Promise.resolve(
this._performUpdate() // 1. host: update
).
const promise = sleep(0).then(() => {
return this._performUpdate(); // 1. host: update
}).
then(() => {
return this._remoteInternal.updateClient(this.state); // 2. client: update
}).
Expand Down
11 changes: 8 additions & 3 deletions dbux-graph-host/src/graph/SearchBar.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import SearchMode from '@dbux/graph-common/src/shared/SearchMode';
import allApplications from '@dbux/data/src/applications/allApplications';
import UserActionType from '@dbux/data/src/pathways/UserActionType';
import traceSelection from '@dbux/data/src/traceSelection/index';
import HostComponentEndpoint from '../componentLib/HostComponentEndpoint';
import { SelectorType } from './controllers/ContextNodeManager';
Expand Down Expand Up @@ -45,8 +44,14 @@ class SearchBar extends HostComponentEndpoint {
}

search = (searchTerm) => {
Verbose && this.logger.log(`.search() with searchTerm=${searchTerm}`);
this.searchController.search(searchTerm, true);
if (searchTerm) {
Verbose && this.logger.log(`.search() with searchTerm=${searchTerm}`);
this.searchController.search(searchTerm, true);
}
else {
Verbose && this.logger.log(`clear search`);
this.searchController.clearSearch();
}
}

handleSearchModeChanged = (mode) => {
Expand Down
32 changes: 24 additions & 8 deletions dbux-graph-host/src/graph/SyncGraphBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,12 @@ class CallGraphNodes {
context,
});
this.contextNodesByContext.set(context, node);

node.addDisposable(() => {
this._handleContextNodeDisposed(context, node);
});
}

node.addDisposable(() => {
this._handleContextNodeDisposed(node);
});

return node;
}

Expand Down Expand Up @@ -403,10 +403,26 @@ class CallGraphNodes {
* dispose, delete, clear
* ##########################################################################*/

_handleContextNodeDisposed = (context, contextNode) => {
if (this.getContextNodeByContext(context) === contextNode) {
// actual removal of node
this.contextNodesByContext.delete(context);
/**
* remove disposed node from `this.contextNodesByContext`
* @param {ContextNode | HoleNode} node
*/
_handleContextNodeDisposed = (node) => {
let contexts;
if (node instanceof ContextNode) {
contexts = [node.state.context];
}
else if (node instanceof HoleNode) {
contexts = node.group.contexts;
}
else {
throw new Error(`Calling "_handleContextNodeDisposed" with non-ContextNode parameter`);
Copy link
Owner

Choose a reason for hiding this comment

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

add node to the message, so we (kinda) know what it is?

}

for (const context of contexts) {
if (this.getContextNodeByContext(context) === node) {
this.contextNodesByContext.delete(context);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion dbux-graph-host/src/graph/controllers/FocusController.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default class FocusController extends HostComponentEndpoint {
}

await targetNode.reveal?.();
this.remote.slideToNode(targetNode);
await this.remote.slideToNode(targetNode);
}

clearFocus() {
Expand Down