Commit 4203215d authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 325318e2
......@@ -8,14 +8,7 @@ import Flash from '../flash';
import Poll from '../lib/utils/poll';
import initSettingsPanels from '../settings_panels';
import eventHub from './event_hub';
import {
APPLICATION_STATUS,
INGRESS,
INGRESS_DOMAIN_SUFFIX,
CROSSPLANE,
KNATIVE,
FLUENTD,
} from './constants';
import { APPLICATION_STATUS, CROSSPLANE, KNATIVE, FLUENTD } from './constants';
import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue';
......@@ -120,10 +113,6 @@ export default class Clusters {
this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason');
this.successApplicationContainer = document.querySelector('.js-cluster-application-notice');
this.tokenField = document.querySelector('.js-cluster-token');
this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text');
this.ingressDomainSnippet =
this.ingressDomainHelpText &&
this.ingressDomainHelpText.querySelector('.js-ingress-domain-snippet');
initProjectSelectDropdown();
Clusters.initDismissableCallout();
......@@ -327,13 +316,6 @@ export default class Clusters {
this.checkForNewInstalls(prevApplicationMap, this.store.state.applications);
this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason);
if (this.ingressDomainHelpText) {
this.toggleIngressDomainHelpText(
prevApplicationMap[INGRESS],
this.store.state.applications[INGRESS],
);
}
if (this.store.state.applications[KNATIVE]?.status === APPLICATION_STATUS.INSTALLED) {
initServerlessSurveyBanner();
}
......@@ -505,13 +487,6 @@ export default class Clusters {
});
}
toggleIngressDomainHelpText({ externalIp }, { externalIp: newExternalIp }) {
if (externalIp !== newExternalIp) {
this.ingressDomainHelpText.classList.toggle('hide', !newExternalIp);
this.ingressDomainSnippet.textContent = `${newExternalIp}${INGRESS_DOMAIN_SUFFIX}`;
}
}
saveKnativeDomain(data) {
const appId = data.id;
this.store.updateApplication(appId);
......
<script>
import { GlFormGroup, GlToggle, GlTooltipDirective } from '@gitlab/ui';
import {
GlFormGroup,
GlFormInput,
GlToggle,
GlTooltipDirective,
GlSprintf,
GlLink,
GlButton,
} from '@gitlab/ui';
import { mapState } from 'vuex';
export default {
components: {
GlFormGroup,
GlToggle,
GlFormInput,
GlSprintf,
GlLink,
GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
},
inject: {
autoDevopsHelpPath: {
type: String,
},
externalEndpointHelpPath: {
type: String,
},
},
data() {
return {
toggleEnabled: true,
envScope: '*',
baseDomainField: '',
externalIp: '',
};
},
computed: {
...mapState(['enabled', 'editable']),
...mapState([
'enabled',
'editable',
'environmentScope',
'baseDomain',
'applicationIngressExternalIp',
]),
canSubmit() {
return (
this.enabled !== this.toggleEnabled ||
this.environmentScope !== this.envScope ||
this.baseDomain !== this.baseDomainField
);
},
},
mounted() {
this.toggleEnabled = this.enabled;
this.envScope = this.environmentScope;
this.baseDomainField = this.baseDomain;
this.externalIp = this.applicationIngressExternalIp;
},
};
</script>
<template>
<div class="d-flex align-items-center">
<div class="d-flex gl-flex-direction-column">
<gl-form-group>
<div class="gl-display-flex gl-align-items-center">
<h4 class="gl-pr-3 gl-m-0 ">{{ s__('ClusterIntegration|GitLab Integration') }}</h4>
<input
id="cluster_enabled"
class="js-project-feature-toggle-input"
type="hidden"
:value="toggleEnabled"
name="cluster[enabled]"
/>
<div id="tooltipcontainer" class="js-cluster-enable-toggle-area">
<h4 class="gl-pr-3 gl-m-0">{{ s__('ClusterIntegration|GitLab Integration') }}</h4>
<div class="js-cluster-enable-toggle-area">
<gl-toggle
id="toggleCluster"
v-model="toggleEnabled"
v-gl-tooltip:tooltipcontainer
name="cluster[enabled]"
class="gl-mb-0 js-project-feature-toggle"
data-qa-selector="integration_status_toggle"
:aria-describedby="__('Toggle Kubernetes cluster')"
aria-describedby="toggleCluster"
:disabled="!editable"
:is_checked="toggleEnabled"
:title="
s__(
'ClusterIntegration|Enable or disable GitLab\'s connection to your Kubernetes cluster.',
......@@ -54,5 +88,76 @@ export default {
</div>
</div>
</gl-form-group>
<gl-form-group
:label="s__('ClusterIntegration|Environment scope')"
label-size="sm"
label-for="cluster_environment_scope"
:description="
s__('ClusterIntegration|Choose which of your environments will use this cluster.')
"
>
<gl-form-input
id="cluster_environment_scope"
v-model="envScope"
name="cluster[environment_scope]"
class="col-md-6"
type="text"
/>
</gl-form-group>
<gl-form-group
:label="s__('ClusterIntegration|Base domain')"
label-size="sm"
label-for="cluster_base_domain"
>
<gl-form-input
id="cluster_base_domain"
v-model="baseDomainField"
name="cluster[base_domain]"
data-qa-selector="base_domain_field"
class="col-md-6"
type="text"
/>
<div class="form-text text-muted inline">
<gl-sprintf
:message="
s__(
'ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. ',
)
"
>
<template #link="{ content }">
<gl-link :href="autoDevopsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
<div v-if="applicationIngressExternalIp" class="js-ingress-domain-help-text inline">
{{ s__('ClusterIntegration|Alternatively, ') }}
<gl-sprintf :message="s__('ClusterIntegration|%{externalIp}.nip.io')">
<template #externalIp>{{ externalIp }}</template>
</gl-sprintf>
{{ s__('ClusterIntegration|can be used instead of a custom domain. ') }}
</div>
<gl-sprintf
class="inline"
:message="s__('ClusterIntegration|%{linkStart}More information%{linkEnd}')"
>
<template #link="{ content }">
<gl-link :href="externalEndpointHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>
</gl-form-group>
<div v-if="editable" class="form group gl-display-flex gl-justify-content-end">
<gl-button
category="primary"
variant="success"
type="submit"
:disabled="!canSubmit"
:aria-disabled="!canSubmit"
data-qa-selector="save_changes_button"
>{{ s__('ClusterIntegration|Save changes') }}</gl-button
>
</div>
</div>
</template>
......@@ -9,13 +9,19 @@ export default () => {
return;
}
const { autoDevopsHelpPath, externalEndpointHelpPath } = entryPoint.dataset;
// eslint-disable-next-line no-new
new Vue({
el: entryPoint,
store: createStore(entryPoint.dataset),
provide: {
autoDevopsHelpPath,
externalEndpointHelpPath,
},
render(createElement) {
return createElement(IntegrationForm);
return createElement(IntegrationForm, {});
},
});
};
......@@ -4,5 +4,10 @@ export default (initialState = {}) => {
return {
enabled: parseBoolean(initialState.enabled),
editable: parseBoolean(initialState.editable),
environmentScope: initialState.environmentScope,
baseDomain: initialState.baseDomain,
applicationIngressExternalIp: initialState.applicationIngressExternalIp,
autoDevopsHelpPath: initialState.autoDevopsHelpPath,
externalEndpointHelpPath: initialState.externalEndpointHelpPath,
};
};
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
import { GlLoadingIcon, GlButtonGroup, GlButton } from '@gitlab/ui';
import { GlLoadingIcon, GlButtonGroup, GlButton, GlAlert } from '@gitlab/ui';
import Mousetrap from 'mousetrap';
import { __ } from '~/locale';
import createFlash from '~/flash';
import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { isSingleViewStyle } from '~/helpers/diffs_helper';
......@@ -38,6 +39,7 @@ export default {
PanelResizer,
GlButtonGroup,
GlButton,
GlAlert,
},
mixins: [glFeatureFlagsMixin()],
props: {
......@@ -133,6 +135,9 @@ export default {
'startVersion',
'currentDiffFileId',
'isTreeLoaded',
'conflictResolutionPath',
'canMerge',
'hasConflicts',
]),
...mapGetters('diffs', ['isParallelView', 'currentDiffIndex']),
...mapGetters(['isNotesFetched', 'getNoteableData']),
......@@ -161,6 +166,9 @@ export default {
isLimitedContainer() {
return !this.showTreeList && !this.isParallelView && !this.isFluidLayout;
},
isDiffHead() {
return parseBoolean(getParameterByName('diff_head'));
},
},
watch: {
commit(newCommit, oldCommit) {
......@@ -422,6 +430,49 @@ export default {
:email-patch-path="emailPatchPath"
/>
<div
v-if="isDiffHead && hasConflicts"
:class="{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"
>
<gl-alert
:dismissible="false"
:title="__('There are merge conflicts')"
variant="warning"
class="w-100 mb-3"
>
<p class="mb-1">
{{ __('The comparison view may be inaccurate due to merge conflicts.') }}
</p>
<p class="mb-0">
{{
__(
'Resolve these conflicts or ask someone with write access to this repository to merge it locally.',
)
}}
</p>
<template #actions>
<gl-button
v-if="conflictResolutionPath"
:href="conflictResolutionPath"
variant="info"
class="mr-3 gl-alert-action"
>
{{ __('Resolve conflicts') }}
</gl-button>
<gl-button
v-if="canMerge"
class="gl-alert-action"
data-toggle="modal"
data-target="#modal_merge_info"
>
{{ __('Merge locally') }}
</gl-button>
</template>
</gl-alert>
</div>
<div
:data-can-create-note="getNoteableData.current_user.can_create_note"
class="files d-flex"
......
......@@ -6,7 +6,7 @@ import { __, sprintf } from '~/locale';
import ImportedProjectTableRow from './imported_project_table_row.vue';
import ProviderRepoTableRow from './provider_repo_table_row.vue';
import IncompatibleRepoTableRow from './incompatible_repo_table_row.vue';
import eventHub from '../event_hub';
import { isProjectImportable } from '../utils';
const reposFetchThrottleDelay = 1000;
......@@ -32,20 +32,29 @@ export default {
},
computed: {
...mapState([
'importedProjects',
'providerRepos',
'incompatibleRepos',
'isLoadingRepos',
'filter',
]),
...mapState(['filter', 'repositories', 'namespaces', 'defaultTargetNamespace']),
...mapGetters([
'isLoading',
'isImportingAnyRepo',
'hasProviderRepos',
'hasImportedProjects',
'hasImportableRepos',
'hasIncompatibleRepos',
]),
availableNamespaces() {
const serializedNamespaces = this.namespaces.map(({ fullPath }) => ({
id: fullPath,
text: fullPath,
}));
return [
{ text: __('Groups'), children: serializedNamespaces },
{
text: __('Users'),
children: [{ id: this.defaultTargetNamespace, text: this.defaultTargetNamespace }],
},
];
},
importAllButtonText() {
return this.hasIncompatibleRepos
? __('Import all compatible repositories')
......@@ -64,7 +73,8 @@ export default {
},
mounted() {
return this.fetchRepos();
this.fetchNamespaces();
this.fetchRepos();
},
beforeDestroy() {
......@@ -75,17 +85,13 @@ export default {
methods: {
...mapActions([
'fetchRepos',
'fetchReposFiltered',
'fetchJobs',
'fetchNamespaces',
'stopJobsPolling',
'clearJobsEtagPoll',
'setFilter',
'importAll',
]),
importAll() {
eventHub.$emit('importAll');
},
handleFilterInput({ target }) {
this.setFilter(target.value);
},
......@@ -93,6 +99,8 @@ export default {
throttledFetchRepos: throttle(function fetch() {
this.fetchRepos();
}, reposFetchThrottleDelay),
isProjectImportable,
},
};
</script>
......@@ -103,21 +111,17 @@ export default {
{{ s__('ImportProjects|Select the projects you want to import') }}
</p>
<template v-if="hasIncompatibleRepos">
<slot name="incompatible-repos-warning"> </slot>
<slot name="incompatible-repos-warning"></slot>
</template>
<div
v-if="!isLoadingRepos"
class="d-flex justify-content-between align-items-end flex-wrap mb-3"
>
<div v-if="!isLoading" class="d-flex justify-content-between align-items-end flex-wrap mb-3">
<gl-button
variant="success"
:loading="isImportingAnyRepo"
:disabled="!hasProviderRepos"
:disabled="!hasImportableRepos"
type="button"
@click="importAll"
>{{ importAllButtonText }}</gl-button
>
{{ importAllButtonText }}
</gl-button>
<slot name="actions"></slot>
<form v-if="filterable" class="gl-ml-auto" novalidate @submit.prevent>
<input
......@@ -134,14 +138,11 @@ export default {
</form>
</div>
<gl-loading-icon
v-if="isLoadingRepos"
v-if="isLoading"
class="js-loading-button-icon import-projects-loading-icon"
size="md"
/>
<div
v-else-if="hasProviderRepos || hasImportedProjects || hasIncompatibleRepos"
class="table-responsive"
>
<div v-else-if="repositories.length" class="table-responsive">
<table class="table import-table">
<thead>
<th class="import-jobs-from-col">{{ fromHeaderText }}</th>
......@@ -150,17 +151,20 @@ export default {
<th class="import-jobs-cta-col"></th>
</thead>
<tbody>
<imported-project-table-row
v-for="project in importedProjects"
:key="project.id"
:project="project"
/>
<provider-repo-table-row v-for="repo in providerRepos" :key="repo.id" :repo="repo" />
<incompatible-repo-table-row
v-for="repo in incompatibleRepos"
:key="repo.id"
:repo="repo"
/>
<template v-for="repo in repositories">
<incompatible-repo-table-row
v-if="repo.importSource.incompatible"
:key="repo.importSource.id"
:repo="repo"
/>
<provider-repo-table-row
v-else-if="isProjectImportable(repo)"
:key="repo.importSource.id"
:repo="repo"
:available-namespaces="availableNamespaces"
/>
<imported-project-table-row v-else :key="repo.importSource.id" :project="repo" />
</template>
</tbody>
</table>
</div>
......
......@@ -18,7 +18,7 @@ export default {
computed: {
displayFullPath() {
return this.project.fullPath.replace(/^\//, '');
return this.project.importedProject.fullPath.replace(/^\//, '');
},
isFinished() {
......@@ -29,29 +29,30 @@ export default {
</script>
<template>
<tr class="js-imported-project import-row">
<tr class="import-row">
<td>
<a
:href="project.providerLink"
:href="project.importSource.providerLink"
rel="noreferrer noopener"
target="_blank"
class="js-provider-link"
>
{{ project.importSource }}
<gl-icon v-if="project.providerLink" name="external-link" />
data-testid="providerLink"
>{{ project.importSource.fullName }}
<gl-icon v-if="project.importSource.providerLink" name="external-link" />
</a>
</td>
<td class="js-full-path">{{ displayFullPath }}</td>
<td><import-status :status="project.importStatus" /></td>
<td data-testid="fullPath">{{ displayFullPath }}</td>
<td>
<import-status :status="project.importStatus" />
</td>
<td>
<a
v-if="isFinished"
class="btn btn-default js-go-to-project"
:href="project.fullPath"
class="btn btn-default"
data-testid="goToProject"
:href="project.importedProject.fullPath"
rel="noreferrer noopener"
target="_blank"
>
{{ __('Go to project') }}
>{{ __('Go to project') }}
</a>
</td>
</tr>
......
......@@ -18,9 +18,9 @@ export default {
<template>
<tr class="import-row">
<td>
<a :href="repo.providerLink" rel="noreferrer noopener" target="_blank">
{{ repo.fullName }}
<gl-icon v-if="repo.providerLink" name="external-link" />
<a :href="repo.importSource.providerLink" rel="noreferrer noopener" target="_blank"
>{{ repo.importSource.fullName }}
<gl-icon v-if="repo.importSource.providerLink" name="external-link" />
</a>
</td>
<td></td>
......
......@@ -3,8 +3,6 @@ import { mapState, mapGetters, mapActions } from 'vuex';
import { GlIcon } from '@gitlab/ui';