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
be3adf55
Commit
be3adf55
authored
Jun 23, 2021
by
Simon Knox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add button to delete iteration cadences
In a confirmation modal
parent
669b4712
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
163 additions
and
16 deletions
+163
-16
ee/app/assets/javascripts/iterations/components/iteration_cadence_list_item.vue
...pts/iterations/components/iteration_cadence_list_item.vue
+31
-1
ee/app/assets/javascripts/iterations/components/iteration_cadences_list.vue
...scripts/iterations/components/iteration_cadences_list.vue
+37
-0
ee/app/assets/javascripts/iterations/index.js
ee/app/assets/javascripts/iterations/index.js
+1
-1
ee/app/assets/javascripts/iterations/queries/destroy_cadence.mutation.graphql
...ripts/iterations/queries/destroy_cadence.mutation.graphql
+5
-0
ee/app/assets/javascripts/iterations/router.js
ee/app/assets/javascripts/iterations/router.js
+1
-1
ee/spec/frontend/iterations/components/iteration_cadence_list_item_spec.js
...iterations/components/iteration_cadence_list_item_spec.js
+41
-1
ee/spec/frontend/iterations/components/iteration_cadences_list_spec.js
...end/iterations/components/iteration_cadences_list_spec.js
+38
-12
locale/gitlab.pot
locale/gitlab.pot
+9
-0
No files found.
ee/app/assets/javascripts/iterations/components/iteration_cadence_list_item.vue
View file @
be3adf55
...
...
@@ -7,6 +7,7 @@ import {
GlDropdownItem
,
GlIcon
,
GlInfiniteScroll
,
GlModal
,
GlSkeletonLoader
,
}
from
'
@gitlab/ui
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
...
...
@@ -18,6 +19,14 @@ const pageSize = 20;
const
i18n
=
Object
.
freeze
({
noResults
:
s__
(
'
Iterations|No iterations in cadence.
'
),
error
:
__
(
'
Error loading iterations
'
),
deleteCadence
:
s__
(
'
Iterations|Delete cadence
'
),
modalTitle
:
s__
(
'
Iterations|Delete iteration cadence?
'
),
modalText
:
s__
(
'
Iterations|This will delete the cadence as well as all of the iterations within it.
'
,
),
modalConfirm
:
s__
(
'
Iterations|Delete cadence
'
),
modalCancel
:
__
(
'
Cancel
'
),
});
export
default
{
...
...
@@ -30,6 +39,7 @@ export default {
GlDropdownItem
,
GlIcon
,
GlInfiniteScroll
,
GlModal
,
GlSkeletonLoader
,
},
apollo
:
{
...
...
@@ -154,6 +164,12 @@ export default {
},
};
},
showModal
()
{
this
.
$refs
.
modal
.
show
();
},
focusMenu
()
{
this
.
$refs
.
menu
.
$el
.
focus
();
},
},
};
</
script
>
...
...
@@ -181,17 +197,31 @@ export default {
>
<gl-dropdown
v-if=
"canEditCadence"
ref=
"menu"
icon=
"ellipsis_v"
category=
"tertiary"
right
lazy
text-sr-only
no-caret
>
<gl-dropdown-item
:to=
"editCadence"
>
{{
s__
(
'
Iterations|Edit cadence
'
)
}}
</gl-dropdown-item>
<gl-dropdown-item
data-testid=
"delete-cadence"
@
click=
"showModal"
>
{{
i18n
.
deleteCadence
}}
</gl-dropdown-item>
</gl-dropdown>
<gl-modal
ref=
"modal"
:modal-id=
"`$
{cadenceId}-delete-modal`"
:title="i18n.modalTitle"
:ok-title="i18n.modalConfirm"
ok-variant="danger"
@hidden="focusMenu"
@ok="$emit('delete-cadence', cadenceId)"
>
{{
i18n
.
modalText
}}
</gl-modal>
</div>
<gl-alert
v-if=
"error"
variant=
"danger"
:dismissible=
"true"
@
dismiss=
"error = ''"
>
...
...
ee/app/assets/javascripts/iterations/components/iteration_cadences_list.vue
View file @
be3adf55
<
script
>
import
{
GlAlert
,
GlButton
,
GlLoadingIcon
,
GlKeysetPagination
,
GlTab
,
GlTabs
}
from
'
@gitlab/ui
'
;
import
produce
from
'
immer
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
import
destroyIterationCadence
from
'
../queries/destroy_cadence.mutation.graphql
'
;
import
query
from
'
../queries/iteration_cadences_list.query.graphql
'
;
import
IterationCadenceListItem
from
'
./iteration_cadence_list_item.vue
'
;
...
...
@@ -96,6 +98,40 @@ export default {
handleTabChange
()
{
this
.
pagination
=
{};
},
deleteCadence
(
cadenceId
)
{
this
.
$apollo
.
mutate
({
mutation
:
destroyIterationCadence
,
variables
:
{
id
:
cadenceId
,
},
update
:
(
store
,
{
data
:
{
iterationCadenceDestroy
}
})
=>
{
if
(
iterationCadenceDestroy
.
errors
?.
length
)
{
throw
iterationCadenceDestroy
.
errors
[
0
];
}
const
sourceData
=
store
.
readQuery
({
query
,
variables
:
this
.
queryVariables
,
});
const
data
=
produce
(
sourceData
,
(
draftData
)
=>
{
draftData
.
group
.
iterationCadences
.
nodes
=
draftData
.
group
.
iterationCadences
.
nodes
.
filter
(
({
id
})
=>
id
!==
cadenceId
,
);
});
store
.
writeQuery
({
query
,
variables
:
this
.
queryVariables
,
data
,
});
},
})
.
catch
((
err
)
=>
{
this
.
error
=
err
;
});
},
},
};
</
script
>
...
...
@@ -122,6 +158,7 @@ export default {
:duration-in-weeks=
"cadence.durationInWeeks"
:title=
"cadence.title"
:iteration-state=
"state"
@
delete-cadence=
"deleteCadence"
/>
</ul>
<p
v-else
class=
"nothing-here-block"
>
...
...
ee/app/assets/javascripts/iterations/index.js
View file @
be3adf55
...
...
@@ -113,7 +113,7 @@ export function initCadenceApp({ namespaceType }) {
previewMarkdownPath
,
noIssuesSvgPath
,
}
=
el
.
dataset
;
const
router
=
createRouter
(
cadencesListPath
);
const
router
=
createRouter
(
{
base
:
cadencesListPath
}
);
return
new
Vue
({
el
,
...
...
ee/app/assets/javascripts/iterations/queries/destroy_cadence.mutation.graphql
0 → 100644
View file @
be3adf55
mutation
destroyIterationCadence
(
$id
:
IterationsCadenceID
!)
{
iterationCadenceDestroy
(
input
:
{
id
:
$id
})
{
errors
}
}
ee/app/assets/javascripts/iterations/router.js
View file @
be3adf55
...
...
@@ -29,7 +29,7 @@ const routes = [
},
];
export
default
function
createRouter
(
base
)
{
export
default
function
createRouter
(
{
base
}
)
{
const
router
=
new
VueRouter
({
base
,
mode
:
'
history
'
,
...
...
ee/spec/frontend/iterations/components/iteration_cadence_list_item_spec.js
View file @
be3adf55
import
{
GlDropdown
,
GlInfiniteScroll
,
GlSkeletonLoader
}
from
'
@gitlab/ui
'
;
import
{
GlDropdown
,
GlInfiniteScroll
,
Gl
Modal
,
Gl
SkeletonLoader
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
,
RouterLinkStub
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
...
...
@@ -188,6 +188,46 @@ describe('Iteration cadence list item', () => {
);
});
describe
(
'
deleting cadence
'
,
()
=>
{
describe
(
'
canEditCadence = false
'
,
()
=>
{
beforeEach
(
async
()
=>
{
await
createComponent
({
canEditCadence
:
false
,
});
});
it
(
'
hides dropdown and delete button
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlDropdown
).
exists
()).
toBe
(
false
);
});
});
describe
(
'
canEditCadence = true
'
,
()
=>
{
beforeEach
(
async
()
=>
{
createComponent
({
canEditCadence
:
true
,
});
wrapper
.
vm
.
$refs
.
modal
.
show
=
jest
.
fn
();
});
it
(
'
shows delete button
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlDropdown
).
exists
()).
toBe
(
true
);
});
it
(
'
opens confirmation modal to delete cadence
'
,
()
=>
{
wrapper
.
findByTestId
(
'
delete-cadence
'
).
trigger
(
'
click
'
);
expect
(
wrapper
.
vm
.
$refs
.
modal
.
show
).
toHaveBeenCalled
();
});
it
(
'
emits delete-cadence event with cadence ID
'
,
()
=>
{
wrapper
.
find
(
GlModal
).
vm
.
$emit
(
'
ok
'
);
expect
(
wrapper
.
emitted
(
'
delete-cadence
'
)).
toEqual
([[
cadence
.
id
]]);
});
});
});
it
(
'
hides dropdown when canEditCadence is false
'
,
async
()
=>
{
await
createComponent
({
canEditCadence
:
false
});
...
...
ee/spec/frontend/iterations/components/iteration_cadences_list_spec.js
View file @
be3adf55
...
...
@@ -2,20 +2,21 @@ import { GlKeysetPagination, GlLoadingIcon } from '@gitlab/ui';
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
IterationCadenceListItem
from
'
ee/iterations/components/iteration_cadence_list_item.vue
'
;
import
IterationCadencesList
from
'
ee/iterations/components/iteration_cadences_list.vue
'
;
import
destroyIterationCadence
from
'
ee/iterations/queries/destroy_cadence.mutation.graphql
'
;
import
cadencesListQuery
from
'
ee/iterations/queries/iteration_cadences_list.query.graphql
'
;
import
createRouter
from
'
ee/iterations/router
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
{
TEST_HOST
}
from
'
helpers/test_constants
'
;
import
{
mountExtended
as
mount
}
from
'
helpers/vue_test_utils_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
const
push
=
jest
.
fn
();
const
$router
=
{
push
,
};
const
localVue
=
createLocalVue
();
const
baseUrl
=
'
/cadences/
'
;
const
router
=
createRouter
(
baseUrl
);
function
createMockApolloProvider
(
requestHandlers
)
{
localVue
.
use
(
VueApollo
);
...
...
@@ -84,15 +85,19 @@ describe('Iteration cadences list', () => {
canCreateCadence
,
canEditCadence
,
resolverMock
=
jest
.
fn
().
mockResolvedValue
(
querySuccessResponse
),
destroyMutationMock
=
jest
.
fn
()
.
mockResolvedValue
({
data
:
{
iterationCadenceDestroy
:
{
errors
:
[]
}
}
}),
}
=
{})
{
apolloProvider
=
createMockApolloProvider
([[
cadencesListQuery
,
resolverMock
]]);
apolloProvider
=
createMockApolloProvider
([
[
cadencesListQuery
,
resolverMock
],
[
destroyIterationCadence
,
destroyMutationMock
],
]);
wrapper
=
mount
(
IterationCadencesList
,
{
localVue
,
apolloProvider
,
mocks
:
{
$router
,
},
router
,
provide
:
{
groupPath
,
cadencesListPath
,
...
...
@@ -184,9 +189,9 @@ describe('Iteration cadences list', () => {
resolverMock
.
mockReset
();
});
it
(
'
correctly disables pagination buttons
'
,
async
()
=>
{
expect
(
findNextPageButton
().
element
.
disabled
).
toBe
(
false
);
expect
(
findPrevPageButton
().
element
.
disabled
).
toBe
(
true
);
it
(
'
correctly disables pagination buttons
'
,
()
=>
{
expect
(
findNextPageButton
().
element
).
not
.
toBeDisabled
(
);
expect
(
findPrevPageButton
().
element
).
toBeDisabled
(
);
});
it
(
'
updates query when next page clicked
'
,
async
()
=>
{
...
...
@@ -215,5 +220,26 @@ describe('Iteration cadences list', () => {
);
});
});
describe
(
'
deleting cadence
'
,
()
=>
{
it
(
'
removes item from list
'
,
async
()
=>
{
await
createComponent
({
canEditCadence
:
true
,
});
await
waitForPromises
();
// 3 cadences * 3 tabs, so 9 in total
expect
(
wrapper
.
findAllComponents
(
IterationCadenceListItem
).
length
).
toBe
(
9
);
expect
(
wrapper
.
text
()).
toContain
(
cadences
[
0
].
title
);
wrapper
.
findComponent
(
IterationCadenceListItem
).
vm
.
$emit
(
'
delete-cadence
'
,
cadences
[
0
].
id
);
await
waitForPromises
();
expect
(
wrapper
.
findAllComponents
(
IterationCadenceListItem
).
length
).
toBe
(
6
);
expect
(
wrapper
.
text
()).
not
.
toContain
(
cadences
[
0
].
title
);
});
});
});
});
locale/gitlab.pot
View file @
be3adf55
...
...
@@ -18238,6 +18238,12 @@ msgstr ""
msgid "Iterations|Create cadence"
msgstr ""
msgid "Iterations|Delete cadence"
msgstr ""
msgid "Iterations|Delete iteration cadence?"
msgstr ""
msgid "Iterations|Duration"
msgstr ""
...
...
@@ -18295,6 +18301,9 @@ msgstr ""
msgid "Iterations|The start date of your first iteration"
msgstr ""
msgid "Iterations|This will delete the cadence as well as all of the iterations within it."
msgstr ""
msgid "Iterations|Title"
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