Skip to content
2 changes: 1 addition & 1 deletion common/scripts/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"0.7.422"
"0.7.423"
49 changes: 49 additions & 0 deletions models/tracker/src/__tests__/migration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright © 2026 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.
//

import { DOMAIN_TASK } from '@hcengineering/model-task'
import tracker from '@hcengineering/tracker'

import { DOMAIN_TRACKER } from '../types'
import { migrateAddStartDate } from '../migration'

describe('migrateAddStartDate', () => {
it('sets startDate=null on every Issue lacking the field (DOMAIN_TASK)', async () => {
const update = jest.fn().mockResolvedValue(undefined)
const client: any = { update }

await migrateAddStartDate(client)

expect(update).toHaveBeenCalledWith(
DOMAIN_TASK,
{ _class: tracker.class.Issue, startDate: { $exists: false } },
{ startDate: null }
)
})

it('sets startDate=null on every Milestone lacking the field (DOMAIN_TRACKER)', async () => {
const update = jest.fn().mockResolvedValue(undefined)
const client: any = { update }

await migrateAddStartDate(client)

expect(update).toHaveBeenCalledWith(
DOMAIN_TRACKER,
{ _class: tracker.class.Milestone, startDate: { $exists: false } },
{ startDate: null }
)
})

it('issues exactly two update calls (one per class)', async () => {
const update = jest.fn().mockResolvedValue(undefined)
const client: any = { update }

await migrateAddStartDate(client)

expect(update).toHaveBeenCalledTimes(2)
})
})
2 changes: 2 additions & 0 deletions models/tracker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
TClassicProjectTypeData,
TComponent,
TIssue,
TIssueRelation,
TIssueStatus,
TIssueTemplate,
TIssueTypeData,
Expand Down Expand Up @@ -441,6 +442,7 @@ export function createModel (builder: Builder): void {
TProject,
TComponent,
TIssue,
TIssueRelation,
TIssueTemplate,
TIssueStatus,
TTypeIssuePriority,
Expand Down
20 changes: 20 additions & 0 deletions models/tracker/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import tracker, {
} from '@hcengineering/tracker'

import { classicIssueTaskStatuses } from '.'
import { DOMAIN_TRACKER } from './types'

async function createDefaultProject (tx: TxOperations): Promise<void> {
const current = await tx.findOne(tracker.class.Project, {
Expand Down Expand Up @@ -170,6 +171,20 @@ async function migrateIdentifiers (client: MigrationClient): Promise<void> {
}
}

export async function migrateAddStartDate (client: MigrationClient): Promise<void> {
// Issues live in DOMAIN_TASK; Milestones live in DOMAIN_TRACKER.
await client.update(
DOMAIN_TASK,
{ _class: tracker.class.Issue, startDate: { $exists: false } },
{ startDate: null }
)
await client.update(
DOMAIN_TRACKER,
{ _class: tracker.class.Milestone, startDate: { $exists: false } },
{ startDate: null }
)
}

async function migrateDefaultStatuses (client: MigrationClient, logger: ModelLogger): Promise<void> {
const defaultTypeId = tracker.ids.ClassingProjectType
const typeDescriptor = tracker.descriptors.ProjectType
Expand Down Expand Up @@ -398,6 +413,11 @@ export const trackerOperation: MigrateOperation = {
state: 'migrateDefaultTypeMixins',
mode: 'upgrade',
func: migrateDefaultTypeMixins
},
{
state: 'gantt-add-startdate',
mode: 'upgrade',
func: migrateAddStartDate
}
])
},
Expand Down
31 changes: 31 additions & 0 deletions models/tracker/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ import time, { type ToDo } from '@hcengineering/time'
import {
type ProjectTargetPreference,
type Component,
type DependencyKind,
type Issue,
type IssueChildInfo,
type IssueParentInfo,
type IssuePriority,
type IssueRelation,
type IssueStatus,
type IssueTemplate,
type IssueTemplateChild,
Expand Down Expand Up @@ -233,6 +235,10 @@ export class TIssue extends TTask implements Issue {
@ReadOnly()
declare space: Ref<Project>

@Prop(TypeDate(DateRangeMode.DATETIME), tracker.string.IssueStartDate)
@Index(IndexKind.Indexed)
declare startDate: Timestamp | null

@Prop(TypeDate(DateRangeMode.DATETIME), tracker.string.DueDate)
declare dueDate: Timestamp | null

Expand Down Expand Up @@ -340,6 +346,28 @@ export class TTimeSpendReport extends TAttachedDoc implements TimeSpendReport {
@Prop(TypeString(), tracker.string.TimeSpendReportDescription)
description!: string
}

/**
* @public
*/
@Model(tracker.class.IssueRelation, core.class.AttachedDoc, DOMAIN_TRACKER)
@UX(tracker.string.GanttDependency, tracker.icon.Issue)
export class TIssueRelation extends TAttachedDoc implements IssueRelation {
@Prop(TypeRef(tracker.class.Issue), tracker.string.Issue)
declare attachedTo: Ref<Issue>

declare collection: 'relations'

@Prop(TypeRef(tracker.class.Issue), tracker.string.Issue)
@Index(IndexKind.Indexed)
target!: Ref<Issue>

@Prop(TypeString(), tracker.string.GanttDependency)
kind!: DependencyKind

@Prop(TypeNumber(), tracker.string.GanttLag)
lag!: number
}
/**
* @public
*/
Expand Down Expand Up @@ -389,6 +417,9 @@ export class TMilestone extends TDoc implements Milestone {
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
attachments?: number

@Prop(TypeDate(), tracker.string.StartDate)
startDate!: Timestamp | null

@Prop(TypeDate(), tracker.string.TargetDate)
targetDate!: Timestamp

Expand Down
8 changes: 7 additions & 1 deletion models/tracker/src/viewlets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ export function defineViewlets (builder: Builder): void {
viewOptions: milestoneOptions,
configOptions: {
strict: true,
hiddenKeys: ['targetDate', 'label', 'description']
hiddenKeys: ['startDate', 'targetDate', 'label', 'description']
},
config: [
{
Expand All @@ -672,6 +672,12 @@ export function defineViewlets (builder: Builder): void {
},
{ key: '', presenter: tracker.component.MilestonePresenter, props: { shouldUseMargin: true } },
{ key: '', displayProps: { grow: true } },
{
key: '',
label: tracker.string.StartDate,
presenter: tracker.component.MilestoneDatePresenter,
props: { field: 'startDate' }
},
{
key: '',
label: tracker.string.TargetDate,
Expand Down
1 change: 1 addition & 0 deletions packages/importer/src/importer/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ export class WorkspaceImporter {
rank,
comments: issue.comments?.length ?? 0,
subIssues: issue.subdocs.length,
startDate: null,
dueDate: null,
parents: parentsInfo,
remainingTime,
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@
"NoAssignee": "Bez přiřazení",
"LastUpdated": "Poslední aktualizace",
"DueDate": "Datum splnění",
"IssueStartDate": "Datum zahájení",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manuální",
"All": "Vše",
"PastWeek": "Minulý týden",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
"NoAssignee": "Nicht zugewiesen",
"LastUpdated": "Zuletzt aktualisiert",
"DueDate": "Fälligkeitsdatum",
"IssueStartDate": "Startdatum",
"GanttDependency": "Abhängigkeit",
"GanttLag": "Verzögerung",
"Manual": "Manuell",
"All": "Alle",
"PastWeek": "Letzte Woche",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
"NoAssignee": "No assignee",
"LastUpdated": "Last updated",
"DueDate": "Due date",
"IssueStartDate": "Start date",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manual",
"All": "All",
"PastWeek": "Past week",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "Sin asignar",
"LastUpdated": "Última actualización",
"DueDate": "Fecha de vencimiento",
"IssueStartDate": "Fecha de inicio",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manual",
"All": "Todos",
"PastWeek": "Semana pasada",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "Non assigné",
"LastUpdated": "Dernière mise à jour",
"DueDate": "Date d'échéance",
"IssueStartDate": "Date de début",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manuel",
"All": "Tous",
"PastWeek": "La semaine passée",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "Nessun assegnatario",
"LastUpdated": "Ultimo aggiornamento",
"DueDate": "Data di scadenza",
"IssueStartDate": "Data di inizio",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manuale",
"All": "Tutti",
"PastWeek": "Settimana scorsa",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "担当者なし",
"LastUpdated": "最終更新日",
"DueDate": "期日",
"IssueStartDate": "開始日",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "手動",
"All": "すべて",
"PastWeek": "先週",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "담당자 없음",
"LastUpdated": "최근 업데이트",
"DueDate": "마감일",
"IssueStartDate": "시작일",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "수동",
"All": "전체",
"PastWeek": "지난주",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/pt-br.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "Sem atribuição",
"LastUpdated": "Última atualização",
"DueDate": "Data de vencimento",
"IssueStartDate": "Data de início",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manual",
"All": "Todos",
"PastWeek": "Semana passada",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "Sem atribuição",
"LastUpdated": "Última atualização",
"DueDate": "Data de vencimento",
"IssueStartDate": "Data de início",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manual",
"All": "Todos",
"PastWeek": "Semana passada",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
"NoAssignee": "Нет исполнителя",
"LastUpdated": "Последнее обновление",
"DueDate": "Срок",
"IssueStartDate": "Дата начала",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Пользовательский",
"All": "Все",
"PastWeek": "Предыдущая неделя",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@
"NoAssignee": "Atanan yok",
"LastUpdated": "Son güncelleme",
"DueDate": "Bitiş tarihi",
"IssueStartDate": "Başlangıç tarihi",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "Manuel",
"All": "Tümü",
"PastWeek": "Geçen hafta",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-assets/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
"NoAssignee": "无受理人",
"LastUpdated": "最后更新",
"DueDate": "截止日期",
"IssueStartDate": "开始日期",
"GanttDependency": "Dependency",
"GanttLag": "Lag",
"Manual": "手动",
"All": "全部",
"PastWeek": "过去一周",
Expand Down
3 changes: 3 additions & 0 deletions plugins/tracker-resources/src/components/CreateIssue.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
priority: priority ?? IssuePriority.NoPriority,
space: _space as Ref<Project>,
component: component ?? $activeComponent ?? null,
startDate: null,
dueDate: null,
attachments: 0,
estimation: 0,
Expand Down Expand Up @@ -312,6 +313,7 @@
_id: generateId(),
space: _space as Ref<Project>,
subIssues: [],
startDate: null,
dueDate: null,
labels:
p.labels !== undefined
Expand Down Expand Up @@ -488,6 +490,7 @@
rank: '',
comments: 0,
subIssues: 0,
startDate: object.startDate,
dueDate: object.dueDate,
parents:
parentIssue != null
Expand Down
1 change: 1 addition & 0 deletions plugins/tracker-resources/src/components/SubIssues.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
rank: '',
comments: 0,
subIssues: 0,
startDate: subIssue.startDate ?? null,
dueDate: null,
parents,
reportedTime: 0,
Expand Down
Loading