Update new issue dialog (#1310)

Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@xored.com>
This commit is contained in:
Sergei Ogorelkov 2022-04-08 13:27:02 +07:00 committed by GitHub
parent a1e557a9b9
commit 207bcf73bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 233 additions and 96 deletions

View File

@ -22,7 +22,7 @@
"InProgress": "In Progress",
"Done": "Done",
"Canceled": "Canceled",
"SetStatus": "Set status...",
"SetStatus": "Set status\u2026",
"Priority": "Priority",
"NoPriority": "No priority",
"Urgent": "Urgent",
@ -35,14 +35,15 @@
"Status": "",
"Number": "Number",
"Assignee": "Assignee",
"Parent": "",
"Parent": "Set parent issue\u2026",
"BlockedBy": "",
"RelatedTo": "",
"Comments": "",
"Attachments": "",
"Labels": "",
"Labels": "Labels",
"Project": "Project",
"Space": "",
"DueDate": "",
"DueDate": "Set due date\u2026",
"Team": "",
"Issue": "",
"Document": "",
@ -53,7 +54,5 @@
"IssueDescriptionPlaceholder": "Add description",
"AddIssueTooltip": "Add issue..."
},
"status": {
}
}
"status": {}
}

View File

@ -15,22 +15,44 @@
"Board": "Board",
"Projects": "Projects",
"CreateTeam": "Create team",
"SaveIssue": "Save issue",
"CreateMore": "Create more",
"NewIssue": "Новая задача",
"SaveIssue": "Сохранить задачу",
"CreateMore": "Создать еще",
"Todo": "Todo",
"InProgress": "In Progress",
"Done": "Done",
"Canceled": "Canceled",
"SetStatus": "Set status...",
"Priority": "Priority",
"NoPriority": "No priority",
"Urgent": "Urgent",
"High": "High",
"Medium": "Medium",
"Low": "Low",
"AddIssueTooltip": "Добавить задачу..."
"InProgress": "В работе",
"Done": "Выполнено",
"Canceled": "Отменено",
"SetStatus": "Установить статус\u2026",
"Priority": "Установить приоритет",
"NoPriority": "Нет приоритета",
"Urgent": "Наивысший",
"High": "Высокий",
"Medium": "Средний",
"Low": "Низкий",
"AddIssueTooltip": "Добавить задачу\u2026",
"Title": "Заголовок",
"Description": "",
"Status": "",
"Number": "Number",
"Assignee": "Исполнитель",
"Parent": "Указать родительскую задачу\u2026",
"BlockedBy": "",
"RelatedTo": "",
"Comments": "",
"Attachments": "",
"Labels": "Метки",
"Project": "Проект",
"Space": "",
"DueDate": "Указать срок выполнения\u2026",
"Team": "",
"Issue": "",
"Document": "",
"DocumentIcon": "",
"DocumentColor": "",
"Rank": "",
"IssueTitlePlaceholder": "Имя задачи",
"IssueDescriptionPlaceholder": "Описание задачи"
},
"status": {
}
}
"status": {}
}

View File

@ -31,6 +31,11 @@ loadMetadata(tracker.icon, {
NewIssue: `${icons}#newissue`,
Magnifier: `${icons}#magnifier`,
Home: `${icons}#home`,
Labels: `${icons}#priority-nopriority`, // TODO: add icon
MoreActions: `${icons}#priority-nopriority`, // TODO: add icon
DueDate: `${icons}#inbox`, // TODO: add icon
Parent: `${icons}#myissues`, // TODO: add icon
StatusBacklog: `${icons}#status-backlog`,
StatusTodo: `${icons}#status-todo`,
StatusInProgress: `${icons}#status-inprogress`,

View File

@ -13,26 +13,28 @@
// limitations under the License.
-->
<script lang="ts">
import { Employee } from '@anticrm/contact'
import contact, { Employee } from '@anticrm/contact'
import core, { Data, generateId, Ref, SortingOrder } from '@anticrm/core'
import { Asset, IntlString } from '@anticrm/platform'
import { getClient } from '@anticrm/presentation'
import { getClient, UserBox } from '@anticrm/presentation'
import { Issue, IssuePriority, IssueStatus, Team } from '@anticrm/tracker'
import ui, { Button, DateRangePresenter, EditBox, showPopup } from '@anticrm/ui'
import { StyledTextBox } from '@anticrm/text-editor'
import { EditBox, Button, showPopup } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import tracker from '../plugin'
import { calcRank } from '../utils'
import Card from './Card.svelte'
import SelectPopup from './SelectPopup.svelte'
import StatusSelector from './StatusSelector.svelte'
import PrioritySelector from './PrioritySelector.svelte'
export let space: Ref<Team>
export let parent: Ref<Issue> | undefined
export let issueStatus = IssueStatus.Backlog
$: _space = space
$: _parent = parent
const assignee: Ref<Employee> | null = null
let assignee: Ref<Employee> | null = null
const object: Data<Issue> = {
title: '',
@ -86,27 +88,10 @@
await client.createDoc(tracker.class.Issue, _space, value, taskId)
}
const startDate: number | null = null
const targetDate: number | null = null
interface IPair {
icon: Asset
label: IntlString
}
const statuses: Array<IPair> =
[{ icon: tracker.icon.StatusBacklog, label: tracker.string.Backlog },
{ icon: tracker.icon.StatusTodo, label: tracker.string.Todo },
{ icon: tracker.icon.StatusInProgress, label: tracker.string.InProgress },
{ icon: tracker.icon.StatusDone, label: tracker.string.Done },
{ icon: tracker.icon.StatusCanceled, label: tracker.string.Canceled }]
// TODO: Refactor
let selectStatus: IPair = statuses[issueStatus]
const priorities: Array<IPair> =
[{ icon: tracker.icon.PriorityNoPriority, label: tracker.string.NoPriority },
{ icon: tracker.icon.PriorityUrgent, label: tracker.string.Urgent },
{ icon: tracker.icon.PriorityHigh, label: tracker.string.High },
{ icon: tracker.icon.PriorityMedium, label: tracker.string.Medium },
{ icon: tracker.icon.PriorityLow, label: tracker.string.Low }]
let selectPriority: IPair = priorities[0]
const moreActions: Array<{ icon: Asset; label: IntlString }> = [
{ icon: tracker.icon.DueDate, label: tracker.string.DueDate },
{ icon: tracker.icon.Parent, label: tracker.string.Parent }
]
</script>
<!-- canSave: object.title.length > 0 && _space != null -->
@ -132,42 +117,49 @@
kind={'large-style'}
focus
/>
<!-- <StyledTextBox alwaysEdit bind:content={object.description} placeholder={tracker.string.IssueDescriptionPlaceholder}/> -->
<!-- <UserBox
_class={contact.class.Employee}
title={tracker.string.Assignee}
caption={tracker.string.Assignee}
bind:value={assignee}
allowDeselect
titleDeselect={tracker.string.TaskUnAssign}
/> -->
<div style="height: 30px"></div>
<div class="mt-4">
<StyledTextBox
alwaysEdit
showButtons={false}
bind:content={object.description}
placeholder={tracker.string.IssueDescriptionPlaceholder}
/>
</div>
<div slot="pool" class="flex-row-center text-sm gap-1-5">
<Button
label={selectStatus.label}
icon={selectStatus.icon}
width={'min-content'}
size={'small'}
kind={'no-border'}
on:click={(ev) => {
showPopup(SelectPopup, { value: statuses, placeholder: tracker.string.SetStatus, searchable: true }, ev.currentTarget, (result) => {
if (result !== undefined) { selectStatus = result }
})
}}
<StatusSelector bind:status={object.status} />
<PrioritySelector bind:priority={object.priority} />
<UserBox
_class={contact.class.Employee}
title={tracker.string.Assignee}
caption={tracker.string.Assignee}
bind:value={assignee}
allowDeselect
titleDeselect={tracker.string.TaskUnAssign}
/>
<Button
label={selectPriority.label}
icon={selectPriority.icon}
width={'min-content'}
size={'small'}
kind={'no-border'}
label={tracker.string.Labels}
icon={tracker.icon.Labels}
width="min-content"
size="small"
kind="no-border"
/>
<Button
label={tracker.string.Project}
icon={tracker.icon.Projects}
width="min-content"
size="small"
kind="no-border"
/>
<Button
icon={tracker.icon.MoreActions}
width="min-content"
size="small"
kind="transparent"
on:click={(ev) => {
showPopup(SelectPopup, { value: priorities, placeholder: tracker.string.SetStatus }, ev.currentTarget, (result) => {
if (result !== undefined) { selectPriority = result }
})
showPopup(SelectPopup, { value: moreActions }, ev.currentTarget)
}}
/>
<DateRangePresenter value={startDate} labelNull={ui.string.StartDate} editable />
<DateRangePresenter value={targetDate} labelNull={ui.string.TargetDate} editable />
<!-- <DateRangePresenter value={startDate} labelNull={ui.string.StartDate} editable />
<DateRangePresenter value={targetDate} labelNull={ui.string.TargetDate} editable /> -->
</div>
</Card>

View File

@ -0,0 +1,53 @@
<!--
// 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 } from '@anticrm/ui'
import { issuePriorities } from '../utils'
import tracker from '../plugin'
import SelectPopup from './SelectPopup.svelte'
export let priority: IssuePriority
const prioritiesInfo = [
IssuePriority.NoPriority,
IssuePriority.Urgent,
IssuePriority.High,
IssuePriority.Medium,
IssuePriority.Low
].map((s) => ({ id: s, ...issuePriorities[s] }))
function handlePriorityChange (id: any) {
if (id !== undefined) {
priority = id
}
}
</script>
<Button
label={issuePriorities[priority].label}
icon={issuePriorities[priority].icon}
width="min-content"
size="small"
kind="no-border"
on:click={(ev) => {
showPopup(
SelectPopup,
{ value: prioritiesInfo, placeholder: tracker.string.SetStatus },
ev.currentTarget,
handlePriorityChange
)
}}
/>

View File

@ -15,26 +15,17 @@
<script lang="ts">
import type { Asset, IntlString } from '@anticrm/platform'
import { translate } from '@anticrm/platform'
import { afterUpdate, createEventDispatcher } from 'svelte'
import type { Ref, Class, Space, DocumentQuery } from '@anticrm/core'
import { createQuery } from '@anticrm/presentation'
import { createEventDispatcher } from 'svelte'
import { Icon, Label } from '@anticrm/ui'
import tracker from '../plugin'
// export let _class: Ref<Class<Space>>
// export let spaceQuery: DocumentQuery<Space> | undefined
export let placeholder: IntlString | undefined = undefined
export let placeholderParam: any | undefined = undefined
export let searchable: boolean = false
export let value: Array<{
icon: Asset
label: IntlString
}>
export let value: Array<{id: number | string, icon: Asset, label: IntlString}>
let search: string = ''
let input: HTMLInputElement
let objects: Space[] = []
let phTraslate: string = ''
$: if (placeholder) translate(placeholder, placeholderParam ?? {}).then(res => { phTraslate = res })
@ -48,13 +39,13 @@
<div class="selectPopup">
{#if searchable}
<div class="header">
<input bind:this={input} type='text' bind:value={search} placeholder={phTraslate} on:input={(ev) => { }} on:change/>
<input type='text' bind:value={search} placeholder={phTraslate} on:input={(ev) => { }} on:change/>
</div>
{/if}
<div class="scroll">
<div class="box">
{#each value.filter(el => el.label.toLowerCase().includes(search.toLowerCase())) as space}
<button class="menu-item" on:click={() => { dispatch('close', space) }}>
<button class="menu-item" on:click={() => { dispatch('close', space.id) }}>
<div class="icon"><Icon icon={space.icon} size={'small'} /></div>
<span class="label"><Label label={space.label} /></span>
</button>

View File

@ -0,0 +1,53 @@
<!--
// 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 { IssueStatus } from '@anticrm/tracker'
import { Button, showPopup } from '@anticrm/ui'
import { issueStatuses } from '../utils'
import tracker from '../plugin'
import SelectPopup from './SelectPopup.svelte'
export let status: IssueStatus
const statusesInfo = [
IssueStatus.Backlog,
IssueStatus.Todo,
IssueStatus.InProgress,
IssueStatus.Done,
IssueStatus.Canceled
].map((s) => ({ id: s, ...issueStatuses[s] }))
function handleStatusChange (id: any) {
if (id !== undefined) {
status = id
}
}
</script>
<Button
label={issueStatuses[status].label}
icon={issueStatuses[status].icon}
width="min-content"
size="small"
kind="no-border"
on:click={(ev) => {
showPopup(
SelectPopup,
{ value: statusesInfo, placeholder: tracker.string.SetStatus, searchable: true },
ev.currentTarget,
handleStatusChange
)
}}
/>

View File

@ -31,6 +31,7 @@ export default mergeIds(trackerId, tracker, {
Active: '' as IntlString,
Backlog: '' as IntlString,
Board: '' as IntlString,
Project: '' as IntlString,
Projects: '' as IntlString,
CreateTeam: '' as IntlString,
NewIssue: '' as IntlString,

View File

@ -16,10 +16,11 @@
import { Ref } from '@anticrm/core'
import type { Asset, IntlString } from '@anticrm/platform'
import { Team } from '@anticrm/tracker'
import { IssuePriority, IssueStatus, Team } from '@anticrm/tracker'
import { AnyComponent } from '@anticrm/ui'
import { LexoDecimal, LexoNumeralSystem36, LexoRank } from 'lexorank'
import LexoRankBucket from 'lexorank/lib/lexoRank/lexoRankBucket'
import tracker from './plugin'
export interface NavigationItem {
id: string
@ -61,3 +62,19 @@ export const calcRank = (prev?: { rank: string }, next?: { rank: string }): stri
return a.between(b).toString()
}
export const issueStatuses: Record<IssueStatus, { icon: Asset, label: IntlString }> = {
[IssueStatus.Backlog]: { icon: tracker.icon.StatusBacklog, label: tracker.string.Backlog },
[IssueStatus.Todo]: { icon: tracker.icon.StatusTodo, label: tracker.string.Todo },
[IssueStatus.InProgress]: { icon: tracker.icon.StatusInProgress, label: tracker.string.InProgress },
[IssueStatus.Done]: { icon: tracker.icon.StatusDone, label: tracker.string.Done },
[IssueStatus.Canceled]: { icon: tracker.icon.StatusCanceled, label: tracker.string.Canceled }
}
export const issuePriorities: Record<IssuePriority, { icon: Asset, label: IntlString }> = {
[IssuePriority.NoPriority]: { icon: tracker.icon.PriorityNoPriority, label: tracker.string.NoPriority },
[IssuePriority.Urgent]: { icon: tracker.icon.PriorityUrgent, label: tracker.string.Urgent },
[IssuePriority.High]: { icon: tracker.icon.PriorityHigh, label: tracker.string.High },
[IssuePriority.Medium]: { icon: tracker.icon.PriorityMedium, label: tracker.string.Medium },
[IssuePriority.Low]: { icon: tracker.icon.PriorityLow, label: tracker.string.Low }
}

View File

@ -149,6 +149,10 @@ export default plugin(trackerId, {
NewIssue: '' as Asset,
Magnifier: '' as Asset,
Home: '' as Asset,
Labels: '' as Asset,
MoreActions: '' as Asset,
DueDate: '' as Asset,
Parent: '' as Asset,
StatusBacklog: '' as Asset,
StatusTodo: '' as Asset,