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
bde6de46
Commit
bde6de46
authored
Jul 16, 2020
by
Sarah GP
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Replace ci-key field with GlFormCombobox
Removes component and test Replaces in parent and parent test
parent
5347ab93
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
7 additions
and
420 deletions
+7
-420
app/assets/javascripts/ci_variable_list/components/ci_key_field.vue
.../javascripts/ci_variable_list/components/ci_key_field.vue
+0
-169
app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
...scripts/ci_variable_list/components/ci_variable_modal.vue
+4
-3
spec/frontend/ci_variable_list/components/ci_key_field_spec.js
...frontend/ci_variable_list/components/ci_key_field_spec.js
+0
-244
spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
...end/ci_variable_list/components/ci_variable_modal_spec.js
+3
-4
No files found.
app/assets/javascripts/ci_variable_list/components/ci_key_field.vue
deleted
100644 → 0
View file @
5347ab93
<
script
>
import
{
uniqueId
}
from
'
lodash
'
;
import
{
GlButton
,
GlFormGroup
,
GlFormInput
}
from
'
@gitlab/ui
'
;
export
default
{
name
:
'
CiKeyField
'
,
components
:
{
GlButton
,
GlFormGroup
,
GlFormInput
,
},
model
:
{
prop
:
'
value
'
,
event
:
'
input
'
,
},
props
:
{
tokenList
:
{
type
:
Array
,
required
:
true
,
},
value
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
results
:
[],
arrowCounter
:
-
1
,
userDismissedResults
:
false
,
suggestionsId
:
uniqueId
(
'
token-suggestions-
'
),
};
},
computed
:
{
showAutocomplete
()
{
return
this
.
showSuggestions
?
'
off
'
:
'
on
'
;
},
showSuggestions
()
{
return
this
.
results
.
length
>
0
;
},
},
mounted
()
{
document
.
addEventListener
(
'
click
'
,
this
.
handleClickOutside
);
},
destroyed
()
{
document
.
removeEventListener
(
'
click
'
,
this
.
handleClickOutside
);
},
methods
:
{
closeSuggestions
()
{
this
.
results
=
[];
this
.
arrowCounter
=
-
1
;
},
handleClickOutside
(
event
)
{
if
(
!
this
.
$el
.
contains
(
event
.
target
))
{
this
.
closeSuggestions
();
}
},
onArrowDown
()
{
const
newCount
=
this
.
arrowCounter
+
1
;
if
(
newCount
>=
this
.
results
.
length
)
{
this
.
arrowCounter
=
0
;
return
;
}
this
.
arrowCounter
=
newCount
;
},
onArrowUp
()
{
const
newCount
=
this
.
arrowCounter
-
1
;
if
(
newCount
<
0
)
{
this
.
arrowCounter
=
this
.
results
.
length
-
1
;
return
;
}
this
.
arrowCounter
=
newCount
;
},
onEnter
()
{
const
currentToken
=
this
.
results
[
this
.
arrowCounter
]
||
this
.
value
;
this
.
selectToken
(
currentToken
);
},
onEsc
()
{
if
(
!
this
.
showSuggestions
)
{
this
.
$emit
(
'
input
'
,
''
);
}
this
.
closeSuggestions
();
this
.
userDismissedResults
=
true
;
},
onEntry
(
value
)
{
this
.
$emit
(
'
input
'
,
value
);
this
.
userDismissedResults
=
false
;
// short circuit so that we don't false match on empty string
if
(
value
.
length
<
1
)
{
this
.
closeSuggestions
();
return
;
}
const
filteredTokens
=
this
.
tokenList
.
filter
(
token
=>
token
.
toLowerCase
().
includes
(
value
.
toLowerCase
()),
);
if
(
filteredTokens
.
length
)
{
this
.
openSuggestions
(
filteredTokens
);
}
else
{
this
.
closeSuggestions
();
}
},
openSuggestions
(
filteredResults
)
{
this
.
results
=
filteredResults
;
},
selectToken
(
value
)
{
this
.
$emit
(
'
input
'
,
value
);
this
.
closeSuggestions
();
this
.
$emit
(
'
key-selected
'
);
},
},
};
</
script
>
<
template
>
<div>
<div
class=
"dropdown position-relative"
role=
"combobox"
aria-owns=
"token-suggestions"
>
<gl-form-group
:label=
"__('Key')"
label-for=
"ci-variable-key"
>
<gl-form-input
id=
"ci-variable-key"
:value=
"value"
type=
"text"
role=
"searchbox"
class=
"form-control pl-2 js-env-input"
:autocomplete=
"showAutocomplete"
aria-autocomplete=
"list"
aria-controls=
"token-suggestions"
aria-haspopup=
"listbox"
:aria-expanded=
"showSuggestions"
data-qa-selector=
"ci_variable_key_field"
@
input=
"onEntry"
@
keydown.down=
"onArrowDown"
@
keydown.up=
"onArrowUp"
@
keydown.enter.prevent=
"onEnter"
@
keydown.esc.stop=
"onEsc"
@
keydown.tab=
"closeSuggestions"
/>
</gl-form-group>
<div
v-show=
"showSuggestions && !userDismissedResults"
id=
"ci-variable-dropdown"
class=
"dropdown-menu dropdown-menu-selectable dropdown-menu-full-width"
:class=
"
{ 'd-block': showSuggestions }"
>
<div
class=
"dropdown-content"
>
<ul
:id=
"suggestionsId"
>
<li
v-for=
"(result, i) in results"
:key=
"i"
role=
"option"
:class=
"
{ 'gl-bg-gray-50': i === arrowCounter }"
:aria-selected="i === arrowCounter"
>
<gl-button
tabindex=
"-1"
class=
"btn-transparent pl-2"
@
click=
"selectToken(result)"
>
{{
result
}}
</gl-button>
</li>
</ul>
</div>
</div>
</div>
</div>
</
template
>
app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
View file @
bde6de46
...
...
@@ -5,6 +5,7 @@ import {
GlCollapse
,
GlDeprecatedButton
,
GlFormCheckbox
,
GlFormCombobox
,
GlFormGroup
,
GlFormInput
,
GlFormSelect
,
...
...
@@ -26,7 +27,6 @@ import {
AWS_TIP_MESSAGE
,
}
from
'
../constants
'
;
import
{
awsTokens
,
awsTokenList
}
from
'
./ci_variable_autocomplete_tokens
'
;
import
CiKeyField
from
'
./ci_key_field.vue
'
;
import
CiEnvironmentsDropdown
from
'
./ci_environments_dropdown.vue
'
;
export
default
{
...
...
@@ -36,12 +36,12 @@ export default {
awsTipMessage
:
AWS_TIP_MESSAGE
,
components
:
{
CiEnvironmentsDropdown
,
CiKeyField
,
GlAlert
,
GlButton
,
GlCollapse
,
GlDeprecatedButton
,
GlFormCheckbox
,
GlFormCombobox
,
GlFormGroup
,
GlFormInput
,
GlFormSelect
,
...
...
@@ -205,10 +205,11 @@ export default {
@
shown=
"setVariableProtectedByDefault"
>
<form>
<
ci-key-field
<
gl-form-combobox
v-if=
"glFeatures.ciKeyAutocomplete"
v-model=
"key"
:token-list=
"$options.tokenList"
:label-text=
"__('Key')"
/>
<gl-form-group
v-else
:label=
"__('Key')"
label-for=
"ci-variable-key"
>
...
...
spec/frontend/ci_variable_list/components/ci_key_field_spec.js
deleted
100644 → 0
View file @
5347ab93
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
GlButton
,
GlFormInput
}
from
'
@gitlab/ui
'
;
import
{
AWS_ACCESS_KEY_ID
,
AWS_DEFAULT_REGION
}
from
'
~/ci_variable_list/constants
'
;
import
CiKeyField
from
'
~/ci_variable_list/components/ci_key_field.vue
'
;
import
{
awsTokens
,
awsTokenList
,
}
from
'
~/ci_variable_list/components/ci_variable_autocomplete_tokens
'
;
const
doTimes
=
(
num
,
fn
)
=>
{
for
(
let
i
=
0
;
i
<
num
;
i
+=
1
)
{
fn
();
}
};
describe
(
'
Ci Key field
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
()
=>
{
wrapper
=
mount
({
data
()
{
return
{
inputVal
:
''
,
tokens
:
awsTokenList
,
};
},
components
:
{
CiKeyField
},
template
:
`
<div>
<ci-key-field
v-model="inputVal"
:token-list="tokens"
/>
</div>
`
,
});
};
const
findDropdown
=
()
=>
wrapper
.
find
(
'
#ci-variable-dropdown
'
);
const
findDropdownOptions
=
()
=>
wrapper
.
findAll
(
GlButton
).
wrappers
.
map
(
item
=>
item
.
text
());
const
findInput
=
()
=>
wrapper
.
find
(
GlFormInput
);
const
findInputValue
=
()
=>
findInput
().
element
.
value
;
const
setInput
=
val
=>
findInput
().
setValue
(
val
);
const
clickDown
=
()
=>
findInput
().
trigger
(
'
keydown.down
'
);
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
match and filter functionality
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
is closed when the input is empty
'
,
()
=>
{
expect
(
findInput
().
isVisible
()).
toBe
(
true
);
expect
(
findInputValue
()).
toBe
(
''
);
expect
(
findDropdown
().
isVisible
()).
toBe
(
false
);
});
it
(
'
is open when the input text matches a token
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
findDropdown
().
isVisible
()).
toBe
(
true
);
});
});
it
(
'
shows partial matches at string start
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
findDropdown
().
isVisible
()).
toBe
(
true
);
expect
(
findDropdownOptions
()).
toEqual
(
awsTokenList
);
});
});
it
(
'
shows partial matches mid-string
'
,
()
=>
{
setInput
(
'
D
'
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
findDropdown
().
isVisible
()).
toBe
(
true
);
expect
(
findDropdownOptions
()).
toEqual
([
awsTokens
[
AWS_ACCESS_KEY_ID
].
name
,
awsTokens
[
AWS_DEFAULT_REGION
].
name
,
]);
});
});
it
(
'
is closed when the text does not match
'
,
()
=>
{
setInput
(
'
elephant
'
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
findDropdown
().
isVisible
()).
toBe
(
false
);
});
});
});
describe
(
'
keyboard navigation in dropdown
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
describe
(
'
on down arrow + enter
'
,
()
=>
{
it
(
'
selects the next item in the list and closes the dropdown
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
findInput
().
trigger
(
'
keydown.down
'
);
findInput
().
trigger
(
'
keydown.enter
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
awsTokenList
[
0
]);
});
});
it
(
'
loops to the top when it reaches the bottom
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
doTimes
(
findDropdownOptions
().
length
+
1
,
clickDown
);
findInput
().
trigger
(
'
keydown.enter
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
awsTokenList
[
0
]);
});
});
});
describe
(
'
on up arrow + enter
'
,
()
=>
{
it
(
'
selects the previous item in the list and closes the dropdown
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
doTimes
(
3
,
clickDown
);
findInput
().
trigger
(
'
keydown.up
'
);
findInput
().
trigger
(
'
keydown.enter
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
awsTokenList
[
1
]);
});
});
it
(
'
loops to the bottom when it reaches the top
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
findInput
().
trigger
(
'
keydown.down
'
);
findInput
().
trigger
(
'
keydown.up
'
);
findInput
().
trigger
(
'
keydown.enter
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
awsTokenList
[
awsTokenList
.
length
-
1
]);
});
});
});
describe
(
'
on enter with no item highlighted
'
,
()
=>
{
it
(
'
does not select any item and closes the dropdown
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
findInput
().
trigger
(
'
keydown.enter
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
'
AWS
'
);
});
});
});
describe
(
'
on click
'
,
()
=>
{
it
(
'
selects the clicked item regardless of arrow highlight
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
wrapper
.
find
(
GlButton
).
trigger
(
'
click
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
awsTokenList
[
0
]);
});
});
});
describe
(
'
on tab
'
,
()
=>
{
it
(
'
selects entered text, closes dropdown
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
findInput
().
trigger
(
'
keydown.tab
'
);
doTimes
(
2
,
clickDown
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
'
AWS
'
);
expect
(
findDropdown
().
isVisible
()).
toBe
(
false
);
});
});
});
describe
(
'
on esc
'
,
()
=>
{
describe
(
'
when dropdown is open
'
,
()
=>
{
it
(
'
closes dropdown and does not select anything
'
,
()
=>
{
setInput
(
'
AWS
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
findInput
().
trigger
(
'
keydown.esc
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
'
AWS
'
);
expect
(
findDropdown
().
isVisible
()).
toBe
(
false
);
});
});
});
describe
(
'
when dropdown is closed
'
,
()
=>
{
it
(
'
clears the input field
'
,
()
=>
{
setInput
(
'
elephant
'
);
return
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
findDropdown
().
isVisible
()).
toBe
(
false
);
findInput
().
trigger
(
'
keydown.esc
'
);
return
wrapper
.
vm
.
$nextTick
();
})
.
then
(()
=>
{
expect
(
findInputValue
()).
toBe
(
''
);
});
});
});
});
});
});
spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
View file @
bde6de46
import
Vuex
from
'
vuex
'
;
import
{
createLocalVue
,
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
{
GlDeprecatedButton
}
from
'
@gitlab/ui
'
;
import
{
GlDeprecatedButton
,
GlFormCombobox
}
from
'
@gitlab/ui
'
;
import
{
AWS_ACCESS_KEY_ID
}
from
'
~/ci_variable_list/constants
'
;
import
CiVariableModal
from
'
~/ci_variable_list/components/ci_variable_modal.vue
'
;
import
CiKeyField
from
'
~/ci_variable_list/components/ci_key_field.vue
'
;
import
createStore
from
'
~/ci_variable_list/store
'
;
import
mockData
from
'
../services/mock_data
'
;
import
ModalStub
from
'
../stubs
'
;
...
...
@@ -50,7 +49,7 @@ describe('Ci variable modal', () => {
});
it
(
'
does not render the autocomplete dropdown
'
,
()
=>
{
expect
(
wrapper
.
contains
(
CiKeyField
)).
toBe
(
false
);
expect
(
wrapper
.
contains
(
GlFormCombobox
)).
toBe
(
false
);
});
});
...
...
@@ -59,7 +58,7 @@ describe('Ci variable modal', () => {
createComponent
(
shallowMount
);
});
it
(
'
renders the autocomplete dropdown
'
,
()
=>
{
expect
(
wrapper
.
find
(
CiKeyField
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
find
(
GlFormCombobox
).
exists
()).
toBe
(
true
);
});
});
});
...
...
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