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:
Alexander Platov 2023-05-17 02:47:21 -07:00 committed by GitHub
parent cc3afc40a3
commit a5a464a112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 234 additions and 219 deletions

View File

@ -165,9 +165,11 @@
{#if $$slots.actions} {#if $$slots.actions}
<div class="popupPanel-body__aside-header"> <div class="popupPanel-body__aside-header">
{#if $$slots['actions-label']} {#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} {/if}
<div class="buttons-group xsmall-gap flex flex-grow"> <div class="buttons-group xsmall-gap">
<slot name="actions" /> <slot name="actions" />
</div> </div>
</div> </div>
@ -177,7 +179,7 @@
<slot name="custom-attributes" direction="column" /> <slot name="custom-attributes" direction="column" />
{:else if $$slots.attributes}<slot name="attributes" direction="column" />{/if} {:else if $$slots.attributes}<slot name="attributes" direction="column" />{/if}
{#if $$slots.aside}<slot name="aside" />{/if} {#if $$slots.aside}<slot name="aside" />{/if}
<div class="h-2 min-h-2 max-h-2" /> <div class="space-divider bottom" />
</Scroller> </Scroller>
</svelte:fragment> </svelte:fragment>

View File

@ -32,7 +32,7 @@
export let justify: 'left' | 'center' = 'left' export let justify: 'left' | 'center' = 'left'
</script> </script>
<div class="popupPanel-body__aside-grid"> <div class="popupPanel-body__aside-grid inCollapsed">
{#each keys as key (typeof key === 'string' ? key : key.key)} {#each keys as key (typeof key === 'string' ? key : key.key)}
<AttributeBarEditor {key} {_class} {object} {showHeader} {readonly} {draft} on:update /> <AttributeBarEditor {key} {_class} {object} {showHeader} {readonly} {draft} on:update />
{/each} {/each}

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
export let size: 'small' | 'medium' | 'large' export let size: 'x-small' | 'small' | 'medium' | 'large'
const fill: string = 'currentColor' const fill: string = 'currentColor'
</script> </script>

View File

@ -38,6 +38,7 @@ export { default as IndexedDocumentPreview } from './components/IndexedDocumentP
export { default as IndexedDocumentCompare } from './components/IndexedDocumentCompare.svelte' export { default as IndexedDocumentCompare } from './components/IndexedDocumentCompare.svelte'
export { default as DraggableList } from './components/DraggableList.svelte' export { default as DraggableList } from './components/DraggableList.svelte'
export { default as NavLink } from './components/NavLink.svelte' export { default as NavLink } from './components/NavLink.svelte'
export { default as IconForward } from './components/icons/Forward.svelte'
export { default } from './plugin' export { default } from './plugin'
export * from './types' export * from './types'
export * from './utils' export * from './utils'

View File

@ -496,7 +496,9 @@ input.search {
.pl-2 { padding-left: .5rem; } .pl-2 { padding-left: .5rem; }
.pl-3 { padding-left: .75rem; } .pl-3 { padding-left: .75rem; }
.pl-4 { padding-left: 1rem; } .pl-4 { padding-left: 1rem; }
.pl-7 { padding-left: 1.75rem; }
.pl-8 { padding-left: 2rem; } .pl-8 { padding-left: 2rem; }
.pl-9 { padding-left: 2.25rem; }
.pl-10 { padding-left: 2.5rem; } .pl-10 { padding-left: 2.5rem; }
.pr-1 { padding-right: .25rem; } .pr-1 { padding-right: .25rem; }
.pr-2 { padding-right: .5rem; } .pr-2 { padding-right: .5rem; }
@ -602,6 +604,7 @@ input.search {
.h-7 { height: 1.75rem; } .h-7 { height: 1.75rem; }
.h-8 { height: 2rem; } .h-8 { height: 2rem; }
.h-9 { height: 2.25rem; } .h-9 { height: 2.25rem; }
.h-12 { height: 3rem; }
.h-14 { height: 3.5rem; } .h-14 { height: 3.5rem; }
.h-16 { height: 4rem; } .h-16 { height: 4rem; }
.h-18 { height: 4.5rem; } .h-18 { height: 4.5rem; }

View File

@ -31,7 +31,7 @@
min-height: 0; min-height: 0;
background: var(--theme-popup-color); background: var(--theme-popup-color);
border-radius: .5rem; border-radius: .5rem;
box-shadow: var(--card-shadow); box-shadow: var(--theme-popup-shadow);
.antiCard-header { .antiCard-header {
position: relative; position: relative;

View File

@ -18,18 +18,38 @@
overflow: hidden; overflow: hidden;
min-width: 400px; min-width: 400px;
background: var(--body-accent); background-color: var(--theme-popup-color);
border: 1px solid var(--divider-color); border: 1px solid var(--theme-popup-divider);
border-radius: .5rem; border-radius: .5rem;
flex-direction: row; flex-direction: row;
box-shadow: var(--popup-shadow); box-shadow: var(--theme-popup-shadow);
// left: 1rem; // 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 { .ac-header {
&.highlight { background-color: var(--accent-bg-color); } &.highlight { background-color: var(--accent-bg-color); }
&.divide { border-bottom: 1px solid var(--divider-color); } &.divide { border-bottom: 1px solid var(--divider-color); }
} }
.ad-section-50 { .ad-section-50 {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -39,7 +59,6 @@
&.divide { border-right: 1px solid var(--divider-color); } &.divide { border-right: 1px solid var(--divider-color); }
} }
.ad-tools { .ad-tools {
position: absolute; position: absolute;
display: flex; display: flex;
@ -58,18 +77,16 @@
.popupPanel { .popupPanel {
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column;
min-height: 0; min-height: 0;
height: 100%; height: 100%;
&.embedded { &.rowContent {
width: 100%; width: 100%;
min-width: 0;
} }
&:not(.rowContent) { flex-direction: column; }
&:not(.embedded) { &.embedded { width: 100%; }
border-radius: .5rem; &:not(.embedded) { border-radius: .5rem; }
// box-shadow: var(--popup-panel-shadow);
}
.popupPanel-title { .popupPanel-title {
display: flex; display: flex;
@ -258,27 +275,29 @@
display: flex; display: flex;
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
padding: .75rem 2rem;
height: 3.5rem; height: 3.5rem;
min-height: 3.5rem; min-height: 3.5rem;
border-bottom: 1px solid var(--theme-divider-color); border-bottom: 1px solid var(--theme-divider-color);
} }
&-tabsheader { &-tabsheader { padding: 0 2rem; }
padding: 0 2rem; &-header {
justify-content: space-between;
padding: .75rem .75rem .75rem 2rem;
} }
&-grid { &-grid {
display: grid; display: grid;
grid-template-columns: 1fr 1.5fr; grid-template-columns: 1fr 1.5fr;
grid-auto-flow: row; grid-auto-rows: minmax(2rem, max-content);
justify-content: start; justify-content: start;
align-items: center; align-items: center;
row-gap: .25rem; row-gap: .25rem;
column-gap: 1rem; column-gap: 1rem;
margin: .5rem 2rem; margin: .25rem 2rem 0;
width: calc(100% - 4rem); width: calc(100% - 4rem);
height: min-content; height: min-content;
&.inCollapsed { margin: 1rem 2rem; }
.divider { .divider {
grid-column: 1 / 3; grid-column: 1 / 3;
margin: .75rem -2rem; margin: .75rem -2rem;
@ -289,9 +308,24 @@
.labelTop { color: var(--theme-dark-color); } .labelTop { color: var(--theme-dark-color); }
.labelTop { .labelTop {
align-self: start; 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 { // &.asideShown .popupPanel-body__main {

View File

@ -79,7 +79,7 @@
</script> </script>
<div <div
class="popupPanel" class="popupPanel panel"
class:embedded class:embedded
use:resizeObserver={(element) => { use:resizeObserver={(element) => {
panelWidth = element.clientWidth panelWidth = element.clientWidth

View File

@ -32,6 +32,7 @@
export let invertScroll: boolean = false export let invertScroll: boolean = false
export let horizontal: boolean = false export let horizontal: boolean = false
export let contentDirection: 'vertical' | 'vertical-reverse' | 'horizontal' = 'vertical' 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 noStretch: boolean = autoscroll
export let buttons: 'normal' | 'union' | false = false export let buttons: 'normal' | 'union' | false = false
export let shrink: boolean = false export let shrink: boolean = false
@ -497,7 +498,7 @@
> >
<div <div
bind:this={divBox} bind:this={divBox}
class="box" class="box{gap ? ` ${gap}` : ''}"
class:align-center={contentDirection === 'horizontal'} class:align-center={contentDirection === 'horizontal'}
style:padding style:padding
style:flex-direction={contentDirection === 'vertical' style:flex-direction={contentDirection === 'vertical'
@ -689,9 +690,9 @@
&.vertical { &.vertical {
min-width: 1.5rem 0; min-width: 1.5rem 0;
} }
&.horizontal { // &.horizontal {
margin-right: 2rem; // margin-right: 2rem;
} // }
&.buttons.vertical { &.buttons.vertical {
margin: 1.5rem 0; margin: 1.5rem 0;
} }

View File

@ -232,18 +232,18 @@
&.link { &.link {
justify-content: flex-start; justify-content: flex-start;
padding: 0 0.875rem; padding: 0 0.875rem;
height: 2rem; color: var(--theme-dark-color);
border-radius: 0.25rem; border-radius: 0.25rem;
.btn-icon { .btn-icon {
margin-right: 0.5rem; color: var(--theme-darker-color);
} }
&:hover { &:hover {
color: var(--theme-caption-color); color: var(--theme-content-color);
background-color: var(--theme-button-hovered); background-color: var(--theme-bg-color);
border-color: var(--theme-divider-color); border-color: var(--theme-divider-color);
.btn-icon { .btn-icon {
color: var(--theme-caption-color); color: var(--theme-content-color);
} }
} }
} }

View File

@ -15,6 +15,7 @@
<script lang="ts"> <script lang="ts">
import { Attachment } from '@hcengineering/attachment' import { Attachment } from '@hcengineering/attachment'
import { Ref } from '@hcengineering/core' import { Ref } from '@hcengineering/core'
import { Scroller } from '@hcengineering/ui'
import AttachmentPreview from './AttachmentPreview.svelte' import AttachmentPreview from './AttachmentPreview.svelte'
export let attachments: Attachment[] = [] export let attachments: Attachment[] = []
@ -22,11 +23,9 @@
</script> </script>
{#if attachments.length} {#if attachments.length}
<div class="flex flex-wrap"> <Scroller contentDirection={'horizontal'} horizontal gap={'gap-3'}>
{#each attachments as attachment} {#each attachments as attachment}
<div class="p-2"> <AttachmentPreview value={attachment} isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false} />
<AttachmentPreview value={attachment} isSaved={savedAttachmentsIds?.includes(attachment._id) ?? false} />
</div>
{/each} {/each}
</div> </Scroller>
{/if} {/if}

View File

@ -379,7 +379,8 @@
} }
tbody tr:not(:last-child), 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); border-bottom: 1px solid var(--theme-bg-divider-color);
} }
tfoot tr, tfoot tr,

View File

@ -120,21 +120,19 @@
</div> </div>
{/if} {/if}
</svelte:fragment> </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}> <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'} {#if dir === 'column'}
<DocAttributeBar <DocAttributeBar
{object} {object}

View File

@ -1,10 +1,14 @@
<script lang="ts"> <script lang="ts">
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { DueDatePresenter } from '@hcengineering/ui' import { DueDatePresenter, ButtonSize, ButtonKind } from '@hcengineering/ui'
import { WithLookup } from '@hcengineering/core' import { WithLookup } from '@hcengineering/core'
import { Task } from '@hcengineering/task' import { Task } from '@hcengineering/task'
export let object: WithLookup<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() const client = getClient()
$: shouldIgnoreOverdue = object.doneState != null $: shouldIgnoreOverdue = object.doneState != null
@ -28,9 +32,11 @@
{#if object} {#if object}
<DueDatePresenter <DueDatePresenter
kind={'link'} {kind}
{width}
{size}
value={object.dueDate} value={object.dueDate}
editable {editable}
onChange={(e) => handleDueDateChanged(e)} onChange={(e) => handleDueDateChanged(e)}
{shouldIgnoreOverdue} {shouldIgnoreOverdue}
/> />

View File

@ -114,7 +114,7 @@
<div class="ac-header full divide caption-height"> <div class="ac-header full divide caption-height">
<div class="ac-header__wrap-title mr-3"> <div class="ac-header__wrap-title mr-3">
<span class="ac-header__title"><Label {label} /></span> <span class="ac-header__title"><Label {label} /></span>
<span class="componentTitle"> <span class="componentTitle ml-1">
<Label label={title} /> <Label label={title} />
</span> </span>
</div> </div>
@ -146,15 +146,8 @@
{/if} {/if}
</div> </div>
</div> </div>
<div class="ac-header full divide search-start"> <div class="ac-header tabs-start full divide">
<div class="ac-header-full small-gap"> <TabList items={filterModeList} selected={filterMode} kind={'plain'} on:select={({ detail }) => detail?.action?.()} />
<TabList
items={filterModeList}
selected={filterMode}
kind="normal"
on:select={({ detail }) => detail?.action?.()}
/>
</div>
</div> </div>
<FilterBar <FilterBar

View File

@ -48,10 +48,8 @@
</Button> </Button>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="aside"> <svelte:fragment slot="aside">
<div class="flex-row p-4 w-60 left-divider"> <div class="popupPanel-body__aside-content">
<div class="fs-title text-xl"> <EditBox kind={'large-style'} bind:value={component.label} on:change={() => change('label', component.label)} />
<EditBox bind:value={component.label} on:change={() => change('label', component.label)} />
</div>
<div class="mt-2"> <div class="mt-2">
<StyledTextBox <StyledTextBox
alwaysEdit={true} alwaysEdit={true}
@ -61,7 +59,7 @@
on:value={(evt) => change('description', evt.detail)} on:value={(evt) => change('description', evt.detail)}
/> />
</div> </div>
<DocAttributeBar object={component} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
</div> </div>
<DocAttributeBar object={component} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
</svelte:fragment> </svelte:fragment>
</IssuesView> </IssuesView>

View File

@ -47,6 +47,6 @@
$: formatTime(value) $: formatTime(value)
</script> </script>
<span style="white-space: nowrap;"> <span class="textPadding" style="white-space: nowrap;">
{time} {time}
</span> </span>

View File

@ -18,9 +18,9 @@
import chunter from '@hcengineering/chunter' import chunter from '@hcengineering/chunter'
import { CommentPopup } from '@hcengineering/chunter-resources' import { CommentPopup } from '@hcengineering/chunter-resources'
import { Ref } from '@hcengineering/core' 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 { Issue, Project } from '@hcengineering/tracker'
import { Label, resizeObserver, Scroller } from '@hcengineering/ui' import { Label, Scroller, resizeObserver } from '@hcengineering/ui'
import tracker from '../../plugin' import tracker from '../../plugin'
import AssigneeEditor from './AssigneeEditor.svelte' import AssigneeEditor from './AssigneeEditor.svelte'
import IssueStatusActivity from './IssueStatusActivity.svelte' import IssueStatusActivity from './IssueStatusActivity.svelte'
@ -50,8 +50,7 @@
$: issueName = currentProject && issue && `${currentProject.identifier}-${issue.number}` $: issueName = currentProject && issue && `${currentProject.identifier}-${issue.number}`
const limit: number = 350 const limit: number = 350
let cHeight: number = 0
let cHeight: number
let parent: Issue | undefined let parent: Issue | undefined
@ -66,73 +65,87 @@
$: getParent(issue?.attachedTo as Ref<Issue>) $: getParent(issue?.attachedTo as Ref<Issue>)
</script> </script>
<div class="flex"> {#if issue}
<Scroller> <div class="ap-header flex-between">
<div class="w-165 scrollerContent"> <div class="flex-col">
{#if parent} <div class="flex-row-center gap-1">
<div class="mb-4 ml-2">{parent.title}</div> {#if parent}
{/if} <span class="overflow-label content-color">{parent.title}</span>
{#if issue} <IconForward size={'x-small'} />
<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} {/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} {/if}
</div> </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> </Scroller>
</div> <div class="h-3 flex-no-shrink" />
{/if}
<style lang="scss"> <style lang="scss">
.descr { .description-container {
overflow: hidden; overflow: hidden;
height: auto;
min-height: 0;
&.mask { &.masked {
mask: linear-gradient(to top, rgba(0, 0, 0, 0) 0, black 5rem); mask-image: linear-gradient(0deg, #0000 0, #000f 4rem);
}
.description-content {
width: 100%;
min-width: 0;
height: max-content;
min-height: 0;
} }
} }
.grid-preview {
.scrollerContent { display: grid;
height: fit-content; grid-template-columns: 1fr 2fr;
max-height: 32rem; 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> </style>

View File

@ -2,13 +2,14 @@
import core, { Ref, Timestamp, Tx, TxCollectionCUD, TxCreateDoc, TxUpdateDoc, WithLookup } from '@hcengineering/core' import core, { Ref, Timestamp, Tx, TxCollectionCUD, TxCreateDoc, TxUpdateDoc, WithLookup } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation' import { createQuery } from '@hcengineering/presentation'
import { Issue, IssueStatus } from '@hcengineering/tracker' import { Issue, IssueStatus } from '@hcengineering/tracker'
import { Label, ticker } from '@hcengineering/ui' import { Label, ticker, Row } from '@hcengineering/ui'
import tracker from '../../plugin' import tracker from '../../plugin'
import { statusStore } from '@hcengineering/presentation' import { statusStore } from '@hcengineering/presentation'
import Duration from './Duration.svelte' import Duration from './Duration.svelte'
import StatusPresenter from './StatusPresenter.svelte' import StatusPresenter from './StatusPresenter.svelte'
export let issue: Issue export let issue: Issue
export let accentHeader: boolean = false
const query = createQuery() const query = createQuery()
@ -86,20 +87,12 @@
$: updateStatus(txes, $statusStore.byId, $ticker) $: updateStatus(txes, $statusStore.byId, $ticker)
</script> </script>
<div class="flex-row mt-4 mb-4"> <Row>
<span class="content-dark-color"><Label label={tracker.string.StatusHistory} />:</span> <span class="label" class:fs-bold={accentHeader} class:content-dark-color={accentHeader}>
<table class="ml-2"> <Label label={tracker.string.StatusHistory} />:
{#each displaySt as st} </span>
<tr> </Row>
<td class="flex-row-center mt-2 mb-2"> {#each displaySt as st}
<StatusPresenter value={st.status} /> <StatusPresenter value={st.status} />
</td> <Duration value={st.duration} />
<td> {/each}
<div class="ml-8 mr-2">
<Duration value={st.duration} />
</div>
</td>
</tr>
{/each}
</table>
</div>

View File

@ -114,12 +114,12 @@
</IssuesHeader> </IssuesHeader>
<FilterBar _class={tracker.class.Issue} query={searchQuery} {viewOptions} on:change={(e) => (resultQuery = e.detail)} /> <FilterBar _class={tracker.class.Issue} query={searchQuery} {viewOptions} on:change={(e) => (resultQuery = e.detail)} />
<slot name="afterHeader" /> <slot name="afterHeader" />
<div class="flex w-full h-full clear-mins"> <div class="popupPanel rowContent">
{#if viewlet} {#if viewlet}
<IssuesContent {viewlet} query={resultQuery} {space} {viewOptions} /> <IssuesContent {viewlet} query={resultQuery} {space} {viewOptions} />
{/if} {/if}
{#if $$slots.aside !== undefined && asideShown} {#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" /> <slot name="aside" />
</div> </div>
{/if} {/if}

View File

@ -289,28 +289,14 @@
<svelte:fragment slot="custom-attributes"> <svelte:fragment slot="custom-attributes">
{#if issue && currentProject} {#if issue && currentProject}
<div class="space-divider" />
<ControlPanel {issue} {showAllMixins} /> <ControlPanel {issue} {showAllMixins} />
{/if} {/if}
<div class="divider" /> <div class="popupPanel-body__aside-grid">
<div class="issue-stats"> <div class="divider" />
<IssueStatusActivity {issue} /> <IssueStatusActivity {issue} />
</div> </div>
</svelte:fragment> </svelte:fragment>
</Panel> </Panel>
{/if} {/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>

View File

@ -61,10 +61,8 @@
</div> </div>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="afterHeader"> <svelte:fragment slot="afterHeader">
<div class="p-1 ml-6 flex-row-center"> <div class="ac-header search-start full divide">
<div class="flex-row-center"> <DatePresenter value={milestone.targetDate} kind={'transparent'} size={'medium'} />
<DatePresenter value={milestone.targetDate} kind={'transparent'} />
</div>
<div class="flex-row-center ml-2"> <div class="flex-row-center ml-2">
{#if milestone?.capacity} {#if milestone?.capacity}
<Label label={tracker.string.CapacityValue} params={{ value: milestone?.capacity }} /> <Label label={tracker.string.CapacityValue} params={{ value: milestone?.capacity }} />
@ -74,10 +72,8 @@
</div> </div>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="aside"> <svelte:fragment slot="aside">
<div class="flex-grow p-4 w-60 left-divider"> <div class="popupPanel-body__aside-content">
<div class="fs-title text-xl"> <EditBox kind={'large-style'} bind:value={milestone.label} on:change={() => change('label', milestone.label)} />
<EditBox bind:value={milestone.label} on:change={() => change('label', milestone.label)} />
</div>
<div class="mt-2"> <div class="mt-2">
<StyledTextBox <StyledTextBox
alwaysEdit={true} alwaysEdit={true}
@ -87,7 +83,7 @@
on:value={(evt) => change('description', evt.detail)} on:value={(evt) => change('description', evt.detail)}
/> />
</div> </div>
<DocAttributeBar object={milestone} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
</div> </div>
<DocAttributeBar object={milestone} mixins={[]} ignoreKeys={['icon', 'label', 'description']} />
</svelte:fragment> </svelte:fragment>
</IssuesView> </IssuesView>

View File

@ -147,17 +147,15 @@
{/if} {/if}
</div> </div>
</div> </div>
<div class="ac-header full divide search-start"> <div class="ac-header tabs-start full divide">
<div class="ac-header-full small-gap"> <TabList
<TabList items={modeList}
items={modeList} selected={mode}
selected={mode} kind={'plain'}
kind={'normal'} on:select={(result) => {
on:select={(result) => { if (result.detail !== undefined && result.detail.action) result.detail.action()
if (result.detail !== undefined && result.detail.action) result.detail.action() }}
}} />
/>
</div>
</div> </div>
<FilterBar <FilterBar

View File

@ -226,9 +226,7 @@
<svelte:window on:keydown={handleKeys} /> <svelte:window on:keydown={handleKeys} />
{#if $previewDocument !== undefined && presenter} {#if $previewDocument !== undefined && presenter}
<div transition:fly|local style:position="fixed" style:right={'0'} style:top={'10rem'} style:z-index={'500'}> <div class="antiPanel float" transition:fly|local>
<div class="antiPanel p-6"> <Component is={presenter} props={{ object: $previewDocument }} />
<Component is={presenter} props={{ object: $previewDocument }} />
</div>
</div> </div>
{/if} {/if}

View File

@ -104,7 +104,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0 0.75rem; padding: 0 0.125rem 0 0.75rem;
font-weight: 600; font-weight: 600;
color: var(--theme-dark-color); color: var(--theme-dark-color);
border-top: 1px solid var(--theme-divider-color); border-top: 1px solid var(--theme-divider-color);

View File

@ -300,21 +300,16 @@
</div> </div>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="aside-tabs"> <svelte:fragment slot="actions">
<div class="flex-row-center flex-reverse flex-grow"> <Button
<Button icon={IconMixin}
kind={'transparent'} kind={'transparent'}
shape={'round'} shape={'round'}
selected={showAllMixins} selected={showAllMixins}
on:click={() => { on:click={() => {
showAllMixins = !showAllMixins showAllMixins = !showAllMixins
}} }}
> />
<svelte:fragment slot="icon">
<IconMixin size={'small'} />
</svelte:fragment>
</Button>
</div>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="attributes" let:direction={dir}> <svelte:fragment slot="attributes" let:direction={dir}>
{#if !headerLoading} {#if !headerLoading}

View File

@ -38,7 +38,7 @@ test('create-issue-and-sub-issue', async ({ page }) => {
await checkIssue(page, props) await checkIssue(page, props)
props.name = `sub${props.name}` props.name = `sub${props.name}`
await createSubissue(page, props) 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) await checkIssue(page, props)
}) })

View File

@ -138,10 +138,10 @@ export async function checkIssue (page: Page, props: IssueProps): Promise<void>
const { name, description, status, assignee, labels, priority, component, milestone } = props const { name, description, status, assignee, labels, priority, component, milestone } = props
if (name !== undefined) { if (name !== undefined) {
await expect(page.locator('.popupPanel')).toContainText(name) await expect(page.locator('.popupPanel.panel')).toContainText(name)
} }
if (description !== undefined) { 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') const asideLocator = page.locator('.popupPanel-body__aside')
if (status !== undefined) { 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> { 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 timeout: 15000
}) })
} }