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

Change tab completion in the UI to prefer common prefix #6759

Merged
merged 4 commits into from
May 22, 2019
Merged
Changes from 1 commit
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
Prev Previous commit
address PR feedback
meirish committed May 21, 2019
commit e0b4c7e9861bd3737aa55bdcfcc89d9d5cd2af55
11 changes: 4 additions & 7 deletions ui/app/mixins/list-controller.js
Original file line number Diff line number Diff line change
@@ -17,18 +17,15 @@ export default Mixin.create({
isLoading: false,

filterMatchesKey: computed('filter', 'model', 'model.[]', function() {
var filter = this.get('filter');
var content = this.get('model');
let { filter, model: content } = this;
return !!(content.length && content.findBy('id', filter));
}),

firstPartialMatch: computed('filter', 'model', 'model.[]', 'filterMatchesKey', function() {
var filter = this.get('filter');
var content = this.get('model');
var filterMatchesKey = this.get('filterMatchesKey');
var re = new RegExp('^' + escapeStringRegexp(filter));
let { filter, filterMatchesKey, model: content } = this;
let re = new RegExp('^' + escapeStringRegexp(filter));
let matchSet = content.filter(key => re.test(key.id));
let match = matchSet.firstObject;
let match = matchSet[0];

if (filterMatchesKey || !match) {
return null;
12 changes: 6 additions & 6 deletions ui/app/utils/common-prefix.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { get } from '@ember/object';

export default function(arr, attribute = 'id') {
let content = arr || [];
export default function(arr = [], attribute = 'id') {
if (!arr.length) {
return '';
}
// this assumes an already sorted array
// if the array is sorted, we want to compare the first and last
// item in the array - if they share a prefix, all of the items do
let firstString = get(content[0], attribute);
let lastString = get(content[arr.length - 1], attribute);
let firstString = arr[0][attribute];
let lastString = arr[arr.length - 1][attribute];

Choose a reason for hiding this comment

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

I'm confused as to why you only check the last string in the array here, maybe I don't understand the use case? Ah ok hold on I just re-read that comment up above here (lines 5-8). Wonder if it would be nicer to just pass the two strings instead of an array?

function commonPrefix(a = '', b = '') {
...
}
commonPrefix(arr[0].id, arr[arr.length - 1].id)
commonPrefix(arr[0].name, arr[arr.length - 1].name)
// maybe I might want to recur this at some point
function(item) {
  commonPrefix(prev.id, item.id)
}

You also remove your get dependency by doing that and reduces your function to just do one thing. Again, up to you

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now I think having the whole array contains the overall logic a bit better - if we later decide to change how we calculate the common prefix, we'll have all of the data here - I don't think it saves us anything because we'd need to pull out those strings somewhere. Good point about the get usage - looking at it, I think we can nix it anyway since we can use ES5 getters - I'll look at that!

// the longest the shared prefix could be is the length of the match
let targetLength = firstString.length;
17 changes: 11 additions & 6 deletions ui/tests/unit/utils/common-prefix-test.js
Original file line number Diff line number Diff line change
@@ -2,26 +2,31 @@ import commonPrefix from 'vault/utils/common-prefix';
import { module, test } from 'qunit';

module('Unit | Util | common prefix', function() {
test('it returns empty string if called with no args or an empty array', function(assert) {
let returned = commonPrefix();
assert.equal(returned, '', 'returns an empty string');
returned = commonPrefix([]);
assert.equal(returned, '', 'returns an empty string for an empty array');
});

test('it returns empty string if there are no common prefixes', function(assert) {
let secrets = ['asecret', 'secret2', 'secret3'].map(s => ({id: s}));
let secrets = ['asecret', 'secret2', 'secret3'].map(s => ({ id: s }));
let returned = commonPrefix(secrets);
assert.equal(returned, '', 'returns an empty string');
});

test('it returns the longest prefix', function(assert) {
let secrets = ['secret1', 'secret2', 'secret3'].map(s => ({id: s}));
let secrets = ['secret1', 'secret2', 'secret3'].map(s => ({ id: s }));
let returned = commonPrefix(secrets);
assert.equal(returned, 'secret', 'finds secret prefix');
let greetings = ['hello-there', 'hello-hi', 'hello-howdy'].map(s => ({id: s}));
let greetings = ['hello-there', 'hello-hi', 'hello-howdy'].map(s => ({ id: s }));
returned = commonPrefix(greetings);
assert.equal(returned, 'hello-', 'finds hello- prefix');
});


test('it can compare an attribute that is not "id" to calculate the longest prefix', function(assert) {
let secrets = ['secret1', 'secret2', 'secret3'].map(s => ({name: s}));
let secrets = ['secret1', 'secret2', 'secret3'].map(s => ({ name: s }));
let returned = commonPrefix(secrets, 'name');
assert.equal(returned, 'secret', 'finds secret prefix from name attribute');
});
});