Tracker: fix status editor (#2097)

Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@xored.com>
This commit is contained in:
Sergei Ogorelkov 2022-06-17 15:28:31 +07:00 committed by GitHub
parent 6af76d678e
commit 5b534391b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 95 additions and 183 deletions

View File

@ -250,7 +250,6 @@
value={object}
statuses={issueStatuses}
kind="no-border"
width="min-content"
size="small"
shouldShowLabel={true}
on:change={({ detail }) => (object.status = detail)}
@ -262,7 +261,6 @@
kind="no-border"
size="small"
justify="center"
width=""
on:change={({ detail }) => (object.priority = detail)}
/>
<AssigneeEditor

View File

@ -1,57 +0,0 @@
<!--
// 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 { IssuePriority } from '@anticrm/tracker'
import { Button, showPopup, SelectPopup, eventToHTMLElement } from '@anticrm/ui'
import type { ButtonKind, ButtonSize } from '@anticrm/ui'
import { defaultPriorities, issuePriorities } from '../utils'
import tracker from '../plugin'
export let priority: IssuePriority
export let shouldShowLabel: boolean = true
export let onPriorityChange: ((newPriority: IssuePriority | undefined) => void) | undefined = undefined
export let isEditable: boolean = true
export let kind: ButtonKind = 'no-border'
export let size: ButtonSize = 'small'
export let justify: 'left' | 'center' = 'center'
export let width: string | undefined = 'min-content'
const prioritiesInfo = defaultPriorities.map((p) => ({ id: p, ...issuePriorities[p] }))
const handlePriorityEditorOpened = (event: MouseEvent) => {
event.stopPropagation()
if (!isEditable) {
return
}
showPopup(
SelectPopup,
{ value: prioritiesInfo, placeholder: tracker.string.SetPriority, searchable: true },
eventToHTMLElement(event),
onPriorityChange
)
}
</script>
<Button
label={shouldShowLabel ? issuePriorities[priority].label : undefined}
icon={issuePriorities[priority].icon}
{justify}
{width}
{size}
{kind}
disabled={!isEditable}
on:click={handlePriorityEditorOpened}
/>

View File

@ -1,65 +0,0 @@
<!--
// 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 { Ref, WithLookup } from '@anticrm/core'
import { IssueStatus } from '@anticrm/tracker'
import { Button, showPopup, SelectPopup, eventToHTMLElement } from '@anticrm/ui'
import type { ButtonKind, ButtonSize } from '@anticrm/ui'
import tracker from '../plugin'
export let selectedStatusId: Ref<IssueStatus>
export let statuses: WithLookup<IssueStatus>[]
export let shouldShowLabel: boolean = true
export let onStatusChange: ((newStatus: Ref<IssueStatus> | undefined) => void) | undefined = undefined
export let isEditable: boolean = true
export let kind: ButtonKind = 'no-border'
export let size: ButtonSize = 'small'
export let justify: 'left' | 'center' = 'center'
export let width: string | undefined = 'min-content'
$: selectedStatus = statuses.find((status) => status._id === selectedStatusId) ?? statuses[0]
$: selectedStatusIcon = selectedStatus?.$lookup?.category?.icon
$: selectedStatusLabel = shouldShowLabel ? selectedStatus?.name : undefined
$: statusesInfo = statuses.map((s) => ({ id: s._id, text: s.name, color: s.color, icon: s.$lookup?.category?.icon }))
const handleStatusEditorOpened = (event: MouseEvent) => {
if (!isEditable) {
return
}
showPopup(
SelectPopup,
{ value: statusesInfo, placeholder: tracker.string.SetStatus, searchable: true },
eventToHTMLElement(event),
onStatusChange
)
}
</script>
<Button
icon={selectedStatusIcon}
{justify}
{width}
{size}
{kind}
disabled={!isEditable}
on:click={handleStatusEditorOpened}
>
<svelte:fragment slot="content">
{#if selectedStatusLabel}
<span class="overflow-label disabled">{selectedStatusLabel}</span>
{/if}
</svelte:fragment>
</Button>

View File

@ -182,14 +182,7 @@
{#if issue && issueStatuses && issue.subIssues > 0}
<SubIssuesSelector {issue} {currentTeam} {issueStatuses} />
{/if}
<PriorityEditor
value={issue}
isEditable={true}
kind={'link-bordered'}
size={'inline'}
justify={'center'}
width={''}
/>
<PriorityEditor value={issue} isEditable={true} kind={'link-bordered'} size={'inline'} justify={'center'} />
<ProjectEditor
value={issue}
isEditable={true}

View File

@ -36,7 +36,7 @@
const replacedKeys: Map<string, BuildModelKey> = new Map<string, BuildModelKey>([
['@currentTeam', { key: '', presenter: tracker.component.IssuePresenter, props: { currentTeam } }],
['@statuses', { key: '', presenter: tracker.component.StatusEditor, props: { statuses } }]
['@statuses', { key: '', presenter: tracker.component.StatusEditor, props: { statuses, justify: 'center' } }]
])
function createConfig (descr: Viewlet, preference: ViewletPreference | undefined): (string | BuildModelKey)[] {

View File

@ -232,6 +232,7 @@
<svelte:component
this={attributeModel.presenter}
value={getObjectValue(attributeModel.key, docObject) ?? ''}
width="100%"
{...attributeModel.props}
/>
</div>
@ -256,6 +257,7 @@
this={attributeModel.presenter}
value={getObjectValue(attributeModel.key, docObject) ?? ''}
issueId={docObject._id}
width="100%"
{...attributeModel.props}
/>
</div>

View File

@ -194,14 +194,7 @@
{#if issue && issueStatuses && issue.subIssues > 0}
<SubIssuesSelector {issue} {currentTeam} {issueStatuses} />
{/if}
<PriorityEditor
value={issue}
isEditable={true}
kind={'link-bordered'}
size={'inline'}
justify={'center'}
width={''}
/>
<PriorityEditor value={issue} isEditable={true} kind={'link-bordered'} size={'inline'} justify={'center'} />
<ProjectEditor
value={issue}
isEditable={true}

View File

@ -17,10 +17,10 @@
import { AttachedData } from '@anticrm/core'
import { Issue, IssuePriority } from '@anticrm/tracker'
import { getClient } from '@anticrm/presentation'
import { tooltip } from '@anticrm/ui'
import type { ButtonKind, ButtonSize } from '@anticrm/ui'
import { Button, eventToHTMLElement } from '@anticrm/ui'
import { ButtonKind, ButtonSize, showPopup, SelectPopup } from '@anticrm/ui'
import tracker from '../../plugin'
import PrioritySelector from '../PrioritySelector.svelte'
import { defaultPriorities, issuePriorities } from '../../utils'
export let value: Issue | AttachedData<Issue>
export let isEditable: boolean = true
@ -29,12 +29,28 @@
export let kind: ButtonKind = 'link'
export let size: ButtonSize = 'large'
export let justify: 'left' | 'center' = 'left'
export let width: string | undefined = '100%'
export let width: string | undefined = undefined
const client = getClient()
const dispatch = createEventDispatcher()
const prioritiesInfo = defaultPriorities.map((p) => ({ id: p, ...issuePriorities[p] }))
const handlePriorityChanged = async (newPriority: IssuePriority | undefined) => {
const handlePriorityEditorOpened = (event: MouseEvent) => {
event.stopPropagation()
if (!isEditable) {
return
}
showPopup(
SelectPopup,
{ value: prioritiesInfo, placeholder: tracker.string.SetPriority, searchable: true },
eventToHTMLElement(event),
changePriority
)
}
const changePriority = async (newPriority: IssuePriority | undefined) => {
if (!isEditable || newPriority === undefined || value.priority === newPriority) {
return
}
@ -48,16 +64,15 @@
</script>
{#if value}
<div class="clear-mins" use:tooltip={isEditable ? { label: tracker.string.SetPriority } : undefined}>
<PrioritySelector
{kind}
{size}
{width}
{justify}
{isEditable}
{shouldShowLabel}
bind:priority={value.priority}
onPriorityChange={handlePriorityChanged}
/>
</div>
<Button
showTooltip={isEditable ? { label: tracker.string.SetPriority } : undefined}
label={shouldShowLabel ? issuePriorities[value.priority].label : undefined}
icon={issuePriorities[value.priority].icon}
{justify}
{width}
{size}
{kind}
disabled={!isEditable}
on:click={handlePriorityEditorOpened}
/>
{/if}

View File

@ -17,13 +17,12 @@
import { AttachedData, Ref, SortingOrder, WithLookup } from '@anticrm/core'
import { Issue, IssueStatus } from '@anticrm/tracker'
import { createQuery, getClient } from '@anticrm/presentation'
import { tooltip, TooltipAlignment } from '@anticrm/ui'
import { Button, showPopup, SelectPopup, TooltipAlignment, eventToHTMLElement } from '@anticrm/ui'
import type { ButtonKind, ButtonSize } from '@anticrm/ui'
import tracker from '../../plugin'
import StatusSelector from '../StatusSelector.svelte'
export let value: Issue | AttachedData<Issue>
export let statuses: WithLookup<IssueStatus>[]
export let statuses: WithLookup<IssueStatus>[] | undefined = undefined
export let isEditable: boolean = true
export let shouldShowLabel: boolean = false
export let tooltipAlignment: TooltipAlignment | undefined = undefined
@ -31,13 +30,13 @@
export let kind: ButtonKind = 'link'
export let size: ButtonSize = 'large'
export let justify: 'left' | 'center' = 'left'
export let width: string | undefined = '100%'
export let width: string | undefined = undefined
const client = getClient()
const statusesQuery = createQuery()
const dispatch = createEventDispatcher()
const handleStatusChanged = async (newStatus: Ref<IssueStatus> | undefined) => {
const changeStatus = async (newStatus: Ref<IssueStatus> | undefined) => {
if (!isEditable || newStatus === undefined || value.status === newStatus) {
return
}
@ -48,6 +47,24 @@
await client.update(value, { status: newStatus })
}
}
const handleStatusEditorOpened = (event: MouseEvent) => {
if (!isEditable) {
return
}
showPopup(
SelectPopup,
{ value: statusesInfo, placeholder: tracker.string.SetStatus, searchable: true },
eventToHTMLElement(event),
changeStatus
)
}
$: selectedStatus = statuses?.find((status) => status._id === value.status) ?? statuses?.[0]
$: selectedStatusIcon = selectedStatus?.$lookup?.category?.icon
$: selectedStatusLabel = shouldShowLabel ? selectedStatus?.name : undefined
$: statusesInfo = statuses?.map((s) => ({ id: s._id, text: s.name, color: s.color, icon: s.$lookup?.category?.icon }))
$: if (!statuses) {
const query = '_id' in value ? { attachedTo: value.space } : {}
statusesQuery.query(
@ -65,20 +82,29 @@
</script>
{#if value && statuses}
<div
class="clear-mins"
use:tooltip={isEditable ? { label: tracker.string.SetStatus, direction: tooltipAlignment } : undefined}
>
<StatusSelector
{kind}
{size}
{width}
{#if selectedStatusLabel}
<Button
showTooltip={isEditable ? { label: tracker.string.SetStatus, direction: tooltipAlignment } : undefined}
icon={selectedStatusIcon}
disabled={!isEditable}
{justify}
{isEditable}
{shouldShowLabel}
{statuses}
bind:selectedStatusId={value.status}
onStatusChange={handleStatusChanged}
{size}
{kind}
{width}
on:click={handleStatusEditorOpened}
>
<span slot="content" class="overflow-label disabled">{selectedStatusLabel}</span>
</Button>
{:else}
<Button
showTooltip={isEditable ? { label: tracker.string.SetStatus, direction: tooltipAlignment } : undefined}
icon={selectedStatusIcon}
disabled={!isEditable}
{justify}
{size}
{kind}
{width}
on:click={handleStatusEditorOpened}
/>
</div>
{/if}
{/if}

View File

@ -103,13 +103,13 @@
<div bind:this={thisRef} class="flex-col root">
<div class="flex-row-top">
<div id="status-editor">
<div id="status-editor" class="mr-1">
<StatusEditor
value={newIssue}
statuses={issueStatuses}
kind="transparent"
width="min-content"
size="medium"
justify="center"
tooltipAlignment="bottom"
on:change={({ detail }) => (newIssue.status = detail)}
/>
@ -141,7 +141,6 @@
kind="no-border"
size="small"
justify="center"
width=""
on:change={({ detail }) => (newIssue.priority = detail)}
/>
<AssigneeEditor

View File

@ -93,13 +93,21 @@
<div class="draggable-mark"><Circles /></div>
</div>
<div class="flex-center ml-6 clear-mins">
<div class="mr-2">
<PriorityEditor value={issue} isEditable kind="transparent" justify="center" width="" />
<div class="mr-1">
<PriorityEditor value={issue} isEditable kind="transparent" justify="center" />
</div>
<span class="flex-no-shrink text" on:click={() => openIssue(issue)}>
{getIssueId(currentTeam, issue)}
</span>
<StatusEditor value={issue} statuses={issueStatuses} kind="transparent" tooltipAlignment="bottom" />
<div class="mx-1">
<StatusEditor
value={issue}
statuses={issueStatuses}
justify="center"
kind="transparent"
tooltipAlignment="bottom"
/>
</div>
<span class="text name" title={issue.title} on:click={() => openIssue(issue)}>
{issue.title}
</span>