diff options
author | Kushal Pandya <kushalspandya@gmail.com> | 2019-08-15 21:49:25 +0530 |
---|---|---|
committer | Kushal Pandya <kushalspandya@gmail.com> | 2019-08-22 17:58:44 +0530 |
commit | 6044b3ed1eb81cb55d1b978e76f1c1f3ee4e3a70 (patch) | |
tree | 67e337d3284590f79873e18e601a917d1b28c8f2 | |
parent | e84f5a673e254c1e7084821a6d7c6ba919679aa5 (diff) | |
download | gitlab-ce-ce-6878-add-epic-select-dropdown.tar.gz |
Add `searchBy` helper & `SidebarItemEpicsSelect`ce-6878-add-epic-select-dropdown
- Adds `searchBy` util in common utils
- Adds placeholder `SidebarItemEpicsSelect`
-rw-r--r-- | app/assets/javascripts/boards/components/board_sidebar.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/common_utils.js | 60 | ||||
-rw-r--r-- | doc/api/epics.md | 8 | ||||
-rw-r--r-- | spec/javascripts/lib/utils/common_utils_spec.js | 39 |
4 files changed, 109 insertions, 0 deletions
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index 2ace0060c42..ba1fe9202fc 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -22,6 +22,8 @@ export default Vue.extend({ components: { AssigneeTitle, Assignees, + SidebarEpicsSelect: () => + import('ee_component/sidebar/components/sidebar_item_epics_select.vue'), RemoveBtn, Subscriptions, TimeTracker, diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 31c4a920bbe..6e8f63a10a4 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -732,6 +732,66 @@ export const NavigationType = { }; /** + * Method to perform case-insensitive search for a string + * within multiple properties and return object containing + * properties in case there are multiple matches or `null` + * if there's no match. + * + * Eg; Suppose we want to allow user to search using for a string + * within `iid`, `title`, `url` or `reference` props of a target object; + * + * const objectToSearch = { + * "iid": 1, + * "title": "Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate. &3", + * "url": "/groups/gitlab-org/-/epics/1", + * "reference": "&1", + * }; + * + * Following is how we call searchBy and the return values it will yield; + * + * - `searchBy('omnis', objectToSearch);`: This will return `{ title: ... }` as our + * query was found within title prop we only return that. + * - `searchBy('1', objectToSearch);`: This will return `{ "iid": ..., "reference": ..., "url": ... }`. + * - `searchBy('https://gitlab.com/groups/gitlab-org/-/epics/1', objectToSearch);`: + * This will return `{ "url": ... }`. + * - `searchBy('foo', objectToSearch);`: This will return `null` as no property value + * matched with our query. + * + * You can learn more about behaviour of this method by referring to tests + * within `spec/javascripts/lib/utils/common_utils_spec.js`. + * + * @param {string} query String to search for + * @param {object} searchSpace Object containing properties to search in for `query` + */ +export const searchBy = (query = '', searchSpace = {}) => { + const targetKeys = searchSpace !== null ? Object.keys(searchSpace) : []; + + if (!query || !targetKeys.length) { + return null; + } + + const normalizedQuery = query.toLowerCase(); + const matches = targetKeys + .filter(item => { + const searchItem = `${searchSpace[item]}`.toLowerCase(); + + return ( + searchItem.indexOf(normalizedQuery) > -1 || + normalizedQuery.indexOf(searchItem) > -1 || + normalizedQuery === searchItem + ); + }) + .reduce((acc, prop) => { + const match = acc; + match[prop] = searchSpace[prop]; + + return acc; + }, {}); + + return Object.keys(matches).length ? matches : null; +}; + +/** * Checks if the given Label has a special syntax `::` in * it's title. * diff --git a/doc/api/epics.md b/doc/api/epics.md index 3036b3c2364..87ae0c48199 100644 --- a/doc/api/epics.md +++ b/doc/api/epics.md @@ -65,6 +65,8 @@ Example response: "title": "Accusamus iste et ullam ratione voluptatem omnis debitis dolor est.", "description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.", "state": "opened", + "web_edit_url": "http://localhost:3001/groups/test/-/epics/4", + "reference": "&4", "author": { "id": 10, "name": "Lu Mayer", @@ -118,6 +120,8 @@ Example response: "title": "Ea cupiditate dolores ut vero consequatur quasi veniam voluptatem et non.", "description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.", "state": "opened", + "web_edit_url": "http://localhost:3001/groups/test/-/epics/5", + "reference": "&5", "author":{ "id": 7, "name": "Pamella Huel", @@ -182,6 +186,8 @@ Example response: "title": "Epic", "description": "Epic description", "state": "opened", + "web_edit_url": "http://localhost:3001/groups/test/-/epics/6", + "reference": "&6", "author": { "name" : "Alexandra Bashirian", "avatar_url" : null, @@ -247,6 +253,8 @@ Example response: "title": "New Title", "description": "Epic description", "state": "opened", + "web_edit_url": "http://localhost:3001/groups/test/-/epics/6", + "reference": "&6", "author": { "name" : "Alexandra Bashirian", "avatar_url" : null, diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 296ee85089f..85949f2ae86 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -895,6 +895,45 @@ describe('common_utils', () => { }); }); + describe('searchBy', () => { + const searchSpace = { + iid: 1, + reference: '&1', + title: 'Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate.', + url: '/groups/gitlab-org/-/epics/1', + }; + + it('returns null when `query` or `searchSpace` params are empty/undefined', () => { + expect(commonUtils.searchBy('omnis', null)).toBeNull(); + expect(commonUtils.searchBy('', searchSpace)).toBeNull(); + expect(commonUtils.searchBy()).toBeNull(); + }); + + it('returns object with matching props based on `query` & `searchSpace` params', () => { + // String `omnis` is found only in `title` prop so return just that + expect(commonUtils.searchBy('omnis', searchSpace)).toEqual( + jasmine.objectContaining({ + title: searchSpace.title, + }), + ); + + // String `1` is found in both `iid` and `reference` props so return both + expect(commonUtils.searchBy('1', searchSpace)).toEqual( + jasmine.objectContaining({ + iid: searchSpace.iid, + reference: searchSpace.reference, + }), + ); + + // String `/epics/1` is found in `url` prop so return just that + expect(commonUtils.searchBy('/epics/1', searchSpace)).toEqual( + jasmine.objectContaining({ + url: searchSpace.url, + }), + ); + }); + }); + describe('isScopedLabel', () => { it('returns true when `::` is present in title', () => { expect(commonUtils.isScopedLabel({ title: 'foo::bar' })).toBe(true); |