mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 21:50:34 +03:00
TSK-425: Supported team settings (#2406)
Signed-off-by: Anton Brechka <anton.brechka@ezthera.com>
This commit is contained in:
parent
a843530bb2
commit
d2345cd931
@ -11,7 +11,14 @@ import core, {
|
|||||||
SortingOrder,
|
SortingOrder,
|
||||||
WorkspaceId
|
WorkspaceId
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import tracker, { calcRank, Issue, IssuePriority, IssueStatus } from '../../../plugins/tracker/lib'
|
import tracker, {
|
||||||
|
calcRank,
|
||||||
|
Issue,
|
||||||
|
IssuePriority,
|
||||||
|
IssueStatus,
|
||||||
|
TimeReportDayType,
|
||||||
|
WorkDayLength
|
||||||
|
} from '../../../plugins/tracker/lib'
|
||||||
|
|
||||||
import { connect } from './connect'
|
import { connect } from './connect'
|
||||||
|
|
||||||
@ -35,7 +42,9 @@ const object: AttachedData<Issue> = {
|
|||||||
reportedTime: 0,
|
reportedTime: 0,
|
||||||
estimation: 0,
|
estimation: 0,
|
||||||
reports: 0,
|
reports: 0,
|
||||||
childInfo: []
|
childInfo: [],
|
||||||
|
workDayLength: WorkDayLength.EIGHT_HOURS,
|
||||||
|
defaultTimeReportDay: TimeReportDayType.PreviousWorkDay
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IssueOptions {
|
export interface IssueOptions {
|
||||||
@ -97,7 +106,9 @@ async function genIssue (client: TxOperations): Promise<void> {
|
|||||||
estimation: object.estimation,
|
estimation: object.estimation,
|
||||||
reports: 0,
|
reports: 0,
|
||||||
relations: [],
|
relations: [],
|
||||||
childInfo: []
|
childInfo: [],
|
||||||
|
workDayLength: object.workDayLength,
|
||||||
|
defaultTimeReportDay: object.defaultTimeReportDay
|
||||||
}
|
}
|
||||||
await client.addCollection(
|
await client.addCollection(
|
||||||
tracker.class.Issue,
|
tracker.class.Issue,
|
||||||
|
@ -68,8 +68,10 @@ import {
|
|||||||
Sprint,
|
Sprint,
|
||||||
SprintStatus,
|
SprintStatus,
|
||||||
Team,
|
Team,
|
||||||
|
TimeReportDayType,
|
||||||
TimeSpendReport,
|
TimeSpendReport,
|
||||||
trackerId
|
trackerId,
|
||||||
|
WorkDayLength
|
||||||
} from '@hcengineering/tracker'
|
} from '@hcengineering/tracker'
|
||||||
import { KeyBinding } from '@hcengineering/view'
|
import { KeyBinding } from '@hcengineering/view'
|
||||||
import tracker from './plugin'
|
import tracker from './plugin'
|
||||||
@ -173,6 +175,9 @@ export class TTeam extends TSpace implements Team {
|
|||||||
|
|
||||||
@Prop(TypeRef(tracker.class.IssueStatus), tracker.string.DefaultIssueStatus)
|
@Prop(TypeRef(tracker.class.IssueStatus), tracker.string.DefaultIssueStatus)
|
||||||
defaultIssueStatus!: Ref<IssueStatus>
|
defaultIssueStatus!: Ref<IssueStatus>
|
||||||
|
|
||||||
|
declare workDayLength: WorkDayLength
|
||||||
|
declare defaultTimeReportDay: TimeReportDayType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -255,6 +260,9 @@ export class TIssue extends TAttachedDoc implements Issue {
|
|||||||
reports!: number
|
reports!: number
|
||||||
|
|
||||||
declare childInfo: IssueChildInfo[]
|
declare childInfo: IssueChildInfo[]
|
||||||
|
|
||||||
|
declare workDayLength: WorkDayLength
|
||||||
|
declare defaultTimeReportDay: TimeReportDayType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -858,6 +866,26 @@ export function createModel (builder: Builder): void {
|
|||||||
tracker.action.EditWorkflowStatuses
|
tracker.action.EditWorkflowStatuses
|
||||||
)
|
)
|
||||||
|
|
||||||
|
createAction(
|
||||||
|
builder,
|
||||||
|
{
|
||||||
|
action: tracker.actionImpl.EditTeam,
|
||||||
|
label: tracker.string.EditTeam,
|
||||||
|
icon: contact.icon.Edit,
|
||||||
|
input: 'focus',
|
||||||
|
category: tracker.category.Tracker,
|
||||||
|
target: tracker.class.Team,
|
||||||
|
query: {
|
||||||
|
archived: false
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
mode: ['context', 'browser'],
|
||||||
|
group: 'edit'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tracker.action.EditTeam
|
||||||
|
)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
view.class.ActionCategory,
|
view.class.ActionCategory,
|
||||||
core.space.Model,
|
core.space.Model,
|
||||||
|
@ -15,7 +15,15 @@
|
|||||||
|
|
||||||
import core, { Doc, DocumentUpdate, generateId, Ref, SortingOrder, TxOperations, TxResult } from '@hcengineering/core'
|
import core, { Doc, DocumentUpdate, generateId, Ref, SortingOrder, TxOperations, TxResult } from '@hcengineering/core'
|
||||||
import { createOrUpdate, MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
|
import { createOrUpdate, MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
|
||||||
import { IssueStatus, IssueStatusCategory, Team, genRanks, Issue } from '@hcengineering/tracker'
|
import {
|
||||||
|
IssueStatus,
|
||||||
|
IssueStatusCategory,
|
||||||
|
Team,
|
||||||
|
genRanks,
|
||||||
|
Issue,
|
||||||
|
TimeReportDayType,
|
||||||
|
WorkDayLength
|
||||||
|
} from '@hcengineering/tracker'
|
||||||
import tags from '@hcengineering/tags'
|
import tags from '@hcengineering/tags'
|
||||||
import { DOMAIN_TRACKER } from '.'
|
import { DOMAIN_TRACKER } from '.'
|
||||||
import tracker from './plugin'
|
import tracker from './plugin'
|
||||||
@ -99,7 +107,9 @@ async function createDefaultTeam (tx: TxOperations): Promise<void> {
|
|||||||
identifier: 'TSK',
|
identifier: 'TSK',
|
||||||
sequence: 0,
|
sequence: 0,
|
||||||
issueStatuses: 0,
|
issueStatuses: 0,
|
||||||
defaultIssueStatus: defaultStatusId
|
defaultIssueStatus: defaultStatusId,
|
||||||
|
defaultTimeReportDay: TimeReportDayType.PreviousWorkDay,
|
||||||
|
workDayLength: WorkDayLength.EIGHT_HOURS
|
||||||
},
|
},
|
||||||
tracker.team.DefaultTeam
|
tracker.team.DefaultTeam
|
||||||
)
|
)
|
||||||
@ -127,6 +137,21 @@ async function fixTeamsIssueStatusesOrder (tx: TxOperations): Promise<void> {
|
|||||||
await Promise.all(teams.map((team) => fixTeamIssueStatusesOrder(tx, team)))
|
await Promise.all(teams.map((team) => fixTeamIssueStatusesOrder(tx, team)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function upgradeTeamSettings (tx: TxOperations): Promise<void> {
|
||||||
|
const teams = await tx.findAll(tracker.class.Team, {
|
||||||
|
defaultTimeReportDay: { $exists: false },
|
||||||
|
workDayLength: { $exists: false }
|
||||||
|
})
|
||||||
|
await Promise.all(
|
||||||
|
teams.map((team) =>
|
||||||
|
tx.update(team, {
|
||||||
|
defaultTimeReportDay: TimeReportDayType.PreviousWorkDay,
|
||||||
|
workDayLength: WorkDayLength.EIGHT_HOURS
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async function upgradeTeamIssueStatuses (tx: TxOperations): Promise<void> {
|
async function upgradeTeamIssueStatuses (tx: TxOperations): Promise<void> {
|
||||||
const teams = await tx.findAll(tracker.class.Team, { issueStatuses: undefined })
|
const teams = await tx.findAll(tracker.class.Team, { issueStatuses: undefined })
|
||||||
|
|
||||||
@ -178,6 +203,25 @@ async function upgradeIssueStatuses (tx: TxOperations): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function upgradeIssueTimeReportSettings (tx: TxOperations): Promise<void> {
|
||||||
|
const issues = await tx.findAll(tracker.class.Issue, {
|
||||||
|
defaultTimeReportDay: { $exists: false },
|
||||||
|
workDayLength: { $exists: false }
|
||||||
|
})
|
||||||
|
|
||||||
|
const teams = await tx.findAll(tracker.class.Team, {
|
||||||
|
_id: { $in: Array.from(new Set(issues.map((issue) => issue.space))) }
|
||||||
|
})
|
||||||
|
const teamsById = new Map(teams.map((team) => [team._id, team]))
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
issues.map((issue) => {
|
||||||
|
const team = teamsById.get(issue.space)
|
||||||
|
return tx.update(issue, { defaultTimeReportDay: team?.defaultTimeReportDay, workDayLength: team?.workDayLength })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async function migrateParentIssues (client: MigrationClient): Promise<void> {
|
async function migrateParentIssues (client: MigrationClient): Promise<void> {
|
||||||
let { updated } = await client.update(
|
let { updated } = await client.update(
|
||||||
DOMAIN_TRACKER,
|
DOMAIN_TRACKER,
|
||||||
@ -305,10 +349,12 @@ async function createDefaults (tx: TxOperations): Promise<void> {
|
|||||||
async function upgradeTeams (tx: TxOperations): Promise<void> {
|
async function upgradeTeams (tx: TxOperations): Promise<void> {
|
||||||
await upgradeTeamIssueStatuses(tx)
|
await upgradeTeamIssueStatuses(tx)
|
||||||
await fixTeamsIssueStatusesOrder(tx)
|
await fixTeamsIssueStatusesOrder(tx)
|
||||||
|
await upgradeTeamSettings(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function upgradeIssues (tx: TxOperations): Promise<void> {
|
async function upgradeIssues (tx: TxOperations): Promise<void> {
|
||||||
await upgradeIssueStatuses(tx)
|
await upgradeIssueStatuses(tx)
|
||||||
|
await upgradeIssueTimeReportSettings(tx)
|
||||||
|
|
||||||
const issues = await tx.findAll(tracker.class.Issue, {
|
const issues = await tx.findAll(tracker.class.Issue, {
|
||||||
$or: [{ blockedBy: { $exists: true } }, { relatedIssue: { $exists: true } }]
|
$or: [{ blockedBy: { $exists: true } }, { relatedIssue: { $exists: true } }]
|
||||||
|
@ -56,6 +56,7 @@ export default mergeIds(trackerId, tracker, {
|
|||||||
actionImpl: {
|
actionImpl: {
|
||||||
CopyToClipboard: '' as ViewAction,
|
CopyToClipboard: '' as ViewAction,
|
||||||
EditWorkflowStatuses: '' as ViewAction,
|
EditWorkflowStatuses: '' as ViewAction,
|
||||||
|
EditTeam: '' as ViewAction,
|
||||||
DeleteSprint: '' as ViewAction
|
DeleteSprint: '' as ViewAction
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
|
@ -191,7 +191,7 @@ export interface DropdownTextItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface DropdownIntlItem {
|
export interface DropdownIntlItem {
|
||||||
id: string
|
id: string | number
|
||||||
label: IntlString
|
label: IntlString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +174,7 @@
|
|||||||
|
|
||||||
"EditIssue": "Edit {title}",
|
"EditIssue": "Edit {title}",
|
||||||
"EditWorkflowStatuses": "Edit issue statuses",
|
"EditWorkflowStatuses": "Edit issue statuses",
|
||||||
|
"EditTeam": "Edit team",
|
||||||
"ManageWorkflowStatuses": "Manage issue statuses within team",
|
"ManageWorkflowStatuses": "Manage issue statuses within team",
|
||||||
"AddWorkflowStatus": "Add issue status",
|
"AddWorkflowStatus": "Add issue status",
|
||||||
"EditWorkflowStatus": "Edit issue status",
|
"EditWorkflowStatus": "Edit issue status",
|
||||||
@ -230,6 +231,7 @@
|
|||||||
"TimeSpendReportValueTooltip": "Reported time in man days",
|
"TimeSpendReportValueTooltip": "Reported time in man days",
|
||||||
"TimeSpendReportDescription": "Description",
|
"TimeSpendReportDescription": "Description",
|
||||||
"TimeSpendValue": "{value}d",
|
"TimeSpendValue": "{value}d",
|
||||||
|
"TimeSpendHours": "{value}h",
|
||||||
"SprintPassed": "{from}d/{to}d",
|
"SprintPassed": "{from}d/{to}d",
|
||||||
"ChildEstimation": "Subissues Estimation",
|
"ChildEstimation": "Subissues Estimation",
|
||||||
"ChildReportedTime": "Subissues Time",
|
"ChildReportedTime": "Subissues Time",
|
||||||
@ -249,9 +251,14 @@
|
|||||||
"TemplateReplace": "You you replace applied process?",
|
"TemplateReplace": "You you replace applied process?",
|
||||||
"TemplateReplaceConfirm": "All changes to template values will be lost.",
|
"TemplateReplaceConfirm": "All changes to template values will be lost.",
|
||||||
|
|
||||||
"WorkDayCurrent": "Current Working Day",
|
"CurrentWorkDay": "Current Working Day",
|
||||||
"WorkDayPrevious": "Previous Working Day",
|
"PreviousWorkDay": "Previous Working Day",
|
||||||
"WorkDayLabel": "Select Working Day Type"
|
"TimeReportDayTypeLabel": "Select time report day type",
|
||||||
|
"DefaultTimeReportDay": "Select default day for time report",
|
||||||
|
|
||||||
|
"WorkDayLength": "Select length of working day",
|
||||||
|
"SevenHoursLength": "Seven Hours",
|
||||||
|
"EightHoursLength": "Eight Hours"
|
||||||
},
|
},
|
||||||
"status": {}
|
"status": {}
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,7 @@
|
|||||||
|
|
||||||
"EditIssue": "Редактирование {title}",
|
"EditIssue": "Редактирование {title}",
|
||||||
"EditWorkflowStatuses": "Редактировать статусы задач",
|
"EditWorkflowStatuses": "Редактировать статусы задач",
|
||||||
|
"EditTeam": "Редактировать команду",
|
||||||
"ManageWorkflowStatuses": "Управлять статусами задач для команды",
|
"ManageWorkflowStatuses": "Управлять статусами задач для команды",
|
||||||
"AddWorkflowStatus": "Добавить статус задачи",
|
"AddWorkflowStatus": "Добавить статус задачи",
|
||||||
"EditWorkflowStatus": "Редактировать статус задачи",
|
"EditWorkflowStatus": "Редактировать статус задачи",
|
||||||
@ -230,6 +231,7 @@
|
|||||||
"TimeSpendReportValueTooltip": "Затраченное время в человеко днях",
|
"TimeSpendReportValueTooltip": "Затраченное время в человеко днях",
|
||||||
"TimeSpendReportDescription": "Описание",
|
"TimeSpendReportDescription": "Описание",
|
||||||
"TimeSpendValue": "{value}d",
|
"TimeSpendValue": "{value}d",
|
||||||
|
"TimeSpendHours": "{value}h",
|
||||||
"SprintPassed": "{from}d/{to}d",
|
"SprintPassed": "{from}d/{to}d",
|
||||||
"ChildEstimation": "Оценка подзадач",
|
"ChildEstimation": "Оценка подзадач",
|
||||||
"ChildReportedTime": "Время водзадач",
|
"ChildReportedTime": "Время водзадач",
|
||||||
@ -249,9 +251,14 @@
|
|||||||
"TemplateReplace": "Вы хотите заменить выбранный процесс?",
|
"TemplateReplace": "Вы хотите заменить выбранный процесс?",
|
||||||
"TemplateReplaceConfirm": "Все внесенные изменения в задачу будут потеряны",
|
"TemplateReplaceConfirm": "Все внесенные изменения в задачу будут потеряны",
|
||||||
|
|
||||||
"WorkDayCurrent": "Текущий Рабочий День",
|
"CurrentWorkDay": "Текущий Рабочий День",
|
||||||
"WorkDayPrevious": "Предыдущий Рабочий День",
|
"PreviousWorkDay": "Предыдущий Рабочий День",
|
||||||
"WorkDayLabel": "Выберите Тип Рабочего Дня"
|
"TimeReportDayTypeLabel": "Выберите тип дня для временного отчета",
|
||||||
|
"DefaultTimeReportDay": "Выберите дeнь для временного отчета по умолчанию",
|
||||||
|
|
||||||
|
"WorkDayLength": "Выберите длину рабочего дня",
|
||||||
|
"SevenHoursLength": "Семь Часов",
|
||||||
|
"EightHoursLength": "Восемь Часов"
|
||||||
},
|
},
|
||||||
"status": {}
|
"status": {}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,9 @@
|
|||||||
IssueTemplateChild,
|
IssueTemplateChild,
|
||||||
Project,
|
Project,
|
||||||
Sprint,
|
Sprint,
|
||||||
Team
|
Team,
|
||||||
|
TimeReportDayType,
|
||||||
|
WorkDayLength
|
||||||
} from '@hcengineering/tracker'
|
} from '@hcengineering/tracker'
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
@ -91,6 +93,7 @@
|
|||||||
let issueStatuses: WithLookup<IssueStatus>[] | undefined
|
let issueStatuses: WithLookup<IssueStatus>[] | undefined
|
||||||
let labels: TagReference[] = draft?.labels || []
|
let labels: TagReference[] = draft?.labels || []
|
||||||
let objectId: Ref<Issue> = draft?.issueId || generateId()
|
let objectId: Ref<Issue> = draft?.issueId || generateId()
|
||||||
|
let currentTeam: Team | undefined
|
||||||
|
|
||||||
function toIssue (initials: AttachedData<Issue>, draft: IssueDraft | null): AttachedData<Issue> {
|
function toIssue (initials: AttachedData<Issue>, draft: IssueDraft | null): AttachedData<Issue> {
|
||||||
if (draft == null) {
|
if (draft == null) {
|
||||||
@ -100,7 +103,29 @@
|
|||||||
return { ...initials, ...issue }
|
return { ...initials, ...issue }
|
||||||
}
|
}
|
||||||
|
|
||||||
let object: AttachedData<Issue> = originalIssue
|
const defaultIssue = {
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
assignee,
|
||||||
|
project,
|
||||||
|
sprint,
|
||||||
|
number: 0,
|
||||||
|
rank: '',
|
||||||
|
status: '' as Ref<IssueStatus>,
|
||||||
|
priority,
|
||||||
|
dueDate: null,
|
||||||
|
comments: 0,
|
||||||
|
subIssues: 0,
|
||||||
|
parents: [],
|
||||||
|
reportedTime: 0,
|
||||||
|
estimation: 0,
|
||||||
|
reports: 0,
|
||||||
|
childInfo: [],
|
||||||
|
workDayLength: currentTeam?.workDayLength ?? WorkDayLength.EIGHT_HOURS,
|
||||||
|
defaultTimeReportDay: currentTeam?.defaultTimeReportDay ?? TimeReportDayType.PreviousWorkDay
|
||||||
|
}
|
||||||
|
|
||||||
|
let object = originalIssue
|
||||||
? {
|
? {
|
||||||
...originalIssue,
|
...originalIssue,
|
||||||
title: `${originalIssue.title} (copy)`,
|
title: `${originalIssue.title} (copy)`,
|
||||||
@ -110,51 +135,19 @@
|
|||||||
reports: 0,
|
reports: 0,
|
||||||
childInfo: []
|
childInfo: []
|
||||||
}
|
}
|
||||||
: toIssue(
|
: toIssue(defaultIssue, draft)
|
||||||
{
|
|
||||||
title: '',
|
$: {
|
||||||
description: '',
|
defaultIssue.workDayLength = currentTeam?.workDayLength ?? WorkDayLength.EIGHT_HOURS
|
||||||
assignee,
|
defaultIssue.defaultTimeReportDay = currentTeam?.defaultTimeReportDay ?? TimeReportDayType.PreviousWorkDay
|
||||||
project,
|
object.workDayLength = defaultIssue.workDayLength
|
||||||
sprint,
|
object.defaultTimeReportDay = defaultIssue.defaultTimeReportDay
|
||||||
number: 0,
|
}
|
||||||
rank: '',
|
|
||||||
status: '' as Ref<IssueStatus>,
|
|
||||||
priority,
|
|
||||||
dueDate: null,
|
|
||||||
comments: 0,
|
|
||||||
subIssues: 0,
|
|
||||||
parents: [],
|
|
||||||
reportedTime: 0,
|
|
||||||
estimation: 0,
|
|
||||||
reports: 0,
|
|
||||||
childInfo: []
|
|
||||||
},
|
|
||||||
draft
|
|
||||||
)
|
|
||||||
|
|
||||||
function resetObject (): void {
|
function resetObject (): void {
|
||||||
templateId = undefined
|
templateId = undefined
|
||||||
template = undefined
|
template = undefined
|
||||||
object = {
|
object = { ...defaultIssue }
|
||||||
title: '',
|
|
||||||
description: '',
|
|
||||||
assignee,
|
|
||||||
project,
|
|
||||||
sprint,
|
|
||||||
number: 0,
|
|
||||||
rank: '',
|
|
||||||
status: '' as Ref<IssueStatus>,
|
|
||||||
priority,
|
|
||||||
dueDate: null,
|
|
||||||
comments: 0,
|
|
||||||
subIssues: 0,
|
|
||||||
parents: [],
|
|
||||||
reportedTime: 0,
|
|
||||||
estimation: 0,
|
|
||||||
reports: 0,
|
|
||||||
childInfo: []
|
|
||||||
}
|
|
||||||
subIssues = []
|
subIssues = []
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,6 +214,7 @@
|
|||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const statusesQuery = createQuery()
|
const statusesQuery = createQuery()
|
||||||
|
const spaceQuery = createQuery()
|
||||||
|
|
||||||
let descriptionBox: AttachmentStyledBox
|
let descriptionBox: AttachmentStyledBox
|
||||||
|
|
||||||
@ -244,6 +238,9 @@
|
|||||||
sort: { rank: SortingOrder.Ascending }
|
sort: { rank: SortingOrder.Ascending }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
$: spaceQuery.query(tracker.class.Team, { _id: _space }, (res) => {
|
||||||
|
currentTeam = res.shift()
|
||||||
|
})
|
||||||
|
|
||||||
async function setPropsFromOriginalIssue () {
|
async function setPropsFromOriginalIssue () {
|
||||||
if (!originalIssue) {
|
if (!originalIssue) {
|
||||||
@ -418,7 +415,9 @@
|
|||||||
estimation: object.estimation,
|
estimation: object.estimation,
|
||||||
reports: 0,
|
reports: 0,
|
||||||
relations: relatedTo !== undefined ? [{ _id: relatedTo._id, _class: relatedTo._class }] : [],
|
relations: relatedTo !== undefined ? [{ _id: relatedTo._id, _class: relatedTo._class }] : [],
|
||||||
childInfo: []
|
childInfo: [],
|
||||||
|
workDayLength: object.workDayLength,
|
||||||
|
defaultTimeReportDay: object.defaultTimeReportDay
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.addCollection(
|
||||||
@ -490,7 +489,9 @@
|
|||||||
estimation: subIssue.estimation,
|
estimation: subIssue.estimation,
|
||||||
reports: 0,
|
reports: 0,
|
||||||
relations: [],
|
relations: [],
|
||||||
childInfo: []
|
childInfo: [],
|
||||||
|
workDayLength: object.workDayLength,
|
||||||
|
defaultTimeReportDay: object.defaultTimeReportDay
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.addCollection(
|
||||||
|
@ -65,7 +65,9 @@
|
|||||||
estimation: 0,
|
estimation: 0,
|
||||||
reportedTime: 0,
|
reportedTime: 0,
|
||||||
reports: 0,
|
reports: 0,
|
||||||
childInfo: []
|
childInfo: [],
|
||||||
|
workDayLength: currentTeam.workDayLength,
|
||||||
|
defaultTimeReportDay: currentTeam.defaultTimeReportDay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
let currentTeam: Team | undefined
|
let currentTeam: Team | undefined
|
||||||
let issueStatuses: WithLookup<IssueStatus>[] | undefined
|
let issueStatuses: WithLookup<IssueStatus>[] | undefined
|
||||||
|
|
||||||
|
$: defaultTimeReportDay = object.defaultTimeReportDay
|
||||||
$: query.query(
|
$: query.query(
|
||||||
object._class,
|
object._class,
|
||||||
{ _id: object._id },
|
{ _id: object._id },
|
||||||
@ -140,7 +141,13 @@
|
|||||||
on:click={(event) => {
|
on:click={(event) => {
|
||||||
showPopup(
|
showPopup(
|
||||||
TimeSpendReportPopup,
|
TimeSpendReportPopup,
|
||||||
{ issueId: object._id, issueClass: object._class, space: object.space, assignee: object.assignee },
|
{
|
||||||
|
issueId: object._id,
|
||||||
|
issueClass: object._class,
|
||||||
|
space: object.space,
|
||||||
|
assignee: object.assignee,
|
||||||
|
defaultTimeReportDay
|
||||||
|
},
|
||||||
eventToHTMLElement(event)
|
eventToHTMLElement(event)
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
<!--
|
|
||||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
|
||||||
// Copyright © 2021 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">
|
|
||||||
export let value: number
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<span class="lines-limit-2 select-text">{value}d</span>
|
|
@ -16,12 +16,13 @@
|
|||||||
import { AttachedData } from '@hcengineering/core'
|
import { AttachedData } from '@hcengineering/core'
|
||||||
|
|
||||||
import { Issue } from '@hcengineering/tracker'
|
import { Issue } from '@hcengineering/tracker'
|
||||||
import { floorFractionDigits, Label } from '@hcengineering/ui'
|
import { floorFractionDigits } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
|
||||||
import EstimationProgressCircle from './EstimationProgressCircle.svelte'
|
import EstimationProgressCircle from './EstimationProgressCircle.svelte'
|
||||||
|
import TimePresenter from './TimePresenter.svelte'
|
||||||
|
|
||||||
export let value: Issue | AttachedData<Issue>
|
export let value: Issue | AttachedData<Issue>
|
||||||
|
|
||||||
|
$: workDayLength = value.workDayLength
|
||||||
$: childReportTime = floorFractionDigits(
|
$: childReportTime = floorFractionDigits(
|
||||||
value.reportedTime + (value.childInfo ?? []).map((it) => it.reportedTime).reduce((a, b) => a + b, 0),
|
value.reportedTime + (value.childInfo ?? []).map((it) => it.reportedTime).reduce((a, b) => a + b, 0),
|
||||||
3
|
3
|
||||||
@ -43,21 +44,18 @@
|
|||||||
{@const reportDiff = floorFractionDigits(rchildReportTime - value.reportedTime, 3)}
|
{@const reportDiff = floorFractionDigits(rchildReportTime - value.reportedTime, 3)}
|
||||||
{#if reportDiff !== 0 && value.reportedTime !== 0}
|
{#if reportDiff !== 0 && value.reportedTime !== 0}
|
||||||
<div class="flex flex-nowrap mr-1" class:showError={reportDiff > 0}>
|
<div class="flex flex-nowrap mr-1" class:showError={reportDiff > 0}>
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: rchildReportTime }} />
|
<TimePresenter value={rchildReportTime} {workDayLength} />
|
||||||
</div>
|
</div>
|
||||||
<div class="romColor">
|
<div class="romColor">
|
||||||
(<Label
|
(<TimePresenter value={value.reportedTime} {workDayLength} />)
|
||||||
label={tracker.string.TimeSpendValue}
|
|
||||||
params={{ value: floorFractionDigits(value.reportedTime, 3) }}
|
|
||||||
/>)
|
|
||||||
</div>
|
</div>
|
||||||
{:else if value.reportedTime === 0}
|
{:else if value.reportedTime === 0}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: childReportTime }} />
|
<TimePresenter value={childReportTime} {workDayLength} />
|
||||||
{:else}
|
{:else}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value.reportedTime, 3) }} />
|
<TimePresenter value={value.reportedTime} {workDayLength} />
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value.reportedTime, 3) }} />
|
<TimePresenter value={value.reportedTime} {workDayLength} />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="p-1">/</div>
|
<div class="p-1">/</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -66,21 +64,18 @@
|
|||||||
{@const estimationDiff = childEstTime - Math.round(value.estimation)}
|
{@const estimationDiff = childEstTime - Math.round(value.estimation)}
|
||||||
{#if estimationDiff !== 0}
|
{#if estimationDiff !== 0}
|
||||||
<div class="flex flex-nowrap mr-1" class:showWarning={estimationDiff !== 0}>
|
<div class="flex flex-nowrap mr-1" class:showWarning={estimationDiff !== 0}>
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: childEstTime }} />
|
<TimePresenter value={childEstTime} {workDayLength} />
|
||||||
</div>
|
</div>
|
||||||
{#if value.estimation !== 0}
|
{#if value.estimation !== 0}
|
||||||
<div class="romColor">
|
<div class="romColor">
|
||||||
(<Label
|
(<TimePresenter value={value.estimation} {workDayLength} />)
|
||||||
label={tracker.string.TimeSpendValue}
|
|
||||||
params={{ value: floorFractionDigits(value.estimation, 3) }}
|
|
||||||
/>)
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value.estimation, 3) }} />
|
<TimePresenter value={value.estimation} {workDayLength} />
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value.estimation, 3) }} />
|
<TimePresenter value={value.estimation} {workDayLength} />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
import { ActionIcon, eventToHTMLElement, floorFractionDigits, IconAdd, Label, showPopup } from '@hcengineering/ui'
|
import { ActionIcon, eventToHTMLElement, floorFractionDigits, IconAdd, Label, showPopup } from '@hcengineering/ui'
|
||||||
import ReportsPopup from './ReportsPopup.svelte'
|
import ReportsPopup from './ReportsPopup.svelte'
|
||||||
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
||||||
|
import TimePresenter from './TimePresenter.svelte'
|
||||||
|
|
||||||
// export let label: IntlString
|
// export let label: IntlString
|
||||||
export let placeholder: IntlString
|
export let placeholder: IntlString
|
||||||
@ -26,10 +27,19 @@
|
|||||||
export let value: number
|
export let value: number
|
||||||
export let kind: 'no-border' | 'link' = 'no-border'
|
export let kind: 'no-border' | 'link' = 'no-border'
|
||||||
|
|
||||||
|
$: defaultTimeReportDay = object.defaultTimeReportDay
|
||||||
|
$: workDayLength = object.workDayLength
|
||||||
|
|
||||||
function addTimeReport (event: MouseEvent): void {
|
function addTimeReport (event: MouseEvent): void {
|
||||||
showPopup(
|
showPopup(
|
||||||
TimeSpendReportPopup,
|
TimeSpendReportPopup,
|
||||||
{ issueId: object._id, issueClass: object._class, space: object.space, assignee: object.assignee },
|
{
|
||||||
|
issueId: object._id,
|
||||||
|
defaultTimeReportDay,
|
||||||
|
issueClass: object._class,
|
||||||
|
space: object.space,
|
||||||
|
assignee: object.assignee
|
||||||
|
},
|
||||||
eventToHTMLElement(event)
|
eventToHTMLElement(event)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -46,9 +56,9 @@
|
|||||||
<div id="ReportedTimeEditor" class="link-container flex-between" on:click={showReports}>
|
<div id="ReportedTimeEditor" class="link-container flex-between" on:click={showReports}>
|
||||||
{#if value !== undefined}
|
{#if value !== undefined}
|
||||||
<span class="overflow-label">
|
<span class="overflow-label">
|
||||||
{floorFractionDigits(value, 3)}
|
<TimePresenter {value} {workDayLength} />
|
||||||
{#if childTime !== 0}
|
{#if childTime !== 0}
|
||||||
/ {childTime}
|
/ <TimePresenter value={childTime} {workDayLength} />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
@ -60,9 +70,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else if value !== undefined}
|
{:else if value !== undefined}
|
||||||
<span class="overflow-label">
|
<span class="overflow-label">
|
||||||
{floorFractionDigits(value, 3)}
|
<TimePresenter {value} {workDayLength} />
|
||||||
{#if childTime !== 0}
|
{#if childTime !== 0}
|
||||||
/ {childTime}
|
/ <TimePresenter value={childTime} {workDayLength} />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
||||||
export let issue: Issue
|
export let issue: Issue
|
||||||
|
|
||||||
|
$: defaultTimeReportDay = issue.defaultTimeReportDay
|
||||||
|
|
||||||
export function canClose (): boolean {
|
export function canClose (): boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -37,7 +39,13 @@
|
|||||||
function addReport (event: MouseEvent): void {
|
function addReport (event: MouseEvent): void {
|
||||||
showPopup(
|
showPopup(
|
||||||
TimeSpendReportPopup,
|
TimeSpendReportPopup,
|
||||||
{ issueId: issue._id, issueClass: issue._class, space: issue.space, assignee: issue.assignee },
|
{
|
||||||
|
issueId: issue._id,
|
||||||
|
issueClass: issue._class,
|
||||||
|
space: issue.space,
|
||||||
|
assignee: issue.assignee,
|
||||||
|
defaultTimeReportDay
|
||||||
|
},
|
||||||
eventToHTMLElement(event)
|
eventToHTMLElement(event)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
<!--
|
||||||
|
// 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 { WorkDayLength } from '@hcengineering/tracker'
|
||||||
|
import { floorFractionDigits, Label, tooltip } from '@hcengineering/ui'
|
||||||
|
import tracker from '../../../plugin'
|
||||||
|
|
||||||
|
export let id: string | undefined = undefined
|
||||||
|
export let kind: 'link' | undefined = undefined
|
||||||
|
export let workDayLength: WorkDayLength = WorkDayLength.EIGHT_HOURS
|
||||||
|
export let value: number
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
{id}
|
||||||
|
class:link={kind === 'link'}
|
||||||
|
on:click
|
||||||
|
use:tooltip={{
|
||||||
|
component: Label,
|
||||||
|
props: { label: tracker.string.TimeSpendHours, params: { value: floorFractionDigits(value * workDayLength, 2) } }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value, 3) }} />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.link {
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: var(--content-color);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--caption-color);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -13,34 +13,32 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { TimeReportDayType } from '@hcengineering/tracker'
|
||||||
import { DropdownIntlItem, DropdownLabelsIntl } from '@hcengineering/ui'
|
import { DropdownIntlItem, DropdownLabelsIntl } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import { WorkDaysType } from '../../../types'
|
import TimeReportDayIcon from './TimeReportDayIcon.svelte'
|
||||||
import { getWorkDate, getWorkDayType } from '../../../utils'
|
|
||||||
import WorkDaysIcon from './WorkDaysIcon.svelte'
|
|
||||||
|
|
||||||
export let dateTimestamp: number
|
export let label = tracker.string.TimeReportDayTypeLabel
|
||||||
|
export let selected: TimeReportDayType | undefined
|
||||||
|
|
||||||
const workDaysDropdownItems: DropdownIntlItem[] = [
|
const workDaysDropdownItems: DropdownIntlItem[] = [
|
||||||
{
|
{
|
||||||
id: WorkDaysType.CURRENT,
|
id: TimeReportDayType.CurrentWorkDay,
|
||||||
label: tracker.string.WorkDayCurrent
|
label: tracker.string.CurrentWorkDay
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: WorkDaysType.PREVIOUS,
|
id: TimeReportDayType.PreviousWorkDay,
|
||||||
label: tracker.string.WorkDayPrevious
|
label: tracker.string.PreviousWorkDay
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
$: selectedWorkDayType = dateTimestamp ? getWorkDayType(dateTimestamp) : undefined
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DropdownLabelsIntl
|
<DropdownLabelsIntl
|
||||||
kind="link-bordered"
|
kind="link-bordered"
|
||||||
icon={WorkDaysIcon}
|
icon={TimeReportDayIcon}
|
||||||
shouldUpdateUndefined={false}
|
shouldUpdateUndefined={false}
|
||||||
label={tracker.string.WorkDayLabel}
|
{label}
|
||||||
items={workDaysDropdownItems}
|
items={workDaysDropdownItems}
|
||||||
bind:selected={selectedWorkDayType}
|
bind:selected
|
||||||
on:selected={({ detail }) => (dateTimestamp = getWorkDate(detail))}
|
on:selected
|
||||||
/>
|
/>
|
@ -13,75 +13,40 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import contact, { Employee } from '@hcengineering/contact'
|
|
||||||
import { WithLookup } from '@hcengineering/core'
|
import { WithLookup } from '@hcengineering/core'
|
||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import type { TimeSpendReport } from '@hcengineering/tracker'
|
import { Issue, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import { eventToHTMLElement, floorFractionDigits, Label, showPopup, tooltip } from '@hcengineering/ui'
|
import { eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||||
import view, { AttributeModel } from '@hcengineering/view'
|
import TimePresenter from './TimePresenter.svelte'
|
||||||
import { getObjectPresenter } from '@hcengineering/view-resources'
|
|
||||||
import tracker from '../../../plugin'
|
|
||||||
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
||||||
|
|
||||||
export let value: WithLookup<TimeSpendReport>
|
export let value: WithLookup<TimeSpendReport>
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
let presenter: AttributeModel
|
|
||||||
|
|
||||||
getObjectPresenter(client, contact.class.Employee, { key: '' }).then((p) => {
|
$: issue = value.$lookup?.attachedTo
|
||||||
presenter = p
|
$: if (!issue) {
|
||||||
})
|
client.findOne(value.attachedToClass, { _id: value.attachedTo }).then((r) => {
|
||||||
|
issue = r as Issue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$: workDayLength = issue?.workDayLength
|
||||||
|
$: defaultTimeReportDay = issue?.defaultTimeReportDay
|
||||||
|
|
||||||
function editSpendReport (event: MouseEvent): void {
|
function editSpendReport (event: MouseEvent): void {
|
||||||
showPopup(
|
showPopup(
|
||||||
TimeSpendReportPopup,
|
TimeSpendReportPopup,
|
||||||
{ issue: value.attachedTo, issueClass: value.attachedToClass, value, assignee: value.employee },
|
{
|
||||||
|
issue: value.attachedTo,
|
||||||
|
issueClass: value.attachedToClass,
|
||||||
|
value,
|
||||||
|
assignee: value.employee,
|
||||||
|
defaultTimeReportDay
|
||||||
|
},
|
||||||
eventToHTMLElement(event)
|
eventToHTMLElement(event)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let employee: Employee | undefined | null = value.$lookup?.employee ?? null
|
|
||||||
$: if (employee === undefined) {
|
|
||||||
client.findOne(value.attachedToClass, { _id: value.attachedTo }).then((r) => {
|
|
||||||
employee = r as Employee
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if value && value.value}
|
{#if value && value.value}
|
||||||
<span
|
<TimePresenter id="TimeSpendReportValue" kind="link" value={value.value} {workDayLength} on:click={editSpendReport} />
|
||||||
id="TimeSpendReportValue"
|
|
||||||
class="issuePresenterRoot flex-row-center"
|
|
||||||
on:click={editSpendReport}
|
|
||||||
use:tooltip={value.employee
|
|
||||||
? {
|
|
||||||
label: tracker.string.TimeSpendReport,
|
|
||||||
component: view.component.ObjectPresenter,
|
|
||||||
props: {
|
|
||||||
objectId: value.employee,
|
|
||||||
_class: contact.class.Employee,
|
|
||||||
value: value.$lookup?.employee
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: undefined}
|
|
||||||
>
|
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value.value, 3) }} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.issuePresenterRoot {
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
color: var(--content-color);
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--caption-color);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
&:active {
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
import { AttachedData, Class, DocumentUpdate, Ref, Space } from '@hcengineering/core'
|
import { AttachedData, Class, DocumentUpdate, Ref, Space } from '@hcengineering/core'
|
||||||
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, TimeSpendReport } from '@hcengineering/tracker'
|
import { Issue, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import { DatePresenter, EditBox } from '@hcengineering/ui'
|
import { DatePresenter, EditBox } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import { getWorkDate, WorkDaysType } from '../../../utils'
|
import { getTimeReportDate, getTimeReportDayType } from '../../../utils'
|
||||||
import WorkDaysDropdown from './WorkDaysDropdown.svelte'
|
import TimeReportDayDropdown from './TimeReportDayDropdown.svelte'
|
||||||
|
|
||||||
export let issueId: Ref<Issue>
|
export let issueId: Ref<Issue>
|
||||||
export let issueClass: Ref<Class<Issue>>
|
export let issueClass: Ref<Class<Issue>>
|
||||||
@ -30,17 +30,21 @@
|
|||||||
|
|
||||||
export let value: TimeSpendReport | undefined
|
export let value: TimeSpendReport | undefined
|
||||||
export let placeholder: IntlString = tracker.string.TimeSpendReportValue
|
export let placeholder: IntlString = tracker.string.TimeSpendReportValue
|
||||||
|
export let defaultTimeReportDay = TimeReportDayType.PreviousWorkDay
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
date: value?.date ?? getTimeReportDate(defaultTimeReportDay),
|
||||||
|
description: value?.description ?? '',
|
||||||
|
value: value?.value,
|
||||||
|
employee: value?.employee ?? assignee ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectedTimeReportDay = getTimeReportDayType(data.date)
|
||||||
|
|
||||||
export function canClose (): boolean {
|
export function canClose (): boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
|
||||||
date: value?.date ?? getWorkDate(WorkDaysType.PREVIOUS),
|
|
||||||
description: value?.description ?? '',
|
|
||||||
value: value?.value,
|
|
||||||
employee: value?.employee ?? assignee ?? null
|
|
||||||
}
|
|
||||||
async function create (): Promise<void> {
|
async function create (): Promise<void> {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
getClient().addCollection(
|
getClient().addCollection(
|
||||||
@ -88,8 +92,16 @@
|
|||||||
bind:value={data.employee}
|
bind:value={data.employee}
|
||||||
showNavigate={false}
|
showNavigate={false}
|
||||||
/>
|
/>
|
||||||
<WorkDaysDropdown bind:dateTimestamp={data.date} />
|
<TimeReportDayDropdown
|
||||||
<DatePresenter kind={'link'} bind:value={data.date} editable />
|
bind:selected={selectedTimeReportDay}
|
||||||
|
on:selected={({ detail }) => (data.date = getTimeReportDate(detail))}
|
||||||
|
/>
|
||||||
|
<DatePresenter
|
||||||
|
kind={'link'}
|
||||||
|
bind:value={data.date}
|
||||||
|
editable
|
||||||
|
on:change={({ detail }) => (selectedTimeReportDay = getTimeReportDayType(detail))}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<EditBox bind:value={data.description} placeholder={tracker.string.TimeSpendReportDescription} kind={'editbox'} />
|
<EditBox bind:value={data.description} placeholder={tracker.string.TimeSpendReportDescription} kind={'editbox'} />
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import { Issue, Team, TimeSpendReport } from '@hcengineering/tracker'
|
import { Issue, Team, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import { floorFractionDigits, Label, Scroller, Spinner } from '@hcengineering/ui'
|
import { floorFractionDigits, Label, Scroller, Spinner } from '@hcengineering/ui'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
|
import TimePresenter from './TimePresenter.svelte'
|
||||||
import TimeSpendReportsList from './TimeSpendReportsList.svelte'
|
import TimeSpendReportsList from './TimeSpendReportsList.svelte'
|
||||||
|
|
||||||
export let issue: Issue
|
export let issue: Issue
|
||||||
@ -28,6 +29,7 @@
|
|||||||
|
|
||||||
let reports: TimeSpendReport[] | undefined
|
let reports: TimeSpendReport[] | undefined
|
||||||
|
|
||||||
|
$: workDayLength = issue.workDayLength
|
||||||
$: subIssuesQuery.query(tracker.class.TimeSpendReport, query, async (result) => (reports = result), {
|
$: subIssuesQuery.query(tracker.class.TimeSpendReport, query, async (result) => (reports = result), {
|
||||||
sort: { modifiedOn: SortingOrder.Descending },
|
sort: { modifiedOn: SortingOrder.Descending },
|
||||||
lookup: {
|
lookup: {
|
||||||
@ -40,8 +42,10 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if reports}
|
{#if reports}
|
||||||
<Label label={tracker.string.ReportedTime} />: {reportedTime}
|
<span class="overflow-label flex-nowrap">
|
||||||
<Label label={tracker.string.TimeSpendReports} />: {total}
|
<Label label={tracker.string.ReportedTime} />: <TimePresenter value={reportedTime} {workDayLength} />
|
||||||
|
<Label label={tracker.string.TimeSpendReports} />: <TimePresenter value={total} {workDayLength} />
|
||||||
|
</span>
|
||||||
<div class="h-50">
|
<div class="h-50">
|
||||||
<Scroller>
|
<Scroller>
|
||||||
<TimeSpendReportsList {reports} {teams} />
|
<TimeSpendReportsList {reports} {teams} />
|
||||||
|
@ -16,19 +16,13 @@
|
|||||||
import contact from '@hcengineering/contact'
|
import contact from '@hcengineering/contact'
|
||||||
import { Doc, Ref, Space, WithLookup } from '@hcengineering/core'
|
import { Doc, Ref, Space, WithLookup } from '@hcengineering/core'
|
||||||
import UserBox from '@hcengineering/presentation/src/components/UserBox.svelte'
|
import UserBox from '@hcengineering/presentation/src/components/UserBox.svelte'
|
||||||
import { Team, TimeSpendReport } from '@hcengineering/tracker'
|
import { Team, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker'
|
||||||
import {
|
import { eventToHTMLElement, getEventPositionElement, ListView, showPopup } from '@hcengineering/ui'
|
||||||
eventToHTMLElement,
|
|
||||||
floorFractionDigits,
|
|
||||||
getEventPositionElement,
|
|
||||||
ListView,
|
|
||||||
showPopup
|
|
||||||
} 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'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import EstimationPresenter from './EstimationPresenter.svelte'
|
import TimePresenter from './TimePresenter.svelte'
|
||||||
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
import TimeSpendReportPopup from './TimeSpendReportPopup.svelte'
|
||||||
|
|
||||||
export let reports: WithLookup<TimeSpendReport>[]
|
export let reports: WithLookup<TimeSpendReport>[]
|
||||||
@ -52,10 +46,20 @@
|
|||||||
}
|
}
|
||||||
const toTeamId = (ref: Ref<Space>) => ref as Ref<Team>
|
const toTeamId = (ref: Ref<Space>) => ref as Ref<Team>
|
||||||
|
|
||||||
function editSpendReport (event: MouseEvent, value: TimeSpendReport): void {
|
function editSpendReport (
|
||||||
|
event: MouseEvent,
|
||||||
|
value: TimeSpendReport,
|
||||||
|
defaultTimeReportDay: TimeReportDayType | undefined
|
||||||
|
): void {
|
||||||
showPopup(
|
showPopup(
|
||||||
TimeSpendReportPopup,
|
TimeSpendReportPopup,
|
||||||
{ issue: value.attachedTo, issueClass: value.attachedToClass, value, assignee: value.employee },
|
{
|
||||||
|
issue: value.attachedTo,
|
||||||
|
issueClass: value.attachedToClass,
|
||||||
|
value,
|
||||||
|
assignee: value.employee,
|
||||||
|
defaultTimeReportDay
|
||||||
|
},
|
||||||
eventToHTMLElement(event)
|
eventToHTMLElement(event)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -75,7 +79,7 @@
|
|||||||
on:focus={() => {
|
on:focus={() => {
|
||||||
listProvider.updateFocus(report)
|
listProvider.updateFocus(report)
|
||||||
}}
|
}}
|
||||||
on:click={(evt) => editSpendReport(evt, report)}
|
on:click={(evt) => editSpendReport(evt, report, currentTeam?.defaultTimeReportDay)}
|
||||||
>
|
>
|
||||||
<div class="flex-row-center clear-mins gap-2 p-2">
|
<div class="flex-row-center clear-mins gap-2 p-2">
|
||||||
<span class="issuePresenter">
|
<span class="issuePresenter">
|
||||||
@ -104,7 +108,7 @@
|
|||||||
readonly
|
readonly
|
||||||
showNavigate={false}
|
showNavigate={false}
|
||||||
/>
|
/>
|
||||||
<EstimationPresenter value={floorFractionDigits(report.value, 3)} />
|
<TimePresenter value={report.value} workDayLength={currentTeam?.workDayLength} />
|
||||||
<DatePresenter value={report.date} />
|
<DatePresenter value={report.date} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
import { Ref, WithLookup } from '@hcengineering/core'
|
import { Ref, WithLookup } from '@hcengineering/core'
|
||||||
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, Team } from '@hcengineering/tracker'
|
||||||
import { ButtonKind, ButtonSize, ButtonShape, floorFractionDigits } from '@hcengineering/ui'
|
import { ButtonKind, ButtonSize, ButtonShape, floorFractionDigits } from '@hcengineering/ui'
|
||||||
import { Label, deviceOptionsStore as deviceInfo } 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'
|
||||||
@ -24,6 +24,7 @@
|
|||||||
import tracker from '../../plugin'
|
import tracker from '../../plugin'
|
||||||
import { getDayOfSprint } from '../../utils'
|
import { getDayOfSprint } from '../../utils'
|
||||||
import EstimationProgressCircle from '../issues/timereport/EstimationProgressCircle.svelte'
|
import EstimationProgressCircle from '../issues/timereport/EstimationProgressCircle.svelte'
|
||||||
|
import TimePresenter from '../issues/timereport/TimePresenter.svelte'
|
||||||
import SprintSelector from './SprintSelector.svelte'
|
import SprintSelector from './SprintSelector.svelte'
|
||||||
|
|
||||||
export let value: Issue | IssueTemplate
|
export let value: Issue | IssueTemplate
|
||||||
@ -42,6 +43,13 @@
|
|||||||
export let enlargedText: boolean = false
|
export let enlargedText: boolean = false
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
const spaceQuery = createQuery()
|
||||||
|
|
||||||
|
let currentTeam: Team | undefined
|
||||||
|
$: spaceQuery.query(tracker.class.Team, { _id: value.space }, (res) => {
|
||||||
|
currentTeam = res.shift()
|
||||||
|
})
|
||||||
|
$: workDayLength = currentTeam?.workDayLength
|
||||||
|
|
||||||
const handleSprintIdChanged = async (newSprintId: Ref<Sprint> | null | undefined) => {
|
const handleSprintIdChanged = async (newSprintId: Ref<Sprint> | null | undefined) => {
|
||||||
if (!isEditable || newSprintId === undefined || value.sprint === newSprintId) {
|
if (!isEditable || newSprintId === undefined || value.sprint === newSprintId) {
|
||||||
@ -157,23 +165,21 @@
|
|||||||
<div class="flex-row-center" class:minus-margin-space={kind === 'list-header'} class:text-sm={twoRows}>
|
<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()}
|
||||||
|
{@const sprintDaysFrom =
|
||||||
|
now < sprint.startDate
|
||||||
|
? 0
|
||||||
|
: now > sprint.targetDate
|
||||||
|
? getDayOfSprint(sprint.startDate, sprint.targetDate)
|
||||||
|
: getDayOfSprint(sprint.startDate, now)}
|
||||||
|
{@const sprintDaysTo = getDayOfSprint(sprint.startDate, sprint.targetDate)}
|
||||||
<DatePresenter value={sprint.startDate} kind={'transparent'} />
|
<DatePresenter value={sprint.startDate} kind={'transparent'} />
|
||||||
<span class="p-1"> / </span>
|
<span class="p-1"> / </span>
|
||||||
<DatePresenter value={sprint.targetDate} kind={'transparent'} />
|
<DatePresenter value={sprint.targetDate} kind={'transparent'} />
|
||||||
<div class="w-2 min-w-2" />
|
<div class="w-2 min-w-2" />
|
||||||
<!-- Active sprint in time -->
|
<!-- Active sprint in time -->
|
||||||
<Label
|
<TimePresenter value={sprintDaysFrom} {workDayLength} />
|
||||||
label={tracker.string.SprintPassed}
|
/
|
||||||
params={{
|
<TimePresenter value={sprintDaysTo} {workDayLength} />
|
||||||
from:
|
|
||||||
now < sprint.startDate
|
|
||||||
? 0
|
|
||||||
: now > sprint.targetDate
|
|
||||||
? getDayOfSprint(sprint.startDate, sprint.targetDate)
|
|
||||||
: getDayOfSprint(sprint.startDate, now),
|
|
||||||
to: getDayOfSprint(sprint.startDate, sprint.targetDate)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if issues}
|
{#if issues}
|
||||||
<!-- <Label label={tracker.string.SprintDay} value={}/> -->
|
<!-- <Label label={tracker.string.SprintDay} value={}/> -->
|
||||||
@ -186,10 +192,10 @@
|
|||||||
<EstimationProgressCircle value={totalReported} max={totalEstimation} />
|
<EstimationProgressCircle value={totalReported} max={totalEstimation} />
|
||||||
<div class="w-2 min-w-2" />
|
<div class="w-2 min-w-2" />
|
||||||
{#if totalReported > 0}
|
{#if totalReported > 0}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: totalReported }} />
|
<TimePresenter value={totalReported} {workDayLength} />
|
||||||
/
|
/
|
||||||
{/if}
|
{/if}
|
||||||
<Label label={tracker.string.TimeSpendValue} params={{ value: totalEstimation }} />
|
<TimePresenter value={totalEstimation} {workDayLength} />
|
||||||
{#if sprint?.capacity}
|
{#if sprint?.capacity}
|
||||||
<Label label={tracker.string.CapacityValue} params={{ value: sprint?.capacity }} />
|
<Label label={tracker.string.CapacityValue} params={{ value: sprint?.capacity }} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,25 +14,56 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { Button, EditBox, eventToHTMLElement, Label, showPopup, ToggleWithLabel } from '@hcengineering/ui'
|
import {
|
||||||
import { getClient, SpaceCreateCard } from '@hcengineering/presentation'
|
Button,
|
||||||
|
DropdownIntlItem,
|
||||||
|
DropdownLabelsIntl,
|
||||||
|
EditBox,
|
||||||
|
eventToHTMLElement,
|
||||||
|
Label,
|
||||||
|
showPopup,
|
||||||
|
ToggleWithLabel
|
||||||
|
} from '@hcengineering/ui'
|
||||||
|
import presentation, { Card, getClient } from '@hcengineering/presentation'
|
||||||
import core, { getCurrentAccount, Ref } from '@hcengineering/core'
|
import core, { getCurrentAccount, Ref } from '@hcengineering/core'
|
||||||
import { IssueStatus } from '@hcengineering/tracker'
|
import { IssueStatus, Team, TimeReportDayType, WorkDayLength } from '@hcengineering/tracker'
|
||||||
import { StyledTextBox } from '@hcengineering/text-editor'
|
import { StyledTextBox } from '@hcengineering/text-editor'
|
||||||
import { Asset } from '@hcengineering/platform'
|
import { Asset } from '@hcengineering/platform'
|
||||||
import tracker from '../../plugin'
|
import tracker from '../../plugin'
|
||||||
import TeamIconChooser from './TeamIconChooser.svelte'
|
import TeamIconChooser from './TeamIconChooser.svelte'
|
||||||
|
import TimeReportDayDropdown from '../issues/timereport/TimeReportDayDropdown.svelte'
|
||||||
|
|
||||||
let name: string = ''
|
export let team: Team | undefined = undefined
|
||||||
let description: string = ''
|
|
||||||
let isPrivate: boolean = false
|
let name: string = team?.name ?? ''
|
||||||
let icon: Asset | undefined = undefined
|
let description: string = team?.description ?? ''
|
||||||
|
let isPrivate: boolean = team?.private ?? false
|
||||||
|
let icon: Asset | undefined = team?.icon ?? undefined
|
||||||
|
let selectedWorkDayType: TimeReportDayType | undefined =
|
||||||
|
team?.defaultTimeReportDay ?? TimeReportDayType.PreviousWorkDay
|
||||||
|
let selectedWorkDayLength: WorkDayLength | undefined = team?.workDayLength ?? WorkDayLength.EIGHT_HOURS
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
const workDayLengthItems: DropdownIntlItem[] = [
|
||||||
|
{
|
||||||
|
id: WorkDayLength.SEVEN_HOURS,
|
||||||
|
label: tracker.string.SevenHoursLength
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: WorkDayLength.EIGHT_HOURS,
|
||||||
|
label: tracker.string.EightHoursLength
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
async function createTeam () {
|
$: isNew = !team
|
||||||
await client.createDoc(tracker.class.Team, core.space.Space, {
|
|
||||||
|
async function handleSave () {
|
||||||
|
isNew ? createTeam() : updateTeam()
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTeamData () {
|
||||||
|
return {
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
private: isPrivate,
|
private: isPrivate,
|
||||||
@ -42,8 +73,31 @@
|
|||||||
sequence: 0,
|
sequence: 0,
|
||||||
issueStatuses: 0,
|
issueStatuses: 0,
|
||||||
defaultIssueStatus: '' as Ref<IssueStatus>,
|
defaultIssueStatus: '' as Ref<IssueStatus>,
|
||||||
icon
|
icon,
|
||||||
})
|
defaultTimeReportDay: selectedWorkDayType ?? TimeReportDayType.PreviousWorkDay,
|
||||||
|
workDayLength: selectedWorkDayLength ?? WorkDayLength.EIGHT_HOURS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateTeam () {
|
||||||
|
const teamData = getTeamData()
|
||||||
|
// update team doc
|
||||||
|
await client.update(team!, teamData)
|
||||||
|
|
||||||
|
// update issues related to team
|
||||||
|
const issuesByTeam = await client.findAll(tracker.class.Issue, { space: team!._id })
|
||||||
|
await Promise.all(
|
||||||
|
issuesByTeam.map((issue) =>
|
||||||
|
client.update(issue, {
|
||||||
|
defaultTimeReportDay: teamData.defaultTimeReportDay,
|
||||||
|
workDayLength: teamData.workDayLength
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createTeam () {
|
||||||
|
await client.createDoc(tracker.class.Team, core.space.Space, getTeamData())
|
||||||
}
|
}
|
||||||
|
|
||||||
function chooseIcon (ev: MouseEvent) {
|
function chooseIcon (ev: MouseEvent) {
|
||||||
@ -55,10 +109,11 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SpaceCreateCard
|
<Card
|
||||||
label={tracker.string.NewTeam}
|
label={isNew ? tracker.string.NewTeam : tracker.string.EditTeam}
|
||||||
okAction={createTeam}
|
okLabel={isNew ? presentation.string.Create : presentation.string.Edit}
|
||||||
canSave={name.length > 0}
|
okAction={handleSave}
|
||||||
|
canSave={name.length > 0 && !!selectedWorkDayType && !!selectedWorkDayLength}
|
||||||
on:close={() => {
|
on:close={() => {
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
}}
|
}}
|
||||||
@ -81,4 +136,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<Button icon={icon ?? tracker.icon.Home} kind="no-border" size="medium" on:click={chooseIcon} />
|
<Button icon={icon ?? tracker.icon.Home} kind="no-border" size="medium" on:click={chooseIcon} />
|
||||||
</div>
|
</div>
|
||||||
</SpaceCreateCard>
|
|
||||||
|
<div class="flex-between">
|
||||||
|
<div class="caption">
|
||||||
|
<Label label={tracker.string.DefaultTimeReportDay} />
|
||||||
|
</div>
|
||||||
|
<TimeReportDayDropdown bind:selected={selectedWorkDayType} label={tracker.string.DefaultTimeReportDay} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-between">
|
||||||
|
<div class="caption">
|
||||||
|
<Label label={tracker.string.WorkDayLength} />
|
||||||
|
</div>
|
||||||
|
<DropdownLabelsIntl
|
||||||
|
kind="link-bordered"
|
||||||
|
label={tracker.string.WorkDayLength}
|
||||||
|
items={workDayLengthItems}
|
||||||
|
shouldUpdateUndefined={false}
|
||||||
|
bind:selected={selectedWorkDayLength}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
@ -164,6 +164,12 @@ async function editWorkflowStatuses (team: Team | undefined): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function editTeam (team: Team | undefined): Promise<void> {
|
||||||
|
if (team !== undefined) {
|
||||||
|
showPopup(CreateTeam, { team })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function moveAndDeleteSprint (client: TxOperations, oldSprint: Sprint, newSprint?: Sprint): Promise<void> {
|
async function moveAndDeleteSprint (client: TxOperations, oldSprint: Sprint, newSprint?: Sprint): Promise<void> {
|
||||||
const noSprintLabel = await translate(tracker.string.NoSprint, {})
|
const noSprintLabel = await translate(tracker.string.NoSprint, {})
|
||||||
|
|
||||||
@ -282,6 +288,7 @@ export default async (): Promise<Resources> => ({
|
|||||||
},
|
},
|
||||||
actionImpl: {
|
actionImpl: {
|
||||||
EditWorkflowStatuses: editWorkflowStatuses,
|
EditWorkflowStatuses: editWorkflowStatuses,
|
||||||
|
EditTeam: editTeam,
|
||||||
DeleteSprint: deleteSprint
|
DeleteSprint: deleteSprint
|
||||||
},
|
},
|
||||||
resolver: {
|
resolver: {
|
||||||
|
@ -90,6 +90,7 @@ export default mergeIds(trackerId, tracker, {
|
|||||||
DefaultIssueStatus: '' as IntlString,
|
DefaultIssueStatus: '' as IntlString,
|
||||||
IssueStatuses: '' as IntlString,
|
IssueStatuses: '' as IntlString,
|
||||||
EditWorkflowStatuses: '' as IntlString,
|
EditWorkflowStatuses: '' as IntlString,
|
||||||
|
EditTeam: '' as IntlString,
|
||||||
ManageWorkflowStatuses: '' as IntlString,
|
ManageWorkflowStatuses: '' as IntlString,
|
||||||
AddWorkflowStatus: '' as IntlString,
|
AddWorkflowStatus: '' as IntlString,
|
||||||
EditWorkflowStatus: '' as IntlString,
|
EditWorkflowStatus: '' as IntlString,
|
||||||
@ -248,6 +249,7 @@ export default mergeIds(trackerId, tracker, {
|
|||||||
TimeSpendReportValue: '' as IntlString,
|
TimeSpendReportValue: '' as IntlString,
|
||||||
TimeSpendReportDescription: '' as IntlString,
|
TimeSpendReportDescription: '' as IntlString,
|
||||||
TimeSpendValue: '' as IntlString,
|
TimeSpendValue: '' as IntlString,
|
||||||
|
TimeSpendHours: '' as IntlString,
|
||||||
SprintPassed: '' as IntlString,
|
SprintPassed: '' as IntlString,
|
||||||
|
|
||||||
ChildEstimation: '' as IntlString,
|
ChildEstimation: '' as IntlString,
|
||||||
@ -265,9 +267,14 @@ export default mergeIds(trackerId, tracker, {
|
|||||||
TemplateReplace: '' as IntlString,
|
TemplateReplace: '' as IntlString,
|
||||||
TemplateReplaceConfirm: '' as IntlString,
|
TemplateReplaceConfirm: '' as IntlString,
|
||||||
|
|
||||||
WorkDayCurrent: '' as IntlString,
|
CurrentWorkDay: '' as IntlString,
|
||||||
WorkDayPrevious: '' as IntlString,
|
PreviousWorkDay: '' as IntlString,
|
||||||
WorkDayLabel: '' as IntlString
|
TimeReportDayTypeLabel: '' as IntlString,
|
||||||
|
DefaultTimeReportDay: '' as IntlString,
|
||||||
|
|
||||||
|
WorkDayLength: '' as IntlString,
|
||||||
|
SevenHoursLength: '' as IntlString,
|
||||||
|
EightHoursLength: '' as IntlString
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
NopeComponent: '' as AnyComponent,
|
NopeComponent: '' as AnyComponent,
|
||||||
|
@ -104,8 +104,3 @@ export const issuesGroupBySorting: Record<IssuesGrouping, SortingQuery<Issue>> =
|
|||||||
[IssuesGrouping.Sprint]: { '$lookup.sprint.label': SortingOrder.Ascending },
|
[IssuesGrouping.Sprint]: { '$lookup.sprint.label': SortingOrder.Ascending },
|
||||||
[IssuesGrouping.NoGrouping]: {}
|
[IssuesGrouping.NoGrouping]: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum WorkDaysType {
|
|
||||||
CURRENT = 'current',
|
|
||||||
PREVIOUS = 'previous'
|
|
||||||
}
|
|
||||||
|
@ -27,7 +27,8 @@ import {
|
|||||||
ProjectStatus,
|
ProjectStatus,
|
||||||
Sprint,
|
Sprint,
|
||||||
SprintStatus,
|
SprintStatus,
|
||||||
Team
|
Team,
|
||||||
|
TimeReportDayType
|
||||||
} from '@hcengineering/tracker'
|
} from '@hcengineering/tracker'
|
||||||
import { ViewOptionModel } from '@hcengineering/view-resources'
|
import { ViewOptionModel } from '@hcengineering/view-resources'
|
||||||
import {
|
import {
|
||||||
@ -39,13 +40,7 @@ import {
|
|||||||
MILLISECONDS_IN_WEEK
|
MILLISECONDS_IN_WEEK
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import tracker from './plugin'
|
import tracker from './plugin'
|
||||||
import {
|
import { defaultPriorities, defaultProjectStatuses, defaultSprintStatuses, issuePriorities } from './types'
|
||||||
defaultPriorities,
|
|
||||||
defaultProjectStatuses,
|
|
||||||
defaultSprintStatuses,
|
|
||||||
issuePriorities,
|
|
||||||
WorkDaysType
|
|
||||||
} from './types'
|
|
||||||
|
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|
||||||
@ -649,13 +644,14 @@ export async function moveIssuesToAnotherSprint (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkDate (type: WorkDaysType): number {
|
export function getTimeReportDate (type: TimeReportDayType): number {
|
||||||
const date = new Date(Date.now())
|
const date = new Date(Date.now())
|
||||||
if (type === WorkDaysType.PREVIOUS) {
|
|
||||||
|
if (type === TimeReportDayType.PreviousWorkDay) {
|
||||||
date.setDate(date.getDate() - 1)
|
date.setDate(date.getDate() - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if currentDate is day off then set date to last working day
|
// if date is day off then set date to last working day
|
||||||
while (isWeekend(date)) {
|
while (isWeekend(date)) {
|
||||||
date.setDate(date.getDate() - 1)
|
date.setDate(date.getDate() - 1)
|
||||||
}
|
}
|
||||||
@ -663,14 +659,14 @@ export function getWorkDate (type: WorkDaysType): number {
|
|||||||
return date.valueOf()
|
return date.valueOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkDayType (timestamp: number): WorkDaysType | undefined {
|
export function getTimeReportDayType (timestamp: number): TimeReportDayType | undefined {
|
||||||
const date = new Date(timestamp)
|
const date = new Date(timestamp)
|
||||||
const currentWorkDate = new Date(getWorkDate(WorkDaysType.CURRENT))
|
const currentWorkDate = new Date(getTimeReportDate(TimeReportDayType.CurrentWorkDay))
|
||||||
const previousWorkDate = new Date(getWorkDate(WorkDaysType.PREVIOUS))
|
const previousWorkDate = new Date(getTimeReportDate(TimeReportDayType.PreviousWorkDay))
|
||||||
|
|
||||||
if (areDatesEqual(date, currentWorkDate)) {
|
if (areDatesEqual(date, currentWorkDate)) {
|
||||||
return WorkDaysType.CURRENT
|
return TimeReportDayType.CurrentWorkDay
|
||||||
} else if (areDatesEqual(date, previousWorkDate)) {
|
} else if (areDatesEqual(date, previousWorkDate)) {
|
||||||
return WorkDaysType.PREVIOUS
|
return TimeReportDayType.PreviousWorkDay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,24 @@ export interface Team extends Space {
|
|||||||
issueStatuses: number
|
issueStatuses: number
|
||||||
defaultIssueStatus: Ref<IssueStatus>
|
defaultIssueStatus: Ref<IssueStatus>
|
||||||
icon?: Asset
|
icon?: Asset
|
||||||
|
workDayLength: WorkDayLength
|
||||||
|
defaultTimeReportDay: TimeReportDayType
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export enum TimeReportDayType {
|
||||||
|
CurrentWorkDay = 'CurrentWorkDay',
|
||||||
|
PreviousWorkDay = 'PreviousWorkDay'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export enum WorkDayLength {
|
||||||
|
SEVEN_HOURS = 7,
|
||||||
|
EIGHT_HOURS = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,6 +193,9 @@ export interface Issue extends AttachedDoc {
|
|||||||
|
|
||||||
childInfo: IssueChildInfo[]
|
childInfo: IssueChildInfo[]
|
||||||
|
|
||||||
|
workDayLength: WorkDayLength
|
||||||
|
defaultTimeReportDay: TimeReportDayType
|
||||||
|
|
||||||
template?: {
|
template?: {
|
||||||
// A template issue is based on
|
// A template issue is based on
|
||||||
template: Ref<IssueTemplate>
|
template: Ref<IssueTemplate>
|
||||||
@ -465,6 +486,7 @@ export default plugin(trackerId, {
|
|||||||
Relations: '' as Ref<Action>,
|
Relations: '' as Ref<Action>,
|
||||||
NewSubIssue: '' as Ref<Action>,
|
NewSubIssue: '' as Ref<Action>,
|
||||||
EditWorkflowStatuses: '' as Ref<Action>,
|
EditWorkflowStatuses: '' as Ref<Action>,
|
||||||
|
EditTeam: '' as Ref<Action>,
|
||||||
SetSprint: '' as Ref<Action>
|
SetSprint: '' as Ref<Action>
|
||||||
},
|
},
|
||||||
team: {
|
team: {
|
||||||
|
Loading…
Reference in New Issue
Block a user