Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
d8ecae2d
Commit
d8ecae2d
authored
Sep 29, 2020
by
Alan (Maciej) Paruszewski
Committed by
Kushal Pandya
Sep 29, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use backend filtering to autocomplete vulnerabilities
parent
c22d662c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
241 additions
and
7 deletions
+241
-7
app/assets/javascripts/gfm_auto_complete.js
app/assets/javascripts/gfm_auto_complete.js
+25
-4
spec/frontend/gfm_auto_complete_spec.js
spec/frontend/gfm_auto_complete_spec.js
+216
-3
No files found.
app/assets/javascripts/gfm_auto_complete.js
View file @
d8ecae2d
...
...
@@ -4,6 +4,7 @@ import { escape, template } from 'lodash';
import
SidebarMediator
from
'
~/sidebar/sidebar_mediator
'
;
import
glRegexp
from
'
./lib/utils/regexp
'
;
import
AjaxCache
from
'
./lib/utils/ajax_cache
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
spriteIcon
}
from
'
./lib/utils/common_utils
'
;
import
*
as
Emoji
from
'
~/emoji
'
;
...
...
@@ -61,6 +62,7 @@ class GfmAutoComplete {
this
.
dataSources
=
dataSources
;
this
.
cachedData
=
{};
this
.
isLoadingData
=
{};
this
.
previousQuery
=
''
;
}
setup
(
input
,
enableMap
=
defaultAutocompleteConfig
)
{
...
...
@@ -526,7 +528,7 @@ class GfmAutoComplete {
}
getDefaultCallbacks
()
{
const
fetchData
=
this
.
fetchData
.
bind
(
this
)
;
const
self
=
this
;
return
{
sorter
(
query
,
items
,
searchKey
)
{
...
...
@@ -539,7 +541,15 @@ class GfmAutoComplete {
},
filter
(
query
,
data
,
searchKey
)
{
if
(
GfmAutoComplete
.
isLoading
(
data
))
{
fetchData
(
this
.
$inputor
,
this
.
at
);
self
.
fetchData
(
this
.
$inputor
,
this
.
at
);
return
data
;
}
if
(
GfmAutoComplete
.
typesWithBackendFiltering
.
includes
(
GfmAutoComplete
.
atTypeMap
[
this
.
at
])
&&
self
.
previousQuery
!==
query
)
{
self
.
fetchData
(
this
.
$inputor
,
this
.
at
,
query
);
self
.
previousQuery
=
query
;
return
data
;
}
return
$
.
fn
.
atwho
.
default
.
callbacks
.
filter
(
query
,
data
,
searchKey
);
...
...
@@ -587,13 +597,22 @@ class GfmAutoComplete {
};
}
fetchData
(
$input
,
at
)
{
fetchData
(
$input
,
at
,
search
)
{
if
(
this
.
isLoadingData
[
at
])
return
;
this
.
isLoadingData
[
at
]
=
true
;
const
dataSource
=
this
.
dataSources
[
GfmAutoComplete
.
atTypeMap
[
at
]];
if
(
this
.
cachedData
[
at
])
{
if
(
GfmAutoComplete
.
typesWithBackendFiltering
.
includes
(
GfmAutoComplete
.
atTypeMap
[
at
]))
{
axios
.
get
(
dataSource
,
{
params
:
{
search
}
})
.
then
(({
data
})
=>
{
this
.
loadData
(
$input
,
at
,
data
);
})
.
catch
(()
=>
{
this
.
isLoadingData
[
at
]
=
false
;
});
}
else
if
(
this
.
cachedData
[
at
])
{
this
.
loadData
(
$input
,
at
,
this
.
cachedData
[
at
]);
}
else
if
(
GfmAutoComplete
.
atTypeMap
[
at
]
===
'
emojis
'
)
{
Emoji
.
initEmojiMap
()
...
...
@@ -687,6 +706,8 @@ GfmAutoComplete.atTypeMap = {
$
:
'
snippets
'
,
};
GfmAutoComplete
.
typesWithBackendFiltering
=
[
'
vulnerabilities
'
];
// Emoji
GfmAutoComplete
.
glEmojiTag
=
null
;
GfmAutoComplete
.
Emoji
=
{
...
...
spec/frontend/gfm_auto_complete_spec.js
View file @
d8ecae2d
...
...
@@ -7,15 +7,228 @@ import GfmAutoComplete, { membersBeforeSave } from 'ee_else_ce/gfm_auto_complete
import
{
TEST_HOST
}
from
'
helpers/test_constants
'
;
import
{
getJSONFixture
}
from
'
helpers/fixtures
'
;
import
waitForPromises
from
'
jest/helpers/wait_for_promises
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
const
labelsFixture
=
getJSONFixture
(
'
autocomplete_sources/labels.json
'
);
describe
(
'
GfmAutoComplete
'
,
()
=>
{
const
gfmAutoCompleteCallbacks
=
GfmAutoComplete
.
prototype
.
getDefaultCallbacks
.
call
({
fetchData
:
()
=>
{},
});
const
fetchDataMock
=
{
fetchData
:
jest
.
fn
()
};
let
gfmAutoCompleteCallbacks
=
GfmAutoComplete
.
prototype
.
getDefaultCallbacks
.
call
(
fetchDataMock
);
let
atwhoInstance
;
let
sorterValue
;
let
filterValue
;
describe
(
'
.typesWithBackendFiltering
'
,
()
=>
{
it
(
'
should contain vulnerabilities
'
,
()
=>
{
expect
(
GfmAutoComplete
.
typesWithBackendFiltering
).
toContain
(
'
vulnerabilities
'
);
});
});
describe
(
'
DefaultOptions.filter
'
,
()
=>
{
let
items
;
beforeEach
(()
=>
{
jest
.
spyOn
(
fetchDataMock
,
'
fetchData
'
);
jest
.
spyOn
(
$
.
fn
.
atwho
.
default
.
callbacks
,
'
filter
'
).
mockImplementation
(()
=>
{});
});
describe
(
'
assets loading
'
,
()
=>
{
beforeEach
(()
=>
{
atwhoInstance
=
{
setting
:
{},
$inputor
:
'
inputor
'
,
at
:
'
+
'
};
items
=
[
'
loading
'
];
filterValue
=
gfmAutoCompleteCallbacks
.
filter
.
call
(
atwhoInstance
,
''
,
items
);
});
it
(
'
should call the fetchData function without query
'
,
()
=>
{
expect
(
fetchDataMock
.
fetchData
).
toHaveBeenCalledWith
(
'
inputor
'
,
'
+
'
);
});
it
(
'
should not call the default atwho filter
'
,
()
=>
{
expect
(
$
.
fn
.
atwho
.
default
.
callbacks
.
filter
).
not
.
toHaveBeenCalled
();
});
it
(
'
should return the passed unfiltered items
'
,
()
=>
{
expect
(
filterValue
).
toEqual
(
items
);
});
});
describe
(
'
backend filtering
'
,
()
=>
{
beforeEach
(()
=>
{
atwhoInstance
=
{
setting
:
{},
$inputor
:
'
inputor
'
,
at
:
'
+
'
};
items
=
[];
});
describe
(
'
when previous query is different from current one
'
,
()
=>
{
beforeEach
(()
=>
{
gfmAutoCompleteCallbacks
=
GfmAutoComplete
.
prototype
.
getDefaultCallbacks
.
call
({
previousQuery
:
'
oldquery
'
,
...
fetchDataMock
,
});
filterValue
=
gfmAutoCompleteCallbacks
.
filter
.
call
(
atwhoInstance
,
'
newquery
'
,
items
);
});
it
(
'
should call the fetchData function with query
'
,
()
=>
{
expect
(
fetchDataMock
.
fetchData
).
toHaveBeenCalledWith
(
'
inputor
'
,
'
+
'
,
'
newquery
'
);
});
it
(
'
should not call the default atwho filter
'
,
()
=>
{
expect
(
$
.
fn
.
atwho
.
default
.
callbacks
.
filter
).
not
.
toHaveBeenCalled
();
});
it
(
'
should return the passed unfiltered items
'
,
()
=>
{
expect
(
filterValue
).
toEqual
(
items
);
});
});
describe
(
'
when previous query is not different from current one
'
,
()
=>
{
beforeEach
(()
=>
{
gfmAutoCompleteCallbacks
=
GfmAutoComplete
.
prototype
.
getDefaultCallbacks
.
call
({
previousQuery
:
'
oldquery
'
,
...
fetchDataMock
,
});
filterValue
=
gfmAutoCompleteCallbacks
.
filter
.
call
(
atwhoInstance
,
'
oldquery
'
,
items
,
'
searchKey
'
,
);
});
it
(
'
should not call the fetchData function
'
,
()
=>
{
expect
(
fetchDataMock
.
fetchData
).
not
.
toHaveBeenCalled
();
});
it
(
'
should call the default atwho filter
'
,
()
=>
{
expect
(
$
.
fn
.
atwho
.
default
.
callbacks
.
filter
).
toHaveBeenCalledWith
(
'
oldquery
'
,
items
,
'
searchKey
'
,
);
});
});
});
});
describe
(
'
fetchData
'
,
()
=>
{
const
{
fetchData
}
=
GfmAutoComplete
.
prototype
;
let
mock
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
jest
.
spyOn
(
axios
,
'
get
'
);
jest
.
spyOn
(
AjaxCache
,
'
retrieve
'
);
});
afterEach
(()
=>
{
mock
.
restore
();
});
describe
(
'
already loading data
'
,
()
=>
{
beforeEach
(()
=>
{
const
context
=
{
isLoadingData
:
{
'
+
'
:
true
},
dataSources
:
{},
cachedData
:
{},
};
fetchData
.
call
(
context
,
{},
'
+
'
,
''
);
});
it
(
'
should not call either axios nor AjaxCache
'
,
()
=>
{
expect
(
axios
.
get
).
not
.
toHaveBeenCalled
();
expect
(
AjaxCache
.
retrieve
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
backend filtering
'
,
()
=>
{
describe
(
'
data is not in cache
'
,
()
=>
{
let
context
;
beforeEach
(()
=>
{
context
=
{
isLoadingData
:
{
'
+
'
:
false
},
dataSources
:
{
vulnerabilities
:
'
vulnerabilities_autocomplete_url
'
},
cachedData
:
{},
};
});
it
(
'
should call axios with query
'
,
()
=>
{
fetchData
.
call
(
context
,
{},
'
+
'
,
'
query
'
);
expect
(
axios
.
get
).
toHaveBeenCalledWith
(
'
vulnerabilities_autocomplete_url
'
,
{
params
:
{
search
:
'
query
'
},
});
});
it
.
each
([
200
,
500
])(
'
should set the loading state
'
,
async
responseStatus
=>
{
mock
.
onGet
(
'
vulnerabilities_autocomplete_url
'
).
replyOnce
(
responseStatus
);
fetchData
.
call
(
context
,
{},
'
+
'
,
'
query
'
);
expect
(
context
.
isLoadingData
[
'
+
'
]).
toBe
(
true
);
await
waitForPromises
();
expect
(
context
.
isLoadingData
[
'
+
'
]).
toBe
(
false
);
});
});
describe
(
'
data is in cache
'
,
()
=>
{
beforeEach
(()
=>
{
const
context
=
{
isLoadingData
:
{
'
+
'
:
false
},
dataSources
:
{
vulnerabilities
:
'
vulnerabilities_autocomplete_url
'
},
cachedData
:
{
'
+
'
:
[{}]
},
};
fetchData
.
call
(
context
,
{},
'
+
'
,
'
query
'
);
});
it
(
'
should anyway call axios with query ignoring cache
'
,
()
=>
{
expect
(
axios
.
get
).
toHaveBeenCalledWith
(
'
vulnerabilities_autocomplete_url
'
,
{
params
:
{
search
:
'
query
'
},
});
});
});
});
describe
(
'
frontend filtering
'
,
()
=>
{
describe
(
'
data is not in cache
'
,
()
=>
{
beforeEach
(()
=>
{
const
context
=
{
isLoadingData
:
{
'
#
'
:
false
},
dataSources
:
{
issues
:
'
issues_autocomplete_url
'
},
cachedData
:
{},
};
fetchData
.
call
(
context
,
{},
'
#
'
,
'
query
'
);
});
it
(
'
should call AjaxCache
'
,
()
=>
{
expect
(
AjaxCache
.
retrieve
).
toHaveBeenCalledWith
(
'
issues_autocomplete_url
'
,
true
);
});
});
describe
(
'
data is in cache
'
,
()
=>
{
beforeEach
(()
=>
{
const
context
=
{
isLoadingData
:
{
'
#
'
:
false
},
dataSources
:
{
issues
:
'
issues_autocomplete_url
'
},
cachedData
:
{
'
#
'
:
[{}]
},
loadData
:
()
=>
{},
};
fetchData
.
call
(
context
,
{},
'
#
'
,
'
query
'
);
});
it
(
'
should not call AjaxCache
'
,
()
=>
{
expect
(
AjaxCache
.
retrieve
).
not
.
toHaveBeenCalled
();
});
});
});
});
describe
(
'
DefaultOptions.sorter
'
,
()
=>
{
describe
(
'
assets loading
'
,
()
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment