Skip to content
Snippets Groups Projects
Commit 7881eb30 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@12-6-stable-ee

parent 64b66e0c
No related branches found
No related tags found
No related merge requests found
Showing
with 217 additions and 167 deletions
Loading
Loading
@@ -4,6 +4,7 @@ import 'core-js/es/array/find';
import 'core-js/es/array/find-index';
import 'core-js/es/array/from';
import 'core-js/es/array/includes';
import 'core-js/es/number/is-integer';
import 'core-js/es/object/assign';
import 'core-js/es/object/values';
import 'core-js/es/object/entries';
Loading
Loading
<script>
import { GlLink } from '@gitlab/ui';
import { __, sprintf } from '../../locale';
import { GlLink, GlSprintf } from '@gitlab/ui';
import { __ } from '../../locale';
import createFlash from '../../flash';
import Api from '../../api';
import state from '../state';
Loading
Loading
@@ -9,6 +9,7 @@ import Dropdown from './dropdown.vue';
export default {
components: {
GlLink,
GlSprintf,
Dropdown,
},
props: {
Loading
Loading
@@ -38,15 +39,6 @@ export default {
selectedProject() {
return state.selectedProject;
},
noForkText() {
return sprintf(
__(
"To protect this issue's confidentiality, %{link_start}fork the project%{link_end} and set the forks visibility to private.",
),
{ link_start: `<a href="${this.newForkPath}" class="help-link">`, link_end: '</a>' },
false,
);
},
},
mounted() {
this.fetchProjects();
Loading
Loading
@@ -123,8 +115,20 @@ export default {
}}
</template>
<template v-else>
{{ __('No forks available to you.') }}<br />
<span v-html="noForkText"></span>
{{ __('No forks are available to you.') }}<br />
<gl-sprintf
:message="
__(
`To protect this issue's confidentiality, %{forkLink} and set the fork's visibility to private.`,
)
"
>
<template #forkLink>
<a :href="newForkPath" target="_blank" class="help-link">{{
__('fork this project')
}}</a>
</template>
</gl-sprintf>
</template>
<gl-link
:href="helpPagePath"
Loading
Loading
import $ from 'jquery';
import { rstrip } from './lib/utils/common_utils';
 
function openConfirmDangerModal($form, text) {
const $input = $('.js-confirm-danger-input');
function openConfirmDangerModal($form, $modal, text) {
const $input = $('.js-confirm-danger-input', $modal);
$input.val('');
 
$('.js-confirm-text').text(text || '');
$('#modal-confirm-danger').modal('show');
$('.js-confirm-text', $modal).text(text || '');
$modal.modal('show');
 
const confirmTextMatch = $('.js-confirm-danger-match').text();
const $submit = $('.js-confirm-danger-submit');
const confirmTextMatch = $('.js-confirm-danger-match', $modal).text();
const $submit = $('.js-confirm-danger-submit', $modal);
$submit.disable();
$input.focus();
 
$('.js-confirm-danger-input')
.off('input')
.on('input', function handleInput() {
const confirmText = rstrip($(this).val());
if (confirmText === confirmTextMatch) {
$submit.enable();
} else {
$submit.disable();
}
});
$('.js-confirm-danger-submit')
$input.off('input').on('input', function handleInput() {
const confirmText = rstrip($(this).val());
if (confirmText === confirmTextMatch) {
$submit.enable();
} else {
$submit.disable();
}
});
$('.js-confirm-danger-submit', $modal)
.off('click')
.on('click', () => $form.submit());
}
 
function getModal($btn) {
const $modal = $btn.prev('.modal');
if ($modal.length) {
return $modal;
}
return $('#modal-confirm-danger');
}
export default function initConfirmDangerModal() {
$(document).on('click', '.js-confirm-danger', e => {
e.preventDefault();
const $btn = $(e.target);
const $form = $btn.closest('form');
const text = $btn.data('confirmDangerMessage');
openConfirmDangerModal($form, text);
const checkFieldName = $btn.data('checkFieldName');
const checkFieldCompareValue = $btn.data('checkCompareValue');
const checkFieldVal = parseInt($(`[name="${checkFieldName}"]`).val(), 10);
if (!checkFieldName || checkFieldVal < checkFieldCompareValue) {
e.preventDefault();
const $form = $btn.closest('form');
const $modal = getModal($btn);
const text = $btn.data('confirmDangerMessage');
openConfirmDangerModal($form, $modal, text);
}
});
}
<script>
import { __ } from '~/locale';
import _ from 'underscore';
import { mapActions, mapState, mapGetters } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts';
import { __ } from '~/locale';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import { getDatesInRange } from '~/lib/utils/datetime_utility';
import { xAxisLabelFormatter, dateFormatter } from '../utils';
Loading
Loading
<script>
import $ from 'jquery';
import { GlIcon } from '@gitlab/ui';
import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue';
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
import { GlIcon } from '@gitlab/ui';
 
const toArray = value => [].concat(value);
const itemsProp = (items, prop) => items.map(item => item[prop]);
Loading
Loading
@@ -106,6 +107,7 @@ export default {
data() {
return {
searchQuery: '',
focusOnSearch: false,
};
},
computed: {
Loading
Loading
@@ -141,6 +143,18 @@ export default {
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() {
$(this.$refs.dropdown).off();
},
methods: {
getItemsOrEmptyList() {
return this.items || [];
Loading
Loading
@@ -170,7 +184,7 @@ export default {
 
<template>
<div>
<div class="js-gcp-machine-type-dropdown dropdown">
<div ref="dropdown" class="dropdown">
<dropdown-hidden-input :name="fieldName" :value="selectedItemsValues" />
<dropdown-button
:class="{ 'border-danger': hasErrors }"
Loading
Loading
@@ -179,7 +193,11 @@ export default {
:toggle-text="toggleText"
/>
<div class="dropdown-menu dropdown-select">
<dropdown-search-input v-model="searchQuery" :placeholder-text="searchFieldPlaceholder" />
<dropdown-search-input
v-model="searchQuery"
:focused="focusOnSearch"
:placeholder-text="searchFieldPlaceholder"
/>
<div class="dropdown-content">
<ul>
<li v-if="!results.length">
Loading
Loading
<script>
import { createNamespacedHelpers, mapState, mapActions } from 'vuex';
import { sprintf, s__ } from '~/locale';
import _ from 'underscore';
import { GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import ClusterFormDropdown from './cluster_form_dropdown.vue';
import { KUBERNETES_VERSIONS } from '../constants';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
Loading
Loading
@@ -22,10 +22,7 @@ const {
mapState: mapSecurityGroupsState,
mapActions: mapSecurityGroupsActions,
} = createNamespacedHelpers('securityGroups');
const {
mapState: mapInstanceTypesState,
mapActions: mapInstanceTypesActions,
} = createNamespacedHelpers('instanceTypes');
const { mapState: mapInstanceTypesState } = createNamespacedHelpers('instanceTypes');
 
export default {
components: {
Loading
Loading
@@ -265,12 +262,10 @@ export default {
mounted() {
this.fetchRegions();
this.fetchRoles();
this.fetchInstanceTypes();
},
methods: {
...mapActions([
'createCluster',
'signOut',
'setClusterName',
'setEnvironmentScope',
'setKubernetesVersion',
Loading
Loading
@@ -290,7 +285,6 @@ export default {
...mapRolesActions({ fetchRoles: 'fetchItems' }),
...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }),
...mapSecurityGroupsActions({ fetchSecurityGroups: 'fetchItems' }),
...mapInstanceTypesActions({ fetchInstanceTypes: 'fetchItems' }),
setRegionAndFetchVpcsAndKeyPairs(region) {
this.setRegion({ region });
this.setVpc({ vpc: null });
Loading
Loading
@@ -316,11 +310,6 @@ export default {
{{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }}
</h2>
<div class="mb-3" v-html="kubernetesIntegrationHelpText"></div>
<div class="mb-3">
<button class="btn btn-link js-sign-out" @click.prevent="signOut()">
{{ s__('ClusterIntegration|Select a different AWS role') }}
</button>
</div>
<div class="form-group">
<label class="label-bold" for="eks-cluster-name">{{
s__('ClusterIntegration|Kubernetes cluster name')
Loading
Loading
<script>
import { GlFormInput } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import _ from 'underscore';
import { mapState, mapActions } from 'vuex';
import { sprintf, s__, __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
 
Loading
Loading
@@ -28,7 +28,7 @@ export default {
},
data() {
return {
roleArn: '',
roleArn: this.$store.state.roleArn,
};
},
computed: {
Loading
Loading
Loading
Loading
@@ -12,20 +12,14 @@ export default el => {
kubernetesIntegrationHelpPath,
accountAndExternalIdsHelpPath,
createRoleArnHelpPath,
getRolesPath,
getRegionsPath,
getKeyPairsPath,
getVpcsPath,
getSubnetsPath,
getSecurityGroupsPath,
getInstanceTypesPath,
externalId,
accountId,
instanceTypes,
hasCredentials,
createRolePath,
createClusterPath,
signOutPath,
externalLinkIcon,
roleArn,
} = el.dataset;
 
return new Vue({
Loading
Loading
@@ -35,18 +29,10 @@ export default el => {
hasCredentials: parseBoolean(hasCredentials),
externalId,
accountId,
instanceTypes: JSON.parse(instanceTypes),
createRolePath,
createClusterPath,
signOutPath,
},
apiPaths: {
getRolesPath,
getRegionsPath,
getKeyPairsPath,
getVpcsPath,
getSubnetsPath,
getSecurityGroupsPath,
getInstanceTypesPath,
roleArn,
},
}),
components: {
Loading
Loading
import axios from '~/lib/utils/axios_utils';
export default apiPaths => ({
fetchRoles() {
return axios
.get(apiPaths.getRolesPath)
.then(({ data: { roles } }) =>
roles.map(({ role_name: name, arn: value }) => ({ name, value })),
);
},
fetchKeyPairs({ region }) {
return axios
.get(apiPaths.getKeyPairsPath, { params: { region } })
.then(({ data: { key_pairs: keyPairs } }) =>
keyPairs.map(({ key_name }) => ({ name: key_name, value: key_name })),
);
},
fetchRegions() {
return axios.get(apiPaths.getRegionsPath).then(({ data: { regions } }) =>
regions.map(({ region_name }) => ({
name: region_name,
value: region_name,
import AWS from 'aws-sdk/global';
import EC2 from 'aws-sdk/clients/ec2';
import IAM from 'aws-sdk/clients/iam';
const lookupVpcName = ({ Tags: tags, VpcId: id }) => {
const nameTag = tags.find(({ Key: key }) => key === 'Name');
return nameTag ? nameTag.Value : id;
};
export const DEFAULT_REGION = 'us-east-2';
export const setAWSConfig = ({ awsCredentials }) => {
AWS.config = {
...awsCredentials,
region: DEFAULT_REGION,
};
};
export const fetchRoles = () => {
const iam = new IAM();
return iam
.listRoles()
.promise()
.then(({ Roles: roles }) => roles.map(({ RoleName: name, Arn: value }) => ({ name, value })));
};
export const fetchRegions = () => {
const ec2 = new EC2();
return ec2
.describeRegions()
.promise()
.then(({ Regions: regions }) =>
regions.map(({ RegionName: name }) => ({
name,
value: name,
})),
);
},
fetchVpcs({ region }) {
return axios.get(apiPaths.getVpcsPath, { params: { region } }).then(({ data: { vpcs } }) =>
vpcs.map(({ vpc_id }) => ({
value: vpc_id,
name: vpc_id,
};
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),
})),
);
},
fetchSubnets({ vpc, region }) {
return axios
.get(apiPaths.getSubnetsPath, { params: { vpc_id: vpc, region } })
.then(({ data: { subnets } }) =>
subnets.map(({ subnet_id }) => ({ name: subnet_id, value: subnet_id })),
);
},
fetchSecurityGroups({ vpc, region }) {
return axios
.get(apiPaths.getSecurityGroupsPath, { params: { vpc_id: vpc, region } })
.then(({ data: { security_groups: securityGroups } }) =>
securityGroups.map(({ group_name: name, group_id: value }) => ({ name, value })),
);
},
fetchInstanceTypes() {
return axios
.get(apiPaths.getInstanceTypesPath)
.then(({ data: { instance_types: instanceTypes } }) =>
instanceTypes.map(({ instance_type_name }) => ({
name: instance_type_name,
value: instance_type_name,
})),
);
},
});
};
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 })),
);
};
import * as types from './mutation_types';
import { setAWSConfig } from '../services/aws_services_facade';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
 
const getErrorMessage = data => {
const errorKey = Object.keys(data)[0];
Loading
Loading
@@ -28,7 +30,7 @@ export const createRole = ({ dispatch, state: { createRolePath } }, payload) =>
role_arn: payload.roleArn,
role_external_id: payload.externalId,
})
.then(() => dispatch('createRoleSuccess'))
.then(({ data }) => dispatch('createRoleSuccess', convertObjectPropsToCamelCase(data)))
.catch(error => dispatch('createRoleError', { error }));
};
 
Loading
Loading
@@ -36,7 +38,8 @@ export const requestCreateRole = ({ commit }) => {
commit(types.REQUEST_CREATE_ROLE);
};
 
export const createRoleSuccess = ({ commit }) => {
export const createRoleSuccess = ({ commit }, awsCredentials) => {
setAWSConfig({ awsCredentials });
commit(types.CREATE_ROLE_SUCCESS);
};
 
Loading
Loading
@@ -117,9 +120,3 @@ export const setInstanceType = ({ commit }, payload) => {
export const setNodeCount = ({ commit }, payload) => {
commit(types.SET_NODE_COUNT, payload);
};
export const signOut = ({ commit, state: { signOutPath } }) =>
axios
.delete(signOutPath)
.then(() => commit(types.SIGN_OUT))
.catch(({ response: { data } }) => createFlash(getErrorMessage(data)));
Loading
Loading
@@ -3,11 +3,11 @@ import actions from './actions';
import mutations from './mutations';
import state from './state';
 
const createStore = fetchFn => ({
const createStore = ({ fetchFn, initialState }) => ({
actions: actions(fetchFn),
getters,
mutations,
state: state(),
state: Object.assign(state(), initialState || {}),
});
 
export default createStore;
Loading
Loading
@@ -6,12 +6,17 @@ import state from './state';
 
import clusterDropdownStore from './cluster_dropdown';
 
import awsServicesFactory from '../services/aws_services_facade';
import {
fetchRoles,
fetchRegions,
fetchKeyPairs,
fetchVpcs,
fetchSubnets,
fetchSecurityGroups,
} from '../services/aws_services_facade';
 
const createStore = ({ initialState, apiPaths }) => {
const awsServices = awsServicesFactory(apiPaths);
return new Vuex.Store({
const createStore = ({ initialState }) =>
new Vuex.Store({
actions,
getters,
mutations,
Loading
Loading
@@ -19,34 +24,33 @@ const createStore = ({ initialState, apiPaths }) => {
modules: {
roles: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchRoles),
...clusterDropdownStore({ fetchFn: fetchRoles }),
},
regions: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchRegions),
...clusterDropdownStore({ fetchFn: fetchRegions }),
},
keyPairs: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchKeyPairs),
...clusterDropdownStore({ fetchFn: fetchKeyPairs }),
},
vpcs: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchVpcs),
...clusterDropdownStore({ fetchFn: fetchVpcs }),
},
subnets: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchSubnets),
...clusterDropdownStore({ fetchFn: fetchSubnets }),
},
securityGroups: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchSecurityGroups),
...clusterDropdownStore({ fetchFn: fetchSecurityGroups }),
},
instanceTypes: {
namespaced: true,
...clusterDropdownStore(awsServices.fetchInstanceTypes),
...clusterDropdownStore({ initialState: { items: initialState.instanceTypes } }),
},
},
});
};
 
export default createStore;
Loading
Loading
@@ -13,7 +13,6 @@ export const SET_GITLAB_MANAGED_CLUSTER = 'SET_GITLAB_MANAGED_CLUSTER';
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 SIGN_OUT = 'SIGN_OUT';
export const REQUEST_CREATE_CLUSTER = 'REQUEST_CREATE_CLUSTER';
export const CREATE_CLUSTER_SUCCESS = 'CREATE_CLUSTER_SUCCESS';
export const CREATE_CLUSTER_ERROR = 'CREATE_CLUSTER_ERROR';
Loading
Loading
@@ -60,7 +60,4 @@ export default {
state.isCreatingCluster = false;
state.createClusterError = error;
},
[types.SIGN_OUT](state) {
state.hasCredentials = false;
},
};
Loading
Loading
@@ -12,6 +12,8 @@ export default () => ({
accountId: '',
externalId: '',
 
roleArn: '',
clusterName: '',
environmentScope: '*',
kubernetesVersion,
Loading
Loading
import _ from 'underscore';
import { GlLoadingIcon } from '@gitlab/ui';
import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue';
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
import { GlLoadingIcon } from '@gitlab/ui';
 
import store from '../store';
 
Loading
Loading
<script>
import { sprintf, s__ } from '~/locale';
import { mapState, mapGetters, mapActions } from 'vuex';
import { sprintf, s__ } from '~/locale';
 
import gkeDropdownMixin from './gke_dropdown_mixin';
 
Loading
Loading
<script>
import _ from 'underscore';
import { s__, sprintf } from '~/locale';
import { mapState, mapGetters, mapActions } from 'vuex';
import { s__, sprintf } from '~/locale';
 
import gkeDropdownMixin from './gke_dropdown_mixin';
 
Loading
Loading
<script>
import { sprintf, s__ } from '~/locale';
import { mapState, mapActions } from 'vuex';
import { sprintf, s__ } from '~/locale';
 
import gkeDropdownMixin from './gke_dropdown_mixin';
 
Loading
Loading
Loading
Loading
@@ -6,7 +6,7 @@ const newClusterViews = [':clusters:new', ':clusters:create_gcp', ':clusters:cre
 
const isProjectLevelCluster = page => page.startsWith('project:clusters');
 
export default (document, gon) => {
export default document => {
const { page } = document.body.dataset;
const isNewClusterView = newClusterViews.some(view => page.endsWith(view));
 
Loading
Loading
@@ -19,17 +19,15 @@ export default (document, gon) => {
 
initGkeDropdowns();
 
if (gon.features.createEksClusters) {
import(/* webpackChunkName: 'eks_cluster' */ '~/create_cluster/eks_cluster')
.then(({ default: initCreateEKSCluster }) => {
const el = document.querySelector('.js-create-eks-cluster-form-container');
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(() => {});
}
if (el) {
initCreateEKSCluster(el);
}
})
.catch(() => {});
 
if (isProjectLevelCluster(page)) {
initGkeNamespace();
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment