Commit fe43c8aa authored by Kushal Pandya's avatar Kushal Pandya Committed by Jarka Košanová

Add initial frontend for attaching child epics

Adds backstage support to related issues app
to enable attaching epics to an epic
parent 68e1a43d
...@@ -82,6 +82,10 @@ export default { ...@@ -82,6 +82,10 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
epicLinksEndpoint: {
type: String,
required: true,
},
issueLinksEndpoint: { issueLinksEndpoint: {
type: String, type: String,
required: true, required: true,
...@@ -146,6 +150,10 @@ export default { ...@@ -146,6 +150,10 @@ export default {
type: Array, type: Array,
required: true, required: true,
}, },
parentEpic: {
type: Object,
required: true,
},
participants: { participants: {
type: Array, type: Array,
required: true, required: true,
...@@ -293,6 +301,7 @@ export default { ...@@ -293,6 +301,7 @@ export default {
:initial-participants="participants" :initial-participants="participants"
:initial-subscribed="subscribed" :initial-subscribed="subscribed"
:initial-todo-exists="todoExists" :initial-todo-exists="todoExists"
:parent-epic="parentEpic"
:namespace="namespace" :namespace="namespace"
:update-path="updateEndpoint" :update-path="updateEndpoint"
:labels-path="labelsPath" :labels-path="labelsPath"
...@@ -302,6 +311,13 @@ export default { ...@@ -302,6 +311,13 @@ export default {
:labels-web-url="labelsWebUrl" :labels-web-url="labelsWebUrl"
:epics-web-url="epicsWebUrl" :epics-web-url="epicsWebUrl"
/> />
<related-issues-root
:endpoint="epicLinksEndpoint"
:can-admin="canAdmin"
:can-reorder="canAdmin"
:allow-auto-complete="false"
title="Epics"
/>
<related-issues-root <related-issues-root
:endpoint="issueLinksEndpoint" :endpoint="issueLinksEndpoint"
:can-admin="canAdmin" :can-admin="canAdmin"
......
...@@ -15,6 +15,16 @@ export default () => { ...@@ -15,6 +15,16 @@ export default () => {
Cookies.set('collapsed_gutter', true); Cookies.set('collapsed_gutter', true);
} }
// TODO remove once API provides proper data
initialData.epicLinksEndpoint = '/';
metaData.parentEpic = {
id: 7,
title: 'Epic with out of range end date',
url: '/groups/gitlab-org/-/epics/7',
human_readable_timestamp: '<strong>30</strong> days remaining',
human_readable_end_date: 'Dec 28, 2018',
};
const props = Object.assign({}, initialData, metaData, el.dataset); const props = Object.assign({}, initialData, metaData, el.dataset);
return new Vue({ return new Vue({
......
...@@ -12,6 +12,7 @@ import SidebarTodo from '~/sidebar/components/todo_toggle/todo.vue'; ...@@ -12,6 +12,7 @@ import SidebarTodo from '~/sidebar/components/todo_toggle/todo.vue';
import SidebarCollapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue'; import SidebarCollapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue';
import ToggleSidebar from '~/vue_shared/components/sidebar/toggle_sidebar.vue'; import ToggleSidebar from '~/vue_shared/components/sidebar/toggle_sidebar.vue';
import SidebarLabelsSelect from '~/vue_shared/components/sidebar/labels_select/base.vue'; import SidebarLabelsSelect from '~/vue_shared/components/sidebar/labels_select/base.vue';
import SidebarItemEpic from 'ee/sidebar/components/sidebar_item_epic.vue';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import SidebarDatePicker from './sidebar_date_picker.vue'; import SidebarDatePicker from './sidebar_date_picker.vue';
...@@ -33,6 +34,7 @@ export default { ...@@ -33,6 +34,7 @@ export default {
SidebarDatePicker, SidebarDatePicker,
SidebarCollapsedGroupedDatePicker, SidebarCollapsedGroupedDatePicker,
SidebarLabelsSelect, SidebarLabelsSelect,
SidebarItemEpic,
SidebarParticipants, SidebarParticipants,
SidebarSubscriptions, SidebarSubscriptions,
}, },
...@@ -116,6 +118,10 @@ export default { ...@@ -116,6 +118,10 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
parentEpic: {
type: Object,
required: true,
},
namespace: { namespace: {
type: String, type: String,
required: false, required: false,
...@@ -462,7 +468,7 @@ export default { ...@@ -462,7 +468,7 @@ export default {
<div class="issuable-sidebar js-issuable-update"> <div class="issuable-sidebar js-issuable-update">
<div class="block issuable-sidebar-header"> <div class="block issuable-sidebar-header">
<span class="issuable-header-text hide-collapsed float-left">{{ __('Todo') }}</span> <span class="issuable-header-text hide-collapsed float-left">{{ __('Todo') }}</span>
<toggle-sidebar :collapsed="collapsed" css-classes="float-right" @toggle="toggleSidebar" /> <toggle-sidebar :collapsed="collapsed" css-classes="float-right" @toggle="toggleSidebar"/>
<sidebar-todo <sidebar-todo
v-if="!collapsed" v-if="!collapsed"
:collapsed="collapsed" :collapsed="collapsed"
...@@ -547,9 +553,11 @@ export default { ...@@ -547,9 +553,11 @@ export default {
@onLabelClick="handleLabelClick" @onLabelClick="handleLabelClick"
@onDropdownClose="handleDropdownClose" @onDropdownClose="handleDropdownClose"
@toggleCollapse="toggleSidebarRevealLabelsDropdown" @toggleCollapse="toggleSidebarRevealLabelsDropdown"
>{{ __('None') }}</sidebar-labels-select >{{ __('None') }}</sidebar-labels-select>
> <div class="block parent-epic">
<sidebar-participants :participants="initialParticipants" @toggleCollapse="toggleSidebar" /> <sidebar-item-epic :block-title="__('Parent epic')" :initial-epic="parentEpic"/>
</div>
<sidebar-participants :participants="initialParticipants" @toggleCollapse="toggleSidebar"/>
<sidebar-subscriptions <sidebar-subscriptions
:loading="savingSubscription" :loading="savingSubscription"
:subscribed="store.subscribed" :subscribed="store.subscribed"
......
...@@ -13,23 +13,43 @@ export default { ...@@ -13,23 +13,43 @@ export default {
components: { components: {
GlLoadingIcon, GlLoadingIcon,
}, },
props: {
blockTitle: {
type: String,
required: false,
default: __('Epic'),
},
initialEpic: {
type: Object,
required: false,
default: () => {},
},
},
data() { data() {
let store = {};
if (!this.initialEpic) {
store = new Store();
}
return { return {
store: new Store(), store,
}; };
}, },
computed: { computed: {
isLoading() { isLoading() {
return this.store.isFetching.epic; return this.initialEpic ? false : this.store.isFetching.epic;
}, },
epicIcon() { epicIcon() {
return spriteIcon('epic'); return spriteIcon('epic');
}, },
epic() {
return this.initialEpic || this.store.epic;
},
epicUrl() { epicUrl() {
return this.store.epic.url; return this.epic.url;
}, },
epicTitle() { epicTitle() {
return this.store.epic.title; return this.epic.title;
}, },
hasEpic() { hasEpic() {
return this.epicUrl && this.epicTitle; return this.epicUrl && this.epicTitle;
...@@ -43,13 +63,13 @@ export default { ...@@ -43,13 +63,13 @@ export default {
} }
let tooltipTitle = this.epicTitle; let tooltipTitle = this.epicTitle;
if (this.store.epic.human_readable_end_date || this.store.epic.human_readable_timestamp) { if (this.epic.human_readable_end_date || this.epic.human_readable_timestamp) {
tooltipTitle += '<br />'; tooltipTitle += '<br />';
tooltipTitle += this.store.epic.human_readable_end_date tooltipTitle += this.epic.human_readable_end_date
? `${this.store.epic.human_readable_end_date} ` ? `${this.epic.human_readable_end_date} `
: ''; : '';
tooltipTitle += this.store.epic.human_readable_timestamp tooltipTitle += this.epic.human_readable_timestamp
? `(${this.store.epic.human_readable_timestamp})` ? `(${this.epic.human_readable_timestamp})`
: ''; : '';
} }
...@@ -71,15 +91,15 @@ export default { ...@@ -71,15 +91,15 @@ export default {
data-boundary="viewport" data-boundary="viewport"
> >
<div v-html="epicIcon"></div> <div v-html="epicIcon"></div>
<span v-if="!isLoading" class="collapse-truncated-title"> {{ collapsedTitle }} </span> <span v-if="!isLoading" class="collapse-truncated-title">{{ collapsedTitle }}</span>
</div> </div>
<div class="title hide-collapsed"> <div class="title hide-collapsed">
Epic {{ blockTitle }}
<gl-loading-icon v-if="isLoading" :inline="true" /> <gl-loading-icon v-if="isLoading" :inline="true"/>
</div> </div>
<div v-if="!isLoading" class="value hide-collapsed"> <div v-if="!isLoading" class="value hide-collapsed">
<a v-if="hasEpic" :href="epicUrl" class="bold"> {{ epicTitle }} </a> <a v-if="hasEpic" :href="epicUrl" class="bold">{{ epicTitle }}</a>
<span v-else class="no-value"> None </span> <span v-else class="no-value">None</span>
</div> </div>
</div> </div>
</template> </template>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment