gitlab-org--gitlab-foss/app/assets/javascripts/pipeline_editor/components/ui/editor_tab.vue

119 lines
3.2 KiB
Vue

<script>
import { GlAlert, GlTab } from '@gitlab/ui';
import { __, s__ } from '~/locale';
/**
* Wrapper of <gl-tab> to optionally lazily render this tab's content
* when its shown **without dismounting after its hidden**.
*
* Usage:
*
* API is the same as <gl-tab>, for example:
*
* <gl-tabs>
* <editor-tab title="Tab 1" lazy>
* lazily mounted content (gets mounted if this is first tab)
* </editor-tab>
* <editor-tab title="Tab 2" lazy>
* lazily mounted content
* </editor-tab>
* <editor-tab title="Tab 3">
* eagerly mounted content
* </editor-tab>
* </gl-tabs>
*
* Once the tab is selected it is permanently set as "not-lazy"
* so it's contents are not dismounted.
*
* lazy is "false" by default, as in <gl-tab>.
*
* It is also possible to pass the `isEmpty` and or `isInvalid` to let
* the tab component handle that state on its own. For example:
*
* * <gl-tabs>
* <editor-tab-with-status title="Tab 1" :is-empty="isEmpty" :is-invalid="isInvalid">
* ...
* </editor-tab-with-status>
* Will be the same as normal, except it will only render the slot component
* if the status is not empty and not invalid. In any of these 2 cases, it will render
* a generic component and avoid mounting whatever it received in the slot.
* </gl-tabs>
*/
export default {
i18n: {
invalid: __('Your CI/CD configuration syntax is invalid. View Lint tab for more details.'),
},
components: {
GlAlert,
GlTab,
// Use a small renderless component to know when the tab content mounts because:
// - gl-tab always gets mounted, even if lazy is `true`. See:
// https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/components/tabs/tab.js#L180
// - we cannot listen to events on <slot />
MountSpy: {
render: () => null,
},
},
inheritAttrs: false,
props: {
emptyMessage: {
type: String,
required: false,
default: s__(
'PipelineEditor|This tab will be usable when the CI/CD configuration file is populated with valid syntax.',
),
},
isEmpty: {
type: Boolean,
required: false,
default: null,
},
isInvalid: {
type: Boolean,
required: false,
default: null,
},
lazy: {
type: Boolean,
required: false,
default: false,
},
keepComponentMounted: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
isLazy: this.lazy,
};
},
computed: {
slots() {
return Object.keys(this.$slots);
},
},
methods: {
onContentMounted() {
// When a child is first mounted make the entire tab
// permanently mounted by setting 'lazy' to false unless
// explicitly opted out.
if (this.keepComponentMounted) {
this.isLazy = false;
}
},
},
};
</script>
<template>
<gl-tab :lazy="isLazy" v-bind="$attrs" v-on="$listeners">
<gl-alert v-if="isEmpty" variant="tip">{{ emptyMessage }}</gl-alert>
<gl-alert v-else-if="isInvalid" variant="danger">{{ $options.i18n.invalid }}</gl-alert>
<template v-else>
<slot v-for="slot in slots" :name="slot"></slot>
<mount-spy @hook:mounted="onContentMounted" />
</template>
</gl-tab>
</template>