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
2f83d038
Commit
2f83d038
authored
May 14, 2021
by
Ezekiel Kigbo
Committed by
Nicolò Maria Mezzopera
May 14, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove legacy custom value stream components and docs
parent
09f5face
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
0 additions
and
1013 deletions
+0
-1013
ee/app/assets/javascripts/analytics/cycle_analytics/components/add_stage_button.vue
...analytics/cycle_analytics/components/add_stage_button.vue
+0
-27
ee/app/assets/javascripts/analytics/cycle_analytics/components/custom_stage_form.vue
...nalytics/cycle_analytics/components/custom_stage_form.vue
+0
-242
ee/app/assets/javascripts/analytics/cycle_analytics/constants.js
...assets/javascripts/analytics/cycle_analytics/constants.js
+0
-10
ee/spec/features/groups/analytics/cycle_analytics/customizable_cycle_analytics_spec.rb
...tics/cycle_analytics/customizable_cycle_analytics_spec.rb
+0
-222
ee/spec/frontend/analytics/cycle_analytics/components/__snapshots__/custom_stage_form_spec.js.snap
...s/components/__snapshots__/custom_stage_form_spec.js.snap
+0
-15
ee/spec/frontend/analytics/cycle_analytics/components/add_stage_button_spec.js
...ytics/cycle_analytics/components/add_stage_button_spec.js
+0
-46
ee/spec/frontend/analytics/cycle_analytics/components/custom_stage_form_spec.js
...tics/cycle_analytics/components/custom_stage_form_spec.js
+0
-427
locale/gitlab.pot
locale/gitlab.pot
+0
-24
No files found.
ee/app/assets/javascripts/analytics/cycle_analytics/components/add_stage_button.vue
deleted
100644 → 0
View file @
09f5face
<
script
>
export
default
{
props
:
{
active
:
{
type
:
Boolean
,
required
:
true
,
},
},
computed
:
{
activeClass
()
{
return
'
active font-weight-bold border-style-solid border-color-blue-300
'
;
},
inactiveClass
()
{
return
'
bg-transparent border-style-dashed border-color-default
'
;
},
},
};
</
script
>
<
template
>
<li
:class=
"[active ? activeClass : inactiveClass]"
class=
"js-add-stage-button stage-nav-item mb-1 rounded d-flex justify-content-center border-width-1px"
@
click.prevent=
"$emit('showform')"
>
{{
s__
(
'
CustomCycleAnalytics|Add a stage
'
)
}}
</li>
</
template
>
ee/app/assets/javascripts/analytics/cycle_analytics/components/custom_stage_form.vue
deleted
100644 → 0
View file @
09f5face
<
script
>
import
{
GlLoadingIcon
,
GlDropdown
,
GlDropdownSectionHeader
,
GlDropdownItem
,
GlSprintf
,
GlButton
,
}
from
'
@gitlab/ui
'
;
import
{
isEqual
}
from
'
lodash
'
;
import
Vue
from
'
vue
'
;
import
{
mapGetters
,
mapState
}
from
'
vuex
'
;
import
{
convertObjectPropsToSnakeCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
STAGE_ACTIONS
}
from
'
../constants
'
;
import
{
getAllowedEndEvents
,
getLabelEventsIdentifiers
,
isLabelEvent
}
from
'
../utils
'
;
import
{
defaultFields
,
ERRORS
,
i18n
}
from
'
./create_value_stream_form/constants
'
;
import
CustomStageFormFields
from
'
./create_value_stream_form/custom_stage_fields.vue
'
;
import
{
validateStage
,
initializeFormData
}
from
'
./create_value_stream_form/utils
'
;
export
default
{
components
:
{
GlLoadingIcon
,
GlDropdown
,
GlDropdownSectionHeader
,
GlDropdownItem
,
GlSprintf
,
GlButton
,
CustomStageFormFields
,
},
props
:
{
events
:
{
type
:
Array
,
required
:
true
,
},
},
data
()
{
return
{
labelEvents
:
getLabelEventsIdentifiers
(
this
.
events
),
fields
:
{},
errors
:
{},
};
},
computed
:
{
...
mapGetters
([
'
hiddenStages
'
]),
...
mapState
(
'
customStages
'
,
[
'
isLoading
'
,
'
isSavingCustomStage
'
,
'
isEditingCustomStage
'
,
'
formInitialData
'
,
'
formErrors
'
,
]),
hasErrors
()
{
return
(
this
.
eventMismatchError
||
Object
.
values
(
this
.
errors
).
some
((
errArray
)
=>
errArray
?.
length
)
);
},
startEventRequiresLabel
()
{
return
isLabelEvent
(
this
.
labelEvents
,
this
.
fields
.
startEventIdentifier
);
},
endEventRequiresLabel
()
{
return
isLabelEvent
(
this
.
labelEvents
,
this
.
fields
.
endEventIdentifier
);
},
isComplete
()
{
if
(
this
.
hasErrors
)
{
return
false
;
}
const
{
fields
:
{
name
,
startEventIdentifier
,
startEventLabelId
,
endEventIdentifier
,
endEventLabelId
,
},
}
=
this
;
const
requiredFields
=
[
startEventIdentifier
,
endEventIdentifier
,
name
];
if
(
this
.
startEventRequiresLabel
)
{
requiredFields
.
push
(
startEventLabelId
);
}
if
(
this
.
endEventRequiresLabel
)
{
requiredFields
.
push
(
endEventLabelId
);
}
return
requiredFields
.
every
(
(
fieldValue
)
=>
fieldValue
&&
(
fieldValue
.
length
>
0
||
fieldValue
>
0
),
);
},
isDirty
()
{
return
!
isEqual
(
this
.
fields
,
this
.
formInitialData
||
defaultFields
);
},
eventMismatchError
()
{
const
{
fields
:
{
startEventIdentifier
=
null
,
endEventIdentifier
=
null
},
}
=
this
;
if
(
!
startEventIdentifier
||
!
endEventIdentifier
)
return
true
;
const
endEvents
=
getAllowedEndEvents
(
this
.
events
,
startEventIdentifier
);
return
!
endEvents
.
length
||
!
endEvents
.
includes
(
endEventIdentifier
);
},
saveStageText
()
{
return
this
.
isEditingCustomStage
?
i18n
.
BTN_UPDATE_STAGE
:
i18n
.
BTN_ADD_STAGE
;
},
formTitle
()
{
return
this
.
isEditingCustomStage
?
i18n
.
TITLE_EDIT_STAGE
:
i18n
.
TITLE_ADD_STAGE
;
},
hasHiddenStages
()
{
return
this
.
hiddenStages
.
length
;
},
},
watch
:
{
formInitialData
(
newFields
=
{})
{
this
.
fields
=
{
...
defaultFields
,
...
newFields
,
};
},
formErrors
(
newErrors
=
{})
{
this
.
errors
=
{
...
newErrors
,
};
},
},
mounted
()
{
this
.
resetFields
();
},
methods
:
{
resetFields
()
{
const
{
formInitialData
,
formErrors
}
=
this
;
const
{
fields
,
errors
}
=
initializeFormData
({
fields
:
formInitialData
,
errors
:
formErrors
,
});
this
.
fields
=
{
...
fields
};
this
.
errors
=
{
...
errors
};
},
handleCancel
()
{
this
.
resetFields
();
this
.
$emit
(
'
cancel
'
);
},
handleSave
()
{
const
data
=
convertObjectPropsToSnakeCase
(
this
.
fields
);
if
(
this
.
isEditingCustomStage
)
{
const
{
id
}
=
this
.
fields
;
this
.
$emit
(
STAGE_ACTIONS
.
UPDATE
,
{
...
data
,
id
});
}
else
{
this
.
$emit
(
STAGE_ACTIONS
.
CREATE
,
data
);
}
},
hasFieldErrors
(
key
)
{
return
this
.
errors
[
key
]?.
length
>
0
;
},
fieldErrorMessage
(
key
)
{
return
this
.
errors
[
key
]?.
join
(
'
\n
'
);
},
handleRecoverStage
(
id
)
{
this
.
$emit
(
STAGE_ACTIONS
.
UPDATE
,
{
id
,
hidden
:
false
});
},
handleUpdateFields
({
field
,
value
})
{
this
.
fields
=
{
...
this
.
fields
,
[
field
]:
value
};
const
newErrors
=
validateStage
({
...
this
.
fields
,
custom
:
true
});
newErrors
.
endEventIdentifier
=
this
.
fields
.
startEventIdentifier
&&
this
.
eventMismatchError
?
[
ERRORS
.
INVALID_EVENT_PAIRS
]
:
newErrors
.
endEventIdentifier
;
Vue
.
set
(
this
,
'
errors
'
,
newErrors
);
},
},
i18n
,
};
</
script
>
<
template
>
<div
v-if=
"isLoading"
>
<gl-loading-icon
class=
"mt-4"
size=
"md"
/>
</div>
<form
v-else
class=
"custom-stage-form m-4 gl-mt-0"
>
<div
class=
"gl-mb-1 gl-display-flex gl-justify-content-space-between gl-align-items-center"
>
<h4>
{{
formTitle
}}
</h4>
<gl-dropdown
:text=
"$options.i18n.RECOVER_HIDDEN_STAGE"
data-testid=
"recover-hidden-stage-dropdown"
right
>
<gl-dropdown-section-header>
{{
$options
.
i18n
.
RECOVER_STAGE_TITLE
}}
</gl-dropdown-section-header>
<template
v-if=
"hasHiddenStages"
>
<gl-dropdown-item
v-for=
"stage in hiddenStages"
:key=
"stage.id"
@
click=
"handleRecoverStage(stage.id)"
>
{{
stage
.
title
}}
</gl-dropdown-item
>
</
template
>
<p
v-else
class=
"gl-mx-5 gl-my-3"
>
{{ $options.i18n.RECOVER_STAGES_VISIBLE }}
</p>
</gl-dropdown>
</div>
<custom-stage-form-fields
:index=
"0"
:total-stages=
"1"
:stage=
"fields"
:errors=
"errors"
:stage-events=
"events"
@
input=
"handleUpdateFields"
@
select-label=
"({ field, value }) => handleUpdateFields({ field, value })"
/>
<div>
<gl-button
:disabled=
"!isDirty"
category=
"primary"
data-testid=
"cancel-custom-stage"
@
click=
"handleCancel"
>
{{ $options.i18n.BTN_CANCEL }}
</gl-button>
<gl-button
:disabled=
"!isComplete || !isDirty"
variant=
"success"
category=
"primary"
data-testid=
"save-custom-stage"
@
click=
"handleSave"
>
<gl-loading-icon
v-if=
"isSavingCustomStage"
size=
"sm"
inline
/>
{{ saveStageText }}
</gl-button>
</div>
<div
class=
"gl-mt-3"
>
<gl-sprintf
:message=
"
__(
'%{strongStart}Note:%{strongEnd} Once a custom stage has been added you can re-order stages by dragging them into the desired position.',
)
"
>
<
template
#strong=
"{ content }"
>
<strong>
{{
content
}}
</strong>
</
template
>
</gl-sprintf>
</div>
</form>
</template>
ee/app/assets/javascripts/analytics/cycle_analytics/constants.js
View file @
2f83d038
...
...
@@ -43,16 +43,6 @@ export const TASKS_BY_TYPE_FILTERS = {
LABEL
:
'
LABEL
'
,
};
export
const
STAGE_ACTIONS
=
{
SELECT
:
'
selectStage
'
,
EDIT
:
'
editStage
'
,
REMOVE
:
'
removeStage
'
,
HIDE
:
'
hideStage
'
,
CREATE
:
'
createStage
'
,
UPDATE
:
'
updateStage
'
,
ADD_STAGE
:
'
showAddStageForm
'
,
};
export
const
DEFAULT_VALUE_STREAM_ID
=
'
default
'
;
export
const
OVERVIEW_METRICS
=
{
...
...
ee/spec/features/groups/analytics/cycle_analytics/customizable_cycle_analytics_spec.rb
deleted
100644 → 0
View file @
09f5face
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'Customizable Group Value Stream Analytics'
,
:js
do
include
DragTo
include
CycleAnalyticsHelpers
let_it_be
(
:group
)
{
create
(
:group
,
name:
'CA-test-group'
)
}
let_it_be
(
:sub_group
)
{
create
(
:group
,
name:
'CA-sub-group'
,
parent:
group
)
}
let_it_be
(
:group2
)
{
create
(
:group
,
name:
'CA-bad-test-group'
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:repository
,
namespace:
group
,
group:
group
,
name:
'Cool fun project'
)
}
let_it_be
(
:group_label1
)
{
create
(
:group_label
,
group:
group
)
}
let_it_be
(
:group_label2
)
{
create
(
:group_label
,
group:
group
)
}
let_it_be
(
:label
)
{
create
(
:group_label
,
group:
group2
)
}
let_it_be
(
:sub_group_label1
)
{
create
(
:group_label
,
group:
sub_group
)
}
let_it_be
(
:sub_group_label2
)
{
create
(
:group_label
,
group:
sub_group
)
}
let_it_be
(
:user
)
do
create
(
:user
).
tap
do
|
u
|
group
.
add_owner
(
u
)
project
.
add_maintainer
(
u
)
end
end
let
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let
(
:mr
)
{
create_merge_request_closing_issue
(
user
,
project
,
issue
,
commit_message:
"References
#{
issue
.
to_reference
}
"
)
}
let
(
:pipeline
)
{
create
(
:ci_empty_pipeline
,
status:
'created'
,
project:
project
,
ref:
mr
.
source_branch
,
sha:
mr
.
source_branch_sha
,
head_pipeline_of:
mr
)
}
let
(
:stage_nav_selector
)
{
'.stage-nav'
}
let
(
:duration_stage_selector
)
{
'.js-dropdown-stages'
}
custom_stage_name
=
'Cool beans'
custom_stage_with_labels_name
=
'Cool beans - now with labels'
start_event_identifier
=
:merge_request_created
end_event_identifier
=
:merge_request_merged
start_event_text
=
"Merge request created"
end_event_text
=
"Merge request merged"
start_label_event
=
:issue_label_added
end_label_event
=
:issue_label_removed
start_event_field
=
'custom-stage-start-event-0'
end_event_field
=
'custom-stage-end-event-0'
start_field_label
=
'custom-stage-start-event-label-0'
end_field_label
=
'custom-stage-end-event-label-0'
name_field
=
'custom-stage-name-0'
let
(
:add_stage_button
)
{
'.js-add-stage-button'
}
let
(
:params
)
{
{
name:
custom_stage_name
,
start_event_identifier:
start_event_identifier
,
end_event_identifier:
end_event_identifier
}
}
let
(
:first_default_stage
)
{
page
.
find
(
'.stage-nav-item-cell'
,
text:
'Issue'
).
ancestor
(
'.stage-nav-item'
)
}
let
(
:first_custom_stage
)
{
page
.
find
(
'.stage-nav-item-cell'
,
text:
custom_stage_name
).
ancestor
(
'.stage-nav-item'
)
}
let
(
:nav
)
{
page
.
find
(
stage_nav_selector
)
}
def
create_custom_stage
(
parent_group
=
group
)
Analytics
::
CycleAnalytics
::
Stages
::
CreateService
.
new
(
parent:
parent_group
,
params:
params
,
current_user:
user
).
execute
end
def
toggle_more_options
(
stage
)
stage
.
hover
find_stage_actions_btn
(
stage
).
click
end
def
select_dropdown_option
(
name
,
value
=
start_event_identifier
)
toggle_dropdown
name
page
.
find
(
"[data-testid='
#{
name
}
'] .dropdown-menu"
).
all
(
'.dropdown-item'
).
find
{
|
item
|
item
.
value
==
value
.
to_s
}.
click
end
def
select_dropdown_label
(
field
,
index
=
1
)
page
.
find
(
"[data-testid='
#{
field
}
'] .dropdown-menu"
).
all
(
'.dropdown-item'
)[
index
].
click
end
def
drag_from_index_to_index
(
from
,
to
)
drag_to
(
selector:
'.stage-nav>ul'
,
from_index:
from
,
to_index:
to
)
end
def
find_stage_actions_btn
(
stage
)
stage
.
find
(
'[data-testid="more-actions-toggle"]'
)
end
before
do
stub_licensed_features
(
cycle_analytics_for_groups:
true
,
type_of_work_analytics:
true
)
sign_in
(
user
)
end
shared_examples
'submits custom stage form successfully'
do
|
stage_name
|
it
'custom stage is saved with confirmation message'
do
fill_in
name_field
,
with:
stage_name
click_button
(
s_
(
'CustomCycleAnalytics|Add stage'
))
expect
(
page
.
find
(
'.flash-notice'
)).
to
have_text
(
_
(
"Your custom stage '%{title}' was created"
)
%
{
title:
stage_name
})
expect
(
page
).
to
have_selector
(
'.stage-nav-item'
,
text:
stage_name
)
end
end
shared_examples
'can create custom stages'
do
context
'Custom stage form'
do
let
(
:show_form_add_stage_button
)
{
'.js-add-stage-button'
}
before
do
page
.
find
(
show_form_add_stage_button
).
click
wait_for_requests
end
context
'with empty fields'
do
it
'submit button is disabled by default'
do
expect
(
page
).
to
have_button
(
s_
(
'CustomCycleAnalytics|Add stage'
),
disabled:
true
)
end
end
context
'with all required fields set'
do
before
do
fill_in
name_field
,
with:
custom_stage_name
select_dropdown_option
start_event_field
,
start_event_identifier
select_dropdown_option
end_event_field
,
end_event_identifier
end
it
'does not have label dropdowns'
do
expect
(
page
).
not_to
have_content
(
s_
(
'CustomCycleAnalytics|Start event label'
))
expect
(
page
).
not_to
have_content
(
s_
(
'CustomCycleAnalytics|End event label'
))
end
it
'submit button is disabled if a default name is used'
do
fill_in
name_field
,
with:
'issue'
expect
(
page
).
to
have_button
(
s_
(
'CustomCycleAnalytics|Add stage'
),
disabled:
true
)
end
it
'submit button is disabled if the start event changes'
do
select_dropdown_option
start_event_field
,
'issue_created'
expect
(
page
).
to
have_button
(
s_
(
'CustomCycleAnalytics|Add stage'
),
disabled:
true
)
end
include_examples
'submits custom stage form successfully'
,
custom_stage_name
end
context
'with label based stages selected'
do
before
do
fill_in
name_field
,
with:
custom_stage_with_labels_name
select_dropdown_option_by_value
start_event_field
,
start_label_event
select_dropdown_option_by_value
end_event_field
,
end_label_event
end
it
'submit button is disabled'
do
expect
(
page
).
to
have_button
(
s_
(
'CustomCycleAnalytics|Add stage'
),
disabled:
true
)
end
context
'with labels available'
do
it
'does not contain labels from outside the group'
do
toggle_dropdown
(
start_field_label
)
menu
=
page
.
find
(
"[data-testid=
#{
start_field_label
}
] .dropdown-menu"
)
expect
(
menu
).
not_to
have_content
(
other_label
.
name
)
expect
(
menu
).
to
have_content
(
first_label
.
name
)
expect
(
menu
).
to
have_content
(
second_label
.
name
)
end
context
'with all required fields set'
do
before
do
toggle_dropdown
(
start_field_label
)
select_dropdown_label
start_field_label
,
0
toggle_dropdown
(
end_field_label
)
select_dropdown_label
end_field_label
,
1
end
include_examples
'submits custom stage form successfully'
,
custom_stage_with_labels_name
end
end
end
end
end
shared_examples
'can edit custom stages'
do
context
'Edit stage form'
do
let
(
:stage_form_class
)
{
'.custom-stage-form'
}
let
(
:stage_save_button
)
{
'[data-testid="save-custom-stage"]'
}
let
(
:updated_custom_stage_name
)
{
'Extra uber cool stage'
}
before
do
toggle_more_options
(
first_custom_stage
)
click_button
(
_
(
'Edit stage'
))
end
context
'with no changes to the data'
do
it
'prepopulates the stage data and disables submit button'
do
expect
(
page
.
find
(
stage_form_class
)).
to
have_text
(
s_
(
'CustomCycleAnalytics|Editing stage'
))
expect
(
page
.
find
(
"[name='
#{
name_field
}
']"
).
value
).
to
eq
custom_stage_name
expect
(
page
.
find
(
"[data-testid='
#{
start_event_field
}
']"
)).
to
have_text
(
start_event_text
)
expect
(
page
.
find
(
"[data-testid='
#{
end_event_field
}
']"
)).
to
have_text
(
end_event_text
)
expect
(
page
.
find
(
stage_save_button
)[
:disabled
]).
to
eq
'true'
end
end
context
'with changes'
do
it
'persists updates to the stage'
do
fill_in
name_field
,
with:
updated_custom_stage_name
page
.
find
(
stage_save_button
).
click
expect
(
page
.
find
(
'.flash-notice'
)).
to
have_text
(
_
(
'Stage data updated'
))
expect
(
page
.
find
(
stage_nav_selector
)).
not_to
have_text
custom_stage_name
expect
(
page
.
find
(
stage_nav_selector
)).
to
have_text
updated_custom_stage_name
end
it
'disables the submit form button if incomplete'
do
fill_in
name_field
,
with:
''
expect
(
page
.
find
(
stage_save_button
)[
:disabled
]).
to
eq
'true'
end
it
'doesnt update the stage if a default name is provided'
do
fill_in
name_field
,
with:
'issue'
page
.
find
(
stage_save_button
).
click
expect
(
page
.
find
(
stage_form_class
)).
to
have_text
(
s_
(
'CustomCycleAnalytics|Stage name already exists'
))
end
end
end
end
end
ee/spec/frontend/analytics/cycle_analytics/components/__snapshots__/custom_stage_form_spec.js.snap
deleted
100644 → 0
View file @
09f5face
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CustomStageForm Editing a custom stage isSavingCustomStage=true displays a loading icon 1`] = `
"<gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\" data-testid=\\"save-custom-stage\\">
<gl-loading-icon-stub label=\\"Loading\\" size=\\"sm\\" color=\\"dark\\" inline=\\"true\\"></gl-loading-icon-stub>
Update stage
</gl-button-stub>"
`;
exports[`CustomStageForm isSavingCustomStage=true displays a loading icon 1`] = `
"<gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\" data-testid=\\"save-custom-stage\\">
<gl-loading-icon-stub label=\\"Loading\\" size=\\"sm\\" color=\\"dark\\" inline=\\"true\\"></gl-loading-icon-stub>
Add stage
</gl-button-stub>"
`;
ee/spec/frontend/analytics/cycle_analytics/components/add_stage_button_spec.js
deleted
100644 → 0
View file @
09f5face
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
AddStageButton
from
'
ee/analytics/cycle_analytics/components/add_stage_button.vue
'
;
describe
(
'
AddStageButton
'
,
()
=>
{
const
active
=
false
;
function
createComponent
(
props
)
{
return
shallowMount
(
AddStageButton
,
{
propsData
:
{
active
,
...
props
,
},
});
}
let
wrapper
=
null
;
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
is not active
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
it
(
'
emits the `showform` event when clicked
'
,
()
=>
{
wrapper
=
createComponent
();
expect
(
wrapper
.
emitted
().
showform
).
toBeUndefined
();
wrapper
.
trigger
(
'
click
'
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
wrapper
.
emitted
().
showform
).
toHaveLength
(
1
);
});
});
it
(
'
does not have the active class
'
,
()
=>
{
expect
(
wrapper
.
classes
(
'
active
'
)).
toBe
(
false
);
});
});
describe
(
'
is active
'
,
()
=>
{
it
(
'
has the active class when active=true
'
,
()
=>
{
wrapper
=
createComponent
({
active
:
true
});
expect
(
wrapper
.
classes
(
'
active
'
)).
toBe
(
true
);
});
});
});
ee/spec/frontend/analytics/cycle_analytics/components/custom_stage_form_spec.js
deleted
100644 → 0
View file @
09f5face
import
{
GlSprintf
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
Vuex
from
'
vuex
'
;
import
CustomStageFields
from
'
ee/analytics/cycle_analytics/components/create_value_stream_form/custom_stage_fields.vue
'
;
import
CustomStageForm
from
'
ee/analytics/cycle_analytics/components/custom_stage_form.vue
'
;
import
{
STAGE_ACTIONS
}
from
'
ee/analytics/cycle_analytics/constants
'
;
import
customStagesStore
from
'
ee/analytics/cycle_analytics/store/modules/custom_stages
'
;
import
{
convertObjectPropsToSnakeCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
endpoints
,
groupLabels
,
customStageEvents
as
events
,
customStageFormErrors
,
}
from
'
../mock_data
'
;
import
{
emptyState
,
formInitialData
,
minimumFields
,
MERGE_REQUEST_CREATED
,
MERGE_REQUEST_CLOSED
,
ISSUE_CREATED
,
ISSUE_CLOSED
,
}
from
'
./create_value_stream_form/mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
const
fakeStore
=
({
initialState
,
initialRootGetters
})
=>
new
Vuex
.
Store
({
getters
:
{
currentGroupPath
:
()
=>
'
fake
'
,
hiddenStages
:
()
=>
[],
...
initialRootGetters
,
},
modules
:
{
customStages
:
{
...
customStagesStore
,
state
:
{
isLoading
:
false
,
...
initialState
,
},
},
},
});
describe
(
'
CustomStageForm
'
,
()
=>
{
function
createComponent
({
initialState
=
{},
initialRootGetters
=
{},
stubs
=
{},
props
=
{},
}
=
{})
{
return
shallowMount
(
CustomStageForm
,
{
localVue
,
store
:
fakeStore
({
initialState
,
initialRootGetters
}),
propsData
:
{
events
,
...
props
,
},
stubs
:
{
GlSprintf
,
CustomStageFields
,
...
stubs
,
},
});
}
let
wrapper
=
null
;
let
mock
;
const
findEvent
=
(
ev
)
=>
wrapper
.
emitted
()[
ev
];
const
findSubmitButton
=
()
=>
wrapper
.
find
(
'
[data-testid="save-custom-stage"]
'
);
const
findCancelButton
=
()
=>
wrapper
.
find
(
'
[data-testid="cancel-custom-stage"]
'
);
const
findRecoverStageDropdown
=
()
=>
wrapper
.
find
(
'
[data-testid="recover-hidden-stage-dropdown"]
'
);
const
findFieldErrors
=
(
field
)
=>
wrapper
.
vm
.
errors
[
field
];
const
setFields
=
async
(
fields
=
minimumFields
)
=>
{
Object
.
entries
(
fields
).
forEach
(([
field
,
value
])
=>
{
wrapper
.
find
(
CustomStageFields
).
vm
.
$emit
(
'
input
'
,
{
field
,
value
});
});
await
wrapper
.
vm
.
$nextTick
();
};
const
setNameField
=
(
value
=
''
)
=>
setFields
({
name
:
value
});
const
setStartEvent
=
(
value
=
MERGE_REQUEST_CREATED
)
=>
setFields
({
startEventIdentifier
:
value
});
const
setEndEvent
=
(
value
=
MERGE_REQUEST_CLOSED
)
=>
setFields
({
endEventIdentifier
:
value
});
const
mockGroupLabelsRequest
=
()
=>
new
MockAdapter
(
axios
).
onGet
(
endpoints
.
groupLabels
).
reply
(
200
,
groupLabels
);
beforeEach
(
async
()
=>
{
mock
=
mockGroupLabelsRequest
();
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
=
null
;
mock
.
restore
();
});
describe
(
'
Default state
'
,
()
=>
{
it
(
'
will set all fields to null
'
,
()
=>
{
expect
(
wrapper
.
vm
.
fields
).
toMatchObject
(
emptyState
);
});
it
(
'
displays the manual ordering helper text
'
,
()
=>
{
expect
(
wrapper
.
html
()).
toContain
(
'
<strong>Note:</strong> Once a custom stage has been added you can re-order stages by dragging them into the desired position.
'
,
);
});
});
describe
(
'
Name
'
,
()
=>
{
describe
(
'
with a reserved name
'
,
()
=>
{
beforeEach
(
async
()
=>
{
wrapper
=
createComponent
();
await
setNameField
(
'
issue
'
);
});
it
(
'
displays an error
'
,
()
=>
{
expect
(
findFieldErrors
(
'
name
'
)).
toContain
(
'
Stage name already exists
'
);
});
it
(
'
clears the error when the field changes
'
,
async
()
=>
{
await
setNameField
(
'
not an issue
'
);
expect
(
findFieldErrors
(
'
name
'
)).
toBeUndefined
();
});
});
});
describe
(
'
End event
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
it
(
'
sets an error if no start event is selected
'
,
()
=>
{
expect
(
findFieldErrors
(
'
endEventIdentifier
'
)).
toContain
(
'
Please select a start event first
'
);
});
it
(
'
clears error when a start event is selected
'
,
async
()
=>
{
await
setStartEvent
();
expect
(
findFieldErrors
(
'
endEventIdentifier
'
)).
not
.
toContain
(
'
Please select a start event first
'
,
);
});
describe
(
'
with a end event selected and a change to the start event
'
,
()
=>
{
beforeEach
(
async
()
=>
{
wrapper
=
createComponent
();
await
setFields
(
minimumFields
);
});
it
(
'
warns that the start event changed
'
,
async
()
=>
{
await
setStartEvent
(
''
);
expect
(
findFieldErrors
(
'
endEventIdentifier
'
)).
toContain
(
'
Please select a start event first
'
,
);
});
it
(
'
warns if the current start and end event pair is not valid
'
,
async
()
=>
{
await
setFields
({
startEventIdentifier
:
'
fake_event_id
'
});
expect
(
findFieldErrors
(
'
endEventIdentifier
'
)).
toContain
(
'
Start event changed, please select a valid end event
'
,
);
});
it
(
'
will disable the submit button until a valid endEvent is selected
'
,
async
()
=>
{
expect
(
findSubmitButton
().
props
(
'
disabled
'
)).
toBe
(
false
);
await
setEndEvent
(
''
);
expect
(
findSubmitButton
().
props
(
'
disabled
'
)).
toBe
(
true
);
});
});
});
describe
(
'
Add stage button
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
it
(
'
has text `Add stage`
'
,
()
=>
{
expect
(
findSubmitButton
().
text
()).
toEqual
(
'
Add stage
'
);
});
describe
(
'
with all fields set
'
,
()
=>
{
beforeEach
(
async
()
=>
{
wrapper
=
createComponent
();
await
setFields
();
});
it
(
'
is enabled
'
,
()
=>
{
expect
(
findSubmitButton
().
props
(
'
disabled
'
)).
toBe
(
false
);
});
it
(
'
does not emit an event until the button is clicked
'
,
()
=>
{
expect
(
findEvent
(
STAGE_ACTIONS
.
CREATE
)).
toBeUndefined
();
});
it
(
`emits a
${
STAGE_ACTIONS
.
CREATE
}
event when clicked`
,
async
()
=>
{
findSubmitButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findEvent
(
STAGE_ACTIONS
.
CREATE
)).
toHaveLength
(
1
);
});
it
(
`
${
STAGE_ACTIONS
.
CREATE
}
event receives the latest data`
,
async
()
=>
{
const
newData
=
{
name
:
'
Cool stage
'
,
start_event_identifier
:
ISSUE_CREATED
,
end_event_identifier
:
ISSUE_CLOSED
,
};
setFields
(
newData
);
findSubmitButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findEvent
(
STAGE_ACTIONS
.
CREATE
)[
0
][
0
]).
toMatchObject
(
newData
);
});
});
});
describe
(
'
Cancel button
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
it
(
'
is disabled by default
'
,
async
()
=>
{
expect
(
findCancelButton
().
props
(
'
disabled
'
)).
toBe
(
true
);
});
it
(
'
is enabled when the form is dirty
'
,
async
()
=>
{
await
setNameField
(
'
Cool stage
'
);
expect
(
findCancelButton
().
props
(
'
disabled
'
)).
toBe
(
false
);
});
it
(
'
will reset the fields when clicked
'
,
async
()
=>
{
await
setFields
();
findCancelButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
vm
.
fields
).
toMatchObject
({
name
:
null
,
startEventIdentifier
:
null
,
startEventLabelId
:
null
,
endEventIdentifier
:
null
,
endEventLabelId
:
null
,
});
});
it
(
'
does not emit an event until the button is clicked
'
,
()
=>
{
expect
(
findEvent
(
'
cancel
'
)).
toBeUndefined
();
});
it
(
'
will emit the `cancel` event when clicked
'
,
async
()
=>
{
await
setFields
();
findCancelButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findEvent
(
'
cancel
'
)).
toHaveLength
(
1
);
});
});
describe
(
'
isSavingCustomStage=true
'
,
()
=>
{
beforeEach
(
async
()
=>
{
wrapper
=
createComponent
({
initialState
:
{
isSavingCustomStage
:
true
,
},
});
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
displays a loading icon
'
,
()
=>
{
expect
(
findSubmitButton
().
html
()).
toMatchSnapshot
();
});
});
describe
(
'
Editing a custom stage
'
,
()
=>
{
beforeEach
(
async
()
=>
{
wrapper
=
createComponent
({
initialState
:
{
isEditingCustomStage
:
true
,
formInitialData
,
},
});
});
it
(
'
Cancel button will reset the fields to initial state when clicked
'
,
async
()
=>
{
await
setFields
(
minimumFields
);
findCancelButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
vm
.
fields
).
toEqual
({
...
formInitialData
});
});
describe
(
'
Update stage button
'
,
()
=>
{
it
(
'
has text `Update stage`
'
,
()
=>
{
expect
(
findSubmitButton
().
text
(
'
value
'
)).
toEqual
(
'
Update stage
'
);
});
it
(
'
is disabled by default
'
,
()
=>
{
expect
(
findSubmitButton
().
props
(
'
disabled
'
)).
toBe
(
true
);
});
it
(
'
is enabled when a field is changed and fields are valid
'
,
async
()
=>
{
await
setFields
(
minimumFields
);
expect
(
findSubmitButton
().
props
(
'
disabled
'
)).
toBe
(
false
);
});
it
(
'
is disabled when a field is changed but fields are incomplete
'
,
async
()
=>
{
await
setFields
({
name
:
''
});
expect
(
findSubmitButton
().
props
(
'
disabled
'
)).
toBe
(
true
);
});
it
(
'
does not emit an event until the button is clicked
'
,
()
=>
{
expect
(
findEvent
(
STAGE_ACTIONS
.
UPDATE
)).
toBeUndefined
();
});
it
(
`emits a
${
STAGE_ACTIONS
.
UPDATE
}
event when clicked`
,
async
()
=>
{
await
setFields
({
name
:
'
Cool updated form
'
});
findSubmitButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
findEvent
(
STAGE_ACTIONS
.
UPDATE
)).
toHaveLength
(
1
);
});
it
(
'
`submit` event receives the latest data
'
,
async
()
=>
{
await
setFields
({
name
:
'
Cool updated form
'
});
findSubmitButton
().
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
const
submitted
=
findEvent
(
STAGE_ACTIONS
.
UPDATE
)[
0
];
expect
(
submitted
).
not
.
toEqual
([
formInitialData
]);
expect
(
submitted
).
toEqual
([
convertObjectPropsToSnakeCase
({
...
formInitialData
,
name
:
'
Cool updated form
'
}),
]);
});
});
describe
(
'
isSavingCustomStage=true
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
initialState
:
{
isEditingCustomStage
:
true
,
isSavingCustomStage
:
true
},
});
});
it
(
'
displays a loading icon
'
,
()
=>
{
expect
(
findSubmitButton
().
html
()).
toMatchSnapshot
();
});
});
});
describe
(
'
With initial errors
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
initialState
:
{
formErrors
:
customStageFormErrors
,
},
});
});
it
(
'
renders the errors for the relevant fields
'
,
()
=>
{
expect
(
findFieldErrors
(
'
name
'
)).
toEqual
([
'
is reserved
'
,
'
cant be blank
'
]);
expect
(
findFieldErrors
(
'
startEventIdentifier
'
)).
toEqual
([
'
cant be blank
'
]);
});
});
describe
(
'
recover stage dropdown
'
,
()
=>
{
describe
(
'
without hidden stages
'
,
()
=>
{
it
(
'
has the recover stage dropdown
'
,
()
=>
{
expect
(
findRecoverStageDropdown
().
exists
()).
toBe
(
true
);
});
it
(
'
has no stages available to recover
'
,
async
()
=>
{
expect
(
findRecoverStageDropdown
().
text
()).
toContain
(
'
All default stages are currently visible
'
,
);
});
});
describe
(
'
with hidden stages
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
initialRootGetters
:
{
hiddenStages
:
()
=>
[
{
id
:
'
my-stage
'
,
title
:
'
My default stage
'
,
hidden
:
true
,
},
],
},
});
});
it
(
'
has stages available to recover
'
,
async
()
=>
{
const
txt
=
findRecoverStageDropdown
().
text
();
expect
(
txt
).
not
.
toContain
(
'
All default stages are currently visible
'
);
expect
(
txt
).
toContain
(
'
My default stage
'
);
});
it
(
`emits the
${
STAGE_ACTIONS
.
UPDATE
}
action when clicking on a stage to recover`
,
async
()
=>
{
findRecoverStageDropdown
().
find
(
GlDropdownItem
).
vm
.
$emit
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
emitted
()).
toEqual
({
[
STAGE_ACTIONS
.
UPDATE
]:
[[{
hidden
:
false
,
id
:
'
my-stage
'
}]],
});
});
});
});
});
locale/gitlab.pot
View file @
2f83d038
...
...
@@ -860,9 +860,6 @@ msgstr ""
msgid "%{strongStart}Deletes%{strongEnd} source branch"
msgstr ""
msgid "%{strongStart}Note:%{strongEnd} Once a custom stage has been added you can re-order stages by dragging them into the desired position."
msgstr ""
msgid "%{strongStart}Tip:%{strongEnd} You can also checkout merge requests locally by %{linkStart}following these guidelines%{linkEnd}"
msgstr ""
...
...
@@ -9774,24 +9771,6 @@ msgstr ""
msgid "Custom range (UTC)"
msgstr ""
msgid "CustomCycleAnalytics|Add a stage"
msgstr ""
msgid "CustomCycleAnalytics|Add stage"
msgstr ""
msgid "CustomCycleAnalytics|Editing stage"
msgstr ""
msgid "CustomCycleAnalytics|End event label"
msgstr ""
msgid "CustomCycleAnalytics|Stage name already exists"
msgstr ""
msgid "CustomCycleAnalytics|Start event label"
msgstr ""
msgid "Customer Portal"
msgstr ""
...
...
@@ -11899,9 +11878,6 @@ msgstr ""
msgid "Edit sidebar"
msgstr ""
msgid "Edit stage"
msgstr ""
msgid "Edit this file only."
msgstr ""
...
...
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