Adds JS to toggle buttons [ci skip]
This commit is contained in:
parent
5413bf0426
commit
0bee018631
8 changed files with 178 additions and 31 deletions
62
app/assets/javascripts/clusters/clusters_index.js
Normal file
62
app/assets/javascripts/clusters/clusters_index.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
import Flash from '../flash';
|
||||
import { s__ } from '../locale';
|
||||
import ClustersService from './services/clusters_service';
|
||||
|
||||
/**
|
||||
* Handles toggle buttons in the cluster's table.
|
||||
*
|
||||
* When the user clicks the toggle button for each cluster, it:
|
||||
* - toggles the button
|
||||
* - shows a loding and disabled state
|
||||
* - Makes a put request to the given endpoint
|
||||
* Once we receive the response, either:
|
||||
* 1) Show updated status in case of successfull response
|
||||
* 2) Show initial status in case of failed response
|
||||
*/
|
||||
export default class ClusterTable {
|
||||
constructor() {
|
||||
this.container = '.js-clusters-list';
|
||||
document.querySelectorAll(`${this.container} .js-toggle-cluster-list`).forEach(button => button.addEventListener('click', e => ClusterTable.updateCluster(e)));
|
||||
}
|
||||
|
||||
removeListeners() {
|
||||
document.querySelectorAll(`${this.container} .js-toggle-cluster-list`).forEach(button => button.removeEventListener('click'));
|
||||
}
|
||||
|
||||
static updateCluster(e) {
|
||||
const toggleButton = e.currentTarget;
|
||||
const value = toggleButton.classList.contains('checked').toString();
|
||||
const endpoint = toggleButton.getAttribute('data-endpoint');
|
||||
|
||||
ClusterTable.toggleValue(toggleButton);
|
||||
ClusterTable.toggleLoadingButton(toggleButton);
|
||||
|
||||
ClustersService.updateCluster(endpoint, { cluster: { enabled: value } })
|
||||
.then(() => {
|
||||
ClusterTable.toggleLoadingButton(toggleButton);
|
||||
})
|
||||
.catch(() => {
|
||||
ClusterTable.toggleLoadingButton(toggleButton);
|
||||
ClusterTable.toggleValue(toggleButton);
|
||||
Flash(s__('ClusterIntegration|Something went wrong on our end.'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles loading and disabled classes.
|
||||
* @param {HTMLElement} button
|
||||
*/
|
||||
static toggleLoadingButton(button) {
|
||||
button.setAttribute('disabled', button.getAttribute('disabled'));
|
||||
button.classList.toggle('disabled');
|
||||
button.classList.toggle('loading');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles checked class for the given button
|
||||
* @param {HTMLElement} button
|
||||
*/
|
||||
static toggleValue(button) {
|
||||
button.classList.toggle('checked');
|
||||
}
|
||||
}
|
|
@ -17,4 +17,8 @@ export default class ClusterService {
|
|||
installApplication(appId) {
|
||||
return axios.post(this.appInstallEndpointMap[appId]);
|
||||
}
|
||||
|
||||
static updateCluster(endpoint, data) {
|
||||
return axios.put(endpoint, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -550,7 +550,15 @@ import ProjectVariables from './project_variables';
|
|||
import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle')
|
||||
.then(cluster => new cluster.default()) // eslint-disable-line new-cap
|
||||
.catch((err) => {
|
||||
Flash(s__('ClusterIntegration|Problem setting up the cluster JavaScript'));
|
||||
Flash(s__('ClusterIntegration|Problem setting up the cluster'));
|
||||
throw err;
|
||||
});
|
||||
break;
|
||||
case 'projects:clusters:index':
|
||||
import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index')
|
||||
.then(clusterIndex => new clusterIndex.default()) // eslint-disable-line new-cap
|
||||
.catch((err) => {
|
||||
Flash(s__('ClusterIntegration|Problem setting up the clusters list'));
|
||||
throw err;
|
||||
});
|
||||
break;
|
||||
|
|
|
@ -7,7 +7,7 @@ class Projects::ClustersController < Projects::ApplicationController
|
|||
before_action :authorize_admin_cluster!, only: [:destroy]
|
||||
|
||||
def index
|
||||
@clusters ||= project.clusters.map { |cluster| cluster.present(current_user: current_user) }
|
||||
@clusters ||= project.clusters.page(params[:page]).per(20).map { |cluster| cluster.present(current_user: current_user) }
|
||||
end
|
||||
|
||||
def login
|
||||
|
@ -64,10 +64,20 @@ class Projects::ClustersController < Projects::ApplicationController
|
|||
.execute(cluster)
|
||||
|
||||
if cluster.valid?
|
||||
flash[:notice] = "Cluster was successfully updated."
|
||||
redirect_to project_cluster_path(project, project.cluster)
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :no_content
|
||||
end
|
||||
format.html do
|
||||
flash[:notice] = "Cluster was successfully updated."
|
||||
redirect_to project_cluster_path(project, project.cluster)
|
||||
end
|
||||
end
|
||||
else
|
||||
render :show
|
||||
respond_to do |format|
|
||||
format.json { head :bad_request }
|
||||
format.html { render :show }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
%p= s_('ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}').html_safe % { link_to_help_page: link_to_help_page}
|
||||
|
||||
%p
|
||||
= link_to s_('ClusterIntegration|Add cluster'), '', class: 'btn btn-success', title: 'Add cluster'
|
||||
= link_to s_('ClusterIntegration|Add cluster'), new_project_cluster_path(@project), class: 'btn btn-success', title: 'Add cluster'
|
||||
.svg-content
|
||||
= image_tag 'illustrations/labels.svg'
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
%span.badge
|
||||
0
|
||||
.nav-controls
|
||||
= link_to s_('ClusterIntegration|Add cluster'), '', class: 'btn btn-success', title: 'Add cluster'
|
||||
.ci-table
|
||||
= link_to s_('ClusterIntegration|Add cluster'), new_project_cluster_path(@project), class: 'btn btn-success', title: 'Add cluster'
|
||||
.ci-table.js-clusters-list
|
||||
.gl-responsive-table-row.table-row-header{ role: 'row' }
|
||||
.table-section.section-30{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Cluster')
|
||||
|
@ -31,27 +31,30 @@
|
|||
.table-section.section-30{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Project namespace')
|
||||
.table-section.section-10{ role: 'rowheader' }
|
||||
.gl-responsive-table-row
|
||||
.table-section.section-30
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Cluster')
|
||||
.table-mobile-content
|
||||
Content goes here
|
||||
.table-section.section-30
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Environment pattern')
|
||||
.table-mobile-content
|
||||
Content goes here
|
||||
.table-section.section-30
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Project namespace')
|
||||
.table-mobile-content
|
||||
Content goes here
|
||||
.table-section.section-10
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
.table-mobile-content
|
||||
%button{ type: 'button',
|
||||
class: "js-toggle-cluster project-feature-toggle",
|
||||
'aria-label': s_('ClusterIntegration|Toggle Cluster'),
|
||||
data: { 'enabled-text': 'Enabled', 'disabled-text': 'Disabled' } }
|
||||
- @clusters.each do |cluster|
|
||||
.gl-responsive-table-row
|
||||
.table-section.section-30
|
||||
.table-mobile-header{ role: 'rowheader' }= s_('ClusterIntegration|Cluster')
|
||||
.table-mobile-content= cluster.name
|
||||
.table-section.section-30
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Environment pattern')
|
||||
.table-mobile-content
|
||||
Content goes here
|
||||
.table-section.section-30
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
= s_('ClusterIntegration|Project namespace')
|
||||
.table-mobile-content
|
||||
Content goes here
|
||||
.table-section.section-10
|
||||
.table-mobile-header{ role: 'rowheader' }
|
||||
.table-mobile-content
|
||||
%button{ type: 'button',
|
||||
class: "js-toggle-cluster-list project-feature-toggle #{'checked' unless !cluster.enabled?} #{'disabled' unless can?(current_user, :update_cluster, cluster)}",
|
||||
'aria-label': s_('ClusterIntegration|Toggle Cluster'),
|
||||
disabled: !can?(current_user, :update_cluster, cluster),
|
||||
data: { 'enabled-text': 'Enabled',
|
||||
'disabled-text': 'Disabled',
|
||||
endpoint: namespace_project_cluster_path(@project.namespace, @project, cluster, format: :json) } }
|
||||
= icon('loading', class: 'hidden')
|
||||
|
||||
|
|
|
@ -94,6 +94,33 @@ feature 'Clusters', :js do
|
|||
visit project_clusters_path(project)
|
||||
end
|
||||
|
||||
it 'user sees a table with one cluster' do
|
||||
|
||||
end
|
||||
|
||||
it 'user sees a disabled add cluster button ' do
|
||||
|
||||
end
|
||||
|
||||
it 'user sees navigation tabs' do
|
||||
|
||||
end
|
||||
|
||||
context 'update cluster' do
|
||||
it 'user can update cluster' do
|
||||
end
|
||||
|
||||
context 'with sucessfull request' do
|
||||
it 'user sees updated cluster' do
|
||||
end
|
||||
end
|
||||
|
||||
context 'with failed request' do
|
||||
it 'user sees not update cluster and error message' do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user clicks on a cluster' do
|
||||
before do
|
||||
# TODO: Replace with Click on cluster after frontend implements list
|
||||
|
@ -216,4 +243,6 @@ feature 'Clusters', :js do
|
|||
expect(page).to have_css('.signin-with-google')
|
||||
end
|
||||
end
|
||||
|
||||
context
|
||||
end
|
||||
|
|
31
spec/javascripts/clusters/clusters_index_spec.js
Normal file
31
spec/javascripts/clusters/clusters_index_spec.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import ClusterTable from '~/clusters/clusters_index';
|
||||
|
||||
describe('Clusters table', () => {
|
||||
let ClustersClass;
|
||||
|
||||
beforeEach(() => {
|
||||
ClustersClass = new ClusterTable();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ClustersClass.removeListeners();
|
||||
});
|
||||
|
||||
describe('update cluster', () => {
|
||||
it('renders a toggle button', () => {
|
||||
|
||||
});
|
||||
|
||||
it('renders loading state while request is made', () => {
|
||||
|
||||
});
|
||||
|
||||
it('shows updated state after sucessfull request', () => {
|
||||
|
||||
});
|
||||
|
||||
it('shows inital state after failed request', () => {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue