Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
44baf08d4f
commit
5333cb6c7c
|
@ -122,6 +122,8 @@ export default {
|
|||
this.toggleAward({ awardName, noteId });
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', this.handleHashChanged);
|
||||
},
|
||||
updated() {
|
||||
this.$nextTick(() => {
|
||||
|
@ -131,6 +133,7 @@ export default {
|
|||
},
|
||||
beforeDestroy() {
|
||||
this.stopPolling();
|
||||
window.removeEventListener('hashchange', this.handleHashChanged);
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
|
@ -138,7 +141,6 @@ export default {
|
|||
'fetchDiscussions',
|
||||
'poll',
|
||||
'toggleAward',
|
||||
'scrollToNoteIfNeeded',
|
||||
'setNotesData',
|
||||
'setNoteableData',
|
||||
'setUserData',
|
||||
|
@ -151,6 +153,13 @@ export default {
|
|||
'convertToDiscussion',
|
||||
'stopPolling',
|
||||
]),
|
||||
handleHashChanged() {
|
||||
const noteId = this.checkLocationHash();
|
||||
|
||||
if (noteId) {
|
||||
this.setTargetNoteHash(getLocationHash());
|
||||
}
|
||||
},
|
||||
fetchNotes() {
|
||||
if (this.isFetching) return null;
|
||||
|
||||
|
@ -194,6 +203,8 @@ export default {
|
|||
this.expandDiscussion({ discussionId: discussion.id });
|
||||
}
|
||||
}
|
||||
|
||||
return noteId;
|
||||
},
|
||||
startReplying(discussionId) {
|
||||
return this.convertToDiscussion(discussionId)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, consistent-return, one-var, no-cond-assign, no-return-assign */
|
||||
/* eslint-disable func-names, consistent-return, no-return-assign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import fuzzaldrinPlus from 'fuzzaldrin-plus';
|
||||
|
@ -9,9 +9,12 @@ import sanitize from 'sanitize-html';
|
|||
|
||||
// highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> )
|
||||
const highlighter = function(element, text, matches) {
|
||||
var j, lastIndex, len, matchIndex, matchedChars, unmatched;
|
||||
lastIndex = 0;
|
||||
matchedChars = [];
|
||||
let j = 0;
|
||||
let len = 0;
|
||||
let lastIndex = 0;
|
||||
let matchedChars = [];
|
||||
let matchIndex = matches[j];
|
||||
let unmatched = text.substring(lastIndex, matchIndex);
|
||||
for (j = 0, len = matches.length; j < len; j += 1) {
|
||||
matchIndex = matches[j];
|
||||
unmatched = text.substring(lastIndex, matchIndex);
|
||||
|
@ -55,10 +58,10 @@ export default class ProjectFindFile {
|
|||
'keyup',
|
||||
(function(_this) {
|
||||
return function(event) {
|
||||
var oldValue, ref, target, value;
|
||||
target = $(event.target);
|
||||
value = target.val();
|
||||
oldValue = (ref = target.data('oldValue')) != null ? ref : '';
|
||||
const target = $(event.target);
|
||||
const value = target.val();
|
||||
const ref = target.data('oldValue');
|
||||
const oldValue = ref != null ? ref : '';
|
||||
if (value !== oldValue) {
|
||||
target.data('oldValue', value);
|
||||
_this.findFile();
|
||||
|
@ -74,9 +77,8 @@ export default class ProjectFindFile {
|
|||
}
|
||||
|
||||
findFile() {
|
||||
var result, searchText;
|
||||
searchText = sanitize(this.inputElement.val());
|
||||
result =
|
||||
const searchText = sanitize(this.inputElement.val());
|
||||
const result =
|
||||
searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
|
||||
return this.renderList(result, searchText);
|
||||
// find file
|
||||
|
@ -101,20 +103,21 @@ export default class ProjectFindFile {
|
|||
|
||||
// render result
|
||||
renderList(filePaths, searchText) {
|
||||
var blobItemUrl, filePath, html, i, len, matches, results;
|
||||
let i = 0;
|
||||
let len = 0;
|
||||
let matches = [];
|
||||
const results = [];
|
||||
this.element.find('.tree-table > tbody').empty();
|
||||
results = [];
|
||||
|
||||
for (i = 0, len = filePaths.length; i < len; i += 1) {
|
||||
filePath = filePaths[i];
|
||||
const filePath = filePaths[i];
|
||||
if (i === 20) {
|
||||
break;
|
||||
}
|
||||
if (searchText) {
|
||||
matches = fuzzaldrinPlus.match(filePath, searchText);
|
||||
}
|
||||
blobItemUrl = `${this.options.blobUrlTemplate}/${encodeURIComponent(filePath)}`;
|
||||
html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
|
||||
const blobItemUrl = `${this.options.blobUrlTemplate}/${encodeURIComponent(filePath)}`;
|
||||
const html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
|
||||
results.push(this.element.find('.tree-table > tbody').append(html));
|
||||
}
|
||||
|
||||
|
@ -125,8 +128,7 @@ export default class ProjectFindFile {
|
|||
|
||||
// make tbody row html
|
||||
static makeHtml(filePath, matches, blobItemUrl) {
|
||||
var $tr;
|
||||
$tr = $(
|
||||
const $tr = $(
|
||||
"<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>",
|
||||
);
|
||||
if (matches) {
|
||||
|
@ -141,9 +143,9 @@ export default class ProjectFindFile {
|
|||
}
|
||||
|
||||
selectRow(type) {
|
||||
var next, rows, selectedRow;
|
||||
rows = this.element.find('.files-slider tr.tree-item');
|
||||
selectedRow = this.element.find('.files-slider tr.tree-item.selected');
|
||||
const rows = this.element.find('.files-slider tr.tree-item');
|
||||
let selectedRow = this.element.find('.files-slider tr.tree-item.selected');
|
||||
let next = selectedRow.prev();
|
||||
if (rows && rows.length > 0) {
|
||||
if (selectedRow && selectedRow.length > 0) {
|
||||
if (type === 'UP') {
|
||||
|
@ -175,7 +177,7 @@ export default class ProjectFindFile {
|
|||
}
|
||||
|
||||
goToBlob() {
|
||||
var $link = this.element.find('.tree-item.selected .tree-item-file-name a');
|
||||
const $link = this.element.find('.tree-item.selected .tree-item-file-name a');
|
||||
|
||||
if ($link.length) {
|
||||
$link.get(0).click();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- flash.each do |key, value|
|
||||
-# Don't show a flash message if the message is nil
|
||||
- if value
|
||||
%div{ class: "flash-#{key}" }
|
||||
%div{ class: "flash-#{key} mb-2" }
|
||||
%span= value
|
||||
%div{ class: "close-icon-wrapper js-close-icon" }
|
||||
= sprite_icon('close', size: 16, css_class: 'close-icon')
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add mb-2 class to global alerts
|
||||
merge_request: 20081
|
||||
author: 2knal
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix expanding collapsed threads when reference link clicked
|
||||
merge_request: 20148
|
||||
author:
|
||||
type: fixed
|
|
@ -366,7 +366,7 @@ to start again from scratch, there are a few steps that can help you:
|
|||
gitlab-ctl tail sidekiq
|
||||
```
|
||||
|
||||
1. Rename repository storage folders and create new ones
|
||||
1. Rename repository storage folders and create new ones. If you are not concerned about possible orphaned directories and files, then you can simply skip this step.
|
||||
|
||||
```sh
|
||||
mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
|
||||
|
@ -413,7 +413,9 @@ to start again from scratch, there are a few steps that can help you:
|
|||
1. Reset the Tracking Database
|
||||
|
||||
```sh
|
||||
gitlab-rake geo:db:reset
|
||||
gitlab-rake geo:db:drop
|
||||
gitlab-ctl reconfigure
|
||||
gitlab-rake geo:db:setup
|
||||
```
|
||||
|
||||
1. Restart previously stopped services
|
||||
|
@ -653,13 +655,6 @@ Geo cannot reuse an existing tracking database.
|
|||
It is safest to use a fresh secondary, or reset the whole secondary by following
|
||||
[Resetting Geo secondary node replication](#resetting-geo-secondary-node-replication).
|
||||
|
||||
If you are not concerned about possible orphaned directories and files, then you
|
||||
can simply reset the existing tracking database with:
|
||||
|
||||
```sh
|
||||
sudo gitlab-rake geo:db:reset
|
||||
```
|
||||
|
||||
### Geo node has a database that is writable which is an indication it is not configured for replication with the primary node
|
||||
|
||||
This error refers to a problem with the database replica on a **secondary** node,
|
||||
|
|
|
@ -539,7 +539,7 @@ type DesignCollection {
|
|||
|
||||
"""
|
||||
Filters designs to only those that existed at the version. If argument is
|
||||
omitted or nil then all designs will reflect the latest version.
|
||||
omitted or nil then all designs will reflect the latest version
|
||||
"""
|
||||
atVersion: ID
|
||||
|
||||
|
@ -548,13 +548,18 @@ type DesignCollection {
|
|||
"""
|
||||
before: String
|
||||
|
||||
"""
|
||||
Filters designs by their filename
|
||||
"""
|
||||
filenames: [String!]
|
||||
|
||||
"""
|
||||
Returns the first _n_ elements from the list.
|
||||
"""
|
||||
first: Int
|
||||
|
||||
"""
|
||||
The list of IDs of designs.
|
||||
Filters designs by their ID
|
||||
"""
|
||||
ids: [ID!]
|
||||
|
||||
|
|
|
@ -7979,7 +7979,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "ids",
|
||||
"description": "The list of IDs of designs.",
|
||||
"description": "Filters designs by their ID",
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
|
@ -7995,9 +7995,27 @@
|
|||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "filenames",
|
||||
"description": "Filters designs by their filename",
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "atVersion",
|
||||
"description": "Filters designs to only those that existed at the version. If argument is omitted or nil then all designs will reflect the latest version.",
|
||||
"description": "Filters designs to only those that existed at the version. If argument is omitted or nil then all designs will reflect the latest version",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 82 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -187,7 +187,7 @@ If JUnit XML files are generated and uploaded as part of a pipeline, these repor
|
|||
can be viewed inside the pipelines details page. The **Tests** tab on this page will
|
||||
display a list of test suites and cases reported from the XML file.
|
||||
|
||||
![Test Reports Widget](img/junit_test_report_ui.png)
|
||||
![Test Reports Widget](img/pipelines_junit_test_report_ui_v12_5.png)
|
||||
|
||||
You can view all the known test suites and click on each of these to see further
|
||||
details, including the cases that makeup the suite. Cases are ordered by status,
|
||||
|
|
|
@ -548,6 +548,32 @@ found, we should raise a
|
|||
`Gitlab::Graphql::Errors::ResourceNotAvailable` error. Which will be
|
||||
correctly rendered to the clients.
|
||||
|
||||
## Gitlab's custom scalars
|
||||
|
||||
### `Types::TimeType`
|
||||
|
||||
[`Types::TimeType`](https://gitlab.com/gitlab-org/gitlab/blob/master/app%2Fgraphql%2Ftypes%2Ftime_type.rb)
|
||||
must be used as the type for all fields and arguments that deal with Ruby
|
||||
`Time` and `DateTime` objects.
|
||||
|
||||
The type is
|
||||
[a custom scalar](https://github.com/rmosolgo/graphql-ruby/blob/master/guides/type_definitions/scalars.md#custom-scalars)
|
||||
that:
|
||||
|
||||
- Converts Ruby's `Time` and `DateTime` objects into standardized
|
||||
ISO-8601 formatted strings, when used as the type for our GraphQL fields.
|
||||
- Converts ISO-8601 formatted time strings into Ruby `Time` objects,
|
||||
when used as the type for our GraphQL arguments.
|
||||
|
||||
This allows our GraphQL API to have a standardized way that it presents time
|
||||
and handles time inputs.
|
||||
|
||||
Example:
|
||||
|
||||
```ruby
|
||||
field :created_at, Types::TimeType, null: false, description: 'Timestamp of when the issue was created'
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
_full stack_ tests for a graphql query or mutation live in
|
||||
|
|
|
@ -5800,6 +5800,9 @@ msgstr ""
|
|||
msgid "DesignManagement|Upload and view the latest designs for this issue. Consistent and easy to find, so everyone is up to date."
|
||||
msgstr ""
|
||||
|
||||
msgid "DesignManagement|We could not delete %{design}. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "DesignManagement|We could not delete design(s). Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
@ -20127,6 +20130,9 @@ msgstr ""
|
|||
msgid "a deleted user"
|
||||
msgstr ""
|
||||
|
||||
msgid "a design"
|
||||
msgstr ""
|
||||
|
||||
msgid "added %{created_at_timeago}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20521,6 +20527,9 @@ msgstr ""
|
|||
msgid "design"
|
||||
msgstr ""
|
||||
|
||||
msgid "designs"
|
||||
msgstr ""
|
||||
|
||||
msgid "detached"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import '~/behaviors/markdown/render_gfm';
|
|||
import { setTestTimeout } from 'helpers/timeout';
|
||||
// TODO: use generated fixture (https://gitlab.com/gitlab-org/gitlab-foss/issues/62491)
|
||||
import * as mockData from '../../notes/mock_data';
|
||||
import * as urlUtility from '~/lib/utils/url_utility';
|
||||
|
||||
setTestTimeout(1000);
|
||||
|
||||
|
@ -54,7 +55,9 @@ describe('note_app', () => {
|
|||
components: {
|
||||
NotesApp,
|
||||
},
|
||||
template: '<div class="js-vue-notes-event"><notes-app v-bind="$attrs" /></div>',
|
||||
template: `<div class="js-vue-notes-event">
|
||||
<notes-app ref="notesApp" v-bind="$attrs" />
|
||||
</div>`,
|
||||
},
|
||||
{
|
||||
attachToDocument: true,
|
||||
|
@ -313,4 +316,23 @@ describe('note_app', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mounted', () => {
|
||||
beforeEach(() => {
|
||||
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
|
||||
wrapper = mountComponent();
|
||||
return waitForDiscussionsRequest();
|
||||
});
|
||||
|
||||
it('should listen hashchange event', () => {
|
||||
const notesApp = wrapper.find(NotesApp);
|
||||
const hash = 'some dummy hash';
|
||||
jest.spyOn(urlUtility, 'getLocationHash').mockReturnValueOnce(hash);
|
||||
const setTargetNoteHash = jest.spyOn(notesApp.vm, 'setTargetNoteHash');
|
||||
|
||||
window.dispatchEvent(new Event('hashchange'), hash);
|
||||
|
||||
expect(setTargetNoteHash).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable no-var, one-var, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, vars-on-top */
|
||||
/* eslint-disable no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
|
@ -6,41 +6,27 @@ import initSearchAutocomplete from '~/search_autocomplete';
|
|||
import '~/lib/utils/common_utils';
|
||||
|
||||
describe('Search autocomplete dropdown', () => {
|
||||
var assertLinks,
|
||||
dashboardIssuesPath,
|
||||
dashboardMRsPath,
|
||||
groupIssuesPath,
|
||||
groupMRsPath,
|
||||
groupName,
|
||||
mockDashboardOptions,
|
||||
mockGroupOptions,
|
||||
mockProjectOptions,
|
||||
projectIssuesPath,
|
||||
projectMRsPath,
|
||||
projectName,
|
||||
userId,
|
||||
widget;
|
||||
var userName = 'root';
|
||||
let widget = null;
|
||||
|
||||
widget = null;
|
||||
const userName = 'root';
|
||||
|
||||
userId = 1;
|
||||
const userId = 1;
|
||||
|
||||
dashboardIssuesPath = '/dashboard/issues';
|
||||
const dashboardIssuesPath = '/dashboard/issues';
|
||||
|
||||
dashboardMRsPath = '/dashboard/merge_requests';
|
||||
const dashboardMRsPath = '/dashboard/merge_requests';
|
||||
|
||||
projectIssuesPath = '/gitlab-org/gitlab-foss/issues';
|
||||
const projectIssuesPath = '/gitlab-org/gitlab-foss/issues';
|
||||
|
||||
projectMRsPath = '/gitlab-org/gitlab-foss/merge_requests';
|
||||
const projectMRsPath = '/gitlab-org/gitlab-foss/merge_requests';
|
||||
|
||||
groupIssuesPath = '/groups/gitlab-org/issues';
|
||||
const groupIssuesPath = '/groups/gitlab-org/issues';
|
||||
|
||||
groupMRsPath = '/groups/gitlab-org/merge_requests';
|
||||
const groupMRsPath = '/groups/gitlab-org/merge_requests';
|
||||
|
||||
projectName = 'GitLab Community Edition';
|
||||
const projectName = 'GitLab Community Edition';
|
||||
|
||||
groupName = 'Gitlab Org';
|
||||
const groupName = 'Gitlab Org';
|
||||
|
||||
const removeBodyAttributes = function() {
|
||||
const $body = $('body');
|
||||
|
@ -76,7 +62,7 @@ describe('Search autocomplete dropdown', () => {
|
|||
};
|
||||
|
||||
// Mock `gl` object in window for dashboard specific page. App code will need it.
|
||||
mockDashboardOptions = function() {
|
||||
const mockDashboardOptions = function() {
|
||||
window.gl || (window.gl = {});
|
||||
return (window.gl.dashboardOptions = {
|
||||
issuesPath: dashboardIssuesPath,
|
||||
|
@ -85,7 +71,7 @@ describe('Search autocomplete dropdown', () => {
|
|||
};
|
||||
|
||||
// Mock `gl` object in window for project specific page. App code will need it.
|
||||
mockProjectOptions = function() {
|
||||
const mockProjectOptions = function() {
|
||||
window.gl || (window.gl = {});
|
||||
return (window.gl.projectOptions = {
|
||||
'gitlab-ce': {
|
||||
|
@ -96,7 +82,7 @@ describe('Search autocomplete dropdown', () => {
|
|||
});
|
||||
};
|
||||
|
||||
mockGroupOptions = function() {
|
||||
const mockGroupOptions = function() {
|
||||
window.gl || (window.gl = {});
|
||||
return (window.gl.groupOptions = {
|
||||
'gitlab-org': {
|
||||
|
@ -107,7 +93,7 @@ describe('Search autocomplete dropdown', () => {
|
|||
});
|
||||
};
|
||||
|
||||
assertLinks = function(list, issuesPath, mrsPath) {
|
||||
const assertLinks = function(list, issuesPath, mrsPath) {
|
||||
if (issuesPath) {
|
||||
const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_username=${userName}"]`;
|
||||
const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_username=${userName}"]`;
|
||||
|
@ -144,29 +130,26 @@ describe('Search autocomplete dropdown', () => {
|
|||
});
|
||||
|
||||
it('should show Dashboard specific dropdown menu', function() {
|
||||
var list;
|
||||
addBodyAttributes();
|
||||
mockDashboardOptions();
|
||||
widget.searchInput.triggerHandler('focus');
|
||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
const list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
return assertLinks(list, dashboardIssuesPath, dashboardMRsPath);
|
||||
});
|
||||
|
||||
it('should show Group specific dropdown menu', function() {
|
||||
var list;
|
||||
addBodyAttributes('group');
|
||||
mockGroupOptions();
|
||||
widget.searchInput.triggerHandler('focus');
|
||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
const list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
return assertLinks(list, groupIssuesPath, groupMRsPath);
|
||||
});
|
||||
|
||||
it('should show Project specific dropdown menu', function() {
|
||||
var list;
|
||||
addBodyAttributes('project');
|
||||
mockProjectOptions();
|
||||
widget.searchInput.triggerHandler('focus');
|
||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
const list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
return assertLinks(list, projectIssuesPath, projectMRsPath);
|
||||
});
|
||||
|
||||
|
@ -180,26 +163,25 @@ describe('Search autocomplete dropdown', () => {
|
|||
});
|
||||
|
||||
it('should not show category related menu if there is text in the input', function() {
|
||||
var link, list;
|
||||
addBodyAttributes('project');
|
||||
mockProjectOptions();
|
||||
widget.searchInput.val('help');
|
||||
widget.searchInput.triggerHandler('focus');
|
||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
link = `a[href='${projectIssuesPath}/?assignee_username=${userName}']`;
|
||||
const list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||
const link = `a[href='${projectIssuesPath}/?assignee_username=${userName}']`;
|
||||
|
||||
expect(list.find(link).length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not submit the search form when selecting an autocomplete row with the keyboard', function() {
|
||||
var ENTER = 13;
|
||||
var DOWN = 40;
|
||||
const ENTER = 13;
|
||||
const DOWN = 40;
|
||||
addBodyAttributes();
|
||||
mockDashboardOptions(true);
|
||||
var submitSpy = spyOnEvent('form', 'submit');
|
||||
const submitSpy = spyOnEvent('form', 'submit');
|
||||
widget.searchInput.triggerHandler('focus');
|
||||
widget.wrap.trigger($.Event('keydown', { which: DOWN }));
|
||||
var enterKeyEvent = $.Event('keydown', { which: ENTER });
|
||||
const enterKeyEvent = $.Event('keydown', { which: ENTER });
|
||||
widget.searchInput.trigger(enterKeyEvent);
|
||||
// This does not currently catch failing behavior. For security reasons,
|
||||
// browsers will not trigger default behavior (form submit, in this
|
||||
|
|
Loading…
Reference in New Issue