Commit 1e4c2a2e authored by Dennis Tang's avatar Dennis Tang

complete vuex implementation + refactoring

parent 41f2c1d5
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import Flash from '~/flash'; import { s__ } from '~/locale';
import { s__, sprintf } from '~/locale';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import LoadingIcon from '~/vue_shared/components/loading_icon.vue'; import LoadingIcon from '~/vue_shared/components/loading_icon.vue';
...@@ -23,10 +22,6 @@ export default { ...@@ -23,10 +22,6 @@ export default {
DropdownHiddenInput, DropdownHiddenInput,
}, },
props: { props: {
service: {
type: Object,
required: true,
},
fieldId: { fieldId: {
type: String, type: String,
required: true, required: true,
...@@ -35,7 +30,7 @@ export default { ...@@ -35,7 +30,7 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
inputValue: { defaultValue: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -46,17 +41,19 @@ export default { ...@@ -46,17 +41,19 @@ export default {
isLoading: false, isLoading: false,
hasErrors: false, hasErrors: false,
searchQuery: '', searchQuery: '',
items: [],
}; };
}, },
computed: { computed: {
...mapState(['selectedProject', 'selectedZone', 'selectedMachineType']), ...mapState(['selectedProject', 'selectedZone', 'selectedMachineType']),
...mapGetters(['hasProject', 'hasZone']), ...mapState({ machineTypes: 'fetchedMachineTypes' }),
...mapGetters(['hasProject', 'hasZone', 'hasMachineType']),
isDisabled() { isDisabled() {
return !this.selectedProject || !this.selectedZone; return !this.selectedProject || !this.selectedZone;
}, },
searchResults() { searchResults() {
return this.items.filter(item => item.name.toLowerCase().indexOf(this.searchQuery) > -1); return this.machineTypes.filter(
item => item.name.toLowerCase().indexOf(this.searchQuery) > -1,
);
}, },
toggleText() { toggleText() {
if (this.isLoading) { if (this.isLoading) {
...@@ -75,54 +72,44 @@ export default { ...@@ -75,54 +72,44 @@ export default {
? s__('ClusterIntegration|Select machine type') ? s__('ClusterIntegration|Select machine type')
: s__('ClusterIntegration|Select zone to choose machine type'); : s__('ClusterIntegration|Select zone to choose machine type');
}, },
placeholderText() { searchPlaceholderText() {
return s__('ClusterIntegration|Search machine types'); return s__('ClusterIntegration|Search machine types');
}, },
}, },
created() { created() {
eventHub.$on('zoneSelected', this.fetchItems); eventHub.$on('zoneSelected', this.fetchMachineTypes);
eventHub.$on('machineTypeSelected', this.enableSubmit); eventHub.$on('machineTypeSelected', this.enableSubmit);
}, },
methods: { methods: {
...mapActions(['setMachineType']), ...mapActions(['setMachineType', 'getMachineTypes']),
fetchItems() { fetchMachineTypes() {
this.isLoading = true; this.isLoading = true;
const request = this.service.machineTypes.list({
project: this.selectedProject.projectId,
zone: this.selectedZone,
});
return request.then( this.getMachineTypes()
resp => { .then(() => {
let machineTypeToSelect; if (this.defaultValue) {
this.items = resp.result.items; const machineTypeToSelect = _.find(
this.machineTypes,
item => item.name === this.defaultValue,
);
if (this.inputValue) { if (machineTypeToSelect) {
machineTypeToSelect = _.find(this.items, item => item.name === this.inputValue); this.setMachineType(machineTypeToSelect.name);
this.setMachineType(machineTypeToSelect.name); }
} }
this.isLoading = false; this.isLoading = false;
this.hasErrors = false; this.hasErrors = false;
}, })
() => { .catch(() => {
this.isLoading = false; this.isLoading = false;
this.hasErrors = true; this.hasErrors = true;
});
if (resp.result.error) {
Flash(
sprintf(
'ClusterIntegration|An error occured while trying to fetch zone machine types: %{error}',
{ error: resp.result.error.message },
),
);
}
},
this,
);
}, },
enableSubmit() { enableSubmit() {
document.querySelector('.js-gke-cluster-creation-submit').removeAttribute('disabled'); if (this.hasProject && this.hasZone && this.hasMachineType) {
document.querySelector('.js-gke-cluster-creation-submit').removeAttribute('disabled');
}
}, },
}, },
}; };
...@@ -146,7 +133,7 @@ export default { ...@@ -146,7 +133,7 @@ export default {
<div class="dropdown-menu dropdown-select"> <div class="dropdown-menu dropdown-select">
<dropdown-search-input <dropdown-search-input
v-model="searchQuery" v-model="searchQuery"
:placeholder-text="placeholderText" :placeholder-text="searchPlaceholderText"
/> />
<div class="dropdown-content"> <div class="dropdown-content">
<ul> <ul>
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import Flash from '~/flash';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
...@@ -10,7 +9,6 @@ import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidde ...@@ -10,7 +9,6 @@ import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidde
import store from '../stores'; import store from '../stores';
import DropdownButton from './dropdown_button.vue'; import DropdownButton from './dropdown_button.vue';
// TODO: Consolidate dropdown code
export default { export default {
name: 'GkeProjectIdDropdown', name: 'GkeProjectIdDropdown',
...@@ -27,10 +25,6 @@ export default { ...@@ -27,10 +25,6 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
service: {
type: Object,
required: true,
},
fieldId: { fieldId: {
type: String, type: String,
required: true, required: true,
...@@ -39,7 +33,7 @@ export default { ...@@ -39,7 +33,7 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
inputValue: { defaultValue: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -50,20 +44,20 @@ export default { ...@@ -50,20 +44,20 @@ export default {
isLoading: true, isLoading: true,
hasErrors: false, hasErrors: false,
searchQuery: '', searchQuery: '',
items: [],
}; };
}, },
computed: { computed: {
...mapState(['selectedProject']), ...mapState(['selectedProject']),
...mapState({ projects: 'fetchedProjects' }),
...mapGetters(['hasProject']), ...mapGetters(['hasProject']),
hasOneProject() { hasOneProject() {
return this.items.length === 1; return this.projects.length === 1;
}, },
isDisabled() { isDisabled() {
return this.items.length < 2; return this.projects.length < 2;
}, },
searchResults() { searchResults() {
return this.items.filter(item => item.name.toLowerCase().indexOf(this.searchQuery) > -1); return this.projects.filter(item => item.name.toLowerCase().indexOf(this.searchQuery) > -1);
}, },
toggleText() { toggleText() {
if (this.isLoading) { if (this.isLoading) {
...@@ -74,11 +68,11 @@ export default { ...@@ -74,11 +68,11 @@ export default {
return this.selectedProject.name; return this.selectedProject.name;
} }
return this.items.length return this.projects.length
? s__('ClusterIntegration|Select project') ? s__('ClusterIntegration|Select project')
: s__('ClusterIntegration|No projects found'); : s__('ClusterIntegration|No projects found');
}, },
placeholderText() { searchPlaceholderText() {
return s__('ClusterIntegration|Search projects'); return s__('ClusterIntegration|Search projects');
}, },
helpText() { helpText() {
...@@ -88,7 +82,7 @@ export default { ...@@ -88,7 +82,7 @@ export default {
'ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.'; 'ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.';
} }
message = this.items.length message = this.projects.length
? 'ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.' ? 'ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.'
: 'ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.'; : 'ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.';
...@@ -105,46 +99,33 @@ export default { ...@@ -105,46 +99,33 @@ export default {
}, },
}, },
created() { created() {
this.fetchItems(); this.fetchProjects();
}, },
methods: { methods: {
...mapActions(['setProject']), ...mapActions(['setProject', 'getProjects']),
fetchItems() { fetchProjects() {
const request = this.service.projects.list(); this.getProjects()
.then(() => {
return request.then( if (this.defaultValue) {
resp => { const projectToSelect = _.find(
let projectToSelect; this.projects,
this.items = resp.result.projects; item => item.projectId === this.defaultValue,
);
if (this.inputValue) { if (projectToSelect) {
projectToSelect = _.find(this.items, item => item.projectId === this.inputValue); this.setProject(projectToSelect);
this.setProject(projectToSelect); }
} else if (this.items.length === 1) { } else if (this.projects.length === 1) {
projectToSelect = this.items[0]; this.setProject(this.projects[0]);
this.setProject(projectToSelect);
} }
this.isLoading = false; this.isLoading = false;
this.hasErrors = false; this.hasErrors = false;
}, })
resp => { .catch(() => {
if (resp.result.error) {
Flash(
sprintf(
'ClusterIntegration|An error occured while trying to fetch your projects: %{error}',
{
error: resp.result.error.message,
},
),
);
}
this.isLoading = false; this.isLoading = false;
this.hasErrors = true; this.hasErrors = true;
}, });
this,
);
}, },
}, },
}; };
...@@ -161,7 +142,10 @@ export default { ...@@ -161,7 +142,10 @@ export default {
:value="selectedProject.projectId" :value="selectedProject.projectId"
/> />
<dropdown-button <dropdown-button
:class="{ 'gl-field-error-outline': hasErrors, 'read-only': hasOneProject }" :class="{
'gl-field-error-outline': hasErrors,
'read-only': hasOneProject
}"
:is-disabled="isDisabled" :is-disabled="isDisabled"
:is-loading="isLoading" :is-loading="isLoading"
:toggle-text="toggleText" :toggle-text="toggleText"
...@@ -169,7 +153,7 @@ export default { ...@@ -169,7 +153,7 @@ export default {
<div class="dropdown-menu dropdown-select"> <div class="dropdown-menu dropdown-select">
<dropdown-search-input <dropdown-search-input
v-model="searchQuery" v-model="searchQuery"
:placeholder-text="placeholderText" :placeholder-text="searchPlaceholderText"
/> />
<div class="dropdown-content"> <div class="dropdown-content">
<ul> <ul>
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import Flash from '~/flash'; import { s__ } from '~/locale';
import { s__, sprintf } from '~/locale';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import LoadingIcon from '~/vue_shared/components/loading_icon.vue'; import LoadingIcon from '~/vue_shared/components/loading_icon.vue';
...@@ -23,10 +22,6 @@ export default { ...@@ -23,10 +22,6 @@ export default {
DropdownHiddenInput, DropdownHiddenInput,
}, },
props: { props: {
service: {
type: Object,
required: true,
},
fieldId: { fieldId: {
type: String, type: String,
required: true, required: true,
...@@ -35,7 +30,7 @@ export default { ...@@ -35,7 +30,7 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
inputValue: { defaultValue: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -46,17 +41,17 @@ export default { ...@@ -46,17 +41,17 @@ export default {
isLoading: false, isLoading: false,
hasErrors: false, hasErrors: false,
searchQuery: '', searchQuery: '',
items: [],
}; };
}, },
computed: { computed: {
...mapState(['selectedProject', 'selectedZone']), ...mapState(['selectedProject', 'selectedZone']),
...mapState({ zones: 'fetchedZones' }),
...mapGetters(['hasProject']), ...mapGetters(['hasProject']),
isDisabled() { isDisabled() {
return !this.hasProject; return !this.hasProject;
}, },
searchResults() { searchResults() {
return this.items.filter(item => item.name.toLowerCase().indexOf(this.searchQuery) > -1); return this.zones.filter(item => item.name.toLowerCase().indexOf(this.searchQuery) > -1);
}, },
toggleText() { toggleText() {
if (this.isLoading) { if (this.isLoading) {
...@@ -71,49 +66,35 @@ export default { ...@@ -71,49 +66,35 @@ export default {
? s__('ClusterIntegration|Select zone') ? s__('ClusterIntegration|Select zone')
: s__('ClusterIntegration|Select project to choose zone'); : s__('ClusterIntegration|Select project to choose zone');
}, },
placeholderText() { searchPlaceholderText() {
return s__('ClusterIntegration|Search zones'); return s__('ClusterIntegration|Search zones');
}, },
}, },
created() { created() {
eventHub.$on('projectSelected', this.fetchItems); eventHub.$on('projectSelected', this.fetchZones);
}, },
methods: { methods: {
...mapActions(['setZone']), ...mapActions(['setZone', 'getZones']),
fetchItems() { fetchZones() {
this.isLoading = true; this.isLoading = true;
const request = this.service.zones.list({
project: this.selectedProject.projectId,
});
return request.then( this.getZones()
resp => { .then(() => {
let zoneToSelect; if (this.defaultValue) {
this.items = resp.result.items; const zoneToSelect = _.find(this.zones, item => item.name === this.defaultValue);
if (this.inputValue) { if (zoneToSelect) {
zoneToSelect = _.find(this.items, item => item.name === this.inputValue); this.setZone(zoneToSelect.name);
this.setZone(zoneToSelect.name); }
} }
this.isLoading = false; this.isLoading = false;
this.hasErrors = false; this.hasErrors = false;
}, })
resp => { .catch(() => {
this.isLoading = false; this.isLoading = false;
this.hasErrors = true; this.hasErrors = true;
});
if (resp.result.error) {
Flash(
sprintf(
'ClusterIntegration|An error occured while trying to fetch project zones: %{error}',
{ error: resp.result.error.message },
),
);
}
},
this,
);
}, },
}, },
}; };
...@@ -137,7 +118,7 @@ export default { ...@@ -137,7 +118,7 @@ export default {
<div class="dropdown-menu dropdown-select"> <div class="dropdown-menu dropdown-select">
<dropdown-search-input <dropdown-search-input
v-model="searchQuery" v-model="searchQuery"
:placeholder-text="placeholderText" :placeholder-text="searchPlaceholderText"
/> />
<div class="dropdown-content"> <div class="dropdown-content">
<ul> <ul>
......
...@@ -21,10 +21,9 @@ const mountGkeProjectIdDropdown = () => { ...@@ -21,10 +21,9 @@ const mountGkeProjectIdDropdown = () => {
createElement('gke-project-id-dropdown', { createElement('gke-project-id-dropdown', {
props: { props: {
docsUrl: el.dataset.docsurl, docsUrl: el.dataset.docsurl,
service: gapi.client.cloudresourcemanager,
fieldName: hiddenInput.getAttribute('name'), fieldName: hiddenInput.getAttribute('name'),
fieldId: hiddenInput.getAttribute('id'), fieldId: hiddenInput.getAttribute('id'),
inputValue: hiddenInput.value, defaultValue: hiddenInput.value,
}, },
}), }),
}); });
...@@ -44,10 +43,9 @@ const mountGkeZoneDropdown = () => { ...@@ -44,10 +43,9 @@ const mountGkeZoneDropdown = () => {
render: createElement => render: createElement =>
createElement('gke-zone-dropdown', { createElement('gke-zone-dropdown', {
props: { props: {
service: gapi.client.compute,
fieldName: hiddenInput.getAttribute('name'), fieldName: hiddenInput.getAttribute('name'),
fieldId: hiddenInput.getAttribute('id'), fieldId: hiddenInput.getAttribute('id'),
inputValue: hiddenInput.value, defaultValue: hiddenInput.value,
}, },
}), }),
}); });
...@@ -67,10 +65,9 @@ const mountGkeMachineTypeDropdown = () => { ...@@ -67,10 +65,9 @@ const mountGkeMachineTypeDropdown = () => {
render: createElement => render: createElement =>
createElement('gke-machine-type-dropdown', { createElement('gke-machine-type-dropdown', {
props: { props: {
service: gapi.client.compute,
fieldName: hiddenInput.getAttribute('name'), fieldName: hiddenInput.getAttribute('name'),
fieldId: hiddenInput.getAttribute('id'), fieldId: hiddenInput.getAttribute('id'),
inputValue: hiddenInput.value, defaultValue: hiddenInput.value,
}, },
}), }),
}); });
......
/* global gapi */
import Flash from '~/flash';
import { sprintf } from '~/locale';
import * as types from './mutation_types'; import * as types from './mutation_types';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
...@@ -18,3 +22,85 @@ export const setMachineType = ({ commit }, selectedMachineType) => { ...@@ -18,3 +22,85 @@ export const setMachineType = ({ commit }, selectedMachineType) => {
eventHub.$emit('machineTypeSelected'); eventHub.$emit('machineTypeSelected');
}; };
export const getProjects = ({ commit }) =>
new Promise((resolve, reject) => {
const request = gapi.client.cloudresourcemanager.projects.list();
return request.then(
resp => {
commit(types.SET_FETCHED_PROJECTS, resp.result.projects);
resolve();
},
resp => {
if (resp.result.error) {
Flash(
sprintf(
'ClusterIntegration|An error occured while trying to fetch your projects: %{error}',
{
error: resp.result.error.message,
},
),
);
}
reject();
},
);
});
export const getZones = ({ commit, state }) =>
new Promise((resolve, reject) => {
const request = gapi.client.compute.zones.list({
project: state.selectedProject.projectId,
});
return request.then(
resp => {
commit(types.SET_FETCHED_ZONES, resp.result.items);
resolve();
},
resp => {
if (resp.result.error) {
Flash(
sprintf(
'ClusterIntegration|An error occured while trying to fetch project zones: %{error}',
{ error: resp.result.error.message },
),
);
}
reject();
},
);
});
export const getMachineTypes = ({ commit, state }) =>
new Promise((resolve, reject) => {
const request = gapi.client.compute.machineTypes.list({
project: state.selectedProject.projectId,
zone: state.selectedZone,
});
return request.then(
resp => {
commit(types.SET_FETCHED_MACHINE_TYPES, resp.result.items);
resolve();
},
resp => {
if (resp.result.error) {
Flash(
sprintf(
'ClusterIntegration|An error occured while trying to fetch zone machine types: %{error}',
{ error: resp.result.error.message },
),
);
}
reject();
},
);
});
...@@ -17,5 +17,8 @@ export default new Vuex.Store({ ...@@ -17,5 +17,8 @@ export default new Vuex.Store({
}, },
selectedZone: '', selectedZone: '',
selectedMachineType: '', selectedMachineType: '',
fetchedProjects: [],
fetchedZones: [],
fetchedMachineTypes: [],
}, },
}); });
export const SET_PROJECT = 'SET_PROJECT'; export const SET_PROJECT = 'SET_PROJECT';
export const SET_ZONE = 'SET_ZONE'; export const SET_ZONE = 'SET_ZONE';
export const SET_MACHINE_TYPE = 'SET_MACHINE_TYPE'; export const SET_MACHINE_TYPE = 'SET_MACHINE_TYPE';
export const SET_FETCHED_PROJECTS = 'SET_FETCHED_PROJECTS';
export const SET_FETCHED_ZONES = 'SET_FETCHED_ZONES';
export const SET_FETCHED_MACHINE_TYPES = 'SET_FETCHED_MACHINE_TYPES';
...@@ -10,4 +10,13 @@ export default { ...@@ -10,4 +10,13 @@ export default {
[types.SET_MACHINE_TYPE](state, selectedMachineType) { [types.SET_MACHINE_TYPE](state, selectedMachineType) {
Object.assign(state, { selectedMachineType }); Object.assign(state, { selectedMachineType });
}, },
[types.SET_FETCHED_PROJECTS](state, fetchedProjects) {
Object.assign(state, { fetchedProjects });
},
[types.SET_FETCHED_ZONES](state, fetchedZones) {
Object.assign(state, { fetchedZones });
},
[types.SET_FETCHED_MACHINE_TYPES](state, fetchedMachineTypes) {
Object.assign(state, { fetchedMachineTypes });
},
}; };
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