UBER-174: Introduce createOn every there (#3222)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev
2023-05-20 00:37:22 +07:00
committed by GitHub
parent 0f62a3175e
commit c0bb68be9e
50 changed files with 159 additions and 317 deletions
+2 -4
View File
@@ -35,8 +35,7 @@ const object: AttachedData<Issue> = {
reportedTime: 0,
estimation: 0,
reports: 0,
childInfo: [],
createOn: Date.now()
childInfo: []
}
export interface IssueOptions {
@@ -98,8 +97,7 @@ async function genIssue (client: TxOperations, statuses: Ref<IssueStatus>[]): Pr
estimation: object.estimation,
reports: 0,
relations: [],
childInfo: [],
createOn: Date.now()
childInfo: []
}
await client.addCollection(
tracker.class.Issue,
+8 -10
View File
@@ -2,23 +2,23 @@ import contact, { Channel, Employee, EmployeeAccount, Person } from '@hcengineer
import core, {
AttachedData,
Data,
generateId,
MeasureContext,
MeasureMetricsContext,
metricsToString,
MixinUpdate,
Ref,
TxOperations,
WorkspaceId
WorkspaceId,
generateId,
metricsToString
} from '@hcengineering/core'
import { MinioService } from '@hcengineering/minio'
import recruit from '@hcengineering/model-recruit'
import { Applicant, Candidate, Vacancy } from '@hcengineering/recruit'
import { genRanks, State } from '@hcengineering/task'
import { State, genRanks } from '@hcengineering/task'
import faker from 'faker'
import jpeg, { BufferRet } from 'jpeg-js'
import { addAttachments, AttachmentOptions } from './attachments'
import { addComments, CommentOptions } from './comments'
import { AttachmentOptions, addAttachments } from './attachments'
import { CommentOptions, addComments } from './comments'
import { connect } from './connect'
import { createUpdateSpaceKanban } from './kanban'
import { findOrUpdate, findOrUpdateAttached } from './utils'
@@ -162,8 +162,7 @@ async function genApplicant (
doneState: null,
rank: rank as string,
startDate: null,
dueDate: null,
createOn: Date.now()
dueDate: null
}
// Update or create candidate
@@ -234,8 +233,7 @@ async function genCandidate (
const candidate: Data<Person> = {
name: fName + ',' + lName,
city: faker.address.city(),
avatar: imgId,
createOn: Date.now()
avatar: imgId
}
const candidateMixin: MixinUpdate<Person, Candidate> = {
-4
View File
@@ -91,10 +91,6 @@ export class TChunterMessage extends TAttachedDoc implements ChunterMessage {
@ReadOnly()
createBy!: Ref<Account>
@Prop(TypeTimestamp(), chunter.string.Create)
@ReadOnly()
createOn!: Timestamp
@Prop(TypeTimestamp(), chunter.string.Edit)
editedOn?: Timestamp
+1 -17
View File
@@ -14,7 +14,7 @@
//
import { Comment, Message, ThreadMessage } from '@hcengineering/chunter'
import core, { Doc, DOMAIN_TX, Ref, TxCreateDoc, TxOperations } from '@hcengineering/core'
import core, { DOMAIN_TX, Doc, Ref, TxCreateDoc, TxOperations } from '@hcengineering/core'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
import { DOMAIN_CHUNTER, DOMAIN_COMMENT } from './index'
import chunter from './plugin'
@@ -81,21 +81,6 @@ async function createBacklink (tx: TxOperations): Promise<void> {
}
}
export async function setCreate (client: TxOperations): Promise<void> {
const messages = (await client.findAll(chunter.class.Message, {}))
.filter((m) => m.createBy === undefined)
.map((m) => m._id)
if (messages.length === 0) return
const txes = await client.findAll(core.class.TxCreateDoc, { objectId: { $in: messages } })
const promises = txes.map(async (tx) => {
await client.updateDoc<Message>(chunter.class.Message, tx.objectSpace, tx.objectId as Ref<Message>, {
createBy: tx.modifiedBy,
createOn: tx.modifiedOn
})
})
await Promise.all(promises)
}
export async function migrateMessages (client: MigrationClient): Promise<void> {
const messages = await client.find(DOMAIN_CHUNTER, {
_class: chunter.class.Message,
@@ -188,6 +173,5 @@ export const chunterOperation: MigrateOperation = {
await createGeneral(tx)
await createRandom(tx)
await createBacklink(tx)
await setCreate(tx)
}
}
-5
View File
@@ -40,7 +40,6 @@ import {
Index,
Model,
Prop,
ReadOnly,
TypeDate,
TypeRef,
TypeString,
@@ -103,10 +102,6 @@ export class TContact extends TDoc implements Contact {
@Prop(TypeString(), contact.string.Location)
@Index(IndexKind.FullText)
city!: string
@Prop(TypeTimestamp(), contact.string.CreatedDate)
@ReadOnly()
createOn!: Timestamp
}
@Model(contact.class.Channel, core.class.AttachedDoc, DOMAIN_CHANNEL)
+3 -64
View File
@@ -1,10 +1,9 @@
//
import { Contact } from '@hcengineering/contact'
import { DOMAIN_TX, TxCreateDoc, TxOperations } from '@hcengineering/core'
import { TxOperations } from '@hcengineering/core'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
import core from '@hcengineering/model-core'
import contact, { DOMAIN_CONTACT } from './index'
import contact from './index'
async function createSpace (tx: TxOperations): Promise<void> {
const current = await tx.findOne(core.class.Space, {
@@ -43,64 +42,6 @@ async function createSpace (tx: TxOperations): Promise<void> {
}
}
let totalCreateOn = 0
async function setCreate (client: MigrationClient): Promise<void> {
while (true) {
const docs = await client.find<Contact>(
DOMAIN_CONTACT,
{
_class: {
$in: [contact.class.Contact, contact.class.Organization, contact.class.Person, contact.class.Employee]
},
createOn: { $exists: false }
},
{ limit: 500 }
)
if (docs.length === 0) {
break
}
totalCreateOn += docs.length
console.log('processing createOn migration', totalCreateOn)
const creates = await client.find<TxCreateDoc<Contact>>(DOMAIN_TX, {
objectId: { $in: docs.map((it) => it._id) },
_class: core.class.TxCreateDoc
})
for (const doc of docs) {
const tx = creates.find((it) => it.objectId === doc._id)
if (tx !== undefined) {
await client.update(
DOMAIN_CONTACT,
{
_id: doc._id
},
{
createOn: tx.modifiedOn
}
)
await client.update(
DOMAIN_TX,
{
_id: tx._id
},
{
'attributes.createOn': tx.modifiedOn
}
)
} else {
await client.update(
DOMAIN_CONTACT,
{
_id: doc._id
},
{
createOn: doc.modifiedOn
}
)
}
}
}
}
async function createEmployeeEmail (client: TxOperations): Promise<void> {
const employees = await client.findAll(contact.class.Employee, {})
const channels = await client.findAll(contact.class.Channel, {
@@ -133,9 +74,7 @@ async function createEmployeeEmail (client: TxOperations): Promise<void> {
}
export const contactOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await setCreate(client)
},
async migrate (client: MigrationClient): Promise<void> {},
async upgrade (client: MigrationUpgradeClient): Promise<void> {
const tx = new TxOperations(client, core.account.System)
await createSpace(tx)
+5
View File
@@ -57,6 +57,7 @@ import {
Mixin as MMixin,
Model,
Prop,
ReadOnly,
TypeBoolean,
TypeIntlString,
TypeRecord,
@@ -101,6 +102,10 @@ export class TDoc extends TObj implements Doc {
@Prop(TypeRef(core.class.Account), core.string.CreatedBy)
@Index(IndexKind.Indexed)
createdBy!: Ref<Account>
@Prop(TypeTimestamp(), core.string.CreatedDate)
@ReadOnly()
createOn!: Timestamp
}
@Model(core.class.AttachedDoc, core.class.Doc)
+67 -4
View File
@@ -13,17 +13,17 @@
// limitations under the License.
//
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
import core, {
Doc,
AttachedDoc,
DOMAIN_BLOB,
DOMAIN_DOC_INDEX_STATE,
DOMAIN_MODEL,
DOMAIN_TX,
TxCreateDoc,
Doc,
TxCollectionCUD,
AttachedDoc
TxCreateDoc
} from '@hcengineering/core'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
async function fillCreatedBy (client: MigrationClient): Promise<void> {
const h = client.hierarchy
@@ -87,9 +87,72 @@ async function fillCreatedBy (client: MigrationClient): Promise<void> {
}
}
}
async function fillCreatedOn (client: MigrationClient): Promise<void> {
const h = client.hierarchy
const domains = h.domains()
for (const domain of domains) {
if (
domain === DOMAIN_TX ||
domain === DOMAIN_MODEL ||
domain === DOMAIN_BLOB ||
domain === DOMAIN_DOC_INDEX_STATE
) {
continue
}
while (true) {
try {
const objects = await client.find<Doc>(
domain,
{ createdOn: { $exists: false } },
{ projection: { _id: 1, modifiedOn: 1 }, limit: 10000 }
)
if (objects.length === 0) {
break
}
const txes = await client.find<TxCreateDoc<Doc>>(
DOMAIN_TX,
{
_class: core.class.TxCreateDoc,
objectId: { $in: Array.from(objects.map((it) => it._id)) }
},
{ projection: { _id: 1, modifiedOn: 1, createOn: 1, objectId: 1 } }
)
const txes2 = (
await client.find<TxCollectionCUD<Doc, AttachedDoc>>(
DOMAIN_TX,
{
_class: core.class.TxCollectionCUD,
'tx._class': core.class.TxCreateDoc,
'tx.objectId': { $in: Array.from(objects.map((it) => it._id)) }
},
{ projection: { _id: 1, modifiedOn: 1, createOn: 1, tx: 1 } }
)
).map((it) => it.tx as unknown as TxCreateDoc<Doc>)
const txMap = new Map(txes.concat(txes2).map((p) => [p.objectId, p]))
console.log('migrateCreateOn', domain, objects.length)
await client.bulk(
domain,
objects.map((it) => {
const createTx = txMap.get(it._id)
return {
filter: { _id: it._id },
update: {
createdOn: createTx?.createOn ?? it.modifiedOn
}
}
})
)
} catch (err) {}
}
}
}
export const coreOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await fillCreatedBy(client)
await fillCreatedOn(client)
},
async upgrade (client: MigrationUpgradeClient): Promise<void> {}
}
+4 -6
View File
@@ -13,11 +13,11 @@
// limitations under the License.
//
import contact, { EmployeeAccount } from '@hcengineering/contact'
import core, { AccountRole, DOMAIN_TX, TxCreateDoc, TxOperations } from '@hcengineering/core'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
import contact, { EmployeeAccount } from '@hcengineering/contact'
import recruit from '@hcengineering/model-recruit'
import { DOMAIN_CONTACT } from '@hcengineering/model-contact'
import recruit from '@hcengineering/model-recruit'
async function createCandidate (
tx: TxOperations,
@@ -33,8 +33,7 @@ async function createCandidate (
if (current !== undefined) return
const u1 = await tx.createDoc(contact.class.Person, recruit.space.CandidatesPublic, {
name,
city,
createOn: Date.now()
city
})
await tx.addCollection(contact.class.Channel, recruit.space.CandidatesPublic, u1, contact.class.Person, 'channels', {
provider: contact.channelProvider.Email,
@@ -74,8 +73,7 @@ export const demoOperation: MigrateOperation = {
const employee = await ops.createDoc(contact.class.Employee, contact.space.Employee, {
name: 'Chen,Rosamund',
city: 'Mountain View',
active: true,
createOn: Date.now()
active: true
})
await ops.createDoc<EmployeeAccount>(contact.class.EmployeeAccount, core.space.Model, {
+1
View File
@@ -270,6 +270,7 @@ export function createModel (builder: Builder): void {
orderBy: [
['state', SortingOrder.Ascending],
['modifiedOn', SortingOrder.Descending],
['createOn', SortingOrder.Descending],
['dueDate', SortingOrder.Ascending],
['rank', SortingOrder.Ascending]
],
+2 -6
View File
@@ -29,7 +29,6 @@ import {
TypeMarkup,
TypeRef,
TypeString,
TypeTimestamp,
UX
} from '@hcengineering/model'
import attachment from '@hcengineering/model-attachment'
@@ -37,6 +36,7 @@ import calendar from '@hcengineering/model-calendar'
import chunter from '@hcengineering/model-chunter'
import contact, { TOrganization, TPerson } from '@hcengineering/model-contact'
import core, { TAttachedDoc, TSpace } from '@hcengineering/model-core'
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
import presentation from '@hcengineering/model-presentation'
import tags from '@hcengineering/model-tags'
import task, { DOMAIN_TASK, TSpaceWithStates, TTask, actionTemplates } from '@hcengineering/model-task'
@@ -59,7 +59,6 @@ import { KeyBinding, ViewOptionsModel } from '@hcengineering/view'
import recruit from './plugin'
import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review'
import { TOpinion, TReview } from './review-model'
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
export { recruitId } from '@hcengineering/recruit'
export { recruitOperation } from './migration'
@@ -167,10 +166,6 @@ export class TApplicant extends TTask implements Applicant {
@Prop(TypeRef(contact.class.Employee), recruit.string.AssignedRecruiter)
declare assignee: Ref<Employee> | null
@Prop(TypeTimestamp(), contact.string.CreatedDate)
@ReadOnly()
createOn!: Timestamp
}
@Model(recruit.class.ApplicantMatch, core.class.AttachedDoc, DOMAIN_TASK)
@@ -629,6 +624,7 @@ export function createModel (builder: Builder): void {
orderBy: [
['state', SortingOrder.Ascending],
['modifiedOn', SortingOrder.Descending],
['createOn', SortingOrder.Descending],
['dueDate', SortingOrder.Ascending],
['rank', SortingOrder.Ascending]
],
+2 -45
View File
@@ -20,7 +20,6 @@ import core, {
DOMAIN_TX,
Ref,
Space,
TxCollectionCUD,
TxCreateDoc,
TxFactory,
TxOperations,
@@ -31,8 +30,8 @@ import { DOMAIN_CALENDAR } from '@hcengineering/model-calendar'
import contact, { DOMAIN_CONTACT } from '@hcengineering/model-contact'
import { DOMAIN_SPACE } from '@hcengineering/model-core'
import tags, { TagCategory } from '@hcengineering/model-tags'
import { createKanbanTemplate, createSequence, DOMAIN_KANBAN, DOMAIN_TASK } from '@hcengineering/model-task'
import { Applicant, Candidate, Vacancy } from '@hcengineering/recruit'
import { createKanbanTemplate, createSequence, DOMAIN_KANBAN } from '@hcengineering/model-task'
import { Vacancy } from '@hcengineering/recruit'
import task, { KanbanTemplate, Sequence } from '@hcengineering/task'
import recruit from './plugin'
@@ -48,47 +47,6 @@ async function fixImportedTitle (client: MigrationClient): Promise<void> {
)
}
async function setCreate (client: MigrationClient): Promise<void> {
while (true) {
const docs = await client.find<Applicant>(
DOMAIN_TASK,
{
_class: recruit.class.Applicant,
createOn: { $exists: false }
},
{ limit: 500 }
)
if (docs.length === 0) break
const txex = await client.find<TxCollectionCUD<Candidate, Applicant>>(DOMAIN_TX, {
'tx.objectId': { $in: docs.map((it) => it._id) },
'tx._class': core.class.TxCreateDoc
})
for (const doc of docs) {
const tx = txex.find((it) => it.tx.objectId === doc._id)
if (tx !== undefined) {
await client.update(
DOMAIN_TASK,
{
_id: doc._id
},
{
createOn: tx.modifiedOn
}
)
await client.update(
DOMAIN_TX,
{
_id: tx._id
},
{
'tx.attributes.createOn': tx.modifiedOn
}
)
}
}
}
}
async function fillVacancyNumbers (client: MigrationClient): Promise<void> {
const docs = await client.find<Vacancy>(DOMAIN_SPACE, {
_class: recruit.class.Vacancy,
@@ -142,7 +100,6 @@ async function fillVacancyNumbers (client: MigrationClient): Promise<void> {
export const recruitOperation: MigrateOperation = {
async migrate (client: MigrationClient): Promise<void> {
await setCreate(client)
await fixImportedTitle(client)
await fillVacancyNumbers(client)
await client.update(
+6 -7
View File
@@ -257,10 +257,6 @@ export class TIssue extends TAttachedDoc implements Issue {
@Prop(Collection(tracker.class.TimeSpendReport), tracker.string.TimeSpendReports)
reports!: number
@Prop(TypeTimestamp(), tracker.string.CreatedDate)
@ReadOnly()
createOn!: Timestamp
declare childInfo: IssueChildInfo[]
}
@@ -1780,7 +1776,8 @@ export function createModel (builder: Builder): void {
groupBy: ['status'],
orderBy: [
['modifiedOn', SortingOrder.Descending],
['targetDate', SortingOrder.Descending]
['targetDate', SortingOrder.Descending],
['createOn', SortingOrder.Descending]
],
other: []
}
@@ -1852,7 +1849,8 @@ export function createModel (builder: Builder): void {
groupBy: ['lead'],
orderBy: [
['startDate', SortingOrder.Descending],
['modifiedOn', SortingOrder.Descending]
['modifiedOn', SortingOrder.Descending],
['createOn', SortingOrder.Descending]
],
other: []
}
@@ -1919,7 +1917,8 @@ export function createModel (builder: Builder): void {
groupBy: [],
orderBy: [
['startDate', SortingOrder.Descending],
['modifiedOn', SortingOrder.Descending]
['modifiedOn', SortingOrder.Descending],
['createOn', SortingOrder.Descending]
],
other: [],
groupDepth: 1
+8 -63
View File
@@ -15,34 +15,33 @@
import core, {
Class,
DOMAIN_STATUS,
DOMAIN_TX,
Doc,
DocumentUpdate,
DOMAIN_TX,
generateId,
Ref,
SortingOrder,
StatusCategory,
TxCollectionCUD,
TxCreateDoc,
TxOperations,
TxResult,
TxUpdateDoc,
DOMAIN_STATUS
generateId
} from '@hcengineering/core'
import { createOrUpdate, MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
import { MigrateOperation, MigrationClient, MigrationUpgradeClient, createOrUpdate } from '@hcengineering/model'
import { DOMAIN_SPACE } from '@hcengineering/model-core'
import tags from '@hcengineering/tags'
import {
calcRank,
genRanks,
Issue,
IssueStatus,
IssueTemplate,
IssueTemplateChild,
Project,
Milestone,
MilestoneStatus,
TimeReportDayType
Project,
TimeReportDayType,
calcRank,
genRanks
} from '@hcengineering/tracker'
import { DOMAIN_TRACKER } from '.'
import tracker from './plugin'
@@ -851,59 +850,6 @@ async function renameProject (client: MigrationClient): Promise<void> {
)
}
async function setCreate (client: MigrationClient): Promise<void> {
while (true) {
const docs = await client.find<Issue>(
DOMAIN_TRACKER,
{
_class: tracker.class.Issue,
createOn: { $exists: false }
},
{ limit: 500 }
)
if (docs.length === 0) {
break
}
const creates = await client.find<TxCollectionCUD<Issue, Issue>>(DOMAIN_TX, {
'tx.objectId': { $in: docs.map((it) => it._id) },
'tx._class': core.class.TxCreateDoc
})
for (const doc of docs) {
const tx = creates.find((it) => it.tx.objectId === doc._id)
if (tx !== undefined) {
await client.update(
DOMAIN_TRACKER,
{
_id: doc._id
},
{
createOn: tx.modifiedOn
}
)
await client.update(
DOMAIN_TX,
{
_id: tx._id
},
{
'tx.attributes.createOn': tx.modifiedOn
}
)
} else {
await client.update(
DOMAIN_TRACKER,
{
_id: doc._id
},
{
createOn: doc.modifiedOn
}
)
}
}
}
}
async function fixMilestoneEmptyStatuses (client: MigrationClient): Promise<void> {
await client.update<Milestone>(
DOMAIN_TRACKER,
@@ -928,7 +874,6 @@ export const trackerOperation: MigrateOperation = {
await fillRank(client)
await renameSprintToMilestone(client)
await renameProject(client)
await setCreate(client)
// Move all status objects into status domain
await client.move(
+2 -1
View File
@@ -56,7 +56,8 @@ export interface Doc extends Obj {
space: Ref<Space>
modifiedOn: Timestamp
modifiedBy: Ref<Account>
createdBy?: Ref<Account>
createdBy?: Ref<Account> // Marked as optional since it will be filled by platform.
createOn?: Timestamp // Marked as optional since it will be filled by platform.
}
/**
+10 -1
View File
@@ -259,7 +259,16 @@ async function loadModel (
): Promise<Timestamp> {
const t = Date.now()
const atxes = await conn.loadModel(lastTxTime)
let atxes = []
try {
atxes = await conn.loadModel(lastTxTime)
} catch (err: any) {
atxes = await conn.findAll(
core.class.Tx,
{ objectSpace: core.space.Model },
{ sort: { _id: SortingOrder.Ascending, modifiedOn: SortingOrder.Ascending } }
)
}
if (reload && atxes.length > modelTransactionThreshold) {
return -1
+1
View File
@@ -172,6 +172,7 @@ export default plugin(coreId, {
Object: '' as IntlString,
System: '' as IntlString,
CreatedBy: '' as IntlString,
CreatedDate: '' as IntlString,
Status: '' as IntlString,
Account: '' as IntlString,
StatusCategory: '' as IntlString
+1
View File
@@ -30,6 +30,7 @@
"Object": "Object",
"System": "System",
"CreatedBy": "Created by",
"CreatedDate": "Created date",
"Status": "Status",
"StatusCategory": "Status category",
"Account": "Account"
+1
View File
@@ -30,6 +30,7 @@
"Object": "Объект",
"System": "Система",
"CreatedBy": "Создан",
"CreatedDate": "Дата создания",
"Status": "Статус",
"StatusCategory": "Категория статуса",
"Account": "Аккаунт"
+2 -1
View File
@@ -353,7 +353,8 @@ export abstract class TxProcessor implements WithTx {
space: tx.objectSpace,
modifiedBy: tx.modifiedBy,
modifiedOn: tx.modifiedOn,
createdBy: tx.createdBy ?? tx.modifiedBy
createdBy: tx.createdBy ?? tx.modifiedBy,
createOn: tx.createOn ?? tx.modifiedBy
} as T
}
+1 -2
View File
@@ -64,7 +64,6 @@ export async function createApplication (
...data,
state: state._id,
number: (incResult as any).object.sequence,
rank: calcRank(lastOne, undefined),
createOn: Date.now()
rank: calcRank(lastOne, undefined)
})
}
+1 -2
View File
@@ -940,8 +940,7 @@ async function synchronizeUsers (
name: combineName(u.NAME, u.LAST_NAME),
avatar: u.PERSONAL_PHOTO,
active: u.ACTIVE,
city: u.PERSONAL_CITY,
createOn: Date.now()
city: u.PERSONAL_CITY
})
accountId = await ops.client.createDoc(contact.class.EmployeeAccount, core.space.Model, {
email: u.EMAIL,
@@ -109,7 +109,7 @@
if (docUpdate === undefined || lastView === undefined) return -1
for (let index = 0; index < messages.length; index++) {
const message = messages[index]
if (message.createOn >= lastView) return index
if ((message.createOn ?? 0) >= lastView) return index
}
return -1
}
@@ -209,7 +209,7 @@
{#if newMessagesPos === i}
<ChannelSeparator title={chunter.string.New} line reverse isNew />
{/if}
{#if i === 0 || isOtherDay(message.createOn, messages[i - 1].createOn)}
{#if i === 0 || isOtherDay(message.createOn ?? 0, messages[i - 1].createOn ?? 0)}
<JumpToDateSelector selectedDate={message.createOn} on:jumpToDate={handleJumpToDate} />
{/if}
<MessageComponent
@@ -16,7 +16,7 @@
import attachment, { Attachment } from '@hcengineering/attachment'
import { AttachmentRefInput } from '@hcengineering/attachment-resources'
import { ChunterMessage, ChunterSpace, Message } from '@hcengineering/chunter'
import { generateId, getCurrentAccount, Ref, Space } from '@hcengineering/core'
import { Ref, Space, generateId, getCurrentAccount } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import { location, navigate } from '@hcengineering/ui'
import { get } from 'svelte/store'
@@ -44,7 +44,6 @@
'messages',
{
content: message,
createOn: Date.now(),
createBy: me,
attachments
},
@@ -228,7 +228,7 @@
{#if employee}
<EmployeePresenter value={employee} shouldShowAvatar={false} inline />
{/if}
<span>{getTime(message.createOn)}</span>
<span>{getTime(message.createOn ?? 0)}</span>
{#if message.editedOn}
<span use:tooltip={{ label: ui.string.TimeTooltip, props: { value: getTime(message.editedOn) } }}>
<Label label={chunter.string.Edited} />
@@ -66,7 +66,7 @@
</div>
</div>
<MessageViewer message={message.content} />
<span class="time">{getTime(message.createOn)}</span>
<span class="time">{getTime(message.createOn ?? 0)}</span>
</div>
{/each}
</div>
@@ -131,7 +131,6 @@
collection: 'repliesCount',
content: message,
createBy: me,
createOn: 0,
attachments
},
commentId
@@ -144,7 +144,6 @@
{
content: message,
createBy: me,
createOn: Date.now(),
attachments
},
commentId
@@ -165,7 +164,7 @@
if (docUpdate === undefined || lastView === undefined) return -1
for (let index = 0; index < comments.length; index++) {
const comment = comments[index]
if (comment.createOn >= lastView) return index
if ((comment.createOn ?? 0) >= lastView) return index
}
return -1
}
-1
View File
@@ -48,7 +48,6 @@ export interface ChunterMessage extends AttachedDoc {
content: string
attachments?: number
createBy: Ref<Account>
createOn: Timestamp
editedOn?: Timestamp
reactions?: number
}
+1 -2
View File
@@ -70,8 +70,7 @@
"UseImage": "Attached photo",
"UseGravatar": "Gravatar",
"UseColor": "Color",
"NotSpecified": "Not specified",
"CreatedDate": "Created date",
"NotSpecified": "Not specified",
"Whatsapp": "Whatsapp",
"WhatsappPlaceholder": "Whatsapp",
"Skype": "Skype",
+1 -2
View File
@@ -71,8 +71,7 @@
"UseGravatar": "Граватар",
"UseColor": "Цвет",
"AvatarProvider": "Тип аватара",
"NotSpecified": "Не указан",
"CreatedDate": "Дата создания",
"NotSpecified": "Не указан",
"Whatsapp": "Whatsapp",
"WhatsappPlaceholder": "Whatsapp",
"Skype": "Skype",
@@ -49,7 +49,6 @@
changeEmail()
const name = combineName(firstName, lastName)
const person: Data<Employee> = {
createOn: Date.now(),
name,
city: object.city,
active: true
@@ -16,7 +16,7 @@
import { Channel, combineName, findPerson, Person } from '@hcengineering/contact'
import { AttachedData, Data, generateId } from '@hcengineering/core'
import { Card, getClient } from '@hcengineering/presentation'
import { EditBox, IconInfo, Label, createFocusManager, FocusHandler } from '@hcengineering/ui'
import { createFocusManager, EditBox, FocusHandler, IconInfo, Label } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { ChannelsDropdown } from '..'
import contact from '../plugin'
@@ -41,7 +41,6 @@
async function createPerson () {
const person: Data<Person> = {
createOn: Date.now(),
name: combineName(firstName, lastName),
city: object.city
}
@@ -54,7 +54,7 @@
'tx.attributes.incoming': false
},
(res) => {
const filtered = res.filter((p) => (p.tx as TxCreateDoc<ChannelItem>).attributes.sendOn >= object.createOn)
const filtered = res.filter((p) => (p.tx as TxCreateDoc<ChannelItem>).attributes.sendOn >= (object.createOn ?? 0))
newTxes = createDisplayTxes(filtered)
}
)
-1
View File
@@ -101,7 +101,6 @@ export interface Contact extends Doc {
comments?: number
channels?: number
city: string
createOn: Timestamp
}
/**
@@ -61,8 +61,7 @@
async function createCustomer () {
const candidate: Data<Contact> = {
name: formatName(targetClass._id, firstName, lastName, object.name),
city: object.city,
createOn: Date.now()
city: object.city
}
if (avatar !== undefined) {
candidate.avatar = await avatarEditor.createAvatar()
@@ -92,8 +92,7 @@
modifiedOn: Date.now(),
modifiedBy: '' as Ref<Account>,
startDate: null,
dueDate: null,
createOn: Date.now()
dueDate: null
}
const dispatch = createEventDispatcher()
@@ -149,8 +148,7 @@
assignee: doc.assignee,
rank: calcRank(lastOne, undefined),
startDate: null,
dueDate: null,
createOn: Date.now()
dueDate: null
},
doc._id
)
@@ -182,8 +180,7 @@
modifiedOn: Date.now(),
modifiedBy: '' as Ref<Account>,
startDate: null,
dueDate: null,
createOn: Date.now()
dueDate: null
}
fillDefaults(hierarchy, doc, recruit.class.Applicant)
}
@@ -174,8 +174,7 @@
const candidate: Data<Person> = {
name: combineName(object.firstName ?? '', object.lastName ?? ''),
city: object.city,
channels: 0,
createOn: Date.now()
channels: 0
}
if (avatar !== undefined) {
candidate.avatar = await avatarEditor.createAvatar()
@@ -142,8 +142,7 @@
estimation: template.estimation,
reports: 0,
relations: [{ _id: id, _class: recruit.class.Vacancy }],
childInfo: [],
createOn: Date.now()
childInfo: []
})
if ((template.labels?.length ?? 0) > 0) {
const tagElements = await client.findAll(tags.class.TagElement, { _id: { $in: template.labels } })
-1
View File
@@ -89,7 +89,6 @@ export interface Applicant extends Task {
attachedTo: Ref<Candidate>
attachments?: number
comments?: number
createOn: Timestamp
}
/**
-1
View File
@@ -270,7 +270,6 @@
"SevenHoursLength": "Seven Hours",
"EightHoursLength": "Eight Hours",
"CreatedDate": "Created date",
"HourLabel": "h",
"Saved": "Saved...",
"CreatedIssue": "Created issue",
-1
View File
@@ -270,7 +270,6 @@
"SevenHoursLength": "Семь Часов",
"EightHoursLength": "Восемь Часов",
"CreatedDate": "Дата создания",
"HourLabel": "ч",
"Saved": "Сохранено...",
"CreatedIssue": "Создал(а) задачу",
@@ -37,8 +37,8 @@
IssuePriority,
IssueStatus,
IssueTemplate,
Project,
Milestone
Milestone,
Project
} from '@hcengineering/tracker'
import {
ActionIcon,
@@ -67,9 +67,9 @@
import PriorityEditor from './issues/PriorityEditor.svelte'
import StatusEditor from './issues/StatusEditor.svelte'
import EstimationEditor from './issues/timereport/EstimationEditor.svelte'
import MilestoneSelector from './milestones/MilestoneSelector.svelte'
import SetDueDateActionPopup from './SetDueDateActionPopup.svelte'
import SetParentIssueActionPopup from './SetParentIssueActionPopup.svelte'
import MilestoneSelector from './milestones/MilestoneSelector.svelte'
import SubIssues from './SubIssues.svelte'
export let space: Ref<Project>
@@ -354,8 +354,7 @@
estimation: object.estimation,
reports: 0,
relations: relatedTo !== undefined ? [{ _id: relatedTo._id, _class: relatedTo._class }] : [],
childInfo: [],
createOn: Date.now()
childInfo: []
}
await client.addCollection(
@@ -94,8 +94,7 @@
estimation: subIssue.estimation,
reports: 0,
relations: [],
childInfo: [],
createOn: Date.now()
childInfo: []
}
await client.addCollection(
@@ -25,7 +25,7 @@
const config: [string, IntlString, object][] = [
['assigned', tracker.string.Assigned, {}],
['created', tracker.string.Created, {}],
['created', tracker.string.Created, { value: 2 }],
['subscribed', tracker.string.Subscribed, {}]
]
const currentUser = getCurrentAccount() as EmployeeAccount
-2
View File
@@ -173,8 +173,6 @@ export interface Issue extends AttachedDoc {
childInfo: IssueChildInfo[]
createOn: Timestamp
template?: {
// A template issue is based on
template: Ref<IssueTemplate>
@@ -184,7 +184,7 @@ async function ThreadMessageDelete (tx: Tx, control: TriggerControl): Promise<Tx
comment.attachedTo,
{
replies: comments.map((comm) => (control.modelDb.getObject(comm.createBy) as EmployeeAccount).employee),
lastReply: comments.length > 0 ? Math.max(...comments.map((comm) => comm.createOn)) : undefined
lastReply: comments.length > 0 ? Math.max(...comments.map((comm) => comm.createOn ?? comm.modifiedOn)) : undefined
}
)
+1 -2
View File
@@ -623,8 +623,7 @@ async function createEmployee (ops: TxOperations, name: string, email: string):
name,
city: '',
...(hasGravatar ? { avatar: `${AvatarType.GRAVATAR}://${gravatarId}` } : {}),
active: true,
createOn: Date.now()
active: true
})
if (!hasGravatar) {
await ops.updateDoc(contact.class.Employee, contact.space.Employee, id, {
+5
View File
@@ -198,11 +198,13 @@ export async function backup (transactorUrl: string, workspaceId: WorkspaceId, s
const connection = (await connect(transactorUrl, workspaceId, undefined, {
mode: 'backup'
})) as unknown as CoreClient & BackupClient
console.log('starting backup')
try {
const domains = connection
.getHierarchy()
.domains()
.filter((it) => it !== DOMAIN_TRANSIENT && it !== DOMAIN_MODEL)
console.log('domains for dump', domains.length)
let backupInfo: BackupInfo = {
workspace: workspaceId.name,
@@ -431,7 +433,10 @@ export async function backup (transactorUrl: string, workspaceId: WorkspaceId, s
}
await storage.writeFile(infoFile, gzipSync(JSON.stringify(backupInfo, undefined, 2)))
} catch (err: any) {
console.error(err)
} finally {
console.log('end backup')
await connection.close()
}
}
+2 -28
View File
@@ -13,16 +13,7 @@
// limitations under the License.
//
import core, {
AttachedDoc,
Doc,
MeasureContext,
ServerStorage,
Timestamp,
Tx,
TxCollectionCUD,
TxCreateDoc
} from '@hcengineering/core'
import core, { MeasureContext, ServerStorage, Tx } from '@hcengineering/core'
import { BroadcastFunc, Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
import { BaseMiddleware } from './base'
@@ -46,24 +37,7 @@ export class ModifiedMiddleware extends BaseMiddleware implements Middleware {
async tx (ctx: SessionContext, tx: Tx): Promise<TxMiddlewareResult> {
if (tx.modifiedBy !== core.account.System) {
tx.modifiedOn = Date.now()
if (this.storage.hierarchy.isDerived(tx._class, core.class.TxCreateDoc)) {
const createTx = tx as TxCreateDoc<Doc & { createOn: Timestamp }>
const hasCreateOn = this.storage.hierarchy.findAttribute(createTx.objectClass, 'createOn')
if (hasCreateOn !== undefined) {
createTx.attributes.createOn = tx.modifiedOn
}
}
if (this.storage.hierarchy.isDerived(tx._class, core.class.TxCollectionCUD)) {
const coltx = tx as TxCollectionCUD<Doc, AttachedDoc>
coltx.tx.modifiedOn = tx.modifiedOn
if (this.storage.hierarchy.isDerived(coltx.tx._class, core.class.TxCreateDoc)) {
const createTx = coltx.tx as TxCreateDoc<AttachedDoc & { createOn: Timestamp }>
const hasCreateOn = this.storage.hierarchy.findAttribute(createTx.objectClass, 'createOn')
if (hasCreateOn !== undefined) {
createTx.attributes.createOn = tx.modifiedOn
}
}
}
tx.createOn = tx.createOn ?? tx.modifiedOn
}
return await this.provideTx(ctx, tx)
}