diff options
Diffstat (limited to 'app/assets/javascripts')
59 files changed, 91 insertions, 2619 deletions
diff --git a/app/assets/javascripts/clusters/components/new_cluster.vue b/app/assets/javascripts/clusters/components/new_cluster.vue index 8f3e2916270..41a33a8459f 100644 --- a/app/assets/javascripts/clusters/components/new_cluster.vue +++ b/app/assets/javascripts/clusters/components/new_cluster.vue @@ -1,6 +1,6 @@ <script> import { GlLink, GlSprintf } from '@gitlab/ui'; -import { mapState } from 'vuex'; +import { helpPagePath } from '~/helpers/help_page_helper'; import { s__ } from '~/locale'; export default { @@ -10,13 +10,11 @@ export default { 'ClusterIntegration|Enter details about your cluster. %{linkStart}How do I use a certificate to connect to my cluster?%{linkEnd}', ), }, + clusterConnectHelpPath: helpPagePath('user/project/clusters/add_existing_cluster'), components: { GlLink, GlSprintf, }, - computed: { - ...mapState(['clusterConnectHelpPath']), - }, }; </script> @@ -26,7 +24,7 @@ export default { <p> <gl-sprintf :message="$options.i18n.information"> <template #link="{ content }"> - <gl-link :href="clusterConnectHelpPath" target="_blank">{{ content }}</gl-link> + <gl-link :href="$options.clusterConnectHelpPath">{{ content }}</gl-link> </template> </gl-sprintf> </p> diff --git a/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue b/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue index 98db620e3ab..dca89133931 100644 --- a/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue +++ b/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue @@ -159,7 +159,7 @@ export default { ) }}</span> <template #modal-footer> - <gl-button variant="secondary" @click="handleCancel">{{ __('Cancel') }}</gl-button> + <gl-button @click="handleCancel">{{ __('Cancel') }}</gl-button> <template v-if="confirmCleanup"> <gl-button :disabled="!canSubmit" diff --git a/app/assets/javascripts/create_cluster/gke_cluster_namespace/index.js b/app/assets/javascripts/clusters/gke_cluster_namespace/index.js index 2b3dfb99328..2b3dfb99328 100644 --- a/app/assets/javascripts/create_cluster/gke_cluster_namespace/index.js +++ b/app/assets/javascripts/clusters/gke_cluster_namespace/index.js diff --git a/app/assets/javascripts/clusters/new_cluster.js b/app/assets/javascripts/clusters/new_cluster.js index 71f585fd307..4df6872bcc1 100644 --- a/app/assets/javascripts/clusters/new_cluster.js +++ b/app/assets/javascripts/clusters/new_cluster.js @@ -1,17 +1,15 @@ import Vue from 'vue'; import NewCluster from './components/new_cluster.vue'; -import { createStore } from './stores/new_cluster'; export default () => { - const entryPoint = document.querySelector('#js-cluster-new'); + const el = document.querySelector('#js-cluster-new'); - if (!entryPoint) { + if (!el) { return null; } return new Vue({ - el: '#js-cluster-new', - store: createStore(entryPoint.dataset), + el, render(createElement) { return createElement(NewCluster); }, diff --git a/app/assets/javascripts/clusters/stores/new_cluster/index.js b/app/assets/javascripts/clusters/stores/new_cluster/index.js deleted file mode 100644 index 87f1c05fdf9..00000000000 --- a/app/assets/javascripts/clusters/stores/new_cluster/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import state from './state'; - -Vue.use(Vuex); - -export const createStore = (initialState) => - new Vuex.Store({ - state: state(initialState), - }); - -export default createStore; diff --git a/app/assets/javascripts/clusters/stores/new_cluster/state.js b/app/assets/javascripts/clusters/stores/new_cluster/state.js deleted file mode 100644 index 1ca1ac8de18..00000000000 --- a/app/assets/javascripts/clusters/stores/new_cluster/state.js +++ /dev/null @@ -1,3 +0,0 @@ -export default (initialState = {}) => ({ - clusterConnectHelpPath: initialState.clusterConnectHelpPath, -}); diff --git a/app/assets/javascripts/clusters_list/components/clusters_actions.vue b/app/assets/javascripts/clusters_list/components/clusters_actions.vue index 8fd759bd3e9..2675d46dd16 100644 --- a/app/assets/javascripts/clusters_list/components/clusters_actions.vue +++ b/app/assets/javascripts/clusters_list/components/clusters_actions.vue @@ -1,5 +1,5 @@ <script> -import { GlDropdown, GlDropdownItem, GlModalDirective, GlTooltip } from '@gitlab/ui'; +import { GlButton, GlDropdown, GlDropdownItem, GlModalDirective, GlTooltip } from '@gitlab/ui'; import { INSTALL_AGENT_MODAL_ID, CLUSTERS_ACTIONS } from '../constants'; @@ -7,6 +7,7 @@ export default { i18n: CLUSTERS_ACTIONS, INSTALL_AGENT_MODAL_ID, components: { + GlButton, GlDropdown, GlDropdownItem, GlTooltip, @@ -15,7 +16,6 @@ export default { GlModalDirective, }, inject: [ - 'newClusterPath', 'addClusterPath', 'newClusterDocsPath', 'canAddCluster', @@ -42,20 +42,59 @@ export default { } return this.addClusterPath; }, + actionItems() { + const createCluster = { + href: this.newClusterDocsPath, + title: this.$options.i18n.createCluster, + testid: 'create-cluster-link', + }; + const connectCluster = { + href: this.addClusterPath, + title: this.$options.i18n.connectClusterCertificate, + testid: 'connect-cluster-link', + }; + const actions = []; + + if (this.displayClusterAgents) { + actions.push(createCluster); + } + if (this.displayClusterAgents && this.certificateBasedClustersEnabled) { + actions.push(connectCluster); + } + + return actions; + }, + }, + methods: { + getTooltipTarget() { + return this.actionItems.length ? this.$refs.actions.$el : this.$refs.actionsContainer; + }, }, }; </script> <template> - <div class="nav-controls gl-ml-auto"> + <div ref="actionsContainer" class="nav-controls gl-ml-auto"> <gl-tooltip v-if="!canAddCluster" - :target="() => $refs.dropdown.$el" - :title="$options.i18n.dropdownDisabledHint" + :target="() => getTooltipTarget()" + :title="$options.i18n.actionsDisabledHint" /> + <gl-button + v-if="!actionItems.length" + data-qa-selector="clusters_actions_button" + category="primary" + variant="confirm" + :disabled="!canAddCluster" + :href="defaultActionUrl" + > + {{ defaultActionText }} + </gl-button> + <gl-dropdown - ref="dropdown" + v-else + ref="actions" v-gl-modal-directive="shouldTriggerModal && $options.INSTALL_AGENT_MODAL_ID" data-qa-selector="clusters_actions_button" category="primary" @@ -67,31 +106,13 @@ export default { right > <gl-dropdown-item - v-if="displayClusterAgents" - :href="newClusterDocsPath" - data-testid="create-cluster-link" - @click.stop - > - {{ $options.i18n.createCluster }} - </gl-dropdown-item> - - <template v-if="displayClusterAgents && certificateBasedClustersEnabled"> - <gl-dropdown-item :href="newClusterPath" data-testid="new-cluster-link" @click.stop> - {{ $options.i18n.createClusterCertificate }} - </gl-dropdown-item> - - <gl-dropdown-item :href="addClusterPath" data-testid="connect-cluster-link" @click.stop> - {{ $options.i18n.connectClusterCertificate }} - </gl-dropdown-item> - </template> - - <gl-dropdown-item - v-if="certificateBasedClustersEnabled && !displayClusterAgents" - :href="newClusterPath" - data-testid="new-cluster-link" + v-for="action in actionItems" + :key="action.title" + :href="action.href" + :data-testid="action.testid" @click.stop > - {{ $options.i18n.createClusterDeprecated }} + {{ action.title }} </gl-dropdown-item> </gl-dropdown> </div> diff --git a/app/assets/javascripts/clusters_list/constants.js b/app/assets/javascripts/clusters_list/constants.js index 4a168e811aa..10e71513065 100644 --- a/app/assets/javascripts/clusters_list/constants.js +++ b/app/assets/javascripts/clusters_list/constants.js @@ -234,11 +234,9 @@ export const CLUSTERS_ACTIONS = { connectCluster: s__('ClusterAgents|Connect a cluster'), connectWithAgent: s__('ClusterAgents|Connect a cluster (agent)'), connectClusterDeprecated: s__('ClusterAgents|Connect a cluster (deprecated)'), - createClusterDeprecated: s__('ClusterAgents|Create a cluster (deprecated)'), createCluster: s__('ClusterAgents|Create a cluster'), - createClusterCertificate: s__('ClusterAgents|Create a cluster (certificate - deprecated)'), connectClusterCertificate: s__('ClusterAgents|Connect a cluster (certificate - deprecated)'), - dropdownDisabledHint: s__( + actionsDisabledHint: s__( 'ClusterAgents|Requires a Maintainer or greater role to perform these actions', ), }; diff --git a/app/assets/javascripts/clusters_list/index.js b/app/assets/javascripts/clusters_list/index.js index f6dfb96ffd9..3d6890c419a 100644 --- a/app/assets/javascripts/clusters_list/index.js +++ b/app/assets/javascripts/clusters_list/index.js @@ -23,7 +23,6 @@ export default () => { defaultBranchName, projectPath, kasAddress, - newClusterPath, addClusterPath, newClusterDocsPath, emptyStateHelpText, @@ -42,7 +41,6 @@ export default () => { emptyStateImage, projectPath, kasAddress, - newClusterPath, addClusterPath, newClusterDocsPath, emptyStateHelpText, diff --git a/app/assets/javascripts/create_cluster/components/cluster_form_dropdown.vue b/app/assets/javascripts/create_cluster/components/cluster_form_dropdown.vue deleted file mode 100644 index fa0a17f3643..00000000000 --- a/app/assets/javascripts/create_cluster/components/cluster_form_dropdown.vue +++ /dev/null @@ -1,246 +0,0 @@ -<script> -import { GlIcon } from '@gitlab/ui'; -import $ from 'jquery'; -import { isNil } from 'lodash'; -import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; -import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; -import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue'; - -const toArray = (value) => (isNil(value) ? [] : [].concat(value)); -const itemsProp = (items, prop) => items.map((item) => item[prop]); -const defaultSearchFn = (searchQuery, labelProp) => (item) => - item[labelProp].toLowerCase().indexOf(searchQuery) > -1; - -export default { - components: { - DropdownButton, - DropdownSearchInput, - DropdownHiddenInput, - GlIcon, - }, - props: { - fieldName: { - type: String, - required: false, - default: '', - }, - placeholder: { - type: String, - required: false, - default: '', - }, - defaultValue: { - type: String, - required: false, - default: '', - }, - value: { - type: [Object, Array, String], - required: false, - default: () => null, - }, - labelProperty: { - type: String, - required: false, - default: 'name', - }, - valueProperty: { - type: String, - required: false, - default: 'value', - }, - items: { - type: Array, - required: false, - default: () => [], - }, - loading: { - type: Boolean, - required: false, - default: false, - }, - disabled: { - type: Boolean, - required: false, - default: false, - }, - loadingText: { - type: String, - required: false, - default: '', - }, - disabledText: { - type: String, - required: false, - default: '', - }, - hasErrors: { - type: Boolean, - required: false, - default: false, - }, - multiple: { - type: Boolean, - required: false, - default: false, - }, - errorMessage: { - type: String, - required: false, - default: '', - }, - searchFieldPlaceholder: { - type: String, - required: false, - default: '', - }, - emptyText: { - type: String, - required: false, - default: '', - }, - searchFn: { - type: Function, - required: false, - default: defaultSearchFn, - }, - }, - data() { - return { - searchQuery: '', - focusOnSearch: false, - }; - }, - computed: { - toggleText() { - if (this.loading && this.loadingText) { - return this.loadingText; - } - - if (this.disabled && this.disabledText) { - return this.disabledText; - } - - if (!this.selectedItems.length) { - return this.placeholder; - } - - return this.selectedItemsLabels; - }, - results() { - return this.getItemsOrEmptyList().filter(this.searchFn(this.searchQuery, this.labelProperty)); - }, - selectedItems() { - const valueProp = this.valueProperty; - const valueList = toArray(this.value); - const items = this.getItemsOrEmptyList(); - - return items.filter((item) => valueList.some((value) => item[valueProp] === value)); - }, - selectedItemsLabels() { - return itemsProp(this.selectedItems, this.labelProperty).join(', '); - }, - selectedItemsValues() { - return itemsProp(this.selectedItems, this.valueProperty).join(', '); - }, - }, - mounted() { - $(this.$refs.dropdown) - .on('shown.bs.dropdown', () => { - this.focusOnSearch = true; - }) - .on('hidden.bs.dropdown', () => { - this.focusOnSearch = false; - }); - }, - beforeDestroy() { - // eslint-disable-next-line @gitlab/no-global-event-off - $(this.$refs.dropdown).off(); - }, - methods: { - getItemsOrEmptyList() { - return this.items || []; - }, - selectSingle(item) { - this.$emit('input', item[this.valueProperty]); - }, - selectMultiple(item) { - const value = toArray(this.value); - const itemValue = item[this.valueProperty]; - const itemValueIndex = value.indexOf(itemValue); - - if (itemValueIndex > -1) { - value.splice(itemValueIndex, 1); - } else { - value.push(itemValue); - } - - this.$emit('input', value); - }, - isSelected(item) { - return this.selectedItems.includes(item); - }, - }, -}; -</script> - -<template> - <div> - <div ref="dropdown" class="dropdown"> - <dropdown-hidden-input :name="fieldName" :value="selectedItemsValues" /> - <dropdown-button - :class="{ 'border-danger': hasErrors }" - :is-disabled="disabled" - :is-loading="loading" - :toggle-text="toggleText" - /> - <div class="dropdown-menu dropdown-select"> - <dropdown-search-input - v-model="searchQuery" - :focused="focusOnSearch" - :placeholder-text="searchFieldPlaceholder" - /> - <div class="dropdown-content"> - <ul> - <li v-if="!results.length"> - <span class="js-empty-text menu-item">{{ emptyText }}</span> - </li> - <li v-for="item in results" :key="item.id"> - <button - v-if="multiple" - class="js-dropdown-item d-flex align-items-center" - type="button" - @click.stop.prevent="selectMultiple(item)" - > - <gl-icon - :class="[{ invisible: !isSelected(item) }, 'mr-1']" - name="mobile-issue-close" - /> - <slot name="item" :item="item">{{ item.name }}</slot> - </button> - <button - v-else - class="js-dropdown-item" - type="button" - @click.prevent="selectSingle(item)" - > - <slot name="item" :item="item">{{ item.name }}</slot> - </button> - </li> - </ul> - </div> - </div> - </div> - <span - v-if="hasErrors && errorMessage" - :class="[ - 'form-text js-eks-dropdown-error-message', - { - 'text-danger': hasErrors, - 'text-muted': !hasErrors, - }, - ]" - >{{ errorMessage }}</span - > - </div> -</template> diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue deleted file mode 100644 index ba170dc0e19..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue +++ /dev/null @@ -1,58 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import EksClusterConfigurationForm from './eks_cluster_configuration_form.vue'; -import ServiceCredentialsForm from './service_credentials_form.vue'; - -export default { - components: { - ServiceCredentialsForm, - EksClusterConfigurationForm, - }, - props: { - gitlabManagedClusterHelpPath: { - type: String, - required: true, - }, - namespacePerEnvironmentHelpPath: { - type: String, - required: true, - }, - kubernetesIntegrationHelpPath: { - type: String, - required: true, - }, - accountAndExternalIdsHelpPath: { - type: String, - required: true, - }, - createRoleArnHelpPath: { - type: String, - required: true, - }, - externalLinkIcon: { - type: String, - required: true, - }, - }, - computed: { - ...mapState(['hasCredentials']), - }, -}; -</script> -<template> - <div class="js-create-eks-cluster"> - <eks-cluster-configuration-form - v-if="hasCredentials" - :gitlab-managed-cluster-help-path="gitlabManagedClusterHelpPath" - :namespace-per-environment-help-path="namespacePerEnvironmentHelpPath" - :kubernetes-integration-help-path="kubernetesIntegrationHelpPath" - :external-link-icon="externalLinkIcon" - /> - <service-credentials-form - v-else - :create-role-arn-help-path="createRoleArnHelpPath" - :account-and-external-ids-help-path="accountAndExternalIdsHelpPath" - :external-link-icon="externalLinkIcon" - /> - </div> -</template> diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue deleted file mode 100644 index 73458a463f2..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue +++ /dev/null @@ -1,530 +0,0 @@ -<script> -import { - GlFormGroup, - GlFormInput, - GlFormCheckbox, - GlIcon, - GlLink, - GlSprintf, - GlButton, -} from '@gitlab/ui'; -import { createNamespacedHelpers, mapState, mapActions, mapGetters } from 'vuex'; -import ClusterFormDropdown from '~/create_cluster/components/cluster_form_dropdown.vue'; -import { s__ } from '~/locale'; -import { KUBERNETES_VERSIONS } from '../constants'; - -const { mapState: mapRolesState, mapActions: mapRolesActions } = createNamespacedHelpers('roles'); -const { mapState: mapKeyPairsState, mapActions: mapKeyPairsActions } = createNamespacedHelpers( - 'keyPairs', -); -const { mapState: mapVpcsState, mapActions: mapVpcActions } = createNamespacedHelpers('vpcs'); -const { mapState: mapSubnetsState, mapActions: mapSubnetActions } = createNamespacedHelpers( - 'subnets', -); -const { - mapState: mapSecurityGroupsState, - mapActions: mapSecurityGroupsActions, -} = createNamespacedHelpers('securityGroups'); -const { mapState: mapInstanceTypesState } = createNamespacedHelpers('instanceTypes'); - -export default { - components: { - ClusterFormDropdown, - GlFormCheckbox, - GlFormGroup, - GlFormInput, - GlIcon, - GlLink, - GlSprintf, - GlButton, - }, - props: { - gitlabManagedClusterHelpPath: { - type: String, - required: true, - }, - namespacePerEnvironmentHelpPath: { - type: String, - required: true, - }, - kubernetesIntegrationHelpPath: { - type: String, - required: true, - }, - externalLinkIcon: { - type: String, - required: true, - }, - }, - i18n: { - kubernetesIntegrationHelpText: s__( - 'ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration.', - ), - roleDropdownHelpText: s__( - 'ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}.', - ), - roleDropdownHelpPath: - 'https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html#create-service-role', - regionInputLabel: s__('ClusterIntegration|Cluster Region'), - regionHelpText: s__( - 'ClusterIntegration|The region the new cluster will be created in. You must reauthenticate to change regions.', - ), - keyPairDropdownHelpText: s__( - 'ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}.', - ), - keyPairDropdownHelpPath: - 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair', - vpcDropdownHelpText: s__( - 'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}.', - ), - vpcDropdownHelpPath: - 'https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#vpc-create', - subnetDropdownHelpText: s__( - 'ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run.', - ), - subnetDropdownHelpPath: 'https://console.aws.amazon.com/vpc/home?#subnets', - securityGroupDropdownHelpText: s__( - 'ClusterIntegration|Choose the %{linkStart}security group%{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.', - ), - securityGroupDropdownHelpPath: 'https://console.aws.amazon.com/vpc/home?#securityGroups', - instanceTypesDropdownHelpText: s__( - 'ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}.', - ), - instanceTypesDropdownHelpPath: 'https://aws.amazon.com/ec2/instance-types', - gitlabManagedClusterHelpText: s__( - 'ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}', - ), - namespacePerEnvironmentHelpText: s__( - 'ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}', - ), - }, - computed: { - ...mapState([ - 'clusterName', - 'environmentScope', - 'kubernetesVersion', - 'selectedRegion', - 'selectedKeyPair', - 'selectedVpc', - 'selectedSubnet', - 'selectedRole', - 'selectedSecurityGroup', - 'selectedInstanceType', - 'nodeCount', - 'gitlabManagedCluster', - 'namespacePerEnvironment', - 'isCreatingCluster', - ]), - ...mapGetters(['subnetValid']), - ...mapRolesState({ - roles: 'items', - isLoadingRoles: 'isLoadingItems', - loadingRolesError: 'loadingItemsError', - }), - ...mapKeyPairsState({ - keyPairs: 'items', - isLoadingKeyPairs: 'isLoadingItems', - loadingKeyPairsError: 'loadingItemsError', - }), - ...mapVpcsState({ - vpcs: 'items', - isLoadingVpcs: 'isLoadingItems', - loadingVpcsError: 'loadingItemsError', - }), - ...mapSubnetsState({ - subnets: 'items', - isLoadingSubnets: 'isLoadingItems', - loadingSubnetsError: 'loadingItemsError', - }), - ...mapSecurityGroupsState({ - securityGroups: 'items', - isLoadingSecurityGroups: 'isLoadingItems', - loadingSecurityGroupsError: 'loadingItemsError', - }), - ...mapInstanceTypesState({ - instanceTypes: 'items', - isLoadingInstanceTypes: 'isLoadingItems', - loadingInstanceTypesError: 'loadingItemsError', - }), - kubernetesVersions() { - return KUBERNETES_VERSIONS; - }, - vpcDropdownDisabled() { - return !this.selectedRegion; - }, - keyPairDropdownDisabled() { - return !this.selectedRegion; - }, - subnetDropdownDisabled() { - return !this.selectedVpc; - }, - securityGroupDropdownDisabled() { - return !this.selectedVpc; - }, - createClusterButtonDisabled() { - return ( - !this.clusterName || - !this.environmentScope || - !this.kubernetesVersion || - !this.selectedRegion || - !this.selectedKeyPair || - !this.selectedVpc || - !this.subnetValid || - !this.selectedRole || - !this.selectedSecurityGroup || - !this.selectedInstanceType || - !this.nodeCount || - this.isCreatingCluster - ); - }, - displaySubnetError() { - return Boolean(this.loadingSubnetsError) || this.selectedSubnet?.length === 1; - }, - createClusterButtonLabel() { - return this.isCreatingCluster - ? s__('ClusterIntegration|Creating Kubernetes cluster') - : s__('ClusterIntegration|Create Kubernetes cluster'); - }, - subnetValidationErrorText() { - if (this.loadingSubnetsError) { - return s__('ClusterIntegration|Could not load subnets for the selected VPC'); - } - - return s__('ClusterIntegration|You should select at least two subnets'); - }, - }, - mounted() { - this.fetchRoles(); - this.setRegionAndFetchVpcsAndKeyPairs(); - }, - methods: { - ...mapActions([ - 'createCluster', - 'setClusterName', - 'setEnvironmentScope', - 'setKubernetesVersion', - 'setRegion', - 'setVpc', - 'setSubnet', - 'setRole', - 'setKeyPair', - 'setSecurityGroup', - 'setInstanceType', - 'setNodeCount', - 'setGitlabManagedCluster', - 'setNamespacePerEnvironment', - ]), - ...mapVpcActions({ fetchVpcs: 'fetchItems' }), - ...mapSubnetActions({ fetchSubnets: 'fetchItems' }), - ...mapRolesActions({ fetchRoles: 'fetchItems' }), - ...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }), - ...mapSecurityGroupsActions({ fetchSecurityGroups: 'fetchItems' }), - setRegionAndFetchVpcsAndKeyPairs() { - this.setVpc({ vpc: null }); - this.setKeyPair({ keyPair: null }); - this.setSubnet({ subnet: [] }); - this.setSecurityGroup({ securityGroup: null }); - this.fetchVpcs({ region: this.selectedRegion }); - this.fetchKeyPairs({ region: this.selectedRegion }); - }, - setVpcAndFetchSubnets(vpc) { - this.setVpc({ vpc }); - this.setSubnet({ subnet: [] }); - this.setSecurityGroup({ securityGroup: null }); - this.fetchSubnets({ vpc, region: this.selectedRegion }); - this.fetchSecurityGroups({ vpc, region: this.selectedRegion }); - }, - }, -}; -</script> -<template> - <form name="eks-cluster-configuration-form"> - <h4> - {{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }} - </h4> - <div class="mb-3"> - <gl-sprintf :message="$options.i18n.kubernetesIntegrationHelpText"> - <template #link="{ content }"> - <gl-link :href="kubernetesIntegrationHelpPath"> - {{ content }} - </gl-link> - </template> - </gl-sprintf> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-cluster-name">{{ - s__('ClusterIntegration|Kubernetes cluster name') - }}</label> - <gl-form-input - id="eks-cluster-name" - :value="clusterName" - @input="setClusterName({ clusterName: $event })" - /> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-environment-scope">{{ - s__('ClusterIntegration|Environment scope') - }}</label> - <gl-form-input - id="eks-environment-scope" - :value="environmentScope" - @input="setEnvironmentScope({ environmentScope: $event })" - /> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-kubernetes-version">{{ - s__('ClusterIntegration|Kubernetes version') - }}</label> - <cluster-form-dropdown - field-id="eks-kubernetes-version" - field-name="eks-kubernetes-version" - :value="kubernetesVersion" - :items="kubernetesVersions" - :empty-text="s__('ClusterIntegration|Kubernetes version not found')" - @input="setKubernetesVersion({ kubernetesVersion: $event })" - /> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Service role') }}</label> - <cluster-form-dropdown - field-id="eks-role" - field-name="eks-role" - :value="selectedRole" - :items="roles" - :loading="isLoadingRoles" - :loading-text="s__('ClusterIntegration|Loading IAM Roles')" - :placeholder="s__('ClusterIntegration|Select service role')" - :search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')" - :empty-text="s__('ClusterIntegration|No IAM Roles found')" - :has-errors="Boolean(loadingRolesError)" - :error-message="s__('ClusterIntegration|Could not load IAM roles')" - @input="setRole({ role: $event })" - /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.roleDropdownHelpText"> - <template #link="{ content }"> - <gl-link :href="$options.i18n.roleDropdownHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <gl-form-group - :label="$options.i18n.regionInputLabel" - :description="$options.i18n.regionHelpText" - > - <gl-form-input id="eks-region" :value="selectedRegion" type="text" readonly /> - </gl-form-group> - <div class="form-group"> - <label class="label-bold" for="eks-key-pair">{{ - s__('ClusterIntegration|Key pair name') - }}</label> - <cluster-form-dropdown - field-id="eks-key-pair" - field-name="eks-key-pair" - :value="selectedKeyPair" - :items="keyPairs" - :disabled="keyPairDropdownDisabled" - :disabled-text="s__('ClusterIntegration|Select a region to choose a Key Pair')" - :loading="isLoadingKeyPairs" - :loading-text="s__('ClusterIntegration|Loading Key Pairs')" - :placeholder="s__('ClusterIntegration|Select key pair')" - :search-field-placeholder="s__('ClusterIntegration|Search Key Pairs')" - :empty-text="s__('ClusterIntegration|No Key Pairs found')" - :has-errors="Boolean(loadingKeyPairsError)" - :error-message="s__('ClusterIntegration|Could not load Key Pairs')" - @input="setKeyPair({ keyPair: $event })" - /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.keyPairDropdownHelpText"> - <template #link="{ content }"> - <gl-link :href="$options.i18n.keyPairDropdownHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-vpc">{{ s__('ClusterIntegration|VPC') }}</label> - <cluster-form-dropdown - field-id="eks-vpc" - field-name="eks-vpc" - :value="selectedVpc" - :items="vpcs" - :loading="isLoadingVpcs" - :disabled="vpcDropdownDisabled" - :disabled-text="s__('ClusterIntegration|Select a region to choose a VPC')" - :loading-text="s__('ClusterIntegration|Loading VPCs')" - :placeholder="s__('ClusterIntegration|Select a VPC')" - :search-field-placeholder="s__('ClusterIntegration|Search VPCs')" - :empty-text="s__('ClusterIntegration|No VPCs found')" - :has-errors="Boolean(loadingVpcsError)" - :error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')" - @input="setVpcAndFetchSubnets($event)" - /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.vpcDropdownHelpText"> - <template #link="{ content }"> - <gl-link :href="$options.i18n.vpcDropdownHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnets') }}</label> - <cluster-form-dropdown - field-id="eks-subnet" - field-name="eks-subnet" - multiple - :value="selectedSubnet" - :items="subnets" - :loading="isLoadingSubnets" - :disabled="subnetDropdownDisabled" - :disabled-text="s__('ClusterIntegration|Select a VPC to choose a subnet')" - :loading-text="s__('ClusterIntegration|Loading subnets')" - :placeholder="s__('ClusterIntegration|Select a subnet')" - :search-field-placeholder="s__('ClusterIntegration|Search subnets')" - :empty-text="s__('ClusterIntegration|No subnet found')" - :has-errors="displaySubnetError" - :error-message="subnetValidationErrorText" - @input="setSubnet({ subnet: $event })" - /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.subnetDropdownHelpText"> - <template #link="{ content }"> - <gl-link :href="$options.i18n.subnetDropdownHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-security-group">{{ - s__('ClusterIntegration|Security group') - }}</label> - <cluster-form-dropdown - field-id="eks-security-group" - field-name="eks-security-group" - :value="selectedSecurityGroup" - :items="securityGroups" - :loading="isLoadingSecurityGroups" - :disabled="securityGroupDropdownDisabled" - :disabled-text="s__('ClusterIntegration|Select a VPC to choose a security group')" - :loading-text="s__('ClusterIntegration|Loading security groups')" - :placeholder="s__('ClusterIntegration|Select a security group')" - :search-field-placeholder="s__('ClusterIntegration|Search security groups')" - :empty-text="s__('ClusterIntegration|No security group found')" - :has-errors="Boolean(loadingSecurityGroupsError)" - :error-message=" - s__('ClusterIntegration|Could not load security groups for the selected VPC') - " - @input="setSecurityGroup({ securityGroup: $event })" - /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.securityGroupDropdownHelpText"> - <template #link="{ content }"> - <gl-link :href="$options.i18n.securityGroupDropdownHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-instance-type">{{ - s__('ClusterIntegration|Instance type') - }}</label> - <cluster-form-dropdown - field-id="eks-instance-type" - field-name="eks-instance-type" - :value="selectedInstanceType" - :items="instanceTypes" - :loading="isLoadingInstanceTypes" - :loading-text="s__('ClusterIntegration|Loading instance types')" - :placeholder="s__('ClusterIntegration|Select an instance type')" - :search-field-placeholder="s__('ClusterIntegration|Search instance types')" - :empty-text="s__('ClusterIntegration|No instance type found')" - :has-errors="Boolean(loadingInstanceTypesError)" - :error-message="s__('ClusterIntegration|Could not load instance types')" - @input="setInstanceType({ instanceType: $event })" - /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.instanceTypesDropdownHelpText"> - <template #link="{ content }"> - <gl-link :href="$options.i18n.instanceTypesDropdownHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <label class="label-bold" for="eks-node-count">{{ - s__('ClusterIntegration|Number of nodes') - }}</label> - <gl-form-input - id="eks-node-count" - type="number" - min="1" - step="1" - :value="nodeCount" - @input="setNodeCount({ nodeCount: $event })" - /> - </div> - <div class="form-group"> - <gl-form-checkbox - :checked="gitlabManagedCluster" - @input="setGitlabManagedCluster({ gitlabManagedCluster: $event })" - >{{ s__('ClusterIntegration|GitLab-managed cluster') }}</gl-form-checkbox - > - <p class="form text text-muted"> - <gl-sprintf :message="$options.i18n.gitlabManagedClusterHelpText"> - <template #link="{ content }"> - <gl-link :href="gitlabManagedClusterHelpPath" target="_blank"> - {{ content }} - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <gl-form-checkbox - :checked="namespacePerEnvironment" - @input="setNamespacePerEnvironment({ namespacePerEnvironment: $event })" - >{{ s__('ClusterIntegration|Namespace per environment') }}</gl-form-checkbox - > - <p class="form text text-muted"> - <gl-sprintf :message="$options.i18n.namespacePerEnvironmentHelpText"> - <template #link="{ content }"> - <gl-link :href="namespacePerEnvironmentHelpPath" target="_blank"> - {{ content }} - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - <div class="form-group"> - <gl-button - variant="success" - category="primary" - class="js-create-cluster" - :disabled="createClusterButtonDisabled" - :loading="isCreatingCluster" - @click="createCluster()" - > - {{ createClusterButtonLabel }} - </gl-button> - </div> - </form> -</template> diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue deleted file mode 100644 index 004c2e26c4e..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue +++ /dev/null @@ -1,182 +0,0 @@ -<script> -import { GlButton, GlFormGroup, GlFormInput, GlIcon, GlLink, GlSprintf, GlAlert } from '@gitlab/ui'; -import { mapState, mapActions } from 'vuex'; -import { s__, __ } from '~/locale'; -import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; -import { DEFAULT_REGION } from '../constants'; - -export default { - components: { - GlButton, - GlFormGroup, - GlFormInput, - GlIcon, - GlLink, - GlSprintf, - ClipboardButton, - GlAlert, - }, - props: { - accountAndExternalIdsHelpPath: { - type: String, - required: true, - }, - createRoleArnHelpPath: { - type: String, - required: true, - }, - externalLinkIcon: { - type: String, - required: true, - }, - }, - i18n: { - regionInputLabel: s__('ClusterIntegration|Cluster Region'), - regionHelpPath: 'https://aws.amazon.com/about-aws/global-infrastructure/regions_az/', - regionHelpText: s__( - 'ClusterIntegration|Select the region you want to create the new cluster in. Make sure you have access to this region for your role to be able to authenticate. If no region is selected, we will use %{codeStart}DEFAULT_REGION%{codeEnd}. Learn more about %{linkStart}Regions%{linkEnd}.', - ), - accountAndExternalIdsHelpText: s__( - 'ClusterIntegration|The Amazon Resource Name (ARN) associated with your role. If you do not have a provisioned role, first create one on %{awsLinkStart}Amazon Web Services %{awsLinkEnd} using the above account and external IDs. %{moreInfoStart}More information%{moreInfoEnd}', - ), - regionHelpTextDefaultRegion: DEFAULT_REGION, - }, - data() { - return { - roleArn: this.$store.state.roleArn, - selectedRegion: this.$store.state.selectedRegion, - }; - }, - computed: { - ...mapState(['accountId', 'externalId', 'isCreatingRole', 'createRoleError']), - submitButtonDisabled() { - return this.isCreatingRole || !this.roleArn; - }, - submitButtonLabel() { - return this.isCreatingRole - ? __('Authenticating') - : s__('ClusterIntegration|Authenticate with AWS'); - }, - awsHelpLink() { - return 'https://console.aws.amazon.com/iam/home?#roles'; - }, - }, - methods: { - ...mapActions(['createRole']), - }, -}; -</script> -<template> - <form name="service-credentials-form"> - <h4>{{ s__('ClusterIntegration|Authenticate with Amazon Web Services') }}</h4> - <p> - {{ - s__( - 'ClusterIntegration|You must grant access to your organization’s AWS resources in order to create a new EKS cluster. To grant access, create a provision role using the account and external ID below and provide us the ARN.', - ) - }} - </p> - <gl-alert - v-if="createRoleError" - class="js-invalid-credentials gl-mb-5" - variant="danger" - :dismissible="false" - > - {{ createRoleError }} - </gl-alert> - <div class="form-row"> - <div class="form-group col-md-6"> - <label for="gitlab-account-id">{{ __('Account ID') }}</label> - <div class="input-group"> - <gl-form-input id="gitlab-account-id" type="text" readonly :value="accountId" /> - <div class="input-group-append"> - <clipboard-button - :text="accountId" - :title="__('Copy Account ID to clipboard')" - class="input-group-text js-copy-account-id-button" - /> - </div> - </div> - </div> - <div class="form-group col-md-6"> - <label for="eks-external-id">{{ __('External ID') }}</label> - <div class="input-group"> - <gl-form-input id="eks-external-id" type="text" readonly :value="externalId" /> - <div class="input-group-append"> - <clipboard-button - :text="externalId" - :title="__('Copy External ID to clipboard')" - class="input-group-text js-copy-external-id-button" - /> - </div> - </div> - </div> - <div class="col-12 mb-3 mt-n3"> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.accountAndExternalIdsHelpText"> - <template #awsLink="{ content }"> - <gl-link :href="awsHelpLink" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - <template #moreInfo="{ content }"> - <gl-link :href="accountAndExternalIdsHelpPath" target="_blank"> - {{ content }} - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - </div> - <div class="form-group"> - <label for="eks-provision-role-arn">{{ s__('ClusterIntegration|Provision Role ARN') }}</label> - <gl-form-input id="eks-provision-role-arn" v-model="roleArn" /> - <p class="form-text text-muted"> - <gl-sprintf :message="$options.i18n.accountAndExternalIdsHelpText"> - <template #awsLink="{ content }"> - <gl-link :href="awsHelpLink" target="_blank"> - {{ content }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </template> - <template #moreInfo="{ content }"> - <gl-link :href="accountAndExternalIdsHelpPath" target="_blank"> - {{ content }} - </gl-link> - </template> - </gl-sprintf> - </p> - </div> - - <gl-form-group :label="$options.i18n.regionInputLabel"> - <gl-form-input id="eks-region" v-model="selectedRegion" type="text" /> - - <template #description> - <gl-sprintf :message="$options.i18n.regionHelpText"> - <template #code> - <code>{{ $options.i18n.regionHelpTextDefaultRegion }}</code> - </template> - - <template #link="{ content }"> - <gl-link :href="$options.i18n.regionHelpPath" target="_blank"> - {{ content }} - <gl-icon name="external-link" /> - </gl-link> - </template> - </gl-sprintf> - </template> - </gl-form-group> - - <gl-button - variant="success" - category="primary" - type="submit" - :disabled="submitButtonDisabled" - :loading="isCreatingRole" - @click.prevent="createRole({ roleArn, selectedRegion, externalId })" - > - {{ submitButtonLabel }} - </gl-button> - </form> -</template> diff --git a/app/assets/javascripts/create_cluster/eks_cluster/constants.js b/app/assets/javascripts/create_cluster/eks_cluster/constants.js deleted file mode 100644 index 3ed0f050301..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/constants.js +++ /dev/null @@ -1,9 +0,0 @@ -export const DEFAULT_REGION = 'us-east-2'; - -export const KUBERNETES_VERSIONS = [ - { name: '1.16', value: '1.16' }, - { name: '1.17', value: '1.17' }, - { name: '1.18', value: '1.18' }, - { name: '1.19', value: '1.19' }, - { name: '1.20', value: '1.20', default: true }, -]; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/index.js b/app/assets/javascripts/create_cluster/eks_cluster/index.js deleted file mode 100644 index 38b7eefd15b..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/index.js +++ /dev/null @@ -1,55 +0,0 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import { parseBoolean } from '~/lib/utils/common_utils'; -import CreateEksCluster from './components/create_eks_cluster.vue'; -import createStore from './store'; - -Vue.use(Vuex); - -export default (el) => { - const { - gitlabManagedClusterHelpPath, - namespacePerEnvironmentHelpPath, - kubernetesIntegrationHelpPath, - accountAndExternalIdsHelpPath, - createRoleArnHelpPath, - externalId, - accountId, - instanceTypes, - hasCredentials, - createRolePath, - createClusterPath, - externalLinkIcon, - roleArn, - } = el.dataset; - - return new Vue({ - el, - store: createStore({ - initialState: { - hasCredentials: parseBoolean(hasCredentials), - externalId, - accountId, - instanceTypes: JSON.parse(instanceTypes), - createRolePath, - createClusterPath, - roleArn, - }, - }), - components: { - CreateEksCluster, - }, - render(createElement) { - return createElement('create-eks-cluster', { - props: { - gitlabManagedClusterHelpPath, - namespacePerEnvironmentHelpPath, - kubernetesIntegrationHelpPath, - accountAndExternalIdsHelpPath, - createRoleArnHelpPath, - externalLinkIcon, - }, - }); - }, - }); -}; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js b/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js deleted file mode 100644 index bd9554521b8..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js +++ /dev/null @@ -1,79 +0,0 @@ -import EC2 from 'aws-sdk/clients/ec2'; -import IAM from 'aws-sdk/clients/iam'; -import AWS from 'aws-sdk/global'; - -const lookupVpcName = ({ Tags: tags, VpcId: id }) => { - const nameTag = tags.find(({ Key: key }) => key === 'Name'); - - return nameTag ? nameTag.Value : id; -}; - -export const setAWSConfig = ({ awsCredentials }) => { - AWS.config = awsCredentials; -}; - -export const fetchRoles = () => { - const iam = new IAM(); - - return iam - .listRoles() - .promise() - .then(({ Roles: roles }) => roles.map(({ RoleName: name, Arn: value }) => ({ name, value }))); -}; - -export const fetchKeyPairs = ({ region }) => { - const ec2 = new EC2({ region }); - - return ec2 - .describeKeyPairs() - .promise() - .then(({ KeyPairs: keyPairs }) => keyPairs.map(({ KeyName: name }) => ({ name, value: name }))); -}; - -export const fetchVpcs = ({ region }) => { - const ec2 = new EC2({ region }); - - return ec2 - .describeVpcs() - .promise() - .then(({ Vpcs: vpcs }) => - vpcs.map((vpc) => ({ - value: vpc.VpcId, - name: lookupVpcName(vpc), - })), - ); -}; - -export const fetchSubnets = ({ vpc, region }) => { - const ec2 = new EC2({ region }); - - return ec2 - .describeSubnets({ - Filters: [ - { - Name: 'vpc-id', - Values: [vpc], - }, - ], - }) - .promise() - .then(({ Subnets: subnets }) => subnets.map(({ SubnetId: id }) => ({ value: id, name: id }))); -}; - -export const fetchSecurityGroups = ({ region, vpc }) => { - const ec2 = new EC2({ region }); - - return ec2 - .describeSecurityGroups({ - Filters: [ - { - Name: 'vpc-id', - Values: [vpc], - }, - ], - }) - .promise() - .then(({ SecurityGroups: securityGroups }) => - securityGroups.map(({ GroupName: name, GroupId: value }) => ({ name, value })), - ); -}; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js deleted file mode 100644 index cd8212a40f9..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js +++ /dev/null @@ -1,148 +0,0 @@ -import createFlash from '~/flash'; -import axios from '~/lib/utils/axios_utils'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import { DEFAULT_REGION } from '../constants'; -import { setAWSConfig } from '../services/aws_services_facade'; -import * as types from './mutation_types'; - -const getErrorMessage = (data) => { - const errorKey = Object.keys(data)[0]; - - return data[errorKey][0]; -}; - -export const setClusterName = ({ commit }, payload) => { - commit(types.SET_CLUSTER_NAME, payload); -}; - -export const setEnvironmentScope = ({ commit }, payload) => { - commit(types.SET_ENVIRONMENT_SCOPE, payload); -}; - -export const setKubernetesVersion = ({ commit }, payload) => { - commit(types.SET_KUBERNETES_VERSION, payload); -}; - -export const createRole = ({ dispatch, state: { createRolePath } }, payload) => { - dispatch('requestCreateRole'); - - const region = payload.selectedRegion || DEFAULT_REGION; - - return axios - .post(createRolePath, { - role_arn: payload.roleArn, - role_external_id: payload.externalId, - region, - }) - .then(({ data }) => { - const awsData = { - ...convertObjectPropsToCamelCase(data), - region, - }; - - dispatch('createRoleSuccess', awsData); - }) - .catch((error) => { - let message = error; - if (error?.response?.data?.message) { - message = error.response.data.message; - } - dispatch('createRoleError', { error: message }); - }); -}; - -export const requestCreateRole = ({ commit }) => { - commit(types.REQUEST_CREATE_ROLE); -}; - -export const createRoleSuccess = ({ dispatch, commit }, awsCredentials) => { - dispatch('setRegion', { region: awsCredentials.region }); - setAWSConfig({ awsCredentials }); - commit(types.CREATE_ROLE_SUCCESS); -}; - -export const createRoleError = ({ commit }, payload) => { - commit(types.CREATE_ROLE_ERROR, payload); -}; - -export const createCluster = ({ dispatch, state }) => { - dispatch('requestCreateCluster'); - - return axios - .post(state.createClusterPath, { - name: state.clusterName, - environment_scope: state.environmentScope, - managed: state.gitlabManagedCluster, - namespace_per_environment: state.namespacePerEnvironment, - provider_aws_attributes: { - kubernetes_version: state.kubernetesVersion, - region: state.selectedRegion, - vpc_id: state.selectedVpc, - subnet_ids: state.selectedSubnet, - role_arn: state.selectedRole, - key_name: state.selectedKeyPair, - security_group_id: state.selectedSecurityGroup, - instance_type: state.selectedInstanceType, - num_nodes: state.nodeCount, - }, - }) - .then(({ headers: { location } }) => dispatch('createClusterSuccess', location)) - .catch(({ response: { data } }) => { - dispatch('createClusterError', data); - }); -}; - -export const requestCreateCluster = ({ commit }) => { - commit(types.REQUEST_CREATE_CLUSTER); -}; - -export const createClusterSuccess = (_, location) => { - window.location.assign(location); -}; - -export const createClusterError = ({ commit }, error) => { - commit(types.CREATE_CLUSTER_ERROR, error); - createFlash({ - message: getErrorMessage(error), - }); -}; - -export const setRegion = ({ commit }, payload) => { - commit(types.SET_REGION, payload); -}; - -export const setKeyPair = ({ commit }, payload) => { - commit(types.SET_KEY_PAIR, payload); -}; - -export const setVpc = ({ commit }, payload) => { - commit(types.SET_VPC, payload); -}; - -export const setSubnet = ({ commit }, payload) => { - commit(types.SET_SUBNET, payload); -}; - -export const setRole = ({ commit }, payload) => { - commit(types.SET_ROLE, payload); -}; - -export const setSecurityGroup = ({ commit }, payload) => { - commit(types.SET_SECURITY_GROUP, payload); -}; - -export const setGitlabManagedCluster = ({ commit }, payload) => { - commit(types.SET_GITLAB_MANAGED_CLUSTER, payload); -}; - -export const setNamespacePerEnvironment = ({ commit }, payload) => { - commit(types.SET_NAMESPACE_PER_ENVIRONMENT, payload); -}; - -export const setInstanceType = ({ commit }, payload) => { - commit(types.SET_INSTANCE_TYPE, payload); -}; - -export const setNodeCount = ({ commit }, payload) => { - commit(types.SET_NODE_COUNT, payload); -}; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/getters.js b/app/assets/javascripts/create_cluster/eks_cluster/store/getters.js deleted file mode 100644 index d8489ca31cf..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/store/getters.js +++ /dev/null @@ -1,2 +0,0 @@ -export const subnetValid = ({ selectedSubnet }) => - Array.isArray(selectedSubnet) && selectedSubnet.length >= 2; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/index.js b/app/assets/javascripts/create_cluster/eks_cluster/store/index.js deleted file mode 100644 index ed054989771..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/store/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import Vuex from 'vuex'; -import clusterDropdownStore from '~/create_cluster/store/cluster_dropdown'; -import { - fetchRoles, - fetchKeyPairs, - fetchVpcs, - fetchSubnets, - fetchSecurityGroups, -} from '../services/aws_services_facade'; -import * as actions from './actions'; -import * as getters from './getters'; -import mutations from './mutations'; -import state from './state'; - -const createStore = ({ initialState }) => - new Vuex.Store({ - actions, - getters, - mutations, - state: Object.assign(state(), initialState), - modules: { - roles: { - namespaced: true, - ...clusterDropdownStore({ fetchFn: fetchRoles }), - }, - keyPairs: { - namespaced: true, - ...clusterDropdownStore({ fetchFn: fetchKeyPairs }), - }, - vpcs: { - namespaced: true, - ...clusterDropdownStore({ fetchFn: fetchVpcs }), - }, - subnets: { - namespaced: true, - ...clusterDropdownStore({ fetchFn: fetchSubnets }), - }, - securityGroups: { - namespaced: true, - ...clusterDropdownStore({ fetchFn: fetchSecurityGroups }), - }, - instanceTypes: { - namespaced: true, - ...clusterDropdownStore({ initialState: { items: initialState.instanceTypes } }), - }, - }, - }); - -export default createStore; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js deleted file mode 100644 index 4a48195a27b..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js +++ /dev/null @@ -1,19 +0,0 @@ -export const SET_CLUSTER_NAME = 'SET_CLUSTER_NAME'; -export const SET_ENVIRONMENT_SCOPE = 'SET_ENVIRONMENT_SCOPE'; -export const SET_KUBERNETES_VERSION = 'SET_KUBERNETES_VERSION'; -export const SET_REGION = 'SET_REGION'; -export const SET_VPC = 'SET_VPC'; -export const SET_KEY_PAIR = 'SET_KEY_PAIR'; -export const SET_SUBNET = 'SET_SUBNET'; -export const SET_ROLE = 'SET_ROLE'; -export const SET_SECURITY_GROUP = 'SET_SECURITY_GROUP'; -export const SET_INSTANCE_TYPE = 'SET_INSTANCE_TYPE'; -export const SET_NODE_COUNT = 'SET_NODE_COUNT'; -export const SET_GITLAB_MANAGED_CLUSTER = 'SET_GITLAB_MANAGED_CLUSTER'; -export const SET_NAMESPACE_PER_ENVIRONMENT = 'SET_NAMESPACE_PER_ENVIRONMENT'; -export const REQUEST_CREATE_ROLE = 'REQUEST_CREATE_ROLE'; -export const CREATE_ROLE_SUCCESS = 'CREATE_ROLE_SUCCESS'; -export const CREATE_ROLE_ERROR = 'CREATE_ROLE_ERROR'; -export const REQUEST_CREATE_CLUSTER = 'REQUEST_CREATE_CLUSTER'; -export const CREATE_CLUSTER_SUCCESS = 'CREATE_CLUSTER_SUCCESS'; -export const CREATE_CLUSTER_ERROR = 'CREATE_CLUSTER_ERROR'; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js deleted file mode 100644 index f57236e0e31..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js +++ /dev/null @@ -1,66 +0,0 @@ -import * as types from './mutation_types'; - -export default { - [types.SET_CLUSTER_NAME](state, { clusterName }) { - state.clusterName = clusterName; - }, - [types.SET_ENVIRONMENT_SCOPE](state, { environmentScope }) { - state.environmentScope = environmentScope; - }, - [types.SET_KUBERNETES_VERSION](state, { kubernetesVersion }) { - state.kubernetesVersion = kubernetesVersion; - }, - [types.SET_REGION](state, { region }) { - state.selectedRegion = region; - }, - [types.SET_KEY_PAIR](state, { keyPair }) { - state.selectedKeyPair = keyPair; - }, - [types.SET_VPC](state, { vpc }) { - state.selectedVpc = vpc; - }, - [types.SET_SUBNET](state, { subnet }) { - state.selectedSubnet = subnet; - }, - [types.SET_ROLE](state, { role }) { - state.selectedRole = role; - }, - [types.SET_SECURITY_GROUP](state, { securityGroup }) { - state.selectedSecurityGroup = securityGroup; - }, - [types.SET_INSTANCE_TYPE](state, { instanceType }) { - state.selectedInstanceType = instanceType; - }, - [types.SET_NODE_COUNT](state, { nodeCount }) { - state.nodeCount = nodeCount; - }, - [types.SET_GITLAB_MANAGED_CLUSTER](state, { gitlabManagedCluster }) { - state.gitlabManagedCluster = gitlabManagedCluster; - }, - [types.SET_NAMESPACE_PER_ENVIRONMENT](state, { namespacePerEnvironment }) { - state.namespacePerEnvironment = namespacePerEnvironment; - }, - [types.REQUEST_CREATE_ROLE](state) { - state.isCreatingRole = true; - state.createRoleError = null; - state.hasCredentials = false; - }, - [types.CREATE_ROLE_SUCCESS](state) { - state.isCreatingRole = false; - state.createRoleError = null; - state.hasCredentials = true; - }, - [types.CREATE_ROLE_ERROR](state, { error }) { - state.isCreatingRole = false; - state.createRoleError = error; - state.hasCredentials = false; - }, - [types.REQUEST_CREATE_CLUSTER](state) { - state.isCreatingCluster = true; - state.createClusterError = null; - }, - [types.CREATE_CLUSTER_ERROR](state, { error }) { - state.isCreatingCluster = false; - state.createClusterError = error; - }, -}; diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/state.js b/app/assets/javascripts/create_cluster/eks_cluster/store/state.js deleted file mode 100644 index c906ddf9011..00000000000 --- a/app/assets/javascripts/create_cluster/eks_cluster/store/state.js +++ /dev/null @@ -1,34 +0,0 @@ -import { KUBERNETES_VERSIONS } from '../constants'; - -const kubernetesVersion = KUBERNETES_VERSIONS.find((version) => version.default).value; - -export default () => ({ - createRolePath: null, - - isCreatingRole: false, - roleCreated: false, - createRoleError: false, - - accountId: '', - externalId: '', - - roleArn: '', - - clusterName: '', - environmentScope: '*', - kubernetesVersion, - selectedRegion: '', - selectedRole: '', - selectedKeyPair: '', - selectedVpc: '', - selectedSubnet: [], - selectedSecurityGroup: '', - selectedInstanceType: 'm5.large', - nodeCount: '3', - - isCreatingCluster: false, - createClusterError: false, - - gitlabManagedCluster: true, - namespacePerEnvironment: true, -}); diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_dropdown_mixin.js b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_dropdown_mixin.js deleted file mode 100644 index 1246fdb19d7..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_dropdown_mixin.js +++ /dev/null @@ -1,70 +0,0 @@ -import { GlLoadingIcon } from '@gitlab/ui'; -import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; -import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; -import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue'; - -import store from '../store'; - -export default { - store, - components: { - DropdownButton, - DropdownSearchInput, - DropdownHiddenInput, - GlLoadingIcon, - }, - props: { - fieldId: { - type: String, - required: true, - }, - fieldName: { - type: String, - required: true, - }, - defaultValue: { - type: String, - required: false, - default: '', - }, - }, - data() { - return { - isLoading: false, - hasErrors: false, - searchQuery: '', - gapiError: '', - }; - }, - computed: { - results() { - if (!this.items) { - return []; - } - - return this.items.filter((item) => item.name.toLowerCase().indexOf(this.searchQuery) > -1); - }, - }, - methods: { - fetchSuccessHandler() { - if (this.defaultValue) { - const itemToSelect = this.items.find((item) => item.name === this.defaultValue); - - if (itemToSelect) { - this.setItem(itemToSelect.name); - } - } - - this.isLoading = false; - this.hasErrors = false; - }, - fetchFailureHandler(resp) { - this.isLoading = false; - this.hasErrors = true; - - if (resp.result && resp.result.error) { - this.gapiError = resp.result.error.message; - } - }, - }, -}; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_machine_type_dropdown.vue b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_machine_type_dropdown.vue deleted file mode 100644 index 23c477bfbfd..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_machine_type_dropdown.vue +++ /dev/null @@ -1,112 +0,0 @@ -<script> -import { mapState, mapGetters, mapActions } from 'vuex'; -import { sprintf, s__ } from '~/locale'; - -import gkeDropdownMixin from './gke_dropdown_mixin'; - -export default { - name: 'GkeMachineTypeDropdown', - mixins: [gkeDropdownMixin], - computed: { - ...mapState([ - 'isValidatingProjectBilling', - 'projectHasBillingEnabled', - 'selectedZone', - 'selectedMachineType', - ]), - ...mapState({ items: 'machineTypes' }), - ...mapGetters(['hasZone', 'hasMachineType']), - isDisabled() { - return ( - this.isLoading || - this.isValidatingProjectBilling || - !this.projectHasBillingEnabled || - !this.hasZone - ); - }, - toggleText() { - if (this.isLoading) { - return s__('ClusterIntegration|Fetching machine types'); - } - - if (this.selectedMachineType) { - return this.selectedMachineType; - } - - if (!this.projectHasBillingEnabled && !this.hasZone) { - return s__('ClusterIntegration|Select project and zone to choose machine type'); - } - - return !this.hasZone - ? s__('ClusterIntegration|Select zone to choose machine type') - : s__('ClusterIntegration|Select machine type'); - }, - errorMessage() { - return sprintf( - s__( - 'ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}', - ), - { error: this.gapiError }, - ); - }, - }, - watch: { - selectedZone() { - this.hasErrors = false; - - if (this.hasZone) { - this.isLoading = true; - - this.fetchMachineTypes().then(this.fetchSuccessHandler).catch(this.fetchFailureHandler); - } - }, - }, - methods: { - ...mapActions(['fetchMachineTypes']), - ...mapActions({ setItem: 'setMachineType' }), - }, -}; -</script> - -<template> - <div> - <div class="js-gcp-machine-type-dropdown dropdown"> - <dropdown-hidden-input :name="fieldName" :value="selectedMachineType" /> - <dropdown-button - :class="{ 'border-danger': hasErrors }" - :is-disabled="isDisabled" - :is-loading="isLoading" - :toggle-text="toggleText" - /> - <div class="dropdown-menu dropdown-select"> - <dropdown-search-input - v-model="searchQuery" - :placeholder-text="s__('ClusterIntegration|Search machine types')" - /> - <div class="dropdown-content"> - <ul> - <li v-show="!results.length"> - <span class="menu-item"> - {{ s__('ClusterIntegration|No machine types matched your search') }} - </span> - </li> - <li v-for="result in results" :key="result.id"> - <button type="button" @click.prevent="setItem(result.name)">{{ result.name }}</button> - </li> - </ul> - </div> - <div class="dropdown-loading"><gl-loading-icon size="sm" /></div> - </div> - </div> - <span - v-if="hasErrors" - :class="{ - 'text-danger': hasErrors, - 'text-muted': !hasErrors, - }" - class="form-text" - > - {{ errorMessage }} - </span> - </div> -</template> diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_network_dropdown.vue b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_network_dropdown.vue deleted file mode 100644 index 8f18ac29c0f..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_network_dropdown.vue +++ /dev/null @@ -1,53 +0,0 @@ -<script> -import { createNamespacedHelpers, mapState, mapGetters, mapActions } from 'vuex'; - -import ClusterFormDropdown from '~/create_cluster/components/cluster_form_dropdown.vue'; - -const { mapState: mapDropdownState } = createNamespacedHelpers('networks'); -const { mapActions: mapSubnetworkActions } = createNamespacedHelpers('subnetworks'); - -export default { - components: { - ClusterFormDropdown, - }, - props: { - fieldName: { - type: String, - required: true, - }, - }, - computed: { - ...mapState(['selectedNetwork']), - ...mapDropdownState(['items', 'isLoadingItems', 'loadingItemsError']), - ...mapGetters(['hasZone', 'projectId', 'region']), - }, - methods: { - ...mapActions(['setNetwork', 'setSubnetwork']), - ...mapSubnetworkActions({ fetchSubnetworks: 'fetchItems' }), - setNetworkAndFetchSubnetworks(network) { - const { projectId: project, region } = this; - - this.setSubnetwork(''); - this.setNetwork(network); - this.fetchSubnetworks({ project, region, network: network.selfLink }); - }, - }, -}; -</script> -<template> - <cluster-form-dropdown - :field-name="fieldName" - :value="selectedNetwork" - :items="items" - :disabled="!hasZone" - :loading="isLoadingItems" - :has-errors="Boolean(loadingItemsError)" - :loading-text="s__('ClusterIntegration|Loading networks')" - :placeholder="s__('ClusterIntegration|Select a network')" - :search-field-placeholder="s__('ClusterIntegration|Search networks')" - :empty-text="s__('ClusterIntegration|No networks found')" - :error-message="s__('ClusterIntegration|Could not load networks')" - :disabled-text="s__('ClusterIntegration|Select a zone to choose a network')" - @input="setNetworkAndFetchSubnetworks" - /> -</template> diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_project_id_dropdown.vue b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_project_id_dropdown.vue deleted file mode 100644 index aba6dd4b493..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_project_id_dropdown.vue +++ /dev/null @@ -1,194 +0,0 @@ -<script> -import { GlSprintf, GlLink, GlIcon } from '@gitlab/ui'; -import { mapState, mapGetters, mapActions } from 'vuex'; -import { s__ } from '~/locale'; - -import gkeDropdownMixin from './gke_dropdown_mixin'; - -export default { - name: 'GkeProjectIdDropdown', - components: { - GlSprintf, - GlLink, - GlIcon, - }, - mixins: [gkeDropdownMixin], - props: { - docsUrl: { - type: String, - required: true, - }, - }, - computed: { - ...mapState(['selectedProject', 'isValidatingProjectBilling', 'projectHasBillingEnabled']), - ...mapState({ items: 'projects' }), - ...mapGetters(['hasProject']), - hasOneProject() { - return this.items && this.items.length === 1; - }, - isDisabled() { - return ( - this.isLoading || this.isValidatingProjectBilling || (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'); - } - - if (this.hasProject) { - return this.selectedProject.name; - } - - if (!this.items) { - return s__('ClusterIntegration|No projects found'); - } - - return s__('ClusterIntegration|Select project'); - }, - helpText() { - if (this.hasErrors) { - return this.errorMessage; - } - - if (!this.items) { - return s__( - 'ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.', - ); - } - - return this.items.length - ? s__( - 'ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.', - ) - : s__( - 'ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.', - ); - }, - 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 s__( - 'ClusterIntegration|This project does not have billing enabled. To create a cluster, %{linkToBillingStart}enable billing%{linkToBillingEnd} and try again.', - ); - } - - return s__( - 'ClusterIntegration|An error occurred while trying to fetch your projects: %{error}', - ); - }, - }, - watch: { - selectedProject() { - this.setIsValidatingProjectBilling(true); - - this.validateProjectBilling() - .then(this.validateProjectBillingSuccessHandler) - .catch(this.validateProjectBillingFailureHandler); - }, - }, - created() { - this.isLoading = true; - - this.fetchProjects().then(this.fetchSuccessHandler).catch(this.fetchFailureHandler); - }, - methods: { - ...mapActions(['fetchProjects', 'setIsValidatingProjectBilling', 'validateProjectBilling']), - ...mapActions({ setItem: 'setProject' }), - fetchSuccessHandler() { - if (this.defaultValue) { - const projectToSelect = this.items.find((item) => item.projectId === this.defaultValue); - - if (projectToSelect) { - this.setItem(projectToSelect); - } - } else if (this.items.length === 1) { - this.setItem(this.items[0]); - } - - this.isLoading = false; - this.hasErrors = false; - }, - validateProjectBillingSuccessHandler() { - this.hasErrors = !this.projectHasBillingEnabled; - }, - validateProjectBillingFailureHandler(resp) { - this.hasErrors = true; - - this.gapiError = resp.result ? resp.result.error.message : resp; - }, - }, -}; -</script> - -<template> - <div> - <div class="js-gcp-project-id-dropdown dropdown"> - <dropdown-hidden-input :name="fieldName" :value="selectedProject.projectId" /> - <dropdown-button - :class="{ - 'border-danger': hasErrors, - 'read-only': hasOneProject, - }" - :is-disabled="isDisabled" - :is-loading="isLoading" - :toggle-text="toggleText" - /> - <div class="dropdown-menu dropdown-select"> - <dropdown-search-input - v-model="searchQuery" - :placeholder-text="s__('ClusterIntegration|Search projects')" - /> - <div class="dropdown-content"> - <ul> - <li v-show="!results.length"> - <span class="menu-item"> - {{ s__('ClusterIntegration|No projects matched your search') }} - </span> - </li> - <li v-for="result in results" :key="result.project_number"> - <button type="button" @click.prevent="setItem(result)">{{ result.name }}</button> - </li> - </ul> - </div> - <div class="dropdown-loading"><gl-loading-icon size="sm" /></div> - </div> - </div> - <span - :class="{ - 'text-danger': hasErrors, - 'text-muted': !hasErrors, - }" - class="form-text" - > - <gl-sprintf :message="helpText"> - <template #linkToBilling="{ content }"> - <gl-link - :href="'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral'" - target="_blank" - >{{ content }} <gl-icon name="external-link" - /></gl-link> - </template> - - <template #docsLink="{ content }"> - <gl-link :href="docsUrl" target="_blank" - >{{ content }} <gl-icon name="external-link" - /></gl-link> - </template> - - <template #error> - {{ gapiError }} - </template> - </gl-sprintf> - </span> - </div> -</template> diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_submit_button.vue b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_submit_button.vue deleted file mode 100644 index a7e08a5e97f..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_submit_button.vue +++ /dev/null @@ -1,18 +0,0 @@ -<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> diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_subnetwork_dropdown.vue b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_subnetwork_dropdown.vue deleted file mode 100644 index dab4adc3789..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_subnetwork_dropdown.vue +++ /dev/null @@ -1,44 +0,0 @@ -<script> -import { createNamespacedHelpers, mapState, mapGetters, mapActions } from 'vuex'; - -import ClusterFormDropdown from '~/create_cluster/components/cluster_form_dropdown.vue'; - -const { mapState: mapDropdownState } = createNamespacedHelpers('subnetworks'); - -export default { - components: { - ClusterFormDropdown, - }, - props: { - fieldName: { - type: String, - required: true, - }, - }, - computed: { - ...mapState(['selectedSubnetwork']), - ...mapDropdownState(['items', 'isLoadingItems', 'loadingItemsError']), - ...mapGetters(['hasNetwork']), - }, - methods: { - ...mapActions(['setSubnetwork']), - }, -}; -</script> -<template> - <cluster-form-dropdown - :field-name="fieldName" - :value="selectedSubnetwork" - :items="items" - :disabled="!hasNetwork" - :loading="isLoadingItems" - :has-errors="Boolean(loadingItemsError)" - :loading-text="s__('ClusterIntegration|Loading subnetworks')" - :placeholder="s__('ClusterIntegration|Select a subnetwork')" - :search-field-placeholder="s__('ClusterIntegration|Search subnetworks')" - :empty-text="s__('ClusterIntegration|No subnetworks found')" - :error-message="s__('ClusterIntegration|Could not load subnetworks')" - :disabled-text="s__('ClusterIntegration|Select a network to choose a subnetwork')" - @input="setSubnetwork" - /> -</template> diff --git a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_zone_dropdown.vue b/app/assets/javascripts/create_cluster/gke_cluster/components/gke_zone_dropdown.vue deleted file mode 100644 index 027ce74753e..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/components/gke_zone_dropdown.vue +++ /dev/null @@ -1,101 +0,0 @@ -<script> -import { mapState, mapActions } from 'vuex'; -import { sprintf, s__ } from '~/locale'; - -import gkeDropdownMixin from './gke_dropdown_mixin'; - -export default { - name: 'GkeZoneDropdown', - mixins: [gkeDropdownMixin], - computed: { - ...mapState([ - 'selectedProject', - 'selectedZone', - 'projects', - 'isValidatingProjectBilling', - 'projectHasBillingEnabled', - ]), - ...mapState({ items: 'zones' }), - isDisabled() { - return this.isLoading || this.isValidatingProjectBilling || !this.projectHasBillingEnabled; - }, - toggleText() { - if (this.isLoading) { - return s__('ClusterIntegration|Fetching zones'); - } - - if (this.selectedZone) { - return this.selectedZone; - } - - return !this.projectHasBillingEnabled - ? s__('ClusterIntegration|Select project to choose zone') - : s__('ClusterIntegration|Select zone'); - }, - errorMessage() { - return sprintf( - s__('ClusterIntegration|An error occurred while trying to fetch project zones: %{error}'), - { error: this.gapiError }, - ); - }, - }, - watch: { - isValidatingProjectBilling(isValidating) { - this.hasErrors = false; - - if (!isValidating && this.projectHasBillingEnabled) { - this.isLoading = true; - - this.fetchZones().then(this.fetchSuccessHandler).catch(this.fetchFailureHandler); - } - }, - }, - methods: { - ...mapActions(['fetchZones']), - ...mapActions({ setItem: 'setZone' }), - }, -}; -</script> - -<template> - <div> - <div class="js-gcp-zone-dropdown dropdown"> - <dropdown-hidden-input :name="fieldName" :value="selectedZone" /> - <dropdown-button - :class="{ 'border-danger': hasErrors }" - :is-disabled="isDisabled" - :is-loading="isLoading" - :toggle-text="toggleText" - /> - <div class="dropdown-menu dropdown-select"> - <dropdown-search-input - v-model="searchQuery" - :placeholder-text="s__('ClusterIntegration|Search zones')" - /> - <div class="dropdown-content"> - <ul> - <li v-show="!results.length"> - <span class="menu-item"> - {{ s__('ClusterIntegration|No zones matched your search') }} - </span> - </li> - <li v-for="result in results" :key="result.id"> - <button type="button" @click.prevent="setItem(result.name)">{{ result.name }}</button> - </li> - </ul> - </div> - <div class="dropdown-loading"><gl-loading-icon size="sm" /></div> - </div> - </div> - <span - v-if="hasErrors" - :class="{ - 'text-danger': hasErrors, - 'text-muted': !hasErrors, - }" - class="form-text" - > - {{ errorMessage }} - </span> - </div> -</template> diff --git a/app/assets/javascripts/create_cluster/gke_cluster/constants.js b/app/assets/javascripts/create_cluster/gke_cluster/constants.js deleted file mode 100644 index 2a1c0819916..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/constants.js +++ /dev/null @@ -1,11 +0,0 @@ -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 = - 'https://www.googleapis.com/discovery/v1/apis/compute/v1/rest'; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/gapi_loader.js b/app/assets/javascripts/create_cluster/gke_cluster/gapi_loader.js deleted file mode 100644 index b5f92fed8eb..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/gapi_loader.js +++ /dev/null @@ -1,24 +0,0 @@ -// This is a helper module to lazily import the google APIs for the GKE cluster -// integration without introducing an indirect global dependency on an -// initialized window.gapi object. -export default () => { - if (window.gapiPromise === undefined) { - // first time loading the module - window.gapiPromise = new Promise((resolve, reject) => { - // this callback is set as a query param to script.src URL - window.onGapiLoad = () => { - resolve(window.gapi); - }; - - const script = document.createElement('script'); - // do not use script.onload, because gapi continues to load after the initial script load - script.type = 'text/javascript'; - script.async = true; - script.src = 'https://apis.google.com/js/api.js?onload=onGapiLoad'; - script.onerror = reject; - document.head.appendChild(script); - }); - } - - return window.gapiPromise; -}; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/index.js b/app/assets/javascripts/create_cluster/gke_cluster/index.js deleted file mode 100644 index 3a42b460e1c..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/index.js +++ /dev/null @@ -1,95 +0,0 @@ -import Vue from 'vue'; -import createFlash from '~/flash'; -import GkeMachineTypeDropdown from './components/gke_machine_type_dropdown.vue'; -import GkeProjectIdDropdown from './components/gke_project_id_dropdown.vue'; -import GkeSubmitButton from './components/gke_submit_button.vue'; -import GkeZoneDropdown from './components/gke_zone_dropdown.vue'; -import * as CONSTANTS from './constants'; -import gapiLoader from './gapi_loader'; - -import store from './store'; - -const mountComponent = (entryPoint, component, componentName, extraProps = {}) => { - const el = document.querySelector(entryPoint); - if (!el) return false; - - const hiddenInput = el.querySelector('input'); - - return new Vue({ - el, - store, - components: { - [componentName]: component, - }, - render: (createElement) => - createElement(componentName, { - props: { - fieldName: hiddenInput.getAttribute('name'), - fieldId: hiddenInput.getAttribute('id'), - defaultValue: hiddenInput.value, - ...extraProps, - }, - }), - }); -}; - -const mountGkeProjectIdDropdown = () => { - const entryPoint = '.js-gcp-project-id-dropdown-entry-point'; - const el = document.querySelector(entryPoint); - - mountComponent(entryPoint, GkeProjectIdDropdown, 'gke-project-id-dropdown', { - docsUrl: el.dataset.docsurl, - }); -}; - -const mountGkeZoneDropdown = () => { - mountComponent('.js-gcp-zone-dropdown-entry-point', GkeZoneDropdown, 'gke-zone-dropdown'); -}; - -const mountGkeMachineTypeDropdown = () => { - mountComponent( - '.js-gcp-machine-type-dropdown-entry-point', - GkeMachineTypeDropdown, - 'gke-machine-type-dropdown', - ); -}; - -const mountGkeSubmitButton = () => { - mountComponent('.js-gke-cluster-creation-submit-container', GkeSubmitButton, 'gke-submit-button'); -}; - -const gkeDropdownErrorHandler = () => { - createFlash({ - message: CONSTANTS.GCP_API_ERROR, - }); -}; - -const initializeGapiClient = (gapi) => () => { - const el = document.querySelector('.js-gke-cluster-creation'); - if (!el) return false; - - return gapi.client - .init({ - discoveryDocs: [ - CONSTANTS.GCP_API_CLOUD_BILLING_ENDPOINT, - CONSTANTS.GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT, - CONSTANTS.GCP_API_COMPUTE_ENDPOINT, - ], - }) - .then(() => { - gapi.client.setToken({ access_token: el.dataset.token }); - - mountGkeProjectIdDropdown(); - mountGkeZoneDropdown(); - mountGkeMachineTypeDropdown(); - mountGkeSubmitButton(); - }) - .catch(gkeDropdownErrorHandler); -}; - -const initGkeDropdowns = () => - gapiLoader() - .then((gapi) => gapi.load('client', initializeGapiClient(gapi))) - .catch(gkeDropdownErrorHandler); - -export default initGkeDropdowns; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/store/actions.js b/app/assets/javascripts/create_cluster/gke_cluster/store/actions.js deleted file mode 100644 index f4c35dafc22..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/store/actions.js +++ /dev/null @@ -1,99 +0,0 @@ -import gapiLoader from '../gapi_loader'; -import * as types from './mutation_types'; - -const gapiResourceListRequest = ({ resource, params, commit, mutation, payloadKey }) => - new Promise((resolve, reject) => { - const request = resource.list(params); - - return request.then( - (resp) => { - const { result } = resp; - - commit(mutation, result[payloadKey]); - - resolve(); - }, - (resp) => { - reject(resp); - }, - ); - }); - -export const setProject = ({ commit }, selectedProject) => { - commit(types.SET_PROJECT, selectedProject); -}; - -export const setZone = ({ commit }, selectedZone) => { - commit(types.SET_ZONE, selectedZone); -}; - -export const setMachineType = ({ commit }, selectedMachineType) => { - commit(types.SET_MACHINE_TYPE, selectedMachineType); -}; - -export const setIsValidatingProjectBilling = ({ commit }, isValidatingProjectBilling) => { - commit(types.SET_IS_VALIDATING_PROJECT_BILLING, isValidatingProjectBilling); -}; - -export const fetchProjects = ({ commit }) => - gapiLoader().then((gapi) => - gapiResourceListRequest({ - resource: gapi.client.cloudresourcemanager.projects, - params: {}, - commit, - mutation: types.SET_PROJECTS, - payloadKey: 'projects', - }), - ); - -export const validateProjectBilling = ({ dispatch, commit, state }) => - gapiLoader() - .then((gapi) => { - const request = gapi.client.cloudbilling.projects.getBillingInfo({ - name: `projects/${state.selectedProject.projectId}`, - }); - - commit(types.SET_ZONE, ''); - commit(types.SET_MACHINE_TYPE, ''); - - return request; - }) - .then( - (resp) => { - const { billingEnabled } = resp.result; - - commit(types.SET_PROJECT_BILLING_STATUS, Boolean(billingEnabled)); - dispatch('setIsValidatingProjectBilling', false); - }, - (errorResp) => { - dispatch('setIsValidatingProjectBilling', false); - return errorResp; - }, - ); - -export const fetchZones = ({ commit, state }) => - gapiLoader().then((gapi) => - gapiResourceListRequest({ - resource: gapi.client.compute.zones, - params: { - project: state.selectedProject.projectId, - }, - commit, - mutation: types.SET_ZONES, - payloadKey: 'items', - }), - ); - -export const fetchMachineTypes = ({ commit, state }) => - gapiLoader().then((gapi) => - gapiResourceListRequest({ - resource: gapi.client.compute.machineTypes, - params: { - project: state.selectedProject.projectId, - zone: state.selectedZone, - }, - commit, - mutation: types.SET_MACHINE_TYPES, - payloadKey: 'items', - }), - ); diff --git a/app/assets/javascripts/create_cluster/gke_cluster/store/getters.js b/app/assets/javascripts/create_cluster/gke_cluster/store/getters.js deleted file mode 100644 index 99f8393ffdb..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/store/getters.js +++ /dev/null @@ -1,5 +0,0 @@ -export const hasProject = (state) => Boolean(state.selectedProject.projectId); -export const hasZone = (state) => Boolean(state.selectedZone); -export const hasMachineType = (state) => Boolean(state.selectedMachineType); -export const hasValidData = (state, getters) => - Boolean(state.projectHasBillingEnabled) && getters.hasZone && getters.hasMachineType; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/store/index.js b/app/assets/javascripts/create_cluster/gke_cluster/store/index.js deleted file mode 100644 index 5f72060633e..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/store/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import * as actions from './actions'; -import * as getters from './getters'; -import mutations from './mutations'; -import createState from './state'; - -Vue.use(Vuex); - -export const createStore = () => - new Vuex.Store({ - actions, - getters, - mutations, - state: createState(), - }); - -export default createStore(); diff --git a/app/assets/javascripts/create_cluster/gke_cluster/store/mutation_types.js b/app/assets/javascripts/create_cluster/gke_cluster/store/mutation_types.js deleted file mode 100644 index 45a91efc2d9..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/store/mutation_types.js +++ /dev/null @@ -1,8 +0,0 @@ -export const SET_PROJECT = 'SET_PROJECT'; -export const SET_PROJECT_BILLING_STATUS = 'SET_PROJECT_BILLING_STATUS'; -export const SET_IS_VALIDATING_PROJECT_BILLING = 'SET_IS_VALIDATING_PROJECT_BILLING'; -export const SET_ZONE = 'SET_ZONE'; -export const SET_MACHINE_TYPE = 'SET_MACHINE_TYPE'; -export const SET_PROJECTS = 'SET_PROJECTS'; -export const SET_ZONES = 'SET_ZONES'; -export const SET_MACHINE_TYPES = 'SET_MACHINE_TYPES'; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/store/mutations.js b/app/assets/javascripts/create_cluster/gke_cluster/store/mutations.js deleted file mode 100644 index 88a2c1b630d..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/store/mutations.js +++ /dev/null @@ -1,28 +0,0 @@ -import * as types from './mutation_types'; - -export default { - [types.SET_PROJECT](state, selectedProject) { - Object.assign(state, { selectedProject }); - }, - [types.SET_IS_VALIDATING_PROJECT_BILLING](state, isValidatingProjectBilling) { - Object.assign(state, { isValidatingProjectBilling }); - }, - [types.SET_PROJECT_BILLING_STATUS](state, projectHasBillingEnabled) { - Object.assign(state, { projectHasBillingEnabled }); - }, - [types.SET_ZONE](state, selectedZone) { - Object.assign(state, { selectedZone }); - }, - [types.SET_MACHINE_TYPE](state, selectedMachineType) { - Object.assign(state, { selectedMachineType }); - }, - [types.SET_PROJECTS](state, projects) { - Object.assign(state, { projects }); - }, - [types.SET_ZONES](state, zones) { - Object.assign(state, { zones }); - }, - [types.SET_MACHINE_TYPES](state, machineTypes) { - Object.assign(state, { machineTypes }); - }, -}; diff --git a/app/assets/javascripts/create_cluster/gke_cluster/store/state.js b/app/assets/javascripts/create_cluster/gke_cluster/store/state.js deleted file mode 100644 index 9f3c473d4bc..00000000000 --- a/app/assets/javascripts/create_cluster/gke_cluster/store/state.js +++ /dev/null @@ -1,13 +0,0 @@ -export default () => ({ - selectedProject: { - projectId: '', - name: '', - }, - selectedZone: '', - selectedMachineType: '', - isValidatingProjectBilling: null, - projectHasBillingEnabled: null, - projects: [], - zones: [], - machineTypes: [], -}); diff --git a/app/assets/javascripts/create_cluster/init_create_cluster.js b/app/assets/javascripts/create_cluster/init_create_cluster.js deleted file mode 100644 index d367d7ec333..00000000000 --- a/app/assets/javascripts/create_cluster/init_create_cluster.js +++ /dev/null @@ -1,35 +0,0 @@ -import PersistentUserCallout from '~/persistent_user_callout'; -import initGkeDropdowns from './gke_cluster'; -import initGkeNamespace from './gke_cluster_namespace'; - -const newClusterViews = [':clusters:new', ':clusters:create_gcp', ':clusters:create_user']; - -const isProjectLevelCluster = (page) => page.startsWith('project:clusters'); - -export default (document) => { - const { page } = document.body.dataset; - const isNewClusterView = newClusterViews.some((view) => page.endsWith(view)); - - if (!isNewClusterView) { - return; - } - - const callout = document.querySelector('.gcp-signup-offer'); - PersistentUserCallout.factory(callout); - - initGkeDropdowns(); - - if (isProjectLevelCluster(page)) { - initGkeNamespace(); - } - - import(/* webpackChunkName: 'eks_cluster' */ '~/create_cluster/eks_cluster') - .then(({ default: initCreateEKSCluster }) => { - const el = document.querySelector('.js-create-eks-cluster-form-container'); - - if (el) { - initCreateEKSCluster(el); - } - }) - .catch(() => {}); -}; diff --git a/app/assets/javascripts/create_cluster/store/cluster_dropdown/actions.js b/app/assets/javascripts/create_cluster/store/cluster_dropdown/actions.js deleted file mode 100644 index 669b0dcc732..00000000000 --- a/app/assets/javascripts/create_cluster/store/cluster_dropdown/actions.js +++ /dev/null @@ -1,14 +0,0 @@ -import * as types from './mutation_types'; - -export default (fetchItems) => ({ - requestItems: ({ commit }) => commit(types.REQUEST_ITEMS), - receiveItemsSuccess: ({ commit }, payload) => commit(types.RECEIVE_ITEMS_SUCCESS, payload), - receiveItemsError: ({ commit }, payload) => commit(types.RECEIVE_ITEMS_ERROR, payload), - fetchItems: ({ dispatch }, payload) => { - dispatch('requestItems'); - - return fetchItems(payload) - .then((items) => dispatch('receiveItemsSuccess', { items })) - .catch((error) => dispatch('receiveItemsError', { error })); - }, -}); diff --git a/app/assets/javascripts/create_cluster/store/cluster_dropdown/getters.js b/app/assets/javascripts/create_cluster/store/cluster_dropdown/getters.js deleted file mode 100644 index e69de29bb2d..00000000000 --- a/app/assets/javascripts/create_cluster/store/cluster_dropdown/getters.js +++ /dev/null diff --git a/app/assets/javascripts/create_cluster/store/cluster_dropdown/index.js b/app/assets/javascripts/create_cluster/store/cluster_dropdown/index.js deleted file mode 100644 index de8cc44fa7c..00000000000 --- a/app/assets/javascripts/create_cluster/store/cluster_dropdown/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import actions from './actions'; -import * as getters from './getters'; -import mutations from './mutations'; -import state from './state'; - -const createStore = ({ fetchFn, initialState }) => ({ - actions: actions(fetchFn), - getters, - mutations, - state: Object.assign(state(), initialState || {}), -}); - -export default createStore; diff --git a/app/assets/javascripts/create_cluster/store/cluster_dropdown/mutation_types.js b/app/assets/javascripts/create_cluster/store/cluster_dropdown/mutation_types.js deleted file mode 100644 index 48959a73924..00000000000 --- a/app/assets/javascripts/create_cluster/store/cluster_dropdown/mutation_types.js +++ /dev/null @@ -1,3 +0,0 @@ -export const REQUEST_ITEMS = 'REQUEST_ITEMS'; -export const RECEIVE_ITEMS_SUCCESS = 'REQUEST_ITEMS_SUCCESS'; -export const RECEIVE_ITEMS_ERROR = 'RECEIVE_ITEMS_ERROR'; diff --git a/app/assets/javascripts/create_cluster/store/cluster_dropdown/mutations.js b/app/assets/javascripts/create_cluster/store/cluster_dropdown/mutations.js deleted file mode 100644 index d09689f1f6c..00000000000 --- a/app/assets/javascripts/create_cluster/store/cluster_dropdown/mutations.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as types from './mutation_types'; - -export default { - [types.REQUEST_ITEMS](state) { - state.isLoadingItems = true; - state.loadingItemsError = null; - }, - [types.RECEIVE_ITEMS_SUCCESS](state, { items }) { - state.isLoadingItems = false; - state.items = items; - }, - [types.RECEIVE_ITEMS_ERROR](state, { error }) { - state.isLoadingItems = false; - state.loadingItemsError = error; - }, -}; diff --git a/app/assets/javascripts/create_cluster/store/cluster_dropdown/state.js b/app/assets/javascripts/create_cluster/store/cluster_dropdown/state.js deleted file mode 100644 index b949a24216e..00000000000 --- a/app/assets/javascripts/create_cluster/store/cluster_dropdown/state.js +++ /dev/null @@ -1,5 +0,0 @@ -export default () => ({ - isLoadingItems: false, - items: [], - loadingItemsError: null, -}); diff --git a/app/assets/javascripts/environments/components/enable_review_app_modal.vue b/app/assets/javascripts/environments/components/enable_review_app_modal.vue index 4d43ee156fb..6343fe8702a 100644 --- a/app/assets/javascripts/environments/components/enable_review_app_modal.vue +++ b/app/assets/javascripts/environments/components/enable_review_app_modal.vue @@ -45,6 +45,8 @@ export default { copyToClipboardText: s__('EnableReviewApp|Copy snippet text'), title: s__('ReviewApp|Enable Review App'), }, + visualReviewsDocs: helpPagePath('ci/review_apps/index.md', { anchor: 'visual-reviews' }), + connectClusterDocs: helpPagePath('user/clusters/agent/index'), data() { const modalInfoCopyId = uniqueId('enable-review-app-copy-string-'); @@ -64,9 +66,6 @@ export default { except: - ${this.defaultBranchName}`; }, - visualReviewsDocs() { - return helpPagePath('ci/review_apps/index.md', { anchor: 'visual-reviews' }); - }, }, }; </script> @@ -88,11 +87,7 @@ export default { <strong>{{ content }}</strong> </template> <template #link="{ content }"> - <gl-link - href="https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html" - target="_blank" - >{{ content }}</gl-link - > + <gl-link :href="$options.connectClusterDocs" target="_blank">{{ content }}</gl-link> </template> </gl-sprintf> </p> @@ -134,7 +129,7 @@ export default { <strong>{{ content }}</strong> </template> <template #link="{ content }"> - <gl-link :href="visualReviewsDocs" target="_blank">{{ content }}</gl-link> + <gl-link :href="$options.visualReviewsDocs" target="_blank">{{ content }}</gl-link> </template> </gl-sprintf> </p> diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue index 9262a4e1e95..5455a034106 100644 --- a/app/assets/javascripts/import_entities/components/import_status.vue +++ b/app/assets/javascripts/import_entities/components/import_status.vue @@ -44,6 +44,11 @@ const STATUS_MAP = { text: __('Failed'), variant: 'danger', }, + [STATUSES.TIMEOUT]: { + icon: 'status-failed', + text: __('Timeout'), + variant: 'danger', + }, [STATUSES.CANCELLED]: { icon: 'status-stopped', text: __('Cancelled'), diff --git a/app/assets/javascripts/import_entities/constants.js b/app/assets/javascripts/import_entities/constants.js index 20a4d2d84b4..c470da21765 100644 --- a/app/assets/javascripts/import_entities/constants.js +++ b/app/assets/javascripts/import_entities/constants.js @@ -10,4 +10,5 @@ export const STATUSES = { NONE: 'none', SCHEDULING: 'scheduling', CANCELLED: 'cancelled', + TIMEOUT: 'timeout', }; diff --git a/app/assets/javascripts/import_entities/import_groups/utils.js b/app/assets/javascripts/import_entities/import_groups/utils.js index 1d0ab75e1cb..f896203ba60 100644 --- a/app/assets/javascripts/import_entities/import_groups/utils.js +++ b/app/assets/javascripts/import_entities/import_groups/utils.js @@ -10,7 +10,7 @@ export function getInvalidNameValidationMessage(importTarget) { } export function isFinished(group) { - return [STATUSES.FINISHED, STATUSES.FAILED].includes(group.progress?.status); + return [STATUSES.FINISHED, STATUSES.FAILED, STATUSES.TIMEOUT].includes(group.progress?.status); } export function isAvailableForImport(group) { diff --git a/app/assets/javascripts/pages/admin/clusters/index.js b/app/assets/javascripts/pages/admin/clusters/index.js deleted file mode 100644 index f398b1cee82..00000000000 --- a/app/assets/javascripts/pages/admin/clusters/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import initCreateCluster from '~/create_cluster/init_create_cluster'; - -initCreateCluster(document, gon); diff --git a/app/assets/javascripts/pages/groups/clusters/index.js b/app/assets/javascripts/pages/groups/clusters/index.js index 4d48bd4be2b..99fb7fa68a9 100644 --- a/app/assets/javascripts/pages/groups/clusters/index.js +++ b/app/assets/javascripts/pages/groups/clusters/index.js @@ -1,5 +1,3 @@ import initIntegrationForm from '~/clusters/forms/show/index'; -import initCreateCluster from '~/create_cluster/init_create_cluster'; -initCreateCluster(document, gon); initIntegrationForm(); diff --git a/app/assets/javascripts/pages/projects/clusters/index.js b/app/assets/javascripts/pages/projects/clusters/index.js deleted file mode 100644 index f398b1cee82..00000000000 --- a/app/assets/javascripts/pages/projects/clusters/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import initCreateCluster from '~/create_cluster/init_create_cluster'; - -initCreateCluster(document, gon); diff --git a/app/assets/javascripts/pages/projects/clusters/show/index.js b/app/assets/javascripts/pages/projects/clusters/show/index.js index 71ab5a0b19c..0b34f374abc 100644 --- a/app/assets/javascripts/pages/projects/clusters/show/index.js +++ b/app/assets/javascripts/pages/projects/clusters/show/index.js @@ -1,6 +1,6 @@ import ClustersBundle from '~/clusters/clusters_bundle'; import initIntegrationForm from '~/clusters/forms/show'; -import initGkeNamespace from '~/create_cluster/gke_cluster_namespace'; +import initGkeNamespace from '~/clusters/gke_cluster_namespace'; import initClusterHealth from './cluster_health'; new ClustersBundle(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue b/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue index 406081e4422..7c2a575bf93 100644 --- a/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue +++ b/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue @@ -19,7 +19,7 @@ export default { type: String, required: true, }, - runnerUrl: { + runnerPath: { type: String, required: false, default: null, @@ -66,7 +66,7 @@ export default { <runner-update-form :loading="loading" :runner="runner" - :runner-url="runnerUrl" + :runner-path="runnerPath" class="gl-my-5" /> </div> diff --git a/app/assets/javascripts/runner/admin_runner_edit/index.js b/app/assets/javascripts/runner/admin_runner_edit/index.js index 876422534c1..a2ac5731a62 100644 --- a/app/assets/javascripts/runner/admin_runner_edit/index.js +++ b/app/assets/javascripts/runner/admin_runner_edit/index.js @@ -12,7 +12,7 @@ export const initAdminRunnerEdit = (selector = '#js-admin-runner-edit') => { return null; } - const { runnerId, runnerUrl } = el.dataset; + const { runnerId, runnerPath } = el.dataset; const apolloProvider = new VueApollo({ defaultClient: createDefaultClient(), @@ -25,7 +25,7 @@ export const initAdminRunnerEdit = (selector = '#js-admin-runner-edit') => { return h(AdminRunnerEditApp, { props: { runnerId, - runnerUrl, + runnerPath, }, }); }, diff --git a/app/assets/javascripts/runner/admin_runner_show/index.js b/app/assets/javascripts/runner/admin_runner_show/index.js index f8a02ecb49a..ea455416648 100644 --- a/app/assets/javascripts/runner/admin_runner_show/index.js +++ b/app/assets/javascripts/runner/admin_runner_show/index.js @@ -1,11 +1,14 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; +import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage'; import AdminRunnerShowApp from './admin_runner_show_app.vue'; Vue.use(VueApollo); export const initAdminRunnerShow = (selector = '#js-admin-runner-show') => { + showAlertFromLocalStorage(); + const el = document.querySelector(selector); if (!el) { diff --git a/app/assets/javascripts/runner/components/runner_update_form.vue b/app/assets/javascripts/runner/components/runner_update_form.vue index 16381a0a853..a87976d0240 100644 --- a/app/assets/javascripts/runner/components/runner_update_form.vue +++ b/app/assets/javascripts/runner/components/runner_update_form.vue @@ -14,10 +14,12 @@ import { runnerToModel, } from 'ee_else_ce/runner/runner_update_form_utils'; import { createAlert, VARIANT_SUCCESS } from '~/flash'; +import { redirectTo } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import { captureException } from '~/runner/sentry_utils'; import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants'; import runnerUpdateMutation from '../graphql/details/runner_update.mutation.graphql'; +import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage'; export default { name: 'RunnerUpdateForm', @@ -46,7 +48,7 @@ export default { required: false, default: false, }, - runnerUrl: { + runnerPath: { type: String, required: false, default: null, @@ -85,24 +87,23 @@ export default { }); if (errors?.length) { - // Validation errors need not be thrown - createAlert({ message: errors[0] }); - return; + this.onError(errors[0]); + } else { + this.onSuccess(); } - - this.onSuccess(); } catch (error) { const { message } = error; - - createAlert({ message }); + this.onError(message); captureException({ error, component: this.$options.name }); - } finally { - this.saving = false; } }, onSuccess() { - createAlert({ message: __('Changes saved.'), variant: VARIANT_SUCCESS }); - this.model = runnerToModel(this.runner); + saveAlertToLocalStorage({ message: __('Changes saved.'), variant: VARIANT_SUCCESS }); + redirectTo(this.runnerPath); + }, + onError(message) { + this.saving = false; + createAlert({ message }); }, }, ACCESS_LEVEL_NOT_PROTECTED, @@ -210,7 +211,7 @@ export default { > {{ __('Save changes') }} </gl-button> - <gl-button :href="runnerUrl"> + <gl-button :href="runnerPath"> {{ __('Cancel') }} </gl-button> </div> diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue deleted file mode 100644 index afde0c81580..00000000000 --- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue +++ /dev/null @@ -1,18 +0,0 @@ -<script> -export default { - props: { - name: { - type: String, - required: true, - }, - value: { - type: [Number, String], - required: true, - }, - }, -}; -</script> - -<template> - <input :name="name" :value="value" type="hidden" /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue deleted file mode 100644 index edb5ffdc39c..00000000000 --- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue +++ /dev/null @@ -1,49 +0,0 @@ -<script> -import { GlIcon } from '@gitlab/ui'; -import { __ } from '~/locale'; - -export default { - components: { - GlIcon, - }, - props: { - placeholderText: { - type: String, - required: true, - default: __('Search'), - }, - focused: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { searchQuery: this.value }; - }, - watch: { - searchQuery(query) { - this.$emit('input', query); - }, - focused(val) { - if (val) { - this.$refs.searchInput.focus(); - } - }, - }, -}; -</script> - -<template> - <div class="dropdown-input"> - <input - ref="searchInput" - v-model="searchQuery" - :placeholder="placeholderText" - class="dropdown-input-field" - type="search" - autocomplete="off" - /> - <gl-icon name="search" class="dropdown-input-search" data-hidden="true" /> - </div> -</template> |