diff options
Diffstat (limited to 'app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue')
-rw-r--r-- | app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue | 137 |
1 files changed, 100 insertions, 37 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue index 0ac98f6c982..298f7c7ad8c 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue @@ -1,7 +1,18 @@ <script> -import { GlButton, GlLoadingIcon, GlIcon, GlLink, GlBadge, GlSafeHtmlDirective } from '@gitlab/ui'; +import { + GlButton, + GlLoadingIcon, + GlLink, + GlBadge, + GlSafeHtmlDirective, + GlTooltipDirective, + GlIntersectionObserver, +} from '@gitlab/ui'; +import { sprintf, s__, __ } from '~/locale'; import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue'; -import StatusIcon from '../mr_widget_status_icon.vue'; +import { EXTENSION_ICON_CLASS } from '../../constants'; +import StatusIcon from './status_icon.vue'; +import Actions from './actions.vue'; export const LOADING_STATES = { collapsedLoading: 'collapsedLoading', @@ -13,14 +24,16 @@ export default { components: { GlButton, GlLoadingIcon, - GlIcon, GlLink, GlBadge, + GlIntersectionObserver, SmartVirtualList, StatusIcon, + Actions, }, directives: { SafeHtml: GlSafeHtmlDirective, + GlTooltip: GlTooltipDirective, }, data() { return { @@ -28,9 +41,16 @@ export default { collapsedData: null, fullData: null, isCollapsed: true, + showFade: false, }; }, computed: { + widgetLabel() { + return this.$options.i18n?.label || this.$options.name; + }, + widgetLoadingText() { + return this.$options.i18n?.loading || __('Loading...'); + }, isLoadingSummary() { return this.loadingState === LOADING_STATES.collapsedLoading; }, @@ -44,17 +64,22 @@ export default { return true; }, + collapseButtonLabel() { + return sprintf( + this.isCollapsed + ? s__('mrWidget|Show %{widget} details') + : s__('mrWidget|Hide %{widget} details'), + { widget: this.widgetLabel }, + ); + }, statusIconName() { - if (this.isLoadingSummary) { - return 'loading'; - } - - if (this.loadingState === LOADING_STATES.collapsedError) { - return 'warning'; - } + if (this.isLoadingSummary) return null; return this.statusIcon(this.collapsedData); }, + tertiaryActionsButtons() { + return this.tertiaryButtons ? this.tertiaryButtons() : undefined; + }, }, watch: { isCollapsed(newVal) { @@ -95,32 +120,59 @@ export default { throw e; }); }, + appear(index) { + if (index === this.fullData.length - 1) { + this.showFade = false; + } + }, + disappear(index) { + if (index === this.fullData.length - 1) { + this.showFade = true; + } + }, }, + EXTENSION_ICON_CLASS, }; </script> <template> - <section class="media-section mr-widget-border-top"> + <section class="media-section" data-testid="widget-extension"> <div class="media gl-p-5"> - <status-icon :status="statusIconName" class="align-self-center" /> - <div class="media-body d-flex flex-align-self-center align-items-center"> - <div class="code-text"> - <template v-if="isLoadingSummary"> - {{ __('Loading...') }} - </template> + <status-icon + :name="$options.label || $options.name" + :is-loading="isLoadingSummary" + :icon-name="statusIconName" + /> + <div class="media-body gl-display-flex gl-flex-direction-row!"> + <div class="gl-flex-grow-1"> + <template v-if="isLoadingSummary">{{ widgetLoadingText }}</template> <div v-else v-safe-html="summary(collapsedData)"></div> </div> - <gl-button - v-if="isCollapsible" - size="small" - class="float-right align-self-center" - @click="toggleCollapsed" - > - {{ isCollapsed ? __('Expand') : __('Collapse') }} - </gl-button> + <actions + :widget="$options.label || $options.name" + :tertiary-buttons="tertiaryActionsButtons" + /> + <div class="gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6"> + <gl-button + v-if="isCollapsible" + v-gl-tooltip + :title="collapseButtonLabel" + :aria-expanded="`${!isCollapsed}`" + :aria-label="collapseButtonLabel" + :icon="isCollapsed ? 'chevron-lg-down' : 'chevron-lg-up'" + category="tertiary" + data-testid="toggle-button" + size="small" + @click="toggleCollapsed" + /> + </div> </div> </div> - <div v-if="!isCollapsed" class="mr-widget-grouped-section"> + <div + v-if="!isCollapsed" + class="mr-widget-grouped-section gl-relative" + data-testid="widget-extension-collapsed-section" + > <div v-if="isLoadingExpanded" class="report-block-container"> <gl-loading-icon size="sm" inline /> {{ __('Loading...') }} </div> @@ -131,27 +183,38 @@ export default { :size="32" wtag="ul" wclass="report-block-list" - class="report-block-container" + class="report-block-container gl-px-5 gl-py-0" > - <li v-for="data in fullData" :key="data.id" class="d-flex align-items-center"> - <div v-if="data.icon" :class="data.icon.class" class="d-flex"> - <gl-icon :name="data.icon.name" :size="24" /> - </div> - <div - class="gl-mt-2 gl-mb-2 align-content-around align-items-start flex-wrap align-self-center d-flex" + <li + v-for="(data, index) in fullData" + :key="data.id" + :class="{ + 'gl-border-b-solid gl-border-b-1 gl-border-gray-100': index !== fullData.length - 1, + }" + class="gl-display-flex gl-align-items-center gl-py-3 gl-pl-7" + data-testid="extension-list-item" + > + <status-icon v-if="data.icon" :icon-name="data.icon.name" :size="12" /> + <gl-intersection-observer + :options="{ rootMargin: '100px', thresholds: 0.1 }" + class="gl-flex-wrap gl-align-self-center gl-display-flex" + @appear="appear(index)" + @disappear="disappear(index)" > - <div class="gl-mr-4"> - {{ data.text }} - </div> + <div v-safe-html="data.text" class="gl-mr-4"></div> <div v-if="data.link"> <gl-link :href="data.link.href">{{ data.link.text }}</gl-link> </div> <gl-badge v-if="data.badge" :variant="data.badge.variant || 'info'"> {{ data.badge.text }} </gl-badge> - </div> + </gl-intersection-observer> </li> </smart-virtual-list> + <div + :class="{ show: showFade }" + class="fade mr-extenson-scrim gl-absolute gl-left-0 gl-bottom-0 gl-w-full gl-h-7" + ></div> </div> </section> </template> |