Update IssuesList layout (#2317)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2022-10-24 13:26:56 +03:00 committed by GitHub
parent bcceb8b5b4
commit 5568eeba3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 321 additions and 137 deletions

View File

@ -472,15 +472,37 @@ export function createModel (builder: Builder): void {
{ {
key: '', key: '',
presenter: tracker.component.ProjectEditor, presenter: tracker.component.ProjectEditor,
props: { kind: 'list', size: 'small', shape: 'round', shouldShowPlaceholder: false } props: {
kind: 'list',
size: 'small',
shape: 'round',
shouldShowPlaceholder: false,
excludeByKey: 'project',
optional: true
}
}, },
{ {
key: '', key: '',
presenter: tracker.component.SprintEditor, presenter: tracker.component.SprintEditor,
props: { kind: 'list', size: 'small', shape: 'round', shouldShowPlaceholder: false } props: {
kind: 'list',
size: 'small',
shape: 'round',
shouldShowPlaceholder: false,
excludeByKey: 'sprint',
optional: true
}
},
{
key: '',
presenter: tracker.component.EstimationEditor,
props: { kind: 'list', size: 'small', optional: true }
},
{
key: 'modifiedOn',
presenter: tracker.component.ModificationDatePresenter,
props: { fixed: 'right', optional: true }
}, },
{ key: '', presenter: tracker.component.EstimationEditor, props: { kind: 'list', size: 'small' } },
{ key: 'modifiedOn', presenter: tracker.component.ModificationDatePresenter, props: { fixed: 'right' } },
{ {
key: '$lookup.assignee', key: '$lookup.assignee',
presenter: tracker.component.AssigneePresenter, presenter: tracker.component.AssigneePresenter,

View File

@ -84,6 +84,7 @@
--divider-color: #303236; --divider-color: #303236;
--menu-bg-select: #2d2f36; --menu-bg-select: #2d2f36;
--menu-icon-hover: #f3f3f8; --menu-icon-hover: #f3f3f8;
--header-bg-color: linear-gradient(0deg, var(--accent-bg-color), #2d2e31);
--popup-bg-color: linear-gradient(136.61deg, var(--accent-bg-color) 13.72%, #2d2e31 74.3%); --popup-bg-color: linear-gradient(136.61deg, var(--accent-bg-color) 13.72%, #2d2e31 74.3%);
--popup-bg-hover: #37373c; --popup-bg-hover: #37373c;
--popup-divider: #313236; --popup-divider: #313236;
@ -236,8 +237,9 @@
--divider-color: #e0e0e0; --divider-color: #e0e0e0;
--menu-bg-select: #f0f3f9; --menu-bg-select: #f0f3f9;
--menu-icon-hover: #282a30; --menu-icon-hover: #282a30;
--popup-bg-color: linear-gradient(136.61deg, rgb(255, 255, 255) 13.72%, rgb(255, 255, 255) 74.3%); --header-bg-color: linear-gradient(0deg, #eee, #f6f6f6);
--popup-bg-hover: #f8f9fb; --popup-bg-color: linear-gradient(136.61deg, #fff 13.72%, #fefefe 74.3%);
--popup-bg-hover: #f0f3f9;
--popup-divider: #eff1f4; --popup-divider: #eff1f4;
--popup-shadow: rgb(0 0 0 / 20%) 0px 4px 24px; // Dark --popup-shadow: rgb(0 0 0 / 20%) 0px 4px 24px; // Dark
--popup-panel-shadow: rgb(0 0 0 / 10%) 0px 4px 18px; --popup-panel-shadow: rgb(0 0 0 / 10%) 0px 4px 18px;

View File

@ -358,6 +358,7 @@ input.search {
.step-lr75 + .step-lr75 { margin-left: .75rem; } .step-lr75 + .step-lr75 { margin-left: .75rem; }
.step-tb75 + .step-tb75 { margin-top: .75rem; } .step-tb75 + .step-tb75 { margin-top: .75rem; }
.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; }
.ml-2 { margin-left: .5rem; } .ml-2 { margin-left: .5rem; }
@ -502,7 +503,9 @@ input.search {
.w-85 { width: 21.25rem; } .w-85 { width: 21.25rem; }
.w-165 { width: 41.25rem; } .w-165 { width: 41.25rem; }
.min-w-0 { min-width: 0; } .min-w-0 { min-width: 0; }
.min-w-2 { min-width: .5rem; }
.min-w-4 { min-width: 1rem; } .min-w-4 { min-width: 1rem; }
.min-w-8 { min-width: 2rem; }
.min-w-9 { min-width: 2.25rem; } .min-w-9 { min-width: 2.25rem; }
.min-w-80 { min-width: 20rem; } .min-w-80 { min-width: 20rem; }
.min-w-min { min-width: min-content; } .min-w-min { min-width: min-content; }

View File

@ -127,7 +127,7 @@
<Spinner /> <Spinner />
{/if} {/if}
{#if label} {#if label}
<span class="overflow-label disabled" class:ml-2={loading}> <span class="overflow-label disabled pointer-events-none" class:ml-2={loading}>
<Label {label} params={labelParams} /> <Label {label} params={labelParams} />
</span> </span>
{:else if $$slots.content} {:else if $$slots.content}

View File

@ -35,7 +35,7 @@
let asideShown: boolean = false let asideShown: boolean = false
let fullSize: boolean = false let fullSize: boolean = false
let twoRows: boolean = false let twoRows: boolean = false
$: twoRows = $deviceInfo.docWidth <= 480 $: twoRows = $deviceInfo.minWidth
const checkPanel = (): void => { const checkPanel = (): void => {
if (panelWidth <= 900 && !asideFloat) asideFloat = true if (panelWidth <= 900 && !asideFloat) asideFloat = true

View File

@ -12,7 +12,9 @@
<div class="flex-center container {status.severity}" class:overflow-label={overflow}> <div class="flex-center container {status.severity}" class:overflow-label={overflow}>
{#if status.severity !== Severity.OK} {#if status.severity !== Severity.OK}
<Info size={'small'} /> <Info size={'small'} />
<div class="text-sm ml-2" class:overflow-label={overflow}><Label label={status.code} params={status.params} /></div> <span class="text-sm ml-2" class:overflow-label={overflow}
><Label label={status.code} params={status.params} /></span
>
{/if} {/if}
</div> </div>

View File

@ -70,6 +70,8 @@
$: $deviceInfo.docHeight = docHeight $: $deviceInfo.docHeight = docHeight
$: $deviceInfo.isPortrait = isPortrait $: $deviceInfo.isPortrait = isPortrait
$: $deviceInfo.isMobile = isMobile $: $deviceInfo.isMobile = isMobile
$: $deviceInfo.minWidth = docWidth <= 480
$: $deviceInfo.twoRows = docWidth <= 680
$: document.documentElement.style.setProperty('--app-height', `${docHeight}px`) $: document.documentElement.style.setProperty('--app-height', `${docHeight}px`)

View File

@ -180,7 +180,9 @@ export const deviceOptionsStore = writable<DeviceOptions>({
docWidth: 0, docWidth: 0,
docHeight: 0, docHeight: 0,
isPortrait: false, isPortrait: false,
isMobile: false isMobile: false,
minWidth: false,
twoRows: false
}) })
export default uis export default uis

View File

@ -231,5 +231,7 @@ export interface DeviceOptions {
docHeight: number docHeight: number
isPortrait: boolean isPortrait: boolean
isMobile: boolean isMobile: boolean
minWidth: boolean
twoRows: boolean
theme?: any theme?: any
} }

View File

@ -100,8 +100,7 @@
} }
}) })
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -63,8 +63,7 @@
showPopup(CreateContact, { space: contact.space.Contacts, targetElement: ev.target }, ev.target as HTMLElement) showPopup(CreateContact, { space: contact.space.Contacts, targetElement: ev.target }, ev.target as HTMLElement)
} }
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<ActionContext <ActionContext

View File

@ -65,8 +65,7 @@
allEmployees = res allEmployees = res
}) })
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings divide" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings divide" class:full={!twoRows} class:mini={twoRows}>

View File

@ -33,8 +33,7 @@
showPopup(CreateCategory, { space: inventory.space.Category }, eventToHTMLElement(ev)) showPopup(CreateCategory, { space: inventory.space.Category }, eventToHTMLElement(ev))
} }
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -131,8 +131,7 @@
return result return result
} }
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -86,8 +86,7 @@
(tagElements?.get(b._id as Ref<TagElement>)?.count ?? 0) - (tagElements?.get(b._id as Ref<TagElement>)?.count ?? 0) -
(tagElements?.get(a._id as Ref<TagElement>)?.count ?? 0) ?? 0 (tagElements?.get(a._id as Ref<TagElement>)?.count ?? 0) ?? 0
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -116,7 +116,11 @@
{loading} {loading}
on:click={handleProjectEditorOpened} on:click={handleProjectEditorOpened}
><svelte:fragment slot="content"> ><svelte:fragment slot="content">
<span class="{enlargedText ? 'ml-1 text-base fs-bold' : 'text-md'} overflow-label content-accent-color"> <span
class="{enlargedText
? 'ml-1 text-base fs-bold'
: 'text-md'} overflow-label content-accent-color pointer-events-none"
>
<Label label={getEmbeddedLabel(projectText)} /> <Label label={getEmbeddedLabel(projectText)} />
</span> </span>
</svelte:fragment></Button </svelte:fragment></Button

View File

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
const fill: string = 'var(--theme-caption-color)' const fill: string = 'var(--caption-color)'
</script> </script>
<svg {fill} viewBox="0 0 6 16" xmlns="http://www.w3.org/2000/svg"> <svg {fill} viewBox="0 0 6 16" xmlns="http://www.w3.org/2000/svg">

View File

@ -20,8 +20,7 @@
} }
}) })
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -30,7 +30,8 @@
IconMoreH, IconMoreH,
showPopup, showPopup,
Spinner, Spinner,
tooltip tooltip,
deviceOptionsStore as deviceInfo
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { AttributeModel, BuildModelKey } from '@hcengineering/view' import { AttributeModel, BuildModelKey } from '@hcengineering/view'
import { buildModel, FixedColumn, getObjectPresenter, LoadingProps, Menu } from '@hcengineering/view-resources' import { buildModel, FixedColumn, getObjectPresenter, LoadingProps, Menu } from '@hcengineering/view-resources'
@ -38,6 +39,7 @@
import tracker from '../../plugin' import tracker from '../../plugin'
import { IssuesGroupByKeys, issuesGroupEditorMap, IssuesOrderByKeys, issuesSortOrderMap } from '../../utils' import { IssuesGroupByKeys, issuesGroupEditorMap, IssuesOrderByKeys, issuesSortOrderMap } from '../../utils'
import CreateIssue from '../CreateIssue.svelte' import CreateIssue from '../CreateIssue.svelte'
import Circles from '../icons/Circles.svelte'
export let _class: Ref<Class<Doc>> export let _class: Ref<Class<Doc>>
export let currentSpace: Ref<Team> | undefined = undefined export let currentSpace: Ref<Team> | undefined = undefined
@ -237,7 +239,7 @@
value: groupByKey ? { [groupByKey]: category } : {}, value: groupByKey ? { [groupByKey]: category } : {},
statuses: groupByKey === 'status' ? statuses : undefined, statuses: groupByKey === 'status' ? statuses : undefined,
issues: groupedIssues[category], issues: groupedIssues[category],
size: 'medium', width: 'min-content',
kind: 'list-header', kind: 'list-header',
enlargedText: true, enlargedText: true,
currentSpace currentSpace
@ -245,7 +247,11 @@
/> />
{/if} {/if}
{#if limited.length < items.length} {#if limited.length < items.length}
<span class="text-base content-dark-color ml-4"> {limited.length} / {items.length}</span> <div class="counter">
{limited.length}
<div class="text-xs mx-1">/</div>
{items.length}
</div>
<ActionIcon <ActionIcon
size={'small'} size={'small'}
icon={IconMoreH} icon={IconMoreH}
@ -255,12 +261,15 @@
}} }}
/> />
{:else} {:else}
<span class="text-base content-dark-color ml-4">{items.length}</span> <span class="counter">{items.length}</span>
{/if} {/if}
</div> </div>
<div class="clear-mins" use:tooltip={{ label: tracker.string.AddIssueTooltip }}> <Button
<Button icon={IconAdd} kind={'transparent'} on:click={(event) => handleNewIssueAdded(event, category)} /> icon={IconAdd}
</div> kind={'transparent'}
showTooltip={{ label: tracker.string.AddIssueTooltip }}
on:click={(event) => handleNewIssueAdded(event, category)}
/>
</div> </div>
{/if} {/if}
<ExpandCollapse isExpanded={!isCollapsedMap[toCat(category)]} duration={400}> <ExpandCollapse isExpanded={!isCollapsedMap[toCat(category)]} duration={400}>
@ -340,6 +349,7 @@
{...attributeModel.props} {...attributeModel.props}
/> />
{:else if attributeModel.props?.fixed} {:else if attributeModel.props?.fixed}
{#if !(attributeModel.props?.optional && $deviceInfo.minWidth)}
<FixedColumn <FixedColumn
width={propsWidth[attributeModel.key]} width={propsWidth[attributeModel.key]}
key={attributeModel.key} key={attributeModel.key}
@ -355,8 +365,9 @@
{currentTeam} {currentTeam}
/> />
</FixedColumn> </FixedColumn>
{:else} {/if}
<div class="gridElement"> {:else if attributeModel.props?.excludeByKey !== groupByKey}
{#if !(attributeModel.props?.optional && $deviceInfo.minWidth)}
<svelte:component <svelte:component
this={attributeModel.presenter} this={attributeModel.presenter}
value={getObjectValue(attributeModel.key, docObject) ?? ''} value={getObjectValue(attributeModel.key, docObject) ?? ''}
@ -366,9 +377,36 @@
{statuses} {statuses}
{currentTeam} {currentTeam}
/> />
</div> {/if}
{/if} {/if}
{/each} {/each}
{#if $deviceInfo.minWidth}
<div class="panel-trigger" tabindex="-1">
<Circles />
<div class="space" />
<Circles />
</div>
<div class="hidden-panel gap-2" tabindex="-1">
<div class="header">
<Circles />
<div class="space" />
<Circles />
</div>
{#each itemModels as attributeModel}
{#if attributeModel.props?.optional && attributeModel.props?.excludeByKey !== groupByKey}
<svelte:component
this={attributeModel.presenter}
value={getObjectValue(attributeModel.key, docObject) ?? ''}
issueId={docObject._id}
groupBy={groupByKey}
{...attributeModel.props}
{statuses}
{currentTeam}
/>
{/if}
{/each}
</div>
{/if}
</div> </div>
{/each} {/each}
{:else if loadingProps !== undefined} {:else if loadingProps !== undefined}
@ -403,11 +441,11 @@
.categoryHeader { .categoryHeader {
position: sticky; position: sticky;
top: 0; top: 0;
padding: 0 1.5rem 0 2.25rem; padding: 0 0.75rem 0 2.25rem;
height: 3rem; height: 3rem;
min-height: 3rem; min-height: 3rem;
min-width: 0; min-width: 0;
background-color: var(--accent-bg-color); background: var(--header-bg-color);
z-index: 5; z-index: 5;
} }
@ -415,10 +453,29 @@
border-bottom: 1px solid var(--accent-bg-color); border-bottom: 1px solid var(--accent-bg-color);
} }
.listGrid { .counter {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 1.5rem 0 0.875rem; flex-wrap: nowrap;
flex-shrink: 0;
margin-left: 1rem;
padding: 0.25rem 0.5rem;
min-width: 1.325rem;
text-align: center;
font-weight: 500;
font-size: 1rem;
line-height: 1rem;
color: var(--accent-color);
background-color: var(--body-color);
border: 1px solid var(--divider-color);
border-radius: 1rem;
}
.listGrid {
position: relative;
display: flex;
align-items: center;
padding: 0 0.75rem 0 0.875rem;
width: 100%; width: 100%;
height: 2.75rem; height: 2.75rem;
min-height: 2.75rem; min-height: 2.75rem;
@ -437,6 +494,68 @@
&.mListGridSelected { &.mListGridSelected {
background-color: var(--highlight-hover); background-color: var(--highlight-hover);
} }
.hidden-panel,
.panel-trigger {
position: absolute;
display: flex;
align-items: center;
top: 0;
bottom: 0;
height: 100%;
}
.hidden-panel {
overflow: hidden;
right: 0;
width: 80%;
background-color: var(--accent-bg-color);
opacity: 0;
pointer-events: none;
z-index: 2;
transition-property: opacity, width;
transition-duration: 0.15s;
transition-timing-function: var(--timing-main);
.header {
display: flex;
flex-direction: column;
justify-content: center;
margin: 0 0.25rem;
width: 0.375rem;
min-width: 0.375rem;
height: 100%;
opacity: 0.25;
}
}
.panel-trigger {
flex-direction: column;
justify-content: center;
padding: 0 0.125rem;
right: 2.5rem;
width: 0.75rem;
border: 1px solid transparent;
border-radius: 0.25rem;
opacity: 0.1;
z-index: 1;
transition: opacity 0.15s var(--timing-main);
&:focus {
border-color: var(--primary-edit-border-color);
opacity: 0.25;
}
& > * {
pointer-events: none;
}
}
.hidden-panel:focus-within,
.panel-trigger:focus + .hidden-panel {
width: 100%;
opacity: 1;
pointer-events: all;
}
.space {
min-height: 0.1075rem;
}
} }
.priorityPresenter, .priorityPresenter,

View File

@ -27,20 +27,18 @@
</script> </script>
{#if value} {#if value}
<span class="root" class:with-margin={shouldUseMargin} title={value.title}> <span class="titlePresenter-container" class:with-margin={shouldUseMargin} title={value.title}>
<span class="name cursor-pointer" on:click={handleIssueEditorOpened}>{value.title}</span> <span class="name overflow-label cursor-pointer" on:click={handleIssueEditorOpened}>{value.title}</span>
<ParentNamesPresenter {value} /> <ParentNamesPresenter {value} />
</span> </span>
{/if} {/if}
<style lang="scss"> <style lang="scss">
.root { .titlePresenter-container {
display: flex; display: flex;
flex-grow: 0; flex-grow: 0;
min-width: 7rem; min-width: 1.5rem;
white-space: nowrap; // flex-shrink: 10;
overflow: hidden;
flex-shrink: 10;
.name { .name {
&:hover { &:hover {

View File

@ -99,7 +99,7 @@
</script> </script>
{#if hasSubIssues} {#if hasSubIssues}
<div class="flex-center clear-mins" bind:this={btn}> <div class="flex-center flex-no-shrink" bind:this={btn}>
<Button <Button
{width} {width}
{kind} {kind}

View File

@ -49,7 +49,8 @@
{#if (value.project && value.project !== $activeProject && groupBy !== 'project') || shouldShowPlaceholder} {#if (value.project && value.project !== $activeProject && groupBy !== 'project') || shouldShowPlaceholder}
<div <div
class="clear-mins" class="min-w-8"
class:minus-margin={kind === 'list-header'}
use:tooltip={{ label: value.project ? tracker.string.MoveToProject : tracker.string.AddToProject }} use:tooltip={{ label: value.project ? tracker.string.MoveToProject : tracker.string.AddToProject }}
> >
<ProjectSelector <ProjectSelector
@ -68,3 +69,9 @@
/> />
</div> </div>
{/if} {/if}
<style lang="scss">
.minus-margin {
margin-left: -0.5rem;
}
</style>

View File

@ -17,7 +17,8 @@
import { IntlString } from '@hcengineering/platform' import { IntlString } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation' import { createQuery, getClient } from '@hcengineering/presentation'
import { Issue, IssueStatus, IssueTemplate, Sprint } from '@hcengineering/tracker' import { Issue, IssueStatus, IssueTemplate, Sprint } from '@hcengineering/tracker'
import { ButtonKind, ButtonShape, ButtonSize, Label, tooltip } from '@hcengineering/ui' import type { ButtonKind, ButtonSize, ButtonShape } from '@hcengineering/ui'
import { Label, 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 { activeSprint } from '../../issues' import { activeSprint } from '../../issues'
import tracker from '../../plugin' import tracker from '../../plugin'
@ -30,15 +31,15 @@
export let shouldShowLabel: boolean = true export let shouldShowLabel: boolean = true
export let popupPlaceholder: IntlString = tracker.string.MoveToSprint export let popupPlaceholder: IntlString = tracker.string.MoveToSprint
export let shouldShowPlaceholder = true export let shouldShowPlaceholder = true
export let kind: ButtonKind = 'link'
export let size: ButtonSize = 'large' export let size: ButtonSize = 'large'
export let kind: ButtonKind = 'link'
export let shape: ButtonShape = undefined export let shape: ButtonShape = undefined
export let justify: 'left' | 'center' = 'left' export let justify: 'left' | 'center' = 'left'
export let width: string | undefined = '100%' export let width: string | undefined = '100%'
export let onlyIcon: boolean = false export let onlyIcon: boolean = false
export let issues: Issue[] | undefined = undefined export let issues: Issue[] | undefined = undefined
export let groupBy: string | undefined = undefined export let groupBy: string | undefined = undefined
export let enlargedText = false export let enlargedText: boolean = false
const client = getClient() const client = getClient()
@ -119,13 +120,17 @@
sprint = res.shift() sprint = res.shift()
}) })
} }
$: twoRows = $deviceInfo.twoRows
</script> </script>
{#if (value.sprint && value.sprint !== $activeSprint && groupBy !== 'sprint') || shouldShowPlaceholder}
<div <div
class="clear-mins" class="flex flex-wrap min-w-8"
use:tooltip={{ label: value.sprint ? tracker.string.MoveToSprint : tracker.string.AddToSprint }} class:minus-margin={kind === 'list-header'}
style:flex-direction={twoRows ? 'column' : 'row'}
> >
{#if (value.sprint && value.sprint !== $activeSprint && groupBy !== 'sprint') || shouldShowPlaceholder}
<div class="flex-row-center" class:minus-margin-vSpace={kind === 'list-header'} style:width>
<SprintSelector <SprintSelector
{kind} {kind}
{size} {size}
@ -137,19 +142,21 @@
{popupPlaceholder} {popupPlaceholder}
{onlyIcon} {onlyIcon}
{enlargedText} {enlargedText}
showTooltip={{ label: value.sprint ? tracker.string.MoveToSprint : tracker.string.AddToSprint }}
value={value.sprint} value={value.sprint}
onChange={handleSprintIdChanged} onChange={handleSprintIdChanged}
/> />
</div> </div>
{/if} {/if}
{#if sprint || issues}
<div class="flex-row-center" class:minus-margin-space={kind === 'list-header'} class:text-sm={twoRows}>
{#if sprint} {#if sprint}
{@const now = Date.now()} {@const now = Date.now()}
<div class="flex-row-center">
<DatePresenter value={sprint.startDate} kind={'transparent'} /> <DatePresenter value={sprint.startDate} kind={'transparent'} />
<span class="p-1"> / </span><DatePresenter value={sprint.targetDate} kind={'transparent'} /> <span class="p-1"> / </span>
</div> <DatePresenter value={sprint.targetDate} kind={'transparent'} />
<div class="flex-row-center ml-2"> <div class="w-2 min-w-2" />
<!-- Active sprint in time --> <!-- Active sprint in time -->
<Label <Label
label={tracker.string.SprintPassed} label={tracker.string.SprintPassed}
@ -163,14 +170,17 @@
to: getDayOfSprint(sprint.startDate, sprint.targetDate) to: getDayOfSprint(sprint.startDate, sprint.targetDate)
}} }}
/> />
</div>
{/if} {/if}
{#if issues} {#if issues}
<!-- <Label label={tracker.string.SprintDay} value={}/> --> <!-- <Label label={tracker.string.SprintDay} value={}/> -->
<div class="ml-4 flex-row-center" class:showWarning={totalEstimation > (sprint?.capacity ?? 0)}> <div
<div class="mr-2"> class="flex-row-center flex-no-shrink h-6"
class:ml-2={sprint}
class:ml-0-5={!sprint}
class:showWarning={totalEstimation > (sprint?.capacity ?? 0)}
>
<EstimationProgressCircle value={totalReported} max={totalEstimation} /> <EstimationProgressCircle value={totalReported} max={totalEstimation} />
</div> <div class="w-2 min-w-2" />
{#if totalReported > 0} {#if totalReported > 0}
<Label label={tracker.string.TimeSpendValue} params={{ value: totalReported }} /> <Label label={tracker.string.TimeSpendValue} params={{ value: totalReported }} />
/ /
@ -181,9 +191,21 @@
{/if} {/if}
</div> </div>
{/if} {/if}
</div>
{/if}
</div>
<style lang="scss"> <style lang="scss">
.showWarning { .showWarning {
color: var(--warning-color) !important; color: var(--warning-color) !important;
} }
.minus-margin {
margin-left: -0.5rem;
&-vSpace {
margin: -0.25rem 0;
}
&-space {
margin: -0.25rem 0 -0.25rem 0.5rem;
}
}
</style> </style>

View File

@ -17,7 +17,7 @@
import { getEmbeddedLabel, IntlString, translate } from '@hcengineering/platform' import { getEmbeddedLabel, IntlString, translate } from '@hcengineering/platform'
import { createQuery } from '@hcengineering/presentation' import { createQuery } from '@hcengineering/presentation'
import { Project, Sprint } from '@hcengineering/tracker' import { Project, Sprint } from '@hcengineering/tracker'
import type { ButtonKind, ButtonSize } from '@hcengineering/ui' import type { ButtonKind, ButtonSize, LabelAndProps } from '@hcengineering/ui'
import { Button, ButtonShape, eventToHTMLElement, SelectPopup, showPopup, Label } from '@hcengineering/ui' import { Button, ButtonShape, eventToHTMLElement, SelectPopup, showPopup, Label } from '@hcengineering/ui'
import tracker from '../../plugin' import tracker from '../../plugin'
import { sprintStatusAssets } from '../../types' import { sprintStatusAssets } from '../../types'
@ -36,6 +36,7 @@
export let enlargedText = false export let enlargedText = false
export let useProject: Ref<Project> | undefined = undefined export let useProject: Ref<Project> | undefined = undefined
export let showTooltip: LabelAndProps | undefined = undefined
let selectedSprint: Sprint | undefined let selectedSprint: Sprint | undefined
let defaultSprintLabel = '' let defaultSprintLabel = ''
@ -101,6 +102,7 @@
{shape} {shape}
{width} {width}
{justify} {justify}
{showTooltip}
icon={sprintIcon} icon={sprintIcon}
disabled={!isEditable} disabled={!isEditable}
on:click={handleSprintEditorOpened} on:click={handleSprintEditorOpened}
@ -112,13 +114,17 @@
{shape} {shape}
{width} {width}
{justify} {justify}
{showTooltip}
icon={sprintIcon} icon={sprintIcon}
disabled={!isEditable} disabled={!isEditable}
on:click={handleSprintEditorOpened} on:click={handleSprintEditorOpened}
><svelte:fragment slot="content"> >
<span class="{enlargedText ? 'ml-1 text-base fs-bold' : 'text-md'} overflow-label content-accent-color"> <svelte:fragment slot="content">
<span
class="{enlargedText ? 'text-base' : 'text-md'} fs-bold overflow-label content-accent-color pointer-events-none"
>
<Label label={getEmbeddedLabel(sprintText)} /> <Label label={getEmbeddedLabel(sprintText)} />
</span> </span>
</svelte:fragment></Button </svelte:fragment>
> </Button>
{/if} {/if}

View File

@ -359,6 +359,8 @@ export interface AttributeModel {
// Extra properties for component // Extra properties for component
props?: Record<string, any> props?: Record<string, any>
sortingKey: string | string[] sortingKey: string | string[]
optional?: boolean
excludeByKey?: string
// Extra icon if applicable // Extra icon if applicable
icon?: Asset icon?: Asset

View File

@ -82,8 +82,7 @@
} }
}) })
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 768
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -75,8 +75,7 @@
return search === '' ? baseQuery : { ...baseQuery, $search: search } return search === '' ? baseQuery : { ...baseQuery, $search: search }
} }
let twoRows: boolean $: twoRows = $deviceInfo.twoRows
$: twoRows = $deviceInfo.docWidth <= 680
</script> </script>
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}> <div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>

View File

@ -38,7 +38,8 @@
showPopup, showPopup,
TooltipInstance, TooltipInstance,
PopupPosAlignment, PopupPosAlignment,
checkMobile checkMobile,
deviceOptionsStore as deviceInfo
} from '@hcengineering/ui' } from '@hcengineering/ui'
import view from '@hcengineering/view' import view from '@hcengineering/view'
import { ActionContext, ActionHandler } from '@hcengineering/view-resources' import { ActionContext, ActionHandler } from '@hcengineering/view-resources'
@ -53,7 +54,6 @@
import NavHeader from './NavHeader.svelte' import NavHeader from './NavHeader.svelte'
import Navigator from './Navigator.svelte' import Navigator from './Navigator.svelte'
import SpaceView from './SpaceView.svelte' import SpaceView from './SpaceView.svelte'
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
export let client: Client export let client: Client
let contentPanel: HTMLElement let contentPanel: HTMLElement