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
20ba7d9c
Commit
20ba7d9c
authored
May 15, 2017
by
Phil Hughes
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ee-30286-ci-badge-component' into 'master'
Port of 30286-ci-badge-component to EE See merge request !1878
parents
efb3f52f
877f3e27
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
418 additions
and
270 deletions
+418
-270
app/assets/javascripts/pipelines/components/stage.js
app/assets/javascripts/pipelines/components/stage.js
+0
-120
app/assets/javascripts/pipelines/components/stage.vue
app/assets/javascripts/pipelines/components/stage.vue
+2
-2
app/assets/javascripts/pipelines/components/status.js
app/assets/javascripts/pipelines/components/status.js
+0
-60
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
...e_merge_request_widget/components/mr_widget_deployment.js
+2
-2
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js
...vue_merge_request_widget/components/mr_widget_pipeline.js
+18
-6
app/assets/javascripts/vue_shared/ci_status_icons.js
app/assets/javascripts/vue_shared/ci_status_icons.js
+43
-0
app/assets/javascripts/vue_shared/components/ci_badge_link.vue
...ssets/javascripts/vue_shared/components/ci_badge_link.vue
+52
-0
app/assets/javascripts/vue_shared/components/ci_icon.vue
app/assets/javascripts/vue_shared/components/ci_icon.vue
+50
-0
app/assets/javascripts/vue_shared/components/pipeline_status_icon.js
...javascripts/vue_shared/components/pipeline_status_icon.js
+0
-23
app/assets/javascripts/vue_shared/components/pipelines_table_row.js
.../javascripts/vue_shared/components/pipelines_table_row.js
+12
-3
app/assets/javascripts/vue_shared/pipeline_svg_icons.js
app/assets/javascripts/vue_shared/pipeline_svg_icons.js
+0
-43
app/assets/stylesheets/pages/merge_requests.scss
app/assets/stylesheets/pages/merge_requests.scss
+2
-6
changelogs/unreleased/30286-ci-badge-component.yml
changelogs/unreleased/30286-ci-badge-component.yml
+4
-0
spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js
...pts/vue_mr_widget/components/mr_widget_deployment_spec.js
+2
-2
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
...ripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
+3
-3
spec/javascripts/vue_shared/components/ci_badge_link_spec.js
spec/javascripts/vue_shared/components/ci_badge_link_spec.js
+89
-0
spec/javascripts/vue_shared/components/ci_icon_spec.js
spec/javascripts/vue_shared/components/ci_icon_spec.js
+139
-0
No files found.
app/assets/javascripts/pipelines/components/stage.js
deleted
100644 → 0
View file @
efb3f52f
/* global Flash */
import
{
statusClassToSvgMap
}
from
'
../../vue_shared/pipeline_svg_icons
'
;
export
default
{
props
:
{
stage
:
{
type
:
Object
,
required
:
true
,
},
},
data
()
{
return
{
builds
:
''
,
spinner
:
'
<span class="fa fa-spinner fa-spin"></span>
'
,
};
},
updated
()
{
if
(
this
.
builds
)
{
this
.
stopDropdownClickPropagation
();
}
},
methods
:
{
fetchBuilds
(
e
)
{
const
ariaExpanded
=
e
.
currentTarget
.
attributes
[
'
aria-expanded
'
];
if
(
ariaExpanded
&&
(
ariaExpanded
.
textContent
===
'
true
'
))
return
null
;
return
this
.
$http
.
get
(
this
.
stage
.
dropdown_path
)
.
then
((
response
)
=>
{
this
.
builds
=
JSON
.
parse
(
response
.
body
).
html
;
})
.
catch
(()
=>
{
// If dropdown is opened we'll close it.
if
(
this
.
$el
.
classList
.
contains
(
'
open
'
))
{
$
(
this
.
$refs
.
dropdown
).
dropdown
(
'
toggle
'
);
}
const
flash
=
new
Flash
(
'
Something went wrong on our end.
'
);
return
flash
;
});
},
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* target the click event of this component.
*/
stopDropdownClickPropagation
()
{
$
(
this
.
$el
.
querySelectorAll
(
'
.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item
'
))
.
on
(
'
click
'
,
(
e
)
=>
{
e
.
stopPropagation
();
});
},
},
computed
:
{
buildsOrSpinner
()
{
return
this
.
builds
?
this
.
builds
:
this
.
spinner
;
},
dropdownClass
()
{
if
(
this
.
builds
)
return
'
js-builds-dropdown-container
'
;
return
'
js-builds-dropdown-loading builds-dropdown-loading
'
;
},
buildStatus
()
{
return
`Build:
${
this
.
stage
.
status
.
label
}
`
;
},
tooltip
()
{
return
`has-tooltip ci-status-icon ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
triggerButtonClass
()
{
return
`mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
svgHTML
()
{
return
statusClassToSvgMap
[
this
.
stage
.
status
.
icon
];
},
},
watch
:
{
'
stage.title
'
:
function
stageTitle
()
{
$
(
this
.
$refs
.
button
).
tooltip
(
'
destroy
'
).
tooltip
();
},
},
template
:
`
<div>
<button
@click="fetchBuilds($event)"
:class="triggerButtonClass"
:title="stage.title"
data-placement="top"
data-toggle="dropdown"
type="button"
:aria-label="stage.title"
ref="dropdown">
<span
v-html="svgHTML"
aria-hidden="true">
</span>
<i
class="fa fa-caret-down"
aria-hidden="true" />
</button>
<ul
ref="dropdown-content"
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<div
class="arrow-up"
aria-hidden="true"></div>
<div
:class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"
v-html="buildsOrSpinner">
</div>
</ul>
</div>
`
,
};
app/assets/javascripts/pipelines/components/stage.vue
View file @
20ba7d9c
...
@@ -14,7 +14,7 @@
...
@@ -14,7 +14,7 @@
*/
*/
/* global Flash */
/* global Flash */
import
{
statusClassToSvgMap
}
from
'
../../vue_shared/pipeline_svg
_icons
'
;
import
{
borderlessStatusIconEntityMap
}
from
'
../../vue_shared/ci_status
_icons
'
;
export
default
{
export
default
{
props
:
{
props
:
{
...
@@ -113,7 +113,7 @@ export default {
...
@@ -113,7 +113,7 @@ export default {
},
},
svgIcon
()
{
svgIcon
()
{
return
statusClassToSvg
Map
[
this
.
stage
.
status
.
icon
];
return
borderlessStatusIconEntity
Map
[
this
.
stage
.
status
.
icon
];
},
},
},
},
};
};
...
...
app/assets/javascripts/pipelines/components/status.js
deleted
100644 → 0
View file @
efb3f52f
import
canceledSvg
from
'
icons/_icon_status_canceled.svg
'
;
import
createdSvg
from
'
icons/_icon_status_created.svg
'
;
import
failedSvg
from
'
icons/_icon_status_failed.svg
'
;
import
manualSvg
from
'
icons/_icon_status_manual.svg
'
;
import
pendingSvg
from
'
icons/_icon_status_pending.svg
'
;
import
runningSvg
from
'
icons/_icon_status_running.svg
'
;
import
skippedSvg
from
'
icons/_icon_status_skipped.svg
'
;
import
successSvg
from
'
icons/_icon_status_success.svg
'
;
import
warningSvg
from
'
icons/_icon_status_warning.svg
'
;
export
default
{
props
:
{
pipeline
:
{
type
:
Object
,
required
:
true
,
},
},
data
()
{
const
svgsDictionary
=
{
icon_status_canceled
:
canceledSvg
,
icon_status_created
:
createdSvg
,
icon_status_failed
:
failedSvg
,
icon_status_manual
:
manualSvg
,
icon_status_pending
:
pendingSvg
,
icon_status_running
:
runningSvg
,
icon_status_skipped
:
skippedSvg
,
icon_status_success
:
successSvg
,
icon_status_warning
:
warningSvg
,
};
return
{
svg
:
svgsDictionary
[
this
.
pipeline
.
details
.
status
.
icon
],
};
},
computed
:
{
cssClasses
()
{
return
`ci-status ci-
${
this
.
pipeline
.
details
.
status
.
group
}
`
;
},
detailsPath
()
{
const
{
status
}
=
this
.
pipeline
.
details
;
return
status
.
has_details
?
status
.
details_path
:
false
;
},
content
()
{
return
`
${
this
.
svg
}
${
this
.
pipeline
.
details
.
status
.
text
}
`
;
},
},
template
:
`
<td class="commit-link">
<a
:class="cssClasses"
:href="detailsPath"
v-html="content">
</a>
</td>
`
,
};
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
View file @
20ba7d9c
/* global Flash */
/* global Flash */
import
'
~/lib/utils/datetime_utility
'
;
import
'
~/lib/utils/datetime_utility
'
;
import
{
status
ClassToSvgMap
}
from
'
../../vue_shared/pipeline_svg
_icons
'
;
import
{
status
IconEntityMap
}
from
'
../../vue_shared/ci_status
_icons
'
;
import
MemoryUsage
from
'
./mr_widget_memory_usage
'
;
import
MemoryUsage
from
'
./mr_widget_memory_usage
'
;
import
MRWidgetService
from
'
../services/mr_widget_service
'
;
import
MRWidgetService
from
'
../services/mr_widget_service
'
;
...
@@ -16,7 +16,7 @@ export default {
...
@@ -16,7 +16,7 @@ export default {
},
},
computed
:
{
computed
:
{
svg
()
{
svg
()
{
return
status
ClassToSvg
Map
.
icon_status_success
;
return
status
IconEntity
Map
.
icon_status_success
;
},
},
},
},
methods
:
{
methods
:
{
...
...
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.js
View file @
20ba7d9c
import
PipelineStage
from
'
../../pipelines/components/stage
'
;
import
PipelineStage
from
'
../../pipelines/components/stage
.vue
'
;
import
pipelineStatusIcon
from
'
../../vue_shared/components/pipeline_status_icon
'
;
import
ciIcon
from
'
../../vue_shared/components/ci_icon.vue
'
;
import
{
status
ClassToSvgMap
}
from
'
../../vue_shared/pipeline_svg
_icons
'
;
import
{
status
IconEntityMap
}
from
'
../../vue_shared/ci_status
_icons
'
;
export
default
{
export
default
{
name
:
'
MRWidgetPipeline
'
,
name
:
'
MRWidgetPipeline
'
,
...
@@ -9,7 +9,7 @@ export default {
...
@@ -9,7 +9,7 @@ export default {
},
},
components
:
{
components
:
{
'
pipeline-stage
'
:
PipelineStage
,
'
pipeline-stage
'
:
PipelineStage
,
'
pipeline-status-icon
'
:
pipelineStatus
Icon
,
ci
Icon
,
},
},
computed
:
{
computed
:
{
hasCIError
()
{
hasCIError
()
{
...
@@ -18,11 +18,17 @@ export default {
...
@@ -18,11 +18,17 @@ export default {
return
hasCI
&&
!
ciStatus
;
return
hasCI
&&
!
ciStatus
;
},
},
svg
()
{
svg
()
{
return
status
ClassToSvg
Map
.
icon_status_failed
;
return
status
IconEntity
Map
.
icon_status_failed
;
},
},
stageText
()
{
stageText
()
{
return
this
.
mr
.
pipeline
.
details
.
stages
.
length
>
1
?
'
stages
'
:
'
stage
'
;
return
this
.
mr
.
pipeline
.
details
.
stages
.
length
>
1
?
'
stages
'
:
'
stage
'
;
},
},
status
()
{
return
this
.
mr
.
pipeline
.
details
.
status
||
{};
},
statusPath
()
{
return
this
.
status
?
this
.
status
.
details_path
:
''
;
},
},
},
template
:
`
template
:
`
<div class="mr-widget-heading">
<div class="mr-widget-heading">
...
@@ -38,7 +44,13 @@ export default {
...
@@ -38,7 +44,13 @@ export default {
<span>Could not connect to the CI server. Please check your settings and try again.</span>
<span>Could not connect to the CI server. Please check your settings and try again.</span>
</template>
</template>
<template v-else>
<template v-else>
<pipeline-status-icon :pipelineStatus="mr.pipelineDetailedStatus" />
<div>
<a
class="icon-link"
:href="statusPath">
<ci-icon :status="status" />
</a>
</div>
<span>
<span>
Pipeline
Pipeline
<a
<a
...
...
app/assets/javascripts/vue_shared/ci_status_icons.js
0 → 100644
View file @
20ba7d9c
import
BORDERLESS_CANCELED_SVG
from
'
icons/_icon_status_canceled_borderless.svg
'
;
import
BORDERLESS_CREATED_SVG
from
'
icons/_icon_status_created_borderless.svg
'
;
import
BORDERLESS_FAILED_SVG
from
'
icons/_icon_status_failed_borderless.svg
'
;
import
BORDERLESS_MANUAL_SVG
from
'
icons/_icon_status_manual_borderless.svg
'
;
import
BORDERLESS_PENDING_SVG
from
'
icons/_icon_status_pending_borderless.svg
'
;
import
BORDERLESS_RUNNING_SVG
from
'
icons/_icon_status_running_borderless.svg
'
;
import
BORDERLESS_SKIPPED_SVG
from
'
icons/_icon_status_skipped_borderless.svg
'
;
import
BORDERLESS_SUCCESS_SVG
from
'
icons/_icon_status_success_borderless.svg
'
;
import
BORDERLESS_WARNING_SVG
from
'
icons/_icon_status_warning_borderless.svg
'
;
import
CANCELED_SVG
from
'
icons/_icon_status_canceled.svg
'
;
import
CREATED_SVG
from
'
icons/_icon_status_created.svg
'
;
import
FAILED_SVG
from
'
icons/_icon_status_failed.svg
'
;
import
MANUAL_SVG
from
'
icons/_icon_status_manual.svg
'
;
import
PENDING_SVG
from
'
icons/_icon_status_pending.svg
'
;
import
RUNNING_SVG
from
'
icons/_icon_status_running.svg
'
;
import
SKIPPED_SVG
from
'
icons/_icon_status_skipped.svg
'
;
import
SUCCESS_SVG
from
'
icons/_icon_status_success.svg
'
;
import
WARNING_SVG
from
'
icons/_icon_status_warning.svg
'
;
export
const
borderlessStatusIconEntityMap
=
{
icon_status_canceled
:
BORDERLESS_CANCELED_SVG
,
icon_status_created
:
BORDERLESS_CREATED_SVG
,
icon_status_failed
:
BORDERLESS_FAILED_SVG
,
icon_status_manual
:
BORDERLESS_MANUAL_SVG
,
icon_status_pending
:
BORDERLESS_PENDING_SVG
,
icon_status_running
:
BORDERLESS_RUNNING_SVG
,
icon_status_skipped
:
BORDERLESS_SKIPPED_SVG
,
icon_status_success
:
BORDERLESS_SUCCESS_SVG
,
icon_status_warning
:
BORDERLESS_WARNING_SVG
,
};
export
const
statusIconEntityMap
=
{
icon_status_canceled
:
CANCELED_SVG
,
icon_status_created
:
CREATED_SVG
,
icon_status_failed
:
FAILED_SVG
,
icon_status_manual
:
MANUAL_SVG
,
icon_status_pending
:
PENDING_SVG
,
icon_status_running
:
RUNNING_SVG
,
icon_status_skipped
:
SKIPPED_SVG
,
icon_status_success
:
SUCCESS_SVG
,
icon_status_warning
:
WARNING_SVG
,
};
app/assets/javascripts/vue_shared/components/ci_badge_link.vue
0 → 100644
View file @
20ba7d9c
<
script
>
import
ciIcon
from
'
./ci_icon.vue
'
;
/**
* Renders CI Badge link with CI icon and status text based on
* API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Shared between:
* - Pipelines table - first column
* - Jobs table - first column
* - Pipeline show view - header
* - Job show view - header
* - MR widget
*/
export
default
{
props
:
{
status
:
{
type
:
Object
,
required
:
true
,
},
},
components
:
{
ciIcon
,
},
computed
:
{
cssClass
()
{
const
className
=
this
.
status
.
group
;
return
className
?
`ci-status ci-
${
this
.
status
.
group
}
`
:
'
ci-status
'
;
},
},
};
</
script
>
<
template
>
<a
:href=
"status.details_path"
:class=
"cssClass"
>
<ci-icon
:status=
"status"
/>
{{
status
.
text
}}
</a>
</
template
>
app/assets/javascripts/vue_shared/components/ci_icon.vue
0 → 100644
View file @
20ba7d9c
<
script
>
import
{
statusIconEntityMap
}
from
'
../ci_status_icons
'
;
/**
* Renders CI icon based on API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Used in:
* - Pipelines table Badge
* - Pipelines table mini graph
* - Pipeline graph
* - Pipeline show view badge
* - Jobs table
* - Jobs show view header
* - Jobs show view sidebar
*/
export
default
{
props
:
{
status
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
statusIconSvg
()
{
return
statusIconEntityMap
[
this
.
status
.
icon
];
},
cssClass
()
{
const
status
=
this
.
status
.
group
;
return
`ci-status-icon ci-status-icon-
${
status
}
js-ci-status-icon-
${
status
}
`
;
},
},
};
</
script
>
<
template
>
<span
:class=
"cssClass"
v-html=
"statusIconSvg"
>
</span>
</
template
>
app/assets/javascripts/vue_shared/components/pipeline_status_icon.js
deleted
100644 → 0
View file @
efb3f52f
import
{
statusClassToSvgMap
}
from
'
../pipeline_svg_icons
'
;
export
default
{
name
:
'
PipelineStatusIcon
'
,
props
:
{
pipelineStatus
:
{
type
:
Object
,
required
:
true
,
default
:
()
=>
({})
},
},
computed
:
{
svg
()
{
return
statusClassToSvgMap
[
this
.
pipelineStatus
.
icon
];
},
statusClass
()
{
return
`ci-status-icon ci-status-icon-
${
this
.
pipelineStatus
.
group
}
`
;
},
},
template
:
`
<div :class="statusClass">
<a class="icon-link" :href="pipelineStatus.details_path">
<span v-html="svg" aria-hidden="true"></span>
</a>
</div>
`
,
};
app/assets/javascripts/vue_shared/components/pipelines_table_row.js
View file @
20ba7d9c
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
import
AsyncButtonComponent
from
'
../../pipelines/components/async_button.vue
'
;
import
AsyncButtonComponent
from
'
../../pipelines/components/async_button.vue
'
;
import
PipelinesActionsComponent
from
'
../../pipelines/components/pipelines_actions
'
;
import
PipelinesActionsComponent
from
'
../../pipelines/components/pipelines_actions
'
;
import
PipelinesArtifactsComponent
from
'
../../pipelines/components/pipelines_artifacts
'
;
import
PipelinesArtifactsComponent
from
'
../../pipelines/components/pipelines_artifacts
'
;
import
PipelinesStatusComponent
from
'
../../pipelines/components/status
'
;
import
ciBadge
from
'
./ci_badge_link.vue
'
;
import
PipelinesStageComponent
from
'
../../pipelines/components/stage.vue
'
;
import
PipelinesStageComponent
from
'
../../pipelines/components/stage.vue
'
;
import
PipelinesUrlComponent
from
'
../../pipelines/components/pipeline_url
'
;
import
PipelinesUrlComponent
from
'
../../pipelines/components/pipeline_url
'
;
import
PipelinesTimeagoComponent
from
'
../../pipelines/components/time_ago
'
;
import
PipelinesTimeagoComponent
from
'
../../pipelines/components/time_ago
'
;
...
@@ -39,7 +39,7 @@ export default {
...
@@ -39,7 +39,7 @@ export default {
'
commit-component
'
:
CommitComponent
,
'
commit-component
'
:
CommitComponent
,
'
dropdown-stage
'
:
PipelinesStageComponent
,
'
dropdown-stage
'
:
PipelinesStageComponent
,
'
pipeline-url
'
:
PipelinesUrlComponent
,
'
pipeline-url
'
:
PipelinesUrlComponent
,
'
status-scope
'
:
PipelinesStatusComponent
,
ciBadge
,
'
time-ago
'
:
PipelinesTimeagoComponent
,
'
time-ago
'
:
PipelinesTimeagoComponent
,
},
},
...
@@ -197,11 +197,20 @@ export default {
...
@@ -197,11 +197,20 @@ export default {
return
''
;
return
''
;
},
},
pipelineStatus
()
{
if
(
this
.
pipeline
.
details
&&
this
.
pipeline
.
details
.
status
)
{
return
this
.
pipeline
.
details
.
status
;
}
return
{};
},
},
},
template
:
`
template
:
`
<tr class="commit">
<tr class="commit">
<status-scope :pipeline="pipeline"/>
<td class="commit-link">
<ci-badge :status="pipelineStatus"/>
</td>
<pipeline-url :pipeline="pipeline"></pipeline-url>
<pipeline-url :pipeline="pipeline"></pipeline-url>
...
...
app/assets/javascripts/vue_shared/pipeline_svg_icons.js
deleted
100644 → 0
View file @
efb3f52f
import
canceledSvg
from
'
icons/_icon_status_canceled.svg
'
;
import
createdSvg
from
'
icons/_icon_status_created.svg
'
;
import
failedSvg
from
'
icons/_icon_status_failed.svg
'
;
import
manualSvg
from
'
icons/_icon_status_manual.svg
'
;
import
pendingSvg
from
'
icons/_icon_status_pending.svg
'
;
import
runningSvg
from
'
icons/_icon_status_running.svg
'
;
import
skippedSvg
from
'
icons/_icon_status_skipped.svg
'
;
import
successSvg
from
'
icons/_icon_status_success.svg
'
;
import
warningSvg
from
'
icons/_icon_status_warning.svg
'
;
import
canceledBorderlessSvg
from
'
icons/_icon_status_canceled_borderless.svg
'
;
import
createdBorderlessSvg
from
'
icons/_icon_status_created_borderless.svg
'
;
import
failedBorderlessSvg
from
'
icons/_icon_status_failed_borderless.svg
'
;
import
manualBorderlessSvg
from
'
icons/_icon_status_manual_borderless.svg
'
;
import
pendingBorderlessSvg
from
'
icons/_icon_status_pending_borderless.svg
'
;
import
runningBorderlessSvg
from
'
icons/_icon_status_running_borderless.svg
'
;
import
skippedBorderlessSvg
from
'
icons/_icon_status_skipped_borderless.svg
'
;
import
successBorderlessSvg
from
'
icons/_icon_status_success_borderless.svg
'
;
import
warningBorderlessSvg
from
'
icons/_icon_status_warning_borderless.svg
'
;
export
const
statusClassToSvgMap
=
{
icon_status_canceled
:
canceledSvg
,
icon_status_created
:
createdSvg
,
icon_status_failed
:
failedSvg
,
icon_status_manual
:
manualSvg
,
icon_status_pending
:
pendingSvg
,
icon_status_running
:
runningSvg
,
icon_status_skipped
:
skippedSvg
,
icon_status_success
:
successSvg
,
icon_status_warning
:
warningSvg
,
};
export
const
statusClassToBorderlessSvgMap
=
{
icon_status_canceled
:
canceledBorderlessSvg
,
icon_status_created
:
createdBorderlessSvg
,
icon_status_failed
:
failedBorderlessSvg
,
icon_status_manual
:
manualBorderlessSvg
,
icon_status_pending
:
pendingBorderlessSvg
,
icon_status_running
:
runningBorderlessSvg
,
icon_status_skipped
:
skippedBorderlessSvg
,
icon_status_success
:
successBorderlessSvg
,
icon_status_warning
:
warningBorderlessSvg
,
};
app/assets/stylesheets/pages/merge_requests.scss
View file @
20ba7d9c
...
@@ -90,11 +90,6 @@
...
@@ -90,11 +90,6 @@
align-items
:
center
;
align-items
:
center
;
padding
:
$gl-padding-top
$gl-padding
0
;
padding
:
$gl-padding-top
$gl-padding
0
;
i
,
svg
{
margin-right
:
8px
;
}
svg
{
svg
{
position
:
relative
;
position
:
relative
;
top
:
1px
;
top
:
1px
;
...
@@ -109,9 +104,10 @@
...
@@ -109,9 +104,10 @@
flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
}
}
.
ci-status-icon
>
.icon-link
svg
{
.
icon-link
>
.ci-status-icon
>
svg
{
width
:
22px
;
width
:
22px
;
height
:
22px
;
height
:
22px
;
margin-right
:
8px
;
}
}
}
}
...
...
changelogs/unreleased/30286-ci-badge-component.yml
0 → 100644
View file @
20ba7d9c
---
title
:
Refactor all CI vue badges to use the same vue component
merge_request
:
author
:
spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js
View file @
20ba7d9c
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
deploymentComponent
from
'
~/vue_merge_request_widget/components/mr_widget_deployment
'
;
import
deploymentComponent
from
'
~/vue_merge_request_widget/components/mr_widget_deployment
'
;
import
MRWidgetService
from
'
~/vue_merge_request_widget/services/mr_widget_service
'
;
import
MRWidgetService
from
'
~/vue_merge_request_widget/services/mr_widget_service
'
;
import
{
status
ClassToSvgMap
}
from
'
~/vue_shared/pipeline_svg
_icons
'
;
import
{
status
IconEntityMap
}
from
'
~/vue_shared/ci_status
_icons
'
;
const
deploymentMockData
=
[
const
deploymentMockData
=
[
{
{
...
@@ -45,7 +45,7 @@ describe('MRWidgetDeployment', () => {
...
@@ -45,7 +45,7 @@ describe('MRWidgetDeployment', () => {
describe
(
'
svg
'
,
()
=>
{
describe
(
'
svg
'
,
()
=>
{
it
(
'
should have the proper SVG icon
'
,
()
=>
{
it
(
'
should have the proper SVG icon
'
,
()
=>
{
const
vm
=
createComponent
(
deploymentMockData
);
const
vm
=
createComponent
(
deploymentMockData
);
expect
(
vm
.
svg
).
toEqual
(
status
ClassToSvg
Map
.
icon_status_success
);
expect
(
vm
.
svg
).
toEqual
(
status
IconEntity
Map
.
icon_status_success
);
});
});
});
});
});
});
...
...
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
View file @
20ba7d9c
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
{
status
ClassToSvgMap
}
from
'
~/vue_shared/pipeline_svg
_icons
'
;
import
{
status
IconEntityMap
}
from
'
~/vue_shared/ci_status
_icons
'
;
import
pipelineComponent
from
'
~/vue_merge_request_widget/components/mr_widget_pipeline
'
;
import
pipelineComponent
from
'
~/vue_merge_request_widget/components/mr_widget_pipeline
'
;
import
mockData
from
'
../mock_data
'
;
import
mockData
from
'
../mock_data
'
;
...
@@ -24,7 +24,7 @@ describe('MRWidgetPipeline', () => {
...
@@ -24,7 +24,7 @@ describe('MRWidgetPipeline', () => {
describe
(
'
components
'
,
()
=>
{
describe
(
'
components
'
,
()
=>
{
it
(
'
should have components added
'
,
()
=>
{
it
(
'
should have components added
'
,
()
=>
{
expect
(
pipelineComponent
.
components
[
'
pipeline-stage
'
]).
toBeDefined
();
expect
(
pipelineComponent
.
components
[
'
pipeline-stage
'
]).
toBeDefined
();
expect
(
pipelineComponent
.
components
[
'
pipeline-status-icon
'
]
).
toBeDefined
();
expect
(
pipelineComponent
.
components
.
ciIcon
).
toBeDefined
();
});
});
});
});
...
@@ -33,7 +33,7 @@ describe('MRWidgetPipeline', () => {
...
@@ -33,7 +33,7 @@ describe('MRWidgetPipeline', () => {
it
(
'
should have the proper SVG icon
'
,
()
=>
{
it
(
'
should have the proper SVG icon
'
,
()
=>
{
const
vm
=
createComponent
({
pipeline
:
mockData
.
pipeline
});
const
vm
=
createComponent
({
pipeline
:
mockData
.
pipeline
});
expect
(
vm
.
svg
).
toEqual
(
status
ClassToSvg
Map
.
icon_status_failed
);
expect
(
vm
.
svg
).
toEqual
(
status
IconEntity
Map
.
icon_status_failed
);
});
});
});
});
...
...
spec/javascripts/vue_shared/components/ci_badge_link_spec.js
0 → 100644
View file @
20ba7d9c
import
Vue
from
'
vue
'
;
import
ciBadge
from
'
~/vue_shared/components/ci_badge_link.vue
'
;
describe
(
'
CI Badge Link Component
'
,
()
=>
{
let
CIBadge
;
const
statuses
=
{
canceled
:
{
text
:
'
canceled
'
,
label
:
'
canceled
'
,
group
:
'
canceled
'
,
icon
:
'
icon_status_canceled
'
,
details_path
:
'
status/canceled
'
,
},
created
:
{
text
:
'
created
'
,
label
:
'
created
'
,
group
:
'
created
'
,
icon
:
'
icon_status_created
'
,
details_path
:
'
status/created
'
,
},
failed
:
{
text
:
'
failed
'
,
label
:
'
failed
'
,
group
:
'
failed
'
,
icon
:
'
icon_status_failed
'
,
details_path
:
'
status/failed
'
,
},
manual
:
{
text
:
'
manual
'
,
label
:
'
manual action
'
,
group
:
'
manual
'
,
icon
:
'
icon_status_manual
'
,
details_path
:
'
status/manual
'
,
},
pending
:
{
text
:
'
pending
'
,
label
:
'
pending
'
,
group
:
'
pending
'
,
icon
:
'
icon_status_pending
'
,
details_path
:
'
status/pending
'
,
},
running
:
{
text
:
'
running
'
,
label
:
'
running
'
,
group
:
'
running
'
,
icon
:
'
icon_status_running
'
,
details_path
:
'
status/running
'
,
},
skipped
:
{
text
:
'
skipped
'
,
label
:
'
skipped
'
,
group
:
'
skipped
'
,
icon
:
'
icon_status_skipped
'
,
details_path
:
'
status/skipped
'
,
},
success_warining
:
{
text
:
'
passed
'
,
label
:
'
passed
'
,
group
:
'
success_with_warnings
'
,
icon
:
'
icon_status_warning
'
,
details_path
:
'
status/warning
'
,
},
success
:
{
text
:
'
passed
'
,
label
:
'
passed
'
,
group
:
'
passed
'
,
icon
:
'
icon_status_success
'
,
details_path
:
'
status/passed
'
,
},
};
it
(
'
should render each status badge
'
,
()
=>
{
CIBadge
=
Vue
.
extend
(
ciBadge
);
Object
.
keys
(
statuses
).
map
((
status
)
=>
{
const
vm
=
new
CIBadge
({
propsData
:
{
status
:
statuses
[
status
],
},
}).
$mount
();
expect
(
vm
.
$el
.
getAttribute
(
'
href
'
)).
toEqual
(
statuses
[
status
].
details_path
);
expect
(
vm
.
$el
.
textContent
.
trim
()).
toEqual
(
statuses
[
status
].
text
);
expect
(
vm
.
$el
.
getAttribute
(
'
class
'
)).
toEqual
(
`ci-status ci-
${
statuses
[
status
].
group
}
`
);
expect
(
vm
.
$el
.
querySelector
(
'
svg
'
)).
toBeDefined
();
return
vm
;
});
});
});
spec/javascripts/vue_shared/components/ci_icon_spec.js
0 → 100644
View file @
20ba7d9c
import
Vue
from
'
vue
'
;
import
ciIcon
from
'
~/vue_shared/components/ci_icon.vue
'
;
describe
(
'
CI Icon component
'
,
()
=>
{
let
CiIcon
;
beforeEach
(()
=>
{
CiIcon
=
Vue
.
extend
(
ciIcon
);
});
it
(
'
should render a span element with an svg
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_success
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
tagName
).
toEqual
(
'
SPAN
'
);
expect
(
component
.
$el
.
querySelector
(
'
span > svg
'
)).
toBeDefined
();
});
it
(
'
should render a success status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_success
'
,
group
:
'
success
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-success
'
)).
toEqual
(
true
);
});
it
(
'
should render a failed status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_failed
'
,
group
:
'
failed
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-failed
'
)).
toEqual
(
true
);
});
it
(
'
should render success with warnings status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_warning
'
,
group
:
'
warning
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-warning
'
)).
toEqual
(
true
);
});
it
(
'
should render pending status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_pending
'
,
group
:
'
pending
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-pending
'
)).
toEqual
(
true
);
});
it
(
'
should render running status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_running
'
,
group
:
'
running
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-running
'
)).
toEqual
(
true
);
});
it
(
'
should render created status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_created
'
,
group
:
'
created
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-created
'
)).
toEqual
(
true
);
});
it
(
'
should render skipped status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_skipped
'
,
group
:
'
skipped
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-skipped
'
)).
toEqual
(
true
);
});
it
(
'
should render canceled status
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_canceled
'
,
group
:
'
canceled
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-canceled
'
)).
toEqual
(
true
);
});
it
(
'
should render status for manual action
'
,
()
=>
{
const
component
=
new
CiIcon
({
propsData
:
{
status
:
{
icon
:
'
icon_status_manual
'
,
group
:
'
manual
'
,
},
},
}).
$mount
();
expect
(
component
.
$el
.
classList
.
contains
(
'
ci-status-icon-manual
'
)).
toEqual
(
true
);
});
});
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