mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-21 07:46:24 +00:00
Update EstimationPopup layout (#2513)
This commit is contained in:
parent
ecc3f55d23
commit
835a37c6f0
@ -381,11 +381,6 @@ input.search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Margins & Paddings */
|
/* Margins & Paddings */
|
||||||
.step-lr25 + .step-lr25 { margin-left: .25rem; }
|
|
||||||
.step-lr75 + .step-lr75 { margin-left: .75rem; }
|
|
||||||
.step-tb75 + .step-tb75 { margin-top: .75rem; }
|
|
||||||
.step-tb-6 + .step-tb-6 { margin-top: 1.5rem; }
|
|
||||||
|
|
||||||
.ml-0-5 { margin-left: .125rem; }
|
.ml-0-5 { margin-left: .125rem; }
|
||||||
.ml-1 { margin-left: .25rem; }
|
.ml-1 { margin-left: .25rem; }
|
||||||
.ml-1-5 { margin-left: .375rem; }
|
.ml-1-5 { margin-left: .375rem; }
|
||||||
@ -476,6 +471,28 @@ input.search {
|
|||||||
.p-6 { padding: 1.5rem; }
|
.p-6 { padding: 1.5rem; }
|
||||||
.p-10 { padding: 2.5rem; }
|
.p-10 { padding: 2.5rem; }
|
||||||
|
|
||||||
|
.p-text { padding: .125rem .25rem; }
|
||||||
|
.p-text-2 { padding: .25rem .5rem; }
|
||||||
|
|
||||||
|
.step-lr25 + .step-lr25 { margin-left: .25rem; }
|
||||||
|
.step-lr75 + .step-lr75 { margin-left: .75rem; }
|
||||||
|
.step-tb75 + .step-tb75 { margin-top: .75rem; }
|
||||||
|
.step-tb-6 + .step-tb-6 { margin-top: 1.5rem; }
|
||||||
|
|
||||||
|
.step-tb-2-accent + .step-tb-2-accent {
|
||||||
|
position: relative;
|
||||||
|
margin-top: .5rem;
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -.25rem;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
background-color: var(--popup-bg-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* --------- */
|
/* --------- */
|
||||||
.no-word-wrap { word-wrap: none; }
|
.no-word-wrap { word-wrap: none; }
|
||||||
.relative { position: relative; }
|
.relative { position: relative; }
|
||||||
|
@ -275,6 +275,9 @@
|
|||||||
min-height: 1px;
|
min-height: 1px;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: var(--divider-color);
|
background-color: var(--divider-color);
|
||||||
|
|
||||||
|
&.dark { background-color: var(--body-accent); }
|
||||||
|
&.noMargin { margin: 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.antiSection {
|
.antiSection {
|
||||||
|
@ -173,10 +173,10 @@
|
|||||||
.antiCard-pool {
|
.antiCard-pool {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0 .75rem .75rem;
|
margin: 0 .5rem .25rem;
|
||||||
font-size: .75rem;
|
font-size: .75rem;
|
||||||
|
|
||||||
& > *:not(:last-child) { margin-right: .375rem; }
|
& > * { margin: 0 .25rem .5rem; }
|
||||||
}
|
}
|
||||||
.antiCard-footer {
|
.antiCard-footer {
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
|
85
packages/ui/src/components/Chevron.svelte
Normal file
85
packages/ui/src/components/Chevron.svelte
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import IconDownOutline from './icons/DownOutline.svelte'
|
||||||
|
|
||||||
|
export let size: 'small' | 'medium' = 'medium'
|
||||||
|
export let fill = 'var(--dark-color)'
|
||||||
|
export let expanded: boolean = false
|
||||||
|
export let direction: 'left' | 'right' = 'right'
|
||||||
|
export let outline: boolean = false
|
||||||
|
export let marginRight: string | undefined = undefined
|
||||||
|
export let marginLeft: string | undefined = undefined
|
||||||
|
export let margin: string | undefined = undefined
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="chevron {size} {direction}"
|
||||||
|
class:outline
|
||||||
|
class:expanded
|
||||||
|
style:margin-right={marginRight}
|
||||||
|
style:margin-left={marginLeft}
|
||||||
|
style:margin
|
||||||
|
>
|
||||||
|
{#if outline}
|
||||||
|
<IconDownOutline {size} {fill} />
|
||||||
|
{:else}
|
||||||
|
<svg {fill} viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0,0L6,3L0,6Z" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.chevron {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: transform 0.15s var(--timing-main);
|
||||||
|
|
||||||
|
&.outline {
|
||||||
|
transform-origin: center;
|
||||||
|
&.right {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
&.left {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
&.expanded {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(.outline) {
|
||||||
|
transform-origin: 35% center;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
width: 0.325rem;
|
||||||
|
height: 0.325rem;
|
||||||
|
}
|
||||||
|
&.medium {
|
||||||
|
width: 0.375rem;
|
||||||
|
height: 0.375rem;
|
||||||
|
}
|
||||||
|
&.right {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
&.left {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
&.expanded {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -18,7 +18,7 @@
|
|||||||
import { tweened } from 'svelte/motion'
|
import { tweened } from 'svelte/motion'
|
||||||
|
|
||||||
export let isExpanded = false
|
export let isExpanded = false
|
||||||
export let duration = 200
|
export let duration = 150
|
||||||
export let easing: (t: number) => number = quintOut
|
export let easing: (t: number) => number = quintOut
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
@ -17,51 +17,62 @@
|
|||||||
import ExpandCollapse from './ExpandCollapse.svelte'
|
import ExpandCollapse from './ExpandCollapse.svelte'
|
||||||
import Icon from './Icon.svelte'
|
import Icon from './Icon.svelte'
|
||||||
import Label from './Label.svelte'
|
import Label from './Label.svelte'
|
||||||
|
import Chevron from './Chevron.svelte'
|
||||||
|
|
||||||
export let icon: Asset | undefined = undefined
|
export let icon: Asset | undefined = undefined
|
||||||
export let label: IntlString | undefined = undefined
|
export let label: IntlString | undefined = undefined
|
||||||
export let expanded: boolean = false
|
export let expanded: boolean = false
|
||||||
|
export let bordered: boolean = false
|
||||||
export let expandable = true
|
export let expandable = true
|
||||||
|
export let contentColor = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
<div class="flex-col">
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<div class="expandable-header flex-between" class:expanded class:bordered>
|
||||||
<div class="flex-grow flex" class:expanded class:expandable>
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div
|
<div
|
||||||
class="fs-title flex-row-center mr-4"
|
class="flex-row-center mr-4"
|
||||||
on:click|stopPropagation={() => {
|
class:cursor-pointer={expandable}
|
||||||
expanded = !expanded
|
on:click|stopPropagation={() => {
|
||||||
}}
|
if (expandable) expanded = !expanded
|
||||||
>
|
}}
|
||||||
<div class="chevron" class:expanded>▶</div>
|
>
|
||||||
<div class="an-element__icon">
|
<Chevron {expanded} marginRight={'.5rem'} />
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<Icon {icon} size={'small'} />
|
<div class="min-w-4 mr-2">
|
||||||
|
<Icon {icon} size={'small'} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
<span class="fs-title overflow-label" class:content-color={contentColor}>
|
||||||
|
{#if label}<Label {label} />{/if}<slot name="title" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="an-element__label title">
|
{#if $$slots.tools}
|
||||||
{#if label}<Label {label} />{/if}
|
<div class="buttons-group small-gap">
|
||||||
<slot name="title" />
|
<slot name="tools" />
|
||||||
</span>
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<slot name="tools" />
|
<ExpandCollapse isExpanded={expanded}>
|
||||||
</div>
|
|
||||||
<ExpandCollapse isExpanded={expanded}>
|
|
||||||
<div class="antiComponent p-2">
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</ExpandCollapse>
|
||||||
</ExpandCollapse>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.expandable {
|
.expandable-header {
|
||||||
.chevron {
|
transition: margin-bottom 0.15s var(--timing-main);
|
||||||
content: '▶';
|
|
||||||
margin-right: 0.5rem;
|
&:not(.expanded) {
|
||||||
font-size: 0.75rem;
|
margin-bottom: 0;
|
||||||
color: var(--dark-color);
|
}
|
||||||
&.expanded {
|
&.expanded {
|
||||||
transform: rotateZ(90deg);
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
&.bordered {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
background-color: var(--body-accent);
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 0.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
export let selection: number = 0
|
export let selection: number = 0
|
||||||
export let count: number
|
export let count: number
|
||||||
|
export let addClass: string | undefined = undefined
|
||||||
|
|
||||||
const refs: HTMLElement[] = []
|
const refs: HTMLElement[] = []
|
||||||
|
|
||||||
@ -66,8 +67,9 @@
|
|||||||
>
|
>
|
||||||
{#each Array(count) as _, row}
|
{#each Array(count) as _, row}
|
||||||
<slot name="category" item={row} />
|
<slot name="category" item={row} />
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div
|
<div
|
||||||
class="list-item"
|
class="list-item{addClass ? ` ${addClass}` : ''}"
|
||||||
class:selection={row === selection}
|
class:selection={row === selection}
|
||||||
on:mouseover={() => onRow(row)}
|
on:mouseover={() => onRow(row)}
|
||||||
on:focus={() => {}}
|
on:focus={() => {}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let size: 'x-small' | 'small' | 'medium' | 'large' | 'full'
|
export let size: 'x-small' | 'small' | 'medium' | 'large' | 'full'
|
||||||
const fill: string = 'currentColor'
|
export let fill: string = 'currentColor'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
@ -99,6 +99,7 @@ export { default as ErrorPresenter } from './components/ErrorPresenter.svelte'
|
|||||||
export { default as Scroller } from './components/Scroller.svelte'
|
export { default as Scroller } from './components/Scroller.svelte'
|
||||||
export { default as ScrollerBar } from './components/ScrollerBar.svelte'
|
export { default as ScrollerBar } from './components/ScrollerBar.svelte'
|
||||||
export { default as TabList } from './components/TabList.svelte'
|
export { default as TabList } from './components/TabList.svelte'
|
||||||
|
export { default as Chevron } from './components/Chevron.svelte'
|
||||||
|
|
||||||
export { default as IconAdd } from './components/icons/Add.svelte'
|
export { default as IconAdd } from './components/icons/Add.svelte'
|
||||||
export { default as IconBack } from './components/icons/Back.svelte'
|
export { default as IconBack } from './components/icons/Back.svelte'
|
||||||
|
@ -75,9 +75,7 @@
|
|||||||
<div class="antiComponent max-w-240 flex-grow p-1">
|
<div class="antiComponent max-w-240 flex-grow p-1">
|
||||||
<Expandable icon={ofClass?.icon} label={getEmbeddedLabel(typeTitle?.label ?? '')}>
|
<Expandable icon={ofClass?.icon} label={getEmbeddedLabel(typeTitle?.label ?? '')}>
|
||||||
<svelte:fragment slot="tools">
|
<svelte:fragment slot="tools">
|
||||||
<div class="flex flex-reverse flex-grow">
|
<Button icon={IconDelete} on:click={() => client.remove(mapping)} size={'small'} />
|
||||||
<Button icon={IconDelete} on:click={() => client.remove(mapping)} size={'small'} />
|
|
||||||
</div>
|
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<Expandable label={getEmbeddedLabel('Options')}>
|
<Expandable label={getEmbeddedLabel('Options')}>
|
||||||
<div class="flex-col">
|
<div class="flex-col">
|
||||||
|
@ -323,44 +323,43 @@
|
|||||||
|
|
||||||
<Expandable label={getEmbeddedLabel(mapping.type)}>
|
<Expandable label={getEmbeddedLabel(mapping.type)}>
|
||||||
<svelte:fragment slot="tools">
|
<svelte:fragment slot="tools">
|
||||||
<div class="flex-row-center">
|
<SpaceSelect
|
||||||
<SpaceSelect
|
_class={core.class.Space}
|
||||||
_class={core.class.Space}
|
label={core.string.Space}
|
||||||
label={core.string.Space}
|
bind:value={space}
|
||||||
bind:value={space}
|
on:change={(evt) => {
|
||||||
on:change={(evt) => {
|
space = evt.detail
|
||||||
space = evt.detail
|
}}
|
||||||
|
autoSelect
|
||||||
|
spaceQuery={{ _id: { $in: [contact.space.Contacts] } }}
|
||||||
|
/>
|
||||||
|
<DropdownLabels
|
||||||
|
label={getEmbeddedLabel('Direction')}
|
||||||
|
items={[
|
||||||
|
{ id: 'ASC', label: 'Ascending' },
|
||||||
|
{ id: 'DSC', label: 'Descending' }
|
||||||
|
]}
|
||||||
|
bind:selected={direction}
|
||||||
|
/>
|
||||||
|
<div class="fs-title">
|
||||||
|
<NumberEditor
|
||||||
|
kind={'button'}
|
||||||
|
value={limit}
|
||||||
|
focus={false}
|
||||||
|
placeholder={getEmbeddedLabel('Limit')}
|
||||||
|
onChange={(val) => {
|
||||||
|
if (val) {
|
||||||
|
limit = val
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
autoSelect
|
|
||||||
spaceQuery={{ _id: { $in: [contact.space.Contacts] } }}
|
|
||||||
/>
|
/>
|
||||||
<DropdownLabels
|
</div>
|
||||||
label={getEmbeddedLabel('Direction')}
|
<div class="buttons-divider" />
|
||||||
items={[
|
<div class="flex-row-center">
|
||||||
{ id: 'ASC', label: 'Ascending' },
|
<div class="p-1">
|
||||||
{ id: 'DSC', label: 'Descending' }
|
{state}
|
||||||
]}
|
|
||||||
bind:selected={direction}
|
|
||||||
/>
|
|
||||||
<div class="fs-title flex-row-center">
|
|
||||||
<NumberEditor
|
|
||||||
kind={'button'}
|
|
||||||
value={limit}
|
|
||||||
focus={false}
|
|
||||||
placeholder={getEmbeddedLabel('Limit')}
|
|
||||||
onChange={(val) => {
|
|
||||||
if (val) {
|
|
||||||
limit = val
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="ml-2 flex-row-center">
|
|
||||||
<div class="p-1">
|
|
||||||
{state}
|
|
||||||
</div>
|
|
||||||
<Button size={'large'} label={getEmbeddedLabel('Synchronize')} {loading} on:click={doSync} />
|
|
||||||
</div>
|
</div>
|
||||||
|
<Button size={'large'} label={getEmbeddedLabel('Synchronize')} {loading} on:click={doSync} />
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<div class="flex-row flex-grow bottom-divider p-2">
|
<div class="flex-row flex-grow bottom-divider p-2">
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
import { Ref, SortingOrder, WithLookup } from '@hcengineering/core'
|
import { Ref, SortingOrder, WithLookup } from '@hcengineering/core'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { calcRank, Issue, IssueStatus, Team } from '@hcengineering/tracker'
|
import { calcRank, Issue, IssueStatus, Team } from '@hcengineering/tracker'
|
||||||
import { Button, Spinner, ExpandCollapse, closeTooltip, IconAdd } from '@hcengineering/ui'
|
import { Button, Spinner, ExpandCollapse, closeTooltip, IconAdd, Chevron, Label } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import Collapsed from '../../icons/Collapsed.svelte'
|
|
||||||
import Expanded from '../../icons/Expanded.svelte'
|
|
||||||
import CreateSubIssue from './CreateSubIssue.svelte'
|
import CreateSubIssue from './CreateSubIssue.svelte'
|
||||||
import SubIssueList from './SubIssueList.svelte'
|
import SubIssueList from './SubIssueList.svelte'
|
||||||
|
|
||||||
@ -62,16 +60,18 @@
|
|||||||
{#if hasSubIssues}
|
{#if hasSubIssues}
|
||||||
<Button
|
<Button
|
||||||
width="min-content"
|
width="min-content"
|
||||||
icon={isCollapsed ? Collapsed : Expanded}
|
|
||||||
size="small"
|
size="small"
|
||||||
kind="transparent"
|
kind="transparent"
|
||||||
label={tracker.string.SubIssuesList}
|
|
||||||
labelParams={{ subIssues: issue.subIssues }}
|
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
isCollapsed = !isCollapsed
|
isCollapsed = !isCollapsed
|
||||||
isCreating = false
|
isCreating = false
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<svelte:fragment slot="content">
|
||||||
|
<Chevron size={'small'} expanded={!isCollapsed} outline fill={'var(--caption-color)'} marginRight={'.375rem'} />
|
||||||
|
<Label label={tracker.string.SubIssuesList} params={{ subIssues: issue.subIssues }} />
|
||||||
|
</svelte:fragment>
|
||||||
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
@ -120,9 +120,6 @@
|
|||||||
<IssuePresenter value={object} disableClick />
|
<IssuePresenter value={object} disableClick />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
<div class="header no-border flex-col p-1">
|
|
||||||
<div class="flex-row-center flex-between" />
|
|
||||||
</div>
|
|
||||||
{#if currentTeam && issueStatuses}
|
{#if currentTeam && issueStatuses}
|
||||||
<SubIssuesEstimations
|
<SubIssuesEstimations
|
||||||
issue={object}
|
issue={object}
|
||||||
@ -143,13 +140,17 @@
|
|||||||
icon={IconAdd}
|
icon={IconAdd}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
on:click={(event) => {
|
on:click={(event) => {
|
||||||
showPopup(TimeSpendReportPopup, {
|
showPopup(
|
||||||
issueId: object._id,
|
TimeSpendReportPopup,
|
||||||
issueClass: object._class,
|
{
|
||||||
space: object.space,
|
issueId: object._id,
|
||||||
assignee: object.assignee,
|
issueClass: object._class,
|
||||||
defaultTimeReportDay
|
space: object.space,
|
||||||
})
|
assignee: object.assignee,
|
||||||
|
defaultTimeReportDay
|
||||||
|
},
|
||||||
|
'top'
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
label={tracker.string.TimeSpendReportAdd}
|
label={tracker.string.TimeSpendReportAdd}
|
||||||
/>
|
/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import { Doc, Ref } from '@hcengineering/core'
|
import { Doc, Ref } from '@hcengineering/core'
|
||||||
import { UserBox } from '@hcengineering/presentation'
|
import { UserBox } from '@hcengineering/presentation'
|
||||||
import { Issue, Team } from '@hcengineering/tracker'
|
import { Issue, Team } from '@hcengineering/tracker'
|
||||||
import { getEventPositionElement, ListView, showPopup } from '@hcengineering/ui'
|
import { getEventPositionElement, ListView, showPopup, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||||
import { ContextMenu, FixedColumn, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
import { ContextMenu, FixedColumn, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
||||||
import { getIssueId } from '../../../issues'
|
import { getIssueId } from '../../../issues'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
@ -28,18 +28,19 @@
|
|||||||
export let teams: Map<Ref<Team>, Team>
|
export let teams: Map<Ref<Team>, Team>
|
||||||
|
|
||||||
function showContextMenu (ev: MouseEvent, object: Issue) {
|
function showContextMenu (ev: MouseEvent, object: Issue) {
|
||||||
showPopup(ContextMenu, { object }, getEventPositionElement(ev))
|
showPopup(ContextMenu, { object }, $deviceInfo.isMobile ? 'top' : getEventPositionElement(ev))
|
||||||
}
|
}
|
||||||
|
|
||||||
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {})
|
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {})
|
||||||
|
$: twoRows = $deviceInfo.twoRows
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ListView count={issues.length}>
|
<ListView count={issues.length} addClass={'step-tb-2-accent'}>
|
||||||
<svelte:fragment slot="item" let:item>
|
<svelte:fragment slot="item" let:item>
|
||||||
{@const issue = issues[item]}
|
{@const issue = issues[item]}
|
||||||
{@const currentTeam = teams.get(issue.space)}
|
{@const currentTeam = teams.get(issue.space)}
|
||||||
<div
|
<div
|
||||||
class="flex-between row"
|
class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2"
|
||||||
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, issue)}
|
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, issue)}
|
||||||
on:mouseover={() => {
|
on:mouseover={() => {
|
||||||
listProvider.updateFocus(issue)
|
listProvider.updateFocus(issue)
|
||||||
@ -48,55 +49,32 @@
|
|||||||
listProvider.updateFocus(issue)
|
listProvider.updateFocus(issue)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex-row-center clear-mins gap-2 p-2 flex-grow">
|
<div class="flex-row-center clear-mins gap-2 flex-grow mr-4" class:p-text={twoRows}>
|
||||||
<span class="issuePresenter">
|
<FixedColumn key={'estimation_issue'} justify={'left'} addClass={'fs-bold'}>
|
||||||
<FixedColumn key={'estimation_issue'} justify={'left'}>
|
{#if currentTeam}
|
||||||
{#if currentTeam}
|
{getIssueId(currentTeam, issue)}
|
||||||
{getIssueId(currentTeam, issue)}
|
{/if}
|
||||||
{/if}
|
</FixedColumn>
|
||||||
</FixedColumn>
|
<span class="overflow-label fs-bold caption-color" title={issue.title}>
|
||||||
</span>
|
|
||||||
<span class="text name" title={issue.title}>
|
|
||||||
{issue.title}
|
{issue.title}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FixedColumn key={'estimation_issue_assignee'} justify={'right'}>
|
<div class="flex-row-center clear-mins gap-2 self-end" class:p-text={twoRows}>
|
||||||
<UserBox
|
<FixedColumn key={'estimation_issue_assignee'} justify={'right'}>
|
||||||
width={'100%'}
|
<UserBox
|
||||||
label={tracker.string.Assignee}
|
width={'100%'}
|
||||||
_class={contact.class.Employee}
|
label={tracker.string.Assignee}
|
||||||
value={issue.assignee}
|
_class={contact.class.Employee}
|
||||||
readonly
|
value={issue.assignee}
|
||||||
showNavigate={false}
|
readonly
|
||||||
/>
|
showNavigate={false}
|
||||||
</FixedColumn>
|
/>
|
||||||
<FixedColumn key={'estimation'} justify={'left'}>
|
</FixedColumn>
|
||||||
<EstimationEditor value={issue} kind={'list'} />
|
<FixedColumn key={'estimation'} justify={'left'}>
|
||||||
</FixedColumn>
|
<EstimationEditor value={issue} kind={'list'} />
|
||||||
|
</FixedColumn>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.row {
|
|
||||||
.text {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--caption-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.issuePresenter {
|
|
||||||
flex-shrink: 0;
|
|
||||||
min-width: 0;
|
|
||||||
min-height: 0;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--content-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
import { Ref, SortingOrder, WithLookup } from '@hcengineering/core'
|
import { Ref, SortingOrder, WithLookup } from '@hcengineering/core'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import { Issue, IssueStatus, Team } from '@hcengineering/tracker'
|
import { Issue, IssueStatus, Team } from '@hcengineering/tracker'
|
||||||
import { Scroller, Spinner } from '@hcengineering/ui'
|
import { Spinner } from '@hcengineering/ui'
|
||||||
import Expandable from '@hcengineering/ui/src/components/Expandable.svelte'
|
import Expandable from '@hcengineering/ui/src/components/Expandable.svelte'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import EstimationSubIssueList from './EstimationSubIssueList.svelte'
|
import EstimationSubIssueList from './EstimationSubIssueList.svelte'
|
||||||
@ -38,15 +38,9 @@
|
|||||||
|
|
||||||
{#if subIssues && issueStatuses}
|
{#if subIssues && issueStatuses}
|
||||||
{#if hasSubIssues}
|
{#if hasSubIssues}
|
||||||
<Expandable label={tracker.string.ChildEstimation}>
|
<Expandable label={tracker.string.ChildEstimation} contentColor bordered>
|
||||||
<svelte:fragment slot="title">
|
<svelte:fragment slot="title">: <span class="caption-color">{total}</span></svelte:fragment>
|
||||||
: {total}
|
<EstimationSubIssueList issues={subIssues} {teams} />
|
||||||
</svelte:fragment>
|
|
||||||
<div class="h-50">
|
|
||||||
<Scroller>
|
|
||||||
<EstimationSubIssueList issues={subIssues} {teams} />
|
|
||||||
</Scroller>
|
|
||||||
</div>
|
|
||||||
</Expandable>
|
</Expandable>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -15,11 +15,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { TimeReportDayType } from '@hcengineering/tracker'
|
import { TimeReportDayType } from '@hcengineering/tracker'
|
||||||
import { DropdownIntlItem, DropdownLabelsIntl } from '@hcengineering/ui'
|
import { DropdownIntlItem, DropdownLabelsIntl } from '@hcengineering/ui'
|
||||||
|
import type { ButtonKind } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import TimeReportDayIcon from './TimeReportDayIcon.svelte'
|
import TimeReportDayIcon from './TimeReportDayIcon.svelte'
|
||||||
|
|
||||||
export let label = tracker.string.TimeReportDayTypeLabel
|
export let label = tracker.string.TimeReportDayTypeLabel
|
||||||
export let selected: TimeReportDayType | undefined
|
export let selected: TimeReportDayType | undefined
|
||||||
|
export let kind: ButtonKind = 'link-bordered'
|
||||||
|
|
||||||
const workDaysDropdownItems: DropdownIntlItem[] = [
|
const workDaysDropdownItems: DropdownIntlItem[] = [
|
||||||
{
|
{
|
||||||
@ -34,7 +36,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DropdownLabelsIntl
|
<DropdownLabelsIntl
|
||||||
kind="link-bordered"
|
{kind}
|
||||||
icon={TimeReportDayIcon}
|
icon={TimeReportDayIcon}
|
||||||
shouldUpdateUndefined={false}
|
shouldUpdateUndefined={false}
|
||||||
{label}
|
{label}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import type { IntlString } from '@hcengineering/platform'
|
import type { IntlString } from '@hcengineering/platform'
|
||||||
import presentation, { Card, getClient, UserBox } from '@hcengineering/presentation'
|
import presentation, { Card, getClient, UserBox } from '@hcengineering/presentation'
|
||||||
import { Issue, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker'
|
import { Issue, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import { DatePresenter, EditBox } from '@hcengineering/ui'
|
import { DatePresenter, EditBox, Button } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import { getTimeReportDate, getTimeReportDayType } from '../../../utils'
|
import { getTimeReportDate, getTimeReportDayType } from '../../../utils'
|
||||||
import TimeReportDayDropdown from './TimeReportDayDropdown.svelte'
|
import TimeReportDayDropdown from './TimeReportDayDropdown.svelte'
|
||||||
@ -85,23 +85,31 @@
|
|||||||
>
|
>
|
||||||
<div class="flex-row-center gap-2">
|
<div class="flex-row-center gap-2">
|
||||||
<EditBox focus bind:value={data.value} {placeholder} format={'number'} maxDigitsAfterPoint={3} kind={'editbox'} />
|
<EditBox focus bind:value={data.value} {placeholder} format={'number'} maxDigitsAfterPoint={3} kind={'editbox'} />
|
||||||
|
<Button kind={'link-bordered'} on:click={() => (data.value = 0.125)}><span slot="content">1/8</span></Button>
|
||||||
|
<Button kind={'link-bordered'} on:click={() => (data.value = 0.25)}><span slot="content">1/4</span></Button>
|
||||||
|
<Button kind={'link-bordered'} on:click={() => (data.value = 0.5)}><span slot="content">1/2</span></Button>
|
||||||
|
<Button kind={'link-bordered'} on:click={() => (data.value = 0.75)}><span slot="content">3/4</span></Button>
|
||||||
|
<div class="buttons-divider" />
|
||||||
|
<Button kind={'link-bordered'} on:click={() => (data.value = 1)}><span slot="content">1</span></Button>
|
||||||
|
</div>
|
||||||
|
<EditBox bind:value={data.description} placeholder={tracker.string.TimeSpendReportDescription} kind={'editbox'} />
|
||||||
|
<svelte:fragment slot="pool">
|
||||||
<UserBox
|
<UserBox
|
||||||
_class={contact.class.Employee}
|
_class={contact.class.Employee}
|
||||||
label={contact.string.Employee}
|
label={contact.string.Employee}
|
||||||
kind={'link-bordered'}
|
kind={'no-border'}
|
||||||
bind:value={data.employee}
|
bind:value={data.employee}
|
||||||
showNavigate={false}
|
showNavigate={false}
|
||||||
/>
|
/>
|
||||||
<TimeReportDayDropdown
|
<TimeReportDayDropdown
|
||||||
|
kind={'no-border'}
|
||||||
bind:selected={selectedTimeReportDay}
|
bind:selected={selectedTimeReportDay}
|
||||||
on:selected={({ detail }) => (data.date = getTimeReportDate(detail))}
|
on:selected={({ detail }) => (data.date = getTimeReportDate(detail))}
|
||||||
/>
|
/>
|
||||||
<DatePresenter
|
<DatePresenter
|
||||||
kind={'link'}
|
|
||||||
bind:value={data.date}
|
bind:value={data.date}
|
||||||
editable
|
editable
|
||||||
on:change={({ detail }) => (selectedTimeReportDay = getTimeReportDayType(detail))}
|
on:change={({ detail }) => (selectedTimeReportDay = getTimeReportDayType(detail))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</svelte:fragment>
|
||||||
<EditBox bind:value={data.description} placeholder={tracker.string.TimeSpendReportDescription} kind={'editbox'} />
|
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
import { DocumentQuery, Ref, SortingOrder } from '@hcengineering/core'
|
import { DocumentQuery, Ref, SortingOrder } from '@hcengineering/core'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import { Issue, Team, TimeSpendReport } from '@hcengineering/tracker'
|
import { Issue, Team, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import { Expandable, floorFractionDigits, Label, Scroller, Spinner } from '@hcengineering/ui'
|
import { Expandable, floorFractionDigits, Label, Spinner } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import TimePresenter from './TimePresenter.svelte'
|
import TimePresenter from './TimePresenter.svelte'
|
||||||
import TimeSpendReportsList from './TimeSpendReportsList.svelte'
|
import TimeSpendReportsList from './TimeSpendReportsList.svelte'
|
||||||
@ -42,21 +42,19 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if reports}
|
{#if reports}
|
||||||
<Expandable expanded={true}>
|
<Expandable expanded={true} contentColor bordered>
|
||||||
<svelte:fragment slot="title">
|
<svelte:fragment slot="title">
|
||||||
<span class="overflow-label flex-nowrap">
|
<span class="overflow-label flex-nowrap">
|
||||||
<Label label={tracker.string.ReportedTime} />: <TimePresenter value={reportedTime} {workDayLength} />
|
<Label label={tracker.string.ReportedTime} />:
|
||||||
<Label label={tracker.string.TimeSpendReports} />: <TimePresenter value={total} {workDayLength} />
|
<span class="caption-color"><TimePresenter value={reportedTime} {workDayLength} /></span>.
|
||||||
|
<Label label={tracker.string.TimeSpendReports} />:
|
||||||
|
<span class="caption-color"><TimePresenter value={total} {workDayLength} /></span>
|
||||||
</span>
|
</span>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<div class="h-50">
|
<TimeSpendReportsList {reports} {teams} />
|
||||||
<Scroller>
|
|
||||||
<TimeSpendReportsList {reports} {teams} />
|
|
||||||
</Scroller>
|
|
||||||
</div>
|
|
||||||
</Expandable>
|
</Expandable>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex-center pt-3">
|
<div class="flex-center">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import UserBox from '@hcengineering/presentation/src/components/UserBox.svelte'
|
import UserBox from '@hcengineering/presentation/src/components/UserBox.svelte'
|
||||||
import { Team, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker'
|
import { Team, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import { eventToHTMLElement, getEventPositionElement, ListView, showPopup } from '@hcengineering/ui'
|
import { eventToHTMLElement, getEventPositionElement, ListView, showPopup } from '@hcengineering/ui'
|
||||||
|
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||||
import DatePresenter from '@hcengineering/ui/src/components/calendar/DatePresenter.svelte'
|
import DatePresenter from '@hcengineering/ui/src/components/calendar/DatePresenter.svelte'
|
||||||
import { ContextMenu, FixedColumn, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
import { ContextMenu, FixedColumn, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
||||||
import { getIssueId } from '../../../issues'
|
import { getIssueId } from '../../../issues'
|
||||||
@ -51,18 +52,19 @@
|
|||||||
assignee: value.employee,
|
assignee: value.employee,
|
||||||
defaultTimeReportDay
|
defaultTimeReportDay
|
||||||
},
|
},
|
||||||
eventToHTMLElement(event)
|
$deviceInfo.isMobile ? 'top' : eventToHTMLElement(event)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
$: twoRows = $deviceInfo.twoRows
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<ListView count={reports.length}>
|
<ListView count={reports.length} addClass={'step-tb-2-accent'}>
|
||||||
<svelte:fragment slot="item" let:item>
|
<svelte:fragment slot="item" let:item>
|
||||||
{@const report = reports[item]}
|
{@const report = reports[item]}
|
||||||
{@const currentTeam = teams.get(toTeamId(report.space))}
|
{@const currentTeam = teams.get(toTeamId(report.space))}
|
||||||
<div
|
<div
|
||||||
class="flex-between row"
|
class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2"
|
||||||
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)}
|
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)}
|
||||||
on:mouseover={() => {
|
on:mouseover={() => {
|
||||||
listProvider.updateFocus(report)
|
listProvider.updateFocus(report)
|
||||||
@ -72,62 +74,36 @@
|
|||||||
}}
|
}}
|
||||||
on:click={(evt) => editSpendReport(evt, report, currentTeam?.defaultTimeReportDay)}
|
on:click={(evt) => editSpendReport(evt, report, currentTeam?.defaultTimeReportDay)}
|
||||||
>
|
>
|
||||||
<div class="flex-row-center clear-mins gap-2 p-2 flex-grow">
|
<div class="flex-row-center clear-mins gap-2 flex-grow mr-4" class:p-text={twoRows}>
|
||||||
<span class="issuePresenter">
|
<FixedColumn key={'tmiespend_issue'} justify={'left'} addClass={'fs-bold'}>
|
||||||
<FixedColumn key={'tmiespend_issue'} justify={'left'}>
|
{#if currentTeam && report.$lookup?.attachedTo}
|
||||||
{#if currentTeam && report.$lookup?.attachedTo}
|
{getIssueId(currentTeam, report.$lookup?.attachedTo)}
|
||||||
{getIssueId(currentTeam, report.$lookup?.attachedTo)}
|
{/if}
|
||||||
{/if}
|
</FixedColumn>
|
||||||
</FixedColumn>
|
|
||||||
</span>
|
|
||||||
{#if report.$lookup?.attachedTo?.title}
|
{#if report.$lookup?.attachedTo?.title}
|
||||||
<span class="text name" title={report.$lookup?.attachedTo?.title}>
|
<span class="overflow-label fs-bold caption-color" title={report.$lookup?.attachedTo?.title}>
|
||||||
{report.$lookup?.attachedTo?.title}
|
{report.$lookup?.attachedTo?.title}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<FixedColumn key={'timespend_assignee'} justify={'left'}>
|
<div class="flex-row-center clear-mins gap-2 self-end" class:p-text={twoRows}>
|
||||||
<UserBox
|
<FixedColumn key={'timespend_assignee'} justify={'left'}>
|
||||||
width={'100%'}
|
<UserBox
|
||||||
label={tracker.string.Assignee}
|
width={'100%'}
|
||||||
_class={contact.class.Employee}
|
label={tracker.string.Assignee}
|
||||||
value={report.employee}
|
_class={contact.class.Employee}
|
||||||
readonly
|
value={report.employee}
|
||||||
showNavigate={false}
|
readonly
|
||||||
/>
|
showNavigate={false}
|
||||||
</FixedColumn>
|
/>
|
||||||
|
</FixedColumn>
|
||||||
<FixedColumn key={'timespend_reported'} justify={'center'}>
|
<FixedColumn key={'timespend_reported'} justify={'center'}>
|
||||||
<div class="p-1">
|
|
||||||
<TimePresenter value={report.value} workDayLength={currentTeam?.workDayLength} />
|
<TimePresenter value={report.value} workDayLength={currentTeam?.workDayLength} />
|
||||||
</div>
|
</FixedColumn>
|
||||||
</FixedColumn>
|
<FixedColumn key={'timespend_date'} justify={'left'}>
|
||||||
<FixedColumn key={'timespend_date'} justify={'left'}>
|
<DatePresenter value={report.date} />
|
||||||
<DatePresenter value={report.date} />
|
</FixedColumn>
|
||||||
</FixedColumn>
|
</div>
|
||||||
</div>
|
</div></svelte:fragment
|
||||||
</svelte:fragment>
|
>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.row {
|
|
||||||
.text {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--caption-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.issuePresenter {
|
|
||||||
flex-shrink: 0;
|
|
||||||
min-width: 0;
|
|
||||||
min-height: 0;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--content-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
export let key: string
|
export let key: string
|
||||||
export let justify: string = ''
|
export let justify: string = ''
|
||||||
|
export let addClass: string | undefined = undefined
|
||||||
let prevKey = key
|
let prevKey = key
|
||||||
let element: HTMLDivElement | undefined
|
let element: HTMLDivElement | undefined
|
||||||
|
|
||||||
@ -48,7 +49,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
bind:this={element}
|
bind:this={element}
|
||||||
class="flex-no-shrink"
|
class="flex-no-shrink{addClass ? ` ${addClass}` : ''}"
|
||||||
style="{justify !== '' ? `text-align: ${justify}; ` : ''} min-width: {$fixedWidthStore[key] ?? 0}px;"
|
style="{justify !== '' ? `text-align: ${justify}; ` : ''} min-width: {$fixedWidthStore[key] ?? 0}px;"
|
||||||
use:resizeObserver={resize}
|
use:resizeObserver={resize}
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user