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
6a360e9a
Commit
6a360e9a
authored
Mar 01, 2021
by
Payton Burdette
Committed by
Markus Koller
Mar 01, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Introduce feature flag
Add feature flag and edit existing components that will not be wrapped.
parent
c3111e93
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
159 additions
and
94 deletions
+159
-94
app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
...ipelines/components/pipelines_list/pipeline_triggerer.vue
+11
-1
app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
...ipts/pipelines/components/pipelines_list/pipeline_url.vue
+11
-1
app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
...s/pipelines/components/pipelines_list/pipelines_table.vue
+43
-35
app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
...pelines/components/pipelines_list/pipelines_table_row.vue
+1
-11
app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
...ascripts/pipelines/components/pipelines_list/time_ago.vue
+23
-18
app/controllers/projects/pipelines_controller.rb
app/controllers/projects/pipelines_controller.rb
+1
-0
config/feature_flags/development/new_pipelines_table.yml
config/feature_flags/development/new_pipelines_table.yml
+8
-0
spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
...s/merge_request/user_sees_merge_request_pipelines_spec.rb
+1
-0
spec/features/projects/pipelines/pipelines_spec.rb
spec/features/projects/pipelines/pipelines_spec.rb
+1
-0
spec/frontend/pipelines/pipelines_table_spec.js
spec/frontend/pipelines/pipelines_table_spec.js
+50
-23
spec/frontend/pipelines/time_ago_spec.js
spec/frontend/pipelines/time_ago_spec.js
+9
-5
No files found.
app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
View file @
6a360e9a
<
script
>
import
UserAvatarLink
from
'
~/vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
export
default
{
components
:
{
UserAvatarLink
,
},
mixins
:
[
glFeatureFlagMixin
()],
props
:
{
pipeline
:
{
type
:
Object
,
...
...
@@ -15,11 +17,19 @@ export default {
user
()
{
return
this
.
pipeline
.
user
;
},
classes
()
{
const
triggererClass
=
'
pipeline-triggerer
'
;
if
(
this
.
glFeatures
.
newPipelinesTable
)
{
return
triggererClass
;
}
return
`table-section section-10 d-none d-md-block
${
triggererClass
}
`
;
},
},
};
</
script
>
<
template
>
<div
class=
"table-section section-10 d-none d-md-block pipeline-triggerer
"
>
<div
:class=
"classes
"
>
<user-avatar-link
v-if=
"user"
:link-href=
"user.path"
...
...
app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
View file @
6a360e9a
<
script
>
import
{
GlLink
,
GlPopover
,
GlSprintf
,
GlTooltipDirective
,
GlBadge
}
from
'
@gitlab/ui
'
;
import
{
helpPagePath
}
from
'
~/helpers/help_page_helper
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
{
SCHEDULE_ORIGIN
}
from
'
../../constants
'
;
export
default
{
...
...
@@ -13,6 +14,7 @@ export default {
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
mixins
:
[
glFeatureFlagMixin
()],
inject
:
{
targetProjectFullPath
:
{
default
:
''
,
...
...
@@ -47,11 +49,19 @@ export default {
autoDevopsHelpPath
()
{
return
helpPagePath
(
'
topics/autodevops/index.md
'
);
},
classes
()
{
const
tagsClass
=
'
pipeline-tags
'
;
if
(
this
.
glFeatures
.
newPipelinesTable
)
{
return
tagsClass
;
}
return
`table-section section-10 d-none d-md-block
${
tagsClass
}
`
;
},
},
};
</
script
>
<
template
>
<div
class=
"table-section section-10 d-none d-md-block pipeline-tag
s"
>
<div
:class=
"classe
s"
>
<gl-link
:href=
"pipeline.path"
data-testid=
"pipeline-url-link"
...
...
app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
View file @
6a360e9a
<
script
>
import
{
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
{
GlTable
,
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
eventHub
from
'
../../event_hub
'
;
import
PipelineStopModal
from
'
./pipeline_stop_modal.vue
'
;
import
PipelinesTableRowComponent
from
'
./pipelines_table_row.vue
'
;
/**
* Pipelines Table Component.
*
* Given an array of objects, renders a table.
*/
export
default
{
components
:
{
GlTable
,
PipelinesTableRowComponent
,
PipelineStopModal
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
},
mixins
:
[
glFeatureFlagMixin
()],
props
:
{
pipelines
:
{
type
:
Array
,
...
...
@@ -45,6 +43,11 @@ export default {
cancelingPipeline
:
null
,
};
},
computed
:
{
legacyTableClass
()
{
return
!
this
.
glFeatures
.
newPipelinesTable
?
'
ci-table
'
:
''
;
},
},
watch
:
{
pipelines
()
{
this
.
cancelingPipeline
=
null
;
...
...
@@ -70,37 +73,42 @@ export default {
};
</
script
>
<
template
>
<div
class=
"ci-table"
>
<div
class=
"gl-responsive-table-row table-row-header"
role=
"row"
>
<div
class=
"table-section section-10 js-pipeline-status"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Status
'
)
}}
</div>
<div
class=
"table-section section-10 js-pipeline-info pipeline-info"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Pipeline
'
)
}}
</div>
<div
class=
"table-section section-10 js-triggerer-info triggerer-info"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Triggerer
'
)
}}
</div>
<div
class=
"table-section section-20 js-pipeline-commit pipeline-commit"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Commit
'
)
}}
</div>
<div
class=
"table-section section-15 js-pipeline-stages pipeline-stages"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Stages
'
)
}}
</div>
<div
class=
"table-section section-15"
role=
"rowheader"
></div>
<div
class=
"table-section section-20"
role=
"rowheader"
>
<slot
name=
"table-header-actions"
></slot>
<div
:class=
"legacyTableClass"
>
<div
v-if=
"!glFeatures.newPipelinesTable"
data-testid=
"ci-table"
>
<div
class=
"gl-responsive-table-row table-row-header"
role=
"row"
>
<div
class=
"table-section section-10 js-pipeline-status"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Status
'
)
}}
</div>
<div
class=
"table-section section-10 js-pipeline-info pipeline-info"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Pipeline
'
)
}}
</div>
<div
class=
"table-section section-10 js-triggerer-info triggerer-info"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Triggerer
'
)
}}
</div>
<div
class=
"table-section section-20 js-pipeline-commit pipeline-commit"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Commit
'
)
}}
</div>
<div
class=
"table-section section-15 js-pipeline-stages pipeline-stages"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Stages
'
)
}}
</div>
<div
class=
"table-section section-15"
role=
"rowheader"
></div>
<div
class=
"table-section section-20"
role=
"rowheader"
>
<slot
name=
"table-header-actions"
></slot>
</div>
</div>
<pipelines-table-row-component
v-for=
"model in pipelines"
:key=
"model.id"
:pipeline=
"model"
:pipeline-schedule-url=
"pipelineScheduleUrl"
:update-graph-dropdown=
"updateGraphDropdown"
:view-type=
"viewType"
:canceling-pipeline=
"cancelingPipeline"
/>
</div>
<pipelines-table-row-component
v-for=
"model in pipelines"
:key=
"model.id"
:pipeline=
"model"
:pipeline-schedule-url=
"pipelineScheduleUrl"
:update-graph-dropdown=
"updateGraphDropdown"
:view-type=
"viewType"
:canceling-pipeline=
"cancelingPipeline"
/>
<gl-table
v-else
/>
<pipeline-stop-modal
:pipeline=
"pipeline"
@
submit=
"onSubmit"
/>
</div>
</
template
>
app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
View file @
6a360e9a
...
...
@@ -131,12 +131,6 @@ export default {
commitTitle
()
{
return
this
.
pipeline
?.
commit
?.
title
;
},
pipelineDuration
()
{
return
this
.
pipeline
?.
details
?.
duration
??
0
;
},
pipelineFinishedAt
()
{
return
this
.
pipeline
?.
details
?.
finished_at
??
''
;
},
pipelineStatus
()
{
return
this
.
pipeline
?.
details
?.
status
??
{};
},
...
...
@@ -231,11 +225,7 @@ export default {
</div>
</div>
<pipelines-timeago
class=
"gl-text-right"
:duration=
"pipelineDuration"
:finished-time=
"pipelineFinishedAt"
/>
<pipelines-timeago
class=
"gl-text-right"
:pipeline=
"pipeline"
/>
<div
v-if=
"displayPipelineActions"
...
...
app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
View file @
6a360e9a
<
script
>
import
{
GlIcon
,
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
export
default
{
...
...
@@ -7,23 +8,19 @@ export default {
GlTooltip
:
GlTooltipDirective
,
},
components
:
{
GlIcon
},
mixins
:
[
timeagoMixin
],
mixins
:
[
timeagoMixin
,
glFeatureFlagMixin
()
],
props
:
{
finishedTime
:
{
type
:
String
,
required
:
true
,
},
duration
:
{
type
:
Number
,
pipeline
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
hasD
uration
()
{
return
this
.
duration
>
0
;
d
uration
()
{
return
this
.
pipeline
?.
details
?.
duration
;
},
hasF
inishedTime
()
{
return
this
.
finishedTime
!==
''
;
f
inishedTime
()
{
return
this
.
pipeline
?.
details
?.
finished_at
;
},
durationFormatted
()
{
const
date
=
new
Date
(
this
.
duration
*
1000
);
...
...
@@ -45,20 +42,28 @@ export default {
return
`
${
hh
}
:
${
mm
}
:
${
ss
}
`
;
},
legacySectionClass
()
{
return
!
this
.
glFeatures
.
newPipelinesTable
?
'
table-section section-15
'
:
''
;
},
legacyTableMobileClass
()
{
return
!
this
.
glFeatures
.
newPipelinesTable
?
'
table-mobile-content
'
:
''
;
},
},
};
</
script
>
<
template
>
<div
class=
"table-section section-15"
>
<div
class=
"table-mobile-header"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Duration
'
)
}}
</div>
<div
class=
"table-mobile-content"
>
<p
v-if=
"hasDuration"
class=
"duration"
>
<gl-icon
name=
"timer"
class=
"gl-vertical-align-baseline!"
/>
<div
:class=
"legacySectionClass"
>
<div
v-if=
"!glFeatures.newPipelinesTable"
class=
"table-mobile-header"
role=
"rowheader"
>
{{
s__
(
'
Pipeline|Duration
'
)
}}
</div>
<div
:class=
"legacyTableMobileClass"
>
<p
v-if=
"duration"
class=
"duration"
>
<gl-icon
name=
"timer"
class=
"gl-vertical-align-baseline!"
:size=
"12"
/>
{{
durationFormatted
}}
</p>
<p
v-if=
"
hasF
inishedTime"
class=
"finished-at d-none d-md-block"
>
<gl-icon
name=
"calendar"
class=
"gl-vertical-align-baseline!"
/>
<p
v-if=
"
f
inishedTime"
class=
"finished-at d-none d-md-block"
>
<gl-icon
name=
"calendar"
class=
"gl-vertical-align-baseline!"
:size=
"12"
/>
<time
v-gl-tooltip
...
...
app/controllers/projects/pipelines_controller.rb
View file @
6a360e9a
...
...
@@ -18,6 +18,7 @@ class Projects::PipelinesController < Projects::ApplicationController
push_frontend_feature_flag
(
:graphql_pipeline_details
,
project
,
type: :development
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:graphql_pipeline_details_users
,
current_user
,
type: :development
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:jira_for_vulnerabilities
,
project
,
type: :development
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:new_pipelines_table
,
project
,
default_enabled: :yaml
)
end
before_action
:ensure_pipeline
,
only:
[
:show
]
...
...
config/feature_flags/development/new_pipelines_table.yml
0 → 100644
View file @
6a360e9a
---
name
:
new_pipelines_table
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54958
rollout_issue_url
:
https://gitlab.com/gitlab-org/gitlab/-/issues/322599
milestone
:
'
13.10'
type
:
development
group
:
group::continuous integration
default_enabled
:
false
spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
View file @
6a360e9a
...
...
@@ -26,6 +26,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
end
before
do
stub_feature_flags
(
new_pipelines_table:
false
)
stub_application_setting
(
auto_devops_enabled:
false
)
stub_ci_pipeline_yaml_file
(
YAML
.
dump
(
config
))
project
.
add_maintainer
(
user
)
...
...
spec/features/projects/pipelines/pipelines_spec.rb
View file @
6a360e9a
...
...
@@ -14,6 +14,7 @@ RSpec.describe 'Pipelines', :js do
sign_in
(
user
)
stub_feature_flags
(
graphql_pipeline_details:
false
)
stub_feature_flags
(
graphql_pipeline_details_users:
false
)
stub_feature_flags
(
new_pipelines_table:
false
)
project
.
add_developer
(
user
)
project
.
update!
(
auto_devops_attributes:
{
enabled:
false
})
...
...
spec/frontend/pipelines/pipelines_table_spec.js
View file @
6a360e9a
import
{
GlTable
}
from
'
@gitlab/ui
'
;
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
PipelinesTable
from
'
~/pipelines/components/pipelines_list/pipelines_table.vue
'
;
describe
(
'
Pipelines Table
'
,
()
=>
{
...
...
@@ -12,20 +14,28 @@ describe('Pipelines Table', () => {
viewType
:
'
root
'
,
};
const
createComponent
=
(
props
=
defaultProps
)
=>
{
wrapper
=
mount
(
PipelinesTable
,
{
propsData
:
props
,
});
const
createComponent
=
(
props
=
defaultProps
,
flagState
=
false
)
=>
{
wrapper
=
extendedWrapper
(
mount
(
PipelinesTable
,
{
propsData
:
props
,
provide
:
{
glFeatures
:
{
newPipelinesTable
:
flagState
,
},
},
}),
);
};
const
findRows
=
()
=>
wrapper
.
findAll
(
'
.commit.gl-responsive-table-row
'
);
const
findGlTable
=
()
=>
wrapper
.
findComponent
(
GlTable
);
const
findLegacyTable
=
()
=>
wrapper
.
findByTestId
(
'
ci-table
'
);
preloadFixtures
(
jsonFixtureName
);
beforeEach
(()
=>
{
const
{
pipelines
}
=
getJSONFixture
(
jsonFixtureName
);
pipeline
=
pipelines
.
find
((
p
)
=>
p
.
user
!==
null
&&
p
.
commit
!==
null
);
createComponent
();
});
afterEach
(()
=>
{
...
...
@@ -33,33 +43,50 @@ describe('Pipelines Table', () => {
wrapper
=
null
;
});
describe
(
'
table
'
,
()
=>
{
it
(
'
should render a table
'
,
()
=>
{
expect
(
wrapper
.
classes
()).
toContain
(
'
ci-table
'
);
});
describe
(
'
table with feature flag off
'
,
()
=>
{
describe
(
'
renders the table correctly
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
should render a table
'
,
()
=>
{
expect
(
wrapper
.
classes
()).
toContain
(
'
ci-table
'
);
});
it
(
'
should render table head with correct columns
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-status
'
).
text
()).
toEqual
(
'
Status
'
);
it
(
'
should render table head with correct columns
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-status
'
).
text
()).
toEqual
(
'
Status
'
);
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-info
'
).
text
()).
toEqual
(
'
Pipeline
'
);
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-info
'
).
text
()).
toEqual
(
'
Pipeline
'
);
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-commit
'
).
text
()).
toEqual
(
'
Commit
'
);
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-commit
'
).
text
()).
toEqual
(
'
Commit
'
);
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-stages
'
).
text
()).
toEqual
(
'
Stages
'
);
expect
(
wrapper
.
find
(
'
.table-section.js-pipeline-stages
'
).
text
()).
toEqual
(
'
Stages
'
);
});
});
});
describe
(
'
without data
'
,
()
=>
{
it
(
'
should render an empty table
'
,
()
=>
{
expect
(
findRows
()).
toHaveLength
(
0
);
describe
(
'
without data
'
,
()
=>
{
it
(
'
should render an empty table
'
,
()
=>
{
createComponent
();
expect
(
findRows
()).
toHaveLength
(
0
);
});
});
describe
(
'
with data
'
,
()
=>
{
it
(
'
should render rows
'
,
()
=>
{
createComponent
({
pipelines
:
[
pipeline
],
viewType
:
'
root
'
});
expect
(
findRows
()).
toHaveLength
(
1
);
});
});
});
describe
(
'
with data
'
,
()
=>
{
it
(
'
should render rows
'
,
()
=>
{
createComponent
(
{
pipelines
:
[
pipeline
],
viewType
:
'
root
'
}
);
describe
(
'
table with feature flag on
'
,
()
=>
{
it
(
'
displays new table
'
,
()
=>
{
createComponent
(
defaultProps
,
true
);
expect
(
findRows
()).
toHaveLength
(
1
);
expect
(
findGlTable
().
exists
()).
toBe
(
true
);
expect
(
findLegacyTable
().
exists
()).
toBe
(
false
);
});
});
});
spec/frontend/pipelines/time_ago_spec.js
View file @
6a360e9a
...
...
@@ -8,7 +8,11 @@ describe('Timeago component', () => {
const
createComponent
=
(
props
=
{})
=>
{
wrapper
=
shallowMount
(
TimeAgo
,
{
propsData
:
{
...
props
,
pipeline
:
{
details
:
{
...
props
,
},
},
},
data
()
{
return
{
...
...
@@ -28,7 +32,7 @@ describe('Timeago component', () => {
describe
(
'
with duration
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
duration
:
10
,
finished
Time
:
''
});
createComponent
({
duration
:
10
,
finished
_at
:
''
});
});
it
(
'
should render duration and timer svg
'
,
()
=>
{
...
...
@@ -41,7 +45,7 @@ describe('Timeago component', () => {
describe
(
'
without duration
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
duration
:
0
,
finished
Time
:
''
});
createComponent
({
duration
:
0
,
finished
_at
:
''
});
});
it
(
'
should not render duration and timer svg
'
,
()
=>
{
...
...
@@ -51,7 +55,7 @@ describe('Timeago component', () => {
describe
(
'
with finishedTime
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
duration
:
0
,
finished
Time
:
'
2017-04-26T12:40:23.277Z
'
});
createComponent
({
duration
:
0
,
finished
_at
:
'
2017-04-26T12:40:23.277Z
'
});
});
it
(
'
should render time and calendar icon
'
,
()
=>
{
...
...
@@ -66,7 +70,7 @@ describe('Timeago component', () => {
describe
(
'
without finishedTime
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
duration
:
0
,
finished
Time
:
''
});
createComponent
({
duration
:
0
,
finished
_at
:
''
});
});
it
(
'
should not render time and calendar icon
'
,
()
=>
{
...
...
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