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

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

parent 50d93f8d
No related branches found
No related tags found
No related merge requests found
Showing
with 766 additions and 42 deletions
Loading
Loading
@@ -48,6 +48,16 @@ export default class BoardService {
return boardsStore.moveIssue(id, fromListId, toListId, moveBeforeId, moveAfterId);
}
 
moveMultipleIssues({
ids,
fromListId = null,
toListId = null,
moveBeforeId = null,
moveAfterId = null,
}) {
return boardsStore.moveMultipleIssues({ ids, fromListId, toListId, moveBeforeId, moveAfterId });
}
newIssue(id, issue) {
return boardsStore.newIssue(id, issue);
}
Loading
Loading
Loading
Loading
@@ -11,6 +11,7 @@ import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import eventHub from '../eventhub';
import { ListType } from '../constants';
 
const boardsStore = {
disabled: false,
Loading
Loading
@@ -39,6 +40,7 @@ const boardsStore = {
issue: {},
list: {},
},
multiSelect: { list: [] },
 
setEndpoints({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId, recentBoardsEndpoint }) {
const listsEndpointGenerate = `${listsEndpoint}/generate.json`;
Loading
Loading
@@ -51,7 +53,6 @@ const boardsStore = {
recentBoardsEndpoint: `${recentBoardsEndpoint}.json`,
};
},
create() {
this.state.lists = [];
this.filter.path = getUrlParamsArray().join('&');
Loading
Loading
@@ -134,6 +135,107 @@ const boardsStore = {
Object.assign(this.moving, { list, issue });
},
 
moveMultipleIssuesToList({ listFrom, listTo, issues, newIndex }) {
const issueTo = issues.map(issue => listTo.findIssue(issue.id));
const issueLists = _.flatten(issues.map(issue => issue.getLists()));
const listLabels = issueLists.map(list => list.label);
const hasMoveableIssues = _.compact(issueTo).length > 0;
if (!hasMoveableIssues) {
// Check if target list assignee is already present in this issue
if (
listTo.type === ListType.assignee &&
listFrom.type === ListType.assignee &&
issues.some(issue => issue.findAssignee(listTo.assignee))
) {
const targetIssues = issues.map(issue => listTo.findIssue(issue.id));
targetIssues.forEach(targetIssue => targetIssue.removeAssignee(listFrom.assignee));
} else if (listTo.type === 'milestone') {
const currentMilestones = issues.map(issue => issue.milestone);
const currentLists = this.state.lists
.filter(list => list.type === 'milestone' && list.id !== listTo.id)
.filter(list =>
list.issues.some(listIssue => issues.some(issue => listIssue.id === issue.id)),
);
issues.forEach(issue => {
currentMilestones.forEach(milestone => {
issue.removeMilestone(milestone);
});
});
issues.forEach(issue => {
issue.addMilestone(listTo.milestone);
});
currentLists.forEach(currentList => {
issues.forEach(issue => {
currentList.removeIssue(issue);
});
});
listTo.addMultipleIssues(issues, listFrom, newIndex);
} else {
// Add to new lists issues if it doesn't already exist
listTo.addMultipleIssues(issues, listFrom, newIndex);
}
} else {
listTo.updateMultipleIssues(issues, listFrom);
issues.forEach(issue => {
issue.removeLabel(listFrom.label);
});
}
if (listTo.type === ListType.closed && listFrom.type !== ListType.backlog) {
issueLists.forEach(list => {
issues.forEach(issue => {
list.removeIssue(issue);
});
});
issues.forEach(issue => {
issue.removeLabels(listLabels);
});
} else if (listTo.type === ListType.backlog && listFrom.type === ListType.assignee) {
issues.forEach(issue => {
issue.removeAssignee(listFrom.assignee);
});
issueLists.forEach(list => {
issues.forEach(issue => {
list.removeIssue(issue);
});
});
} else if (listTo.type === ListType.backlog && listFrom.type === ListType.milestone) {
issues.forEach(issue => {
issue.removeMilestone(listFrom.milestone);
});
issueLists.forEach(list => {
issues.forEach(issue => {
list.removeIssue(issue);
});
});
} else if (
this.shouldRemoveIssue(listFrom, listTo) &&
this.issuesAreContiguous(listFrom, issues)
) {
listFrom.removeMultipleIssues(issues);
}
},
issuesAreContiguous(list, issues) {
// When there's only 1 issue selected, we can return early.
if (issues.length === 1) return true;
// Create list of ids for issues involved.
const listIssueIds = list.issues.map(issue => issue.id);
const movedIssueIds = issues.map(issue => issue.id);
// Check if moved issue IDs is sub-array
// of source list issue IDs (i.e. contiguous selection).
return listIssueIds.join('|').includes(movedIssueIds.join('|'));
},
moveIssueToList(listFrom, listTo, issue, newIndex) {
const issueTo = listTo.findIssue(issue.id);
const issueLists = issue.getLists();
Loading
Loading
@@ -195,6 +297,17 @@ const boardsStore = {
 
list.moveIssue(issue, oldIndex, newIndex, beforeId, afterId);
},
moveMultipleIssuesInList({ list, issues, oldIndicies, newIndex, idArray }) {
const beforeId = parseInt(idArray[newIndex - 1], 10) || null;
const afterId = parseInt(idArray[newIndex + issues.length], 10) || null;
list.moveMultipleIssues({
issues,
oldIndicies,
newIndex,
moveBeforeId: beforeId,
moveAfterId: afterId,
});
},
findList(key, val, type = 'label') {
const filteredList = this.state.lists.filter(list => {
const byType = type
Loading
Loading
@@ -260,6 +373,10 @@ const boardsStore = {
}`;
},
 
generateMultiDragPath(boardId) {
return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues/bulk_move`;
},
all() {
return axios.get(this.state.endpoints.listsEndpoint);
},
Loading
Loading
@@ -309,6 +426,16 @@ const boardsStore = {
});
},
 
moveMultipleIssues({ ids, fromListId, toListId, moveBeforeId, moveAfterId }) {
return axios.put(this.generateMultiDragPath(this.state.endpoints.boardId), {
from_list_id: fromListId,
to_list_id: toListId,
move_before_id: moveBeforeId,
move_after_id: moveAfterId,
ids,
});
},
newIssue(id, issue) {
return axios.post(this.generateIssuesPath(id), {
issue,
Loading
Loading
@@ -379,6 +506,25 @@ const boardsStore = {
setCurrentBoard(board) {
this.state.currentBoard = board;
},
toggleMultiSelect(issue) {
const selectedIssueIds = this.multiSelect.list.map(issue => issue.id);
const index = selectedIssueIds.indexOf(issue.id);
if (index === -1) {
this.multiSelect.list.push(issue);
return;
}
this.multiSelect.list = [
...this.multiSelect.list.slice(0, index),
...this.multiSelect.list.slice(index + 1),
];
},
clearMultiSelect() {
this.multiSelect.list = [];
},
};
 
BoardsStoreEE.initEESpecific(boardsStore);
Loading
Loading
/* eslint-disable func-names, prefer-arrow-callback */
/* eslint-disable func-names */
 
import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility';
Loading
Loading
@@ -12,11 +12,11 @@ export default class BuildArtifacts {
}
// eslint-disable-next-line class-methods-use-this
disablePropagation() {
$('.top-block').on('click', '.download', function(e) {
return e.stopPropagation();
$('.top-block').on('click', '.download', e => {
e.stopPropagation();
});
return $('.tree-holder').on('click', 'tr[data-link] a', function(e) {
return e.stopImmediatePropagation();
return $('.tree-holder').on('click', 'tr[data-link] a', e => {
e.stopImmediatePropagation();
});
}
// eslint-disable-next-line class-methods-use-this
Loading
Loading
Loading
Loading
@@ -41,6 +41,8 @@ export default class Clusters {
managePrometheusPath,
clusterEnvironmentsPath,
hasRbac,
providerType,
preInstalledKnative,
clusterType,
clusterStatus,
clusterStatusReason,
Loading
Loading
@@ -50,6 +52,7 @@ export default class Clusters {
environmentsHelpPath,
clustersHelpPath,
deployBoardsHelpPath,
cloudRunHelpPath,
clusterId,
} = document.querySelector('.js-edit-cluster-form').dataset;
 
Loading
Loading
@@ -65,10 +68,13 @@ export default class Clusters {
environmentsHelpPath,
clustersHelpPath,
deployBoardsHelpPath,
cloudRunHelpPath,
);
this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
this.store.updateProviderType(providerType);
this.store.updatePreInstalledKnative(preInstalledKnative);
this.store.updateRbac(hasRbac);
this.service = new ClustersService({
endpoint: statusPath,
Loading
Loading
@@ -153,6 +159,9 @@ export default class Clusters {
ingressHelpPath: this.state.ingressHelpPath,
managePrometheusPath: this.state.managePrometheusPath,
ingressDnsHelpPath: this.state.ingressDnsHelpPath,
cloudRunHelpPath: this.state.cloudRunHelpPath,
providerType: this.state.providerType,
preInstalledKnative: this.state.preInstalledKnative,
rbac: this.state.rbac,
},
});
Loading
Loading
Loading
Loading
@@ -78,6 +78,10 @@ export default {
required: false,
default: false,
},
installedVia: {
type: String,
required: false,
},
version: {
type: String,
required: false,
Loading
Loading
@@ -311,6 +315,11 @@ export default {
>
<span v-else class="js-cluster-application-title">{{ title }}</span>
</strong>
<span
v-if="installedVia"
class="js-cluster-application-installed-via"
v-html="installedVia"
></span>
<slot name="description"></slot>
<div v-if="hasError" class="cluster-application-error text-danger prepend-top-10">
<p class="js-cluster-application-general-error-message append-bottom-0">
Loading
Loading
Loading
Loading
@@ -16,7 +16,7 @@ import { s__, sprintf } from '../../locale';
import applicationRow from './application_row.vue';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import KnativeDomainEditor from './knative_domain_editor.vue';
import { CLUSTER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '~/clusters/event_hub';
 
Loading
Loading
@@ -54,11 +54,26 @@ export default {
required: false,
default: '',
},
cloudRunHelpPath: {
type: String,
required: false,
default: '',
},
managePrometheusPath: {
type: String,
required: false,
default: '',
},
providerType: {
type: String,
required: false,
default: '',
},
preInstalledKnative: {
type: Boolean,
required: false,
default: false,
},
rbac: {
type: Boolean,
required: false,
Loading
Loading
@@ -156,6 +171,25 @@ export default {
knative() {
return this.applications.knative;
},
cloudRun() {
return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative;
},
installedVia() {
if (this.cloudRun) {
return sprintf(
_.escape(s__(`ClusterIntegration|installed via %{installed_via}`)),
{
installed_via: `<a href="${
this.cloudRunHelpPath
}" target="_blank" rel="noopener noreferrer">${_.escape(
s__('ClusterIntegration|Cloud Run'),
)}</a>`,
},
false,
);
}
return null;
},
},
created() {
this.helmInstallIllustration = helmInstallIllustration;
Loading
Loading
@@ -260,7 +294,7 @@ export default {
<span class="input-group-append">
<clipboard-button
:text="ingressExternalEndpoint"
:title="s__('ClusterIntegration|Copy Ingress Endpoint to clipboard')"
:title="s__('ClusterIntegration|Copy Ingress Endpoint')"
class="input-group-text js-clipboard-btn"
/>
</span>
Loading
Loading
@@ -438,7 +472,7 @@ export default {
<span class="input-group-btn">
<clipboard-button
:text="jupyterHostname"
:title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')"
:title="s__('ClusterIntegration|Copy Jupyter Hostname')"
class="js-clipboard-btn"
/>
</span>
Loading
Loading
@@ -468,6 +502,7 @@ export default {
:installed="applications.knative.installed"
:install-failed="applications.knative.installFailed"
:install-application-request-params="{ hostname: applications.knative.hostname }"
:installed-via="installedVia"
:uninstallable="applications.knative.uninstallable"
:uninstall-successful="applications.knative.uninstallSuccessful"
:uninstall-failed="applications.knative.uninstallFailed"
Loading
Loading
@@ -499,7 +534,7 @@ export default {
</p>
 
<knative-domain-editor
v-if="knative.installed || (helmInstalled && rbac)"
v-if="(knative.installed || (helmInstalled && rbac)) && !preInstalledKnative"
:knative="knative"
:ingress-dns-help-path="ingressDnsHelpPath"
@save="saveKnativeDomain"
Loading
Loading
Loading
Loading
@@ -103,7 +103,7 @@ export default {
<span class="input-group-append">
<clipboard-button
:text="knativeExternalEndpoint"
:title="s__('ClusterIntegration|Copy Knative Endpoint to clipboard')"
:title="s__('ClusterIntegration|Copy Knative Endpoint')"
class="input-group-text js-knative-endpoint-clipboard-btn"
/>
</span>
Loading
Loading
Loading
Loading
@@ -5,8 +5,14 @@ import trackUninstallButtonClickMixin from 'ee_else_ce/clusters/mixins/track_uni
import { HELM, INGRESS, CERT_MANAGER, PROMETHEUS, RUNNER, KNATIVE, JUPYTER } from '../constants';
 
const CUSTOM_APP_WARNING_TEXT = {
[HELM]: s__(
'ClusterIntegration|The associated Tiller pod will be deleted and cannot be restored.',
[HELM]: sprintf(
s__(
'ClusterIntegration|The associated Tiller pod, the %{gitlabManagedAppsNamespace} namespace, and all of its resources will be deleted and cannot be restored.',
),
{
gitlabManagedAppsNamespace: '<code>gitlab-managed-apps</code>',
},
false,
),
[INGRESS]: s__(
'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.',
Loading
Loading
@@ -76,6 +82,7 @@ export default {
:modal-id="modalId"
:title="title"
@ok="confirmUninstall()"
>{{ warningText }} {{ customAppWarningText }}</gl-modal
>
{{ warningText }} <span v-html="customAppWarningText"></span>
</gl-modal>
</template>
Loading
Loading
@@ -5,6 +5,11 @@ export const CLUSTER_TYPE = {
PROJECT: 'project_type',
};
 
// These need to match the available providers in app/models/clusters/providers/
export const PROVIDER_TYPE = {
GCP: 'gcp',
};
// These need to match what is returned from the server
export const APPLICATION_STATUS = {
NO_STATUS: null,
Loading
Loading
@@ -19,6 +24,7 @@ export const APPLICATION_STATUS = {
UNINSTALLING: 'uninstalling',
UNINSTALL_ERRORED: 'uninstall_errored',
ERROR: 'errored',
PRE_INSTALLED: 'pre_installed',
};
 
/*
Loading
Loading
@@ -29,6 +35,7 @@ export const APPLICATION_INSTALLED_STATUSES = [
APPLICATION_STATUS.INSTALLED,
APPLICATION_STATUS.UPDATING,
APPLICATION_STATUS.UNINSTALLING,
APPLICATION_STATUS.PRE_INSTALLED,
];
 
// These are only used client-side
Loading
Loading
Loading
Loading
@@ -13,6 +13,7 @@ const {
UPDATE_ERRORED,
UNINSTALLING,
UNINSTALL_ERRORED,
PRE_INSTALLED,
} = APPLICATION_STATUS;
 
const applicationStateMachine = {
Loading
Loading
@@ -63,6 +64,9 @@ const applicationStateMachine = {
uninstallFailed: true,
},
},
[PRE_INSTALLED]: {
target: PRE_INSTALLED,
},
},
},
[NOT_INSTALLABLE]: {
Loading
Loading
@@ -123,6 +127,27 @@ const applicationStateMachine = {
},
},
},
[PRE_INSTALLED]: {
on: {
[UPDATE_EVENT]: {
target: UPDATING,
effects: {
updateFailed: false,
updateSuccessful: false,
},
},
[NOT_INSTALLABLE]: {
target: NOT_INSTALLABLE,
},
[UNINSTALL_EVENT]: {
target: UNINSTALLING,
effects: {
uninstallFailed: false,
uninstallSuccessful: false,
},
},
},
},
[UPDATING]: {
on: {
[UPDATED]: {
Loading
Loading
Loading
Loading
@@ -35,7 +35,10 @@ export default class ClusterStore {
environmentsHelpPath: null,
clustersHelpPath: null,
deployBoardsHelpPath: null,
cloudRunHelpPath: null,
status: null,
providerType: null,
preInstalledKnative: false,
rbac: false,
statusReason: null,
applications: {
Loading
Loading
@@ -95,6 +98,7 @@ export default class ClusterStore {
environmentsHelpPath,
clustersHelpPath,
deployBoardsHelpPath,
cloudRunHelpPath,
) {
this.state.helpPath = helpPath;
this.state.ingressHelpPath = ingressHelpPath;
Loading
Loading
@@ -102,6 +106,7 @@ export default class ClusterStore {
this.state.environmentsHelpPath = environmentsHelpPath;
this.state.clustersHelpPath = clustersHelpPath;
this.state.deployBoardsHelpPath = deployBoardsHelpPath;
this.state.cloudRunHelpPath = cloudRunHelpPath;
}
 
setManagePrometheusPath(managePrometheusPath) {
Loading
Loading
@@ -112,6 +117,14 @@ export default class ClusterStore {
this.state.status = status;
}
 
updateProviderType(providerType) {
this.state.providerType = providerType;
}
updatePreInstalledKnative(preInstalledKnative) {
this.state.preInstalledKnative = parseBoolean(preInstalledKnative);
}
updateRbac(rbac) {
this.state.rbac = parseBoolean(rbac);
}
Loading
Loading
/* eslint-disable func-names, no-var, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, one-var, no-return-assign, no-unused-expressions, no-sequences */
/* eslint-disable func-names, no-var, no-else-return, consistent-return, one-var, no-return-assign, no-unused-expressions, no-sequences */
 
import $ from 'jquery';
 
Loading
Loading
@@ -13,14 +13,14 @@ export default class ImageFile {
$('.two-up.view .frame.deleted img', this.file),
(function(_this) {
return function() {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function() {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), () => {
_this.initViewModes();
 
// Load two-up view after images are loaded
// so that we can display the correct width and height information
const $images = $('.two-up.view img', _this.file);
 
$images.waitForImages(function() {
$images.waitForImages(() => {
_this.initView('two-up');
});
});
Loading
Loading
@@ -49,13 +49,13 @@ export default class ImageFile {
activateViewMode(viewMode) {
$('.view-modes-menu li', this.file)
.removeClass('active')
.filter('.' + viewMode)
.filter(`.${viewMode}`)
.addClass('active');
return $('.view:visible:not(.' + viewMode + ')', this.file).fadeOut(
return $(`.view:visible:not(.${viewMode})`, this.file).fadeOut(
200,
(function(_this) {
return function() {
$('.view.' + viewMode, _this.file).fadeIn(200);
$(`.view.${viewMode}`, _this.file).fadeIn(200);
return _this.initView(viewMode);
};
})(this),
Loading
Loading
@@ -138,9 +138,9 @@ export default class ImageFile {
return $(this).width(availWidth / 2);
}
});
return _this.requestImageInfo($('img', wrap), function(width, height) {
$('.image-info .meta-width', wrap).text(width + 'px');
$('.image-info .meta-height', wrap).text(height + 'px');
return _this.requestImageInfo($('img', wrap), (width, height) => {
$('.image-info .meta-width', wrap).text(`${width}px`);
$('.image-info .meta-height', wrap).text(`${height}px`);
return $('.image-info', wrap).removeClass('hide');
});
};
Loading
Loading
@@ -175,7 +175,7 @@ export default class ImageFile {
 
wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
 
_this.initDraggable($swipeBar, wrapPadding, function(e, left) {
_this.initDraggable($swipeBar, wrapPadding, (e, left) => {
if (left > 0 && left < $swipeFrame.width() - wrapPadding * 2) {
$swipeWrap.width(maxWidth + 1 - left);
$swipeBar.css('left', left);
Loading
Loading
@@ -215,7 +215,7 @@ export default class ImageFile {
$frameAdded.css('opacity', 1);
framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
 
_this.initDraggable($dragger, framePadding, function(e, left) {
_this.initDraggable($dragger, framePadding, (e, left) => {
var opacity = left / dragTrackWidth;
 
if (opacity >= 0 && opacity <= 1) {
Loading
Loading
import Vue from 'vue';
import '../vue_shared/vue_resource_interceptor';
import GlFeatureFlagsPlugin from '~/vue_shared/gl_feature_flags_plugin';
 
if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false;
}
Vue.use(GlFeatureFlagsPlugin);
Loading
Loading
@@ -3,6 +3,8 @@ import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_searc
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
 
const findItem = (items, valueProp, value) => items.find(item => item[valueProp] === value);
export default {
components: {
DropdownButton,
Loading
Loading
@@ -26,7 +28,7 @@ export default {
default: '',
},
value: {
type: Object,
type: [Object, String],
required: false,
default: () => null,
},
Loading
Loading
@@ -93,8 +95,8 @@ export default {
},
data() {
return {
selectedItem: findItem(this.items, this.value),
searchQuery: '',
selectedItem: null,
};
},
computed: {
Loading
Loading
@@ -127,10 +129,15 @@ export default {
return (this.selectedItem && this.selectedItem[this.valueProperty]) || '';
},
},
watch: {
value(value) {
this.selectedItem = findItem(this.items, this.valueProperty, value);
},
},
methods: {
select(item) {
this.selectedItem = item;
this.$emit('input', item);
this.$emit('input', item[this.valueProperty]);
},
},
};
Loading
Loading
Loading
Loading
@@ -7,8 +7,23 @@ export default {
ServiceCredentialsForm,
EksClusterConfigurationForm,
},
props: {
gitlabManagedClusterHelpPath: {
type: String,
required: true,
},
kubernetesIntegrationHelpPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<eks-cluster-configuration-form />
<div class="js-create-eks-cluster">
<eks-cluster-configuration-form
:gitlab-managed-cluster-help-path="gitlabManagedClusterHelpPath"
:kubernetes-integration-help-path="kubernetesIntegrationHelpPath"
/>
</div>
</template>
<script>
import RoleNameDropdown from './role_name_dropdown.vue';
import SecurityGroupDropdown from './security_group_dropdown.vue';
import SubnetDropdown from './subnet_dropdown.vue';
import VPCDropdown from './vpc_dropdown.vue';
import { createNamespacedHelpers, mapState, mapActions } from 'vuex';
import { sprintf, s__ } from '~/locale';
import _ from 'underscore';
import { GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import ClusterFormDropdown from './cluster_form_dropdown.vue';
import RegionDropdown from './region_dropdown.vue';
import { KUBERNETES_VERSIONS } from '../constants';
const { mapState: mapRolesState, mapActions: mapRolesActions } = createNamespacedHelpers('roles');
const { mapState: mapRegionsState, mapActions: mapRegionsActions } = createNamespacedHelpers(
'regions',
);
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');
 
export default {
components: {
RoleNameDropdown,
SecurityGroupDropdown,
SubnetDropdown,
VPCDropdown,
ClusterFormDropdown,
RegionDropdown,
GlFormInput,
GlFormCheckbox,
},
props: {
gitlabManagedClusterHelpPath: {
type: String,
required: true,
},
kubernetesIntegrationHelpPath: {
type: String,
required: true,
},
},
computed: {
...mapState([
'clusterName',
'environmentScope',
'kubernetesVersion',
'selectedRegion',
'selectedKeyPair',
'selectedVpc',
'selectedSubnet',
'selectedRole',
'selectedSecurityGroup',
'gitlabManagedCluster',
]),
...mapRolesState({
roles: 'items',
isLoadingRoles: 'isLoadingItems',
loadingRolesError: 'loadingItemsError',
}),
...mapRegionsState({
regions: 'items',
isLoadingRegions: 'isLoadingItems',
loadingRegionsError: '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',
}),
kubernetesVersions() {
return KUBERNETES_VERSIONS;
},
vpcDropdownDisabled() {
return !this.selectedRegion;
},
keyPairDropdownDisabled() {
return !this.selectedRegion;
},
subnetDropdownDisabled() {
return !this.selectedVpc;
},
securityGroupDropdownDisabled() {
return !this.selectedVpc;
},
kubernetesIntegrationHelpText() {
const escapedUrl = _.escape(this.kubernetesIntegrationHelpPath);
return sprintf(
s__(
'ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration.',
),
{
link_start: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
link_end: '</a>',
},
false,
);
},
roleDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
keyPairDropdownHelpText() {
return sprintf(
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 %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
vpcDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/vpc/home?#vpc" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
subnetDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Choose the %{startLink}subnets%{endLink} in your VPC where your worker nodes will run.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/vpc/home?#subnets" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
securityGroupDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Choose the %{startLink}security groups%{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/vpc/home?#securityGroups" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
gitlabManagedHelpText() {
const escapedUrl = _.escape(this.gitlabManagedClusterHelpPath);
return sprintf(
s__(
'ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}',
),
{
startLink: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
endLink: '</a>',
},
false,
);
},
},
mounted() {
this.fetchRegions();
this.fetchRoles();
},
methods: {
...mapActions([
'setClusterName',
'setEnvironmentScope',
'setKubernetesVersion',
'setRegion',
'setVpc',
'setSubnet',
'setRole',
'setKeyPair',
'setSecurityGroup',
'setGitlabManagedCluster',
]),
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
...mapVpcActions({ fetchVpcs: 'fetchItems' }),
...mapSubnetActions({ fetchSubnets: 'fetchItems' }),
...mapRolesActions({ fetchRoles: 'fetchItems' }),
...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }),
...mapSecurityGroupsActions({ fetchSecurityGroups: 'fetchItems' }),
setRegionAndFetchVpcsAndKeyPairs(region) {
this.setRegion({ region });
this.fetchVpcs({ region });
this.fetchKeyPairs({ region });
},
setVpcAndFetchSubnets(vpc) {
this.setVpc({ vpc });
this.fetchSubnets({ vpc });
this.fetchSecurityGroups({ vpc });
},
},
};
</script>
<template>
<form name="eks-cluster-configuration-form">
<h2>
{{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }}
</h2>
<p v-html="kubernetesIntegrationHelpText"></p>
<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 })"
/>
<p class="form-text text-muted" v-html="roleDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Role name') }}</label>
<cluster-form-dropdown
field-id="eks-role"
field-name="eks-role"
:input="selectedRole"
:items="roles"
:loading="isLoadingRoles"
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
:placeholder="s__('ClusterIntergation|Select role name')"
: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" v-html="roleDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Region') }}</label>
<region-dropdown
:value="selectedRegion"
:regions="regions"
:error="loadingRegionsError"
:loading="isLoadingRegions"
@input="setRegionAndFetchVpcsAndKeyPairs($event)"
/>
</div>
<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"
:input="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__('ClusterIntergation|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" v-html="keyPairDropdownHelpText"></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"
:input="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__('ClusterIntergation|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" v-html="vpcDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnet') }}</label>
<cluster-form-dropdown
field-id="eks-subnet"
field-name="eks-subnet"
:input="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__('ClusterIntergation|Select a subnet')"
:search-field-placeholder="s__('ClusterIntegration|Search subnets')"
:empty-text="s__('ClusterIntegration|No subnet found')"
:has-errors="Boolean(loadingSubnetsError)"
:error-message="s__('ClusterIntegration|Could not load subnets for the selected VPC')"
@input="setSubnet({ subnet: $event })"
/>
<p class="form-text text-muted" v-html="subnetDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-security-group">{{
s__('ClusterIntegration|Security groups')
}}</label>
<cluster-form-dropdown
field-id="eks-security-group"
field-name="eks-security-group"
:input="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__('ClusterIntergation|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" v-html="securityGroupDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" name="role" for="eks-role">
{{ s__('ClusterIntegration|Role name') }}
</label>
<role-name-dropdown />
<gl-form-checkbox
:checked="gitlabManagedCluster"
@input="setGitlabManagedCluster({ gitlabManagedCluster: $event })"
>{{ s__('ClusterIntegration|GitLab-managed cluster') }}</gl-form-checkbox
>
<p class="form-text text-muted" v-html="gitlabManagedHelpText"></p>
</div>
</form>
</template>
Loading
Loading
@@ -8,7 +8,7 @@ export default {
ClusterFormDropdown,
},
props: {
roles: {
regions: {
type: Array,
required: false,
default: () => [],
Loading
Loading
@@ -18,16 +18,22 @@ export default {
required: false,
default: false,
},
error: {
type: Object,
required: false,
default: null,
},
},
computed: {
hasErrors() {
return Boolean(this.error);
},
helpText() {
return sprintf(
s__(
'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
s__('ClusterIntegration|Learn more about %{startLink}Regions%{endLink}.'),
{
startLink:
'<a href="https://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
'<a href="https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
Loading
Loading
@@ -39,14 +45,18 @@ export default {
<template>
<div>
<cluster-form-dropdown
field-id="eks-role-name"
field-name="eks-role-name"
:items="roles"
field-id="eks-region"
field-name="eks-region"
:items="regions"
:loading="loading"
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
:placeholder="s__('ClusterIntergation|Select role name')"
:search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')"
:empty-text="s__('ClusterIntegration|No IAM Roles found')"
:loading-text="s__('ClusterIntegration|Loading Regions')"
:placeholder="s__('ClusterIntergation|Select a region')"
:search-field-placeholder="s__('ClusterIntegration|Search regions')"
:empty-text="s__('ClusterIntegration|No region found')"
:has-errors="hasErrors"
:error-message="s__('ClusterIntegration|Could not load regions from your AWS account')"
v-bind="$attrs"
v-on="$listeners"
/>
<p class="form-text text-muted" v-html="helpText"></p>
</div>
Loading
Loading
// eslint-disable-next-line import/prefer-default-export
export const KUBERNETES_VERSIONS = [
{ name: '1.14', value: '1.14' },
{ name: '1.13', value: '1.13' },
{ name: '1.12', value: '1.12' },
{ name: '1.11', value: '1.11' },
];
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