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
9a23bf3f
Commit
9a23bf3f
authored
Mar 03, 2022
by
Paul Slaughter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resolve EE/CE duplication in invite_modal_base
-
https://gitlab.com/gitlab-org/gitlab/-/issues/354003
parent
90c7f9f1
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
287 additions
and
423 deletions
+287
-423
app/assets/javascripts/invite_members/components/invite_modal_base.vue
...vascripts/invite_members/components/invite_modal_base.vue
+117
-68
app/assets/javascripts/vue_shared/components/content_transition.vue
.../javascripts/vue_shared/components/content_transition.vue
+32
-0
ee/app/assets/javascripts/invite_members/components/invite_modal_base.vue
...vascripts/invite_members/components/invite_modal_base.vue
+73
-269
ee/spec/frontend/invite_members/components/invite_modal_base_spec.js
...ntend/invite_members/components/invite_modal_base_spec.js
+59
-86
spec/frontend/invite_members/components/invite_groups_modal_spec.js
...end/invite_members/components/invite_groups_modal_spec.js
+2
-0
spec/frontend/invite_members/components/invite_members_modal_spec.js
...nd/invite_members/components/invite_members_modal_spec.js
+2
-0
spec/frontend/invite_members/components/invite_modal_base_spec.js
...ntend/invite_members/components/invite_modal_base_spec.js
+2
-0
No files found.
app/assets/javascripts/invite_members/components/invite_modal_base.vue
View file @
9a23bf3f
...
@@ -11,6 +11,7 @@ import {
...
@@ -11,6 +11,7 @@ import {
GlFormInput
,
GlFormInput
,
}
from
'
@gitlab/ui
'
;
}
from
'
@gitlab/ui
'
;
import
{
sprintf
}
from
'
~/locale
'
;
import
{
sprintf
}
from
'
~/locale
'
;
import
ContentTransition
from
'
~/vue_shared/components/content_transition.vue
'
;
import
{
import
{
ACCESS_LEVEL
,
ACCESS_LEVEL
,
ACCESS_EXPIRE_DATE
,
ACCESS_EXPIRE_DATE
,
...
@@ -20,6 +21,17 @@ import {
...
@@ -20,6 +21,17 @@ import {
HEADER_CLOSE_LABEL
,
HEADER_CLOSE_LABEL
,
}
from
'
../constants
'
;
}
from
'
../constants
'
;
const
DEFAULT_SLOT
=
'
default
'
;
const
DEFAULT_SLOTS
=
[
{
key
:
DEFAULT_SLOT
,
attributes
:
{
class
:
'
invite-modal-content
'
,
'
data-testid
'
:
'
invite-modal-initial-content
'
,
},
},
];
export
default
{
export
default
{
components
:
{
components
:
{
GlFormGroup
,
GlFormGroup
,
...
@@ -31,6 +43,7 @@ export default {
...
@@ -31,6 +43,7 @@ export default {
GlSprintf
,
GlSprintf
,
GlButton
,
GlButton
,
GlFormInput
,
GlFormInput
,
ContentTransition
,
},
},
inheritAttrs
:
false
,
inheritAttrs
:
false
,
props
:
{
props
:
{
...
@@ -86,6 +99,21 @@ export default {
...
@@ -86,6 +99,21 @@ export default {
required
:
false
,
required
:
false
,
default
:
''
,
default
:
''
,
},
},
submitButtonText
:
{
type
:
String
,
required
:
false
,
default
:
INVITE_BUTTON_TEXT
,
},
currentSlot
:
{
type
:
String
,
required
:
false
,
default
:
DEFAULT_SLOT
,
},
extraSlots
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
},
},
data
()
{
data
()
{
// Be sure to check out reset!
// Be sure to check out reset!
...
@@ -110,6 +138,9 @@ export default {
...
@@ -110,6 +138,9 @@ export default {
(
key
)
=>
this
.
accessLevels
[
key
]
===
Number
(
this
.
selectedAccessLevel
),
(
key
)
=>
this
.
accessLevels
[
key
]
===
Number
(
this
.
selectedAccessLevel
),
);
);
},
},
contentSlots
()
{
return
[...
DEFAULT_SLOTS
,
...(
this
.
extraSlots
||
[])];
},
},
},
watch
:
{
watch
:
{
selectedAccessLevel
:
{
selectedAccessLevel
:
{
...
@@ -148,6 +179,7 @@ export default {
...
@@ -148,6 +179,7 @@ export default {
READ_MORE_TEXT
,
READ_MORE_TEXT
,
INVITE_BUTTON_TEXT
,
INVITE_BUTTON_TEXT
,
CANCEL_BUTTON_TEXT
,
CANCEL_BUTTON_TEXT
,
DEFAULT_SLOT
,
};
};
</
script
>
</
script
>
...
@@ -164,6 +196,13 @@ export default {
...
@@ -164,6 +196,13 @@ export default {
@
close=
"reset"
@
close=
"reset"
@
hide=
"reset"
@
hide=
"reset"
>
>
<content-transition
class=
"gl-display-grid"
transition-name=
"invite-modal-transition"
:slots=
"contentSlots"
:current-slot=
"currentSlot"
>
<template
#
[$
options
.
DEFAULT_SLOT
]
>
<div
class=
"gl-display-flex"
data-testid=
"modal-base-intro-text"
>
<div
class=
"gl-display-flex"
data-testid=
"modal-base-intro-text"
>
<slot
name=
"intro-text-before"
></slot>
<slot
name=
"intro-text-before"
></slot>
<p>
<p>
...
@@ -227,16 +266,26 @@ export default {
...
@@ -227,16 +266,26 @@ export default {
:target=
"null"
:target=
"null"
>
>
<
template
#default=
"{ formattedDate }"
>
<
template
#default=
"{ formattedDate }"
>
<gl-form-input
class=
"gl-w-full"
:value=
"formattedDate"
:placeholder=
"__(`YYYY-MM-DD`)"
/>
<gl-form-input
class=
"gl-w-full"
:value=
"formattedDate"
:placeholder=
"__(`YYYY-MM-DD`)"
/>
</
template
>
</
template
>
</gl-datepicker>
</gl-datepicker>
</div>
</div>
<slot
name=
"form-after"
></slot>
<slot
name=
"form-after"
></slot>
</template>
<
template
v-for=
"{ key } in extraSlots"
#
[
key
]
>
<slot
:name=
"key"
></slot>
</
template
>
</content-transition>
<
template
#modal-footer
>
<
template
#modal-footer
>
<slot
name=
"cancel-button"
>
<gl-button
data-testid=
"cancel-button"
@
click=
"closeModal"
>
<gl-button
data-testid=
"cancel-button"
@
click=
"closeModal"
>
{{
$options
.
CANCEL_BUTTON_TEXT
}}
{{
$options
.
CANCEL_BUTTON_TEXT
}}
</gl-button>
</gl-button>
</slot>
<gl-button
<gl-button
:disabled=
"submitDisabled"
:disabled=
"submitDisabled"
:loading=
"isLoading"
:loading=
"isLoading"
...
@@ -245,7 +294,7 @@ export default {
...
@@ -245,7 +294,7 @@ export default {
data-testid=
"invite-button"
data-testid=
"invite-button"
@
click=
"submit"
@
click=
"submit"
>
>
{{
$options
.
INVITE_BUTTON_TEXT
}}
{{
submitButtonText
}}
</gl-button>
</gl-button>
</
template
>
</
template
>
</gl-modal>
</gl-modal>
...
...
app/assets/javascripts/vue_shared/components/content_transition.vue
0 → 100644
View file @
9a23bf3f
<
script
>
export
default
{
props
:
{
currentSlot
:
{
type
:
String
,
required
:
true
,
},
slots
:
{
type
:
Array
,
required
:
true
,
},
transitionName
:
{
type
:
String
,
required
:
true
,
},
},
methods
:
{
shouldShow
(
key
)
{
return
this
.
currentSlot
===
key
;
},
},
};
</
script
>
<
template
>
<div>
<transition
v-for=
"
{ key, attributes } in slots" :key="key" :name="transitionName">
<div
v-show=
"shouldShow(key)"
v-bind=
"attributes"
>
<slot
:name=
"key"
></slot>
</div>
</transition>
</div>
</
template
>
ee/app/assets/javascripts/invite_members/components/invite_modal_base.vue
View file @
9a23bf3f
<
script
>
<
script
>
import
{
import
{
GlLink
,
GlButton
}
from
'
@gitlab/ui
'
;
GlFormGroup
,
GlModal
,
GlDropdown
,
GlDropdownItem
,
GlDatepicker
,
GlLink
,
GlSprintf
,
GlButton
,
GlFormInput
,
}
from
'
@gitlab/ui
'
;
import
{
sprintf
}
from
'
~/locale
'
;
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
{
import
InviteModalBase
from
'
~/invite_members/components/invite_modal_base.vue
'
;
ACCESS_LEVEL
,
ACCESS_EXPIRE_DATE
,
READ_MORE_TEXT
,
INVITE_BUTTON_TEXT
,
CANCEL_BUTTON_TEXT
,
HEADER_CLOSE_LABEL
,
}
from
'
~/invite_members/constants
'
;
import
{
import
{
OVERAGE_MODAL_LINK
,
OVERAGE_MODAL_LINK
,
OVERAGE_MODAL_TITLE
,
OVERAGE_MODAL_TITLE
,
...
@@ -30,73 +12,34 @@ import {
...
@@ -30,73 +12,34 @@ import {
overageModalInfoWarning
,
overageModalInfoWarning
,
}
from
'
../constants
'
;
}
from
'
../constants
'
;
const
OVERAGE_CONTENT_SLOT
=
'
overage-content
'
;
const
EXTRA_SLOTS
=
[
{
key
:
OVERAGE_CONTENT_SLOT
,
attributes
:
{
class
:
'
invite-modal-content
'
,
'
data-testid
'
:
'
invite-modal-overage-content
'
,
},
},
];
export
default
{
export
default
{
components
:
{
components
:
{
GlFormGroup
,
GlDatepicker
,
GlLink
,
GlLink
,
GlModal
,
GlDropdown
,
GlDropdownItem
,
GlSprintf
,
GlButton
,
GlButton
,
GlFormInput
,
InviteModalBase
,
},
},
mixins
:
[
glFeatureFlagsMixin
()],
mixins
:
[
glFeatureFlagsMixin
()],
inheritAttrs
:
false
,
inheritAttrs
:
false
,
props
:
{
props
:
{
modalTitle
:
{
type
:
String
,
required
:
true
,
},
modalId
:
{
type
:
String
,
required
:
true
,
},
name
:
{
name
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
},
},
accessLevels
:
{
modalTitle
:
{
type
:
Object
,
required
:
true
,
},
defaultAccessLevel
:
{
type
:
Number
,
required
:
true
,
},
helpLink
:
{
type
:
String
,
required
:
true
,
},
labelIntroText
:
{
type
:
String
,
required
:
true
,
},
labelSearchField
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
},
},
formGroupDescription
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
submitDisabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isLoading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
invalidFeedbackMessage
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
subscriptionSeats
:
{
subscriptionSeats
:
{
type
:
Number
,
type
:
Number
,
required
:
false
,
required
:
false
,
...
@@ -104,29 +47,19 @@ export default {
...
@@ -104,29 +47,19 @@ export default {
},
},
},
},
data
()
{
data
()
{
// Be sure to check out reset!
return
{
return
{
selectedAccessLevel
:
this
.
defaultAccessLevel
,
selectedDate
:
undefined
,
minDate
:
new
Date
(),
hasOverage
:
false
,
hasOverage
:
false
,
totalUserCount
:
null
,
totalUserCount
:
null
,
};
};
},
},
computed
:
{
computed
:
{
introText
()
{
currentSlot
()
{
return
sprintf
(
this
.
labelIntroText
,
{
name
:
this
.
name
});
if
(
this
.
showOverageModal
)
{
},
return
OVERAGE_CONTENT_SLOT
;
validationState
()
{
}
return
this
.
invalidFeedbackMessage
?
false
:
null
;
},
// Use CE default
selectLabelId
()
{
return
undefined
;
return
`
${
this
.
modalId
}
_select`
;
},
selectedRoleName
()
{
return
Object
.
keys
(
this
.
accessLevels
).
find
(
(
key
)
=>
this
.
accessLevels
[
key
]
===
Number
(
this
.
selectedAccessLevel
),
);
},
},
showOverageModal
()
{
showOverageModal
()
{
return
this
.
hasOverage
&&
this
.
enabledOverageCheck
;
return
this
.
hasOverage
&&
this
.
enabledOverageCheck
;
...
@@ -136,220 +69,91 @@ export default {
...
@@ -136,220 +69,91 @@ export default {
},
},
modalInfo
()
{
modalInfo
()
{
if
(
this
.
totalUserCount
)
{
if
(
this
.
totalUserCount
)
{
const
infoText
=
this
.
$options
.
i18n
.
i
nfoText
(
this
.
subscriptionSeats
);
const
infoText
=
overageModalI
nfoText
(
this
.
subscriptionSeats
);
const
infoWarning
=
this
.
$options
.
i18n
.
i
nfoWarning
(
this
.
totalUserCount
,
this
.
name
);
const
infoWarning
=
overageModalI
nfoWarning
(
this
.
totalUserCount
,
this
.
name
);
return
`
${
infoText
}
${
infoWarning
}
`
;
return
`
${
infoText
}
${
infoWarning
}
`
;
}
}
return
''
;
return
''
;
},
},
modalTitleLabel
()
{
modalTitleOverride
()
{
return
this
.
showOverageModal
?
this
.
$options
.
i18n
.
OVERAGE_MODAL_TITLE
:
this
.
modalTitle
;
return
this
.
showOverageModal
?
OVERAGE_MODAL_TITLE
:
this
.
modalTitle
;
},
},
watch
:
{
selectedAccessLevel
:
{
immediate
:
true
,
handler
(
val
)
{
this
.
$emit
(
'
access-level
'
,
val
);
},
},
submitButtonText
()
{
if
(
this
.
showOverageModal
)
{
return
OVERAGE_MODAL_CONTINUE_BUTTON
;
}
// Use CE default
return
undefined
;
},
},
},
},
methods
:
{
methods
:
{
reset
()
{
getPassthroughListeners
()
{
// This component isn't necessarily disposed,
// This gets the listeners we don't manually handle here
// so we might need to reset it's state.
// so we can pass them through to the CE invite_modal_base.vue
this
.
selectedAccessLevel
=
this
.
defaultAccessLevel
;
const
{
reset
,
submit
,
...
listeners
}
=
this
.
$listeners
;
this
.
selectedDate
=
undefined
;
return
listeners
;
},
onReset
(...
args
)
{
// don't reopen the overage modal
// don't reopen the overage modal
this
.
hasOverage
=
false
;
this
.
hasOverage
=
false
;
this
.
$emit
(
'
reset
'
);
this
.
$emit
(
'
reset
'
,
...
args
);
},
closeModal
()
{
this
.
reset
();
this
.
$refs
.
modal
.
hide
();
},
changeSelectedItem
(
item
)
{
this
.
selectedAccessLevel
=
item
;
},
},
submit
()
{
onSubmit
(...
args
)
{
this
.
$emit
(
'
submit
'
,
{
if
(
this
.
enabledOverageCheck
&&
!
this
.
hasOverage
)
{
accessLevel
:
this
.
selectedAccessLevel
,
expiresAt
:
this
.
selectedDate
,
});
},
checkOverage
()
{
// add a more complex check in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78287
// totalUserCount should be calculated there
if
(
this
.
enabledOverageCheck
)
{
this
.
totalUserCount
=
1
;
this
.
totalUserCount
=
1
;
this
.
hasOverage
=
true
;
this
.
hasOverage
=
true
;
}
else
{
}
else
{
this
.
submit
(
);
this
.
$emit
(
'
submit
'
,
...
args
);
}
}
},
},
handleBack
()
{
handleBack
()
{
this
.
hasOverage
=
false
;
this
.
hasOverage
=
false
;
},
},
passthroughSlotNames
()
{
return
Object
.
keys
(
this
.
$scopedSlots
||
{});
},
},
},
i18n
:
{
i18n
:
{
HEADER_CLOSE_LABEL
,
ACCESS_EXPIRE_DATE
,
ACCESS_LEVEL
,
READ_MORE_TEXT
,
INVITE_BUTTON_TEXT
,
CANCEL_BUTTON_TEXT
,
OVERAGE_MODAL_TITLE
,
OVERAGE_MODAL_TITLE
,
OVERAGE_MODAL_LINK
,
OVERAGE_MODAL_LINK
,
OVERAGE_MODAL_BACK_BUTTON
,
OVERAGE_MODAL_BACK_BUTTON
,
OVERAGE_MODAL_CONTINUE_BUTTON
,
OVERAGE_MODAL_CONTINUE_BUTTON
,
OVERAGE_MODAL_LINK_TEXT
,
OVERAGE_MODAL_LINK_TEXT
,
infoText
:
overageModalInfoText
,
infoWarning
:
overageModalInfoWarning
,
},
},
OVERAGE_CONTENT_SLOT
,
EXTRA_SLOTS
,
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<gl-modal
<invite-modal-base
ref=
"modal"
:modal-id=
"modalId"
data-qa-selector=
"invite_members_modal_content"
data-testid=
"invite-modal"
size=
"sm"
:title=
"modalTitleLabel"
:header-close-label=
"$options.i18n.HEADER_CLOSE_LABEL"
@
hidden=
"reset"
@
close=
"reset"
@
hide=
"reset"
>
<div
class=
"gl-display-grid"
>
<transition
name=
"invite-modal-transition"
>
<div
v-show=
"!showOverageModal"
class=
"invite-modal-content"
data-testid=
"invite-modal-initial-content"
>
<div
class=
"gl-display-flex"
data-testid=
"modal-base-intro-text"
>
<slot
name=
"intro-text-before"
></slot>
<p>
<gl-sprintf
:message=
"introText"
>
<template
#strong
="
{ content }">
<strong>
{{
content
}}
</strong>
</
template
>
</gl-sprintf>
</p>
<slot
name=
"intro-text-after"
></slot>
</div>
<gl-form-group
:invalid-feedback=
"invalidFeedbackMessage"
:state=
"validationState"
:description=
"formGroupDescription"
data-testid=
"members-form-group"
>
<label
:id=
"selectLabelId"
class=
"col-form-label"
>
{{ labelSearchField }}
</label>
<slot
name=
"select"
v-bind=
"{ validationState, labelId: selectLabelId }"
></slot>
</gl-form-group>
<label
class=
"gl-font-weight-bold"
>
{{ $options.i18n.ACCESS_LEVEL }}
</label>
<div
class=
"gl-mt-2 gl-w-half gl-xs-w-full"
>
<gl-dropdown
class=
"gl-shadow-none gl-w-full"
data-qa-selector=
"access_level_dropdown"
v-bind=
"$attrs"
v-bind=
"$attrs"
:text=
"selectedRoleName"
:name=
"name"
>
:submit-button-text=
"submitButtonText"
<
template
v-for=
"(key, item) in accessLevels"
>
:modal-title=
"modalTitleOverride"
<gl-dropdown-item
:current-slot=
"currentSlot"
:key=
"key"
:extra-slots=
"$options.EXTRA_SLOTS"
active-class=
"is-active"
@
reset=
"onReset"
is-check-item
@
submit=
"onSubmit"
:is-checked=
"key === selectedAccessLevel"
v-on=
"getPassthroughListeners()"
@
click=
"changeSelectedItem(key)"
>
<div>
{{
item
}}
</div>
</gl-dropdown-item>
</
template
>
</gl-dropdown>
</div>
<div
class=
"gl-mt-2 gl-w-half gl-xs-w-full"
>
<gl-sprintf
:message=
"$options.i18n.READ_MORE_TEXT"
>
<
template
#link=
"{ content }"
>
<gl-link
:href=
"helpLink"
target=
"_blank"
>
{{
content
}}
</gl-link>
</
template
>
</gl-sprintf>
</div>
<label
class=
"gl-mt-5 gl-display-block"
for=
"expires_at"
>
{{
$options.i18n.ACCESS_EXPIRE_DATE
}}
</label>
<div
class=
"gl-mt-2 gl-w-half gl-xs-w-full gl-display-inline-block"
>
<gl-datepicker
v-model=
"selectedDate"
class=
"gl-display-inline!"
:min-date=
"minDate"
:target=
"null"
>
<
template
#default=
"{ formattedDate }"
>
<gl-form-input
class=
"gl-w-full"
:value=
"formattedDate"
:placeholder=
"__(`YYYY-MM-DD`)"
/>
</
template
>
</gl-datepicker>
</div>
<slot
name=
"form-after"
></slot>
</div>
</transition>
<transition
name=
"invite-modal-transition"
>
<div
v-show=
"showOverageModal"
class=
"invite-modal-content"
data-testid=
"invite-modal-overage-content"
>
>
<template
#
[$
options
.
OVERAGE_CONTENT_SLOT
]
>
{{
modalInfo
}}
{{
modalInfo
}}
<gl-link
:href=
"$options.i18n.OVERAGE_MODAL_LINK"
target=
"_blank"
>
{{
<gl-link
:href=
"$options.i18n.OVERAGE_MODAL_LINK"
target=
"_blank"
>
{{
$options
.
i18n
.
OVERAGE_MODAL_LINK_TEXT
$options
.
i18n
.
OVERAGE_MODAL_LINK_TEXT
}}
</gl-link>
}}
</gl-link>
</div>
</transition>
</div>
<
template
#modal-footer
>
<template
v-if=
"!showOverageModal"
>
<gl-button
data-testid=
"cancel-button"
@
click=
"closeModal"
>
{{
$options
.
i18n
.
CANCEL_BUTTON_TEXT
}}
</gl-button>
<gl-button
:disabled=
"submitDisabled"
:loading=
"isLoading"
variant=
"confirm"
data-qa-selector=
"invite_button"
data-testid=
"invite-button"
@
click=
"checkOverage"
>
{{
$options
.
i18n
.
INVITE_BUTTON_TEXT
}}
</gl-button>
</
template
>
</
template
>
<
template
v-else
>
<
template
v-if=
"enabledOverageCheck && hasOverage"
#cancel-button
>
<gl-button
data-testid=
"overage-back-button"
@
click=
"handleBack"
>
<gl-button
data-testid=
"overage-back-button"
@
click=
"handleBack"
>
{{
$options
.
i18n
.
OVERAGE_MODAL_BACK_BUTTON
}}
{{
$options
.
i18n
.
OVERAGE_MODAL_BACK_BUTTON
}}
</gl-button>
</gl-button>
<gl-button
:disabled=
"submitDisabled"
:loading=
"isLoading"
variant=
"confirm"
data-qa-selector=
"invite_with_overage_button"
data-testid=
"invite-with-overage-button"
@
click=
"submit"
>
{{
$options
.
i18n
.
OVERAGE_MODAL_CONTINUE_BUTTON
}}
</gl-button>
</
template
>
</
template
>
<
template
v-for=
"(_, slot) of $scopedSlots"
#[slot]=
"scope"
>
<slot
:name=
"slot"
v-bind=
"scope"
></slot>
</
template
>
</
template
>
</
gl-modal
>
</
invite-modal-base
>
</template>
</template>
ee/spec/frontend/invite_members/components/invite_modal_base_spec.js
View file @
9a23bf3f
import
{
import
{
GlModal
,
GlSprintf
}
from
'
@gitlab/ui
'
;
GlDropdown
,
import
{
nextTick
}
from
'
vue
'
;
GlDropdownItem
,
GlDatepicker
,
GlFormGroup
,
GlSprintf
,
GlLink
,
GlModal
,
}
from
'
@gitlab/ui
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
InviteModalBase
from
'
ee_else_ce/invite_members/components/invite_modal_base.vue
'
;
import
ContentTransition
from
'
~/vue_shared/components/content_transition.vue
'
;
import
{
CANCEL_BUTTON_TEXT
,
INVITE_BUTTON_TEXT
}
from
'
~/invite_members/constants
'
;
import
CEInviteModalBase
from
'
~/invite_members/components/invite_modal_base.vue
'
;
import
EEInviteModalBase
from
'
ee/invite_members/components/invite_modal_base.vue
'
;
import
{
import
{
OVERAGE_MODAL_TITLE
,
OVERAGE_MODAL_TITLE
,
OVERAGE_MODAL_CONTINUE_BUTTON
,
OVERAGE_MODAL_CONTINUE_BUTTON
,
...
@@ -18,11 +12,12 @@ import {
...
@@ -18,11 +12,12 @@ import {
}
from
'
ee/invite_members/constants
'
;
}
from
'
ee/invite_members/constants
'
;
import
{
propsData
}
from
'
jest/invite_members/mock_data/modal_base
'
;
import
{
propsData
}
from
'
jest/invite_members/mock_data/modal_base
'
;
describe
(
'
InviteModalBase
'
,
()
=>
{
describe
(
'
EE
InviteModalBase
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
let
listenerSpy
;
const
createComponent
=
(
props
=
{},
glFeatures
=
{})
=>
{
const
createComponent
=
(
props
=
{},
glFeatures
=
{})
=>
{
wrapper
=
shallowMountExtended
(
InviteModalBase
,
{
wrapper
=
shallowMountExtended
(
EE
InviteModalBase
,
{
propsData
:
{
propsData
:
{
...
propsData
,
...
propsData
,
...
props
,
...
props
,
...
@@ -31,125 +26,103 @@ describe('InviteModalBase', () => {
...
@@ -31,125 +26,103 @@ describe('InviteModalBase', () => {
...
glFeatures
,
...
glFeatures
,
},
},
stubs
:
{
stubs
:
{
GlSprintf
,
InviteModalBase
:
CEInviteModalBase
,
ContentTransition
,
GlModal
:
stubComponent
(
GlModal
,
{
GlModal
:
stubComponent
(
GlModal
,
{
template
:
template
:
'
<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>
'
,
'
<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>
'
,
}),
}),
GlDropdown
:
true
,
},
GlDropdownItem
:
true
,
listeners
:
{
GlSprintf
,
submit
:
(...
args
)
=>
listenerSpy
(
'
submit
'
,
...
args
),
GlFormGroup
:
stubComponent
(
GlFormGroup
,
{
reset
:
(...
args
)
=>
listenerSpy
(
'
reset
'
,
...
args
),
props
:
[
'
state
'
,
'
invalidFeedback
'
,
'
description
'
],
foo
:
(...
args
)
=>
listenerSpy
(
'
foo
'
,
...
args
),
}),
},
},
});
});
};
};
beforeEach
(()
=>
{
listenerSpy
=
jest
.
fn
();
});
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
wrapper
=
null
;
wrapper
=
null
;
});
});
const
findDropdown
=
()
=>
wrapper
.
findComponent
(
GlDropdown
);
const
findCEBase
=
()
=>
wrapper
.
findComponent
(
CEInviteModalBase
);
const
findDropdownItems
=
()
=>
findDropdown
().
findAllComponents
(
GlDropdownItem
);
const
findDatepicker
=
()
=>
wrapper
.
findComponent
(
GlDatepicker
);
const
findLink
=
()
=>
wrapper
.
findComponent
(
GlLink
);
const
findIntroText
=
()
=>
wrapper
.
findByTestId
(
'
modal-base-intro-text
'
).
text
();
const
findCancelButton
=
()
=>
wrapper
.
findByTestId
(
'
cancel-button
'
);
const
findInviteButton
=
()
=>
wrapper
.
findByTestId
(
'
invite-button
'
);
const
findInviteButton
=
()
=>
wrapper
.
findByTestId
(
'
invite-button
'
);
const
findBackButton
=
()
=>
wrapper
.
findByTestId
(
'
overage-back-button
'
);
const
findBackButton
=
()
=>
wrapper
.
findByTestId
(
'
overage-back-button
'
);
const
findOverageInviteButton
=
()
=>
wrapper
.
findByTestId
(
'
invite-with-overage-button
'
);
const
findInitialModalContent
=
()
=>
wrapper
.
findByTestId
(
'
invite-modal-initial-content
'
);
const
findInitialModalContent
=
()
=>
wrapper
.
findByTestId
(
'
invite-modal-initial-content
'
);
const
findOverageModalContent
=
()
=>
wrapper
.
findByTestId
(
'
invite-modal-overage-content
'
);
const
findOverageModalContent
=
()
=>
wrapper
.
findByTestId
(
'
invite-modal-overage-content
'
);
const
findM
embersFormGroup
=
()
=>
wrapper
.
findByTestId
(
'
members-form-group
'
);
const
findM
odalTitle
=
()
=>
wrapper
.
findComponent
(
GlModal
).
props
(
'
title
'
);
const
clickInviteButton
=
()
=>
findInviteButton
().
vm
.
$emit
(
'
click
'
);
const
clickInviteButton
=
()
=>
findInviteButton
().
vm
.
$emit
(
'
click
'
);
const
clickBackButton
=
()
=>
findBackButton
().
vm
.
$emit
(
'
click
'
);
const
clickBackButton
=
()
=>
findBackButton
().
vm
.
$emit
(
'
click
'
);
describe
(
'
rendering the modal
'
,
()
=>
{
describe
(
'
default
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
createComponent
();
createComponent
();
});
});
it
(
'
renders the modal with the correct title
'
,
()
=>
{
it
(
'
passes attrs to CE base
'
,
()
=>
{
expect
(
wrapper
.
findComponent
(
GlModal
).
props
(
'
title
'
)).
toBe
(
propsData
.
modalTitle
);
expect
(
findCEBase
().
props
()).
toMatchObject
({
});
...
propsData
,
currentSlot
:
'
default
'
,
it
(
'
displays the introText
'
,
()
=>
{
extraSlots
:
EEInviteModalBase
.
EXTRA_SLOTS
,
expect
(
findIntroText
()).
toBe
(
propsData
.
labelIntroText
);
});
it
(
'
renders the Cancel button text correctly
'
,
()
=>
{
expect
(
findCancelButton
().
text
()).
toBe
(
CANCEL_BUTTON_TEXT
);
});
});
it
(
'
renders the Invite button text correctly
'
,
()
=>
{
expect
(
findInviteButton
().
text
()).
toBe
(
INVITE_BUTTON_TEXT
);
});
});
it
(
'
renders the Invite button modal without isLoading
'
,
()
=>
{
it
(
"
doesn't show the overage content
"
,
()
=>
{
expect
(
findInviteButton
().
props
(
'
loading
'
)).
toBe
(
false
);
expect
(
findOverageModalContent
().
isVisible
()).
toBe
(
false
);
});
describe
(
'
rendering the access levels dropdown
'
,
()
=>
{
it
(
'
sets the default dropdown text to the default access level name
'
,
()
=>
{
expect
(
findDropdown
().
attributes
(
'
text
'
)).
toBe
(
'
Guest
'
);
});
});
it
(
'
renders dropdown items for each accessLevel
'
,
()
=>
{
it
(
'
when reset is emitted on base, emits reset
'
,
()
=>
{
expect
(
findDropdownItems
()).
toHaveLength
(
5
);
expect
(
wrapper
.
emitted
(
'
reset
'
)).
toBeUndefined
();
});
});
it
(
'
renders the correct link
'
,
()
=>
{
findCEBase
().
vm
.
$emit
(
'
reset
'
);
expect
(
findLink
().
attributes
(
'
href
'
)).
toBe
(
propsData
.
helpLink
);
});
it
(
'
renders the datepicker
'
,
()
=>
{
expect
(
wrapper
.
emitted
(
'
reset
'
)).
toHaveLength
(
1
);
expect
(
findDatepicker
().
exists
()).
toBe
(
true
);
});
});
it
(
"
doesn't show the overage content
"
,
()
=>
{
describe
(
'
(integration) when invite is clicked
'
,
()
=>
{
expect
(
findOverageModalContent
().
isVisible
()).
toBe
(
false
);
beforeEach
(
async
()
=>
{
clickInviteButton
();
await
nextTick
();
});
});
it
(
'
renders the members form group
'
,
()
=>
{
it
(
'
does not change title
'
,
()
=>
{
expect
(
findMembersFormGroup
().
props
()).
toEqual
({
expect
(
findModalTitle
()).
toBe
(
propsData
.
modalTitle
);
description
:
propsData
.
formGroupDescription
,
invalidFeedback
:
''
,
state
:
null
,
});
});
});
});
it
(
'
with isLoading, shows loading for invite button
'
,
()
=>
{
it
(
'
does not show back button
'
,
()
=>
{
createComponent
({
expect
(
findBackButton
().
exists
()).
toBe
(
false
);
isLoading
:
true
,
});
});
expect
(
findInviteButton
().
props
(
'
loading
'
)).
toBe
(
true
);
it
(
'
shows initial modal content
'
,
()
=>
{
expect
(
findInitialModalContent
().
isVisible
()).
toBe
(
true
);
});
});
it
(
'
with invalidFeedbackMessage, set members form group validation state
'
,
()
=>
{
it
(
'
emits submit
'
,
()
=>
{
createComponent
({
expect
(
wrapper
.
emitted
(
'
submit
'
)).
toEqual
([[{
accessLevel
:
10
,
expiresAt
:
undefined
}]]);
invalidFeedbackMessage
:
'
invalid message!
'
,
});
});
expect
(
findMembersFormGroup
().
props
()).
toEqual
({
description
:
propsData
.
formGroupDescription
,
invalidFeedback
:
'
invalid message!
'
,
state
:
false
,
});
});
});
});
describe
(
'
displays overage modal
'
,
()
=>
{
describe
(
'
with overageMembersModal feature flag, and invite is clicked
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(
async
()
=>
{
createComponent
({},
{
glFeatures
:
{
overageMembersModal
:
true
}
});
createComponent
({},
{
glFeatures
:
{
overageMembersModal
:
true
}
});
clickInviteButton
();
clickInviteButton
();
await
nextTick
();
});
it
(
'
does not emit submit
'
,
()
=>
{
expect
(
wrapper
.
emitted
().
submit
).
toBeUndefined
();
});
});
it
(
'
renders the modal with the correct title
'
,
()
=>
{
it
(
'
renders the modal with the correct title
'
,
()
=>
{
expect
(
wrapper
.
findComponent
(
GlModal
).
props
(
'
title
'
)).
toBe
(
OVERAGE_MODAL_TITLE
);
expect
(
findModalTitle
(
)).
toBe
(
OVERAGE_MODAL_TITLE
);
});
});
it
(
'
renders the Back button text correctly
'
,
()
=>
{
it
(
'
renders the Back button text correctly
'
,
()
=>
{
...
@@ -157,7 +130,7 @@ describe('InviteModalBase', () => {
...
@@ -157,7 +130,7 @@ describe('InviteModalBase', () => {
});
});
it
(
'
renders the Continue button text correctly
'
,
()
=>
{
it
(
'
renders the Continue button text correctly
'
,
()
=>
{
expect
(
find
Overage
InviteButton
().
text
()).
toBe
(
OVERAGE_MODAL_CONTINUE_BUTTON
);
expect
(
findInviteButton
().
text
()).
toBe
(
OVERAGE_MODAL_CONTINUE_BUTTON
);
});
});
it
(
'
shows the info text
'
,
()
=>
{
it
(
'
shows the info text
'
,
()
=>
{
...
@@ -174,7 +147,7 @@ describe('InviteModalBase', () => {
...
@@ -174,7 +147,7 @@ describe('InviteModalBase', () => {
beforeEach
(()
=>
clickBackButton
());
beforeEach
(()
=>
clickBackButton
());
it
(
'
shows the initial modal
'
,
()
=>
{
it
(
'
shows the initial modal
'
,
()
=>
{
expect
(
wrapper
.
findComponent
(
GlModal
).
props
(
'
title
'
)).
toBe
(
'
_modal_title_
'
);
expect
(
wrapper
.
findComponent
(
GlModal
).
props
(
'
title
'
)).
toBe
(
propsData
.
modalTitle
);
expect
(
findInitialModalContent
().
isVisible
()).
toBe
(
true
);
expect
(
findInitialModalContent
().
isVisible
()).
toBe
(
true
);
});
});
...
...
spec/frontend/invite_members/components/invite_groups_modal_spec.js
View file @
9a23bf3f
...
@@ -4,6 +4,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
...
@@ -4,6 +4,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import
Api
from
'
~/api
'
;
import
Api
from
'
~/api
'
;
import
InviteGroupsModal
from
'
~/invite_members/components/invite_groups_modal.vue
'
;
import
InviteGroupsModal
from
'
~/invite_members/components/invite_groups_modal.vue
'
;
import
InviteModalBase
from
'
~/invite_members/components/invite_modal_base.vue
'
;
import
InviteModalBase
from
'
~/invite_members/components/invite_modal_base.vue
'
;
import
ContentTransition
from
'
~/vue_shared/components/content_transition.vue
'
;
import
GroupSelect
from
'
~/invite_members/components/group_select.vue
'
;
import
GroupSelect
from
'
~/invite_members/components/group_select.vue
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
propsData
,
sharedGroup
}
from
'
../mock_data/group_modal
'
;
import
{
propsData
,
sharedGroup
}
from
'
../mock_data/group_modal
'
;
...
@@ -19,6 +20,7 @@ describe('InviteGroupsModal', () => {
...
@@ -19,6 +20,7 @@ describe('InviteGroupsModal', () => {
},
},
stubs
:
{
stubs
:
{
InviteModalBase
,
InviteModalBase
,
ContentTransition
,
GlSprintf
,
GlSprintf
,
GlModal
:
stubComponent
(
GlModal
,
{
GlModal
:
stubComponent
(
GlModal
,
{
template
:
'
<div><slot></slot><slot name="modal-footer"></slot></div>
'
,
template
:
'
<div><slot></slot><slot name="modal-footer"></slot></div>
'
,
...
...
spec/frontend/invite_members/components/invite_members_modal_spec.js
View file @
9a23bf3f
...
@@ -19,6 +19,7 @@ import {
...
@@ -19,6 +19,7 @@ import {
LEARN_GITLAB
,
LEARN_GITLAB
,
}
from
'
~/invite_members/constants
'
;
}
from
'
~/invite_members/constants
'
;
import
eventHub
from
'
~/invite_members/event_hub
'
;
import
eventHub
from
'
~/invite_members/event_hub
'
;
import
ContentTransition
from
'
~/vue_shared/components/content_transition.vue
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
httpStatus
from
'
~/lib/utils/http_status
'
;
import
httpStatus
from
'
~/lib/utils/http_status
'
;
import
{
getParameterValues
}
from
'
~/lib/utils/url_utility
'
;
import
{
getParameterValues
}
from
'
~/lib/utils/url_utility
'
;
...
@@ -55,6 +56,7 @@ describe('InviteMembersModal', () => {
...
@@ -55,6 +56,7 @@ describe('InviteMembersModal', () => {
},
},
stubs
:
{
stubs
:
{
InviteModalBase
,
InviteModalBase
,
ContentTransition
,
GlSprintf
,
GlSprintf
,
GlModal
:
stubComponent
(
GlModal
,
{
GlModal
:
stubComponent
(
GlModal
,
{
template
:
'
<div><slot></slot><slot name="modal-footer"></slot></div>
'
,
template
:
'
<div><slot></slot><slot name="modal-footer"></slot></div>
'
,
...
...
spec/frontend/invite_members/components/invite_modal_base_spec.js
View file @
9a23bf3f
...
@@ -10,6 +10,7 @@ import {
...
@@ -10,6 +10,7 @@ import {
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
InviteModalBase
from
'
~/invite_members/components/invite_modal_base.vue
'
;
import
InviteModalBase
from
'
~/invite_members/components/invite_modal_base.vue
'
;
import
ContentTransition
from
'
~/vue_shared/components/content_transition.vue
'
;
import
{
CANCEL_BUTTON_TEXT
,
INVITE_BUTTON_TEXT
}
from
'
~/invite_members/constants
'
;
import
{
CANCEL_BUTTON_TEXT
,
INVITE_BUTTON_TEXT
}
from
'
~/invite_members/constants
'
;
import
{
propsData
}
from
'
../mock_data/modal_base
'
;
import
{
propsData
}
from
'
../mock_data/modal_base
'
;
...
@@ -23,6 +24,7 @@ describe('InviteModalBase', () => {
...
@@ -23,6 +24,7 @@ describe('InviteModalBase', () => {
...
props
,
...
props
,
},
},
stubs
:
{
stubs
:
{
ContentTransition
,
GlModal
:
stubComponent
(
GlModal
,
{
GlModal
:
stubComponent
(
GlModal
,
{
template
:
template
:
'
<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>
'
,
'
<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>
'
,
...
...
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