mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
USER-79: fixed the sidebar in the Panel. Update IssuePreview layout. (#3201)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
cc3afc40a3
commit
a5a464a112
@ -165,9 +165,11 @@
|
||||
{#if $$slots.actions}
|
||||
<div class="popupPanel-body__aside-header">
|
||||
{#if $$slots['actions-label']}
|
||||
<span class="fs-bold w-27 mr-6"><slot name="actions-label" /></span>
|
||||
<span class="fs-bold w-27 mr-4"><slot name="actions-label" /></span>
|
||||
{:else if $$slots.actions}
|
||||
<span class="fs-bold w-27 mr-4" />
|
||||
{/if}
|
||||
<div class="buttons-group xsmall-gap flex flex-grow">
|
||||
<div class="buttons-group xsmall-gap">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
@ -177,7 +179,7 @@
|
||||
<slot name="custom-attributes" direction="column" />
|
||||
{:else if $$slots.attributes}<slot name="attributes" direction="column" />{/if}
|
||||
{#if $$slots.aside}<slot name="aside" />{/if}
|
||||
<div class="h-2 min-h-2 max-h-2" />
|
||||
<div class="space-divider bottom" />
|
||||
</Scroller>
|
||||
</svelte:fragment>
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
export let justify: 'left' | 'center' = 'left'
|
||||
</script>
|
||||
|
||||
<div class="popupPanel-body__aside-grid">
|
||||
<div class="popupPanel-body__aside-grid inCollapsed">
|
||||
{#each keys as key (typeof key === 'string' ? key : key.key)}
|
||||
<AttributeBarEditor {key} {_class} {object} {showHeader} {readonly} {draft} on:update />
|
||||
{/each}
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
|
@ -38,6 +38,7 @@ export { default as IndexedDocumentPreview } from './components/IndexedDocumentP
|
||||
export { default as IndexedDocumentCompare } from './components/IndexedDocumentCompare.svelte'
|
||||
export { default as DraggableList } from './components/DraggableList.svelte'
|
||||
export { default as NavLink } from './components/NavLink.svelte'
|
||||
export { default as IconForward } from './components/icons/Forward.svelte'
|
||||
export { default } from './plugin'
|
||||
export * from './types'
|
||||
export * from './utils'
|
||||
|
@ -496,7 +496,9 @@ input.search {
|
||||
.pl-2 { padding-left: .5rem; }
|
||||
.pl-3 { padding-left: .75rem; }
|
||||
.pl-4 { padding-left: 1rem; }
|
||||
.pl-7 { padding-left: 1.75rem; }
|
||||
.pl-8 { padding-left: 2rem; }
|
||||
.pl-9 { padding-left: 2.25rem; }
|
||||
.pl-10 { padding-left: 2.5rem; }
|
||||
.pr-1 { padding-right: .25rem; }
|
||||
.pr-2 { padding-right: .5rem; }
|
||||
@ -602,6 +604,7 @@ input.search {
|
||||
.h-7 { height: 1.75rem; }
|
||||
.h-8 { height: 2rem; }
|
||||
.h-9 { height: 2.25rem; }
|
||||
.h-12 { height: 3rem; }
|
||||
.h-14 { height: 3.5rem; }
|
||||
.h-16 { height: 4rem; }
|
||||
.h-18 { height: 4.5rem; }
|
||||
|
@ -31,7 +31,7 @@
|
||||
min-height: 0;
|
||||
background: var(--theme-popup-color);
|
||||
border-radius: .5rem;
|
||||
box-shadow: var(--card-shadow);
|
||||
box-shadow: var(--theme-popup-shadow);
|
||||
|
||||
.antiCard-header {
|
||||
position: relative;
|
||||
|
@ -18,18 +18,38 @@
|
||||
overflow: hidden;
|
||||
min-width: 400px;
|
||||
|
||||
background: var(--body-accent);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-popup-color);
|
||||
border: 1px solid var(--theme-popup-divider);
|
||||
border-radius: .5rem;
|
||||
flex-direction: row;
|
||||
box-shadow: var(--popup-shadow);
|
||||
box-shadow: var(--theme-popup-shadow);
|
||||
// left: 1rem;
|
||||
|
||||
&.float {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 5rem;
|
||||
right: .5rem;
|
||||
width: 42rem;
|
||||
height: fit-content;
|
||||
min-height: 0;
|
||||
max-height: 32rem;
|
||||
z-index: 500;
|
||||
|
||||
.ap-header {
|
||||
flex-shrink: 0;
|
||||
padding: 1.5rem 1.75rem .5rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ac-header {
|
||||
&.highlight { background-color: var(--accent-bg-color); }
|
||||
&.divide { border-bottom: 1px solid var(--divider-color); }
|
||||
}
|
||||
|
||||
.ad-section-50 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -39,7 +59,6 @@
|
||||
|
||||
&.divide { border-right: 1px solid var(--divider-color); }
|
||||
}
|
||||
|
||||
.ad-tools {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
@ -58,18 +77,16 @@
|
||||
.popupPanel {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
|
||||
&.embedded {
|
||||
|
||||
&.rowContent {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&:not(.embedded) {
|
||||
border-radius: .5rem;
|
||||
// box-shadow: var(--popup-panel-shadow);
|
||||
}
|
||||
&:not(.rowContent) { flex-direction: column; }
|
||||
&.embedded { width: 100%; }
|
||||
&:not(.embedded) { border-radius: .5rem; }
|
||||
|
||||
.popupPanel-title {
|
||||
display: flex;
|
||||
@ -258,27 +275,29 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: .75rem 2rem;
|
||||
height: 3.5rem;
|
||||
min-height: 3.5rem;
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
&-tabsheader {
|
||||
padding: 0 2rem;
|
||||
&-tabsheader { padding: 0 2rem; }
|
||||
&-header {
|
||||
justify-content: space-between;
|
||||
padding: .75rem .75rem .75rem 2rem;
|
||||
}
|
||||
|
||||
&-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.5fr;
|
||||
grid-auto-flow: row;
|
||||
grid-auto-rows: minmax(2rem, max-content);
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
row-gap: .25rem;
|
||||
column-gap: 1rem;
|
||||
margin: .5rem 2rem;
|
||||
margin: .25rem 2rem 0;
|
||||
width: calc(100% - 4rem);
|
||||
height: min-content;
|
||||
|
||||
&.inCollapsed { margin: 1rem 2rem; }
|
||||
.divider {
|
||||
grid-column: 1 / 3;
|
||||
margin: .75rem -2rem;
|
||||
@ -289,9 +308,24 @@
|
||||
.labelTop { color: var(--theme-dark-color); }
|
||||
.labelTop {
|
||||
align-self: start;
|
||||
margin-top: 0.385rem;
|
||||
}
|
||||
}
|
||||
margin-top: 0.625rem;
|
||||
}
|
||||
.textPadding { margin-left: .875rem; }
|
||||
}
|
||||
&-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 1.25rem 2rem;
|
||||
}
|
||||
.space-divider {
|
||||
flex-shrink: 0;
|
||||
height: .75rem;
|
||||
|
||||
&.bottom { height: 1.25rem; }
|
||||
}
|
||||
}
|
||||
|
||||
// &.asideShown .popupPanel-body__main {
|
||||
|
@ -79,7 +79,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="popupPanel"
|
||||
class="popupPanel panel"
|
||||
class:embedded
|
||||
use:resizeObserver={(element) => {
|
||||
panelWidth = element.clientWidth
|
||||
|
@ -32,6 +32,7 @@
|
||||
export let invertScroll: boolean = false
|
||||
export let horizontal: boolean = false
|
||||
export let contentDirection: 'vertical' | 'vertical-reverse' | 'horizontal' = 'vertical'
|
||||
export let gap: 'gap-1' | 'gap-1-5' | 'gap-2' | 'gap-3' | 'gap-around-2' | 'gap-around-4' | undefined = undefined
|
||||
export let noStretch: boolean = autoscroll
|
||||
export let buttons: 'normal' | 'union' | false = false
|
||||
export let shrink: boolean = false
|
||||
@ -497,7 +498,7 @@
|
||||
>
|
||||
<div
|
||||
bind:this={divBox}
|
||||
class="box"
|
||||
class="box{gap ? ` ${gap}` : ''}"
|
||||
class:align-center={contentDirection === 'horizontal'}
|
||||
style:padding
|
||||
style:flex-direction={contentDirection === 'vertical'
|
||||
@ -689,9 +690,9 @@
|
||||
&.vertical {
|
||||
min-width: 1.5rem 0;
|
||||
}
|
||||
&.horizontal {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
// &.horizontal {
|
||||
// margin-right: 2rem;
|
||||
// }
|
||||
&.buttons.vertical {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
@ -232,18 +232,18 @@
|
||||
&.link {
|
||||
justify-content: flex-start;
|
||||
padding: 0 0.875rem;
|
||||
height: 2rem;
|
||||
color: var(--theme-dark-color);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.btn-icon {
|
||||
margin-right: 0.5rem;
|
||||
color: var(--theme-darker-color);
|
||||
}
|
||||
&:hover {
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-hovered);
|
||||
color: var(--theme-content-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
border-color: var(--theme-divider-color);
|
||||
.btn-icon {
|
||||
color: var(--theme-caption-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { Attachment } from '@hcengineering/attachment'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Scroller } from '@hcengineering/ui'
|
||||
import AttachmentPreview from './AttachmentPreview.svelte'
|
||||
|
||||
export let attachments: Attachment[] = []
|
||||
@ -22,11 +23,9 @@
|
||||
</script>
|
||||
|
||||
{#if attachments.length}
|
||||
<div class="flex flex-wrap">
|
||||
<Scroller contentDirection={'horizontal'} horizontal gap={'gap-3'}>
|
||||
{#each attachments as attachment}
|
||||
<div class="p-2">
|
||||
<AttachmentPreview value={attachment} isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false} />
|
||||
</div>
|
||||
<AttachmentPreview value={attachment} isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false} />
|
||||
{/each}
|
||||
</div>
|
||||
</Scroller>
|
||||
{/if}
|
||||
|
@ -379,7 +379,8 @@
|
||||
}
|
||||
|
||||
tbody tr:not(:last-child),
|
||||
thead th:first-child .fullfill {
|
||||
thead th:first-child .fullfill,
|
||||
tfoot tr {
|
||||
border-bottom: 1px solid var(--theme-bg-divider-color);
|
||||
}
|
||||
tfoot tr,
|
||||
|
@ -120,21 +120,19 @@
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="actions">
|
||||
<Button
|
||||
icon={IconMixin}
|
||||
kind={'transparent'}
|
||||
shape={'round'}
|
||||
selected={showAllMixins}
|
||||
on:click={() => {
|
||||
showAllMixins = !showAllMixins
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="attributes" let:direction={dir}>
|
||||
<div class="flex flex-reverse flex-no-shrink clear-mins">
|
||||
<Button
|
||||
kind={'transparent'}
|
||||
shape={'round'}
|
||||
selected={showAllMixins}
|
||||
on:click={() => {
|
||||
showAllMixins = !showAllMixins
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="content">
|
||||
<IconMixin size={'small'} />
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
</div>
|
||||
{#if dir === 'column'}
|
||||
<DocAttributeBar
|
||||
{object}
|
||||
|
@ -1,10 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { DueDatePresenter } from '@hcengineering/ui'
|
||||
import { DueDatePresenter, ButtonSize, ButtonKind } from '@hcengineering/ui'
|
||||
import { WithLookup } from '@hcengineering/core'
|
||||
import { Task } from '@hcengineering/task'
|
||||
|
||||
export let object: WithLookup<Task>
|
||||
export let width: string | undefined = undefined
|
||||
export let size: ButtonSize = 'medium'
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let editable: boolean = true
|
||||
|
||||
const client = getClient()
|
||||
$: shouldIgnoreOverdue = object.doneState != null
|
||||
@ -28,9 +32,11 @@
|
||||
|
||||
{#if object}
|
||||
<DueDatePresenter
|
||||
kind={'link'}
|
||||
{kind}
|
||||
{width}
|
||||
{size}
|
||||
value={object.dueDate}
|
||||
editable
|
||||
{editable}
|
||||
onChange={(e) => handleDueDateChanged(e)}
|
||||
{shouldIgnoreOverdue}
|
||||
/>
|
||||
|
@ -114,7 +114,7 @@
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<span class="ac-header__title"><Label {label} /></span>
|
||||
<span class="componentTitle">
|
||||
<span class="componentTitle ml-1">
|
||||
› <Label label={title} />
|
||||
</span>
|
||||
</div>
|
||||
@ -146,15 +146,8 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<TabList
|
||||
items={filterModeList}
|
||||
selected={filterMode}
|
||||
kind="normal"
|
||||
on:select={({ detail }) => detail?.action?.()}
|
||||
/>
|
||||
</div>
|
||||
<div class="ac-header tabs-start full divide">
|
||||
<TabList items={filterModeList} selected={filterMode} kind={'plain'} on:select={({ detail }) => detail?.action?.()} />
|
||||
</div>
|
||||
|
||||
<FilterBar
|
||||
|
@ -48,10 +48,8 @@
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="aside">
|
||||
<div class="flex-row p-4 w-60 left-divider">
|
||||
<div class="fs-title text-xl">
|
||||
<EditBox bind:value={component.label} on:change={() => change('label', component.label)} />
|
||||
</div>
|
||||
<div class="popupPanel-body__aside-content">
|
||||
<EditBox kind={'large-style'} bind:value={component.label} on:change={() => change('label', component.label)} />
|
||||
<div class="mt-2">
|
||||
<StyledTextBox
|
||||
alwaysEdit={true}
|
||||
@ -61,7 +59,7 @@
|
||||
on:value={(evt) => change('description', evt.detail)}
|
||||
/>
|
||||
</div>
|
||||
<DocAttributeBar object={component} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
|
||||
</div>
|
||||
<DocAttributeBar object={component} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
|
||||
</svelte:fragment>
|
||||
</IssuesView>
|
||||
|
@ -47,6 +47,6 @@
|
||||
$: formatTime(value)
|
||||
</script>
|
||||
|
||||
<span style="white-space: nowrap;">
|
||||
<span class="textPadding" style="white-space: nowrap;">
|
||||
{time}
|
||||
</span>
|
||||
|
@ -18,9 +18,9 @@
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { CommentPopup } from '@hcengineering/chunter-resources'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient, MessageViewer } from '@hcengineering/presentation'
|
||||
import { createQuery, getClient, MessageViewer, IconForward } from '@hcengineering/presentation'
|
||||
import { Issue, Project } from '@hcengineering/tracker'
|
||||
import { Label, resizeObserver, Scroller } from '@hcengineering/ui'
|
||||
import { Label, Scroller, resizeObserver } from '@hcengineering/ui'
|
||||
import tracker from '../../plugin'
|
||||
import AssigneeEditor from './AssigneeEditor.svelte'
|
||||
import IssueStatusActivity from './IssueStatusActivity.svelte'
|
||||
@ -50,8 +50,7 @@
|
||||
$: issueName = currentProject && issue && `${currentProject.identifier}-${issue.number}`
|
||||
|
||||
const limit: number = 350
|
||||
|
||||
let cHeight: number
|
||||
let cHeight: number = 0
|
||||
|
||||
let parent: Issue | undefined
|
||||
|
||||
@ -66,73 +65,87 @@
|
||||
$: getParent(issue?.attachedTo as Ref<Issue>)
|
||||
</script>
|
||||
|
||||
<div class="flex">
|
||||
<Scroller>
|
||||
<div class="w-165 scrollerContent">
|
||||
{#if parent}
|
||||
<div class="mb-4 ml-2">{parent.title}</div>
|
||||
{/if}
|
||||
{#if issue}
|
||||
<div class="fs-title text-xl ml-2">{issueName} {issue.title}</div>
|
||||
<div class="flex mt-2">
|
||||
<StatusEditor value={issue} shouldShowLabel kind={'transparent'} />
|
||||
<PriorityEditor value={issue} shouldShowLabel />
|
||||
{#if issue.assignee}
|
||||
<AssigneeEditor value={issue} width={'min-content'} />
|
||||
{/if}
|
||||
</div>
|
||||
<IssueStatusActivity {issue} />
|
||||
|
||||
<div class="mb-2">
|
||||
<Label label={tracker.string.Description} />:
|
||||
</div>
|
||||
{#if issue.description}
|
||||
<div
|
||||
class="descr ml-2"
|
||||
class:mask={cHeight >= limit}
|
||||
use:resizeObserver={(element) => {
|
||||
cHeight = element.clientHeight
|
||||
}}
|
||||
>
|
||||
<MessageViewer message={issue.description} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="ml-2 content-dark-color">
|
||||
<Label label={tracker.string.NoDescription} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if issue.attachments}
|
||||
<div class="mt-2 mb-2">
|
||||
<Label label={attachment.string.Attachments} />:
|
||||
</div>
|
||||
<div>
|
||||
<AttachmentDocList value={issue} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if issue.comments}
|
||||
<div class="mt-2 mb-2">
|
||||
<Label label={chunter.string.Comments} />:
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
<CommentPopup objectId={issue._id} object={issue} />
|
||||
</div>
|
||||
{#if issue}
|
||||
<div class="ap-header flex-between">
|
||||
<div class="flex-col">
|
||||
<div class="flex-row-center gap-1">
|
||||
{#if parent}
|
||||
<span class="overflow-label content-color">{parent.title}</span>
|
||||
<IconForward size={'x-small'} />
|
||||
{/if}
|
||||
<span class="content-dark-color">{issueName}</span>
|
||||
</div>
|
||||
<span class="overflow-label text-xl caption-color">{issue.title}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Scroller padding={'0.75rem 1.75rem 0'}>
|
||||
<div class="flex-row-center gap-2 mb-2">
|
||||
<StatusEditor value={issue} shouldShowLabel kind={'secondary'} />
|
||||
<PriorityEditor value={issue} shouldShowLabel kind={'secondary'} />
|
||||
{#if issue.assignee}
|
||||
<AssigneeEditor value={issue} width={'min-content'} kind={'secondary'} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid-preview">
|
||||
<IssueStatusActivity {issue} accentHeader />
|
||||
</div>
|
||||
|
||||
<div class="mt-6 mb-2 overflow-label fs-bold content-dark-color">
|
||||
<Label label={tracker.string.Description} />:
|
||||
</div>
|
||||
{#if issue.description}
|
||||
<div class="description-container" class:masked={cHeight > limit} style:max-height={`${limit}px`}>
|
||||
<div class="description-content" use:resizeObserver={(element) => (cHeight = element.clientHeight)}>
|
||||
<MessageViewer message={issue.description} />
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-label content-darker-color">
|
||||
<Label label={tracker.string.NoDescription} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if issue.attachments}
|
||||
<div class="mt-6 mb-2 overflow-label fs-bold content-dark-color">
|
||||
<Label label={attachment.string.Attachments} />:
|
||||
</div>
|
||||
<AttachmentDocList value={issue} />
|
||||
{/if}
|
||||
{#if issue.comments}
|
||||
<div class="mt-6 mb-2 overflow-label fs-bold content-dark-color">
|
||||
<Label label={chunter.string.Comments} />:
|
||||
</div>
|
||||
<CommentPopup objectId={issue._id} object={issue} />
|
||||
{/if}
|
||||
<div class="h-3 flex-no-shrink" />
|
||||
</Scroller>
|
||||
</div>
|
||||
<div class="h-3 flex-no-shrink" />
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.descr {
|
||||
.description-container {
|
||||
overflow: hidden;
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
|
||||
&.mask {
|
||||
mask: linear-gradient(to top, rgba(0, 0, 0, 0) 0, black 5rem);
|
||||
&.masked {
|
||||
mask-image: linear-gradient(0deg, #0000 0, #000f 4rem);
|
||||
}
|
||||
.description-content {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: max-content;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollerContent {
|
||||
height: fit-content;
|
||||
max-height: 32rem;
|
||||
.grid-preview {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
grid-auto-rows: minmax(2rem, max-content);
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
row-gap: 0.25rem;
|
||||
column-gap: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,13 +2,14 @@
|
||||
import core, { Ref, Timestamp, Tx, TxCollectionCUD, TxCreateDoc, TxUpdateDoc, WithLookup } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Issue, IssueStatus } from '@hcengineering/tracker'
|
||||
import { Label, ticker } from '@hcengineering/ui'
|
||||
import { Label, ticker, Row } from '@hcengineering/ui'
|
||||
import tracker from '../../plugin'
|
||||
import { statusStore } from '@hcengineering/presentation'
|
||||
import Duration from './Duration.svelte'
|
||||
import StatusPresenter from './StatusPresenter.svelte'
|
||||
|
||||
export let issue: Issue
|
||||
export let accentHeader: boolean = false
|
||||
|
||||
const query = createQuery()
|
||||
|
||||
@ -86,20 +87,12 @@
|
||||
$: updateStatus(txes, $statusStore.byId, $ticker)
|
||||
</script>
|
||||
|
||||
<div class="flex-row mt-4 mb-4">
|
||||
<span class="content-dark-color"><Label label={tracker.string.StatusHistory} />:</span>
|
||||
<table class="ml-2">
|
||||
{#each displaySt as st}
|
||||
<tr>
|
||||
<td class="flex-row-center mt-2 mb-2">
|
||||
<StatusPresenter value={st.status} />
|
||||
</td>
|
||||
<td>
|
||||
<div class="ml-8 mr-2">
|
||||
<Duration value={st.duration} />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
<Row>
|
||||
<span class="label" class:fs-bold={accentHeader} class:content-dark-color={accentHeader}>
|
||||
<Label label={tracker.string.StatusHistory} />:
|
||||
</span>
|
||||
</Row>
|
||||
{#each displaySt as st}
|
||||
<StatusPresenter value={st.status} />
|
||||
<Duration value={st.duration} />
|
||||
{/each}
|
||||
|
@ -114,12 +114,12 @@
|
||||
</IssuesHeader>
|
||||
<FilterBar _class={tracker.class.Issue} query={searchQuery} {viewOptions} on:change={(e) => (resultQuery = e.detail)} />
|
||||
<slot name="afterHeader" />
|
||||
<div class="flex w-full h-full clear-mins">
|
||||
<div class="popupPanel rowContent">
|
||||
{#if viewlet}
|
||||
<IssuesContent {viewlet} query={resultQuery} {space} {viewOptions} />
|
||||
{/if}
|
||||
{#if $$slots.aside !== undefined && asideShown}
|
||||
<div class="popupPanel-body__aside flex" class:float={asideFloat} class:shown={asideShown}>
|
||||
<div class="popupPanel-body__aside" class:shown={asideShown}>
|
||||
<slot name="aside" />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -289,28 +289,14 @@
|
||||
|
||||
<svelte:fragment slot="custom-attributes">
|
||||
{#if issue && currentProject}
|
||||
<div class="space-divider" />
|
||||
<ControlPanel {issue} {showAllMixins} />
|
||||
{/if}
|
||||
|
||||
<div class="divider" />
|
||||
<div class="issue-stats">
|
||||
<div class="popupPanel-body__aside-grid">
|
||||
<div class="divider" />
|
||||
<IssueStatusActivity {issue} />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.divider {
|
||||
flex-shrink: 0;
|
||||
margin: 0.5rem 0;
|
||||
height: 1px;
|
||||
background-color: var(--theme-divider-color);
|
||||
}
|
||||
.issue-stats {
|
||||
flex-shrink: 0;
|
||||
margin: 0 2rem;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -61,10 +61,8 @@
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="afterHeader">
|
||||
<div class="p-1 ml-6 flex-row-center">
|
||||
<div class="flex-row-center">
|
||||
<DatePresenter value={milestone.targetDate} kind={'transparent'} />
|
||||
</div>
|
||||
<div class="ac-header search-start full divide">
|
||||
<DatePresenter value={milestone.targetDate} kind={'transparent'} size={'medium'} />
|
||||
<div class="flex-row-center ml-2">
|
||||
{#if milestone?.capacity}
|
||||
<Label label={tracker.string.CapacityValue} params={{ value: milestone?.capacity }} />
|
||||
@ -74,10 +72,8 @@
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="aside">
|
||||
<div class="flex-grow p-4 w-60 left-divider">
|
||||
<div class="fs-title text-xl">
|
||||
<EditBox bind:value={milestone.label} on:change={() => change('label', milestone.label)} />
|
||||
</div>
|
||||
<div class="popupPanel-body__aside-content">
|
||||
<EditBox kind={'large-style'} bind:value={milestone.label} on:change={() => change('label', milestone.label)} />
|
||||
<div class="mt-2">
|
||||
<StyledTextBox
|
||||
alwaysEdit={true}
|
||||
@ -87,7 +83,7 @@
|
||||
on:value={(evt) => change('description', evt.detail)}
|
||||
/>
|
||||
</div>
|
||||
<DocAttributeBar object={milestone} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
|
||||
</div>
|
||||
<DocAttributeBar object={milestone} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
|
||||
</svelte:fragment>
|
||||
</IssuesView>
|
||||
|
@ -147,17 +147,15 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<TabList
|
||||
items={modeList}
|
||||
selected={mode}
|
||||
kind={'normal'}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined && result.detail.action) result.detail.action()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="ac-header tabs-start full divide">
|
||||
<TabList
|
||||
items={modeList}
|
||||
selected={mode}
|
||||
kind={'plain'}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined && result.detail.action) result.detail.action()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FilterBar
|
||||
|
@ -226,9 +226,7 @@
|
||||
<svelte:window on:keydown={handleKeys} />
|
||||
|
||||
{#if $previewDocument !== undefined && presenter}
|
||||
<div transition:fly|local style:position="fixed" style:right={'0'} style:top={'10rem'} style:z-index={'500'}>
|
||||
<div class="antiPanel p-6">
|
||||
<Component is={presenter} props={{ object: $previewDocument }} />
|
||||
</div>
|
||||
<div class="antiPanel float" transition:fly|local>
|
||||
<Component is={presenter} props={{ object: $previewDocument }} />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -104,7 +104,7 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 0.75rem;
|
||||
padding: 0 0.125rem 0 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--theme-dark-color);
|
||||
border-top: 1px solid var(--theme-divider-color);
|
||||
|
@ -300,21 +300,16 @@
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="aside-tabs">
|
||||
<div class="flex-row-center flex-reverse flex-grow">
|
||||
<Button
|
||||
kind={'transparent'}
|
||||
shape={'round'}
|
||||
selected={showAllMixins}
|
||||
on:click={() => {
|
||||
showAllMixins = !showAllMixins
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="icon">
|
||||
<IconMixin size={'small'} />
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
</div>
|
||||
<svelte:fragment slot="actions">
|
||||
<Button
|
||||
icon={IconMixin}
|
||||
kind={'transparent'}
|
||||
shape={'round'}
|
||||
selected={showAllMixins}
|
||||
on:click={() => {
|
||||
showAllMixins = !showAllMixins
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="attributes" let:direction={dir}>
|
||||
{#if !headerLoading}
|
||||
|
@ -38,7 +38,7 @@ test('create-issue-and-sub-issue', async ({ page }) => {
|
||||
await checkIssue(page, props)
|
||||
props.name = `sub${props.name}`
|
||||
await createSubissue(page, props)
|
||||
await page.click(`span[title=${props.name}]`)
|
||||
await page.click(`.antiList__row:has-text("${props.name}") .name a`)
|
||||
await checkIssue(page, props)
|
||||
})
|
||||
|
||||
|
@ -138,10 +138,10 @@ export async function checkIssue (page: Page, props: IssueProps): Promise<void>
|
||||
const { name, description, status, assignee, labels, priority, component, milestone } = props
|
||||
|
||||
if (name !== undefined) {
|
||||
await expect(page.locator('.popupPanel')).toContainText(name)
|
||||
await expect(page.locator('.popupPanel.panel')).toContainText(name)
|
||||
}
|
||||
if (description !== undefined) {
|
||||
await expect(page.locator('.popupPanel')).toContainText(description)
|
||||
await expect(page.locator('.popupPanel.panel')).toContainText(description)
|
||||
}
|
||||
const asideLocator = page.locator('.popupPanel-body__aside')
|
||||
if (status !== undefined) {
|
||||
@ -170,7 +170,7 @@ export async function checkIssueFromList (page: Page, issueName: string): Promis
|
||||
}
|
||||
|
||||
export async function openIssue (page: Page, name: string): Promise<void> {
|
||||
await page.click(`.antiList__row:has-text("${name}") .issuePresenterRoot`, {
|
||||
await page.click(`.antiList__row:has-text("${name}") .name a`, {
|
||||
timeout: 15000
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user