validate project billing status after selection
This commit is contained in:
parent
2b903eceda
commit
c960fea181
9 changed files with 111 additions and 33 deletions
|
@ -8,14 +8,14 @@ export default {
|
|||
name: 'GkeMachineTypeDropdown',
|
||||
mixins: [gkeDropdownMixin],
|
||||
computed: {
|
||||
...mapState(['selectedProject', 'selectedZone', 'selectedMachineType']),
|
||||
...mapState(['projectHasBillingEnabled', 'selectedZone', 'selectedMachineType']),
|
||||
...mapState({ items: 'machineTypes' }),
|
||||
...mapGetters(['hasProject', 'hasZone', 'hasMachineType']),
|
||||
...mapGetters(['hasZone', 'hasMachineType']),
|
||||
allDropdownsSelected() {
|
||||
return this.hasProject && this.hasZone && this.hasMachineType;
|
||||
return this.projectHasBillingEnabled && this.hasZone && this.hasMachineType;
|
||||
},
|
||||
isDisabled() {
|
||||
return !this.selectedProject || !this.selectedZone;
|
||||
return !this.projectHasBillingEnabled || !this.selectedZone;
|
||||
},
|
||||
toggleText() {
|
||||
if (this.isLoading) {
|
||||
|
@ -26,7 +26,7 @@ export default {
|
|||
return this.selectedMachineType;
|
||||
}
|
||||
|
||||
if (!this.hasProject && !this.hasZone) {
|
||||
if (!this.projectHasBillingEnabled && !this.hasZone) {
|
||||
return s__('ClusterIntegration|Select project and zone to choose machine type');
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,13 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isValidatingProjectBilling: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['selectedProject']),
|
||||
...mapState(['selectedProject', 'projectHasBillingEnabled']),
|
||||
...mapState({ items: 'projects' }),
|
||||
...mapGetters(['hasProject']),
|
||||
hasOneProject() {
|
||||
|
@ -25,6 +30,10 @@ export default {
|
|||
return this.items && this.items.length < 2;
|
||||
},
|
||||
toggleText() {
|
||||
if (this.isValidatingProjectBilling) {
|
||||
return s__('ClusterIntegration|Validating project billing status');
|
||||
}
|
||||
|
||||
if (this.isLoading) {
|
||||
return s__('ClusterIntegration|Fetching projects');
|
||||
}
|
||||
|
@ -42,7 +51,7 @@ export default {
|
|||
helpText() {
|
||||
let message;
|
||||
if (this.hasErrors) {
|
||||
message = this.gapiError;
|
||||
return this.errorMessage;
|
||||
}
|
||||
|
||||
if (!this.items) {
|
||||
|
@ -67,12 +76,45 @@ export default {
|
|||
);
|
||||
},
|
||||
errorMessage() {
|
||||
if (!this.projectHasBillingEnabled) {
|
||||
if (this.gapiError) {
|
||||
return s__(
|
||||
'ClusterIntegration|We could not verify that one of your projects on GCP has billing enabled. Please try again.',
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
s__(
|
||||
'Please <a href=%{linkToBilling} target="_blank" rel="noopener noreferrer">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again.',
|
||||
),
|
||||
{
|
||||
linkToBilling:
|
||||
'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral',
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
s__('ClusterIntegration|An error occured while trying to fetch your projects: %{error}'),
|
||||
{ error: this.gapiError },
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedProject() {
|
||||
this.isLoading = true;
|
||||
this.isValidatingProjectBilling = true;
|
||||
|
||||
this.validateProjectBilling()
|
||||
.then(this.validateProjectBillingSuccessHandler)
|
||||
.catch(this.validateProjectBillingFailureHandler);
|
||||
},
|
||||
projectHasBillingEnabled(billingEnabled) {
|
||||
this.hasErrors = !billingEnabled;
|
||||
this.isValidatingProjectBilling = false;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.isLoading = true;
|
||||
|
||||
|
@ -81,7 +123,7 @@ export default {
|
|||
.catch(this.fetchFailureHandler);
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['fetchProjects']),
|
||||
...mapActions(['fetchProjects', 'validateProjectBilling']),
|
||||
...mapActions({ setItem: 'setProject' }),
|
||||
fetchSuccessHandler() {
|
||||
if (this.defaultValue) {
|
||||
|
@ -97,6 +139,15 @@ export default {
|
|||
this.isLoading = false;
|
||||
this.hasErrors = false;
|
||||
},
|
||||
validateProjectBillingSuccessHandler() {
|
||||
this.isLoading = false;
|
||||
},
|
||||
validateProjectBillingFailureHandler(resp) {
|
||||
this.isLoading = false;
|
||||
this.hasErrors = true;
|
||||
|
||||
this.gapiError = resp.result ? resp.result.error.message : resp;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { sprintf, s__ } from '~/locale';
|
||||
import { mapState, mapGetters, mapActions } from 'vuex';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
|
||||
import gkeDropdownMixin from './gke_dropdown_mixin';
|
||||
|
||||
|
@ -8,11 +8,10 @@ export default {
|
|||
name: 'GkeZoneDropdown',
|
||||
mixins: [gkeDropdownMixin],
|
||||
computed: {
|
||||
...mapState(['selectedProject', 'selectedZone', 'projects']),
|
||||
...mapState(['selectedProject', 'selectedZone', 'projects', 'projectHasBillingEnabled']),
|
||||
...mapState({ items: 'zones' }),
|
||||
...mapGetters(['hasProject']),
|
||||
isDisabled() {
|
||||
return !this.hasProject;
|
||||
return !this.projectHasBillingEnabled;
|
||||
},
|
||||
toggleText() {
|
||||
if (this.isLoading) {
|
||||
|
@ -23,7 +22,7 @@ export default {
|
|||
return this.selectedZone;
|
||||
}
|
||||
|
||||
return !this.hasProject
|
||||
return !this.projectHasBillingEnabled
|
||||
? s__('ClusterIntegration|Select project to choose zone')
|
||||
: s__('ClusterIntegration|Select zone');
|
||||
},
|
||||
|
@ -35,10 +34,11 @@ export default {
|
|||
},
|
||||
},
|
||||
watch: {
|
||||
selectedProject() {
|
||||
projectHasBillingEnabled(billingEnabled) {
|
||||
if (!billingEnabled) return false;
|
||||
this.isLoading = true;
|
||||
|
||||
this.fetchZones()
|
||||
return this.fetchZones()
|
||||
.then(this.fetchSuccessHandler)
|
||||
.catch(this.fetchFailureHandler);
|
||||
},
|
||||
|
|
|
@ -3,6 +3,8 @@ import { s__ } from '~/locale';
|
|||
export const GCP_API_ERROR = s__(
|
||||
'ClusterIntegration|An error occurred when trying to contact the Google Cloud API. Please try again later.',
|
||||
);
|
||||
export const GCP_API_CLOUD_BILLING_ENDPOINT =
|
||||
'https://www.googleapis.com/discovery/v1/apis/cloudbilling/v1/rest';
|
||||
export const GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT =
|
||||
'https://www.googleapis.com/discovery/v1/apis/cloudresourcemanager/v1/rest';
|
||||
export const GCP_API_COMPUTE_ENDPOINT =
|
||||
|
|
|
@ -56,19 +56,20 @@ const gkeDropdownErrorHandler = () => {
|
|||
|
||||
const initializeGapiClient = () => {
|
||||
const el = document.querySelector('.js-gke-cluster-creation');
|
||||
if (!el) return false;
|
||||
|
||||
gapi.client.setToken({ access_token: el.dataset.token });
|
||||
|
||||
gapi.client
|
||||
.load(CONSTANTS.GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT)
|
||||
.then(() => {
|
||||
mountGkeProjectIdDropdown();
|
||||
return gapi.client
|
||||
.init({
|
||||
discoveryDocs: [
|
||||
CONSTANTS.GCP_API_CLOUD_BILLING_ENDPOINT,
|
||||
CONSTANTS.GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT,
|
||||
CONSTANTS.GCP_API_COMPUTE_ENDPOINT,
|
||||
],
|
||||
})
|
||||
.catch(gkeDropdownErrorHandler);
|
||||
|
||||
gapi.client
|
||||
.load(CONSTANTS.GCP_API_COMPUTE_ENDPOINT)
|
||||
.then(() => {
|
||||
gapi.client.setToken({ access_token: el.dataset.token });
|
||||
|
||||
mountGkeProjectIdDropdown();
|
||||
mountGkeZoneDropdown();
|
||||
mountGkeMachineTypeDropdown();
|
||||
})
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* global gapi */
|
||||
import * as types from './mutation_types';
|
||||
|
||||
const gapiRequest = ({ service, params, commit, mutation, payloadKey }) =>
|
||||
const gapiResourceListRequest = ({ resource, params, commit, mutation, payloadKey }) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const request = service.list(params);
|
||||
const request = resource.list(params);
|
||||
|
||||
return request.then(
|
||||
resp => {
|
||||
|
@ -32,17 +32,36 @@ export const setMachineType = ({ commit }, selectedMachineType) => {
|
|||
};
|
||||
|
||||
export const fetchProjects = ({ commit }) =>
|
||||
gapiRequest({
|
||||
service: gapi.client.cloudresourcemanager.projects,
|
||||
gapiResourceListRequest({
|
||||
resource: gapi.client.cloudresourcemanager.projects,
|
||||
params: {},
|
||||
commit,
|
||||
mutation: types.SET_PROJECTS,
|
||||
payloadKey: 'projects',
|
||||
});
|
||||
|
||||
export const validateProjectBilling = ({ commit, state }) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const request = gapi.client.cloudbilling.projects.getBillingInfo({
|
||||
name: `projects/${state.selectedProject.projectId}`,
|
||||
});
|
||||
|
||||
return request.then(
|
||||
resp => {
|
||||
const { billingEnabled } = resp.result;
|
||||
|
||||
commit(types.SET_PROJECT_BILLING_STATUS, !!billingEnabled);
|
||||
resolve();
|
||||
},
|
||||
resp => {
|
||||
reject(resp);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
export const fetchZones = ({ commit, state }) =>
|
||||
gapiRequest({
|
||||
service: gapi.client.compute.zones,
|
||||
gapiResourceListRequest({
|
||||
resource: gapi.client.compute.zones,
|
||||
params: {
|
||||
project: state.selectedProject.projectId,
|
||||
},
|
||||
|
@ -52,8 +71,8 @@ export const fetchZones = ({ commit, state }) =>
|
|||
});
|
||||
|
||||
export const fetchMachineTypes = ({ commit, state }) =>
|
||||
gapiRequest({
|
||||
service: gapi.client.compute.machineTypes,
|
||||
gapiResourceListRequest({
|
||||
resource: gapi.client.compute.machineTypes,
|
||||
params: {
|
||||
project: state.selectedProject.projectId,
|
||||
zone: state.selectedZone,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export const SET_PROJECT = 'SET_PROJECT';
|
||||
export const SET_PROJECT_BILLING_STATUS = 'SET_PROJECT_BILLING_STATUS';
|
||||
export const SET_ZONE = 'SET_ZONE';
|
||||
export const SET_MACHINE_TYPE = 'SET_MACHINE_TYPE';
|
||||
export const SET_PROJECTS = 'SET_PROJECTS';
|
||||
|
|
|
@ -4,6 +4,9 @@ export default {
|
|||
[types.SET_PROJECT](state, selectedProject) {
|
||||
Object.assign(state, { selectedProject });
|
||||
},
|
||||
[types.SET_PROJECT_BILLING_STATUS](state, projectHasBillingEnabled) {
|
||||
Object.assign(state, { projectHasBillingEnabled });
|
||||
},
|
||||
[types.SET_ZONE](state, selectedZone) {
|
||||
Object.assign(state, { selectedZone });
|
||||
},
|
||||
|
|
|
@ -5,6 +5,7 @@ export default {
|
|||
},
|
||||
selectedZone: '',
|
||||
selectedMachineType: '',
|
||||
projectHasBillingEnabled: null,
|
||||
projects: [],
|
||||
zones: [],
|
||||
machineTypes: [],
|
||||
|
|
Loading…
Reference in a new issue