diff options
Diffstat (limited to 'app/assets/javascripts/issue_show')
-rw-r--r-- | app/assets/javascripts/issue_show/components/app.vue | 79 | ||||
-rw-r--r-- | app/assets/javascripts/issue_show/components/pinned_links.vue | 39 | ||||
-rw-r--r-- | app/assets/javascripts/issue_show/constants.js | 17 |
3 files changed, 120 insertions, 15 deletions
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index 8cf2cda64a4..09acfd1cfae 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -1,9 +1,10 @@ <script> +import { GlIcon, GlIntersectionObserver } from '@gitlab/ui'; import Visibility from 'visibilityjs'; import { __, s__, sprintf } from '~/locale'; import createFlash from '~/flash'; -import { visitUrl } from '../../lib/utils/url_utility'; -import Poll from '../../lib/utils/poll'; +import { visitUrl } from '~/lib/utils/url_utility'; +import Poll from '~/lib/utils/poll'; import eventHub from '../event_hub'; import Service from '../services/index'; import Store from '../stores'; @@ -12,10 +13,13 @@ import descriptionComponent from './description.vue'; import editedComponent from './edited.vue'; import formComponent from './form.vue'; import PinnedLinks from './pinned_links.vue'; -import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; +import recaptchaModalImplementor from '~/vue_shared/mixins/recaptcha_modal_implementor'; +import { IssuableStatus, IssuableStatusText, IssuableType } from '../constants'; export default { components: { + GlIcon, + GlIntersectionObserver, descriptionComponent, titleComponent, editedComponent, @@ -58,12 +62,22 @@ export default { zoomMeetingUrl: { type: String, required: false, - default: null, + default: '', + }, + publishedIncidentUrl: { + type: String, + required: false, + default: '', }, issuableRef: { type: String, required: true, }, + issuableStatus: { + type: String, + required: false, + default: '', + }, initialTitleHtml: { type: String, required: true, @@ -157,6 +171,7 @@ export default { state: store.state, showForm: false, templatesRequested: false, + isStickyHeaderShowing: false, }; }, computed: { @@ -191,6 +206,18 @@ export default { defaultErrorMessage() { return sprintf(s__('Error updating %{issuableType}'), { issuableType: this.issuableType }); }, + isOpenStatus() { + return this.issuableStatus === IssuableStatus.Open; + }, + statusIcon() { + return this.isOpenStatus ? 'issue-open-m' : 'mobile-issue-close'; + }, + statusText() { + return IssuableStatusText[this.issuableStatus]; + }, + shouldShowStickyHeader() { + return this.isStickyHeaderShowing && this.issuableType === IssuableType.Issue; + }, }, created() { this.service = new Service(this.endpoint); @@ -344,6 +371,14 @@ export default { ); }); }, + + hideStickyHeader() { + this.isStickyHeaderShowing = false; + }, + + showStickyHeader() { + this.isStickyHeaderShowing = true; + }, }, }; </script> @@ -380,7 +415,40 @@ export default { :title-text="state.titleText" :show-inline-edit-button="showInlineEditButton" /> - <pinned-links :zoom-meeting-url="zoomMeetingUrl" /> + + <gl-intersection-observer @appear="hideStickyHeader" @disappear="showStickyHeader"> + <transition name="issuable-header-slide"> + <div + v-if="shouldShowStickyHeader" + class="issue-sticky-header gl-fixed gl-z-index-2 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-200 gl-py-3" + data-testid="issue-sticky-header" + > + <div + class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-mx-auto gl-px-5" + > + <p + class="issuable-status-box status-box gl-my-0" + :class="[isOpenStatus ? 'status-box-open' : 'status-box-issue-closed']" + > + <gl-icon :name="statusIcon" class="gl-display-block d-sm-none gl-h-6!" /> + <span class="gl-display-none d-sm-block">{{ statusText }}</span> + </p> + <p + class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0" + :title="state.titleText" + > + {{ state.titleText }} + </p> + </div> + </div> + </transition> + </gl-intersection-observer> + + <pinned-links + :zoom-meeting-url="zoomMeetingUrl" + :published-incident-url="publishedIncidentUrl" + /> + <description-component v-if="state.descriptionHtml" :can-update="canUpdate" @@ -393,6 +461,7 @@ export default { :lock-version="state.lock_version" @taskListUpdateFailed="updateStoreState" /> + <edited-component v-if="hasUpdated" :updated-at="state.updatedAt" diff --git a/app/assets/javascripts/issue_show/components/pinned_links.vue b/app/assets/javascripts/issue_show/components/pinned_links.vue index 965e8a3d751..4b50acceb62 100644 --- a/app/assets/javascripts/issue_show/components/pinned_links.vue +++ b/app/assets/javascripts/issue_show/components/pinned_links.vue @@ -11,21 +11,40 @@ export default { zoomMeetingUrl: { type: String, required: false, - default: null, + default: '', + }, + publishedIncidentUrl: { + type: String, + required: false, + default: '', }, }, }; </script> <template> - <div v-if="zoomMeetingUrl" class="border-bottom mb-3 mt-n2"> - <gl-link - :href="zoomMeetingUrl" - target="_blank" - class="btn btn-inverted btn-secondary btn-sm text-dark mb-3" - > - <icon name="brand-zoom" :size="14" /> - <strong class="vertical-align-top">{{ __('Join Zoom meeting') }}</strong> - </gl-link> + <div class="border-bottom gl-mb-6 gl-display-flex gl-justify-content-start"> + <div v-if="publishedIncidentUrl" class="gl-pr-3"> + <gl-link + :href="publishedIncidentUrl" + target="_blank" + class="btn btn-inverted btn-secondary btn-sm text-dark mb-3" + data-testid="publishedIncidentUrl" + > + <icon name="tanuki" :size="14" /> + <strong class="vertical-align-top">{{ __('Published on status page') }}</strong> + </gl-link> + </div> + <div v-if="zoomMeetingUrl"> + <gl-link + :href="zoomMeetingUrl" + target="_blank" + class="btn btn-inverted btn-secondary btn-sm text-dark mb-3" + data-testid="zoomMeetingUrl" + > + <icon name="brand-zoom" :size="14" /> + <strong class="vertical-align-top">{{ __('Join Zoom meeting') }}</strong> + </gl-link> + </div> </div> </template> diff --git a/app/assets/javascripts/issue_show/constants.js b/app/assets/javascripts/issue_show/constants.js new file mode 100644 index 00000000000..d73cc8cf007 --- /dev/null +++ b/app/assets/javascripts/issue_show/constants.js @@ -0,0 +1,17 @@ +import { __ } from '~/locale'; + +export const IssuableStatus = { + Open: 'opened', + Closed: 'closed', +}; + +export const IssuableStatusText = { + [IssuableStatus.Open]: __('Open'), + [IssuableStatus.Closed]: __('Closed'), +}; + +export const IssuableType = { + Issue: 'issue', + Epic: 'epic', + MergeRequest: 'merge_request', +}; |