diff options
Diffstat (limited to 'app/assets/javascripts/issue_show/components')
10 files changed, 226 insertions, 57 deletions
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index 992d87a969f..22db0f1cfc1 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -20,7 +20,6 @@ export default { components: { GlIcon, GlIntersectionObserver, - descriptionComponent, titleComponent, editedComponent, formComponent, @@ -152,6 +151,18 @@ export default { required: false, default: 0, }, + descriptionComponent: { + type: Object, + required: false, + default: () => { + return descriptionComponent; + }, + }, + showTitleBorder: { + type: Boolean, + required: false, + default: true, + }, }, data() { const store = new Store({ @@ -209,6 +220,11 @@ export default { isOpenStatus() { return this.issuableStatus === IssuableStatus.Open; }, + pinnedLinkClasses() { + return this.showTitleBorder + ? 'gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-mb-6' + : ''; + }, statusIcon() { return this.isOpenStatus ? 'issue-open-m' : 'mobile-issue-close'; }, @@ -231,7 +247,7 @@ export default { }); if (!Visibility.hidden()) { - this.poll.makeRequest(); + this.poll.makeDelayedRequest(2000); } Visibility.change(() => { @@ -447,10 +463,11 @@ export default { <pinned-links :zoom-meeting-url="zoomMeetingUrl" :published-incident-url="publishedIncidentUrl" + :class="pinnedLinkClasses" /> - <description-component - v-if="state.descriptionHtml" + <component + :is="descriptionComponent" :can-update="canUpdate" :description-html="state.descriptionHtml" :description-text="state.descriptionText" diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue index abb63f606ae..2a6468c783b 100644 --- a/app/assets/javascripts/issue_show/components/description.vue +++ b/app/assets/javascripts/issue_show/components/description.vue @@ -1,5 +1,6 @@ <script> import $ from 'jquery'; +import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; import { s__, sprintf } from '~/locale'; import { deprecatedCreateFlash as createFlash } from '~/flash'; import animateMixin from '../mixins/animate'; @@ -7,6 +8,10 @@ import TaskList from '../../task_list'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor'; export default { + directives: { + SafeHtml, + }, + mixins: [animateMixin, recaptchaModalImplementor], props: { @@ -20,7 +25,8 @@ export default { }, descriptionText: { type: String, - required: true, + required: false, + default: '', }, taskStatus: { type: String, @@ -47,11 +53,16 @@ export default { return { preAnimation: false, pulseAnimation: false, + initialUpdate: true, }; }, watch: { - descriptionHtml() { - this.animateChange(); + descriptionHtml(newDescription, oldDescription) { + if (!this.initialUpdate && newDescription !== oldDescription) { + this.animateChange(); + } else { + this.initialUpdate = false; + } this.$nextTick(() => { this.renderGFM(); @@ -136,12 +147,12 @@ export default { > <div ref="gfm-content" + v-safe-html="descriptionHtml" :class="{ 'issue-realtime-pre-pulse': preAnimation, 'issue-realtime-trigger-pulse': pulseAnimation, }" class="md" - v-html="descriptionHtml" ></div> <textarea v-if="descriptionText" diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue index 4ee44e50d2f..14ada5adcf6 100644 --- a/app/assets/javascripts/issue_show/components/edit_actions.vue +++ b/app/assets/javascripts/issue_show/components/edit_actions.vue @@ -1,5 +1,5 @@ <script> -/* eslint-disable @gitlab/vue-require-i18n-strings */ +import { GlButton } from '@gitlab/ui'; import { __, sprintf } from '~/locale'; import updateMixin from '../mixins/update'; import eventHub from '../event_hub'; @@ -10,6 +10,9 @@ const issuableTypes = { }; export default { + components: { + GlButton, + }, mixins: [updateMixin], props: { canDestroy: { @@ -64,28 +67,30 @@ export default { <template> <div class="gl-mt-3 gl-mb-3 clearfix"> - <button - :class="{ disabled: formState.updateLoading || !isSubmitEnabled }" + <gl-button + :loading="formState.updateLoading" :disabled="formState.updateLoading || !isSubmitEnabled" - class="btn btn-success float-left qa-save-button" + category="primary" + variant="success" + class="float-left qa-save-button" type="submit" @click.prevent="updateIssuable" > - Save changes - <i v-if="formState.updateLoading" class="fa fa-spinner fa-spin" aria-hidden="true"> </i> - </button> - <button class="btn btn-default float-right" type="button" @click="closeForm"> + {{ __('Save changes') }} + </gl-button> + <gl-button class="float-right" @click="closeForm"> {{ __('Cancel') }} - </button> - <button + </gl-button> + <gl-button v-if="shouldShowDeleteButton" - :class="{ disabled: deleteLoading }" + :loading="deleteLoading" :disabled="deleteLoading" - class="btn btn-danger float-right gl-mr-3 qa-delete-button" - type="button" + category="primary" + variant="danger" + class="float-right gl-mr-3 qa-delete-button" @click="deleteIssuable" > - Delete <i v-if="deleteLoading" class="fa fa-spinner fa-spin" aria-hidden="true"> </i> - </button> + {{ __('Delete') }} + </gl-button> </div> </template> diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue index 6d8a9950b6d..e1b308c6f57 100644 --- a/app/assets/javascripts/issue_show/components/fields/description_template.vue +++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue @@ -1,9 +1,13 @@ <script> /* eslint-disable @gitlab/vue-require-i18n-strings */ import $ from 'jquery'; +import { GlIcon } from '@gitlab/ui'; import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors'; export default { + components: { + GlIcon, + }, props: { formState: { type: Object, @@ -61,14 +65,14 @@ export default { <i aria-hidden="true" class="fa fa-chevron-down"> </i> </button> <div class="dropdown-menu dropdown-select"> - <div class="dropdown-title"> - Choose a template + <div class="dropdown-title gl-display-flex gl-justify-content-center"> + <span class="gl-ml-auto">Choose a template</span> <button - class="dropdown-title-button dropdown-menu-close" + class="dropdown-title-button dropdown-menu-close gl-ml-auto" :aria-label="__('Close')" type="button" > - <i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon"> </i> + <gl-icon name="close" class="dropdown-menu-close-icon" :aria-hidden="true" /> </button> </div> <div class="dropdown-input"> @@ -79,12 +83,11 @@ export default { autocomplete="off" /> <i aria-hidden="true" class="fa fa-search dropdown-input-search"> </i> - <i - role="button" + <gl-icon + name="close" + class="dropdown-input-clear js-dropdown-input-clear" :aria-label="__('Clear templates search input')" - class="fa fa-times dropdown-input-clear js-dropdown-input-clear" - > - </i> + /> </div> <div class="dropdown-content"></div> <div class="dropdown-footer"> diff --git a/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql new file mode 100644 index 00000000000..00ddc80432d --- /dev/null +++ b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql @@ -0,0 +1,20 @@ +query getAlert($iid: String!, $fullPath: ID!) { + project(fullPath: $fullPath) { + issue(iid: $iid) { + alertManagementAlert { + iid + title + detailsUrl + severity + status + startedAt + eventCount + monitoringTool + service + description + endedAt + details + } + } + } +} diff --git a/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue b/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue new file mode 100644 index 00000000000..a47fe4c84cf --- /dev/null +++ b/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue @@ -0,0 +1,42 @@ +<script> +import { GlLink } from '@gitlab/ui'; +import { formatDate } from '~/lib/utils/datetime_utility'; + +export default { + components: { + GlLink, + }, + props: { + alert: { + type: Object, + required: true, + }, + }, + computed: { + startTime() { + return formatDate(this.alert.startedAt, 'yyyy-mm-dd Z'); + }, + }, +}; +</script> + +<template> + <div + class="gl-border-solid gl-border-1 gl-border-gray-100 gl-p-5 gl-mb-3 gl-rounded-base gl-display-flex gl-justify-content-space-between" + > + <div class="text-truncate gl-pr-3"> + <span class="gl-font-weight-bold">{{ s__('HighlightBar|Original alert:') }}</span> + <gl-link :href="alert.detailsUrl">{{ alert.title }}</gl-link> + </div> + + <div class="gl-pr-3 gl-white-space-nowrap"> + <span class="gl-font-weight-bold">{{ s__('HighlightBar|Alert start time:') }}</span> + {{ startTime }} + </div> + + <div class="gl-white-space-nowrap"> + <span class="gl-font-weight-bold">{{ s__('HighlightBar|Alert events:') }}</span> + <span>{{ alert.eventCount }}</span> + </div> + </div> +</template> diff --git a/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue new file mode 100644 index 00000000000..4104ddbf06f --- /dev/null +++ b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue @@ -0,0 +1,71 @@ +<script> +import { GlTab, GlTabs } from '@gitlab/ui'; +import DescriptionComponent from '../description.vue'; +import HighlightBar from './highlight_bar.vue'; +import createFlash from '~/flash'; +import { s__ } from '~/locale'; +import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue'; + +import getAlert from './graphql/queries/get_alert.graphql'; + +export default { + components: { + AlertDetailsTable, + DescriptionComponent, + GlTab, + GlTabs, + HighlightBar, + }, + inject: ['fullPath', 'iid'], + apollo: { + alert: { + query: getAlert, + variables() { + return { + fullPath: this.fullPath, + iid: this.iid, + }; + }, + update(data) { + return data?.project?.issue?.alertManagementAlert; + }, + error() { + createFlash({ + message: s__('Incident|There was an issue loading alert data. Please try again.'), + }); + }, + }, + }, + data() { + return { + alert: null, + }; + }, + computed: { + loading() { + return this.$apollo.queries.alert.loading; + }, + alertTableFields() { + if (this.alert) { + const { detailsUrl, __typename, ...restDetails } = this.alert; + return restDetails; + } + return null; + }, + }, +}; +</script> + +<template> + <div> + <gl-tabs content-class="gl-reset-line-height" class="gl-mt-n3" data-testid="incident-tabs"> + <gl-tab :title="s__('Incident|Summary')"> + <highlight-bar v-if="alert" :alert="alert" /> + <description-component v-bind="$attrs" /> + </gl-tab> + <gl-tab v-if="alert" class="alert-management-details" :title="s__('Incident|Alert details')"> + <alert-details-table :alert="alertTableFields" :loading="loading" /> + </gl-tab> + </gl-tabs> + </div> +</template> diff --git a/app/assets/javascripts/issue_show/components/locked_warning.vue b/app/assets/javascripts/issue_show/components/locked_warning.vue index 19c7a11d87b..96f5a7c88e0 100644 --- a/app/assets/javascripts/issue_show/components/locked_warning.vue +++ b/app/assets/javascripts/issue_show/components/locked_warning.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable vue/no-v-html */ import { __, sprintf } from '~/locale'; export default { diff --git a/app/assets/javascripts/issue_show/components/pinned_links.vue b/app/assets/javascripts/issue_show/components/pinned_links.vue index a877aa2ac96..d38189307bd 100644 --- a/app/assets/javascripts/issue_show/components/pinned_links.vue +++ b/app/assets/javascripts/issue_show/components/pinned_links.vue @@ -20,20 +20,25 @@ export default { }, computed: { pinnedLinks() { - return [ - { + const links = []; + if (this.publishedIncidentUrl) { + links.push({ id: 'publishedIncidentUrl', url: this.publishedIncidentUrl, text: STATUS_PAGE_PUBLISHED, icon: 'tanuki', - }, - { + }); + } + if (this.zoomMeetingUrl) { + links.push({ id: 'zoomMeetingUrl', url: this.zoomMeetingUrl, text: JOIN_ZOOM_MEETING, icon: 'brand-zoom', - }, - ]; + }); + } + + return links; }, }, methods: { @@ -45,7 +50,7 @@ export default { </script> <template> - <div class="border-bottom gl-mb-6 gl-display-flex gl-justify-content-start"> + <div v-if="pinnedLinks && pinnedLinks.length" class="gl-display-flex gl-justify-content-start"> <template v-for="(link, i) in pinnedLinks"> <div v-if="link.url" :key="link.id" :class="{ 'gl-pr-3': needsPaddingClass(i) }"> <gl-button diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue index 1e1dce5f4fc..b03a91716fe 100644 --- a/app/assets/javascripts/issue_show/components/title.vue +++ b/app/assets/javascripts/issue_show/components/title.vue @@ -1,12 +1,15 @@ <script> +import { GlButton, GlTooltipDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; import animateMixin from '../mixins/animate'; import eventHub from '../event_hub'; -import tooltip from '../../vue_shared/directives/tooltip'; -import { spriteIcon } from '../../lib/utils/common_utils'; export default { + components: { + GlButton, + }, directives: { - tooltip, + GlTooltip: GlTooltipDirective, + SafeHtml, }, mixins: [animateMixin], props: { @@ -40,11 +43,6 @@ export default { titleEl: document.querySelector('title'), }; }, - computed: { - pencilIcon() { - return spriteIcon('pencil', 'link-highlight'); - }, - }, watch: { titleHtml() { this.setPageTitle(); @@ -67,25 +65,21 @@ export default { <template> <div class="title-container"> <h2 + v-safe-html="titleHtml" :class="{ 'issue-realtime-pre-pulse': preAnimation, 'issue-realtime-trigger-pulse': pulseAnimation, }" class="title qa-title" dir="auto" - v-html="titleHtml" ></h2> - <button + <gl-button v-if="showInlineEditButton && canUpdate" - v-tooltip - type="button" - class="btn btn-default btn-edit btn-svg js-issuable-edit - qa-edit-button" + v-gl-tooltip.bottom + icon="pencil" + class="btn-edit js-issuable-edit qa-edit-button" title="Edit title and description" - data-placement="bottom" - data-container="body" @click="edit" - v-html="pencilIcon" - ></button> + /> </div> </template> |