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
16992141
Commit
16992141
authored
Oct 25, 2018
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-10-25
parents
8a23167e
f5d71ad8
Changes
56
Show whitespace changes
Inline
Side-by-side
Showing
56 changed files
with
863 additions
and
694 deletions
+863
-694
.gitlab-ci.yml
.gitlab-ci.yml
+3
-3
.ruby-version
.ruby-version
+1
-1
app/assets/javascripts/breadcrumb.js
app/assets/javascripts/breadcrumb.js
+8
-7
app/assets/javascripts/build_artifacts.js
app/assets/javascripts/build_artifacts.js
+11
-7
app/assets/javascripts/ci_variable_list/ajax_variable_list.js
...assets/javascripts/ci_variable_list/ajax_variable_list.js
+29
-27
app/assets/javascripts/ci_variable_list/ci_variable_list.js
app/assets/javascripts/ci_variable_list/ci_variable_list.js
+21
-16
app/assets/javascripts/ci_variable_list/native_form_variable_list.js
...javascripts/ci_variable_list/native_form_variable_list.js
+1
-4
app/assets/javascripts/clusters/stores/clusters_store.js
app/assets/javascripts/clusters/stores/clusters_store.js
+2
-6
app/assets/javascripts/comment_type_toggle.js
app/assets/javascripts/comment_type_toggle.js
+32
-24
app/assets/javascripts/commit/image_file.js
app/assets/javascripts/commit/image_file.js
+179
-141
app/assets/javascripts/commit/pipelines/pipelines_bundle.js
app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+6
-4
app/assets/javascripts/commit/pipelines/pipelines_table.vue
app/assets/javascripts/commit/pipelines/pipelines_table.vue
+59
-63
app/assets/javascripts/commit_merge_requests.js
app/assets/javascripts/commit_merge_requests.js
+4
-3
app/assets/javascripts/commits.js
app/assets/javascripts/commits.js
+27
-11
app/assets/javascripts/commons/bootstrap.js
app/assets/javascripts/commons/bootstrap.js
+10
-2
app/assets/javascripts/confirm_danger_modal.js
app/assets/javascripts/confirm_danger_modal.js
+14
-10
app/assets/javascripts/contextual_sidebar.js
app/assets/javascripts/contextual_sidebar.js
+5
-2
app/assets/javascripts/create_item_dropdown.js
app/assets/javascripts/create_item_dropdown.js
+5
-8
app/assets/javascripts/create_label.js
app/assets/javascripts/create_label.js
+31
-32
app/assets/javascripts/deploy_keys/components/app.vue
app/assets/javascripts/deploy_keys/components/app.vue
+4
-2
app/assets/javascripts/deploy_keys/service/index.js
app/assets/javascripts/deploy_keys/service/index.js
+3
-6
app/assets/javascripts/diff.js
app/assets/javascripts/diff.js
+9
-5
app/assets/javascripts/dropzone_input.js
app/assets/javascripts/dropzone_input.js
+26
-15
app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js
...s/javascripts/emoji/support/is_emoji_unicode_supported.js
+30
-25
app/assets/javascripts/experimental_flags.js
app/assets/javascripts/experimental_flags.js
+1
-1
app/assets/javascripts/files_comment_button.js
app/assets/javascripts/files_comment_button.js
+8
-4
app/assets/javascripts/filterable_list.js
app/assets/javascripts/filterable_list.js
+16
-9
app/assets/javascripts/flash.js
app/assets/javascripts/flash.js
+17
-16
app/assets/javascripts/fly_out_nav.js
app/assets/javascripts/fly_out_nav.js
+33
-19
app/assets/javascripts/gl_field_error.js
app/assets/javascripts/gl_field_error.js
+2
-1
app/assets/javascripts/gl_field_errors.js
app/assets/javascripts/gl_field_errors.js
+9
-5
app/assets/javascripts/gl_form.js
app/assets/javascripts/gl_form.js
+12
-7
app/assets/javascripts/group_avatar.js
app/assets/javascripts/group_avatar.js
+3
-2
app/assets/javascripts/group_label_subscription.js
app/assets/javascripts/group_label_subscription.js
+7
-3
app/assets/javascripts/groups/components/item_stats.vue
app/assets/javascripts/groups/components/item_stats.vue
+36
-36
app/assets/javascripts/groups/components/item_stats_value.vue
...assets/javascripts/groups/components/item_stats_value.vue
+43
-43
app/assets/javascripts/groups/new_group_child.js
app/assets/javascripts/groups/new_group_child.js
+12
-10
app/assets/javascripts/groups/store/groups_store.js
app/assets/javascripts/groups/store/groups_store.js
+12
-11
app/assets/javascripts/groups/transfer_dropdown.js
app/assets/javascripts/groups/transfer_dropdown.js
+1
-1
app/assets/javascripts/groups_select.js
app/assets/javascripts/groups_select.js
+6
-3
app/assets/javascripts/helpers/avatar_helper.js
app/assets/javascripts/helpers/avatar_helper.js
+3
-1
app/assets/javascripts/image_diff/image_diff.js
app/assets/javascripts/image_diff/image_diff.js
+4
-2
app/assets/javascripts/image_diff/init_discussion_tab.js
app/assets/javascripts/image_diff/init_discussion_tab.js
+2
-1
app/assets/javascripts/image_diff/replaced_image_diff.js
app/assets/javascripts/image_diff/replaced_image_diff.js
+7
-8
app/assets/javascripts/importer_status.js
app/assets/javascripts/importer_status.js
+62
-60
app/assets/javascripts/init_changes_dropdown.js
app/assets/javascripts/init_changes_dropdown.js
+1
-1
app/assets/javascripts/init_notes.js
app/assets/javascripts/init_notes.js
+1
-7
app/assets/javascripts/integrations/integration_settings_form.js
...ets/javascripts/integrations/integration_settings_form.js
+3
-2
app/assets/javascripts/issuable/auto_width_dropdown_select.js
...assets/javascripts/issuable/auto_width_dropdown_select.js
+4
-1
app/assets/javascripts/issuable_bulk_update_actions.js
app/assets/javascripts/issuable_bulk_update_actions.js
+5
-5
app/views/instance_statistics/conversational_development_index/_disabled.html.haml
...tics/conversational_development_index/_disabled.html.haml
+1
-1
bin/secpick
bin/secpick
+10
-4
changelogs/unreleased/53070-fix-enable-usage-ping-link.yml
changelogs/unreleased/53070-fix-enable-usage-ping-link.yml
+5
-0
doc/install/installation.md
doc/install/installation.md
+3
-3
doc/update/11.3-to-11.4.md
doc/update/11.3-to-11.4.md
+3
-3
lib/tasks/haml-lint.rake
lib/tasks/haml-lint.rake
+11
-0
No files found.
.gitlab-ci.yml
View file @
16992141
image
:
"
dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.
4
-golang-1.9-git-2.18-chrome-69.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29"
image
:
"
dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.
5
-golang-1.9-git-2.18-chrome-69.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29"
.dedicated-runner
:
&dedicated-runner
retry
:
1
...
...
@@ -6,7 +6,7 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git
-
gitlab-org
.default-cache
:
&default-cache
key
:
"
ruby-2.4.
4
-debian-stretch-with-yarn"
key
:
"
ruby-2.4.
5
-debian-stretch-with-yarn"
paths
:
-
vendor/ruby
-
.yarn-cache/
...
...
@@ -752,7 +752,7 @@ static-analysis:
script
:
-
scripts/static-analysis
cache
:
key
:
"
ruby-2.4.
4
-debian-stretch-with-yarn-and-rubocop"
key
:
"
ruby-2.4.
5
-debian-stretch-with-yarn-and-rubocop"
paths
:
-
vendor/ruby
-
.yarn-cache/
...
...
.ruby-version
View file @
16992141
2.4.
4
2.4.
5
app/assets/javascripts/breadcrumb.js
View file @
16992141
import
$
from
'
jquery
'
;
export
const
addTooltipToEl
=
(
el
)
=>
{
export
const
addTooltipToEl
=
el
=>
{
const
textEl
=
el
.
querySelector
(
'
.js-breadcrumb-item-text
'
);
if
(
textEl
&&
textEl
.
scrollWidth
>
textEl
.
offsetWidth
)
{
...
...
@@ -14,16 +14,17 @@ export default () => {
const
breadcrumbs
=
document
.
querySelector
(
'
.js-breadcrumbs-list
'
);
if
(
breadcrumbs
)
{
const
topLevelLinks
=
[...
breadcrumbs
.
children
].
filter
(
el
=>
!
el
.
classList
.
contains
(
'
dropdown
'
))
const
topLevelLinks
=
[...
breadcrumbs
.
children
]
.
filter
(
el
=>
!
el
.
classList
.
contains
(
'
dropdown
'
))
.
map
(
el
=>
el
.
querySelector
(
'
a
'
))
.
filter
(
el
=>
el
);
const
$expander
=
$
(
'
.js-breadcrumbs-collapsed-expander
'
);
topLevelLinks
.
forEach
(
el
=>
addTooltipToEl
(
el
));
$expander
.
closest
(
'
.dropdown
'
)
.
on
(
'
show.bs.dropdown hide.bs.dropdown
'
,
(
e
)
=>
{
$
(
'
.js-breadcrumbs-collapsed-expander
'
,
e
.
currentTarget
)
.
toggleClass
(
'
open
'
)
$expander
.
closest
(
'
.dropdown
'
)
.
on
(
'
show.bs.dropdown hide.bs.dropdown
'
,
e
=>
{
$
(
'
.js-breadcrumbs-collapsed-expander
'
,
e
.
currentTarget
)
.
toggleClass
(
'
open
'
)
.
tooltip
(
'
hide
'
);
});
}
...
...
app/assets/javascripts/build_artifacts.js
View file @
16992141
...
...
@@ -12,16 +12,16 @@ export default class BuildArtifacts {
}
// eslint-disable-next-line class-methods-use-this
disablePropagation
()
{
$
(
'
.top-block
'
).
on
(
'
click
'
,
'
.download
'
,
function
(
e
)
{
$
(
'
.top-block
'
).
on
(
'
click
'
,
'
.download
'
,
function
(
e
)
{
return
e
.
stopPropagation
();
});
return
$
(
'
.tree-holder
'
).
on
(
'
click
'
,
'
tr[data-link] a
'
,
function
(
e
)
{
return
$
(
'
.tree-holder
'
).
on
(
'
click
'
,
'
tr[data-link] a
'
,
function
(
e
)
{
return
e
.
stopImmediatePropagation
();
});
}
// eslint-disable-next-line class-methods-use-this
setupEntryClick
()
{
return
$
(
'
.tree-holder
'
).
on
(
'
click
'
,
'
tr[data-link]
'
,
function
()
{
return
$
(
'
.tree-holder
'
).
on
(
'
click
'
,
'
tr[data-link]
'
,
function
()
{
visitUrl
(
this
.
dataset
.
link
,
convertPermissionToBoolean
(
this
.
dataset
.
externalLink
));
});
}
...
...
@@ -37,11 +37,15 @@ export default class BuildArtifacts {
// We want the tooltip to show if you hover anywhere on the row
// But be placed below and in the middle of the file name
$
(
'
.js-artifact-tree-row
'
)
.
on
(
'
mouseenter
'
,
(
e
)
=>
{
$
(
e
.
currentTarget
).
find
(
'
.js-artifact-tree-tooltip
'
).
tooltip
(
'
show
'
);
.
on
(
'
mouseenter
'
,
e
=>
{
$
(
e
.
currentTarget
)
.
find
(
'
.js-artifact-tree-tooltip
'
)
.
tooltip
(
'
show
'
);
})
.
on
(
'
mouseleave
'
,
(
e
)
=>
{
$
(
e
.
currentTarget
).
find
(
'
.js-artifact-tree-tooltip
'
).
tooltip
(
'
hide
'
);
.
on
(
'
mouseleave
'
,
e
=>
{
$
(
e
.
currentTarget
)
.
find
(
'
.js-artifact-tree-tooltip
'
)
.
tooltip
(
'
hide
'
);
});
}
}
app/assets/javascripts/ci_variable_list/ajax_variable_list.js
View file @
16992141
...
...
@@ -7,11 +7,13 @@ import statusCodes from '../lib/utils/http_status';
import
VariableList
from
'
./ci_variable_list
'
;
function
generateErrorBoxContent
(
errors
)
{
const
errorList
=
[].
concat
(
errors
).
map
(
errorString
=>
`
const
errorList
=
[].
concat
(
errors
).
map
(
errorString
=>
`
<li>
${
_
.
escape
(
errorString
)}
</li>
`
);
`
,
);
return
`
<p>
...
...
@@ -25,13 +27,7 @@ function generateErrorBoxContent(errors) {
// Used for the variable list on CI/CD projects/groups settings page
export
default
class
AjaxVariableList
{
constructor
({
container
,
saveButton
,
errorBox
,
formField
=
'
variables
'
,
saveEndpoint
,
})
{
constructor
({
container
,
saveButton
,
errorBox
,
formField
=
'
variables
'
,
saveEndpoint
})
{
this
.
container
=
container
;
this
.
saveButton
=
saveButton
;
this
.
errorBox
=
errorBox
;
...
...
@@ -58,18 +54,21 @@ export default class AjaxVariableList {
// to match it up in `updateRowsWithPersistedVariables`
this
.
variableList
.
toggleEnableRow
(
false
);
return
axios
.
patch
(
this
.
saveEndpoint
,
{
return
axios
.
patch
(
this
.
saveEndpoint
,
{
variables_attributes
:
this
.
variableList
.
getAllData
(),
},
{
},
{
// We want to be able to process the `res.data` from a 400 error response
// and print the validation messages such as duplicate variable keys
validateStatus
:
status
=>
(
status
>=
statusCodes
.
OK
&&
status
<
statusCodes
.
MULTIPLE_CHOICES
)
||
validateStatus
:
status
=>
(
status
>=
statusCodes
.
OK
&&
status
<
statusCodes
.
MULTIPLE_CHOICES
)
||
status
===
statusCodes
.
BAD_REQUEST
,
})
.
then
((
res
)
=>
{
},
)
.
then
(
res
=>
{
loadingIcon
.
classList
.
toggle
(
'
hide
'
,
true
);
this
.
variableList
.
toggleEnableRow
(
true
);
...
...
@@ -90,12 +89,15 @@ export default class AjaxVariableList {
}
updateRowsWithPersistedVariables
(
persistedVariables
=
[])
{
const
persistedVariableMap
=
[].
concat
(
persistedVariables
).
reduce
((
variableMap
,
variable
)
=>
({
const
persistedVariableMap
=
[].
concat
(
persistedVariables
).
reduce
(
(
variableMap
,
variable
)
=>
({
...
variableMap
,
[
variable
.
key
]:
variable
,
}),
{});
}),
{},
);
this
.
container
.
querySelectorAll
(
'
.js-row
'
).
forEach
(
(
row
)
=>
{
this
.
container
.
querySelectorAll
(
'
.js-row
'
).
forEach
(
row
=>
{
// If we submitted a row that was destroyed, remove it so we don't try
// to destroy it again which would cause a BE error
const
destroyInput
=
row
.
querySelector
(
'
.js-ci-variable-input-destroy
'
);
...
...
app/assets/javascripts/ci_variable_list/ci_variable_list.js
View file @
16992141
...
...
@@ -16,10 +16,7 @@ function createEnvironmentItem(value) {
}
export
default
class
VariableList
{
constructor
({
container
,
formField
,
})
{
constructor
({
container
,
formField
})
{
this
.
$container
=
$
(
container
);
this
.
formField
=
formField
;
this
.
environmentDropdownMap
=
new
WeakMap
();
...
...
@@ -71,7 +68,7 @@ export default class VariableList {
this
.
initRow
(
rowEl
);
});
this
.
$container
.
on
(
'
click
'
,
'
.js-row-remove-button
'
,
(
e
)
=>
{
this
.
$container
.
on
(
'
click
'
,
'
.js-row-remove-button
'
,
e
=>
{
e
.
preventDefault
();
this
.
removeRow
(
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
));
});
...
...
@@ -81,7 +78,7 @@ export default class VariableList {
.
join
(
'
,
'
);
// Remove any empty rows except the last row
this
.
$container
.
on
(
'
blur
'
,
inputSelector
,
(
e
)
=>
{
this
.
$container
.
on
(
'
blur
'
,
inputSelector
,
e
=>
{
const
$row
=
$
(
e
.
currentTarget
).
closest
(
'
.js-row
'
);
if
(
$row
.
is
(
'
:not(:last-child)
'
)
&&
!
this
.
checkIfRowTouched
(
$row
))
{
...
...
@@ -136,7 +133,7 @@ export default class VariableList {
$rowClone
.
removeAttr
(
'
data-is-persisted
'
);
// Reset the inputs to their defaults
Object
.
keys
(
this
.
inputMap
).
forEach
(
(
name
)
=>
{
Object
.
keys
(
this
.
inputMap
).
forEach
(
name
=>
{
const
entry
=
this
.
inputMap
[
name
];
$rowClone
.
find
(
entry
.
selector
).
val
(
entry
.
default
);
});
...
...
@@ -171,7 +168,7 @@ export default class VariableList {
}
checkIfRowTouched
(
$row
)
{
return
Object
.
keys
(
this
.
inputMap
).
some
(
(
name
)
=>
{
return
Object
.
keys
(
this
.
inputMap
).
some
(
name
=>
{
const
entry
=
this
.
inputMap
[
name
];
const
$el
=
$row
.
find
(
entry
.
selector
);
return
$el
.
length
&&
$el
.
val
()
!==
entry
.
default
;
...
...
@@ -190,11 +187,14 @@ export default class VariableList {
getAllData
()
{
// Ignore the last empty row because we don't want to try persist
// a blank variable and run into validation problems.
const
validRows
=
this
.
$container
.
find
(
'
.js-row
'
).
toArray
().
slice
(
0
,
-
1
);
const
validRows
=
this
.
$container
.
find
(
'
.js-row
'
)
.
toArray
()
.
slice
(
0
,
-
1
);
return
validRows
.
map
(
(
rowEl
)
=>
{
return
validRows
.
map
(
rowEl
=>
{
const
resultant
=
{};
Object
.
keys
(
this
.
inputMap
).
forEach
(
(
name
)
=>
{
Object
.
keys
(
this
.
inputMap
).
forEach
(
name
=>
{
const
entry
=
this
.
inputMap
[
name
];
const
$input
=
$
(
rowEl
).
find
(
entry
.
selector
);
if
(
$input
.
length
)
{
...
...
@@ -207,11 +207,16 @@ export default class VariableList {
}
getEnvironmentValues
()
{
const
valueMap
=
this
.
$container
.
find
(
this
.
inputMap
.
environment_scope
.
selector
).
toArray
()
.
reduce
((
prevValueMap
,
envInput
)
=>
({
const
valueMap
=
this
.
$container
.
find
(
this
.
inputMap
.
environment_scope
.
selector
)
.
toArray
()
.
reduce
(
(
prevValueMap
,
envInput
)
=>
({
...
prevValueMap
,
[
envInput
.
value
]:
envInput
.
value
,
}),
{});
}),
{},
);
return
Object
.
keys
(
valueMap
).
map
(
createEnvironmentItem
);
}
...
...
app/assets/javascripts/ci_variable_list/native_form_variable_list.js
View file @
16992141
...
...
@@ -2,10 +2,7 @@ import $ from 'jquery';
import
VariableList
from
'
./ci_variable_list
'
;
// Used for the variable list on scheduled pipeline edit page
export
default
function
setupNativeFormVariableList
({
container
,
formField
=
'
variables
'
,
})
{
export
default
function
setupNativeFormVariableList
({
container
,
formField
=
'
variables
'
})
{
const
$container
=
$
(
container
);
const
variableList
=
new
VariableList
({
...
...
app/assets/javascripts/clusters/stores/clusters_store.js
View file @
16992141
...
...
@@ -76,12 +76,8 @@ export default class ClusterStore {
this
.
state
.
status
=
serverState
.
status
;
this
.
state
.
statusReason
=
serverState
.
status_reason
;
serverState
.
applications
.
forEach
((
serverAppEntry
)
=>
{
const
{
name
:
appId
,
status
,
status_reason
:
statusReason
,
}
=
serverAppEntry
;
serverState
.
applications
.
forEach
(
serverAppEntry
=>
{
const
{
name
:
appId
,
status
,
status_reason
:
statusReason
}
=
serverAppEntry
;
this
.
state
.
applications
[
appId
]
=
{
...(
this
.
state
.
applications
[
appId
]
||
{}),
...
...
app/assets/javascripts/comment_type_toggle.js
View file @
16992141
...
...
@@ -24,36 +24,44 @@ class CommentTypeToggle {
setConfig
()
{
const
config
=
{
InputSetter
:
[{
InputSetter
:
[
{
input
:
this
.
noteTypeInput
,
valueAttribute
:
'
data-value
'
,
},
{
input
:
this
.
submitButton
,
valueAttribute
:
'
data-submit-text
'
,
}],
},
],
};
if
(
this
.
closeButton
)
{
config
.
InputSetter
.
push
({
config
.
InputSetter
.
push
(
{
input
:
this
.
closeButton
,
valueAttribute
:
'
data-close-text
'
,
},
{
},
{
input
:
this
.
closeButton
,
valueAttribute
:
'
data-close-text
'
,
inputAttribute
:
'
data-alternative-text
'
,
});
},
);
}
if
(
this
.
reopenButton
)
{
config
.
InputSetter
.
push
({
config
.
InputSetter
.
push
(
{
input
:
this
.
reopenButton
,
valueAttribute
:
'
data-reopen-text
'
,
},
{
},
{
input
:
this
.
reopenButton
,
valueAttribute
:
'
data-reopen-text
'
,
inputAttribute
:
'
data-alternative-text
'
,
});
},
);
}
return
config
;
...
...
app/assets/javascripts/commit/image_file.js
View file @
16992141
...
...
@@ -9,9 +9,14 @@ const viewModes = ['two-up', 'swipe'];
export
default
class
ImageFile
{
constructor
(
file
)
{
this
.
file
=
file
;
this
.
requestImageInfo
(
$
(
'
.two-up.view .frame.deleted img
'
,
this
.
file
),
(
function
(
_this
)
{
this
.
requestImageInfo
(
$
(
'
.two-up.view .frame.deleted img
'
,
this
.
file
),
(
function
(
_this
)
{
return
function
(
deletedWidth
,
deletedHeight
)
{
return
_this
.
requestImageInfo
(
$
(
'
.two-up.view .frame.added img
'
,
_this
.
file
),
function
(
width
,
height
)
{
return
_this
.
requestImageInfo
(
$
(
'
.two-up.view .frame.added img
'
,
_this
.
file
),
function
(
width
,
height
,
)
{
_this
.
initViewModes
();
// Load two-up view after images are loaded
...
...
@@ -23,30 +28,41 @@ export default class ImageFile {
});
});
};
})(
this
));
})(
this
),
);
}
initViewModes
()
{
const
viewMode
=
viewModes
[
0
];
$
(
'
.view-modes
'
,
this
.
file
).
removeClass
(
'
hide
'
);
$
(
'
.view-modes-menu
'
,
this
.
file
).
on
(
'
click
'
,
'
li
'
,
(
function
(
_this
)
{
$
(
'
.view-modes-menu
'
,
this
.
file
).
on
(
'
click
'
,
'
li
'
,
(
function
(
_this
)
{
return
function
(
event
)
{
if
(
!
$
(
event
.
currentTarget
).
hasClass
(
'
active
'
))
{
return
_this
.
activateViewMode
(
event
.
currentTarget
.
className
);
}
};
})(
this
));
})(
this
),
);
return
this
.
activateViewMode
(
viewMode
);
}
activateViewMode
(
viewMode
)
{
$
(
'
.view-modes-menu li
'
,
this
.
file
).
removeClass
(
'
active
'
).
filter
(
"
.
"
+
viewMode
).
addClass
(
'
active
'
);
return
$
(
"
.view:visible:not(.
"
+
viewMode
+
"
)
"
,
this
.
file
).
fadeOut
(
200
,
(
function
(
_this
)
{
$
(
'
.view-modes-menu li
'
,
this
.
file
)
.
removeClass
(
'
active
'
)
.
filter
(
'
.
'
+
viewMode
)
.
addClass
(
'
active
'
);
return
$
(
'
.view:visible:not(.
'
+
viewMode
+
'
)
'
,
this
.
file
).
fadeOut
(
200
,
(
function
(
_this
)
{
return
function
()
{
$
(
"
.view.
"
+
viewMode
,
_this
.
file
).
fadeIn
(
200
);
$
(
'
.view.
'
+
viewMode
,
_this
.
file
).
fadeIn
(
200
);
return
_this
.
initView
(
viewMode
);
};
})(
this
));
})(
this
),
);
}
initView
(
viewMode
)
{
...
...
@@ -63,7 +79,10 @@ export default class ImageFile {
$body
.
css
(
'
user-select
'
,
'
none
'
);
});
$body
.
off
(
'
mouseup
'
).
off
(
'
mousemove
'
).
on
(
'
mouseup
'
,
function
()
{
$body
.
off
(
'
mouseup
'
)
.
off
(
'
mousemove
'
)
.
on
(
'
mouseup
'
,
function
()
{
dragging
=
false
;
$body
.
css
(
'
user-select
'
,
''
);
})
...
...
@@ -81,24 +100,29 @@ export default class ImageFile {
var
maxHeight
,
maxWidth
;
maxWidth
=
0
;
maxHeight
=
0
;
$
(
'
.frame
'
,
view
).
each
((
function
(
_this
)
{
$
(
'
.frame
'
,
view
)
.
each
(
(
function
(
_this
)
{
return
function
(
index
,
frame
)
{
var
height
,
width
;
width
=
$
(
frame
).
width
();
height
=
$
(
frame
).
height
();
maxWidth
=
width
>
maxWidth
?
width
:
maxWidth
;
return
maxHeight
=
height
>
maxHeight
?
height
:
maxHeight
;
return
(
maxHeight
=
height
>
maxHeight
?
height
:
maxHeight
)
;
};
})(
this
)).
css
({
})(
this
),
)
.
css
({
width
:
maxWidth
,
height
:
maxHeight
height
:
maxHeight
,
});
return
[
maxWidth
,
maxHeight
];
}
views
=
{
'
two-up
'
:
function
()
{
return
$
(
'
.two-up.view .wrap
'
,
this
.
file
).
each
((
function
(
_this
)
{
return
$
(
'
.two-up.view .wrap
'
,
this
.
file
).
each
(
(
function
(
_this
)
{
return
function
(
index
,
wrap
)
{
$
(
'
img
'
,
wrap
).
each
(
function
()
{
var
currentWidth
;
...
...
@@ -108,58 +132,68 @@ export default class ImageFile {
}
});
return
_this
.
requestImageInfo
(
$
(
'
img
'
,
wrap
),
function
(
width
,
height
)
{
$
(
'
.image-info .meta-width
'
,
wrap
).
text
(
width
+
"
px
"
);
$
(
'
.image-info .meta-height
'
,
wrap
).
text
(
height
+
"
px
"
);
$
(
'
.image-info .meta-width
'
,
wrap
).
text
(
width
+
'
px
'
);
$
(
'
.image-info .meta-height
'
,
wrap
).
text
(
height
+
'
px
'
);
return
$
(
'
.image-info
'
,
wrap
).
removeClass
(
'
hide
'
);
});
};
})(
this
));
})(
this
),
);
},
'
swipe
'
:
function
()
{
swipe
()
{
var
maxHeight
,
maxWidth
;
maxWidth
=
0
;
maxHeight
=
0
;
return
$
(
'
.swipe.view
'
,
this
.
file
).
each
((
function
(
_this
)
{
return
$
(
'
.swipe.view
'
,
this
.
file
).
each
(
(
function
(
_this
)
{
return
function
(
index
,
view
)
{
var
$swipeWrap
,
$swipeBar
,
$swipeFrame
,
wrapPadding
,
ref
;
ref
=
_this
.
prepareFrames
(
view
),
[
maxWidth
,
maxHeight
]
=
ref
;
(
ref
=
_this
.
prepareFrames
(
view
)),
([
maxWidth
,
maxHeight
]
=
ref
)
;
$swipeFrame
=
$
(
'
.swipe-frame
'
,
view
);
$swipeWrap
=
$
(
'
.swipe-wrap
'
,
view
);
$swipeBar
=
$
(
'
.swipe-bar
'
,
view
);
$swipeFrame
.
css
({
width
:
maxWidth
+
16
,
height
:
maxHeight
+
28
height
:
maxHeight
+
28
,
});
$swipeWrap
.
css
({
width
:
maxWidth
+
1
,
height
:
maxHeight
+
2
height
:
maxHeight
+
2
,
});
// Set swipeBar left position to match image frame
$swipeBar
.
css
({
left
:
1
left
:
1
,
});
wrapPadding
=
parseInt
(
$swipeWrap
.
css
(
'
right
'
).
replace
(
'
px
'
,
''
),
10
);
_this
.
initDraggable
(
$swipeBar
,
wrapPadding
,
function
(
e
,
left
)
{
if
(
left
>
0
&&
left
<
$swipeFrame
.
width
()
-
(
wrapPadding
*
2
)
)
{
$swipeWrap
.
width
((
maxWidth
+
1
)
-
left
);
if
(
left
>
0
&&
left
<
$swipeFrame
.
width
()
-
wrapPadding
*
2
)
{
$swipeWrap
.
width
(
maxWidth
+
1
-
left
);
$swipeBar
.
css
(
'
left
'
,
left
);
}
});
};
})(
this
));
})(
this
),
);
},
'
onion-skin
'
:
function
()
{
var
dragTrackWidth
,
maxHeight
,
maxWidth
;
maxWidth
=
0
;
maxHeight
=
0
;
dragTrackWidth
=
$
(
'
.drag-track
'
,
this
.
file
).
width
()
-
$
(
'
.dragger
'
,
this
.
file
).
width
();
return
$
(
'
.onion-skin.view
'
,
this
.
file
).
each
((
function
(
_this
)
{
return
$
(
'
.onion-skin.view
'
,
this
.
file
).
each
(
(
function
(
_this
)
{
return
function
(
index
,
view
)
{
var
$frame
,
$track
,
$dragger
,
$frameAdded
,
framePadding
,
ref
,
dragging
=
false
;
ref
=
_this
.
prepareFrames
(
view
),
[
maxWidth
,
maxHeight
]
=
ref
;
var
$frame
,
$track
,
$dragger
,
$frameAdded
,
framePadding
,
ref
,
dragging
=
false
;
(
ref
=
_this
.
prepareFrames
(
view
)),
([
maxWidth
,
maxHeight
]
=
ref
);
$frame
=
$
(
'
.onion-skin-frame
'
,
view
);
$frameAdded
=
$
(
'
.frame.added
'
,
view
);
$track
=
$
(
'
.drag-track
'
,
view
);
...
...
@@ -167,14 +201,14 @@ export default class ImageFile {
$frame
.
css
({
width
:
maxWidth
+
16
,
height
:
maxHeight
+
28
height
:
maxHeight
+
28
,
});
$
(
'
.swipe-wrap
'
,
view
).
css
({
width
:
maxWidth
+
1
,
height
:
maxHeight
+
2
height
:
maxHeight
+
2
,
});
$dragger
.
css
({
left
:
dragTrackWidth
left
:
dragTrackWidth
,
});
$frameAdded
.
css
(
'
opacity
'
,
1
);
...
...
@@ -189,9 +223,10 @@ export default class ImageFile {
}
});
};
})(
this
));
}
}
})(
this
),
);
},
};
requestImageInfo
(
img
,
callback
)
{
const
domImg
=
img
.
get
(
0
);
...
...
@@ -199,11 +234,14 @@ export default class ImageFile {
if
(
domImg
.
complete
)
{
return
callback
.
call
(
this
,
domImg
.
naturalWidth
,
domImg
.
naturalHeight
);
}
else
{
return
img
.
on
(
'
load
'
,
(
function
(
_this
)
{
return
img
.
on
(
'
load
'
,
(
function
(
_this
)
{
return
function
()
{
return
callback
.
call
(
_this
,
domImg
.
naturalWidth
,
domImg
.
naturalHeight
);
};
})(
this
));
})(
this
),
);
}
}
}
...
...
app/assets/javascripts/commit/pipelines/pipelines_bundle.js
View file @
16992141
...
...
@@ -20,10 +20,12 @@ export default () => {
if
(
pipelineTableViewEl
)
{
// Update MR and Commits tabs
pipelineTableViewEl
.
addEventListener
(
'
update-pipelines-count
'
,
(
event
)
=>
{
if
(
event
.
detail
.
pipelines
&&
pipelineTableViewEl
.
addEventListener
(
'
update-pipelines-count
'
,
event
=>
{
if
(
event
.
detail
.
pipelines
&&
event
.
detail
.
pipelines
.
count
&&
event
.
detail
.
pipelines
.
count
.
all
)
{
event
.
detail
.
pipelines
.
count
.
all
)
{
const
badge
=
document
.
querySelector
(
'
.js-pipelines-mr-count
'
);
badge
.
textContent
=
event
.
detail
.
pipelines
.
count
.
all
;
...
...
app/assets/javascripts/commit/pipelines/pipelines_table.vue
View file @
16992141
<
script
>
import
PipelinesService
from
'
../../pipelines/services/pipelines_service
'
;
import
PipelineStore
from
'
../../pipelines/stores/pipelines_store
'
;
import
pipelinesMixin
from
'
../../pipelines/mixins/pipelines
'
;
import
PipelinesService
from
'
../../pipelines/services/pipelines_service
'
;
import
PipelineStore
from
'
../../pipelines/stores/pipelines_store
'
;
import
pipelinesMixin
from
'
../../pipelines/mixins/pipelines
'
;
export
default
{
mixins
:
[
pipelinesMixin
,
],
export
default
{
mixins
:
[
pipelinesMixin
],
props
:
{
endpoint
:
{
type
:
String
,
...
...
@@ -42,9 +40,7 @@
computed
:
{
shouldRenderTable
()
{
return
!
this
.
isLoading
&&
this
.
state
.
pipelines
.
length
>
0
&&
!
this
.
hasError
;
return
!
this
.
isLoading
&&
this
.
state
.
pipelines
.
length
>
0
&&
!
this
.
hasError
;
},
shouldRenderErrorState
()
{
return
this
.
hasError
&&
!
this
.
isLoading
;
...
...
@@ -71,7 +67,7 @@
}
},
},
};
};
</
script
>
<
template
>
<div
class=
"content-list pipelines"
>
...
...
app/assets/javascripts/commit_merge_requests.js
View file @
16992141
...
...
@@ -50,7 +50,7 @@ export function createContent(mergeRequests) {
if
(
mergeRequests
.
length
===
0
)
{
$content
.
text
(
s__
(
'
Commits|No related merge requests found
'
));
}
else
{
mergeRequests
.
forEach
(
(
mergeRequest
)
=>
{
mergeRequests
.
forEach
(
mergeRequest
=>
{
const
$header
=
createHeader
(
$content
.
children
().
length
,
mergeRequests
.
length
);
const
$item
=
createItem
(
mergeRequest
);
$content
.
append
(
$header
);
...
...
@@ -64,8 +64,9 @@ export function createContent(mergeRequests) {
export
function
fetchCommitMergeRequests
()
{
const
$container
=
$
(
'
.merge-requests
'
);
axios
.
get
(
$container
.
data
(
'
projectCommitPath
'
))
.
then
((
response
)
=>
{
axios
.
get
(
$container
.
data
(
'
projectCommitPath
'
))
.
then
(
response
=>
{
const
$content
=
createContent
(
response
.
data
);
$container
.
html
(
$content
);
...
...
app/assets/javascripts/commits.js
View file @
16992141
...
...
@@ -32,11 +32,16 @@ export default class CommitsList {
if
(
search
===
this
.
lastSearch
)
return
Promise
.
resolve
();
const
commitsUrl
=
`
${
form
.
attr
(
'
action
'
)}
?
${
form
.
serialize
()}
`
;
this
.
content
.
fadeTo
(
'
fast
'
,
0.5
);
const
params
=
form
.
serializeArray
().
reduce
((
acc
,
obj
)
=>
Object
.
assign
(
acc
,
{
const
params
=
form
.
serializeArray
().
reduce
(
(
acc
,
obj
)
=>
Object
.
assign
(
acc
,
{
[
obj
.
name
]:
obj
.
value
,
}),
{});
}),
{},
);
return
axios
.
get
(
form
.
attr
(
'
action
'
),
{
return
axios
.
get
(
form
.
attr
(
'
action
'
),
{
params
,
})
.
then
(({
data
})
=>
{
...
...
@@ -45,9 +50,13 @@ export default class CommitsList {
this
.
content
.
fadeTo
(
'
fast
'
,
1.0
);
// Change url so if user reload a page - search results are saved
window
.
history
.
replaceState
({
window
.
history
.
replaceState
(
{
page
:
commitsUrl
,
},
document
.
title
,
commitsUrl
);
},
document
.
title
,
commitsUrl
,
);
})
.
catch
(()
=>
{
this
.
content
.
fadeTo
(
'
fast
'
,
1.0
);
...
...
@@ -75,8 +84,15 @@ export default class CommitsList {
processedData
=
$processedData
.
not
(
`li.js-commit-header[data-day='
${
loadedShownDayFirst
}
']`
);
// Update commits count in the previous commits header.
commitsCount
+=
Number
(
$
(
processedData
).
nextUntil
(
'
li.js-commit-header
'
).
first
().
find
(
'
li.commit
'
).
length
);
$commitsHeadersLast
.
find
(
'
span.commits-count
'
).
text
(
`
${
commitsCount
}
${
pluralize
(
'
commit
'
,
commitsCount
)}
`
);
commitsCount
+=
Number
(
$
(
processedData
)
.
nextUntil
(
'
li.js-commit-header
'
)
.
first
()
.
find
(
'
li.commit
'
).
length
,
);
$commitsHeadersLast
.
find
(
'
span.commits-count
'
)
.
text
(
`
${
commitsCount
}
${
pluralize
(
'
commit
'
,
commitsCount
)}
`
);
}
localTimeAgo
(
$processedData
.
find
(
'
.js-timeago
'
));
...
...
app/assets/javascripts/commons/bootstrap.js
View file @
16992141
...
...
@@ -5,6 +5,14 @@ import 'bootstrap';
// custom jQuery functions
$
.
fn
.
extend
({
disable
()
{
return
$
(
this
).
prop
(
'
disabled
'
,
true
).
addClass
(
'
disabled
'
);
},
enable
()
{
return
$
(
this
).
prop
(
'
disabled
'
,
false
).
removeClass
(
'
disabled
'
);
},
disable
()
{
return
$
(
this
)
.
prop
(
'
disabled
'
,
true
)
.
addClass
(
'
disabled
'
);
},
enable
()
{
return
$
(
this
)
.
prop
(
'
disabled
'
,
false
)
.
removeClass
(
'
disabled
'
);
},
});
app/assets/javascripts/confirm_danger_modal.js
View file @
16992141
...
...
@@ -13,7 +13,9 @@ function openConfirmDangerModal($form, text) {
$submit
.
disable
();
$input
.
focus
();
$
(
'
.js-confirm-danger-input
'
).
off
(
'
input
'
).
on
(
'
input
'
,
function
handleInput
()
{
$
(
'
.js-confirm-danger-input
'
)
.
off
(
'
input
'
)
.
on
(
'
input
'
,
function
handleInput
()
{
const
confirmText
=
rstrip
(
$
(
this
).
val
());
if
(
confirmText
===
confirmTextMatch
)
{
$submit
.
enable
();
...
...
@@ -21,11 +23,13 @@ function openConfirmDangerModal($form, text) {
$submit
.
disable
();
}
});
$
(
'
.js-confirm-danger-submit
'
).
off
(
'
click
'
).
on
(
'
click
'
,
()
=>
$form
.
submit
());
$
(
'
.js-confirm-danger-submit
'
)
.
off
(
'
click
'
)
.
on
(
'
click
'
,
()
=>
$form
.
submit
());
}
export
default
function
initConfirmDangerModal
()
{
$
(
document
).
on
(
'
click
'
,
'
.js-confirm-danger
'
,
(
e
)
=>
{
$
(
document
).
on
(
'
click
'
,
'
.js-confirm-danger
'
,
e
=>
{
e
.
preventDefault
();
const
$btn
=
$
(
e
.
target
);
const
$form
=
$btn
.
closest
(
'
form
'
);
...
...
app/assets/javascripts/contextual_sidebar.js
View file @
16992141
...
...
@@ -20,8 +20,11 @@ export default class ContextualSidebar {
}
bindEvents
()
{
document
.
addEventListener
(
'
click
'
,
(
e
)
=>
{
if
(
!
e
.
target
.
closest
(
'
.nav-sidebar
'
)
&&
(
bp
.
getBreakpointSize
()
===
'
sm
'
||
bp
.
getBreakpointSize
()
===
'
md
'
))
{
document
.
addEventListener
(
'
click
'
,
e
=>
{
if
(
!
e
.
target
.
closest
(
'
.nav-sidebar
'
)
&&
(
bp
.
getBreakpointSize
()
===
'
sm
'
||
bp
.
getBreakpointSize
()
===
'
md
'
)
)
{
this
.
toggleCollapsedSidebar
(
true
);
}
});
...
...
app/assets/javascripts/create_item_dropdown.js
View file @
16992141
...
...
@@ -36,7 +36,7 @@ export default class CreateItemDropdown {
},
selectable
:
true
,
toggleLabel
(
selected
)
{
return
(
selected
&&
'
id
'
in
selected
)
?
_
.
escape
(
selected
.
title
)
:
this
.
defaultToggleLabel
;
return
selected
&&
'
id
'
in
selected
?
_
.
escape
(
selected
.
title
)
:
this
.
defaultToggleLabel
;
},
fieldName
:
this
.
fieldName
,
text
(
item
)
{
...
...
@@ -46,7 +46,7 @@ export default class CreateItemDropdown {
return
_
.
escape
(
item
.
id
);
},
onFilter
:
this
.
toggleCreateNewButton
.
bind
(
this
),
clicked
:
(
options
)
=>
{
clicked
:
options
=>
{
options
.
e
.
preventDefault
();
this
.
onSelect
();
},
...
...
@@ -77,9 +77,8 @@ export default class CreateItemDropdown {
getData
(
term
,
callback
)
{
this
.
getDataOption
(
term
,
(
data
=
[])
=>
{
// Ensure the selected item isn't already in the data to avoid duplicates
const
alreadyHasSelectedItem
=
this
.
selectedItem
&&
data
.
some
(
item
=>
item
.
id
===
this
.
selectedItem
.
id
,
);
const
alreadyHasSelectedItem
=
this
.
selectedItem
&&
data
.
some
(
item
=>
item
.
id
===
this
.
selectedItem
.
id
);
let
uniqueData
=
data
;
if
(
!
alreadyHasSelectedItem
)
{
...
...
@@ -106,9 +105,7 @@ export default class CreateItemDropdown {
if
(
newValue
)
{
this
.
selectedItem
=
this
.
createNewItemFromValue
(
newValue
);
this
.
$dropdownContainer
.
find
(
'
.js-dropdown-create-new-item code
'
)
.
text
(
newValue
);
this
.
$dropdownContainer
.
find
(
'
.js-dropdown-create-new-item code
'
).
text
(
newValue
);
}
this
.
toggleFooter
(
!
newValue
);
...
...
app/assets/javascripts/create_label.js
View file @
16992141
...
...
@@ -37,7 +37,7 @@ export default class CreateLabelDropdown {
addBinding
()
{
const
self
=
this
;
this
.
$colorSuggestions
.
on
(
'
click
'
,
function
(
e
)
{
this
.
$colorSuggestions
.
on
(
'
click
'
,
function
(
e
)
{
const
$this
=
$
(
this
);
self
.
addColorValue
(
e
,
$this
);
});
...
...
@@ -47,7 +47,7 @@ export default class CreateLabelDropdown {
this
.
$dropdownBack
.
on
(
'
click
'
,
this
.
resetForm
.
bind
(
this
));
this
.
$cancelButton
.
on
(
'
click
'
,
function
(
e
)
{
this
.
$cancelButton
.
on
(
'
click
'
,
function
(
e
)
{
e
.
preventDefault
();
e
.
stopPropagation
();
...
...
@@ -79,13 +79,9 @@ export default class CreateLabelDropdown {
}
resetForm
()
{
this
.
$newLabelField
.
val
(
''
)
.
trigger
(
'
change
'
);
this
.
$newLabelField
.
val
(
''
).
trigger
(
'
change
'
);
this
.
$newColorField
.
val
(
''
)
.
trigger
(
'
change
'
);
this
.
$newColorField
.
val
(
''
).
trigger
(
'
change
'
);
this
.
$colorPreview
.
css
(
'
background-color
'
,
''
)
...
...
@@ -97,10 +93,14 @@ export default class CreateLabelDropdown {
e
.
preventDefault
();
e
.
stopPropagation
();
Api
.
newLabel
(
this
.
namespacePath
,
this
.
projectPath
,
{
Api
.
newLabel
(
this
.
namespacePath
,
this
.
projectPath
,
{
title
:
this
.
$newLabelField
.
val
(),
color
:
this
.
$newColorField
.
val
(),
},
(
label
)
=>
{
},
label
=>
{
this
.
$newLabelCreateButton
.
enable
();
if
(
label
.
message
)
{
...
...
@@ -109,19 +109,18 @@ export default class CreateLabelDropdown {
if
(
typeof
label
.
message
===
'
string
'
)
{
errors
=
label
.
message
;
}
else
{
errors
=
Object
.
keys
(
label
.
message
).
map
(
key
=>
`
${
humanize
(
key
)}
${
label
.
message
[
key
].
join
(
'
,
'
)}
`
,
)
.
join
(
'
<br/>
'
);
errors
=
Object
.
keys
(
label
.
message
)
.
map
(
key
=>
`
${
humanize
(
key
)}
${
label
.
message
[
key
].
join
(
'
,
'
)}
`
)
.
join
(
'
<br/>
'
);
}
this
.
$newLabelError
.
html
(
errors
)
.
show
();
this
.
$newLabelError
.
html
(
errors
).
show
();
}
else
{
this
.
$dropdownBack
.
trigger
(
'
click
'
);
$
(
document
).
trigger
(
'
created.label
'
,
label
);
}
});
},
);
}
}
app/assets/javascripts/deploy_keys/components/app.vue
View file @
16992141
...
...
@@ -95,8 +95,10 @@ export default {
.
catch
(()
=>
new
Flash
(
s__
(
'
DeployKeys|Error enabling deploy key
'
)));
},
disableKey
(
deployKey
,
callback
)
{
if
(
// eslint-disable-next-line no-alert
if
(
window
.
confirm
(
s__
(
'
DeployKeys|You are going to remove this deploy key. Are you sure?
'
)))
{
window
.
confirm
(
s__
(
'
DeployKeys|You are going to remove this deploy key. Are you sure?
'
))
)
{
this
.
service
.
disableKey
(
deployKey
.
id
)
.
then
(
this
.
fetchKeys
)
...
...
app/assets/javascripts/deploy_keys/service/index.js
View file @
16992141
...
...
@@ -8,17 +8,14 @@ export default class DeployKeysService {
}
getKeys
()
{
return
this
.
axios
.
get
()
.
then
(
response
=>
response
.
data
);
return
this
.
axios
.
get
().
then
(
response
=>
response
.
data
);
}
enableKey
(
id
)
{
return
this
.
axios
.
put
(
`
${
id
}
/enable`
)
.
then
(
response
=>
response
.
data
);
return
this
.
axios
.
put
(
`
${
id
}
/enable`
).
then
(
response
=>
response
.
data
);
}
disableKey
(
id
)
{
return
this
.
axios
.
put
(
`
${
id
}
/disable`
)
.
then
(
response
=>
response
.
data
);
return
this
.
axios
.
put
(
`
${
id
}
/disable`
).
then
(
response
=>
response
.
data
);
}
}
app/assets/javascripts/diff.js
View file @
16992141
...
...
@@ -21,9 +21,12 @@ export default class Diff {
});
const
tab
=
document
.
getElementById
(
'
diffs
'
);
if
(
!
tab
||
(
tab
&&
tab
.
dataset
&&
tab
.
dataset
.
isLocked
!==
''
))
FilesCommentButton
.
init
(
$diffFile
);
if
(
!
tab
||
(
tab
&&
tab
.
dataset
&&
tab
.
dataset
.
isLocked
!==
''
))
FilesCommentButton
.
init
(
$diffFile
);
const
firstFile
=
$
(
'
.files
'
).
first
().
get
(
0
);
const
firstFile
=
$
(
'
.files
'
)
.
first
()
.
get
(
0
);
const
canCreateNote
=
firstFile
&&
firstFile
.
hasAttribute
(
'
data-can-create-note
'
);
$diffFile
.
each
((
index
,
file
)
=>
imageDiffHelper
.
initImageDiff
(
file
,
canCreateNote
));
...
...
@@ -73,7 +76,8 @@ export default class Diff {
const
view
=
file
.
data
(
'
view
'
);
const
params
=
{
since
,
to
,
bottom
,
offset
,
unfold
,
view
};
axios
.
get
(
link
,
{
params
})
axios
.
get
(
link
,
{
params
})
.
then
(({
data
})
=>
$target
.
parent
().
replaceWith
(
data
))
.
catch
(()
=>
flash
(
__
(
'
An error occurred while loading diff
'
)));
}
...
...
app/assets/javascripts/dropzone_input.js
View file @
16992141
...
...
@@ -136,7 +136,7 @@ export default function dropzoneInput(form) {
// removeAllFiles(true) stops uploading files (if any)
// and remove them from dropzone files queue.
$cancelButton
.
on
(
'
click
'
,
(
e
)
=>
{
$cancelButton
.
on
(
'
click
'
,
e
=>
{
e
.
preventDefault
();
e
.
stopPropagation
();
Dropzone
.
forElement
(
$formDropzone
.
get
(
0
)).
removeAllFiles
(
true
);
...
...
@@ -146,8 +146,10 @@ export default function dropzoneInput(form) {
// clear dropzone files queue, change status of failed files to undefined,
// and add that files to the dropzone files queue again.
// addFile() adds file to dropzone files queue and upload it.
$retryLink
.
on
(
'
click
'
,
(
e
)
=>
{
const
dropzoneInstance
=
Dropzone
.
forElement
(
e
.
target
.
closest
(
'
.js-main-target-form
'
).
querySelector
(
'
.div-dropzone
'
));
$retryLink
.
on
(
'
click
'
,
e
=>
{
const
dropzoneInstance
=
Dropzone
.
forElement
(
e
.
target
.
closest
(
'
.js-main-target-form
'
).
querySelector
(
'
.div-dropzone
'
),
);
const
failedFiles
=
dropzoneInstance
.
files
;
e
.
preventDefault
();
...
...
@@ -156,7 +158,7 @@ export default function dropzoneInput(form) {
// uploading of files that are being uploaded at the moment.
dropzoneInstance
.
removeAllFiles
(
true
);
failedFiles
.
map
(
(
failedFile
)
=>
{
failedFiles
.
map
(
failedFile
=>
{
const
file
=
failedFile
;
if
(
file
.
status
===
Dropzone
.
ERROR
)
{
...
...
@@ -168,7 +170,7 @@ export default function dropzoneInput(form) {
});
});
// eslint-disable-next-line consistent-return
handlePaste
=
(
event
)
=>
{
handlePaste
=
event
=>
{
const
pasteEvent
=
event
.
originalEvent
;
if
(
pasteEvent
.
clipboardData
&&
pasteEvent
.
clipboardData
.
items
)
{
const
image
=
isImage
(
pasteEvent
);
...
...
@@ -182,7 +184,7 @@ export default function dropzoneInput(form) {
}
};
isImage
=
(
data
)
=>
{
isImage
=
data
=>
{
let
i
=
0
;
while
(
i
<
data
.
clipboardData
.
items
.
length
)
{
const
item
=
data
.
clipboardData
.
items
[
i
];
...
...
@@ -203,8 +205,12 @@ export default function dropzoneInput(form) {
const
caretStart
=
textarea
.
selectionStart
;
const
caretEnd
=
textarea
.
selectionEnd
;
const
textEnd
=
$
(
child
).
val
().
length
;
const
beforeSelection
=
$
(
child
).
val
().
substring
(
0
,
caretStart
);
const
afterSelection
=
$
(
child
).
val
().
substring
(
caretEnd
,
textEnd
);
const
beforeSelection
=
$
(
child
)
.
val
()
.
substring
(
0
,
caretStart
);
const
afterSelection
=
$
(
child
)
.
val
()
.
substring
(
caretEnd
,
textEnd
);
$
(
child
).
val
(
beforeSelection
+
formattedText
+
afterSelection
);
textarea
.
setSelectionRange
(
caretStart
+
formattedText
.
length
,
caretEnd
+
formattedText
.
length
);
textarea
.
style
.
height
=
`
${
textarea
.
scrollHeight
}
px`
;
...
...
@@ -212,11 +218,11 @@ export default function dropzoneInput(form) {
return
formTextarea
.
trigger
(
'
input
'
);
};
addFileToForm
=
(
path
)
=>
{
addFileToForm
=
path
=>
{
$
(
form
).
append
(
`<input type="hidden" name="files[]" value="
${
_
.
escape
(
path
)}
">`
);
};
getFilename
=
(
e
)
=>
{
getFilename
=
e
=>
{
let
value
;
if
(
window
.
clipboardData
&&
window
.
clipboardData
.
getData
)
{
value
=
window
.
clipboardData
.
getData
(
'
Text
'
);
...
...
@@ -231,7 +237,7 @@ export default function dropzoneInput(form) {
const
closeSpinner
=
()
=>
$uploadingProgressContainer
.
addClass
(
'
hide
'
);
const
showError
=
(
message
)
=>
{
const
showError
=
message
=>
{
$uploadingErrorContainer
.
removeClass
(
'
hide
'
);
$uploadingErrorMessage
.
html
(
message
);
};
...
...
@@ -252,14 +258,15 @@ export default function dropzoneInput(form) {
showSpinner
();
closeAlertMessage
();
axios
.
post
(
uploadsPath
,
formData
)
axios
.
post
(
uploadsPath
,
formData
)
.
then
(({
data
})
=>
{
const
md
=
data
.
link
.
markdown
;
insertToTextArea
(
filename
,
md
);
closeSpinner
();
})
.
catch
(
(
e
)
=>
{
.
catch
(
e
=>
{
showError
(
e
.
response
.
data
.
message
);
closeSpinner
();
});
...
...
@@ -267,7 +274,8 @@ export default function dropzoneInput(form) {
updateAttachingMessage
=
(
files
,
messageContainer
)
=>
{
let
attachingMessage
;
const
filesCount
=
files
.
filter
(
file
=>
file
.
status
===
'
uploading
'
||
file
.
status
===
'
queued
'
).
length
;
const
filesCount
=
files
.
filter
(
file
=>
file
.
status
===
'
uploading
'
||
file
.
status
===
'
queued
'
)
.
length
;
// Dinamycally change uploading files text depending on files number in
// dropzone files queue.
...
...
@@ -282,7 +290,10 @@ export default function dropzoneInput(form) {
form
.
find
(
'
.markdown-selector
'
).
click
(
function
onMarkdownClick
(
e
)
{
e
.
preventDefault
();
$
(
this
).
closest
(
'
.gfm-form
'
).
find
(
'
.div-dropzone
'
).
click
();
$
(
this
)
.
closest
(
'
.gfm-form
'
)
.
find
(
'
.div-dropzone
'
)
.
click
();
formTextarea
.
focus
();
});
...
...
app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js
View file @
16992141
...
...
@@ -13,9 +13,11 @@ const rainbowCodePoint = 127752; // parseInt('1F308', 16)
function
isRainbowFlagEmoji
(
emojiUnicode
)
{
const
characters
=
Array
.
from
(
emojiUnicode
);
// Length 4 because flags are made of 2 characters which are surrogate pairs
return
emojiUnicode
.
length
===
4
&&
return
(
emojiUnicode
.
length
===
4
&&
characters
[
0
].
codePointAt
(
0
)
===
baseFlagCodePoint
&&
characters
[
1
].
codePointAt
(
0
)
===
rainbowCodePoint
;
characters
[
1
].
codePointAt
(
0
)
===
rainbowCodePoint
);
}
// Chrome <57 renders keycaps oddly
...
...
@@ -26,22 +28,28 @@ function isKeycapEmoji(emojiUnicode) {
}
// Check for a skin tone variation emoji which aren't always supported
const
tone1
=
127995
;
// parseInt('1F3FB', 16)
const
tone5
=
127999
;
// parseInt('1F3FF', 16)
const
tone1
=
127995
;
// parseInt('1F3FB', 16)
const
tone5
=
127999
;
// parseInt('1F3FF', 16)
function
isSkinToneComboEmoji
(
emojiUnicode
)
{
return
emojiUnicode
.
length
>
2
&&
Array
.
from
(
emojiUnicode
).
some
((
char
)
=>
{
return
(
emojiUnicode
.
length
>
2
&&
Array
.
from
(
emojiUnicode
).
some
(
char
=>
{
const
cp
=
char
.
codePointAt
(
0
);
return
cp
>=
tone1
&&
cp
<=
tone5
;
});
})
);
}
// macOS supports most skin tone emoji's but
// doesn't support the skin tone versions of horse racing
const
horseRacingCodePoint
=
127943
;
// parseInt('1F3C7', 16)
const
horseRacingCodePoint
=
127943
;
// parseInt('1F3C7', 16)
function
isHorceRacingSkinToneComboEmoji
(
emojiUnicode
)
{
const
firstCharacter
=
Array
.
from
(
emojiUnicode
)[
0
];
return
firstCharacter
&&
firstCharacter
.
codePointAt
(
0
)
===
horseRacingCodePoint
&&
isSkinToneComboEmoji
(
emojiUnicode
);
return
(
firstCharacter
&&
firstCharacter
.
codePointAt
(
0
)
===
horseRacingCodePoint
&&
isSkinToneComboEmoji
(
emojiUnicode
)
);
}
// Check for `family_*`, `kiss_*`, `couple_*`
...
...
@@ -52,7 +60,7 @@ const personEndCodePoint = 128105; // parseInt('1F469', 16)
function
isPersonZwjEmoji
(
emojiUnicode
)
{
let
hasPersonEmoji
=
false
;
let
hasZwj
=
false
;
Array
.
from
(
emojiUnicode
).
forEach
(
(
character
)
=>
{
Array
.
from
(
emojiUnicode
).
forEach
(
character
=>
{
const
cp
=
character
.
codePointAt
(
0
);
if
(
cp
===
zwj
)
{
hasZwj
=
true
;
...
...
@@ -80,10 +88,7 @@ function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) {
// in `isEmojiUnicodeSupported` logic
function
checkSkinToneModifierSupport
(
unicodeSupportMap
,
emojiUnicode
)
{
const
isSkinToneResult
=
isSkinToneComboEmoji
(
emojiUnicode
);
return
(
(
unicodeSupportMap
.
skinToneModifier
&&
isSkinToneResult
)
||
!
isSkinToneResult
);
return
(
unicodeSupportMap
.
skinToneModifier
&&
isSkinToneResult
)
||
!
isSkinToneResult
;
}
// Helper func so we don't have to run `isHorceRacingSkinToneComboEmoji` twice
...
...
@@ -91,8 +96,7 @@ function checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) {
function
checkHorseRacingSkinToneComboEmojiSupport
(
unicodeSupportMap
,
emojiUnicode
)
{
const
isHorseRacingSkinToneResult
=
isHorceRacingSkinToneComboEmoji
(
emojiUnicode
);
return
(
(
unicodeSupportMap
.
horseRacing
&&
isHorseRacingSkinToneResult
)
||
!
isHorseRacingSkinToneResult
(
unicodeSupportMap
.
horseRacing
&&
isHorseRacingSkinToneResult
)
||
!
isHorseRacingSkinToneResult
);
}
...
...
@@ -100,10 +104,7 @@ function checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnico
// in `isEmojiUnicodeSupported` logic
function
checkPersonEmojiSupport
(
unicodeSupportMap
,
emojiUnicode
)
{
const
isPersonZwjResult
=
isPersonZwjEmoji
(
emojiUnicode
);
return
(
(
unicodeSupportMap
.
personZwj
&&
isPersonZwjResult
)
||
!
isPersonZwjResult
);
return
(
unicodeSupportMap
.
personZwj
&&
isPersonZwjResult
)
||
!
isPersonZwjResult
;
}
// Takes in a support map and determines whether
...
...
@@ -111,16 +112,20 @@ function checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode) {
//
// Combines all the edge case tests into a one-stop shop method
function
isEmojiUnicodeSupported
(
unicodeSupportMap
=
{},
emojiUnicode
,
unicodeVersion
)
{
const
isOlderThanChrome57
=
unicodeSupportMap
.
meta
&&
unicodeSupportMap
.
meta
.
isChrome
&&
const
isOlderThanChrome57
=
unicodeSupportMap
.
meta
&&
unicodeSupportMap
.
meta
.
isChrome
&&
unicodeSupportMap
.
meta
.
chromeVersion
<
57
;
// For comments about each scenario, see the comments above each individual respective function
return
unicodeSupportMap
[
unicodeVersion
]
&&
return
(
unicodeSupportMap
[
unicodeVersion
]
&&
!
(
isOlderThanChrome57
&&
isKeycapEmoji
(
emojiUnicode
))
&&
checkFlagEmojiSupport
(
unicodeSupportMap
,
emojiUnicode
)
&&
checkSkinToneModifierSupport
(
unicodeSupportMap
,
emojiUnicode
)
&&
checkHorseRacingSkinToneComboEmojiSupport
(
unicodeSupportMap
,
emojiUnicode
)
&&
checkPersonEmojiSupport
(
unicodeSupportMap
,
emojiUnicode
);
checkPersonEmojiSupport
(
unicodeSupportMap
,
emojiUnicode
)
);
}
export
{
...
...
app/assets/javascripts/experimental_flags.js
View file @
16992141
...
...
@@ -2,7 +2,7 @@ import $ from 'jquery';
import
Cookies
from
'
js-cookie
'
;
export
default
()
=>
{
$
(
'
.js-experiment-feature-toggle
'
).
on
(
'
change
'
,
(
e
)
=>
{
$
(
'
.js-experiment-feature-toggle
'
).
on
(
'
change
'
,
e
=>
{
const
el
=
e
.
target
;
Cookies
.
set
(
el
.
name
,
el
.
value
,
{
...
...
app/assets/javascripts/files_comment_button.js
View file @
16992141
...
...
@@ -25,13 +25,15 @@ export default {
if
(
!
this
.
userCanCreateNote
)
{
// data-can-create-note is an empty string when true, otherwise undefined
this
.
userCanCreateNote
=
$diffFile
.
closest
(
DIFF_CONTAINER_SELECTOR
).
data
(
'
canCreateNote
'
)
===
''
;
this
.
userCanCreateNote
=
$diffFile
.
closest
(
DIFF_CONTAINER_SELECTOR
).
data
(
'
canCreateNote
'
)
===
''
;
}
this
.
isParallelView
=
Cookies
.
get
(
'
diff_view
'
)
===
'
parallel
'
;
if
(
this
.
userCanCreateNote
)
{
$diffFile
.
on
(
'
mouseover
'
,
LINE_COLUMN_CLASSES
,
e
=>
this
.
showButton
(
this
.
isParallelView
,
e
))
$diffFile
.
on
(
'
mouseover
'
,
LINE_COLUMN_CLASSES
,
e
=>
this
.
showButton
(
this
.
isParallelView
,
e
))
.
on
(
'
mouseleave
'
,
LINE_COLUMN_CLASSES
,
e
=>
this
.
hideButton
(
this
.
isParallelView
,
e
));
}
},
...
...
@@ -64,9 +66,11 @@ export default {
},
validateButtonParent
(
buttonParentElement
)
{
return
!
buttonParentElement
.
classList
.
contains
(
EMPTY_CELL_CLASS
)
&&
return
(
!
buttonParentElement
.
classList
.
contains
(
EMPTY_CELL_CLASS
)
&&
!
buttonParentElement
.
classList
.
contains
(
UNFOLDABLE_LINE_CLASS
)
&&
!
buttonParentElement
.
classList
.
contains
(
NO_COMMENT_CLASS
)
&&
!
buttonParentElement
.
parentNode
.
classList
.
contains
(
DIFF_EXPANDED_CLASS
);
!
buttonParentElement
.
parentNode
.
classList
.
contains
(
DIFF_EXPANDED_CLASS
)
);
},
};
app/assets/javascripts/filterable_list.js
View file @
16992141
...
...
@@ -65,12 +65,15 @@ export default class FilterableList {
this
.
isBusy
=
true
;
return
axios
.
get
(
this
.
getFilterEndpoint
(),
{
return
axios
.
get
(
this
.
getFilterEndpoint
(),
{
params
,
}).
then
((
res
)
=>
{
})
.
then
(
res
=>
{
this
.
onFilterSuccess
(
res
,
params
);
this
.
onFilterComplete
();
}).
catch
(()
=>
this
.
onFilterComplete
());
})
.
catch
(()
=>
this
.
onFilterComplete
());
}
onFilterSuccess
(
response
,
queryData
)
{
...
...
@@ -81,9 +84,13 @@ export default class FilterableList {
// Change url so if user reload a page - search results are saved
const
currentPath
=
this
.
getPagePath
(
queryData
);
return
window
.
history
.
replaceState
({
return
window
.
history
.
replaceState
(
{
page
:
currentPath
,
},
document
.
title
,
currentPath
);
},
document
.
title
,
currentPath
,
);
}
onFilterComplete
()
{
...
...
app/assets/javascripts/flash.js
View file @
16992141
...
...
@@ -8,14 +8,19 @@ const hideFlash = (flashEl, fadeTransition = true) => {
});
}
flashEl
.
addEventListener
(
'
transitionend
'
,
()
=>
{
flashEl
.
addEventListener
(
'
transitionend
'
,
()
=>
{
flashEl
.
remove
();
window
.
dispatchEvent
(
new
Event
(
'
resize
'
));
if
(
document
.
body
.
classList
.
contains
(
'
flash-shown
'
))
document
.
body
.
classList
.
remove
(
'
flash-shown
'
);
},
{
if
(
document
.
body
.
classList
.
contains
(
'
flash-shown
'
))
document
.
body
.
classList
.
remove
(
'
flash-shown
'
);
},
{
once
:
true
,
passive
:
true
,
});
},
);
if
(
!
fadeTransition
)
flashEl
.
dispatchEvent
(
new
Event
(
'
transitionend
'
));
};
...
...
@@ -84,7 +89,9 @@ const createFlash = function createFlash(
flashEl
.
innerHTML
+=
createAction
(
actionConfig
);
if
(
actionConfig
.
clickHandler
)
{
flashEl
.
querySelector
(
'
.flash-action
'
).
addEventListener
(
'
click
'
,
e
=>
actionConfig
.
clickHandler
(
e
));
flashEl
.
querySelector
(
'
.flash-action
'
)
.
addEventListener
(
'
click
'
,
e
=>
actionConfig
.
clickHandler
(
e
));
}
}
...
...
@@ -95,11 +102,5 @@ const createFlash = function createFlash(
return
flashContainer
;
};
export
{
createFlash
as
default
,
createFlashEl
,
createAction
,
hideFlash
,
removeFlashClickListener
,
};
export
{
createFlash
as
default
,
createFlashEl
,
createAction
,
hideFlash
,
removeFlashClickListener
};
window
.
Flash
=
createFlash
;
app/assets/javascripts/fly_out_nav.js
View file @
16992141
...
...
@@ -11,9 +11,13 @@ let sidebar;
export
const
mousePos
=
[];
export
const
setSidebar
=
(
el
)
=>
{
sidebar
=
el
;
};
export
const
setSidebar
=
el
=>
{
sidebar
=
el
;
};
export
const
getOpenMenu
=
()
=>
currentOpenMenu
;
export
const
setOpenMenu
=
(
menu
=
null
)
=>
{
currentOpenMenu
=
menu
;
};
export
const
setOpenMenu
=
(
menu
=
null
)
=>
{
currentOpenMenu
=
menu
;
};
export
const
slope
=
(
a
,
b
)
=>
(
b
.
y
-
a
.
y
)
/
(
b
.
x
-
a
.
x
);
...
...
@@ -21,9 +25,10 @@ let headerHeight = 50;
export
const
getHeaderHeight
=
()
=>
headerHeight
;
export
const
isSidebarCollapsed
=
()
=>
sidebar
&&
sidebar
.
classList
.
contains
(
'
sidebar-collapsed-desktop
'
);
export
const
isSidebarCollapsed
=
()
=>
sidebar
&&
sidebar
.
classList
.
contains
(
'
sidebar-collapsed-desktop
'
);
export
const
canShowActiveSubItems
=
(
el
)
=>
{
export
const
canShowActiveSubItems
=
el
=>
{
if
(
el
.
classList
.
contains
(
'
active
'
)
&&
!
isSidebarCollapsed
())
{
return
false
;
}
...
...
@@ -31,7 +36,10 @@ export const canShowActiveSubItems = (el) => {
return
true
;
};
export
const
canShowSubItems
=
()
=>
bp
.
getBreakpointSize
()
===
'
sm
'
||
bp
.
getBreakpointSize
()
===
'
md
'
||
bp
.
getBreakpointSize
()
===
'
lg
'
;
export
const
canShowSubItems
=
()
=>
bp
.
getBreakpointSize
()
===
'
sm
'
||
bp
.
getBreakpointSize
()
===
'
md
'
||
bp
.
getBreakpointSize
()
===
'
lg
'
;
export
const
getHideSubItemsInterval
=
()
=>
{
if
(
!
currentOpenMenu
||
!
mousePos
.
length
)
return
0
;
...
...
@@ -41,11 +49,12 @@ export const getHideSubItemsInterval = () => {
const
currentMousePosY
=
currentMousePos
.
y
;
const
[
menuTop
,
menuBottom
]
=
menuCornerLocs
;
if
(
currentMousePosY
<
menuTop
.
y
||
currentMousePosY
>
menuBottom
.
y
)
return
0
;
if
(
currentMousePosY
<
menuTop
.
y
||
currentMousePosY
>
menuBottom
.
y
)
return
0
;
if
(
slope
(
prevMousePos
,
menuBottom
)
<
slope
(
currentMousePos
,
menuBottom
)
&&
slope
(
prevMousePos
,
menuTop
)
>
slope
(
currentMousePos
,
menuTop
))
{
if
(
slope
(
prevMousePos
,
menuBottom
)
<
slope
(
currentMousePos
,
menuBottom
)
&&
slope
(
prevMousePos
,
menuTop
)
>
slope
(
currentMousePos
,
menuTop
)
)
{
return
HIDE_INTERVAL_TIMEOUT
;
}
...
...
@@ -56,11 +65,12 @@ export const calculateTop = (boundingRect, outerHeight) => {
const
windowHeight
=
window
.
innerHeight
;
const
bottomOverflow
=
windowHeight
-
(
boundingRect
.
top
+
outerHeight
);
return
bottomOverflow
<
0
?
(
boundingRect
.
top
-
outerHeight
)
+
boundingRect
.
height
:
boundingRect
.
top
;
return
bottomOverflow
<
0
?
boundingRect
.
top
-
outerHeight
+
boundingRect
.
height
:
boundingRect
.
top
;
};
export
const
hideMenu
=
(
el
)
=>
{
export
const
hideMenu
=
el
=>
{
if
(
!
el
)
return
;
const
parentEl
=
el
.
parentNode
;
...
...
@@ -101,7 +111,7 @@ export const moveSubItemsToPosition = (el, subItems) => {
}
};
export
const
showSubLevelItems
=
(
el
)
=>
{
export
const
showSubLevelItems
=
el
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
const
isIconOnly
=
subItems
&&
subItems
.
classList
.
contains
(
'
is-fly-out-only
'
);
...
...
@@ -128,16 +138,20 @@ export const mouseEnterTopItems = (el, timeout = getHideSubItemsInterval()) => {
},
timeout
);
};
export
const
mouseLeaveTopItem
=
(
el
)
=>
{
export
const
mouseLeaveTopItem
=
el
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
if
(
!
canShowSubItems
()
||
!
canShowActiveSubItems
(
el
)
||
(
subItems
&&
subItems
===
currentOpenMenu
))
return
;
if
(
!
canShowSubItems
()
||
!
canShowActiveSubItems
(
el
)
||
(
subItems
&&
subItems
===
currentOpenMenu
)
)
return
;
el
.
classList
.
remove
(
IS_OVER_CLASS
);
};
export
const
documentMouseMove
=
(
e
)
=>
{
export
const
documentMouseMove
=
e
=>
{
mousePos
.
push
({
x
:
e
.
clientX
,
y
:
e
.
clientY
,
...
...
@@ -146,7 +160,7 @@ export const documentMouseMove = (e) => {
if
(
mousePos
.
length
>
6
)
mousePos
.
shift
();
};
export
const
subItemsMouseLeave
=
(
relatedTarget
)
=>
{
export
const
subItemsMouseLeave
=
relatedTarget
=>
{
clearTimeout
(
timeoutId
);
if
(
relatedTarget
&&
!
relatedTarget
.
closest
(
`.
${
IS_OVER_CLASS
}
`
))
{
...
...
@@ -174,7 +188,7 @@ export default () => {
headerHeight
=
document
.
querySelector
(
'
.nav-sidebar
'
).
offsetTop
;
items
.
forEach
(
(
el
)
=>
{
items
.
forEach
(
el
=>
{
const
subItems
=
el
.
querySelector
(
'
.sidebar-sub-level-items
'
);
if
(
subItems
)
{
...
...
app/assets/javascripts/gl_field_error.js
View file @
16992141
...
...
@@ -116,7 +116,8 @@ export default class GlFieldError {
this
.
form
.
focusOnFirstInvalid
.
apply
(
this
.
form
);
// For UX, wait til after first invalid submission to check each keyup
this
.
inputElement
.
off
(
'
keyup.fieldValidator
'
)
this
.
inputElement
.
off
(
'
keyup.fieldValidator
'
)
.
on
(
'
keyup.fieldValidator
'
,
this
.
updateValidity
.
bind
(
this
));
}
...
...
app/assets/javascripts/gl_field_errors.js
View file @
16992141
...
...
@@ -16,9 +16,12 @@ export default class GlFieldErrors {
initValidators
()
{
// register selectors here as needed
const
validateSelectors
=
[
'
:text
'
,
'
:password
'
,
'
[type=email]
'
]
.
map
(
selector
=>
`input
${
selector
}
`
).
join
(
'
,
'
);
.
map
(
selector
=>
`input
${
selector
}
`
)
.
join
(
'
,
'
);
this
.
state
.
inputs
=
this
.
form
.
find
(
validateSelectors
).
toArray
()
this
.
state
.
inputs
=
this
.
form
.
find
(
validateSelectors
)
.
toArray
()
.
filter
(
input
=>
!
input
.
classList
.
contains
(
customValidationFlag
))
.
map
(
input
=>
new
GlFieldError
({
input
,
formErrors
:
this
}));
...
...
@@ -42,7 +45,7 @@ export default class GlFieldErrors {
/* Public method for triggering validity updates manually */
updateFormValidityState
()
{
this
.
state
.
inputs
.
forEach
(
(
field
)
=>
{
this
.
state
.
inputs
.
forEach
(
field
=>
{
if
(
field
.
state
.
submitted
)
{
field
.
updateValidity
();
}
...
...
@@ -50,8 +53,9 @@ export default class GlFieldErrors {
}
focusOnFirstInvalid
()
{
const
firstInvalid
=
this
.
state
.
inputs
.
filter
(
input
=>
!
input
.
inputDomElement
.
validity
.
valid
)[
0
];
const
firstInvalid
=
this
.
state
.
inputs
.
filter
(
input
=>
!
input
.
inputDomElement
.
validity
.
valid
,
)[
0
];
firstInvalid
.
inputElement
.
focus
();
}
}
app/assets/javascripts/gl_form.js
View file @
16992141
...
...
@@ -39,7 +39,10 @@ export default class GLForm {
this
.
form
.
find
(
'
.div-dropzone
'
).
remove
();
this
.
form
.
addClass
(
'
gfm-form
'
);
// remove notify commit author checkbox for non-commit notes
gl
.
utils
.
disableButtonIfEmptyField
(
this
.
form
.
find
(
'
.js-note-text
'
),
this
.
form
.
find
(
'
.js-comment-button, .js-note-new-discussion
'
));
gl
.
utils
.
disableButtonIfEmptyField
(
this
.
form
.
find
(
'
.js-note-text
'
),
this
.
form
.
find
(
'
.js-comment-button, .js-note-new-discussion
'
),
);
this
.
autoComplete
=
new
GfmAutoComplete
(
gl
.
GfmAutoComplete
&&
gl
.
GfmAutoComplete
.
dataSources
);
this
.
autoComplete
.
setup
(
this
.
form
.
find
(
'
.js-gfm-input
'
),
this
.
enableGFM
);
dropzoneInput
(
this
.
form
);
...
...
@@ -55,11 +58,9 @@ export default class GLForm {
}
setupAutosize
()
{
this
.
textarea
.
off
(
'
autosize:resized
'
)
.
on
(
'
autosize:resized
'
,
this
.
setHeightData
.
bind
(
this
));
this
.
textarea
.
off
(
'
autosize:resized
'
).
on
(
'
autosize:resized
'
,
this
.
setHeightData
.
bind
(
this
));
this
.
textarea
.
off
(
'
mouseup.autosize
'
)
.
on
(
'
mouseup.autosize
'
,
this
.
destroyAutosize
.
bind
(
this
));
this
.
textarea
.
off
(
'
mouseup.autosize
'
).
on
(
'
mouseup.autosize
'
,
this
.
destroyAutosize
.
bind
(
this
));
setTimeout
(()
=>
{
autosize
(
this
.
textarea
);
...
...
@@ -91,10 +92,14 @@ export default class GLForm {
addEventListeners
()
{
this
.
textarea
.
on
(
'
focus
'
,
function
focusTextArea
()
{
$
(
this
).
closest
(
'
.md-area
'
).
addClass
(
'
is-focused
'
);
$
(
this
)
.
closest
(
'
.md-area
'
)
.
addClass
(
'
is-focused
'
);
});
this
.
textarea
.
on
(
'
blur
'
,
function
blurTextArea
()
{
$
(
this
).
closest
(
'
.md-area
'
).
removeClass
(
'
is-focused
'
);
$
(
this
)
.
closest
(
'
.md-area
'
)
.
removeClass
(
'
is-focused
'
);
});
}
}
app/assets/javascripts/group_avatar.js
View file @
16992141
...
...
@@ -7,8 +7,9 @@ export default function groupAvatar() {
});
$
(
'
.js-group-avatar-input
'
).
on
(
'
change
'
,
function
onChangeAvatarInput
()
{
const
form
=
$
(
this
).
closest
(
'
form
'
);
// eslint-disable-next-line no-useless-escape
const
filename
=
$
(
this
).
val
().
replace
(
/^.*
[\\\/]
/
,
''
);
const
filename
=
$
(
this
)
.
val
()
.
replace
(
/^.*
[\\\/]
/
,
''
);
// eslint-disable-line no-useless-escape
return
form
.
find
(
'
.js-avatar-filename
'
).
text
(
filename
);
});
}
app/assets/javascripts/group_label_subscription.js
View file @
16992141
...
...
@@ -23,7 +23,8 @@ export default class GroupLabelSubscription {
event
.
preventDefault
();
const
url
=
this
.
$unsubscribeButtons
.
attr
(
'
data-url
'
);
axios
.
post
(
url
)
axios
.
post
(
url
)
.
then
(()
=>
{
this
.
toggleSubscriptionButtons
();
this
.
$unsubscribeButtons
.
removeAttr
(
'
data-url
'
);
...
...
@@ -39,7 +40,8 @@ export default class GroupLabelSubscription {
this
.
$unsubscribeButtons
.
attr
(
'
data-url
'
,
url
);
axios
.
post
(
url
)
axios
.
post
(
url
)
.
then
(()
=>
GroupLabelSubscription
.
setNewTooltip
(
$btn
))
.
then
(()
=>
this
.
toggleSubscriptionButtons
())
.
catch
(()
=>
flash
(
__
(
'
There was an error when subscribing to this label.
'
)));
...
...
@@ -58,6 +60,8 @@ export default class GroupLabelSubscription {
const
newTitle
=
tooltipTitles
[
type
];
$
(
'
.js-unsubscribe-button
'
,
$button
.
closest
(
'
.label-actions-list
'
))
.
tooltip
(
'
hide
'
).
attr
(
'
title
'
,
newTitle
).
tooltip
(
'
_fixTitle
'
);
.
tooltip
(
'
hide
'
)
.
attr
(
'
title
'
,
newTitle
)
.
tooltip
(
'
_fixTitle
'
);
}
}
app/assets/javascripts/groups/components/item_stats.vue
View file @
16992141
<
script
>
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
timeAgoTooltip
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
import
{
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
timeAgoTooltip
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
import
{
ITEM_TYPE
,
VISIBILITY_TYPE_ICON
,
GROUP_VISIBILITY_TYPE
,
PROJECT_VISIBILITY_TYPE
,
}
from
'
../constants
'
;
import
itemStatsValue
from
'
./item_stats_value.vue
'
;
}
from
'
../constants
'
;
import
itemStatsValue
from
'
./item_stats_value.vue
'
;
export
default
{
export
default
{
components
:
{
icon
,
timeAgoTooltip
,
...
...
@@ -38,7 +38,7 @@
return
this
.
item
.
type
===
ITEM_TYPE
.
GROUP
;
},
},
};
};
</
script
>
<
template
>
...
...
app/assets/javascripts/groups/components/item_stats_value.vue
View file @
16992141
<
script
>
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
export
default
{
export
default
{
components
:
{
icon
,
},
...
...
@@ -46,7 +46,7 @@
return
this
.
value
!==
''
;
},
},
};
};
</
script
>
<
template
>
...
...
app/assets/javascripts/groups/new_group_child.js
View file @
16992141
...
...
@@ -37,20 +37,22 @@ export default class NewGroupChild {
getDroplabConfig
()
{
return
{
InputSetter
:
[{
InputSetter
:
[
{
input
:
this
.
newGroupChildButton
,
valueAttribute
:
'
data-value
'
,
inputAttribute
:
'
data-action
'
,
},
{
},
{
input
:
this
.
newGroupChildButton
,
valueAttribute
:
'
data-text
'
,
}],
},
],
};
}
bindEvents
()
{
this
.
newGroupChildButton
.
addEventListener
(
'
click
'
,
this
.
onClickNewGroupChildButton
.
bind
(
this
));
this
.
newGroupChildButton
.
addEventListener
(
'
click
'
,
this
.
onClickNewGroupChildButton
.
bind
(
this
));
}
onClickNewGroupChildButton
(
e
)
{
...
...
app/assets/javascripts/groups/store/groups_store.js
View file @
16992141
...
...
@@ -17,7 +17,8 @@ export default class GroupsStore {
}
setSearchedGroups
(
rawGroups
)
{
const
formatGroups
=
groups
=>
groups
.
map
((
group
)
=>
{
const
formatGroups
=
groups
=>
groups
.
map
(
group
=>
{
const
formattedGroup
=
this
.
formatGroupItem
(
group
);
if
(
formattedGroup
.
children
&&
formattedGroup
.
children
.
length
)
{
formattedGroup
.
children
=
formatGroups
(
formattedGroup
.
children
);
...
...
@@ -62,10 +63,10 @@ export default class GroupsStore {
formatGroupItem
(
rawGroupItem
)
{
const
groupChildren
=
rawGroupItem
.
children
||
[];
const
groupIsOpen
=
(
groupChildren
.
length
>
0
)
||
false
;
const
childrenCount
=
this
.
hideProjects
?
rawGroupItem
.
subgroup_count
:
rawGroupItem
.
children_count
;
const
groupIsOpen
=
groupChildren
.
length
>
0
||
false
;
const
childrenCount
=
this
.
hideProjects
?
rawGroupItem
.
subgroup_count
:
rawGroupItem
.
children_count
;
return
{
id
:
rawGroupItem
.
id
,
...
...
app/assets/javascripts/groups/transfer_dropdown.js
View file @
16992141
...
...
@@ -22,7 +22,7 @@ export default class TransferDropdown {
search
:
{
fields
:
[
'
text
'
]
},
data
:
extraOptions
.
concat
(
this
.
data
),
text
:
item
=>
item
.
text
,
clicked
:
(
options
)
=>
{
clicked
:
options
=>
{
const
{
e
}
=
options
;
e
.
preventDefault
();
this
.
assignSelected
(
options
.
selectedObj
);
...
...
app/assets/javascripts/groups_select.js
View file @
16992141
...
...
@@ -23,7 +23,7 @@ export default function groupsSelect() {
axios
[
params
.
type
.
toLowerCase
()](
params
.
url
,
{
params
:
params
.
data
,
})
.
then
(
(
res
)
=>
{
.
then
(
res
=>
{
const
results
=
res
.
data
||
[];
const
headers
=
normalizeHeaders
(
res
.
headers
);
const
currentPage
=
parseInt
(
headers
[
'
X-PAGE
'
],
10
)
||
0
;
...
...
@@ -36,7 +36,8 @@ export default function groupsSelect() {
more
,
},
});
}).
catch
(
params
.
error
);
})
.
catch
(
params
.
error
);
},
data
(
search
,
page
)
{
return
{
...
...
@@ -68,7 +69,9 @@ export default function groupsSelect() {
}
},
formatResult
(
object
)
{
return
`<div class='group-result'> <div class='group-name'>
${
object
.
full_name
}
</div> <div class='group-path'>
${
object
.
full_path
}
</div> </div>`
;
return
`<div class='group-result'> <div class='group-name'>
${
object
.
full_name
}
</div> <div class='group-path'>
${
object
.
full_path
}
</div> </div>`
;
},
formatSelection
(
object
)
{
return
object
.
full_name
;
...
...
app/assets/javascripts/helpers/avatar_helper.js
View file @
16992141
...
...
@@ -19,7 +19,9 @@ export function renderIdenticon(entity, options = {}) {
const
bgClass
=
getIdenticonBackgroundClass
(
entity
.
id
);
const
title
=
getIdenticonTitle
(
entity
.
name
);
return
`<div class="avatar identicon
${
_
.
escape
(
sizeClass
)}
${
_
.
escape
(
bgClass
)}
">
${
_
.
escape
(
title
)}
</div>`
;
return
`<div class="avatar identicon
${
_
.
escape
(
sizeClass
)}
${
_
.
escape
(
bgClass
)}
">
${
_
.
escape
(
title
,
)}
</div>`
;
}
export
function
renderAvatar
(
entity
,
options
=
{})
{
...
...
app/assets/javascripts/image_diff/image_diff.js
View file @
16992141
...
...
@@ -60,8 +60,10 @@ export default class ImageDiff {
}
renderBadge
(
discussionEl
,
index
)
{
const
imageBadge
=
imageDiffHelper
.
generateBadgeFromDiscussionDOM
(
this
.
imageFrameEl
,
discussionEl
);
const
imageBadge
=
imageDiffHelper
.
generateBadgeFromDiscussionDOM
(
this
.
imageFrameEl
,
discussionEl
,
);
this
.
imageBadges
.
push
(
imageBadge
);
...
...
app/assets/javascripts/image_diff/init_discussion_tab.js
View file @
16992141
...
...
@@ -8,5 +8,6 @@ export default () => {
const
diffFileEls
=
document
.
querySelectorAll
(
'
.timeline-content .diff-file.js-image-file
'
);
[...
diffFileEls
].
forEach
(
diffFileEl
=>
imageDiffHelper
.
initImageDiff
(
diffFileEl
,
canCreateNote
,
renderCommentBadge
));
imageDiffHelper
.
initImageDiff
(
diffFileEl
,
canCreateNote
,
renderCommentBadge
),
);
};
app/assets/javascripts/image_diff/replaced_image_diff.js
View file @
16992141
...
...
@@ -26,7 +26,7 @@ export default class ReplacedImageDiff extends ImageDiff {
this
.
imageEls
=
{};
const
viewTypeNames
=
Object
.
getOwnPropertyNames
(
viewTypes
);
viewTypeNames
.
forEach
(
(
viewType
)
=>
{
viewTypeNames
.
forEach
(
viewType
=>
{
this
.
imageEls
[
viewType
]
=
this
.
imageFrameEls
[
viewType
].
querySelector
(
'
img
'
);
});
}
...
...
@@ -79,8 +79,7 @@ export default class ReplacedImageDiff extends ImageDiff {
// Re-render indicator in new view
if
(
indicator
.
removed
)
{
const
normalizedIndicator
=
imageDiffHelper
.
resizeCoordinatesToImageElement
(
this
.
imageEl
,
{
const
normalizedIndicator
=
imageDiffHelper
.
resizeCoordinatesToImageElement
(
this
.
imageEl
,
{
x
:
indicator
.
x
,
y
:
indicator
.
y
,
width
:
indicator
.
image
.
width
,
...
...
app/assets/javascripts/importer_status.js
View file @
16992141
...
...
@@ -60,7 +60,8 @@ class ImporterStatus {
attributes
=
Object
.
assign
(
repoData
,
attributes
);
}
return
axios
.
post
(
this
.
importUrl
,
attributes
)
return
axios
.
post
(
this
.
importUrl
,
attributes
)
.
then
(({
data
})
=>
{
const
job
=
$
(
`tr#repo_
${
id
}
`
);
job
.
attr
(
'
id
'
,
`project_
${
data
.
id
}
`
);
...
...
@@ -70,14 +71,19 @@ class ImporterStatus {
job
.
addClass
(
'
table-active
'
);
const
connectingVerb
=
this
.
ciCdOnly
?
__
(
'
connecting
'
)
:
__
(
'
importing
'
);
job
.
find
(
'
.import-actions
'
).
html
(
sprintf
(
_
.
escape
(
__
(
'
%{loadingIcon} Started
'
)),
{
loadingIcon
:
`<i class="fa fa-spinner fa-spin" aria-label="
${
_
.
escape
(
connectingVerb
)}
"></i>`
,
job
.
find
(
'
.import-actions
'
).
html
(
sprintf
(
_
.
escape
(
__
(
'
%{loadingIcon} Started
'
)),
{
loadingIcon
:
`<i class="fa fa-spinner fa-spin" aria-label="
${
_
.
escape
(
connectingVerb
,
)}
"></i>`
,
},
false
,
));
),
);
})
.
catch
((
error
)
=>
{
.
catch
(
error
=>
{
let
details
=
error
;
const
$statusField
=
$
(
`#repo_
${
this
.
id
}
.job-status`
);
...
...
@@ -92,9 +98,8 @@ class ImporterStatus {
}
autoUpdate
()
{
return
axios
.
get
(
this
.
jobsUrl
)
.
then
(({
data
=
[]
})
=>
{
data
.
forEach
((
job
)
=>
{
return
axios
.
get
(
this
.
jobsUrl
).
then
(({
data
=
[]
})
=>
{
data
.
forEach
(
job
=>
{
const
jobItem
=
$
(
`#project_
${
job
.
id
}
`
);
const
statusField
=
jobItem
.
find
(
'
.job-status
'
);
...
...
@@ -141,7 +146,4 @@ function initImporterStatus() {
}
}
export
{
initImporterStatus
as
default
,
ImporterStatus
,
};
export
{
initImporterStatus
as
default
,
ImporterStatus
};
app/assets/javascripts/init_changes_dropdown.js
View file @
16992141
import
$
from
'
jquery
'
;
import
{
stickyMonitor
}
from
'
./lib/utils/sticky
'
;
export
default
(
stickyTop
)
=>
{
export
default
stickyTop
=>
{
stickyMonitor
(
document
.
querySelector
(
'
.js-diff-files-changed
'
),
stickyTop
);
$
(
'
.js-diff-stats-dropdown
'
).
glDropdown
({
...
...
app/assets/javascripts/init_notes.js
View file @
16992141
...
...
@@ -2,13 +2,7 @@ import Notes from './notes';
export
default
()
=>
{
const
dataEl
=
document
.
querySelector
(
'
.js-notes-data
'
);
const
{
notesUrl
,
notesIds
,
now
,
diffView
,
enableGFM
,
}
=
JSON
.
parse
(
dataEl
.
innerHTML
);
const
{
notesUrl
,
notesIds
,
now
,
diffView
,
enableGFM
}
=
JSON
.
parse
(
dataEl
.
innerHTML
);
// Create a singleton so that we don't need to assign
// into the window object, we can just access the current isntance with Notes.instance
...
...
app/assets/javascripts/integrations/integration_settings_form.js
View file @
16992141
...
...
@@ -97,7 +97,8 @@ export default class IntegrationSettingsForm {
testSettings
(
formData
)
{
this
.
toggleSubmitBtnState
(
true
);
return
axios
.
put
(
this
.
testEndPoint
,
formData
)
return
axios
.
put
(
this
.
testEndPoint
,
formData
)
.
then
(({
data
})
=>
{
if
(
data
.
error
)
{
let
flashActions
;
...
...
@@ -105,7 +106,7 @@ export default class IntegrationSettingsForm {
if
(
data
.
test_failed
)
{
flashActions
=
{
title
:
'
Save anyway
'
,
clickHandler
:
(
e
)
=>
{
clickHandler
:
e
=>
{
e
.
preventDefault
();
this
.
$form
.
submit
();
},
...
...
app/assets/javascripts/issuable/auto_width_dropdown_select.js
View file @
16992141
...
...
@@ -27,7 +27,10 @@ class AutoWidthDropdownSelect {
// We have to look at the parent because
// `offsetParent` on a `display: none;` is `null`
const
offsetParentWidth
=
$
(
this
).
parent
().
offsetParent
().
width
();
const
offsetParentWidth
=
$
(
this
)
.
parent
()
.
offsetParent
()
.
width
();
// Reset any width to let it naturally flow
$dropdown
.
css
(
'
width
'
,
'
auto
'
);
if
(
$dropdown
.
outerWidth
(
false
)
>
offsetParentWidth
)
{
...
...
app/assets/javascripts/issuable_bulk_update_actions.js
View file @
16992141
...
...
@@ -32,7 +32,7 @@ export default {
onFormSubmitFailure
()
{
this
.
form
.
find
(
'
[type="submit"]
'
).
enable
();
return
new
Flash
(
"
Issue update failed
"
);
return
new
Flash
(
'
Issue update failed
'
);
},
getSelectedIssues
()
{
...
...
@@ -63,7 +63,7 @@ export default {
const
result
=
[];
const
labelsToKeep
=
this
.
$labelDropdown
.
data
(
'
indeterminate
'
);
this
.
getLabelsFromSelection
().
forEach
(
(
id
)
=>
{
this
.
getLabelsFromSelection
().
forEach
(
id
=>
{
if
(
labelsToKeep
.
indexOf
(
id
)
===
-
1
)
{
result
.
push
(
id
);
}
...
...
@@ -89,8 +89,8 @@ export default {
issuable_ids
:
this
.
form
.
find
(
'
input[name="update[issuable_ids]"]
'
).
val
(),
subscription_event
:
this
.
form
.
find
(
'
input[name="update[subscription_event]"]
'
).
val
(),
add_label_ids
:
[],
remove_label_ids
:
[]
}
remove_label_ids
:
[]
,
}
,
};
if
(
this
.
willUpdateLabels
)
{
formData
.
update
.
add_label_ids
=
this
.
$labelDropdown
.
data
(
'
marked
'
);
...
...
@@ -134,7 +134,7 @@ export default {
// Collect unique label IDs for all checked issues
this
.
getElement
(
'
.selected-issuable:checked
'
).
each
((
i
,
el
)
=>
{
issuableLabels
=
this
.
getElement
(
`#
${
this
.
prefixId
}${
el
.
dataset
.
id
}
`
).
data
(
'
labels
'
);
issuableLabels
.
forEach
(
(
labelId
)
=>
{
issuableLabels
.
forEach
(
labelId
=>
{
// Store unique IDs
if
(
uniqueIds
.
indexOf
(
labelId
)
===
-
1
)
{
uniqueIds
.
push
(
labelId
);
...
...
app/views/instance_statistics/conversational_development_index/_disabled.html.haml
View file @
16992141
...
...
@@ -11,4 +11,4 @@
%p
=
_
(
'Enable usage ping to get an overview of how you are using GitLab from a feature perspective.'
)
-
if
current_user
.
admin?
=
link_to
_
(
'Enable usage ping'
),
admin_application_settings_path
(
anchor:
'usage-statistic
s'
),
class:
'btn btn-primary'
=
link_to
_
(
'Enable usage ping'
),
metrics_and_profiling_admin_application_settings_path
(
anchor:
'js-usage-setting
s'
),
class:
'btn btn-primary'
bin/secpick
View file @
16992141
...
...
@@ -15,7 +15,7 @@ parser = OptionParser.new do |opts|
options
[
:version
]
=
version
&
.
tr
(
'.'
,
'-'
)
end
opts
.
on
(
'-b'
,
'--branch security-fix-branch'
,
'Original branch name'
)
do
|
branch
|
opts
.
on
(
'-b'
,
'--branch security-fix-branch'
,
'Original branch name
(optional, defaults to current)
'
)
do
|
branch
|
options
[
:branch
]
=
branch
end
...
...
@@ -32,15 +32,21 @@ end
parser
.
parse!
options
[
:branch
]
||=
`git rev-parse --abbrev-ref HEAD`
abort
(
"Missing options. Use
#{
$0
}
--help to see the list of options available"
.
red
)
if
options
.
values
.
include?
(
nil
)
abort
(
"Wrong version format
#{
options
[
:version
].
bold
}
"
.
red
)
unless
options
[
:version
]
=~
/\A\d*\-\d*\Z/
branch
=
"
#{
options
[
:branch
]
}
-
#{
options
[
:version
]
}
"
ee
=
File
.
exist?
(
'./CHANGELOG-EE.md'
)
original_branch
=
options
[
:branch
].
strip
branch
=
"
#{
original_branch
}
-
#{
options
[
:version
]
}
"
branch
.
prepend
(
"
#{
BRANCH_PREFIX
}
-"
)
unless
branch
.
start_with?
(
"
#{
BRANCH_PREFIX
}
-"
)
branch
=
branch
.
freeze
stable_branch
=
"
#{
BRANCH_PREFIX
}
-
#{
options
[
:version
]
}
"
.
freeze
stable_branch
=
"
#{
BRANCH_PREFIX
}
-
#{
options
[
:version
]
}
"
.
tap
do
|
name
|
name
<<
"-ee"
if
ee
end
.
freeze
command
=
"git fetch
#{
REMOTE
}
#{
stable_branch
}
&& git checkout
#{
stable_branch
}
&& git pull
#{
REMOTE
}
#{
stable_branch
}
&& git checkout -B
#{
branch
}
&& git cherry-pick
#{
options
[
:sha
]
}
&& git push
#{
REMOTE
}
#{
branch
}
"
command
=
"git fetch
#{
REMOTE
}
#{
stable_branch
}
&& git checkout
#{
stable_branch
}
&& git pull
#{
REMOTE
}
#{
stable_branch
}
&& git checkout -B
#{
branch
}
&& git cherry-pick
#{
options
[
:sha
]
}
&& git push
#{
REMOTE
}
#{
branch
}
&& git checkout
#{
original_branch
}
"
_stdin
,
stdout
,
stderr
=
Open3
.
popen3
(
command
)
...
...
changelogs/unreleased/53070-fix-enable-usage-ping-link.yml
0 → 100644
View file @
16992141
---
title
:
"
fix
link
to
enable
usage
ping
from
convdev
index"
merge_request
:
22545
author
:
Anand Capur
type
:
fixed
doc/install/installation.md
View file @
16992141
...
...
@@ -132,9 +132,9 @@ Remove the old Ruby 1.8 if present:
Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.
4
.tar.gz
echo '
ec82b0d53bd0adad9b19e6b45e44d54e9ec3f10c ruby-2.4.4.tar.gz' | shasum -c - && tar xzf ruby-2.4.4
.tar.gz
cd ruby-2.4.
4
curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.
5
.tar.gz
echo '
4d650f302f1ec00256450b112bb023644b6ab6dd ruby-2.4.5.tar.gz' | shasum -c - && tar xzf ruby-2.4.5
.tar.gz
cd ruby-2.4.
5
./configure --disable-install-rdoc
make
...
...
doc/update/11.3-to-11.4.md
View file @
16992141
...
...
@@ -39,9 +39,9 @@ Download Ruby and compile it:
```
bash
mkdir
/tmp/ruby
&&
cd
/tmp/ruby
curl
--remote-name
--progress
https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.
4
.tar.gz
echo
'
ec82b0d53bd0adad9b19e6b45e44d54e9ec3f10c ruby-2.4.4.tar.gz'
| shasum
-c
-
&&
tar
xzf ruby-2.4.4
.tar.gz
cd
ruby-2.4.
4
curl
--remote-name
--progress
https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.
5
.tar.gz
echo
'
4d650f302f1ec00256450b112bb023644b6ab6dd ruby-2.4.5.tar.gz'
| shasum
-c
-
&&
tar
xzf ruby-2.4.5
.tar.gz
cd
ruby-2.4.
5
./configure
--disable-install-rdoc
make
...
...
lib/tasks/haml-lint.rake
View file @
16992141
...
...
@@ -2,5 +2,16 @@ unless Rails.env.production?
require
'haml_lint/rake_task'
require
'haml_lint/inline_javascript'
# Workaround for warnings from parser/current
# Keep it even if it no longer emits any warnings,
# because we'll still see warnings in console/server anyway,
# and we don't need to break static-analysis for this.
task
:haml_lint
do
require
'parser'
def
Parser
.
warn
(
*
args
)
puts
(
*
args
)
# static-analysis ignores stdout if status is 0
end
end
HamlLint
::
RakeTask
.
new
end
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