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
0
Merge Requests
0
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
Jérome Perrin
gitlab-ce
Commits
88c9199a
Commit
88c9199a
authored
Feb 03, 2018
by
Matija Čupić
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into persistent-callouts
parents
20714ee9
a3166376
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
664 additions
and
350 deletions
+664
-350
app/assets/javascripts/behaviors/secret_values.js
app/assets/javascripts/behaviors/secret_values.js
+5
-3
app/assets/javascripts/ci_variable_list/ci_variable_list.js
app/assets/javascripts/ci_variable_list/ci_variable_list.js
+205
-0
app/assets/javascripts/ci_variable_list/native_form_variable_list.js
...javascripts/ci_variable_list/native_form_variable_list.js
+26
-0
app/assets/javascripts/commons/polyfills.js
app/assets/javascripts/commons/polyfills.js
+2
-0
app/assets/javascripts/pipeline_schedules/pipeline_schedule_form_bundle.js
...ripts/pipeline_schedules/pipeline_schedule_form_bundle.js
+5
-2
app/assets/javascripts/pipeline_schedules/setup_pipeline_variable_list.js
...cripts/pipeline_schedules/setup_pipeline_variable_list.js
+0
-73
app/assets/javascripts/toggle_buttons.js
app/assets/javascripts/toggle_buttons.js
+4
-4
app/assets/stylesheets/framework.scss
app/assets/stylesheets/framework.scss
+1
-0
app/assets/stylesheets/framework/buttons.scss
app/assets/stylesheets/framework/buttons.scss
+5
-0
app/assets/stylesheets/framework/ci_variable_list.scss
app/assets/stylesheets/framework/ci_variable_list.scss
+88
-0
app/assets/stylesheets/framework/variables.scss
app/assets/stylesheets/framework/variables.scss
+2
-2
app/assets/stylesheets/pages/pipeline_schedules.scss
app/assets/stylesheets/pages/pipeline_schedules.scss
+0
-81
app/views/ci/variables/_variable_row.html.haml
app/views/ci/variables/_variable_row.html.haml
+49
-0
app/views/projects/pipeline_schedules/_form.html.haml
app/views/projects/pipeline_schedules/_form.html.haml
+11
-5
app/views/projects/pipeline_schedules/_variable_row.html.haml
...views/projects/pipeline_schedules/_variable_row.html.haml
+0
-17
changelogs/unreleased/refactor-ci-variable-list-for-future-usage-in-4110.yml
...ed/refactor-ci-variable-list-for-future-usage-in-4110.yml
+5
-0
lib/banzai/color_parser.rb
lib/banzai/color_parser.rb
+4
-4
spec/features/projects/pipeline_schedules_spec.rb
spec/features/projects/pipeline_schedules_spec.rb
+16
-14
spec/javascripts/ci_variable_list/ci_variable_list_spec.js
spec/javascripts/ci_variable_list/ci_variable_list_spec.js
+163
-0
spec/javascripts/ci_variable_list/native_form_variable_list_spec.js
...cripts/ci_variable_list/native_form_variable_list_spec.js
+30
-0
spec/javascripts/fixtures/pipeline_schedules.rb
spec/javascripts/fixtures/pipeline_schedules.rb
+43
-0
spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
...s/pipeline_schedules/setup_pipeline_variable_list_spec.js
+0
-145
No files found.
app/assets/javascripts/behaviors/secret_values.js
View file @
88c9199a
...
...
@@ -15,10 +15,12 @@ export default class SecretValues {
init
()
{
this
.
revealButton
=
this
.
container
.
querySelector
(
'
.js-secret-value-reveal-button
'
);
const
isRevealed
=
convertPermissionToBoolean
(
this
.
revealButton
.
dataset
.
secretRevealStatus
);
this
.
updateDom
(
isRevealed
);
if
(
this
.
revealButton
)
{
const
isRevealed
=
convertPermissionToBoolean
(
this
.
revealButton
.
dataset
.
secretRevealStatus
);
this
.
updateDom
(
isRevealed
);
this
.
revealButton
.
addEventListener
(
'
click
'
,
this
.
onRevealButtonClicked
.
bind
(
this
));
this
.
revealButton
.
addEventListener
(
'
click
'
,
this
.
onRevealButtonClicked
.
bind
(
this
));
}
}
onRevealButtonClicked
()
{
...
...
app/assets/javascripts/ci_variable_list/ci_variable_list.js
0 → 100644
View file @
88c9199a
import
$
from
'
jquery
'
;
import
{
convertPermissionToBoolean
}
from
'
../lib/utils/common_utils
'
;
import
{
s__
}
from
'
../locale
'
;
import
setupToggleButtons
from
'
../toggle_buttons
'
;
import
CreateItemDropdown
from
'
../create_item_dropdown
'
;
import
SecretValues
from
'
../behaviors/secret_values
'
;
const
ALL_ENVIRONMENTS_STRING
=
s__
(
'
CiVariable|All environments
'
);
function
createEnvironmentItem
(
value
)
{
return
{
title
:
value
===
'
*
'
?
ALL_ENVIRONMENTS_STRING
:
value
,
id
:
value
,
text
:
value
,
};
}
export
default
class
VariableList
{
constructor
({
container
,
formField
,
})
{
this
.
$container
=
$
(
container
);
this
.
formField
=
formField
;
this
.
environmentDropdownMap
=
new
WeakMap
();
this
.
inputMap
=
{
id
:
{
selector
:
'
.js-ci-variable-input-id
'
,
default
:
''
,
},
key
:
{
selector
:
'
.js-ci-variable-input-key
'
,
default
:
''
,
},
value
:
{
selector
:
'
.js-ci-variable-input-value
'
,
default
:
''
,
},
protected
:
{
selector
:
'
.js-ci-variable-input-protected
'
,
default
:
'
true
'
,
},
environment
:
{
// We can't use a `.js-` class here because
// gl_dropdown replaces the <input> and doesn't copy over the class
// See https://gitlab.com/gitlab-org/gitlab-ce/issues/42458
selector
:
`input[name="
${
this
.
formField
}
[variables_attributes][][environment]"]`
,
default
:
'
*
'
,
},
_destroy
:
{
selector
:
'
.js-ci-variable-input-destroy
'
,
default
:
''
,
},
};
this
.
secretValues
=
new
SecretValues
({
container
:
this
.
$container
[
0
],
valueSelector
:
'
.js-row:not(:last-child) .js-secret-value
'
,
placeholderSelector
:
'
.js-row:not(:last-child) .js-secret-value-placeholder
'
,
});
}
init
()
{
this
.
bindEvents
();
this
.
secretValues
.
init
();
}
bindEvents
()
{
this
.
$container
.
find
(
'
.js-row
'
).
each
((
index
,
rowEl
)
=>
{
this
.
initRow
(
rowEl
);
});
this
.
$container
.
on
(
'
click
'
,
'
.js-row-remove-button
'
,
(
e
)
=>
{
e
.
preventDefault
();
this
.
removeRow
(
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
));
});
const
inputSelector
=
Object
.
keys
(
this
.
inputMap
)
.
map
(
name
=>
this
.
inputMap
[
name
].
selector
)
.
join
(
'
,
'
);
// Remove any empty rows except the last row
this
.
$container
.
on
(
'
blur
'
,
inputSelector
,
(
e
)
=>
{
const
$row
=
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
);
if
(
$row
.
is
(
'
:not(:last-child)
'
)
&&
!
this
.
checkIfRowTouched
(
$row
))
{
this
.
removeRow
(
$row
);
}
});
// Always make sure there is an empty last row
this
.
$container
.
on
(
'
input trigger-change
'
,
inputSelector
,
()
=>
{
const
$lastRow
=
this
.
$container
.
find
(
'
.js-row
'
).
last
();
if
(
this
.
checkIfRowTouched
(
$lastRow
))
{
this
.
insertRow
(
$lastRow
);
}
});
}
initRow
(
rowEl
)
{
const
$row
=
$
(
rowEl
);
setupToggleButtons
(
$row
[
0
]);
const
$environmentSelect
=
$row
.
find
(
'
.js-variable-environment-toggle
'
);
if
(
$environmentSelect
.
length
)
{
const
createItemDropdown
=
new
CreateItemDropdown
({
$dropdown
:
$environmentSelect
,
defaultToggleLabel
:
ALL_ENVIRONMENTS_STRING
,
fieldName
:
`
${
this
.
formField
}
[variables_attributes][][environment]`
,
getData
:
(
term
,
callback
)
=>
callback
(
this
.
getEnvironmentValues
()),
createNewItemFromValue
:
createEnvironmentItem
,
onSelect
:
()
=>
{
// Refresh the other dropdowns in the variable list
// so they have the new value we just picked
this
.
refreshDropdownData
();
$row
.
find
(
this
.
inputMap
.
environment
.
selector
).
trigger
(
'
trigger-change
'
);
},
});
// Clear out any data that might have been left-over from the row clone
createItemDropdown
.
clearDropdown
();
this
.
environmentDropdownMap
.
set
(
$row
[
0
],
createItemDropdown
);
}
}
insertRow
(
$row
)
{
const
$rowClone
=
$row
.
clone
();
$rowClone
.
removeAttr
(
'
data-is-persisted
'
);
// Reset the inputs to their defaults
Object
.
keys
(
this
.
inputMap
).
forEach
((
name
)
=>
{
const
entry
=
this
.
inputMap
[
name
];
$rowClone
.
find
(
entry
.
selector
).
val
(
entry
.
default
);
});
this
.
initRow
(
$rowClone
);
$row
.
after
(
$rowClone
);
}
removeRow
(
$row
)
{
const
isPersisted
=
convertPermissionToBoolean
(
$row
.
attr
(
'
data-is-persisted
'
));
if
(
isPersisted
)
{
$row
.
hide
();
$row
// eslint-disable-next-line no-underscore-dangle
.
find
(
this
.
inputMap
.
_destroy
.
selector
)
.
val
(
true
);
}
else
{
$row
.
remove
();
}
}
checkIfRowTouched
(
$row
)
{
return
Object
.
keys
(
this
.
inputMap
).
some
((
name
)
=>
{
const
entry
=
this
.
inputMap
[
name
];
const
$el
=
$row
.
find
(
entry
.
selector
);
return
$el
.
length
&&
$el
.
val
()
!==
entry
.
default
;
});
}
getAllData
()
{
// Ignore the last empty row because we don't want to try persist
// a blank variable and run into validation problems.
const
validRows
=
this
.
$container
.
find
(
'
.js-row
'
).
toArray
().
slice
(
0
,
-
1
);
return
validRows
.
map
((
rowEl
)
=>
{
const
resultant
=
{};
Object
.
keys
(
this
.
inputMap
).
forEach
((
name
)
=>
{
const
entry
=
this
.
inputMap
[
name
];
const
$input
=
$
(
rowEl
).
find
(
entry
.
selector
);
if
(
$input
.
length
)
{
resultant
[
name
]
=
$input
.
val
();
}
});
return
resultant
;
});
}
getEnvironmentValues
()
{
const
valueMap
=
this
.
$container
.
find
(
this
.
inputMap
.
environment
.
selector
).
toArray
()
.
reduce
((
prevValueMap
,
envInput
)
=>
({
...
prevValueMap
,
[
envInput
.
value
]:
envInput
.
value
,
}),
{});
return
Object
.
keys
(
valueMap
).
map
(
createEnvironmentItem
);
}
refreshDropdownData
()
{
this
.
$container
.
find
(
'
.js-row
'
).
each
((
index
,
rowEl
)
=>
{
const
environmentDropdown
=
this
.
environmentDropdownMap
.
get
(
rowEl
);
if
(
environmentDropdown
)
{
environmentDropdown
.
refreshData
();
}
});
}
}
app/assets/javascripts/ci_variable_list/native_form_variable_list.js
0 → 100644
View file @
88c9199a
import
VariableList
from
'
./ci_variable_list
'
;
// Used for the variable list on scheduled pipeline edit page
export
default
function
setupNativeFormVariableList
({
container
,
formField
=
'
variables
'
,
})
{
const
$container
=
$
(
container
);
const
variableList
=
new
VariableList
({
container
:
$container
,
formField
,
});
variableList
.
init
();
// Clear out the names in the empty last row so it
// doesn't get submitted and throw validation errors
$container
.
closest
(
'
form
'
).
on
(
'
submit trigger-submit
'
,
()
=>
{
const
$lastRow
=
$container
.
find
(
'
.js-row
'
).
last
();
const
isTouched
=
variableList
.
checkIfRowTouched
(
$lastRow
);
if
(
!
isTouched
)
{
$lastRow
.
find
(
'
input, textarea
'
).
attr
(
'
name
'
,
''
);
}
});
}
app/assets/javascripts/commons/polyfills.js
View file @
88c9199a
...
...
@@ -8,6 +8,8 @@ import 'core-js/fn/promise';
import
'
core-js/fn/string/code-point-at
'
;
import
'
core-js/fn/string/from-code-point
'
;
import
'
core-js/fn/symbol
'
;
import
'
core-js/es6/map
'
;
import
'
core-js/es6/weak-map
'
;
// Browser polyfills
import
'
classlist-polyfill
'
;
...
...
app/assets/javascripts/pipeline_schedules/pipeline_schedule_form_bundle.js
View file @
88c9199a
...
...
@@ -4,7 +4,7 @@ import GlFieldErrors from '../gl_field_errors';
import
intervalPatternInput
from
'
./components/interval_pattern_input.vue
'
;
import
TimezoneDropdown
from
'
./components/timezone_dropdown
'
;
import
TargetBranchDropdown
from
'
./components/target_branch_dropdown
'
;
import
{
setupPipelineVariableList
}
from
'
./setup_pipeline
_variable_list
'
;
import
setupNativeFormVariableList
from
'
../ci_variable_list/native_form
_variable_list
'
;
Vue
.
use
(
Translate
);
...
...
@@ -42,5 +42,8 @@ document.addEventListener('DOMContentLoaded', () => {
gl
.
targetBranchDropdown
=
new
TargetBranchDropdown
();
gl
.
pipelineScheduleFieldErrors
=
new
GlFieldErrors
(
formElement
);
setupPipelineVariableList
(
$
(
'
.js-pipeline-variable-list
'
));
setupNativeFormVariableList
({
container
:
$
(
'
.js-ci-variable-list-section
'
),
formField
:
'
schedule
'
,
});
});
app/assets/javascripts/pipeline_schedules/setup_pipeline_variable_list.js
deleted
100644 → 0
View file @
20714ee9
import
{
convertPermissionToBoolean
}
from
'
../lib/utils/common_utils
'
;
function
insertRow
(
$row
)
{
const
$rowClone
=
$row
.
clone
();
$rowClone
.
removeAttr
(
'
data-is-persisted
'
);
$rowClone
.
find
(
'
input, textarea
'
).
val
(
''
);
$row
.
after
(
$rowClone
);
}
function
removeRow
(
$row
)
{
const
isPersisted
=
convertPermissionToBoolean
(
$row
.
attr
(
'
data-is-persisted
'
));
if
(
isPersisted
)
{
$row
.
hide
();
$row
.
find
(
'
.js-destroy-input
'
)
.
val
(
1
);
}
else
{
$row
.
remove
();
}
}
function
checkIfRowTouched
(
$row
)
{
return
$row
.
find
(
'
.js-user-input
'
).
toArray
().
some
(
el
=>
$
(
el
).
val
().
length
>
0
);
}
function
setupPipelineVariableList
(
parent
=
document
)
{
const
$parent
=
$
(
parent
);
$parent
.
on
(
'
click
'
,
'
.js-row-remove-button
'
,
(
e
)
=>
{
const
$row
=
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
);
removeRow
(
$row
);
e
.
preventDefault
();
});
// Remove any empty rows except the last r
$parent
.
on
(
'
blur
'
,
'
.js-user-input
'
,
(
e
)
=>
{
const
$row
=
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
);
const
isTouched
=
checkIfRowTouched
(
$row
);
if
(
$row
.
is
(
'
:not(:last-child)
'
)
&&
!
isTouched
)
{
removeRow
(
$row
);
}
});
// Always make sure there is an empty last row
$parent
.
on
(
'
input
'
,
'
.js-user-input
'
,
()
=>
{
const
$lastRow
=
$parent
.
find
(
'
.js-row
'
).
last
();
const
isTouched
=
checkIfRowTouched
(
$lastRow
);
if
(
isTouched
)
{
insertRow
(
$lastRow
);
}
});
// Clear out the empty last row so it
// doesn't get submitted and throw validation errors
$parent
.
closest
(
'
form
'
).
on
(
'
submit
'
,
()
=>
{
const
$lastRow
=
$parent
.
find
(
'
.js-row
'
).
last
();
const
isTouched
=
checkIfRowTouched
(
$lastRow
);
if
(
!
isTouched
)
{
$lastRow
.
find
(
'
input, textarea
'
).
attr
(
'
name
'
,
''
);
}
});
}
export
{
setupPipelineVariableList
,
insertRow
,
removeRow
,
};
app/assets/javascripts/toggle_buttons.js
View file @
88c9199a
...
...
@@ -13,7 +13,7 @@ import { convertPermissionToBoolean } from './lib/utils/common_utils';
```
*/
function
update
t
oggle
(
toggle
,
isOn
)
{
function
update
T
oggle
(
toggle
,
isOn
)
{
toggle
.
classList
.
toggle
(
'
is-checked
'
,
isOn
);
}
...
...
@@ -21,7 +21,7 @@ function onToggleClicked(toggle, input, clickCallback) {
const
previousIsOn
=
convertPermissionToBoolean
(
input
.
value
);
// Visually change the toggle and start loading
update
t
oggle
(
toggle
,
!
previousIsOn
);
update
T
oggle
(
toggle
,
!
previousIsOn
);
toggle
.
setAttribute
(
'
disabled
'
,
true
);
toggle
.
classList
.
toggle
(
'
is-loading
'
,
true
);
...
...
@@ -32,7 +32,7 @@ function onToggleClicked(toggle, input, clickCallback) {
})
.
catch
(()
=>
{
// Revert the visuals if something goes wrong
update
t
oggle
(
toggle
,
previousIsOn
);
update
T
oggle
(
toggle
,
previousIsOn
);
})
.
then
(()
=>
{
// Remove the loading indicator in any case
...
...
@@ -54,7 +54,7 @@ export default function setupToggleButtons(container, clickCallback = () => {})
const
isOn
=
convertPermissionToBoolean
(
input
.
value
);
// Get the visible toggle in sync with the hidden input
update
t
oggle
(
toggle
,
isOn
);
update
T
oggle
(
toggle
,
isOn
);
toggle
.
addEventListener
(
'
click
'
,
onToggleClicked
.
bind
(
null
,
toggle
,
input
,
clickCallback
));
});
...
...
app/assets/stylesheets/framework.scss
View file @
88c9199a
...
...
@@ -60,3 +60,4 @@
@import
"framework/memory_graph"
;
@import
"framework/responsive_tables"
;
@import
"framework/stacked-progress-bar"
;
@import
"framework/ci_variable_list"
;
app/assets/stylesheets/framework/buttons.scss
View file @
88c9199a
...
...
@@ -176,6 +176,11 @@
&
.btn-remove
{
@include
btn-outline
(
$white-light
,
$red-500
,
$red-500
,
$red-500
,
$white-light
,
$red-600
,
$red-600
,
$red-700
);
}
&
.btn-primary
,
&
.btn-info
{
@include
btn-outline
(
$white-light
,
$blue-500
,
$blue-500
,
$blue-500
,
$white-light
,
$blue-600
,
$blue-600
,
$blue-700
);
}
}
&
.btn-gray
{
...
...
app/assets/stylesheets/framework/ci_variable_list.scss
0 → 100644
View file @
88c9199a
.ci-variable-list
{
margin-left
:
0
;
margin-bottom
:
0
;
padding-left
:
0
;
list-style
:
none
;
clear
:
both
;
}
.ci-variable-row
{
display
:
flex
;
align-items
:
flex-end
;
&
:not
(
:last-child
)
{
margin-bottom
:
$gl-btn-padding
;
@media
(
max-width
:
$screen-xs-max
)
{
margin-bottom
:
3
*
$gl-btn-padding
;
}
}
&
:last-child
{
.ci-variable-body-item
:last-child
{
margin-right
:
$ci-variable-remove-button-width
;
@media
(
max-width
:
$screen-xs-max
)
{
margin-right
:
0
;
}
}
.ci-variable-row-remove-button
{
display
:
none
;
}
@media
(
max-width
:
$screen-xs-max
)
{
.ci-variable-row-body
{
margin-right
:
$ci-variable-remove-button-width
;
}
}
}
}
.ci-variable-row-body
{
display
:
flex
;
width
:
100%
;
@media
(
max-width
:
$screen-xs-max
)
{
display
:
block
;
}
}
.ci-variable-body-item
{
flex
:
1
;
&
:not
(
:last-child
)
{
margin-right
:
$gl-btn-padding
;
@media
(
max-width
:
$screen-xs-max
)
{
margin-right
:
0
;
margin-bottom
:
$gl-btn-padding
;
}
}
}
.ci-variable-protected-item
{
flex
:
0
1
auto
;
display
:
flex
;
align-items
:
center
;
}
.ci-variable-row-remove-button
{
@include
transition
(
color
);
flex-shrink
:
0
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
width
:
$ci-variable-remove-button-width
;
height
:
$input-height
;
padding
:
0
;
background
:
transparent
;
border
:
0
;
color
:
$gl-text-color-secondary
;
&
:hover
,
&
:focus
{
outline
:
none
;
color
:
$gl-text-color
;
}
}
app/assets/stylesheets/framework/variables.scss
View file @
88c9199a
...
...
@@ -668,9 +668,9 @@ $pipeline-dropdown-line-height: 20px;
$pipeline-dropdown-status-icon-size
:
18px
;
/*
Pipeline Schedule
s
CI variable list
s
*/
$
pipeline
-variable-remove-button-width
:
calc
(
1em
+
#{
2
*
$gl-padding
}
);
$
ci
-variable-remove-button-width
:
calc
(
1em
+
#{
2
*
$gl-padding
}
);
/*
...
...
app/assets/stylesheets/pages/pipeline_schedules.scss
View file @
88c9199a
...
...
@@ -78,84 +78,3 @@
margin-right
:
3px
;
}
}
.pipeline-variable-list
{
margin-left
:
0
;
margin-bottom
:
0
;
padding-left
:
0
;
list-style
:
none
;
clear
:
both
;
}
.pipeline-variable-row
{
display
:
flex
;
align-items
:
flex-end
;
&
:not
(
:last-child
)
{
margin-bottom
:
$gl-btn-padding
;
}
@media
(
max-width
:
$screen-sm-max
)
{
padding-right
:
$gl-col-padding
;
}
&
:last-child
{
.pipeline-variable-row-remove-button
{
display
:
none
;
}
@media
(
max-width
:
$screen-sm-max
)
{
.pipeline-variable-value-input
{
margin-right
:
$pipeline-variable-remove-button-width
;
}
}
@media
(
max-width
:
$screen-xs-max
)
{
.pipeline-variable-row-body
{
margin-right
:
$pipeline-variable-remove-button-width
;
}
}
}
}
.pipeline-variable-row-body
{
display
:
flex
;
width
:
calc
(
75%
-
#{
$gl-col-padding
}
);
padding-left
:
$gl-col-padding
;
@media
(
max-width
:
$screen-sm-max
)
{
width
:
100%
;
}
@media
(
max-width
:
$screen-xs-max
)
{
display
:
block
;
}
}
.pipeline-variable-key-input
{
margin-right
:
$gl-btn-padding
;
@media
(
max-width
:
$screen-xs-max
)
{
margin-bottom
:
$gl-btn-padding
;
}
}
.pipeline-variable-row-remove-button
{
@include
transition
(
color
);
flex-shrink
:
0
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
width
:
$pipeline-variable-remove-button-width
;
height
:
$input-height
;
padding
:
0
;
background
:
transparent
;
border
:
0
;
color
:
$gl-text-color-secondary
;
&
:hover
,
&
:focus
{
outline
:
none
;
color
:
$gl-text-color
;
}
}
app/views/ci/variables/_variable_row.html.haml
0 → 100644
View file @
88c9199a
-
form_field
=
local_assigns
.
fetch
(
:form_field
,
nil
)
-
variable
=
local_assigns
.
fetch
(
:variable
,
nil
)
-
only_key_value
=
local_assigns
.
fetch
(
:only_key_value
,
false
)
-
id
=
variable
&
.
id
-
key
=
variable
&
.
key
-
value
=
variable
&
.
value
-
is_protected
=
variable
&&
!
only_key_value
?
variable
.
protected
:
true
-
id_input_name
=
"
#{
form_field
}
[variables_attributes][][id]"
-
destroy_input_name
=
"
#{
form_field
}
[variables_attributes][][_destroy]"
-
key_input_name
=
"
#{
form_field
}
[variables_attributes][][key]"
-
value_input_name
=
"
#{
form_field
}
[variables_attributes][][value]"
-
protected_input_name
=
"
#{
form_field
}
[variables_attributes][][protected]"
%li
.js-row.ci-variable-row
{
data:
{
is_persisted:
"#{!id.nil?}"
}
}
.ci-variable-row-body
%input
.js-ci-variable-input-id
{
type:
"hidden"
,
name:
id_input_name
,
value:
id
}
%input
.js-ci-variable-input-destroy
{
type:
"hidden"
,
name:
destroy_input_name
}
%input
.js-ci-variable-input-key.ci-variable-body-item.form-control
{
type:
"text"
,
name:
key_input_name
,
value:
key
,
placeholder:
s_
(
'CiVariables|Input variable key'
)
}
.ci-variable-body-item
.form-control.js-secret-value-placeholder
{
class:
(
'hide'
unless
id
)
}
=
'*'
*
20
%textarea
.js-ci-variable-input-value.js-secret-value.form-control
{
class:
(
'hide'
if
id
),
rows:
1
,
name:
value_input_name
,
placeholder:
s_
(
'CiVariables|Input variable value'
)
}
=
value
-
unless
only_key_value
.ci-variable-body-item.ci-variable-protected-item
.append-right-default
=
s_
(
"CiVariable|Protected"
)
%button
{
type:
'button'
,
class:
"js-project-feature-toggle project-feature-toggle #{'is-checked' if is_protected}"
,
"aria-label"
:
s_
(
"CiVariable|Toggle protected"
)
}
%input
{
type:
"hidden"
,
class:
'js-ci-variable-input-protected js-project-feature-toggle-input'
,
name:
protected_input_name
,
value:
is_protected
}
%span
.toggle-icon
=
sprite_icon
(
'status_success_borderless'
,
size:
16
,
css_class:
'toggle-icon-svg toggle-status-checked'
)
=
sprite_icon
(
'status_failed_borderless'
,
size:
16
,
css_class:
'toggle-icon-svg toggle-status-unchecked'
)
-# EE-specific start
-# EE-specific end
%button
.js-row-remove-button.ci-variable-row-remove-button
{
type:
'button'
,
'aria-label'
:
s_
(
'CiVariables|Remove variable row'
)
}
=
icon
(
'minus-circle'
)
app/views/projects/pipeline_schedules/_form.html.haml
View file @
88c9199a
...
...
@@ -22,14 +22,20 @@
=
f
.
label
:ref
,
_
(
'Target Branch'
),
class:
'label-light'
=
dropdown_tag
(
_
(
"Select target branch"
),
options:
{
toggle_class:
'btn js-target-branch-dropdown'
,
dropdown_class:
'git-revision-dropdown'
,
title:
_
(
"Select target branch"
),
filter:
true
,
placeholder:
s_
(
"OfSearchInADropdown|Filter"
),
data:
{
data:
@project
.
repository
.
branch_names
,
default_branch:
@project
.
default_branch
}
}
)
=
f
.
text_field
:ref
,
value:
@schedule
.
ref
,
id:
'schedule_ref'
,
class:
'hidden'
,
name:
'schedule[ref]'
,
required:
true
.form-group
.form-group
.js-ci-variable-list-section
.col-md-9
%label
.label-light
#{
s_
(
'PipelineSchedules|Variables'
)
}
%ul
.js-pipeline-variable-list.pipeline-variable-list
-
@schedule
.
variables
.
each
do
|
variable
|
=
render
'variable_row'
,
id:
variable
.
id
,
key:
variable
.
key
,
value:
variable
.
value
=
render
'variable_row'
%ul
.ci-variable-list
-
@schedule
.
variables
.
each
do
|
variable
|
=
render
'ci/variables/variable_row'
,
form_field:
'schedule'
,
variable:
variable
,
only_key_value:
true
=
render
'ci/variables/variable_row'
,
form_field:
'schedule'
,
only_key_value:
true
-
if
@schedule
.
variables
.
size
>
0
%button
.btn.btn-info.btn-inverted.prepend-top-10.js-secret-value-reveal-button
{
type:
'button'
,
data:
{
secret_reveal_status:
"#{@schedule.variables.size == 0}"
}
}
-
if
@schedule
.
variables
.
size
==
0
=
n_
(
'Hide value'
,
'Hide values'
,
@schedule
.
variables
.
size
)
-
else
=
n_
(
'Reveal value'
,
'Reveal values'
,
@schedule
.
variables
.
size
)
.form-group
.col-md-9
=
f
.
label
:active
,
s_
(
'PipelineSchedules|Activated'
),
class:
'label-light'
...
...
app/views/projects/pipeline_schedules/_variable_row.html.haml
deleted
100644 → 0
View file @
20714ee9
-
id
=
local_assigns
.
fetch
(
:id
,
nil
)
-
key
=
local_assigns
.
fetch
(
:key
,
""
)
-
value
=
local_assigns
.
fetch
(
:value
,
""
)
%li
.js-row.pipeline-variable-row
{
data:
{
is_persisted:
"#{!id.nil?}"
}
}
.pipeline-variable-row-body
%input
{
type:
"hidden"
,
name:
"schedule[variables_attributes][][id]"
,
value:
id
}
%input
.js-destroy-input
{
type:
"hidden"
,
name:
"schedule[variables_attributes][][_destroy]"
}
%input
.js-user-input.pipeline-variable-key-input.form-control
{
type:
"text"
,
name:
"schedule[variables_attributes][][key]"
,
value:
key
,
placeholder:
s_
(
'PipelineSchedules|Input variable key'
)
}
%textarea
.js-user-input.pipeline-variable-value-input.form-control
{
rows:
1
,
name:
"schedule[variables_attributes][][value]"
,
placeholder:
s_
(
'PipelineSchedules|Input variable value'
)
}
=
value
%button
.js-row-remove-button.pipeline-variable-row-remove-button
{
'aria-label'
:
s_
(
'PipelineSchedules|Remove variable row'
)
}
%i
.fa.fa-minus-circle
{
'aria-hidden'
:
"true"
}
changelogs/unreleased/refactor-ci-variable-list-for-future-usage-in-4110.yml
0 → 100644
View file @
88c9199a
---
title
:
Hide variable values on pipeline schedule edit page
merge_request
:
16729
author
:
type
:
changed
lib/banzai/color_parser.rb
View file @
88c9199a
...
...
@@ -7,7 +7,7 @@ module Banzai
DEGS
=
/-?\d+(?:deg)?/i
# [-]digits[deg]
RADS
=
/-?(?:\d+(?:\.\d+)?|\.\d+)rad/i
# [-](digits[.digits] OR .digits)rad
HEX_FORMAT
=
/\#(?:\h{3}|\h{4}|\h{6}|\h{8})/
RGB_FORMAT
=
/
RGB_FORMAT
=
%r{
(?:rgba?
\(
(?:
...
...
@@ -18,15 +18,15 @@ module Banzai
#{
ALPHA_CHANNEL
}
\)
)
/
xi
HSL_FORMAT
=
/
}
xi
HSL_FORMAT
=
%r{
(?:hsla?
\(
(?:
#{
DEGS
}
|
#{
RADS
}
),
\s
*
#{
PERCENTS
}
,
\s
*
#{
PERCENTS
}
#{
ALPHA_CHANNEL
}
\)
)
/
xi
}
xi
FORMATS
=
[
HEX_FORMAT
,
RGB_FORMAT
,
HSL_FORMAT
].
freeze
...
...
spec/features/projects/pipeline_schedules_spec.rb
View file @
88c9199a
...
...
@@ -168,11 +168,11 @@ feature 'Pipeline Schedules', :js do
scenario
'user sees the new variable in edit window'
do
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
page
.
within
(
'.
pipeline
-variable-list'
)
do
expect
(
find
(
".
pipeline-variable-row:nth-child(1) .pipeline-variable-key-input
"
).
value
).
to
eq
(
'AAA'
)
expect
(
find
(
".
pipeline-variable-row:nth-child(1) .pipeline-variable-value-input"
).
value
).
to
eq
(
'AAA123'
)
expect
(
find
(
".
pipeline-variable-row:nth-child(2) .pipeline-variable-key-input
"
).
value
).
to
eq
(
'BBB'
)
expect
(
find
(
".
pipeline-variable-row:nth-child(2) .pipeline-variable-value-input"
).
value
).
to
eq
(
'BBB123'
)
page
.
within
(
'.
ci
-variable-list'
)
do
expect
(
find
(
".
ci-variable-row:nth-child(1) .js-ci-variable-input-key
"
).
value
).
to
eq
(
'AAA'
)
expect
(
find
(
".
ci-variable-row:nth-child(1) .js-ci-variable-input-value"
,
visible:
false
).
value
).
to
eq
(
'AAA123'
)
expect
(
find
(
".
ci-variable-row:nth-child(2) .js-ci-variable-input-key
"
).
value
).
to
eq
(
'BBB'
)
expect
(
find
(
".
ci-variable-row:nth-child(2) .js-ci-variable-input-value"
,
visible:
false
).
value
).
to
eq
(
'BBB123'
)
end
end
end
...
...
@@ -185,16 +185,18 @@ feature 'Pipeline Schedules', :js do
visit_pipelines_schedules
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
all
(
'[name="schedule[variables_attributes][][key]"]'
)[
0
].
set
(
'foo'
)
all
(
'[name="schedule[variables_attributes][][value]"]'
)[
0
].
set
(
'bar'
)
find
(
'.js-ci-variable-list-section .js-secret-value-reveal-button'
).
click
first
(
'.js-ci-variable-input-key'
).
set
(
'foo'
)
first
(
'.js-ci-variable-input-value'
).
set
(
'bar'
)
click_button
'Save pipeline schedule'
end
scenario
'user sees the updated variable in edit window'
do
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
page
.
within
(
'.
pipeline
-variable-list'
)
do
expect
(
find
(
".
pipeline-variable-row:nth-child(1) .pipeline-variable-key-input
"
).
value
).
to
eq
(
'foo'
)
expect
(
find
(
".
pipeline-variable-row:nth-child(1) .pipeline-variable-value-input"
).
value
).
to
eq
(
'bar'
)
page
.
within
(
'.
ci
-variable-list'
)
do
expect
(
find
(
".
ci-variable-row:nth-child(1) .js-ci-variable-input-key
"
).
value
).
to
eq
(
'foo'
)
expect
(
find
(
".
ci-variable-row:nth-child(1) .js-ci-variable-input-value"
,
visible:
false
).
value
).
to
eq
(
'bar'
)
end
end
end
...
...
@@ -207,15 +209,15 @@ feature 'Pipeline Schedules', :js do
visit_pipelines_schedules
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
find
(
'.
pipeline-variable-list .pipeline
-variable-row-remove-button'
).
click
find
(
'.
ci-variable-list .ci
-variable-row-remove-button'
).
click
click_button
'Save pipeline schedule'
end
scenario
'user does not see the removed variable in edit window'
do
find
(
".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']"
).
click
page
.
within
(
'.
pipeline
-variable-list'
)
do
expect
(
find
(
".
pipeline-variable-row:nth-child(1) .pipeline-variable-key-input
"
).
value
).
to
eq
(
''
)
expect
(
find
(
".
pipeline-variable-row:nth-child(1) .pipeline-variable-value-input"
).
value
).
to
eq
(
''
)
page
.
within
(
'.
ci
-variable-list'
)
do
expect
(
find
(
".
ci-variable-row:nth-child(1) .js-ci-variable-input-key
"
).
value
).
to
eq
(
''
)
expect
(
find
(
".
ci-variable-row:nth-child(1) .js-ci-variable-input-value"
,
visible:
false
).
value
).
to
eq
(
''
)
end
end
end
...
...
spec/javascripts/ci_variable_list/ci_variable_list_spec.js
0 → 100644
View file @
88c9199a
import
VariableList
from
'
~/ci_variable_list/ci_variable_list
'
;
import
getSetTimeoutPromise
from
'
../helpers/set_timeout_promise_helper
'
;
describe
(
'
VariableList
'
,
()
=>
{
preloadFixtures
(
'
pipeline_schedules/edit.html.raw
'
);
preloadFixtures
(
'
pipeline_schedules/edit_with_variables.html.raw
'
);
let
$wrapper
;
let
variableList
;
describe
(
'
with only key/value inputs
'
,
()
=>
{
describe
(
'
with no variables
'
,
()
=>
{
beforeEach
(()
=>
{
loadFixtures
(
'
pipeline_schedules/edit.html.raw
'
);
$wrapper
=
$
(
'
.js-ci-variable-list-section
'
);
variableList
=
new
VariableList
({
container
:
$wrapper
,
formField
:
'
schedule
'
,
});
variableList
.
init
();
});
it
(
'
should remove the row when clicking the remove button
'
,
()
=>
{
$wrapper
.
find
(
'
.js-row-remove-button
'
).
trigger
(
'
click
'
);
expect
(
$wrapper
.
find
(
'
.js-row
'
).
length
).
toBe
(
0
);
});
it
(
'
should add another row when editing the last rows key input
'
,
()
=>
{
const
$row
=
$wrapper
.
find
(
'
.js-row
'
);
$row
.
find
(
'
.js-ci-variable-input-key
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$wrapper
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
// Check for the correct default in the new row
const
$keyInput
=
$wrapper
.
find
(
'
.js-row:last-child
'
).
find
(
'
.js-ci-variable-input-key
'
);
expect
(
$keyInput
.
val
()).
toBe
(
''
);
});
it
(
'
should add another row when editing the last rows value textarea
'
,
()
=>
{
const
$row
=
$wrapper
.
find
(
'
.js-row
'
);
$row
.
find
(
'
.js-ci-variable-input-value
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$wrapper
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
// Check for the correct default in the new row
const
$valueInput
=
$wrapper
.
find
(
'
.js-row:last-child
'
).
find
(
'
.js-ci-variable-input-key
'
);
expect
(
$valueInput
.
val
()).
toBe
(
''
);
});
it
(
'
should remove empty row after blurring
'
,
()
=>
{
const
$row
=
$wrapper
.
find
(
'
.js-row
'
);
$row
.
find
(
'
.js-ci-variable-input-key
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$wrapper
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
$row
.
find
(
'
.js-ci-variable-input-key
'
)
.
val
(
''
)
.
trigger
(
'
input
'
)
.
trigger
(
'
blur
'
);
expect
(
$wrapper
.
find
(
'
.js-row
'
).
length
).
toBe
(
1
);
});
});
describe
(
'
with persisted variables
'
,
()
=>
{
beforeEach
(()
=>
{
loadFixtures
(
'
pipeline_schedules/edit_with_variables.html.raw
'
);
$wrapper
=
$
(
'
.js-ci-variable-list-section
'
);
variableList
=
new
VariableList
({
container
:
$wrapper
,
formField
:
'
schedule
'
,
});
variableList
.
init
();
});
it
(
'
should have "Reveal values" button initially when there are already variables
'
,
()
=>
{
expect
(
$wrapper
.
find
(
'
.js-secret-value-reveal-button
'
).
text
()).
toBe
(
'
Reveal values
'
);
});
it
(
'
should reveal hidden values
'
,
()
=>
{
const
$row
=
$wrapper
.
find
(
'
.js-row:first-child
'
);
const
$inputValue
=
$row
.
find
(
'
.js-ci-variable-input-value
'
);
const
$placeholder
=
$row
.
find
(
'
.js-secret-value-placeholder
'
);
expect
(
$placeholder
.
hasClass
(
'
hide
'
)).
toBe
(
false
);
expect
(
$inputValue
.
hasClass
(
'
hide
'
)).
toBe
(
true
);
// Reveal values
$wrapper
.
find
(
'
.js-secret-value-reveal-button
'
).
click
();
expect
(
$placeholder
.
hasClass
(
'
hide
'
)).
toBe
(
true
);
expect
(
$inputValue
.
hasClass
(
'
hide
'
)).
toBe
(
false
);
});
});
});
describe
(
'
with all inputs(key, value, protected)
'
,
()
=>
{
beforeEach
(()
=>
{
// This markup will be replaced with a fixture when we can render the
// CI/CD settings page with the new dynamic variable list in https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4110
$wrapper
=
$
(
`<form class="js-variable-list">
<ul>
<li class="js-row">
<div class="ci-variable-body-item">
<input class="js-ci-variable-input-key" name="variables[variables_attributes][][key]">
</div>
<div class="ci-variable-body-item">
<textarea class="js-ci-variable-input-value" name="variables[variables_attributes][][value]"></textarea>
</div>
<div class="ci-variable-body-item ci-variable-protected-item">
<button type="button" class="js-project-feature-toggle project-feature-toggle">
<input
type="hidden"
class="js-ci-variable-input-protected js-project-feature-toggle-input"
name="variables[variables_attributes][][protected]"
value="true"
/>
</button>
</div>
<button type="button" class="js-row-remove-button"></button>
</li>
</ul>
<button type="button" class="js-secret-value-reveal-button">
Reveal values
</button>
</form>`
);
variableList
=
new
VariableList
({
container
:
$wrapper
,
formField
:
'
variables
'
,
});
variableList
.
init
();
});
it
(
'
should add another row when editing the last rows protected checkbox
'
,
(
done
)
=>
{
const
$row
=
$wrapper
.
find
(
'
.js-row:last-child
'
);
$row
.
find
(
'
.ci-variable-protected-item .js-project-feature-toggle
'
).
click
();
getSetTimeoutPromise
()
.
then
(()
=>
{
expect
(
$wrapper
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
// Check for the correct default in the new row
const
$protectedInput
=
$wrapper
.
find
(
'
.js-row:last-child
'
).
find
(
'
.js-ci-variable-input-protected
'
);
expect
(
$protectedInput
.
val
()).
toBe
(
'
true
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
spec/javascripts/ci_variable_list/native_form_variable_list_spec.js
0 → 100644
View file @
88c9199a
import
setupNativeFormVariableList
from
'
~/ci_variable_list/native_form_variable_list
'
;
describe
(
'
NativeFormVariableList
'
,
()
=>
{
preloadFixtures
(
'
pipeline_schedules/edit.html.raw
'
);
let
$wrapper
;
beforeEach
(()
=>
{
loadFixtures
(
'
pipeline_schedules/edit.html.raw
'
);
$wrapper
=
$
(
'
.js-ci-variable-list-section
'
);
setupNativeFormVariableList
({
container
:
$wrapper
,
formField
:
'
schedule
'
,
});
});
describe
(
'
onFormSubmit
'
,
()
=>
{
it
(
'
should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)
'
,
()
=>
{
const
$row
=
$wrapper
.
find
(
'
.js-row
'
);
expect
(
$row
.
find
(
'
.js-ci-variable-input-key
'
).
attr
(
'
name
'
)).
toBe
(
'
schedule[variables_attributes][][key]
'
);
expect
(
$row
.
find
(
'
.js-ci-variable-input-value
'
).
attr
(
'
name
'
)).
toBe
(
'
schedule[variables_attributes][][value]
'
);
$wrapper
.
closest
(
'
form
'
).
trigger
(
'
trigger-submit
'
);
expect
(
$row
.
find
(
'
.js-ci-variable-input-key
'
).
attr
(
'
name
'
)).
toBe
(
''
);
expect
(
$row
.
find
(
'
.js-ci-variable-input-value
'
).
attr
(
'
name
'
)).
toBe
(
''
);
});
});
});
spec/javascripts/fixtures/pipeline_schedules.rb
0 → 100644
View file @
88c9199a
require
'spec_helper'
describe
Projects
::
PipelineSchedulesController
,
'(JavaScript fixtures)'
,
type: :controller
do
include
JavaScriptFixturesHelpers
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:namespace
)
{
create
(
:namespace
,
name:
'frontend-fixtures'
)}
let
(
:project
)
{
create
(
:project
,
:public
,
:repository
)
}
let!
(
:pipeline_schedule
)
{
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
admin
)
}
let!
(
:pipeline_schedule_populated
)
{
create
(
:ci_pipeline_schedule
,
project:
project
,
owner:
admin
)
}
let!
(
:pipeline_schedule_variable1
)
{
create
(
:ci_pipeline_schedule_variable
,
key:
'foo'
,
value:
'foovalue'
,
pipeline_schedule:
pipeline_schedule_populated
)
}
let!
(
:pipeline_schedule_variable2
)
{
create
(
:ci_pipeline_schedule_variable
,
key:
'bar'
,
value:
'barvalue'
,
pipeline_schedule:
pipeline_schedule_populated
)
}
render_views
before
(
:all
)
do
clean_frontend_fixtures
(
'pipeline_schedules/'
)
end
before
do
sign_in
(
admin
)
end
it
'pipeline_schedules/edit.html.raw'
do
|
example
|
get
:edit
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule
.
id
expect
(
response
).
to
be_success
store_frontend_fixture
(
response
,
example
.
description
)
end
it
'pipeline_schedules/edit_with_variables.html.raw'
do
|
example
|
get
:edit
,
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
,
id:
pipeline_schedule_populated
.
id
expect
(
response
).
to
be_success
store_frontend_fixture
(
response
,
example
.
description
)
end
end
spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
deleted
100644 → 0
View file @
20714ee9
import
{
setupPipelineVariableList
,
insertRow
,
removeRow
,
}
from
'
~/pipeline_schedules/setup_pipeline_variable_list
'
;
describe
(
'
Pipeline Variable List
'
,
()
=>
{
let
$markup
;
describe
(
'
insertRow
'
,
()
=>
{
it
(
'
should insert another row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row">
<input>
<textarea></textarea>
</li>
</div>`
);
insertRow
(
$markup
.
find
(
'
.js-row
'
));
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
});
it
(
'
should clear `data-is-persisted` on cloned row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row" data-is-persisted="true"></li>
</div>`
);
insertRow
(
$markup
.
find
(
'
.js-row
'
));
const
$lastRow
=
$markup
.
find
(
'
.js-row
'
).
last
();
expect
(
$lastRow
.
attr
(
'
data-is-persisted
'
)).
toBe
(
undefined
);
});
it
(
'
should clear inputs on cloned row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row">
<input value="foo">
<textarea>bar</textarea>
</li>
</div>`
);
insertRow
(
$markup
.
find
(
'
.js-row
'
));
const
$lastRow
=
$markup
.
find
(
'
.js-row
'
).
last
();
expect
(
$lastRow
.
find
(
'
input
'
).
val
()).
toBe
(
''
);
expect
(
$lastRow
.
find
(
'
textarea
'
).
val
()).
toBe
(
''
);
});
});
describe
(
'
removeRow
'
,
()
=>
{
it
(
'
should remove dynamic row
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row">
<input>
<textarea></textarea>
</li>
</div>`
);
removeRow
(
$markup
.
find
(
'
.js-row
'
));
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
0
);
});
it
(
'
should hide and mark to destroy with already persisted rows
'
,
()
=>
{
$markup
=
$
(
`<div>
<li class="js-row" data-is-persisted="true">
<input class="js-destroy-input">
</li>
</div>`
);
const
$row
=
$markup
.
find
(
'
.js-row
'
);
removeRow
(
$row
);
expect
(
$row
.
find
(
'
.js-destroy-input
'
).
val
()).
toBe
(
'
1
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
1
);
});
});
describe
(
'
setupPipelineVariableList
'
,
()
=>
{
beforeEach
(()
=>
{
$markup
=
$
(
`<form>
<li class="js-row">
<input class="js-user-input" name="schedule[variables_attributes][][key]">
<textarea class="js-user-input" name="schedule[variables_attributes][][value]"></textarea>
<button class="js-row-remove-button"></button>
<button class="js-row-add-button"></button>
</li>
</form>`
);
setupPipelineVariableList
(
$markup
);
});
it
(
'
should remove the row when clicking the remove button
'
,
()
=>
{
$markup
.
find
(
'
.js-row-remove-button
'
).
trigger
(
'
click
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
0
);
});
it
(
'
should add another row when editing the last rows key input
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
$row
.
find
(
'
input.js-user-input
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
});
it
(
'
should add another row when editing the last rows value textarea
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
$row
.
find
(
'
textarea.js-user-input
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
});
it
(
'
should remove empty row after blurring
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
$row
.
find
(
'
input.js-user-input
'
)
.
val
(
'
foo
'
)
.
trigger
(
'
input
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
2
);
$row
.
find
(
'
input.js-user-input
'
)
.
val
(
''
)
.
trigger
(
'
input
'
)
.
trigger
(
'
blur
'
);
expect
(
$markup
.
find
(
'
.js-row
'
).
length
).
toBe
(
1
);
});
it
(
'
should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)
'
,
()
=>
{
const
$row
=
$markup
.
find
(
'
.js-row
'
);
expect
(
$row
.
find
(
'
input
'
).
attr
(
'
name
'
)).
toBe
(
'
schedule[variables_attributes][][key]
'
);
expect
(
$row
.
find
(
'
textarea
'
).
attr
(
'
name
'
)).
toBe
(
'
schedule[variables_attributes][][value]
'
);
$markup
.
filter
(
'
form
'
).
submit
();
expect
(
$row
.
find
(
'
input
'
).
attr
(
'
name
'
)).
toBe
(
''
);
expect
(
$row
.
find
(
'
textarea
'
).
attr
(
'
name
'
)).
toBe
(
''
);
});
});
});
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