gitlab-ce/app/assets/javascripts/environments/components/environment_namespace_selec...

157 lines
4.3 KiB
Vue

<script>
import {
GlFormGroup,
GlCollapsibleListbox,
GlAlert,
GlButton,
GlSprintf,
GlLink,
} from '@gitlab/ui';
import { __, s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import getNamespacesQuery from '../graphql/queries/k8s_namespaces.query.graphql';
export default {
components: {
GlFormGroup,
GlCollapsibleListbox,
GlAlert,
GlButton,
GlSprintf,
GlLink,
},
props: {
configuration: {
required: true,
type: Object,
},
namespace: {
required: false,
type: String,
default: '',
},
},
clustersHelpPagePath: helpPagePath('user/clusters/agent/index.md'),
i18n: {
namespaceLabel: s__('Environments|Kubernetes namespace (optional)'),
namespaceHelpText: s__('Environments|Select namespace'),
selectButton: s__('Environments|Or select namespace: %{searchTerm}'),
namespaceSelectorDescription: s__(
'Environments|No selection shows all authorized resources in the cluster. %{linkStart}Learn more.%{linkEnd}',
),
reset: __('Reset'),
},
data() {
return {
k8sNamespaces: [],
searchTerm: '',
kubernetesError: '',
};
},
apollo: {
k8sNamespaces: {
query: getNamespacesQuery,
variables() {
return {
configuration: this.configuration,
};
},
update(data) {
return (
data?.k8sNamespaces?.map((item) => {
return {
value: item.metadata.name,
text: item.metadata.name,
};
}) || []
);
},
error(error) {
this.kubernetesError = error.message;
},
result(result) {
if (!result?.error && !result.errors?.length) {
this.kubernetesError = null;
}
},
},
},
computed: {
loadingNamespacesList() {
return this.$apollo.queries.k8sNamespaces.loading;
},
filteredNamespacesList() {
const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
return this.k8sNamespaces.filter((item) =>
item.text.toLowerCase().includes(lowerCasedSearchTerm),
);
},
namespaceDropdownToggleText() {
return this.namespace || this.$options.i18n.namespaceHelpText;
},
shouldRenderSelectButton() {
const hasSearchedItem = this.k8sNamespaces.some(
(item) => item.text === this.searchTerm.toLowerCase(),
);
return this.searchTerm && !hasSearchedItem;
},
},
methods: {
onChange(namespace) {
this.$emit('change', namespace);
},
onNamespaceSearch(search) {
this.searchTerm = search;
},
onSelect(namespace) {
this.onChange(namespace);
this.$refs.namespaceSelector.close();
},
},
};
</script>
<template>
<gl-form-group :label="$options.i18n.namespaceLabel" label-for="environment_namespace">
<gl-alert v-if="kubernetesError" variant="warning" :dismissible="false" class="gl-mb-5">
{{ kubernetesError }}
</gl-alert>
<gl-collapsible-listbox
id="environment_namespace"
ref="namespaceSelector"
:selected="namespace"
class="gl-w-full"
block
:items="filteredNamespacesList"
:loading="loadingNamespacesList"
:toggle-text="namespaceDropdownToggleText"
:header-text="$options.i18n.namespaceHelpText"
:reset-button-label="$options.i18n.reset"
:searchable="true"
@search="onNamespaceSearch"
@select="onChange"
@reset="onChange(null)"
>
<template v-if="shouldRenderSelectButton" #footer>
<gl-button
category="tertiary"
class="!gl-justify-start !gl-rounded-tl-none !gl-rounded-tr-none !gl-border-t-1 gl-border-t-dropdown !gl-pl-7 gl-border-t-solid"
:class="{ 'gl-mt-3': !filteredNamespacesList.length }"
@click="onSelect(searchTerm)"
>
<gl-sprintf :message="$options.i18n.selectButton">
<template #searchTerm>{{ searchTerm }}</template>
</gl-sprintf>
</gl-button>
</template>
</gl-collapsible-listbox>
<template #description>
<gl-sprintf :message="$options.i18n.namespaceSelectorDescription">
<template #link="{ content }">
<gl-link :href="$options.clustersHelpPagePath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
</gl-form-group>
</template>