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
2520e00b
Commit
2520e00b
authored
4 years ago
by
Nicolò Maria Mezzopera
Committed by
Natalia Tepluhina
4 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rename model fields
- expiration_policy_fields - tests
parent
cef17004
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
459 additions
and
226 deletions
+459
-226
app/assets/javascripts/registry/settings/components/registry_settings_app.vue
...ts/registry/settings/components/registry_settings_app.vue
+37
-13
app/assets/javascripts/registry/settings/components/settings_form.vue
...avascripts/registry/settings/components/settings_form.vue
+69
-27
app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
...s/registry/shared/components/expiration_policy_fields.vue
+12
-20
app/assets/javascripts/registry/shared/utils.js
app/assets/javascripts/registry/shared/utils.js
+14
-8
locale/gitlab.pot
locale/gitlab.pot
+10
-0
spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
...mponents/__snapshots__/registry_settings_app_spec.js.snap
+0
-7
spec/frontend/registry/settings/components/registry_settings_app_spec.js
...egistry/settings/components/registry_settings_app_spec.js
+48
-40
spec/frontend/registry/settings/components/settings_form_spec.js
...ontend/registry/settings/components/settings_form_spec.js
+199
-94
spec/frontend/registry/settings/mock_data.js
spec/frontend/registry/settings/mock_data.js
+32
-0
spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
...frontend/registry/shared/__snapshots__/utils_spec.js.snap
+4
-4
spec/frontend/registry/shared/components/expiration_policy_fields_spec.js
...gistry/shared/components/expiration_policy_fields_spec.js
+10
-10
spec/frontend/registry/shared/stubs.js
spec/frontend/registry/shared/stubs.js
+11
-0
spec/frontend/registry/shared/utils_spec.js
spec/frontend/registry/shared/utils_spec.js
+13
-3
No files found.
app/assets/javascripts/registry/settings/components/registry_settings_app.vue
View file @
2520e00b
<
script
>
<
script
>
import
{
mapActions
,
mapGetters
,
mapState
}
from
'
vuex
'
;
import
{
GlAlert
,
GlSprintf
,
GlLink
}
from
'
@gitlab/ui
'
;
import
{
GlAlert
,
GlSprintf
,
GlLink
}
from
'
@gitlab/ui
'
;
import
{
isEqual
}
from
'
lodash
'
;
import
expirationPolicyQuery
from
'
../graphql/queries/get_expiration_policy.graphql
'
;
import
{
FETCH_SETTINGS_ERROR_MESSAGE
}
from
'
../../shared/constants
'
;
import
{
FETCH_SETTINGS_ERROR_MESSAGE
}
from
'
../../shared/constants
'
;
import
SettingsForm
from
'
./settings_form.vue
'
;
import
SettingsForm
from
'
./settings_form.vue
'
;
...
@@ -19,21 +19,39 @@ export default {
...
@@ -19,21 +19,39 @@ export default {
GlSprintf
,
GlSprintf
,
GlLink
,
GlLink
,
},
},
inject
:
[
'
projectPath
'
,
'
isAdmin
'
,
'
adminSettingsPath
'
,
'
enableHistoricEntries
'
],
i18n
:
{
i18n
:
{
UNAVAILABLE_FEATURE_TITLE
,
UNAVAILABLE_FEATURE_TITLE
,
UNAVAILABLE_FEATURE_INTRO_TEXT
,
UNAVAILABLE_FEATURE_INTRO_TEXT
,
FETCH_SETTINGS_ERROR_MESSAGE
,
FETCH_SETTINGS_ERROR_MESSAGE
,
},
},
apollo
:
{
containerExpirationPolicy
:
{
query
:
expirationPolicyQuery
,
variables
()
{
return
{
projectPath
:
this
.
projectPath
,
};
},
update
:
data
=>
data
.
project
?.
containerExpirationPolicy
,
result
({
data
})
{
this
.
workingCopy
=
{
...
data
.
project
?.
containerExpirationPolicy
};
},
error
(
e
)
{
this
.
fetchSettingsError
=
e
;
},
},
},
data
()
{
data
()
{
return
{
return
{
fetchSettingsError
:
false
,
fetchSettingsError
:
false
,
containerExpirationPolicy
:
null
,
workingCopy
:
{},
};
};
},
},
computed
:
{
computed
:
{
...
mapState
([
'
isAdmin
'
,
'
adminSettingsPath
'
]),
isDisabled
()
{
...
mapGetters
({
isDisabled
:
'
getIsDisabled
'
}),
return
!
(
this
.
containerExpirationPolicy
||
this
.
enableHistoricEntries
);
showSettingForm
()
{
return
!
this
.
isDisabled
&&
!
this
.
fetchSettingsError
;
},
},
showDisabledFormMessage
()
{
showDisabledFormMessage
()
{
return
this
.
isDisabled
&&
!
this
.
fetchSettingsError
;
return
this
.
isDisabled
&&
!
this
.
fetchSettingsError
;
...
@@ -41,21 +59,27 @@ export default {
...
@@ -41,21 +59,27 @@ export default {
unavailableFeatureMessage
()
{
unavailableFeatureMessage
()
{
return
this
.
isAdmin
?
UNAVAILABLE_ADMIN_FEATURE_TEXT
:
UNAVAILABLE_USER_FEATURE_TEXT
;
return
this
.
isAdmin
?
UNAVAILABLE_ADMIN_FEATURE_TEXT
:
UNAVAILABLE_USER_FEATURE_TEXT
;
},
},
},
isEdited
()
{
mounted
()
{
return
!
isEqual
(
this
.
containerExpirationPolicy
,
this
.
workingCopy
);
this
.
fetchSettings
().
catch
(()
=>
{
},
this
.
fetchSettingsError
=
true
;
});
},
},
methods
:
{
methods
:
{
...
mapActions
([
'
fetchSettings
'
]),
restoreOriginal
()
{
this
.
workingCopy
=
{
...
this
.
containerExpirationPolicy
};
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div>
<div>
<settings-form
v-if=
"showSettingForm"
/>
<settings-form
v-if=
"containerExpirationPolicy"
v-model=
"workingCopy"
:is-loading=
"$apollo.queries.containerExpirationPolicy.loading"
:is-edited=
"isEdited"
@
reset=
"restoreOriginal"
/>
<template
v-else
>
<template
v-else
>
<gl-alert
<gl-alert
v-if=
"showDisabledFormMessage"
v-if=
"showDisabledFormMessage"
...
...
This diff is collapsed.
Click to expand it.
app/assets/javascripts/registry/settings/components/settings_form.vue
View file @
2520e00b
<
script
>
<
script
>
import
{
get
}
from
'
lodash
'
;
import
{
GlCard
,
GlButton
}
from
'
@gitlab/ui
'
;
import
{
mapActions
,
mapState
,
mapGetters
}
from
'
vuex
'
;
import
{
GlCard
,
GlButton
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
Tracking
from
'
~/tracking
'
;
import
Tracking
from
'
~/tracking
'
;
import
{
mapComputed
}
from
'
~/vuex_shared/bindings
'
;
import
{
import
{
UPDATE_SETTINGS_ERROR_MESSAGE
,
UPDATE_SETTINGS_ERROR_MESSAGE
,
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
}
from
'
../../shared/constants
'
;
}
from
'
../../shared/constants
'
;
import
ExpirationPolicyFields
from
'
../../shared/components/expiration_policy_fields.vue
'
;
import
ExpirationPolicyFields
from
'
../../shared/components/expiration_policy_fields.vue
'
;
import
{
SET_CLEANUP_POLICY_BUTTON
,
CLEANUP_POLICY_CARD_HEADER
}
from
'
../constants
'
;
import
{
SET_CLEANUP_POLICY_BUTTON
,
CLEANUP_POLICY_CARD_HEADER
}
from
'
../constants
'
;
import
{
formOptionsGenerator
}
from
'
~/registry/shared/utils
'
;
import
updateContainerExpirationPolicyMutation
from
'
../graphql/mutations/update_container_expiration_policy.graphql
'
;
import
{
updateContainerExpirationPolicy
}
from
'
../graphql/utils/cache_update
'
;
export
default
{
export
default
{
components
:
{
components
:
{
GlCard
,
GlCard
,
GlButton
,
GlButton
,
GlLoadingIcon
,
ExpirationPolicyFields
,
ExpirationPolicyFields
,
},
},
mixins
:
[
Tracking
.
mixin
()],
mixins
:
[
Tracking
.
mixin
()],
inject
:
[
'
projectPath
'
],
props
:
{
value
:
{
type
:
Object
,
required
:
true
,
},
isLoading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isEdited
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
labelsConfig
:
{
labelsConfig
:
{
cols
:
3
,
cols
:
3
,
align
:
'
right
'
,
align
:
'
right
'
,
},
},
formOptions
:
formOptionsGenerator
(),
i18n
:
{
i18n
:
{
CLEANUP_POLICY_CARD_HEADER
,
CLEANUP_POLICY_CARD_HEADER
,
SET_CLEANUP_POLICY_BUTTON
,
SET_CLEANUP_POLICY_BUTTON
,
...
@@ -34,49 +51,74 @@ export default {
...
@@ -34,49 +51,74 @@ export default {
},
},
fieldsAreValid
:
true
,
fieldsAreValid
:
true
,
apiErrors
:
null
,
apiErrors
:
null
,
mutationLoading
:
false
,
};
};
},
},
computed
:
{
computed
:
{
...
mapState
([
'
formOptions
'
,
'
isLoading
'
]),
showLoadingIcon
()
{
...
mapGetters
({
isEdited
:
'
getIsEdited
'
}),
return
this
.
isLoading
||
this
.
mutationLoading
;
...
mapComputed
([{
key
:
'
settings
'
,
getter
:
'
getSettings
'
}],
'
updateSettings
'
)
,
}
,
isSubmitButtonDisabled
()
{
isSubmitButtonDisabled
()
{
return
!
this
.
fieldsAreValid
||
this
.
isLoading
;
return
!
this
.
fieldsAreValid
||
this
.
showLoadingIcon
;
},
},
isCancelButtonDisabled
()
{
isCancelButtonDisabled
()
{
return
!
this
.
isEdited
||
this
.
isLoading
;
return
!
this
.
isEdited
||
this
.
isLoading
||
this
.
mutationLoading
;
},
mutationVariables
()
{
return
{
projectPath
:
this
.
projectPath
,
enabled
:
this
.
value
.
enabled
,
cadence
:
this
.
value
.
cadence
,
olderThan
:
this
.
value
.
olderThan
,
keepN
:
this
.
value
.
keepN
,
nameRegex
:
this
.
value
.
nameRegex
,
nameRegexKeep
:
this
.
value
.
nameRegexKeep
,
};
},
},
},
},
methods
:
{
methods
:
{
...
mapActions
([
'
resetSettings
'
,
'
saveSettings
'
]),
reset
()
{
reset
()
{
this
.
track
(
'
reset_form
'
);
this
.
track
(
'
reset_form
'
);
this
.
apiErrors
=
null
;
this
.
apiErrors
=
null
;
this
.
resetSettings
(
);
this
.
$emit
(
'
reset
'
);
},
},
setApiErrors
(
response
)
{
setApiErrors
(
response
)
{
const
messages
=
get
(
response
,
'
data.message
'
,
[]);
this
.
apiErrors
=
response
.
graphQLErrors
.
reduce
((
acc
,
curr
)
=>
{
curr
.
extensions
.
problems
.
forEach
(
item
=>
{
this
.
apiErrors
=
Object
.
keys
(
messages
).
reduce
((
acc
,
curr
)
=>
{
acc
[
item
.
path
[
0
]]
=
item
.
message
;
if
(
curr
.
startsWith
(
'
container_expiration_policy.
'
))
{
});
const
key
=
curr
.
replace
(
'
container_expiration_policy.
'
,
''
);
acc
[
key
]
=
get
(
messages
,
[
curr
,
0
],
''
);
}
return
acc
;
return
acc
;
},
{});
},
{});
},
},
submit
()
{
submit
()
{
this
.
track
(
'
submit_form
'
);
this
.
track
(
'
submit_form
'
);
this
.
apiErrors
=
null
;
this
.
apiErrors
=
null
;
this
.
saveSettings
()
this
.
mutationLoading
=
true
;
.
then
(()
=>
this
.
$toast
.
show
(
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
{
type
:
'
success
'
}))
return
this
.
$apollo
.
catch
(({
response
})
=>
{
.
mutate
({
this
.
setApiErrors
(
response
);
mutation
:
updateContainerExpirationPolicyMutation
,
variables
:
{
input
:
this
.
mutationVariables
,
},
update
:
updateContainerExpirationPolicy
(
this
.
projectPath
),
})
.
then
(({
data
})
=>
{
const
errorMessage
=
data
?.
updateContainerExpirationPolicy
?.
errors
[
0
];
if
(
errorMessage
)
{
this
.
$toast
.
show
(
errorMessage
,
{
type
:
'
error
'
});
}
this
.
$toast
.
show
(
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
{
type
:
'
success
'
});
})
.
catch
(
error
=>
{
this
.
setApiErrors
(
error
);
this
.
$toast
.
show
(
UPDATE_SETTINGS_ERROR_MESSAGE
,
{
type
:
'
error
'
});
this
.
$toast
.
show
(
UPDATE_SETTINGS_ERROR_MESSAGE
,
{
type
:
'
error
'
});
})
.
finally
(()
=>
{
this
.
mutationLoading
=
false
;
});
});
},
},
onModelChange
(
changePayload
)
{
onModelChange
(
changePayload
)
{
this
.
settings
=
changePayload
.
newValue
;
this
.
$emit
(
'
input
'
,
changePayload
.
newValue
)
;
if
(
this
.
apiErrors
)
{
if
(
this
.
apiErrors
)
{
this
.
apiErrors
[
changePayload
.
modified
]
=
undefined
;
this
.
apiErrors
[
changePayload
.
modified
]
=
undefined
;
}
}
...
@@ -93,8 +135,8 @@ export default {
...
@@ -93,8 +135,8 @@ export default {
</
template
>
</
template
>
<
template
#default
>
<
template
#default
>
<expiration-policy-fields
<expiration-policy-fields
:value=
"
settings
"
:value=
"
value
"
:form-options=
"formOptions"
:form-options=
"
$options.
formOptions"
:is-loading=
"isLoading"
:is-loading=
"isLoading"
:api-errors=
"apiErrors"
:api-errors=
"apiErrors"
@
validated=
"fieldsAreValid = true"
@
validated=
"fieldsAreValid = true"
...
@@ -115,12 +157,12 @@ export default {
...
@@ -115,12 +157,12 @@ export default {
ref=
"save-button"
ref=
"save-button"
type=
"submit"
type=
"submit"
:disabled=
"isSubmitButtonDisabled"
:disabled=
"isSubmitButtonDisabled"
:loading=
"showLoadingIcon"
variant=
"success"
variant=
"success"
category=
"primary"
category=
"primary"
class=
"js-no-auto-disable"
class=
"js-no-auto-disable"
>
>
{{
$options
.
i18n
.
SET_CLEANUP_POLICY_BUTTON
}}
{{
$options
.
i18n
.
SET_CLEANUP_POLICY_BUTTON
}}
<gl-loading-icon
v-if=
"isLoading"
class=
"gl-ml-3"
/>
</gl-button>
</gl-button>
</
template
>
</
template
>
</gl-card>
</gl-card>
...
...
This diff is collapsed.
Click to expand it.
app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
View file @
2520e00b
...
@@ -68,34 +68,31 @@ export default {
...
@@ -68,34 +68,31 @@ export default {
{
{
name
:
'
expiration-policy-interval
'
,
name
:
'
expiration-policy-interval
'
,
label
:
EXPIRATION_INTERVAL_LABEL
,
label
:
EXPIRATION_INTERVAL_LABEL
,
model
:
'
older_than
'
,
model
:
'
olderThan
'
,
optionKey
:
'
olderThan
'
,
},
},
{
{
name
:
'
expiration-policy-schedule
'
,
name
:
'
expiration-policy-schedule
'
,
label
:
EXPIRATION_SCHEDULE_LABEL
,
label
:
EXPIRATION_SCHEDULE_LABEL
,
model
:
'
cadence
'
,
model
:
'
cadence
'
,
optionKey
:
'
cadence
'
,
},
},
{
{
name
:
'
expiration-policy-latest
'
,
name
:
'
expiration-policy-latest
'
,
label
:
KEEP_N_LABEL
,
label
:
KEEP_N_LABEL
,
model
:
'
keep_n
'
,
model
:
'
keepN
'
,
optionKey
:
'
keepN
'
,
},
},
],
],
textAreaList
:
[
textAreaList
:
[
{
{
name
:
'
expiration-policy-name-matching
'
,
name
:
'
expiration-policy-name-matching
'
,
label
:
NAME_REGEX_LABEL
,
label
:
NAME_REGEX_LABEL
,
model
:
'
name
_r
egex
'
,
model
:
'
name
R
egex
'
,
placeholder
:
NAME_REGEX_PLACEHOLDER
,
placeholder
:
NAME_REGEX_PLACEHOLDER
,
description
:
NAME_REGEX_DESCRIPTION
,
description
:
NAME_REGEX_DESCRIPTION
,
},
},
{
{
name
:
'
expiration-policy-keep-name
'
,
name
:
'
expiration-policy-keep-name
'
,
label
:
NAME_REGEX_KEEP_LABEL
,
label
:
NAME_REGEX_KEEP_LABEL
,
model
:
'
name
_regex_k
eep
'
,
model
:
'
name
RegexK
eep
'
,
placeholder
:
NAME_REGEX_KEEP_PLACEHOLDER
,
placeholder
:
NAME_REGEX_KEEP_PLACEHOLDER
,
description
:
NAME_REGEX_KEEP_DESCRIPTION
,
description
:
NAME_REGEX_KEEP_DESCRIPTION
,
},
},
...
@@ -107,17 +104,16 @@ export default {
...
@@ -107,17 +104,16 @@ export default {
},
},
computed
:
{
computed
:
{
...
mapComputedToEvent
(
...
mapComputedToEvent
(
[
'
enabled
'
,
'
cadence
'
,
'
older
_than
'
,
'
keep_n
'
,
'
name_regex
'
,
'
name_regex_k
eep
'
],
[
'
enabled
'
,
'
cadence
'
,
'
older
Than
'
,
'
keepN
'
,
'
nameRegex
'
,
'
nameRegexK
eep
'
],
'
value
'
,
'
value
'
,
),
),
policyEnabledText
()
{
policyEnabledText
()
{
return
this
.
enabled
?
ENABLED_TEXT
:
DISABLED_TEXT
;
return
this
.
enabled
?
ENABLED_TEXT
:
DISABLED_TEXT
;
},
},
textAreaValidation
()
{
textAreaValidation
()
{
const
nameRegexErrors
=
const
nameRegexErrors
=
this
.
apiErrors
?.
nameRegex
||
this
.
validateRegexLength
(
this
.
nameRegex
);
this
.
apiErrors
?.
name_regex
||
this
.
validateRegexLength
(
this
.
name_regex
);
const
nameKeepRegexErrors
=
const
nameKeepRegexErrors
=
this
.
apiErrors
?.
name
_regex_keep
||
this
.
validateRegexLength
(
this
.
name_regex_k
eep
);
this
.
apiErrors
?.
name
RegexKeep
||
this
.
validateRegexLength
(
this
.
nameRegexK
eep
);
return
{
return
{
/*
/*
...
@@ -127,11 +123,11 @@ export default {
...
@@ -127,11 +123,11 @@ export default {
* false: red border, error message
* false: red border, error message
* So in this function we keep null if the are no message otherwise we 'invert' the error message
* So in this function we keep null if the are no message otherwise we 'invert' the error message
*/
*/
name
_r
egex
:
{
name
R
egex
:
{
state
:
nameRegexErrors
===
null
?
null
:
!
nameRegexErrors
,
state
:
nameRegexErrors
===
null
?
null
:
!
nameRegexErrors
,
message
:
nameRegexErrors
,
message
:
nameRegexErrors
,
},
},
name
_regex_k
eep
:
{
name
RegexK
eep
:
{
state
:
nameKeepRegexErrors
===
null
?
null
:
!
nameKeepRegexErrors
,
state
:
nameKeepRegexErrors
===
null
?
null
:
!
nameKeepRegexErrors
,
message
:
nameKeepRegexErrors
,
message
:
nameKeepRegexErrors
,
},
},
...
@@ -139,8 +135,8 @@ export default {
...
@@ -139,8 +135,8 @@ export default {
},
},
fieldsValidity
()
{
fieldsValidity
()
{
return
(
return
(
this
.
textAreaValidation
.
name
_r
egex
.
state
!==
false
&&
this
.
textAreaValidation
.
name
R
egex
.
state
!==
false
&&
this
.
textAreaValidation
.
name
_regex_k
eep
.
state
!==
false
this
.
textAreaValidation
.
name
RegexK
eep
.
state
!==
false
);
);
},
},
isFormElementDisabled
()
{
isFormElementDisabled
()
{
...
@@ -216,11 +212,7 @@ export default {
...
@@ -216,11 +212,7 @@ export default {
:disabled=
"isFormElementDisabled"
:disabled=
"isFormElementDisabled"
@
input=
"updateModel($event, select.model)"
@
input=
"updateModel($event, select.model)"
>
>
<option
<option
v-for=
"option in formOptions[select.model]"
:key=
"option.key"
:value=
"option.key"
>
v-for=
"option in formOptions[select.optionKey]"
:key=
"option.key"
:value=
"option.key"
>
{{ option.label }}
{{ option.label }}
</option>
</option>
</gl-form-select>
</gl-form-select>
...
...
This diff is collapsed.
Click to expand it.
app/assets/javascripts/registry/shared/utils.js
View file @
2520e00b
...
@@ -21,20 +21,26 @@ export const mapComputedToEvent = (list, root) => {
...
@@ -21,20 +21,26 @@ export const mapComputedToEvent = (list, root) => {
return
result
;
return
result
;
};
};
export
const
optionLabelGenerator
=
(
collection
,
singularSentence
,
pluralSentence
)
=>
export
const
olderThanTranslationGenerator
=
variable
=>
n__
(
'
%d day until tags are automatically removed
'
,
'
%d days until tags are automatically removed
'
,
variable
,
);
export
const
keepNTranslationGenerator
=
variable
=>
n__
(
'
%d tag per image name
'
,
'
%d tags per image name
'
,
variable
);
export
const
optionLabelGenerator
=
(
collection
,
translationFn
)
=>
collection
.
map
(
option
=>
({
collection
.
map
(
option
=>
({
...
option
,
...
option
,
label
:
n__
(
singularSentence
,
pluralSentence
,
option
.
variable
),
label
:
translationFn
(
option
.
variable
),
}));
}));
export
const
formOptionsGenerator
=
()
=>
{
export
const
formOptionsGenerator
=
()
=>
{
return
{
return
{
olderThan
:
optionLabelGenerator
(
olderThan
:
optionLabelGenerator
(
OLDER_THAN_OPTIONS
,
olderThanTranslationGenerator
),
OLDER_THAN_OPTIONS
,
'
%d days until tags are automatically removed
'
,
'
%d day until tags are automatically removed
'
,
),
cadence
:
CADENCE_OPTIONS
,
cadence
:
CADENCE_OPTIONS
,
keepN
:
optionLabelGenerator
(
KEEP_N_OPTIONS
,
'
%d tag per image name
'
,
'
%d tags per image name
'
),
keepN
:
optionLabelGenerator
(
KEEP_N_OPTIONS
,
keepNTranslationGenerator
),
};
};
};
};
This diff is collapsed.
Click to expand it.
locale/gitlab.pot
View file @
2520e00b
...
@@ -165,6 +165,11 @@ msgid_plural "%d days"
...
@@ -165,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[0] ""
msgstr[1] ""
msgstr[1] ""
msgid "%d day until tags are automatically removed"
msgid_plural "%d days until tags are automatically removed"
msgstr[0] ""
msgstr[1] ""
msgid "%d error"
msgid "%d error"
msgid_plural "%d errors"
msgid_plural "%d errors"
msgstr[0] ""
msgstr[0] ""
...
@@ -300,6 +305,11 @@ msgid_plural "%d tags"
...
@@ -300,6 +305,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[0] ""
msgstr[1] ""
msgstr[1] ""
msgid "%d tag per image name"
msgid_plural "%d tags per image name"
msgstr[0] ""
msgstr[1] ""
msgid "%d unassigned issue"
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgid_plural "%d unassigned issues"
msgstr[0] ""
msgstr[0] ""
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
deleted
100644 → 0
View file @
cef17004
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Registry Settings App renders 1`] = `
<div>
<settings-form-stub />
</div>
`;
This diff is collapsed.
Click to expand it.
spec/frontend/registry/settings/components/registry_settings_app_spec.js
View file @
2520e00b
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
GlAlert
,
GlSprintf
,
GlLink
}
from
'
@gitlab/ui
'
;
import
{
GlAlert
,
GlSprintf
,
GlLink
}
from
'
@gitlab/ui
'
;
import
createMockApollo
from
'
jest/helpers/mock_apollo_helper
'
;
import
component
from
'
~/registry/settings/components/registry_settings_app.vue
'
;
import
component
from
'
~/registry/settings/components/registry_settings_app.vue
'
;
import
expirationPolicyQuery
from
'
~/registry/settings/graphql/queries/get_expiration_policy.graphql
'
;
import
SettingsForm
from
'
~/registry/settings/components/settings_form.vue
'
;
import
SettingsForm
from
'
~/registry/settings/components/settings_form.vue
'
;
import
{
createStore
}
from
'
~/registry/settings/store/
'
;
import
{
SET_SETTINGS
,
SET_INITIAL_STATE
}
from
'
~/registry/settings/store/mutation_types
'
;
import
{
FETCH_SETTINGS_ERROR_MESSAGE
}
from
'
~/registry/shared/constants
'
;
import
{
FETCH_SETTINGS_ERROR_MESSAGE
}
from
'
~/registry/shared/constants
'
;
import
{
import
{
UNAVAILABLE_FEATURE_INTRO_TEXT
,
UNAVAILABLE_FEATURE_INTRO_TEXT
,
UNAVAILABLE_USER_FEATURE_TEXT
,
UNAVAILABLE_USER_FEATURE_TEXT
,
}
from
'
~/registry/settings/constants
'
;
}
from
'
~/registry/settings/constants
'
;
import
{
stringifiedFormOptions
}
from
'
../../shared/mock_data
'
;
import
{
expirationPolicyPayload
}
from
'
../mock_data
'
;
const
localVue
=
createLocalVue
();
describe
(
'
Registry Settings App
'
,
()
=>
{
describe
(
'
Registry Settings App
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
let
store
;
let
fakeApollo
;
const
defaultProvidedValues
=
{
projectPath
:
'
path
'
,
isAdmin
:
false
,
adminSettingsPath
:
'
settingsPath
'
,
enableHistoricEntries
:
false
,
};
const
findSettingsComponent
=
()
=>
wrapper
.
find
(
SettingsForm
);
const
findSettingsComponent
=
()
=>
wrapper
.
find
(
SettingsForm
);
const
findAlert
=
()
=>
wrapper
.
find
(
GlAlert
);
const
findAlert
=
()
=>
wrapper
.
find
(
GlAlert
);
const
mountComponent
=
({
dispatchMock
=
'
mockResolvedValue
'
}
=
{})
=>
{
const
mountComponent
=
(
provide
=
defaultProvidedValues
,
config
)
=>
{
const
dispatchSpy
=
jest
.
spyOn
(
store
,
'
dispatch
'
);
dispatchSpy
[
dispatchMock
]();
wrapper
=
shallowMount
(
component
,
{
wrapper
=
shallowMount
(
component
,
{
stubs
:
{
stubs
:
{
GlSprintf
,
GlSprintf
,
...
@@ -32,71 +39,72 @@ describe('Registry Settings App', () => {
...
@@ -32,71 +39,72 @@ describe('Registry Settings App', () => {
show
:
jest
.
fn
(),
show
:
jest
.
fn
(),
},
},
},
},
store
,
provide
,
...
config
,
});
});
};
};
beforeEach
(()
=>
{
const
mountComponentWithApollo
=
({
provide
=
defaultProvidedValues
,
resolver
}
=
{})
=>
{
store
=
createStore
();
localVue
.
use
(
VueApollo
);
});
const
requestHandlers
=
[[
expirationPolicyQuery
,
resolver
]];
fakeApollo
=
createMockApollo
(
requestHandlers
);
mountComponent
(
provide
,
{
localVue
,
apolloProvider
:
fakeApollo
,
});
return
requestHandlers
.
map
(
request
=>
request
[
1
]);
};
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
});
});
it
(
'
renders
'
,
()
=>
{
it
(
'
renders the setting form
'
,
async
()
=>
{
store
.
commit
(
SET_SETTINGS
,
{
foo
:
'
bar
'
});
const
requests
=
mountComponentWithApollo
({
mountComponent
();
resolver
:
jest
.
fn
().
mockResolvedValue
(
expirationPolicyPayload
()),
expect
(
wrapper
.
element
).
toMatchSnapshot
();
});
});
await
Promise
.
all
(
requests
);
it
(
'
call the store function to load the data on mount
'
,
()
=>
{
mountComponent
();
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
fetchSettings
'
);
});
it
(
'
renders the setting form
'
,
()
=>
{
store
.
commit
(
SET_SETTINGS
,
{
foo
:
'
bar
'
});
mountComponent
();
expect
(
findSettingsComponent
().
exists
()).
toBe
(
true
);
expect
(
findSettingsComponent
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
the form is disabled
'
,
()
=>
{
describe
(
'
the form is disabled
'
,
()
=>
{
beforeEach
(()
=>
{
it
(
'
the form is hidden
'
,
()
=>
{
store
.
commit
(
SET_SETTINGS
,
undefined
);
mountComponent
();
mountComponent
();
});
it
(
'
the form is hidden
'
,
()
=>
{
expect
(
findSettingsComponent
().
exists
()).
toBe
(
false
);
expect
(
findSettingsComponent
().
exists
()).
toBe
(
false
);
});
});
it
(
'
shows an alert
'
,
()
=>
{
it
(
'
shows an alert
'
,
()
=>
{
mountComponent
();
const
text
=
findAlert
().
text
();
const
text
=
findAlert
().
text
();
expect
(
text
).
toContain
(
UNAVAILABLE_FEATURE_INTRO_TEXT
);
expect
(
text
).
toContain
(
UNAVAILABLE_FEATURE_INTRO_TEXT
);
expect
(
text
).
toContain
(
UNAVAILABLE_USER_FEATURE_TEXT
);
expect
(
text
).
toContain
(
UNAVAILABLE_USER_FEATURE_TEXT
);
});
});
describe
(
'
an admin is visiting the page
'
,
()
=>
{
describe
(
'
an admin is visiting the page
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
commit
(
SET_INITIAL_STATE
,
{
...
stringifiedFormOptions
,
isAdmin
:
true
,
adminSettingsPath
:
'
foo
'
,
});
});
it
(
'
shows the admin part of the alert message
'
,
()
=>
{
it
(
'
shows the admin part of the alert message
'
,
()
=>
{
mountComponent
({
...
defaultProvidedValues
,
isAdmin
:
true
});
const
sprintf
=
findAlert
().
find
(
GlSprintf
);
const
sprintf
=
findAlert
().
find
(
GlSprintf
);
expect
(
sprintf
.
text
()).
toBe
(
'
administration settings
'
);
expect
(
sprintf
.
text
()).
toBe
(
'
administration settings
'
);
expect
(
sprintf
.
find
(
GlLink
).
attributes
(
'
href
'
)).
toBe
(
'
foo
'
);
expect
(
sprintf
.
find
(
GlLink
).
attributes
(
'
href
'
)).
toBe
(
defaultProvidedValues
.
adminSettingsPath
,
);
});
});
});
});
});
});
describe
(
'
fetchSettingsError
'
,
()
=>
{
describe
(
'
fetchSettingsError
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mountComponent
({
dispatchMock
:
'
mockRejectedValue
'
});
const
requests
=
mountComponentWithApollo
({
resolver
:
jest
.
fn
().
mockRejectedValue
(
new
Error
(
'
GraphQL error
'
)),
});
return
Promise
.
all
(
requests
);
});
});
it
(
'
the form is hidden
'
,
()
=>
{
it
(
'
the form is hidden
'
,
()
=>
{
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/registry/settings/components/settings_form_spec.js
View file @
2520e00b
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
createMockApollo
from
'
jest/helpers/mock_apollo_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
Tracking
from
'
~/tracking
'
;
import
Tracking
from
'
~/tracking
'
;
import
component
from
'
~/registry/settings/components/settings_form.vue
'
;
import
component
from
'
~/registry/settings/components/settings_form.vue
'
;
import
expirationPolicyFields
from
'
~/registry/shared/components/expiration_policy_fields.vue
'
;
import
expirationPolicyFields
from
'
~/registry/shared/components/expiration_policy_fields.vue
'
;
import
{
createStore
}
from
'
~/registry/settings/store/
'
;
import
updateContainerExpirationPolicyMutation
from
'
~/registry/settings/graphql/mutations/update_container_expiration_policy.graphql
'
;
import
expirationPolicyQuery
from
'
~/registry/settings/graphql/queries/get_expiration_policy.graphql
'
;
import
{
import
{
UPDATE_SETTINGS_ERROR_MESSAGE
,
UPDATE_SETTINGS_ERROR_MESSAGE
,
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
}
from
'
~/registry/shared/constants
'
;
}
from
'
~/registry/shared/constants
'
;
import
{
stringifiedFormOptions
}
from
'
../../shared/mock_data
'
;
import
{
GlCard
,
GlLoadingIcon
}
from
'
../../shared/stubs
'
;
import
{
expirationPolicyPayload
,
expirationPolicyMutationPayload
}
from
'
../mock_data
'
;
const
localVue
=
createLocalVue
();
describe
(
'
Settings Form
'
,
()
=>
{
describe
(
'
Settings Form
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
let
store
;
let
fakeApollo
;
let
dispatchSpy
;
const
defaultProvidedValues
=
{
const
GlLoadingIcon
=
{
name
:
'
gl-loading-icon-stub
'
,
template
:
'
<svg></svg>
'
};
projectPath
:
'
path
'
,
const
GlCard
=
{
};
name
:
'
gl-card-stub
'
,
template
:
`
const
{
<div>
data
:
{
<slot name="header"></slot>
project
:
{
containerExpirationPolicy
},
<slot></slot>
},
<slot name="footer"></slot>
}
=
expirationPolicyPayload
();
</div>
`
,
const
defaultProps
=
{
value
:
{
...
containerExpirationPolicy
},
};
};
const
trackingPayload
=
{
const
trackingPayload
=
{
...
@@ -35,14 +42,21 @@ describe('Settings Form', () => {
...
@@ -35,14 +42,21 @@ describe('Settings Form', () => {
const
findFields
=
()
=>
wrapper
.
find
(
expirationPolicyFields
);
const
findFields
=
()
=>
wrapper
.
find
(
expirationPolicyFields
);
const
findCancelButton
=
()
=>
wrapper
.
find
({
ref
:
'
cancel-button
'
});
const
findCancelButton
=
()
=>
wrapper
.
find
({
ref
:
'
cancel-button
'
});
const
findSaveButton
=
()
=>
wrapper
.
find
({
ref
:
'
save-button
'
});
const
findSaveButton
=
()
=>
wrapper
.
find
({
ref
:
'
save-button
'
});
const
findLoadingIcon
=
(
parent
=
wrapper
)
=>
parent
.
find
(
GlLoadingIcon
);
const
mountComponent
=
(
data
=
{})
=>
{
const
mountComponent
=
({
props
=
defaultProps
,
data
,
config
,
provide
=
defaultProvidedValues
,
mocks
,
}
=
{})
=>
{
wrapper
=
shallowMount
(
component
,
{
wrapper
=
shallowMount
(
component
,
{
stubs
:
{
stubs
:
{
GlCard
,
GlCard
,
GlLoadingIcon
,
GlLoadingIcon
,
},
},
propsData
:
{
...
props
},
provide
,
data
()
{
data
()
{
return
{
return
{
...
data
,
...
data
,
...
@@ -52,15 +66,42 @@ describe('Settings Form', () => {
...
@@ -52,15 +66,42 @@ describe('Settings Form', () => {
$toast
:
{
$toast
:
{
show
:
jest
.
fn
(),
show
:
jest
.
fn
(),
},
},
...
mocks
,
},
},
store
,
...
config
,
});
});
};
};
const
mountComponentWithApollo
=
({
provide
=
defaultProvidedValues
,
resolver
}
=
{})
=>
{
localVue
.
use
(
VueApollo
);
const
requestHandlers
=
[
[
updateContainerExpirationPolicyMutation
,
resolver
],
[
expirationPolicyQuery
,
jest
.
fn
().
mockResolvedValue
(
expirationPolicyPayload
())],
];
fakeApollo
=
createMockApollo
(
requestHandlers
);
fakeApollo
.
defaultClient
.
cache
.
writeQuery
({
query
:
expirationPolicyQuery
,
variables
:
{
projectPath
:
provide
.
projectPath
,
},
...
expirationPolicyPayload
(),
});
mountComponent
({
provide
,
config
:
{
localVue
,
apolloProvider
:
fakeApollo
,
},
});
return
requestHandlers
.
map
(
resolvers
=>
resolvers
[
1
]);
};
beforeEach
(()
=>
{
beforeEach
(()
=>
{
store
=
createStore
();
store
.
dispatch
(
'
setInitialState
'
,
stringifiedFormOptions
);
dispatchSpy
=
jest
.
spyOn
(
store
,
'
dispatch
'
);
jest
.
spyOn
(
Tracking
,
'
event
'
);
jest
.
spyOn
(
Tracking
,
'
event
'
);
});
});
...
@@ -72,12 +113,12 @@ describe('Settings Form', () => {
...
@@ -72,12 +113,12 @@ describe('Settings Form', () => {
it
(
'
v-model change update the settings property
'
,
()
=>
{
it
(
'
v-model change update the settings property
'
,
()
=>
{
mountComponent
();
mountComponent
();
findFields
().
vm
.
$emit
(
'
input
'
,
{
newValue
:
'
foo
'
});
findFields
().
vm
.
$emit
(
'
input
'
,
{
newValue
:
'
foo
'
});
expect
(
dispatchSpy
).
toHaveBeenCalledWith
(
'
updateSettings
'
,
{
settings
:
'
foo
'
}
);
expect
(
wrapper
.
emitted
(
'
input
'
)).
toEqual
([[
'
foo
'
]]
);
});
});
it
(
'
v-model change update the api error property
'
,
()
=>
{
it
(
'
v-model change update the api error property
'
,
()
=>
{
const
apiErrors
=
{
baz
:
'
bar
'
};
const
apiErrors
=
{
baz
:
'
bar
'
};
mountComponent
({
apiErrors
});
mountComponent
({
data
:
{
apiErrors
}
});
expect
(
findFields
().
props
(
'
apiErrors
'
)).
toEqual
(
apiErrors
);
expect
(
findFields
().
props
(
'
apiErrors
'
)).
toEqual
(
apiErrors
);
findFields
().
vm
.
$emit
(
'
input
'
,
{
newValue
:
'
foo
'
,
modified
:
'
baz
'
});
findFields
().
vm
.
$emit
(
'
input
'
,
{
newValue
:
'
foo
'
,
modified
:
'
baz
'
});
expect
(
findFields
().
props
(
'
apiErrors
'
)).
toEqual
({});
expect
(
findFields
().
props
(
'
apiErrors
'
)).
toEqual
({});
...
@@ -85,19 +126,14 @@ describe('Settings Form', () => {
...
@@ -85,19 +126,14 @@ describe('Settings Form', () => {
});
});
describe
(
'
form
'
,
()
=>
{
describe
(
'
form
'
,
()
=>
{
let
form
;
beforeEach
(()
=>
{
mountComponent
();
form
=
findForm
();
dispatchSpy
.
mockReturnValue
();
});
describe
(
'
form reset event
'
,
()
=>
{
describe
(
'
form reset event
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
form
.
trigger
(
'
reset
'
);
mountComponent
();
findForm
().
trigger
(
'
reset
'
);
});
});
it
(
'
calls the appropriate function
'
,
()
=>
{
it
(
'
calls the appropriate function
'
,
()
=>
{
expect
(
dispatchSpy
).
toHaveBeenCalledWith
(
'
resetSettings
'
);
expect
(
wrapper
.
emitted
(
'
reset
'
)).
toEqual
([[]]
);
});
});
it
(
'
tracks the reset event
'
,
()
=>
{
it
(
'
tracks the reset event
'
,
()
=>
{
...
@@ -108,54 +144,96 @@ describe('Settings Form', () => {
...
@@ -108,54 +144,96 @@ describe('Settings Form', () => {
describe
(
'
form submit event
'
,
()
=>
{
describe
(
'
form submit event
'
,
()
=>
{
it
(
'
save has type submit
'
,
()
=>
{
it
(
'
save has type submit
'
,
()
=>
{
mountComponent
();
mountComponent
();
expect
(
findSaveButton
().
attributes
(
'
type
'
)).
toBe
(
'
submit
'
);
expect
(
findSaveButton
().
attributes
(
'
type
'
)).
toBe
(
'
submit
'
);
});
});
it
(
'
dispatches the saveSettings action
'
,
()
=>
{
it
(
'
dispatches the correct apollo mutation
'
,
async
()
=>
{
dispatchSpy
.
mockResolvedValue
();
const
[
expirationPolicyMutationResolver
]
=
mountComponentWithApollo
({
form
.
trigger
(
'
submit
'
);
resolver
:
jest
.
fn
().
mockResolvedValue
(
expirationPolicyMutationPayload
()),
expect
(
dispatchSpy
).
toHaveBeenCalledWith
(
'
saveSettings
'
);
});
findForm
().
trigger
(
'
submit
'
);
await
expirationPolicyMutationResolver
();
expect
(
expirationPolicyMutationResolver
).
toHaveBeenCalled
();
});
});
it
(
'
tracks the submit event
'
,
()
=>
{
it
(
'
tracks the submit event
'
,
()
=>
{
dispatchSpy
.
mockResolvedValue
();
mountComponentWithApollo
({
form
.
trigger
(
'
submit
'
);
resolver
:
jest
.
fn
().
mockResolvedValue
(
expirationPolicyMutationPayload
()),
});
findForm
().
trigger
(
'
submit
'
);
expect
(
Tracking
.
event
).
toHaveBeenCalledWith
(
undefined
,
'
submit_form
'
,
trackingPayload
);
expect
(
Tracking
.
event
).
toHaveBeenCalledWith
(
undefined
,
'
submit_form
'
,
trackingPayload
);
});
});
it
(
'
show a success toast when submit succeed
'
,
async
()
=>
{
it
(
'
show a success toast when submit succeed
'
,
async
()
=>
{
dispatchSpy
.
mockResolvedValue
();
const
handlers
=
mountComponentWithApollo
({
form
.
trigger
(
'
submit
'
);
resolver
:
jest
.
fn
().
mockResolvedValue
(
expirationPolicyMutationPayload
()),
await
waitForPromises
();
});
findForm
().
trigger
(
'
submit
'
);
await
Promise
.
all
(
handlers
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
vm
.
$toast
.
show
).
toHaveBeenCalledWith
(
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
{
expect
(
wrapper
.
vm
.
$toast
.
show
).
toHaveBeenCalledWith
(
UPDATE_SETTINGS_SUCCESS_MESSAGE
,
{
type
:
'
success
'
,
type
:
'
success
'
,
});
});
});
});
describe
(
'
when submit fails
'
,
()
=>
{
describe
(
'
when submit fails
'
,
()
=>
{
it
(
'
shows an error
'
,
async
()
=>
{
describe
(
'
user recoverable errors
'
,
()
=>
{
dispatchSpy
.
mockRejectedValue
({
response
:
{}
});
it
(
'
when there is an error is shown in a toast
'
,
async
()
=>
{
form
.
trigger
(
'
submit
'
);
const
handlers
=
mountComponentWithApollo
({
await
waitForPromises
();
resolver
:
jest
expect
(
wrapper
.
vm
.
$toast
.
show
).
toHaveBeenCalledWith
(
UPDATE_SETTINGS_ERROR_MESSAGE
,
{
.
fn
()
type
:
'
error
'
,
.
mockResolvedValue
(
expirationPolicyMutationPayload
({
errors
:
[
'
foo
'
]
})),
});
findForm
().
trigger
(
'
submit
'
);
await
Promise
.
all
(
handlers
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
vm
.
$toast
.
show
).
toHaveBeenCalledWith
(
'
foo
'
,
{
type
:
'
error
'
,
});
});
});
});
});
describe
(
'
global errors
'
,
()
=>
{
it
(
'
shows an error
'
,
async
()
=>
{
const
handlers
=
mountComponentWithApollo
({
resolver
:
jest
.
fn
().
mockRejectedValue
(
expirationPolicyMutationPayload
()),
});
findForm
().
trigger
(
'
submit
'
);
await
Promise
.
all
(
handlers
);
await
wrapper
.
vm
.
$nextTick
();
await
wrapper
.
vm
.
$nextTick
();
it
(
'
parses the error messages
'
,
async
()
=>
{
expect
(
wrapper
.
vm
.
$toast
.
show
).
toHaveBeenCalledWith
(
UPDATE_SETTINGS_ERROR_MESSAGE
,
{
dispatchSpy
.
mockRejectedValue
({
type
:
'
error
'
,
response
:
{
});
data
:
{
});
message
:
{
foo
:
'
bar
'
,
it
(
'
parses the error messages
'
,
async
()
=>
{
'
container_expiration_policy.name
'
:
[
'
baz
'
],
const
mutate
=
jest
.
fn
().
mockRejectedValue
({
graphQLErrors
:
[
{
extensions
:
{
problems
:
[{
path
:
[
'
name
'
],
message
:
'
baz
'
}],
},
},
},
},
],
},
});
mountComponent
({
mocks
:
{
$apollo
:
{
mutate
}
}
});
findForm
().
trigger
(
'
submit
'
);
await
waitForPromises
();
await
wrapper
.
vm
.
$nextTick
();
expect
(
findFields
().
props
(
'
apiErrors
'
)).
toEqual
({
name
:
'
baz
'
});
});
});
form
.
trigger
(
'
submit
'
);
await
waitForPromises
();
expect
(
findFields
().
props
(
'
apiErrors
'
)).
toEqual
({
name
:
'
baz
'
});
});
});
});
});
});
});
...
@@ -163,51 +241,78 @@ describe('Settings Form', () => {
...
@@ -163,51 +241,78 @@ describe('Settings Form', () => {
describe
(
'
form actions
'
,
()
=>
{
describe
(
'
form actions
'
,
()
=>
{
describe
(
'
cancel button
'
,
()
=>
{
describe
(
'
cancel button
'
,
()
=>
{
beforeEach
(()
=>
{
it
(
'
has type reset
'
,
()
=>
{
store
.
commit
(
'
SET_SETTINGS
'
,
{
foo
:
'
bar
'
});
mountComponent
();
mountComponent
();
});
it
(
'
has type reset
'
,
()
=>
{
expect
(
findCancelButton
().
attributes
(
'
type
'
)).
toBe
(
'
reset
'
);
expect
(
findCancelButton
().
attributes
(
'
type
'
)).
toBe
(
'
reset
'
);
});
});
it
(
'
is disabled when isEdited is false
'
,
()
=>
it
.
each
`
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
isLoading | isEdited | mutationLoading | isDisabled
expect
(
findCancelButton
().
attributes
(
'
disabled
'
)).
toBe
(
'
true
'
);
${
true
}
|
${
true
}
|
${
true
}
|
${
true
}
}));
${
false
}
|
${
true
}
|
${
true
}
|
${
true
}
${
false
}
|
${
false
}
|
${
true
}
|
${
true
}
it
(
'
is disabled isLoading is true
'
,
()
=>
{
${
true
}
|
${
false
}
|
${
false
}
|
${
true
}
store
.
commit
(
'
TOGGLE_LOADING
'
);
${
false
}
|
${
false
}
|
${
false
}
|
${
true
}
store
.
commit
(
'
UPDATE_SETTINGS
'
,
{
settings
:
{
foo
:
'
baz
'
}
});
${
false
}
|
${
true
}
|
${
false
}
|
${
false
}
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
`
(
expect
(
findCancelButton
().
attributes
(
'
disabled
'
)).
toBe
(
'
true
'
);
'
when isLoading is $isLoading and isEdited is $isEdited and mutationLoading is $mutationLoading is $isDisabled that the is disabled
'
,
store
.
commit
(
'
TOGGLE_LOADING
'
);
({
isEdited
,
isLoading
,
mutationLoading
,
isDisabled
})
=>
{
});
mountComponent
({
});
props
:
{
...
defaultProps
,
isEdited
,
isLoading
},
data
:
{
mutationLoading
},
});
it
(
'
is enabled when isLoading is false and isEdited is true
'
,
()
=>
{
const
expectation
=
isDisabled
?
'
true
'
:
undefined
;
store
.
commit
(
'
UPDATE_SETTINGS
'
,
{
settings
:
{
foo
:
'
baz
'
}
});
expect
(
findCancelButton
().
attributes
(
'
disabled
'
)).
toBe
(
expectation
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
},
expect
(
findCancelButton
().
attributes
(
'
disabled
'
)).
toBe
(
undefined
);
);
});
});
});
});
describe
(
'
when isLoading is true
'
,
()
=>
{
describe
(
'
submit button
'
,
()
=>
{
beforeEach
(()
=>
{
it
(
'
has type submit
'
,
()
=>
{
store
.
commit
(
'
TOGGLE_LOADING
'
);
mountComponent
();
mountComponent
();
});
afterEach
(()
=>
{
store
.
commit
(
'
TOGGLE_LOADING
'
);
});
it
(
'
submit button is disabled and shows a spinner
'
,
()
=>
{
expect
(
findSaveButton
().
attributes
(
'
type
'
)).
toBe
(
'
submit
'
);
const
button
=
findSaveButton
();
expect
(
button
.
attributes
(
'
disabled
'
)).
toBeTruthy
();
expect
(
findLoadingIcon
(
button
).
exists
()).
toBe
(
true
);
});
});
it
.
each
`
isLoading | fieldsAreValid | mutationLoading | isDisabled
${
true
}
|
${
true
}
|
${
true
}
|
${
true
}
${
false
}
|
${
true
}
|
${
true
}
|
${
true
}
${
false
}
|
${
false
}
|
${
true
}
|
${
true
}
${
true
}
|
${
false
}
|
${
false
}
|
${
true
}
${
false
}
|
${
false
}
|
${
false
}
|
${
true
}
${
false
}
|
${
true
}
|
${
false
}
|
${
false
}
`
(
'
when isLoading is $isLoading and fieldsAreValid is $fieldsAreValid and mutationLoading is $mutationLoading is $isDisabled that the is disabled
'
,
({
fieldsAreValid
,
isLoading
,
mutationLoading
,
isDisabled
})
=>
{
mountComponent
({
props
:
{
...
defaultProps
,
isLoading
},
data
:
{
mutationLoading
,
fieldsAreValid
},
});
const
expectation
=
isDisabled
?
'
true
'
:
undefined
;
expect
(
findSaveButton
().
attributes
(
'
disabled
'
)).
toBe
(
expectation
);
},
);
it
.
each
`
isLoading | mutationLoading | showLoading
${
true
}
|
${
true
}
|
${
true
}
${
true
}
|
${
false
}
|
${
true
}
${
false
}
|
${
true
}
|
${
true
}
${
false
}
|
${
false
}
|
${
false
}
`
(
'
when isLoading is $isLoading and mutationLoading is $mutationLoading is $showLoading that the loading icon is shown
'
,
({
isLoading
,
mutationLoading
,
showLoading
})
=>
{
mountComponent
({
props
:
{
...
defaultProps
,
isLoading
},
data
:
{
mutationLoading
},
});
expect
(
findSaveButton
().
props
(
'
loading
'
)).
toBe
(
showLoading
);
},
);
});
});
});
});
});
});
This diff is collapsed.
Click to expand it.
spec/frontend/registry/settings/mock_data.js
0 → 100644
View file @
2520e00b
export
const
expirationPolicyPayload
=
override
=>
({
data
:
{
project
:
{
containerExpirationPolicy
:
{
cadence
:
'
EVERY_DAY
'
,
enabled
:
true
,
keepN
:
'
TEN_TAGS
'
,
nameRegex
:
'
asdasdssssdfdf
'
,
nameRegexKeep
:
'
sss
'
,
olderThan
:
'
FOURTEEN_DAYS
'
,
...
override
,
},
},
},
});
export
const
expirationPolicyMutationPayload
=
({
override
,
errors
=
[]
}
=
{})
=>
({
data
:
{
updateContainerExpirationPolicy
:
{
containerExpirationPolicy
:
{
cadence
:
'
EVERY_DAY
'
,
enabled
:
true
,
keepN
:
'
TEN_TAGS
'
,
nameRegex
:
'
asdasdssssdfdf
'
,
nameRegexKeep
:
'
sss
'
,
olderThan
:
'
FOURTEEN_DAYS
'
,
...
override
,
},
errors
,
},
},
});
This diff is collapsed.
Click to expand it.
spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
View file @
2520e00b
...
@@ -76,25 +76,25 @@ Array [
...
@@ -76,25 +76,25 @@ Array [
Object {
Object {
"default": false,
"default": false,
"key": "SEVEN_DAYS",
"key": "SEVEN_DAYS",
"label": "7 day until tags are automatically removed",
"label": "7 day
s
until tags are automatically removed",
"variable": 7,
"variable": 7,
},
},
Object {
Object {
"default": false,
"default": false,
"key": "FOURTEEN_DAYS",
"key": "FOURTEEN_DAYS",
"label": "14 day until tags are automatically removed",
"label": "14 day
s
until tags are automatically removed",
"variable": 14,
"variable": 14,
},
},
Object {
Object {
"default": false,
"default": false,
"key": "THIRTY_DAYS",
"key": "THIRTY_DAYS",
"label": "30 day until tags are automatically removed",
"label": "30 day
s
until tags are automatically removed",
"variable": 30,
"variable": 30,
},
},
Object {
Object {
"default": true,
"default": true,
"key": "NINETY_DAYS",
"key": "NINETY_DAYS",
"label": "90 day until tags are automatically removed",
"label": "90 day
s
until tags are automatically removed",
"variable": 90,
"variable": 90,
},
},
]
]
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/registry/shared/components/expiration_policy_fields_spec.js
View file @
2520e00b
...
@@ -40,13 +40,13 @@ describe('Expiration Policy Form', () => {
...
@@ -40,13 +40,13 @@ describe('Expiration Policy Form', () => {
});
});
describe
.
each
`
describe
.
each
`
elementName | modelName
| value | disabledByToggle
elementName | modelName | value | disabledByToggle
${
'
toggle
'
}
|
${
'
enabled
'
}
|
${
true
}
|
${
'
not disabled
'
}
${
'
toggle
'
}
|
${
'
enabled
'
}
|
${
true
}
|
${
'
not disabled
'
}
${
'
interval
'
}
|
${
'
older
_than
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
interval
'
}
|
${
'
older
Than
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
schedule
'
}
|
${
'
cadence
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
schedule
'
}
|
${
'
cadence
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
latest
'
}
|
${
'
keep
_n
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
latest
'
}
|
${
'
keep
N
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
name-matching
'
}
|
${
'
name
_regex
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
name-matching
'
}
|
${
'
name
Regex
'
}
|
${
'
foo
'
}
|
${
'
disabled
'
}
${
'
keep-name
'
}
|
${
'
name
_regex_k
eep
'
}
|
${
'
bar
'
}
|
${
'
disabled
'
}
${
'
keep-name
'
}
|
${
'
name
RegexK
eep
'
}
|
${
'
bar
'
}
|
${
'
disabled
'
}
`
(
`
(
`
${
FORM_ELEMENTS_ID_PREFIX
}
-$elementName form element`
,
`
${
FORM_ELEMENTS_ID_PREFIX
}
-$elementName form element`
,
({
elementName
,
modelName
,
value
,
disabledByToggle
})
=>
{
({
elementName
,
modelName
,
value
,
disabledByToggle
})
=>
{
...
@@ -128,9 +128,9 @@ describe('Expiration Policy Form', () => {
...
@@ -128,9 +128,9 @@ describe('Expiration Policy Form', () => {
});
});
describe
.
each
`
describe
.
each
`
modelName
| elementName
modelName | elementName
${
'
name
_regex
'
}
|
${
'
name-matching
'
}
${
'
name
Regex
'
}
|
${
'
name-matching
'
}
${
'
name
_regex_k
eep
'
}
|
${
'
keep-name
'
}
${
'
name
RegexK
eep
'
}
|
${
'
keep-name
'
}
`
(
'
regex textarea validation
'
,
({
modelName
,
elementName
})
=>
{
`
(
'
regex textarea validation
'
,
({
modelName
,
elementName
})
=>
{
const
invalidString
=
new
Array
(
NAME_REGEX_LENGTH
+
2
).
join
(
'
,
'
);
const
invalidString
=
new
Array
(
NAME_REGEX_LENGTH
+
2
).
join
(
'
,
'
);
...
...
This diff is collapsed.
Click to expand it.
spec/frontend/registry/shared/stubs.js
0 → 100644
View file @
2520e00b
export
const
GlLoadingIcon
=
{
name
:
'
gl-loading-icon-stub
'
,
template
:
'
<svg></svg>
'
};
export
const
GlCard
=
{
name
:
'
gl-card-stub
'
,
template
:
`
<div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
`
,
};
This diff is collapsed.
Click to expand it.
spec/frontend/registry/shared/utils_spec.js
View file @
2520e00b
import
{
formOptionsGenerator
,
optionLabelGenerator
}
from
'
~/registry/shared/utils
'
;
import
{
formOptionsGenerator
,
optionLabelGenerator
,
olderThanTranslationGenerator
,
}
from
'
~/registry/shared/utils
'
;
describe
(
'
Utils
'
,
()
=>
{
describe
(
'
Utils
'
,
()
=>
{
describe
(
'
optionLabelGenerator
'
,
()
=>
{
describe
(
'
optionLabelGenerator
'
,
()
=>
{
it
(
'
returns an array with a set label
'
,
()
=>
{
it
(
'
returns an array with a set label
'
,
()
=>
{
const
result
=
optionLabelGenerator
([{
variable
:
1
},
{
variable
:
2
}],
'
%d day
'
,
'
%d days
'
);
const
result
=
optionLabelGenerator
(
expect
(
result
).
toEqual
([{
variable
:
1
,
label
:
'
1 day
'
},
{
variable
:
2
,
label
:
'
2 days
'
}]);
[{
variable
:
1
},
{
variable
:
2
}],
olderThanTranslationGenerator
,
);
expect
(
result
).
toEqual
([
{
variable
:
1
,
label
:
'
1 day until tags are automatically removed
'
},
{
variable
:
2
,
label
:
'
2 days until tags are automatically removed
'
},
]);
});
});
});
});
...
...
This diff is collapsed.
Click to expand it.
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