Ensure query compare order matches expectation

A user typically expects that the first selection would be
the query that they are comparing _from_ and the second query
is being compared _to_.

This commit ensures that something like this expectation will
always hold.

So, when there are two queries selected, the first one selected
will always be _from_ and appear on the left side of the compare
view. The one selected later will be _to_ and appear on the right.

There is a corner case when there are 3 or more selected queries
and a user *unselects* a query. We do not track the selection
order of the remaining two queries.
This commit is contained in:
Andrew Eisenberg
2020-06-23 11:44:27 -07:00
parent f4e983e214
commit 77b13bd8e3
2 changed files with 73 additions and 4 deletions

View File

@@ -167,7 +167,7 @@ export class QueryHistoryManager {
treeDataProvider: HistoryTreeDataProvider;
treeView: vscode.TreeView<CompletedQuery>;
lastItemClick: { time: Date; item: CompletedQuery } | undefined;
compareWithItem: CompletedQuery | undefined;
constructor(
ctx: ExtensionContext,
@@ -185,6 +185,7 @@ export class QueryHistoryManager {
treeDataProvider,
canSelectMany: true,
});
// Lazily update the tree view selection due to limitations of TreeView API (see
// `updateTreeViewSelectionIfVisible` doc for details)
this.treeView.onDidChangeVisibility(async (_ev) =>
@@ -195,6 +196,7 @@ export class QueryHistoryManager {
if (ev.selection.length == 0) {
this.updateTreeViewSelectionIfVisible();
}
this.updateCompareWith(ev.selection);
});
logger.log('Registering query history panel commands.');
ctx.subscriptions.push(
@@ -349,8 +351,8 @@ export class QueryHistoryManager {
throw new Error('Please select a successful query.');
}
const from = singleItem;
const to = await this.findOtherQueryToCompare(singleItem, multiSelect);
const from = this.compareWithItem || singleItem;
const to = await this.findOtherQueryToCompare(from, multiSelect);
if (from && to) {
this.doCompareCallback(from, to);
@@ -588,4 +590,33 @@ the file in the file explorer and dragging it into the workspace.`
}
return true;
}
/**
* Updates the compare with source query. This ensures that all compare command invocations
* when exactly 2 queries are selected always have the proper _from_ query. Always use
* compareWithItem as the _from_ query.
*
* The heuristic is this:
*
* 1. If selection is empty or has length > 2 delete compareWithItem.
* 2. If selection is length 1, then set that item to compareWithItem.
* 3. If selection is length 2, then make sure compareWithItem is one of the selected items
* if not, then delete compareWithItem. If it is then, do nothing.
*
* This ensures that compareWithItem is always the first item selected if there are only
* two selected items.
*
* @param newSelection the new selection after the most recent selection change
*/
private updateCompareWith(newSelection: CompletedQuery[]) {
if (newSelection.length === 1) {
this.compareWithItem = newSelection[0];
} else if (
newSelection.length !== 2 ||
!this.compareWithItem ||
!newSelection.includes(this.compareWithItem)
) {
this.compareWithItem = undefined;
}
}
}

View File

@@ -169,6 +169,42 @@ describe('query-history', () => {
}
});
});
describe('updateCompareWith', () => {
it('should update compareWithItem when there is a single item', () => {
const queryHistory = createMockQueryHistory([]);
queryHistory.updateCompareWith(['a']);
expect(queryHistory.compareWithItem).to.be.eq('a');
});
it('should delete compareWithItem when there are 0 items', () => {
const queryHistory = createMockQueryHistory([]);
queryHistory.compareWithItem = 'a';
queryHistory.updateCompareWith([]);
expect(queryHistory.compareWithItem).to.be.undefined;
});
it('should delete compareWithItem when there are more than 2 items', () => {
const queryHistory = createMockQueryHistory([]);
queryHistory.compareWithItem = 'a';
queryHistory.updateCompareWith(['a', 'b', 'c']);
expect(queryHistory.compareWithItem).to.be.undefined;
});
it('should delete compareWithItem when there are 2 items and disjoint from compareWithItem', () => {
const queryHistory = createMockQueryHistory([]);
queryHistory.compareWithItem = 'a';
queryHistory.updateCompareWith(['b', 'c']);
expect(queryHistory.compareWithItem).to.be.undefined;
});
it('should do nothing when compareWithItem exists and exactly 2 items', () => {
const queryHistory = createMockQueryHistory([]);
queryHistory.compareWithItem = 'a';
queryHistory.updateCompareWith(['a', 'b']);
expect(queryHistory.compareWithItem).to.be.eq('a');
});
});
});
function createMockQueryHistory(allHistory: {}[]) {
@@ -177,6 +213,8 @@ function createMockQueryHistory(allHistory: {}[]) {
findOtherQueryToCompare: (QueryHistoryManager.prototype as any).findOtherQueryToCompare,
treeDataProvider: {
allHistory
}
},
updateCompareWith: (QueryHistoryManager.prototype as any).updateCompareWith,
compareWithItem: undefined as undefined | string,
};
}