mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-13 03:40:48 +00:00
Update new issue dialog (#1310)
Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@xored.com>
This commit is contained in:
parent
a1e557a9b9
commit
207bcf73bb
@ -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": {}
|
||||
}
|
||||
|
@ -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": {}
|
||||
}
|
||||
|
@ -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`,
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
)
|
||||
}}
|
||||
/>
|
@ -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>
|
||||
|
@ -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
|
||||
)
|
||||
}}
|
||||
/>
|
@ -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,
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user