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
0
Merge Requests
0
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
Léo-Paul Géneau
gitlab-ce
Commits
3271c5f0
Commit
3271c5f0
authored
Oct 10, 2018
by
Mike Greiling
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prettify vue_shared modules
parent
8b7c86ea
Changes
28
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
914 additions
and
925 deletions
+914
-925
app/assets/javascripts/vue_shared/components/bar_chart.vue
app/assets/javascripts/vue_shared/components/bar_chart.vue
+5
-5
app/assets/javascripts/vue_shared/components/deprecated_modal.vue
...ts/javascripts/vue_shared/components/deprecated_modal.vue
+75
-75
app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
...ascripts/vue_shared/components/file_icon/file_icon_map.js
+1
-3
app/assets/javascripts/vue_shared/components/gl_modal.vue
app/assets/javascripts/vue_shared/components/gl_modal.vue
+6
-2
app/assets/javascripts/vue_shared/components/icon.vue
app/assets/javascripts/vue_shared/components/icon.vue
+0
-1
app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
...javascripts/vue_shared/components/issue/issue_warning.vue
+25
-25
app/assets/javascripts/vue_shared/components/loading_button.vue
...sets/javascripts/vue_shared/components/loading_button.vue
+28
-28
app/assets/javascripts/vue_shared/components/markdown/field.vue
...sets/javascripts/vue_shared/components/markdown/field.vue
+118
-118
app/assets/javascripts/vue_shared/components/markdown/header.vue
...ets/javascripts/vue_shared/components/markdown/header.vue
+51
-50
app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
...ts/javascripts/vue_shared/components/markdown/toolbar.vue
+24
-24
app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
...scripts/vue_shared/components/markdown/toolbar_button.vue
+36
-36
app/assets/javascripts/vue_shared/components/memory_graph.vue
...assets/javascripts/vue_shared/components/memory_graph.vue
+2
-1
app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
...ascripts/vue_shared/components/notes/placeholder_note.vue
+33
-35
app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
...s/vue_shared/components/notes/placeholder_system_note.vue
+16
-16
app/assets/javascripts/vue_shared/components/panel_resizer.vue
...ssets/javascripts/vue_shared/components/panel_resizer.vue
+78
-78
app/assets/javascripts/vue_shared/components/pikaday.vue
app/assets/javascripts/vue_shared/components/pikaday.vue
+53
-53
app/assets/javascripts/vue_shared/components/project_avatar/image.vue
...avascripts/vue_shared/components/project_avatar/image.vue
+61
-62
app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
...ets/javascripts/vue_shared/components/recaptcha_modal.vue
+47
-47
app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
...javascripts/vue_shared/components/sidebar/date_picker.vue
+91
-91
app/assets/javascripts/vue_shared/components/table_pagination.vue
...ts/javascripts/vue_shared/components/table_pagination.vue
+103
-103
app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
...ts/javascripts/vue_shared/components/time_ago_tooltip.vue
+1
-3
app/assets/javascripts/vue_shared/components/toggle_button.vue
...ssets/javascripts/vue_shared/components/toggle_button.vue
+47
-47
app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
...ts/vue_shared/components/user_avatar/user_avatar_link.vue
+0
-1
app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
...pts/vue_shared/components/user_avatar/user_avatar_svg.vue
+0
-2
app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
.../javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
+9
-10
app/assets/javascripts/vue_shared/models/label.js
app/assets/javascripts/vue_shared/models/label.js
+1
-1
app/assets/javascripts/vue_shared/translate.js
app/assets/javascripts/vue_shared/translate.js
+2
-7
app/assets/javascripts/vue_shared/vue_resource_interceptor.js
...assets/javascripts/vue_shared/vue_resource_interceptor.js
+1
-1
No files found.
app/assets/javascripts/vue_shared/components/bar_chart.vue
View file @
3271c5f0
...
...
@@ -118,7 +118,9 @@ export default {
this
.
rectYAxisLabelDims
.
height
!=
null
?
this
.
rectYAxisLabelDims
.
height
/
2
:
0
;
const
yCoord
=
this
.
vbHeight
/
2
+
rectWidth
-
5
;
return
`translate(
${
this
.
minX
+
this
.
yAxisTextTransformPadding
}
,
${
yCoord
}
) rotate(-
${
this
.
yAxisTextRotation
}
)`
;
return
`translate(
${
this
.
minX
+
this
.
yAxisTextTransformPadding
}
,
${
yCoord
}
) rotate(-
${
this
.
yAxisTextRotation
}
)`
;
},
},
mounted
()
{
...
...
@@ -207,8 +209,7 @@ export default {
renderedYAxis
.
selectAll
(
'
.tick
'
).
each
(
function
createTickLines
(
d
,
i
)
{
if
(
i
>
0
)
{
d3
.
select
(
this
)
d3
.
select
(
this
)
.
select
(
'
line
'
)
.
attr
(
'
x2
'
,
width
)
.
attr
(
'
class
'
,
'
axis-tick
'
);
...
...
@@ -217,8 +218,7 @@ export default {
// Add the panning capabilities
if
(
this
.
isPanAvailable
)
{
d3
.
select
(
this
.
$refs
.
baseSvg
)
d3
.
select
(
this
.
$refs
.
baseSvg
)
.
call
(
this
.
zoom
)
.
on
(
'
wheel.zoom
'
,
null
);
// This disables the pan of the graph with the scroll of the mouse wheel
}
...
...
app/assets/javascripts/vue_shared/components/deprecated_modal.vue
View file @
3271c5f0
<
script
>
/* eslint-disable vue/require-default-prop */
export
default
{
name
:
'
DeprecatedModal
'
,
// use GlModal instead
/* eslint-disable vue/require-default-prop */
export
default
{
name
:
'
DeprecatedModal
'
,
// use GlModal instead
props
:
{
id
:
{
type
:
String
,
required
:
false
,
},
title
:
{
type
:
String
,
required
:
false
,
},
text
:
{
type
:
String
,
required
:
false
,
},
hideFooter
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
kind
:
{
type
:
String
,
required
:
false
,
default
:
'
primary
'
,
},
modalDialogClass
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
closeKind
:
{
type
:
String
,
required
:
false
,
default
:
'
default
'
,
},
closeButtonLabel
:
{
type
:
String
,
required
:
false
,
default
:
'
Cancel
'
,
},
primaryButtonLabel
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
secondaryButtonLabel
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
submitDisabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
props
:
{
id
:
{
type
:
String
,
required
:
false
,
},
title
:
{
type
:
String
,
required
:
false
,
},
text
:
{
type
:
String
,
required
:
false
,
},
hideFooter
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
kind
:
{
type
:
String
,
required
:
false
,
default
:
'
primary
'
,
},
modalDialogClass
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
closeKind
:
{
type
:
String
,
required
:
false
,
default
:
'
default
'
,
},
closeButtonLabel
:
{
type
:
String
,
required
:
false
,
default
:
'
Cancel
'
,
},
primaryButtonLabel
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
secondaryButtonLabel
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
submitDisabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
btnKindClass
()
{
return
{
[
`btn-
${
this
.
kind
}
`
]:
true
,
};
},
btnCancelKindClass
()
{
return
{
[
`btn-
${
this
.
closeKind
}
`
]:
true
,
};
},
computed
:
{
btnKindClass
()
{
return
{
[
`btn-
${
this
.
kind
}
`
]:
true
,
};
},
btnCancelKindClass
()
{
return
{
[
`btn-
${
this
.
closeKind
}
`
]:
true
,
};
},
},
methods
:
{
emitCancel
(
event
)
{
this
.
$emit
(
'
cancel
'
,
event
);
},
emitSubmit
(
event
)
{
this
.
$emit
(
'
submit
'
,
event
);
},
methods
:
{
emitCancel
(
event
)
{
this
.
$emit
(
'
cancel
'
,
event
);
},
emitSubmit
(
event
)
{
this
.
$emit
(
'
submit
'
,
event
);
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
View file @
3271c5f0
...
...
@@ -583,7 +583,5 @@ const fileNameIcons = {
};
export
default
function
getIconForFile
(
name
)
{
return
fileNameIcons
[
name
]
||
fileExtensionIcons
[
name
?
name
.
split
(
'
.
'
).
pop
()
:
''
]
||
''
;
return
fileNameIcons
[
name
]
||
fileExtensionIcons
[
name
?
name
.
split
(
'
.
'
).
pop
()
:
''
]
||
''
;
}
app/assets/javascripts/vue_shared/components/gl_modal.vue
View file @
3271c5f0
...
...
@@ -41,10 +41,14 @@ export default {
},
},
mounted
()
{
$
(
this
.
$el
).
on
(
'
shown.bs.modal
'
,
this
.
opened
).
on
(
'
hidden.bs.modal
'
,
this
.
closed
);
$
(
this
.
$el
)
.
on
(
'
shown.bs.modal
'
,
this
.
opened
)
.
on
(
'
hidden.bs.modal
'
,
this
.
closed
);
},
beforeDestroy
()
{
$
(
this
.
$el
).
off
(
'
shown.bs.modal
'
,
this
.
opened
).
off
(
'
hidden.bs.modal
'
,
this
.
closed
);
$
(
this
.
$el
)
.
off
(
'
shown.bs.modal
'
,
this
.
opened
)
.
off
(
'
hidden.bs.modal
'
,
this
.
closed
);
},
methods
:
{
emitCancel
(
event
)
{
...
...
app/assets/javascripts/vue_shared/components/icon.vue
View file @
3271c5f0
<
script
>
// only allow classes in images.scss e.g. s12
const
validSizes
=
[
8
,
10
,
12
,
16
,
18
,
24
,
32
,
48
,
72
];
let
iconValidator
=
()
=>
true
;
...
...
app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
View file @
3271c5f0
<
script
>
import
icon
from
'
../../../vue_shared/components/icon.vue
'
;
import
icon
from
'
../../../vue_shared/components/icon.vue
'
;
export
default
{
components
:
{
icon
,
export
default
{
components
:
{
icon
,
},
props
:
{
isLocked
:
{
type
:
Boolean
,
default
:
false
,
required
:
false
,
},
props
:
{
isLocked
:
{
type
:
Boolean
,
default
:
false
,
required
:
false
,
},
isConfidential
:
{
type
:
Boolean
,
default
:
false
,
required
:
false
,
},
isConfidential
:
{
type
:
Boolean
,
default
:
false
,
required
:
false
,
},
computed
:
{
warningIcon
()
{
if
(
this
.
isConfidential
)
return
'
eye-slash
'
;
if
(
this
.
isLocked
)
return
'
lock
'
;
},
computed
:
{
warningIcon
()
{
if
(
this
.
isConfidential
)
return
'
eye-slash
'
;
if
(
this
.
isLocked
)
return
'
lock
'
;
return
''
;
},
isLockedAndConfidential
()
{
return
this
.
isConfidential
&&
this
.
isLocked
;
},
return
''
;
},
};
isLockedAndConfidential
()
{
return
this
.
isConfidential
&&
this
.
isLocked
;
},
},
};
</
script
>
<
template
>
<div
class=
"issuable-note-warning"
>
...
...
app/assets/javascripts/vue_shared/components/loading_button.vue
View file @
3271c5f0
<
script
>
/* eslint-disable vue/require-default-prop */
/* This is a re-usable vue component for rendering a button
/* eslint-disable vue/require-default-prop */
/* This is a re-usable vue component for rendering a button
that will probably be sending off ajax requests and need
to show the loading status by setting the `loading` option.
This can also be used for initial page load when you don't
...
...
@@ -17,34 +17,34 @@
*/
export
default
{
props
:
{
loading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
disabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
label
:
{
type
:
String
,
required
:
false
,
},
containerClass
:
{
type
:
[
String
,
Array
,
Object
],
required
:
false
,
default
:
'
btn btn-align-content
'
,
},
export
default
{
props
:
{
loading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
methods
:
{
onClick
(
e
)
{
this
.
$emit
(
'
click
'
,
e
);
}
,
disabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
};
label
:
{
type
:
String
,
required
:
false
,
},
containerClass
:
{
type
:
[
String
,
Array
,
Object
],
required
:
false
,
default
:
'
btn btn-align-content
'
,
},
},
methods
:
{
onClick
(
e
)
{
this
.
$emit
(
'
click
'
,
e
);
},
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/markdown/field.vue
View file @
3271c5f0
<
script
>
import
$
from
'
jquery
'
;
import
{
s__
}
from
'
~/locale
'
;
import
Flash
from
'
../../../flash
'
;
import
GLForm
from
'
../../../gl_form
'
;
import
markdownHeader
from
'
./header.vue
'
;
import
markdownToolbar
from
'
./toolbar.vue
'
;
import
icon
from
'
../icon.vue
'
;
import
$
from
'
jquery
'
;
import
{
s__
}
from
'
~/locale
'
;
import
Flash
from
'
../../../flash
'
;
import
GLForm
from
'
../../../gl_form
'
;
import
markdownHeader
from
'
./header.vue
'
;
import
markdownToolbar
from
'
./toolbar.vue
'
;
import
icon
from
'
../icon.vue
'
;
export
default
{
components
:
{
markdownHeader
,
markdownToolbar
,
icon
,
export
default
{
components
:
{
markdownHeader
,
markdownToolbar
,
icon
,
},
props
:
{
markdownPreviewPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
props
:
{
markdownPreviewPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
markdownDocsPath
:
{
type
:
String
,
required
:
true
,
},
markdownVersion
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
addSpacingClasses
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
quickActionsDocsPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
canAttachFile
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
enableAutocomplete
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
markdownDocsPath
:
{
type
:
String
,
required
:
true
,
},
data
()
{
return
{
markdownPreview
:
''
,
referencedCommands
:
''
,
referencedUsers
:
''
,
markdownPreviewLoading
:
false
,
previewMarkdown
:
false
,
};
markdownVersion
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
computed
:
{
shouldShowReferencedUsers
()
{
const
referencedUsersThreshold
=
10
;
return
this
.
referencedUsers
.
length
>=
referencedUsersThreshold
;
},
addSpacingClasses
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
mounted
()
{
/*
GLForm class handles all the toolbar buttons
*/
return
new
GLForm
(
$
(
this
.
$refs
[
'
gl-form
'
]),
{
emojis
:
this
.
enableAutocomplete
,
members
:
this
.
enableAutocomplete
,
issues
:
this
.
enableAutocomplete
,
mergeRequests
:
this
.
enableAutocomplete
,
epics
:
this
.
enableAutocomplete
,
milestones
:
this
.
enableAutocomplete
,
labels
:
this
.
enableAutocomplete
,
snippets
:
this
.
enableAutocomplete
,
});
quickActionsDocsPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
beforeDestroy
()
{
const
glForm
=
$
(
this
.
$refs
[
'
gl-form
'
]).
data
(
'
glForm
'
);
if
(
glForm
)
{
glForm
.
destroy
();
}
canAttachFile
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
enableAutocomplete
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
methods
:
{
showPreviewTab
()
{
if
(
this
.
previewMarkdown
)
return
;
},
data
()
{
return
{
markdownPreview
:
''
,
referencedCommands
:
''
,
referencedUsers
:
''
,
markdownPreviewLoading
:
false
,
previewMarkdown
:
false
,
};
},
computed
:
{
shouldShowReferencedUsers
()
{
const
referencedUsersThreshold
=
10
;
return
this
.
referencedUsers
.
length
>=
referencedUsersThreshold
;
},
},
mounted
()
{
/*
GLForm class handles all the toolbar buttons
*/
return
new
GLForm
(
$
(
this
.
$refs
[
'
gl-form
'
]),
{
emojis
:
this
.
enableAutocomplete
,
members
:
this
.
enableAutocomplete
,
issues
:
this
.
enableAutocomplete
,
mergeRequests
:
this
.
enableAutocomplete
,
epics
:
this
.
enableAutocomplete
,
milestones
:
this
.
enableAutocomplete
,
labels
:
this
.
enableAutocomplete
,
snippets
:
this
.
enableAutocomplete
,
});
},
beforeDestroy
()
{
const
glForm
=
$
(
this
.
$refs
[
'
gl-form
'
]).
data
(
'
glForm
'
);
if
(
glForm
)
{
glForm
.
destroy
();
}
},
methods
:
{
showPreviewTab
()
{
if
(
this
.
previewMarkdown
)
return
;
this
.
previewMarkdown
=
true
;
this
.
previewMarkdown
=
true
;
/*
/*
Can't use `$refs` as the component is technically in the parent component
so we access the VNode & then get the element
*/
const
text
=
this
.
$slots
.
textarea
[
0
].
elm
.
value
;
const
text
=
this
.
$slots
.
textarea
[
0
].
elm
.
value
;
if
(
text
)
{
this
.
markdownPreviewLoading
=
true
;
this
.
$http
.
post
(
this
.
versionedPreviewPath
(),
{
text
})
.
then
(
resp
=>
resp
.
json
())
.
then
(
data
=>
this
.
renderMarkdown
(
data
))
.
catch
(()
=>
new
Flash
(
s__
(
'
Error loading markdown preview
'
)));
}
else
{
this
.
renderMarkdown
();
}
},
if
(
text
)
{
this
.
markdownPreviewLoading
=
true
;
this
.
$http
.
post
(
this
.
versionedPreviewPath
(),
{
text
})
.
then
(
resp
=>
resp
.
json
())
.
then
(
data
=>
this
.
renderMarkdown
(
data
))
.
catch
(()
=>
new
Flash
(
s__
(
'
Error loading markdown preview
'
)));
}
else
{
this
.
renderMarkdown
();
}
},
showWriteTab
()
{
this
.
markdownPreview
=
''
;
this
.
previewMarkdown
=
false
;
},
showWriteTab
()
{
this
.
markdownPreview
=
''
;
this
.
previewMarkdown
=
false
;
},
renderMarkdown
(
data
=
{})
{
this
.
markdownPreviewLoading
=
false
;
this
.
markdownPreview
=
data
.
body
||
'
Nothing to preview.
'
;
renderMarkdown
(
data
=
{})
{
this
.
markdownPreviewLoading
=
false
;
this
.
markdownPreview
=
data
.
body
||
'
Nothing to preview.
'
;
if
(
data
.
references
)
{
this
.
referencedCommands
=
data
.
references
.
commands
;
this
.
referencedUsers
=
data
.
references
.
users
;
}
if
(
data
.
references
)
{
this
.
referencedCommands
=
data
.
references
.
commands
;
this
.
referencedUsers
=
data
.
references
.
users
;
}
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
[
'
markdown-preview
'
]).
renderGFM
();
});
},
this
.
$nextTick
(()
=>
{
$
(
this
.
$refs
[
'
markdown-preview
'
]).
renderGFM
();
});
},
versionedPreviewPath
()
{
const
{
markdownPreviewPath
,
markdownVersion
}
=
this
;
return
`
${
markdownPreviewPath
}${
markdownPreviewPath
.
indexOf
(
'
?
'
)
===
-
1
?
'
?
'
:
'
&
'
}
markdown_version=
${
markdownVersion
}
`
;
},
versionedPreviewPath
()
{
const
{
markdownPreviewPath
,
markdownVersion
}
=
this
;
return
`
${
markdownPreviewPath
}${
markdownPreviewPath
.
indexOf
(
'
?
'
)
===
-
1
?
'
?
'
:
'
&
'
}
markdown_version=
${
markdownVersion
}
`
;
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/markdown/header.vue
View file @
3271c5f0
<
script
>
import
$
from
'
jquery
'
;
import
tooltip
from
'
../../directives/tooltip
'
;
import
toolbarButton
from
'
./toolbar_button.vue
'
;
import
icon
from
'
../icon.vue
'
;
import
$
from
'
jquery
'
;
import
tooltip
from
'
../../directives/tooltip
'
;
import
toolbarButton
from
'
./toolbar_button.vue
'
;
import
icon
from
'
../icon.vue
'
;
export
default
{
directives
:
{
tooltip
,
export
default
{
directives
:
{
tooltip
,
},
components
:
{
toolbarButton
,
icon
,
},
props
:
{
previewMarkdown
:
{
type
:
Boolean
,
required
:
true
,
},
components
:
{
toolbarButton
,
icon
,
},
computed
:
{
mdTable
()
{
return
[
'
| header | header |
'
,
'
| ------ | ------ |
'
,
'
| cell | cell |
'
,
'
| cell | cell |
'
,
].
join
(
'
\n
'
);
},
props
:
{
previewMarkdown
:
{
type
:
Boolean
,
required
:
true
,
},
},
mounted
()
{
$
(
document
).
on
(
'
markdown-preview:show.vue
'
,
this
.
previewMarkdownTab
);
$
(
document
).
on
(
'
markdown-preview:hide.vue
'
,
this
.
writeMarkdownTab
);
},
beforeDestroy
()
{
$
(
document
).
off
(
'
markdown-preview:show.vue
'
,
this
.
previewMarkdownTab
);
$
(
document
).
off
(
'
markdown-preview:hide.vue
'
,
this
.
writeMarkdownTab
);
},
methods
:
{
isValid
(
form
)
{
return
(
!
form
||
(
form
.
find
(
'
.js-vue-markdown-field
'
).
length
&&
$
(
this
.
$el
).
closest
(
'
form
'
)[
0
]
===
form
[
0
])
);
},
computed
:
{
mdTable
()
{
return
[
'
| header | header |
'
,
'
| ------ | ------ |
'
,
'
| cell | cell |
'
,
'
| cell | cell |
'
,
].
join
(
'
\n
'
);
},
},
mounted
()
{
$
(
document
).
on
(
'
markdown-preview:show.vue
'
,
this
.
previewMarkdownTab
);
$
(
document
).
on
(
'
markdown-preview:hide.vue
'
,
this
.
writeMarkdownTab
);
},
beforeDestroy
()
{
$
(
document
).
off
(
'
markdown-preview:show.vue
'
,
this
.
previewMarkdownTab
);
$
(
document
).
off
(
'
markdown-preview:hide.vue
'
,
this
.
writeMarkdownTab
);
},
methods
:
{
isValid
(
form
)
{
return
!
form
||
form
.
find
(
'
.js-vue-markdown-field
'
).
length
&&
$
(
this
.
$el
).
closest
(
'
form
'
)[
0
]
===
form
[
0
];
},
previewMarkdownTab
(
event
,
form
)
{
if
(
event
.
target
.
blur
)
event
.
target
.
blur
();
if
(
!
this
.
isValid
(
form
))
return
;
previewMarkdownTab
(
event
,
form
)
{
if
(
event
.
target
.
blur
)
event
.
target
.
blur
();
if
(
!
this
.
isValid
(
form
))
return
;
this
.
$emit
(
'
preview-markdown
'
);
},
this
.
$emit
(
'
preview-markdown
'
);
},
writeMarkdownTab
(
event
,
form
)
{
if
(
event
.
target
.
blur
)
event
.
target
.
blur
();
if
(
!
this
.
isValid
(
form
))
return
;
writeMarkdownTab
(
event
,
form
)
{
if
(
event
.
target
.
blur
)
event
.
target
.
blur
();
if
(
!
this
.
isValid
(
form
))
return
;
this
.
$emit
(
'
write-markdown
'
);
},
this
.
$emit
(
'
write-markdown
'
);
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
View file @
3271c5f0
<
script
>
import
{
Link
}
from
'
@gitlab-org/gitlab-ui
'
;
import
{
Link
}
from
'
@gitlab-org/gitlab-ui
'
;
export
default
{
components
:
{
'
gl-link
'
:
Link
,
export
default
{
components
:
{
'
gl-link
'
:
Link
,
},
props
:
{
markdownDocsPath
:
{
type
:
String
,
required
:
true
,
},
props
:
{
markdownDocsPath
:
{
type
:
String
,
required
:
true
,
},
quickActionsDocsPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
canAttachFile
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
quickActionsDocsPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
c
omputed
:
{
hasQuickActionsDocsPath
()
{
return
this
.
quickActionsDocsPath
!==
''
;
}
,
c
anAttachFile
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
};
},
computed
:
{
hasQuickActionsDocsPath
()
{
return
this
.
quickActionsDocsPath
!==
''
;
},
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
View file @
3271c5f0
<
script
>
import
tooltip
from
'
../../directives/tooltip
'
;
import
icon
from
'
../icon.vue
'
;
import
tooltip
from
'
../../directives/tooltip
'
;
import
icon
from
'
../icon.vue
'
;
export
default
{
components
:
{
icon
,
export
default
{
components
:
{
icon
,
},
directives
:
{
tooltip
,
},
props
:
{
buttonTitle
:
{
type
:
String
,
required
:
true
,
},
directives
:
{
tooltip
,
icon
:
{
type
:
String
,
required
:
true
,
},
props
:
{
buttonTitle
:
{
type
:
String
,
required
:
true
,
},
icon
:
{
type
:
String
,
required
:
true
,
},
tag
:
{
type
:
String
,
required
:
true
,
},
tagBlock
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
tagSelect
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
prepend
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
tag
:
{
type
:
String
,
required
:
true
,
},
};
tagBlock
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
tagSelect
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
prepend
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/memory_graph.vue
View file @
3271c5f0
...
...
@@ -41,7 +41,8 @@ export default {
// Find metric timestamp which is closest to deploymentTime
timestampDiff
=
Math
.
abs
(
metricTimestamps
[
0
]
-
median
);
metricTimestamps
.
forEach
((
timestamp
,
index
)
=>
{
if
(
index
===
0
)
{
// Skip first element
if
(
index
===
0
)
{
// Skip first element
return
;
}
...
...
app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
View file @
3271c5f0
<
script
>
/**
* Common component to render a placeholder note and user information.
*
* This component needs to be used with a vuex store.
* That vuex store needs to have a `getUserData` getter that contains
* {
* path: String,
* avatar_url: String,
* name: String,
* username: String,
* }
*
* @example
* <placeholder-note
* :note="{body: 'This is a note'}"
* />
*/
import
{
mapGetters
}
from
'
vuex
'
;
import
userAvatarLink
from
'
../user_avatar/user_avatar_link.vue
'
;
/**
* Common component to render a placeholder note and user information.
*
* This component needs to be used with a vuex store.
* That vuex store needs to have a `getUserData` getter that contains
* {
* path: String,
* avatar_url: String,
* name: String,
* username: String,
* }
*
* @example
* <placeholder-note
* :note="{body: 'This is a note'}"
* />
*/
import
{
mapGetters
}
from
'
vuex
'
;
import
userAvatarLink
from
'
../user_avatar/user_avatar_link.vue
'
;
export
default
{
name
:
'
PlaceholderNote
'
,
components
:
{
userAvatarLink
,
export
default
{
name
:
'
PlaceholderNote
'
,
components
:
{
userAvatarLink
,
},
props
:
{
note
:
{
type
:
Object
,
required
:
true
,
},
props
:
{
note
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
...
mapGetters
([
'
getUserData
'
,
]),
},
};
},
computed
:
{
...
mapGetters
([
'
getUserData
'
]),
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
View file @
3271c5f0
<
script
>
/**
* Common component to render a placeholder system note.
*
* @example
* <placeholder-system-note
* :note="{ body: 'Commands are being applied'}"
* />
*/
export
default
{
name
:
'
PlaceholderSystemNote
'
,
props
:
{
note
:
{
type
:
Object
,
required
:
true
,
},
/**
* Common component to render a placeholder system note.
*
* @example
* <placeholder-system-note
* :note="{ body: 'Commands are being applied'}"
* />
*/
export
default
{
name
:
'
PlaceholderSystemNote
'
,
props
:
{
note
:
{
type
:
Object
,
required
:
true
,
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/panel_resizer.vue
View file @
3271c5f0
<
script
>
export
default
{
props
:
{
startSize
:
{
type
:
Number
,
required
:
true
,
},
side
:
{
type
:
String
,
required
:
true
,
},
minSize
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
maxSize
:
{
type
:
Number
,
required
:
false
,
default
:
Number
.
MAX_VALUE
,
},
enabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
export
default
{
props
:
{
startSize
:
{
type
:
Number
,
required
:
true
,
},
data
()
{
return
{
size
:
this
.
startSize
,
};
side
:
{
type
:
String
,
required
:
true
,
},
computed
:
{
className
()
{
return
`drag-
${
this
.
side
}
`
;
},
cursorStyle
()
{
if
(
this
.
enabled
)
{
return
{
cursor
:
'
ew-resize
'
};
}
return
{};
},
minSize
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
methods
:
{
resetSize
(
e
)
{
e
.
preventDefault
();
this
.
$emit
(
'
resize-start
'
,
this
.
size
);
maxSize
:
{
type
:
Number
,
required
:
false
,
default
:
Number
.
MAX_VALUE
,
},
enabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
},
data
()
{
return
{
size
:
this
.
startSize
,
};
},
computed
:
{
className
()
{
return
`drag-
${
this
.
side
}
`
;
},
cursorStyle
()
{
if
(
this
.
enabled
)
{
return
{
cursor
:
'
ew-resize
'
};
}
return
{};
},
},
methods
:
{
resetSize
(
e
)
{
e
.
preventDefault
();
this
.
$emit
(
'
resize-start
'
,
this
.
size
);
this
.
size
=
this
.
startSize
;
this
.
$emit
(
'
update:size
'
,
this
.
size
);
this
.
size
=
this
.
startSize
;
this
.
$emit
(
'
update:size
'
,
this
.
size
);
// End resizing on next tick so that listeners can react to DOM changes
this
.
$nextTick
(()
=>
{
this
.
$emit
(
'
resize-end
'
,
this
.
size
);
});
},
startDrag
(
e
)
{
if
(
this
.
enabled
)
{
e
.
preventDefault
();
this
.
startPos
=
e
.
clientX
;
this
.
currentStartSize
=
this
.
size
;
document
.
addEventListener
(
'
mousemove
'
,
this
.
drag
);
document
.
addEventListener
(
'
mouseup
'
,
this
.
endDrag
,
{
once
:
true
});
this
.
$emit
(
'
resize-start
'
,
this
.
size
);
}
},
drag
(
e
)
{
// End resizing on next tick so that listeners can react to DOM changes
this
.
$nextTick
(()
=>
{
this
.
$emit
(
'
resize-end
'
,
this
.
size
);
});
},
startDrag
(
e
)
{
if
(
this
.
enabled
)
{
e
.
preventDefault
();
let
moved
=
e
.
clientX
-
this
.
startPos
;
if
(
this
.
side
===
'
left
'
)
moved
=
-
moved
;
let
newSize
=
this
.
currentStartSize
+
moved
;
if
(
newSize
<
this
.
minSize
)
{
newSize
=
this
.
minSize
;
}
else
if
(
newSize
>
this
.
maxSize
)
{
newSize
=
this
.
maxSize
;
}
this
.
size
=
newSize
;
this
.
startPos
=
e
.
clientX
;
this
.
currentStartSize
=
this
.
size
;
document
.
addEventListener
(
'
mousemove
'
,
this
.
drag
);
document
.
addEventListener
(
'
mouseup
'
,
this
.
endDrag
,
{
once
:
true
});
this
.
$emit
(
'
resize-start
'
,
this
.
size
);
}
},
drag
(
e
)
{
e
.
preventDefault
();
let
moved
=
e
.
clientX
-
this
.
startPos
;
if
(
this
.
side
===
'
left
'
)
moved
=
-
moved
;
let
newSize
=
this
.
currentStartSize
+
moved
;
if
(
newSize
<
this
.
minSize
)
{
newSize
=
this
.
minSize
;
}
else
if
(
newSize
>
this
.
maxSize
)
{
newSize
=
this
.
maxSize
;
}
this
.
size
=
newSize
;
this
.
$emit
(
'
update:size
'
,
newSize
);
},
endDrag
(
e
)
{
e
.
preventDefault
();
document
.
removeEventListener
(
'
mousemove
'
,
this
.
drag
);
this
.
$emit
(
'
resize-end
'
,
this
.
size
);
},
this
.
$emit
(
'
update:size
'
,
newSize
);
},
endDrag
(
e
)
{
e
.
preventDefault
();
document
.
removeEventListener
(
'
mousemove
'
,
this
.
drag
);
this
.
$emit
(
'
resize-end
'
,
this
.
size
);
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/pikaday.vue
View file @
3271c5f0
<
script
>
import
Pikaday
from
'
pikaday
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
../../lib/utils/datefix
'
;
import
Pikaday
from
'
pikaday
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
../../lib/utils/datefix
'
;
export
default
{
name
:
'
DatePicker
'
,
props
:
{
label
:
{
type
:
String
,
required
:
false
,
default
:
'
Date picker
'
,
},
selectedDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
minDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
maxDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
export
default
{
name
:
'
DatePicker
'
,
props
:
{
label
:
{
type
:
String
,
required
:
false
,
default
:
'
Date picker
'
,
},
mounted
()
{
this
.
calendar
=
new
Pikaday
({
field
:
this
.
$el
.
querySelector
(
'
.dropdown-menu-toggle
'
),
theme
:
'
gitlab-theme animate-picker
'
,
format
:
'
yyyy-mm-dd
'
,
container
:
this
.
$el
,
defaultDate
:
this
.
selectedDate
,
setDefaultDate
:
!!
this
.
selectedDate
,
minDate
:
this
.
minDate
,
maxDate
:
this
.
maxDate
,
parse
:
dateString
=>
parsePikadayDate
(
dateString
),
toString
:
date
=>
pikadayToString
(
date
),
onSelect
:
this
.
selected
.
bind
(
this
),
onClose
:
this
.
toggled
.
bind
(
this
),
});
this
.
$el
.
append
(
this
.
calendar
.
el
);
this
.
calendar
.
show
();
selectedDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
minDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
beforeDestroy
()
{
this
.
calendar
.
destroy
();
maxDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
},
mounted
()
{
this
.
calendar
=
new
Pikaday
({
field
:
this
.
$el
.
querySelector
(
'
.dropdown-menu-toggle
'
),
theme
:
'
gitlab-theme animate-picker
'
,
format
:
'
yyyy-mm-dd
'
,
container
:
this
.
$el
,
defaultDate
:
this
.
selectedDate
,
setDefaultDate
:
!!
this
.
selectedDate
,
minDate
:
this
.
minDate
,
maxDate
:
this
.
maxDate
,
parse
:
dateString
=>
parsePikadayDate
(
dateString
),
toString
:
date
=>
pikadayToString
(
date
),
onSelect
:
this
.
selected
.
bind
(
this
),
onClose
:
this
.
toggled
.
bind
(
this
),
});
this
.
$el
.
append
(
this
.
calendar
.
el
);
this
.
calendar
.
show
();
},
beforeDestroy
()
{
this
.
calendar
.
destroy
();
},
methods
:
{
selected
(
dateText
)
{
this
.
$emit
(
'
newDateSelected
'
,
this
.
calendar
.
toString
(
dateText
));
},
methods
:
{
selected
(
dateText
)
{
this
.
$emit
(
'
newDateSelected
'
,
this
.
calendar
.
toString
(
dateText
));
},
toggled
()
{
this
.
$emit
(
'
hidePicker
'
);
},
toggled
()
{
this
.
$emit
(
'
hidePicker
'
);
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/project_avatar/image.vue
View file @
3271c5f0
<
script
>
/* This is a re-usable vue component for rendering a project avatar that
/* This is a re-usable vue component for rendering a project avatar that
does not need to link to the project's profile. The image and an optional
tooltip can be configured by props passed to this component.
...
...
@@ -16,70 +15,70 @@
*/
import
defaultAvatarUrl
from
'
images/no_avatar.png
'
;
import
{
placeholderImage
}
from
'
../../../lazy_loader
'
;
import
tooltip
from
'
../../directives/tooltip
'
;
import
defaultAvatarUrl
from
'
images/no_avatar.png
'
;
import
{
placeholderImage
}
from
'
../../../lazy_loader
'
;
import
tooltip
from
'
../../directives/tooltip
'
;
export
default
{
name
:
'
ProjectAvatarImage
'
,
directives
:
{
tooltip
,
export
default
{
name
:
'
ProjectAvatarImage
'
,
directives
:
{
tooltip
,
},
props
:
{
lazy
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
imgSrc
:
{
type
:
String
,
required
:
false
,
default
:
defaultAvatarUrl
,
},
cssClasses
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
imgAlt
:
{
type
:
String
,
required
:
false
,
default
:
'
project avatar
'
,
},
size
:
{
type
:
Number
,
required
:
false
,
default
:
20
,
},
tooltipText
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
tooltipPlacement
:
{
type
:
String
,
required
:
false
,
default
:
'
top
'
,
},
},
computed
:
{
// API response sends null when gravatar is disabled and
// we provide an empty string when we use it inside project avatar link.
// In both cases we should render the defaultAvatarUrl
sanitizedSource
()
{
return
this
.
imgSrc
===
''
||
this
.
imgSrc
===
null
?
defaultAvatarUrl
:
this
.
imgSrc
;
},
resultantSrcAttribute
()
{
return
this
.
lazy
?
placeholderImage
:
this
.
sanitizedSource
;
},
props
:
{
lazy
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
imgSrc
:
{
type
:
String
,
required
:
false
,
default
:
defaultAvatarUrl
,
},
cssClasses
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
imgAlt
:
{
type
:
String
,
required
:
false
,
default
:
'
project avatar
'
,
},
size
:
{
type
:
Number
,
required
:
false
,
default
:
20
,
},
tooltipText
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
tooltipPlacement
:
{
type
:
String
,
required
:
false
,
default
:
'
top
'
,
},
tooltipContainer
()
{
return
this
.
tooltipText
?
'
body
'
:
null
;
},
computed
:
{
// API response sends null when gravatar is disabled and
// we provide an empty string when we use it inside project avatar link.
// In both cases we should render the defaultAvatarUrl
sanitizedSource
()
{
return
this
.
imgSrc
===
''
||
this
.
imgSrc
===
null
?
defaultAvatarUrl
:
this
.
imgSrc
;
},
resultantSrcAttribute
()
{
return
this
.
lazy
?
placeholderImage
:
this
.
sanitizedSource
;
},
tooltipContainer
()
{
return
this
.
tooltipText
?
'
body
'
:
null
;
},
avatarSizeClass
()
{
return
`s
${
this
.
size
}
`
;
},
avatarSizeClass
()
{
return
`s
${
this
.
size
}
`
;
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
View file @
3271c5f0
<
script
>
import
DeprecatedModal
from
'
./deprecated_modal.vue
'
;
import
DeprecatedModal
from
'
./deprecated_modal.vue
'
;
export
default
{
name
:
'
RecaptchaModal
'
,
export
default
{
name
:
'
RecaptchaModal
'
,
components
:
{
DeprecatedModal
,
},
components
:
{
DeprecatedModal
,
},
props
:
{
html
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
props
:
{
html
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
data
()
{
return
{
script
:
{},
scriptSrc
:
'
https://www.google.com/recaptcha/api.js
'
,
};
},
data
()
{
return
{
script
:
{},
scriptSrc
:
'
https://www.google.com/recaptcha/api.js
'
,
};
},
watch
:
{
html
()
{
this
.
appendRecaptchaScript
();
},
watch
:
{
html
()
{
this
.
appendRecaptchaScript
();
},
},
mounted
()
{
window
.
recaptchaDialogCallback
=
this
.
submit
.
bind
(
this
);
},
mounted
()
{
window
.
recaptchaDialogCallback
=
this
.
submit
.
bind
(
this
);
},
methods
:
{
appendRecaptchaScript
()
{
this
.
removeRecaptchaScript
();
methods
:
{
appendRecaptchaScript
()
{
this
.
removeRecaptchaScript
();
const
script
=
document
.
createElement
(
'
script
'
);
script
.
src
=
this
.
scriptSrc
;
script
.
classList
.
add
(
'
js-recaptcha-script
'
);
script
.
async
=
true
;
script
.
defer
=
true
;
const
script
=
document
.
createElement
(
'
script
'
);
script
.
src
=
this
.
scriptSrc
;
script
.
classList
.
add
(
'
js-recaptcha-script
'
);
script
.
async
=
true
;
script
.
defer
=
true
;
this
.
script
=
script
;
this
.
script
=
script
;
document
.
body
.
appendChild
(
script
);
},
document
.
body
.
appendChild
(
script
);
},
removeRecaptchaScript
()
{
if
(
this
.
script
instanceof
Element
)
this
.
script
.
remove
();
},
removeRecaptchaScript
()
{
if
(
this
.
script
instanceof
Element
)
this
.
script
.
remove
();
},
close
()
{
this
.
removeRecaptchaScript
();
this
.
$emit
(
'
close
'
);
},
close
()
{
this
.
removeRecaptchaScript
();
this
.
$emit
(
'
close
'
);
},
submit
()
{
this
.
$el
.
querySelector
(
'
form
'
).
submit
();
},
submit
()
{
this
.
$el
.
querySelector
(
'
form
'
).
submit
();
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
View file @
3271c5f0
<
script
>
import
datePicker
from
'
../pikaday.vue
'
;
import
toggleSidebar
from
'
./toggle_sidebar.vue
'
;
import
collapsedCalendarIcon
from
'
./collapsed_calendar_icon.vue
'
;
import
{
dateInWords
}
from
'
../../../lib/utils/datetime_utility
'
;
import
datePicker
from
'
../pikaday.vue
'
;
import
toggleSidebar
from
'
./toggle_sidebar.vue
'
;
import
collapsedCalendarIcon
from
'
./collapsed_calendar_icon.vue
'
;
import
{
dateInWords
}
from
'
../../../lib/utils/datetime_utility
'
;
export
default
{
name
:
'
SidebarDatePicker
'
,
components
:
{
datePicker
,
toggleSidebar
,
collapsedCalendarIcon
,
},
props
:
{
blockClass
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
collapsed
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
showToggleSidebar
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isLoading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
editable
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
label
:
{
type
:
String
,
required
:
false
,
default
:
'
Date picker
'
,
},
selectedDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
minDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
maxDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
},
data
()
{
return
{
editing
:
false
,
};
},
computed
:
{
selectedAndEditable
()
{
return
this
.
selectedDate
&&
this
.
editable
;
},
selectedDateWords
()
{
return
dateInWords
(
this
.
selectedDate
,
true
);
},
collapsedText
()
{
return
this
.
selectedDateWords
?
this
.
selectedDateWords
:
'
None
'
;
},
},
methods
:
{
stopEditing
()
{
this
.
editing
=
false
;
},
toggleDatePicker
()
{
this
.
editing
=
!
this
.
editing
;
},
newDateSelected
(
date
=
null
)
{
this
.
date
=
date
;
this
.
editing
=
false
;
this
.
$emit
(
'
saveDate
'
,
date
);
},
toggleSidebar
()
{
this
.
$emit
(
'
toggleCollapse
'
);
},
},
};
export
default
{
name
:
'
SidebarDatePicker
'
,
components
:
{
datePicker
,
toggleSidebar
,
collapsedCalendarIcon
,
},
props
:
{
blockClass
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
collapsed
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
showToggleSidebar
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isLoading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
editable
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
label
:
{
type
:
String
,
required
:
false
,
default
:
'
Date picker
'
,
},
selectedDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
minDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
maxDate
:
{
type
:
Date
,
required
:
false
,
default
:
null
,
},
},
data
()
{
return
{
editing
:
false
,
};
},
computed
:
{
selectedAndEditable
()
{
return
this
.
selectedDate
&&
this
.
editable
;
},
selectedDateWords
()
{
return
dateInWords
(
this
.
selectedDate
,
true
);
},
collapsedText
()
{
return
this
.
selectedDateWords
?
this
.
selectedDateWords
:
'
None
'
;
},
},
methods
:
{
stopEditing
()
{
this
.
editing
=
false
;
},
toggleDatePicker
()
{
this
.
editing
=
!
this
.
editing
;
},
newDateSelected
(
date
=
null
)
{
this
.
date
=
date
;
this
.
editing
=
false
;
this
.
$emit
(
'
saveDate
'
,
date
);
},
toggleSidebar
()
{
this
.
$emit
(
'
toggleCollapse
'
);
},
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/table_pagination.vue
View file @
3271c5f0
<
script
>
import
{
s__
}
from
'
../../locale
'
;
const
PAGINATION_UI_BUTTON_LIMIT
=
4
;
const
UI_LIMIT
=
6
;
const
SPREAD
=
'
...
'
;
const
PREV
=
s__
(
'
Pagination|Prev
'
);
const
NEXT
=
s__
(
'
Pagination|Next
'
);
const
FIRST
=
s__
(
'
Pagination|« First
'
);
const
LAST
=
s__
(
'
Pagination|Last »
'
);
export
default
{
props
:
{
/**
import
{
s__
}
from
'
../../locale
'
;
const
PAGINATION_UI_BUTTON_LIMIT
=
4
;
const
UI_LIMIT
=
6
;
const
SPREAD
=
'
...
'
;
const
PREV
=
s__
(
'
Pagination|Prev
'
);
const
NEXT
=
s__
(
'
Pagination|Next
'
);
const
FIRST
=
s__
(
'
Pagination|« First
'
);
const
LAST
=
s__
(
'
Pagination|Last »
'
);
export
default
{
props
:
{
/**
This function will take the information given by the pagination component
Here is an example `change` method:
...
...
@@ -20,12 +20,12 @@
gl.utils.visitUrl(`?page=${pagenum}`);
},
*/
change
:
{
type
:
Function
,
required
:
true
,
},
change
:
{
type
:
Function
,
required
:
true
,
},
/**
/**
pageInfo will come from the headers of the API call
in the `.then` clause of the VueResource API call
there should be a function that contructs the pageInfo for this component
...
...
@@ -41,94 +41,94 @@
previousPage: +headers['X-Prev-Page'],
});
*/
pageInfo
:
{
type
:
Object
,
required
:
true
,
},
pageInfo
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
prev
()
{
return
this
.
pageInfo
.
previousPage
;
},
next
()
{
return
this
.
pageInfo
.
nextPage
;
},
getItems
()
{
const
total
=
this
.
pageInfo
.
totalPages
;
const
{
page
}
=
this
.
pageInfo
;
const
items
=
[];
if
(
page
>
1
)
{
items
.
push
({
title
:
FIRST
,
first
:
true
});
}
if
(
page
>
1
)
{
items
.
push
({
title
:
PREV
,
prev
:
true
});
}
else
{
items
.
push
({
title
:
PREV
,
disabled
:
true
,
prev
:
true
});
}
if
(
page
>
UI_LIMIT
)
items
.
push
({
title
:
SPREAD
,
separator
:
true
});
const
start
=
Math
.
max
(
page
-
PAGINATION_UI_BUTTON_LIMIT
,
1
);
const
end
=
Math
.
min
(
page
+
PAGINATION_UI_BUTTON_LIMIT
,
total
);
for
(
let
i
=
start
;
i
<=
end
;
i
+=
1
)
{
const
isActive
=
i
===
page
;
items
.
push
({
title
:
i
,
active
:
isActive
,
page
:
true
});
}
if
(
total
-
page
>
PAGINATION_UI_BUTTON_LIMIT
)
{
items
.
push
({
title
:
SPREAD
,
separator
:
true
,
page
:
true
});
}
if
(
page
===
total
)
{
items
.
push
({
title
:
NEXT
,
disabled
:
true
,
next
:
true
});
}
else
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
NEXT
,
next
:
true
});
}
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
LAST
,
last
:
true
});
}
return
items
;
},
showPagination
()
{
return
this
.
pageInfo
.
totalPages
>
1
;
},
computed
:
{
prev
()
{
return
this
.
pageInfo
.
previousPage
;
},
next
()
{
return
this
.
pageInfo
.
nextPage
;
},
getItems
()
{
const
total
=
this
.
pageInfo
.
totalPages
;
const
{
page
}
=
this
.
pageInfo
;
const
items
=
[];
if
(
page
>
1
)
{
items
.
push
({
title
:
FIRST
,
first
:
true
});
}
if
(
page
>
1
)
{
items
.
push
({
title
:
PREV
,
prev
:
true
});
}
else
{
items
.
push
({
title
:
PREV
,
disabled
:
true
,
prev
:
true
});
}
if
(
page
>
UI_LIMIT
)
items
.
push
({
title
:
SPREAD
,
separator
:
true
});
const
start
=
Math
.
max
(
page
-
PAGINATION_UI_BUTTON_LIMIT
,
1
);
const
end
=
Math
.
min
(
page
+
PAGINATION_UI_BUTTON_LIMIT
,
total
);
for
(
let
i
=
start
;
i
<=
end
;
i
+=
1
)
{
const
isActive
=
i
===
page
;
items
.
push
({
title
:
i
,
active
:
isActive
,
page
:
true
});
}
if
(
total
-
page
>
PAGINATION_UI_BUTTON_LIMIT
)
{
items
.
push
({
title
:
SPREAD
,
separator
:
true
,
page
:
true
});
}
if
(
page
===
total
)
{
items
.
push
({
title
:
NEXT
,
disabled
:
true
,
next
:
true
});
}
else
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
NEXT
,
next
:
true
});
}
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
LAST
,
last
:
true
});
}
return
items
;
},
showPagination
()
{
return
this
.
pageInfo
.
totalPages
>
1
;
},
},
methods
:
{
changePage
(
text
,
isDisabled
)
{
if
(
isDisabled
)
return
;
const
{
totalPages
,
nextPage
,
previousPage
}
=
this
.
pageInfo
;
switch
(
text
)
{
case
SPREAD
:
break
;
case
LAST
:
this
.
change
(
totalPages
);
break
;
case
NEXT
:
this
.
change
(
nextPage
);
break
;
case
PREV
:
this
.
change
(
previousPage
);
break
;
case
FIRST
:
this
.
change
(
1
);
break
;
default
:
this
.
change
(
+
text
);
break
;
}
},
methods
:
{
changePage
(
text
,
isDisabled
)
{
if
(
isDisabled
)
return
;
const
{
totalPages
,
nextPage
,
previousPage
}
=
this
.
pageInfo
;
switch
(
text
)
{
case
SPREAD
:
break
;
case
LAST
:
this
.
change
(
totalPages
);
break
;
case
NEXT
:
this
.
change
(
nextPage
);
break
;
case
PREV
:
this
.
change
(
previousPage
);
break
;
case
FIRST
:
this
.
change
(
1
);
break
;
default
:
this
.
change
(
+
text
);
break
;
}
},
hideOnSmallScreen
(
item
)
{
return
!
item
.
first
&&
!
item
.
last
&&
!
item
.
next
&&
!
item
.
prev
&&
!
item
.
active
;
},
hideOnSmallScreen
(
item
)
{
return
!
item
.
first
&&
!
item
.
last
&&
!
item
.
next
&&
!
item
.
prev
&&
!
item
.
active
;
},
};
},
};
</
script
>
<
template
>
<div
...
...
app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
View file @
3271c5f0
...
...
@@ -11,9 +11,7 @@ export default {
directives
:
{
tooltip
,
},
mixins
:
[
timeagoMixin
,
],
mixins
:
[
timeagoMixin
],
props
:
{
time
:
{
type
:
String
,
...
...
app/assets/javascripts/vue_shared/components/toggle_button.vue
View file @
3271c5f0
<
script
>
import
{
s__
}
from
'
../../locale
'
;
import
icon
from
'
./icon.vue
'
;
import
{
s__
}
from
'
../../locale
'
;
import
icon
from
'
./icon.vue
'
;
const
ICON_ON
=
'
status_success_borderless
'
;
const
ICON_OFF
=
'
status_failed_borderless
'
;
const
LABEL_ON
=
s__
(
'
ToggleButton|Toggle Status: ON
'
);
const
LABEL_OFF
=
s__
(
'
ToggleButton|Toggle Status: OFF
'
);
const
ICON_ON
=
'
status_success_borderless
'
;
const
ICON_OFF
=
'
status_failed_borderless
'
;
const
LABEL_ON
=
s__
(
'
ToggleButton|Toggle Status: ON
'
);
const
LABEL_OFF
=
s__
(
'
ToggleButton|Toggle Status: OFF
'
);
export
default
{
components
:
{
icon
,
},
export
default
{
components
:
{
icon
,
},
model
:
{
prop
:
'
value
'
,
event
:
'
change
'
,
},
model
:
{
prop
:
'
value
'
,
event
:
'
change
'
,
},
props
:
{
name
:
{
type
:
String
,
required
:
false
,
default
:
null
,
},
value
:
{
type
:
Boolean
,
required
:
false
,
default
:
null
,
},
disabledInput
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isLoading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
props
:
{
name
:
{
type
:
String
,
required
:
false
,
default
:
null
,
},
value
:
{
type
:
Boolean
,
required
:
false
,
default
:
null
,
},
disabledInput
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
isLoading
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
toggleIcon
()
{
return
this
.
value
?
ICON_ON
:
ICON_OFF
;
},
ariaLabel
()
{
return
this
.
value
?
LABEL_ON
:
LABEL_OFF
;
},
computed
:
{
toggleIcon
()
{
return
this
.
value
?
ICON_ON
:
ICON_OFF
;
},
ariaLabel
()
{
return
this
.
value
?
LABEL_ON
:
LABEL_OFF
;
},
},
methods
:
{
toggleFeature
()
{
if
(
!
this
.
disabledInput
)
this
.
$emit
(
'
change
'
,
!
this
.
value
);
},
methods
:
{
toggleFeature
()
{
if
(
!
this
.
disabledInput
)
this
.
$emit
(
'
change
'
,
!
this
.
value
);
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
View file @
3271c5f0
<
script
>
/* This is a re-usable vue component for rendering a user avatar wrapped in
a clickable link (likely to the user's profile). The link, image, and
tooltip can be configured by props passed to this component.
...
...
app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
View file @
3271c5f0
<
script
>
/* This is a re-usable vue component for rendering a user avatar svg (typically
for a blank state). It will receive styles comparable to the user avatar,
but no image is loaded, it isn't wrapped in a link, and tooltips aren't supported.
...
...
@@ -42,4 +41,3 @@ export default {
v-html=
"svg"
/>
</
template
>
app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
View file @
3271c5f0
...
...
@@ -4,10 +4,7 @@
*
* Components need to have `scope`, `page` and `requestData`
*/
import
{
historyPushState
,
buildUrlWithCurrentLocation
,
}
from
'
../../lib/utils/common_utils
'
;
import
{
historyPushState
,
buildUrlWithCurrentLocation
}
from
'
../../lib/utils/common_utils
'
;
export
default
{
methods
:
{
...
...
@@ -24,12 +21,14 @@ export default {
// stop polling
this
.
poll
.
stop
();
const
queryString
=
Object
.
keys
(
parameters
).
map
((
parameter
)
=>
{
const
value
=
parameters
[
parameter
];
// update internal state for UI
this
[
parameter
]
=
value
;
return
`
${
parameter
}
=
${
encodeURIComponent
(
value
)}
`
;
}).
join
(
'
&
'
);
const
queryString
=
Object
.
keys
(
parameters
)
.
map
(
parameter
=>
{
const
value
=
parameters
[
parameter
];
// update internal state for UI
this
[
parameter
]
=
value
;
return
`
${
parameter
}
=
${
encodeURIComponent
(
value
)}
`
;
})
.
join
(
'
&
'
);
// update polling parameters
this
.
requestData
=
parameters
;
...
...
app/assets/javascripts/vue_shared/models/label.js
View file @
3271c5f0
...
...
@@ -6,7 +6,7 @@ export default class ListLabel {
this
.
color
=
obj
.
color
;
this
.
textColor
=
obj
.
text_color
;
this
.
description
=
obj
.
description
;
this
.
priority
=
(
obj
.
priority
!==
null
)
?
obj
.
priority
:
Infinity
;
this
.
priority
=
obj
.
priority
!==
null
?
obj
.
priority
:
Infinity
;
}
}
...
...
app/assets/javascripts/vue_shared/translate.js
View file @
3271c5f0
import
{
__
,
n__
,
s__
,
sprintf
,
}
from
'
../locale
'
;
import
{
__
,
n__
,
s__
,
sprintf
}
from
'
../locale
'
;
export
default
(
Vue
)
=>
{
export
default
Vue
=>
{
Vue
.
mixin
({
methods
:
{
/**
...
...
app/assets/javascripts/vue_shared/vue_resource_interceptor.js
View file @
3271c5f0
...
...
@@ -21,7 +21,7 @@ Vue.http.interceptors.push((request, next) => {
Vue
.
http
.
interceptors
.
push
((
request
,
next
)
=>
{
request
.
headers
.
set
(
csrf
.
headerKey
,
csrf
.
token
);
next
(
(
response
)
=>
{
next
(
response
=>
{
// Headers object has a `forEach` property that iterates through all values.
const
headers
=
{};
...
...
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