Merge branch 'tc-fix-unplayable-build-action-404' into 'master'
Disable pipeline & environment actions that are not playable Closes #25385 and #24601 See merge request !10052
This commit is contained in:
commit
e3ce5b642e
|
@ -45,11 +45,20 @@ export default {
|
|||
new Flash('An error occured while making the request.');
|
||||
});
|
||||
},
|
||||
|
||||
isActionDisabled(action) {
|
||||
if (action.playable === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !action.playable;
|
||||
},
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="btn-group" role="group">
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown btn btn-default dropdown-new js-dropdown-play-icon-container has-tooltip"
|
||||
data-container="body"
|
||||
data-toggle="dropdown"
|
||||
|
@ -58,15 +67,23 @@ export default {
|
|||
:disabled="isLoading">
|
||||
<span>
|
||||
<span v-html="playIconSvg"></span>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
<i v-if="isLoading" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
|
||||
<i
|
||||
class="fa fa-caret-down"
|
||||
aria-hidden="true"/>
|
||||
<i
|
||||
v-if="isLoading"
|
||||
class="fa fa-spinner fa-spin"
|
||||
aria-hidden="true"/>
|
||||
</span>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-align-right">
|
||||
<li v-for="action in actions">
|
||||
<button
|
||||
type="button"
|
||||
class="js-manual-action-link no-btn btn"
|
||||
@click="onClickAction(action.play_path)"
|
||||
class="js-manual-action-link no-btn">
|
||||
:class="{ 'disabled': isActionDisabled(action) }"
|
||||
:disabled="isActionDisabled(action)">
|
||||
${playIconSvg}
|
||||
<span>
|
||||
{{action.name}}
|
||||
|
|
|
@ -142,6 +142,7 @@ export default {
|
|||
const parsedAction = {
|
||||
name: gl.text.humanize(action.name),
|
||||
play_path: action.play_path,
|
||||
playable: action.playable,
|
||||
};
|
||||
return parsedAction;
|
||||
});
|
||||
|
|
|
@ -38,6 +38,14 @@ export default {
|
|||
new Flash('An error occured while making the request.');
|
||||
});
|
||||
},
|
||||
|
||||
isActionDisabled(action) {
|
||||
if (action.playable === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !action.playable;
|
||||
},
|
||||
},
|
||||
|
||||
template: `
|
||||
|
@ -51,16 +59,23 @@ export default {
|
|||
aria-label="Manual job"
|
||||
:disabled="isLoading">
|
||||
${playIconSvg}
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
<i v-if="isLoading" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
|
||||
<i
|
||||
class="fa fa-caret-down"
|
||||
aria-hidden="true" />
|
||||
<i
|
||||
v-if="isLoading"
|
||||
class="fa fa-spinner fa-spin"
|
||||
aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-align-right">
|
||||
<li v-for="action in actions">
|
||||
<button
|
||||
type="button"
|
||||
class="js-pipeline-action-link no-btn"
|
||||
@click="onClickAction(action.path)">
|
||||
class="js-pipeline-action-link no-btn btn"
|
||||
@click="onClickAction(action.path)"
|
||||
:class="{ 'disabled': isActionDisabled(action) }"
|
||||
:disabled="isActionDisabled(action)">
|
||||
${playIconSvg}
|
||||
<span>{{action.name}}</span>
|
||||
</button>
|
||||
|
|
|
@ -11,4 +11,6 @@ class BuildActionEntity < Grape::Entity
|
|||
build.project,
|
||||
build)
|
||||
end
|
||||
|
||||
expose :playable?, as: :playable
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@ class BuildEntity < Grape::Entity
|
|||
path_to(:play_namespace_project_build, build)
|
||||
end
|
||||
|
||||
expose :playable?, as: :playable
|
||||
expose :created_at
|
||||
expose :updated_at
|
||||
expose :detailed_status, as: :status, with: StatusEntity
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Disable pipeline and environment actions that are not playable
|
||||
merge_request: 10052
|
||||
author:
|
|
@ -192,5 +192,10 @@ FactoryGirl.define do
|
|||
trait :no_options do
|
||||
options { {} }
|
||||
end
|
||||
|
||||
trait :non_playable do
|
||||
status 'created'
|
||||
self.when 'manual'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,5 +32,10 @@ FactoryGirl.define do
|
|||
environment.update_attribute(:deployments, [deployment])
|
||||
end
|
||||
end
|
||||
|
||||
trait :non_playable do
|
||||
status 'created'
|
||||
self.when 'manual'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,6 +19,11 @@ describe('Actions Component', () => {
|
|||
name: 'foo',
|
||||
play_path: '#',
|
||||
},
|
||||
{
|
||||
name: 'foo bar',
|
||||
play_path: 'url',
|
||||
playable: false,
|
||||
},
|
||||
];
|
||||
|
||||
spy = jasmine.createSpy('spy').and.returnValue(Promise.resolve());
|
||||
|
@ -49,4 +54,14 @@ describe('Actions Component', () => {
|
|||
|
||||
expect(spy).toHaveBeenCalledWith(actionsMock[0].play_path);
|
||||
});
|
||||
|
||||
it('should render a disabled action when it\'s not playable', () => {
|
||||
expect(
|
||||
component.$el.querySelector('.dropdown-menu li:last-child button').getAttribute('disabled'),
|
||||
).toEqual('disabled');
|
||||
|
||||
expect(
|
||||
component.$el.querySelector('.dropdown-menu li:last-child button').classList.contains('disabled'),
|
||||
).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,6 +15,11 @@ describe('Pipelines Actions dropdown', () => {
|
|||
name: 'stop_review',
|
||||
path: '/root/review-app/builds/1893/play',
|
||||
},
|
||||
{
|
||||
name: 'foo',
|
||||
path: '#',
|
||||
playable: false,
|
||||
},
|
||||
];
|
||||
|
||||
spy = jasmine.createSpy('spy').and.returnValue(Promise.resolve());
|
||||
|
@ -59,4 +64,14 @@ describe('Pipelines Actions dropdown', () => {
|
|||
|
||||
expect(component.$el.querySelector('.fa-spinner')).toEqual(null);
|
||||
});
|
||||
|
||||
it('should render a disabled action when it\'s not playable', () => {
|
||||
expect(
|
||||
component.$el.querySelector('.dropdown-menu li:last-child button').getAttribute('disabled'),
|
||||
).toEqual('disabled');
|
||||
|
||||
expect(
|
||||
component.$el.querySelector('.dropdown-menu li:last-child button').classList.contains('disabled'),
|
||||
).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,5 +17,9 @@ describe BuildActionEntity do
|
|||
it 'contains path to the action play' do
|
||||
expect(subject[:path]).to include "builds/#{build.id}/play"
|
||||
end
|
||||
|
||||
it 'contains whether it is playable' do
|
||||
expect(subject[:playable]).to eq build.playable?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,6 +24,10 @@ describe BuildEntity do
|
|||
expect(subject).not_to include(/variables/)
|
||||
end
|
||||
|
||||
it 'contains whether it is playable' do
|
||||
expect(subject[:playable]).to eq build.playable?
|
||||
end
|
||||
|
||||
it 'contains timestamps' do
|
||||
expect(subject).to include(:created_at, :updated_at)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue