Commit e4bbe03c authored by Dan Davison's avatar Dan Davison

Merge branch 'refactor-gke-submit-button' into 'master'

Create GKE submit button component

See merge request gitlab-org/gitlab!23205
parents 2ce8db89 93f5d463
...@@ -16,9 +16,6 @@ export default { ...@@ -16,9 +16,6 @@ export default {
]), ]),
...mapState({ items: 'machineTypes' }), ...mapState({ items: 'machineTypes' }),
...mapGetters(['hasZone', 'hasMachineType']), ...mapGetters(['hasZone', 'hasMachineType']),
allDropdownsSelected() {
return this.projectHasBillingEnabled && this.hasZone && this.hasMachineType;
},
isDisabled() { isDisabled() {
return ( return (
this.isLoading || this.isLoading ||
...@@ -65,22 +62,10 @@ export default { ...@@ -65,22 +62,10 @@ export default {
.catch(this.fetchFailureHandler); .catch(this.fetchFailureHandler);
} }
}, },
selectedMachineType() {
this.enableSubmit();
},
}, },
methods: { methods: {
...mapActions(['fetchMachineTypes']), ...mapActions(['fetchMachineTypes']),
...mapActions({ setItem: 'setMachineType' }), ...mapActions({ setItem: 'setMachineType' }),
enableSubmit() {
if (this.allDropdownsSelected) {
const submitButtonEl = document.querySelector('.js-gke-cluster-creation-submit');
if (submitButtonEl) {
submitButtonEl.removeAttribute('disabled');
}
}
},
}, },
}; };
</script> </script>
......
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['hasValidData']),
},
};
</script>
<template>
<button
type="submit"
:disabled="!hasValidData"
class="js-gke-cluster-creation-submit btn btn-success"
>
{{ s__('ClusterIntegration|Create Kubernetes cluster') }}
</button>
</template>
...@@ -4,6 +4,10 @@ import Flash from '~/flash'; ...@@ -4,6 +4,10 @@ import Flash from '~/flash';
import GkeProjectIdDropdown from './components/gke_project_id_dropdown.vue'; import GkeProjectIdDropdown from './components/gke_project_id_dropdown.vue';
import GkeZoneDropdown from './components/gke_zone_dropdown.vue'; import GkeZoneDropdown from './components/gke_zone_dropdown.vue';
import GkeMachineTypeDropdown from './components/gke_machine_type_dropdown.vue'; import GkeMachineTypeDropdown from './components/gke_machine_type_dropdown.vue';
import GkeSubmitButton from './components/gke_submit_button.vue';
import store from './store';
import * as CONSTANTS from './constants'; import * as CONSTANTS from './constants';
const mountComponent = (entryPoint, component, componentName, extraProps = {}) => { const mountComponent = (entryPoint, component, componentName, extraProps = {}) => {
...@@ -14,6 +18,7 @@ const mountComponent = (entryPoint, component, componentName, extraProps = {}) = ...@@ -14,6 +18,7 @@ const mountComponent = (entryPoint, component, componentName, extraProps = {}) =
return new Vue({ return new Vue({
el, el,
store,
components: { components: {
[componentName]: component, [componentName]: component,
}, },
...@@ -50,6 +55,10 @@ const mountGkeMachineTypeDropdown = () => { ...@@ -50,6 +55,10 @@ const mountGkeMachineTypeDropdown = () => {
); );
}; };
const mountGkeSubmitButton = () => {
mountComponent('.js-gke-cluster-creation-submit-container', GkeSubmitButton, 'gke-submit-button');
};
const gkeDropdownErrorHandler = () => { const gkeDropdownErrorHandler = () => {
Flash(CONSTANTS.GCP_API_ERROR); Flash(CONSTANTS.GCP_API_ERROR);
}; };
...@@ -72,6 +81,7 @@ const initializeGapiClient = () => { ...@@ -72,6 +81,7 @@ const initializeGapiClient = () => {
mountGkeProjectIdDropdown(); mountGkeProjectIdDropdown();
mountGkeZoneDropdown(); mountGkeZoneDropdown();
mountGkeMachineTypeDropdown(); mountGkeMachineTypeDropdown();
mountGkeSubmitButton();
}) })
.catch(gkeDropdownErrorHandler); .catch(gkeDropdownErrorHandler);
}; };
......
export const hasProject = state => Boolean(state.selectedProject.projectId); export const hasProject = state => Boolean(state.selectedProject.projectId);
export const hasZone = state => Boolean(state.selectedZone); export const hasZone = state => Boolean(state.selectedZone);
export const hasMachineType = state => Boolean(state.selectedMachineType); export const hasMachineType = state => Boolean(state.selectedMachineType);
export const hasValidData = (state, getters) =>
Boolean(state.projectHasBillingEnabled) && getters.hasZone && getters.hasMachineType;
...@@ -79,6 +79,6 @@ ...@@ -79,6 +79,6 @@
= s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.') = s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.')
= link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank' = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank'
.form-group .form-group.js-gke-cluster-creation-submit-container
= field.submit s_('ClusterIntegration|Create Kubernetes cluster'), = field.submit s_('ClusterIntegration|Create Kubernetes cluster'),
class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true
...@@ -14,6 +14,11 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -14,6 +14,11 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 } allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
end end
def submit_form
execute_script('document.querySelector(".js-gke-cluster-creation-submit").removeAttribute("disabled")')
execute_script('document.querySelector(".js-gke-cluster-creation-submit").click()')
end
context 'when user has signed with Google' do context 'when user has signed with Google' do
let(:project_id) { 'test-project-1234' } let(:project_id) { 'test-project-1234' }
...@@ -34,7 +39,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -34,7 +39,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
end end
context 'when user filled form with valid parameters' do context 'when user filled form with valid parameters' do
subject { click_button 'Create Kubernetes cluster' } subject { submit_form }
before do before do
allow_any_instance_of(GoogleApi::CloudPlatform::Client) allow_any_instance_of(GoogleApi::CloudPlatform::Client)
...@@ -47,8 +52,8 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -47,8 +52,8 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil)
execute_script('document.querySelector(".js-gke-cluster-creation-submit").removeAttribute("disabled")') expect(page).to have_css('.js-gcp-project-id-dropdown')
sleep 2 # wait for ajax
execute_script('document.querySelector(".js-gcp-project-id-dropdown input").setAttribute("type", "text")') execute_script('document.querySelector(".js-gcp-project-id-dropdown input").setAttribute("type", "text")')
execute_script('document.querySelector(".js-gcp-zone-dropdown input").setAttribute("type", "text")') execute_script('document.querySelector(".js-gcp-zone-dropdown input").setAttribute("type", "text")')
execute_script('document.querySelector(".js-gcp-machine-type-dropdown input").setAttribute("type", "text")') execute_script('document.querySelector(".js-gcp-machine-type-dropdown input").setAttribute("type", "text")')
...@@ -86,8 +91,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -86,8 +91,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user filled form with invalid parameters' do context 'when user filled form with invalid parameters' do
before do before do
execute_script('document.querySelector(".js-gke-cluster-creation-submit").removeAttribute("disabled")') submit_form
click_button 'Create Kubernetes cluster'
end end
it 'user sees a validation error' do it 'user sees a validation error' do
......
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import GkeSubmitButton from '~/create_cluster/gke_cluster/components/gke_submit_button.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('GkeSubmitButton', () => {
let wrapper;
let store;
let hasValidData;
const buildStore = () =>
new Vuex.Store({
getters: {
hasValidData,
},
});
const buildWrapper = () =>
shallowMount(GkeSubmitButton, {
store,
localVue,
});
const bootstrap = () => {
store = buildStore();
wrapper = buildWrapper();
};
beforeEach(() => {
hasValidData = jest.fn();
});
afterEach(() => {
wrapper.destroy();
});
it('is disabled when hasValidData is false', () => {
hasValidData.mockReturnValueOnce(false);
bootstrap();
expect(wrapper.attributes('disabled')).toBe('disabled');
});
it('is not disabled when hasValidData is true', () => {
hasValidData.mockReturnValueOnce(true);
bootstrap();
expect(wrapper.attributes('disabled')).toBeFalsy();
});
});
import * as getters from '~/create_cluster/gke_cluster/store/getters'; import {
hasProject,
hasZone,
hasMachineType,
hasValidData,
} from '~/create_cluster/gke_cluster/store/getters';
import { selectedProjectMock, selectedZoneMock, selectedMachineTypeMock } from '../mock_data'; import { selectedProjectMock, selectedZoneMock, selectedMachineTypeMock } from '../mock_data';
describe('GCP Cluster Dropdown Store Getters', () => { describe('GCP Cluster Dropdown Store Getters', () => {
...@@ -7,6 +12,7 @@ describe('GCP Cluster Dropdown Store Getters', () => { ...@@ -7,6 +12,7 @@ describe('GCP Cluster Dropdown Store Getters', () => {
describe('valid states', () => { describe('valid states', () => {
beforeEach(() => { beforeEach(() => {
state = { state = {
projectHasBillingEnabled: true,
selectedProject: selectedProjectMock, selectedProject: selectedProjectMock,
selectedZone: selectedZoneMock, selectedZone: selectedZoneMock,
selectedMachineType: selectedMachineTypeMock, selectedMachineType: selectedMachineTypeMock,
...@@ -15,19 +21,25 @@ describe('GCP Cluster Dropdown Store Getters', () => { ...@@ -15,19 +21,25 @@ describe('GCP Cluster Dropdown Store Getters', () => {
describe('hasProject', () => { describe('hasProject', () => {
it('should return true when project is selected', () => { it('should return true when project is selected', () => {
expect(getters.hasProject(state)).toEqual(true); expect(hasProject(state)).toEqual(true);
}); });
}); });
describe('hasZone', () => { describe('hasZone', () => {
it('should return true when zone is selected', () => { it('should return true when zone is selected', () => {
expect(getters.hasZone(state)).toEqual(true); expect(hasZone(state)).toEqual(true);
}); });
}); });
describe('hasMachineType', () => { describe('hasMachineType', () => {
it('should return true when machine type is selected', () => { it('should return true when machine type is selected', () => {
expect(getters.hasMachineType(state)).toEqual(true); expect(hasMachineType(state)).toEqual(true);
});
});
describe('hasValidData', () => {
it('should return true when a project, zone and machine type are selected', () => {
expect(hasValidData(state, { hasZone: true, hasMachineType: true })).toEqual(true);
}); });
}); });
}); });
...@@ -46,19 +58,45 @@ describe('GCP Cluster Dropdown Store Getters', () => { ...@@ -46,19 +58,45 @@ describe('GCP Cluster Dropdown Store Getters', () => {
describe('hasProject', () => { describe('hasProject', () => {
it('should return false when project is not selected', () => { it('should return false when project is not selected', () => {
expect(getters.hasProject(state)).toEqual(false); expect(hasProject(state)).toEqual(false);
}); });
}); });
describe('hasZone', () => { describe('hasZone', () => {
it('should return false when zone is not selected', () => { it('should return false when zone is not selected', () => {
expect(getters.hasZone(state)).toEqual(false); expect(hasZone(state)).toEqual(false);
}); });
}); });
describe('hasMachineType', () => { describe('hasMachineType', () => {
it('should return false when machine type is not selected', () => { it('should return false when machine type is not selected', () => {
expect(getters.hasMachineType(state)).toEqual(false); expect(hasMachineType(state)).toEqual(false);
});
});
describe('hasValidData', () => {
let getters;
beforeEach(() => {
getters = { hasZone: true, hasMachineType: true };
});
it('should return false when project is not billable', () => {
state.projectHasBillingEnabled = false;
expect(hasValidData(state, getters)).toEqual(false);
});
it('should return false when zone is not selected', () => {
getters.hasZone = false;
expect(hasValidData(state, getters)).toEqual(false);
});
it('should return false when machine type is not selected', () => {
getters.hasMachineType = false;
expect(hasValidData(state, getters)).toEqual(false);
}); });
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment