diff options
Diffstat (limited to 'app/assets')
6 files changed, 212 insertions, 32 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index da34c5030f9..1b11ec355bb 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -259,7 +259,7 @@ export default class Clusters { eventHub.$on('installApplication', this.installApplication); eventHub.$on('updateApplication', data => this.updateApplication(data)); eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data)); - eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data)); + eventHub.$on('setKnativeDomain', data => this.setKnativeDomain(data)); eventHub.$on('uninstallApplication', data => this.uninstallApplication(data)); eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data)); eventHub.$on('setIngressModSecurityEnabled', data => this.setIngressModSecurityEnabled(data)); @@ -275,7 +275,7 @@ export default class Clusters { eventHub.$off('installApplication', this.installApplication); eventHub.$off('updateApplication', this.updateApplication); eventHub.$off('saveKnativeDomain'); - eventHub.$off('setKnativeHostname'); + eventHub.$off('setKnativeDomain'); eventHub.$off('setCrossplaneProviderStack'); eventHub.$off('uninstallApplication'); eventHub.$off('setIngressModSecurityEnabled'); @@ -521,10 +521,10 @@ export default class Clusters { }); } - setKnativeHostname(data) { - const appId = data.id; - this.store.updateAppProperty(appId, 'isEditingHostName', true); - this.store.updateAppProperty(appId, 'hostname', data.hostname); + setKnativeDomain({ id: appId, domain, domainId }) { + this.store.updateAppProperty(appId, 'isEditingDomain', true); + this.store.updateAppProperty(appId, 'hostname', domain); + this.store.updateAppProperty(appId, 'pagesDomain', domainId ? { id: domainId, domain } : null); } setCrossplaneProviderStack(data) { diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 219825b1c01..723030c5b8b 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -240,16 +240,20 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity this.helmInstallIllustration = helmInstallIllustration; }, methods: { - saveKnativeDomain(hostname) { + saveKnativeDomain() { eventHub.$emit('saveKnativeDomain', { id: 'knative', - params: { hostname }, + params: { + hostname: this.applications.knative.hostname, + pages_domain_id: this.applications.knative.pagesDomain?.id, + }, }); }, - setKnativeHostname(hostname) { - eventHub.$emit('setKnativeHostname', { + setKnativeDomain({ domainId, domain }) { + eventHub.$emit('setKnativeDomain', { id: 'knative', - hostname, + domainId, + domain, }); }, setCrossplaneProviderStack(stack) { @@ -591,7 +595,10 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :request-reason="applications.knative.requestReason" :installed="applications.knative.installed" :install-failed="applications.knative.installFailed" - :install-application-request-params="{ hostname: applications.knative.hostname }" + :install-application-request-params="{ + hostname: applications.knative.hostname, + pages_domain_id: applications.knative.pagesDomain && applications.knative.pagesDomain.id, + }" :installed-via="installedVia" :uninstallable="applications.knative.uninstallable" :uninstall-successful="applications.knative.uninstallSuccessful" @@ -628,7 +635,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :knative="knative" :ingress-dns-help-path="ingressDnsHelpPath" @save="saveKnativeDomain" - @set="setKnativeHostname" + @set="setKnativeDomain" /> </div> </application-row> diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue index 30efbe2e0f7..8136704d13b 100644 --- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue +++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue @@ -1,5 +1,12 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { + GlDropdown, + GlDropdownDivider, + GlDropdownItem, + GlLoadingIcon, + GlSearchBoxByType, + GlSprintf, +} from '@gitlab/ui'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; import ClipboardButton from '../../vue_shared/components/clipboard_button.vue'; import { __, s__ } from '~/locale'; @@ -13,6 +20,11 @@ export default { LoadingButton, ClipboardButton, GlLoadingIcon, + GlDropdown, + GlDropdownDivider, + GlDropdownItem, + GlSearchBoxByType, + GlSprintf, }, props: { knative: { @@ -25,6 +37,11 @@ export default { required: false, }, }, + data() { + return { + searchQuery: '', + }; + }, computed: { saveButtonDisabled() { return [UNINSTALLING, UPDATING].includes(this.knative.status); @@ -49,9 +66,22 @@ export default { return this.knative.hostname; }, set(hostname) { - this.$emit('set', hostname); + this.selectCustomDomain(hostname); }, }, + domainDropdownText() { + return this.knativeHostname || s__('ClusterIntegration|Select existing domain or use new'); + }, + availableDomains() { + return this.knative.availableDomains || []; + }, + filteredDomains() { + const query = this.searchQuery.toLowerCase(); + return this.availableDomains.filter(({ domain }) => domain.toLowerCase().includes(query)); + }, + showDomainsDropdown() { + return this.availableDomains.length > 0; + }, }, watch: { knativeUpdateSuccessful(updateSuccessful) { @@ -60,6 +90,14 @@ export default { } }, }, + methods: { + selectDomain({ id, domain }) { + this.$emit('set', { domain, domainId: id }); + }, + selectCustomDomain(domain) { + this.$emit('set', { domain, domainId: null }); + }, + }, }; </script> @@ -72,22 +110,55 @@ export default { {{ s__('ClusterIntegration|Something went wrong while updating Knative domain name.') }} </div> - <template> - <div - :class="{ 'col-md-6': knativeInstalled, 'col-12': !knativeInstalled }" - class="form-group col-sm-12 mb-0" + <div + :class="{ 'col-md-6': knativeInstalled, 'col-12': !knativeInstalled }" + class="form-group col-sm-12 mb-0" + > + <label for="knative-domainname"> + <strong>{{ s__('ClusterIntegration|Knative Domain Name:') }}</strong> + </label> + + <gl-dropdown + v-if="showDomainsDropdown" + :text="domainDropdownText" + toggle-class="dropdown-menu-toggle" + class="w-100 mb-2" > - <label for="knative-domainname"> - <strong>{{ s__('ClusterIntegration|Knative Domain Name:') }}</strong> - </label> - <input - id="knative-domainname" - v-model="knativeHostname" - type="text" - class="form-control js-knative-domainname" + <gl-search-box-by-type + v-model.trim="searchQuery" + :placeholder="s__('ClusterIntegration|Search domains')" + class="m-2" /> - </div> - </template> + <gl-dropdown-item + v-for="domain in filteredDomains" + :key="domain.id" + @click="selectDomain(domain)" + > + <span class="ml-1">{{ domain.domain }}</span> + </gl-dropdown-item> + <template v-if="searchQuery"> + <gl-dropdown-divider /> + <gl-dropdown-item key="custom-domain" @click="selectCustomDomain(searchQuery)"> + <span class="ml-1"> + <gl-sprintf :message="s__('ClusterIntegration|Use %{query}')"> + <template #query> + <code>{{ searchQuery }}</code> + </template> + </gl-sprintf> + </span> + </gl-dropdown-item> + </template> + </gl-dropdown> + + <input + v-else + id="knative-domainname" + v-model="knativeHostname" + type="text" + class="form-control js-knative-domainname" + /> + </div> + <template v-if="knativeInstalled"> <div class="form-group col-sm-12 col-md-6 pl-md-0 mb-0 mt-3 mt-md-0"> <label for="knative-endpoint"> @@ -144,7 +215,7 @@ export default { :loading="saving" :disabled="saveButtonDisabled" :label="saveButtonLabel" - @click="$emit('save', knativeHostname)" + @click="$emit('save')" /> </template> </div> diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 8685e3decc5..b09fd6800b6 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -93,7 +93,7 @@ export default class ClusterStore { ...applicationInitialState, title: s__('ClusterIntegration|Knative'), hostname: null, - isEditingHostName: false, + isEditingDomain: false, externalIp: null, externalHostname: null, updateSuccessful: false, @@ -234,7 +234,12 @@ export default class ClusterStore { 'jupyter', ); } else if (appId === KNATIVE) { - if (!this.state.applications.knative.isEditingHostName) { + if (serverAppEntry.available_domains) { + this.state.applications.knative.availableDomains = serverAppEntry.available_domains; + } + if (!this.state.applications.knative.isEditingDomain) { + this.state.applications.knative.pagesDomain = + serverAppEntry.pages_domain || this.state.applications.knative.pagesDomain; this.state.applications.knative.hostname = serverAppEntry.hostname || this.state.applications.knative.hostname; } diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index 1ff4f7bab97..a495d2040d3 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -318,3 +318,11 @@ export const setUrlParams = (params, url = window.location.href, clearParams = f export function urlIsDifferent(url, compare = String(window.location)) { return url !== compare; } + +export function getHTTPProtocol(url) { + if (!url) { + return window.location.protocol.slice(0, -1); + } + const protocol = url.split(':'); + return protocol.length > 1 ? protocol[0] : undefined; +} diff --git a/app/assets/javascripts/vue_shared/components/clone_dropdown.vue b/app/assets/javascripts/vue_shared/components/clone_dropdown.vue new file mode 100644 index 00000000000..3b9b9f37f52 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/clone_dropdown.vue @@ -0,0 +1,89 @@ +<script> +import { + GlNewDropdown, + GlNewDropdownHeader, + GlFormInputGroup, + GlNewButton, + GlIcon, + GlTooltipDirective, +} from '@gitlab/ui'; +import { __, sprintf } from '~/locale'; +import { getHTTPProtocol } from '~/lib/utils/url_utility'; + +export default { + components: { + GlNewDropdown, + GlNewDropdownHeader, + GlFormInputGroup, + GlNewButton, + GlIcon, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + sshLink: { + type: String, + required: false, + default: '', + }, + httpLink: { + type: String, + required: false, + default: '', + }, + }, + computed: { + httpLabel() { + const protocol = this.httpLink ? getHTTPProtocol(this.httpLink)?.toUpperCase() : ''; + return sprintf(__('Clone with %{protocol}'), { protocol }); + }, + }, + labels: { + defaultLabel: __('Clone'), + ssh: __('Clone with SSH'), + }, + copyURLTooltip: __('Copy URL'), +}; +</script> +<template> + <gl-new-dropdown :text="$options.labels.defaultLabel" category="primary" variant="info"> + <div class="pb-2 mx-1"> + <template v-if="sshLink"> + <gl-new-dropdown-header>{{ $options.labels.ssh }}</gl-new-dropdown-header> + + <div class="mx-3"> + <gl-form-input-group :value="sshLink" readonly select-on-click> + <template #append> + <gl-new-button + v-gl-tooltip.hover + :title="$options.copyURLTooltip" + :data-clipboard-text="sshLink" + > + <gl-icon name="copy-to-clipboard" :title="$options.copyURLTooltip" /> + </gl-new-button> + </template> + </gl-form-input-group> + </div> + </template> + + <template v-if="httpLink"> + <gl-new-dropdown-header>{{ httpLabel }}</gl-new-dropdown-header> + + <div class="mx-3"> + <gl-form-input-group :value="httpLink" readonly select-on-click> + <template #append> + <gl-new-button + v-gl-tooltip.hover + :title="$options.copyURLTooltip" + :data-clipboard-text="httpLink" + > + <gl-icon name="copy-to-clipboard" :title="$options.copyURLTooltip" /> + </gl-new-button> + </template> + </gl-form-input-group> + </div> + </template> + </div> + </gl-new-dropdown> +</template> |