Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TSK-1062: Fix merge properly #2919

Merged
merged 1 commit into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev/tool/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"docker:build": "docker build -t hardcoreeng/tool .",
"docker:staging": "../../common/scripts/docker_tag.sh hardcoreeng/tool staging",
"docker:push": "../../common/scripts/docker_tag.sh hardcoreeng/tool",
"run-local": "cross-env SERVER_SECRET=secret MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_ENDPOINT=localhost MONGO_URL=mongodb://localhost:27017 TRANSACTOR_URL=ws:/localhost:3333 TELEGRAM_DATABASE=telegram-service ELASTIC_URL=http://localhost:9200 REKONI_URL=http://localhost:4004 node --inspect -r ts-node/register ./src/__start.ts",
"run-local": "cross-env SERVER_SECRET=secret MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_ENDPOINT=localhost MONGO_URL=mongodb://localhost:27017 TRANSACTOR_URL=ws:/localhost:3333 TELEGRAM_DATABASE=telegram-service ELASTIC_URL=http://localhost:9200 REKONI_URL=http://localhost:4004 node -r ts-node/register ./src/__start.ts",
"run": "cross-env ts-node ./src/__start.ts",
"upgrade": "rushx run-local upgrade",
"lint": "eslint src",
Expand Down
22 changes: 22 additions & 0 deletions models/contact/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,25 @@ export function createModel (builder: Builder): void {
},
contact.action.KickEmployee
)
createAction(
builder,
{
action: contact.actionImpl.KickEmployee,
label: contact.string.DeleteEmployee,
query: {
active: false
},
category: contact.category.Contact,
target: contact.class.Employee,
input: 'focus',
context: {
mode: ['context'],
group: 'other'
},
secured: true
},
contact.action.KickEmployee
)

createAction(
builder,
Expand All @@ -602,6 +621,9 @@ export function createModel (builder: Builder): void {
_object: 'value'
}
},
query: {
active: false
},
label: contact.string.MergeEmployee,
category: contact.category.Contact,
target: contact.class.Employee,
Expand Down
2 changes: 1 addition & 1 deletion models/recruit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ export function createModel (builder: Builder): void {
}

const applicantViewOptions: ViewOptionsModel = {
groupBy: ['state', 'doneState', 'assignee'],
groupBy: ['state', 'doneState', 'assignee', 'space'],
orderBy: [
['state', SortingOrder.Ascending],
['doneState', SortingOrder.Ascending],
Expand Down
5 changes: 3 additions & 2 deletions models/server-contact/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export function createModel (builder: Builder): void {
trigger: serverContact.trigger.OnContactDelete
})

builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverContact.trigger.OnEmployeeUpdate
builder.createDoc(serverCore.class.AsyncTrigger, core.space.Model, {
trigger: serverContact.trigger.OnEmployeeUpdate,
classes: [contact.class.Employee]
})
}
4 changes: 3 additions & 1 deletion models/task/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ export const taskOperation: MigrateOperation = {
const stateTemplateClasses = client.hierarchy.getDescendants(task.class.StateTemplate)
const doneStateTemplatesClasses = client.hierarchy.getDescendants(task.class.DoneStateTemplate)

await client.move(DOMAIN_STATE, { _class: { $in: [...stateClasses, ...doneStateClasses] } }, DOMAIN_STATUS)
try {
await client.move(DOMAIN_STATE, { _class: { $in: [...stateClasses, ...doneStateClasses] } }, DOMAIN_STATUS)
} catch (err) {}

await client.update(
DOMAIN_STATUS,
Expand Down
102 changes: 97 additions & 5 deletions packages/core/src/operations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { DocumentUpdate, Hierarchy, MixinData, MixinUpdate, ModelDb } from '.'
import type { Account, AttachedData, AttachedDoc, Class, Data, Doc, Mixin, Ref, Space, Timestamp } from './classes'
import { DocumentUpdate, Hierarchy, MixinData, MixinUpdate, ModelDb, toFindResult } from '.'
import type {
Account,
AnyAttribute,
AttachedData,
AttachedDoc,
Class,
Data,
Doc,
Mixin,
Ref,
Space,
Timestamp
} from './classes'
import { Client } from './client'
import core from './component'
import type { DocumentQuery, FindOptions, FindResult, TxResult, WithLookup } from './storage'
Expand Down Expand Up @@ -215,6 +227,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
): Promise<TxResult> {
const hierarchy = this.client.getHierarchy()
if (hierarchy.isMixin(doc._class)) {
// TODO: Rework it is wrong, we need to split values to mixin update and original document update if mixed.
const baseClass = hierarchy.getBaseClass(doc._class)
return this.updateMixin(doc._id, baseClass, doc.space, doc._class, update, modifiedOn, modifiedBy)
}
Expand Down Expand Up @@ -291,8 +304,87 @@ export class ApplyOperations extends TxOperations {
}

async commit (): Promise<boolean> {
return await ((await this.ops.tx(
this.ops.txFactory.createTxApplyIf(core.space.Tx, this.scope, this.matches, this.txes)
)) as Promise<boolean>)
if (this.txes.length > 0) {
return await ((await this.ops.tx(
this.ops.txFactory.createTxApplyIf(core.space.Tx, this.scope, this.matches, this.txes)
)) as Promise<boolean>)
}
return true
}
}

/**
* @public
*
* Builder for TxOperations.
*/
export class TxBuilder extends TxOperations {
txes: TxCUD<Doc>[] = []
matches: DocumentClassQuery<Doc>[] = []
constructor (readonly hierarchy: Hierarchy, readonly modelDb: ModelDb, user: Ref<Account>) {
const txClient: Client = {
getHierarchy: () => this.hierarchy,
getModel: () => this.modelDb,
close: async () => {},
findOne: async (_class, query, options?) => undefined,
findAll: async (_class, query, options?) => toFindResult([]),
tx: async (tx): Promise<TxResult> => {
if (this.hierarchy.isDerived(tx._class, core.class.TxCUD)) {
this.txes.push(tx as TxCUD<Doc>)
}
return {}
}
}
super(txClient, user)
}
}

/**
* @public
*/
export async function updateAttribute (
client: TxOperations,
object: Doc,
_class: Ref<Class<Doc>>,
attribute: { key: string, attr: AnyAttribute },
value: any,
modifyBy?: Ref<Account>
): Promise<void> {
const doc = object
const attributeKey = attribute.key
if ((doc as any)[attributeKey] === value) return
const attr = attribute.attr
if (client.getHierarchy().isMixin(attr.attributeOf)) {
await client.updateMixin(
doc._id,
_class,
doc.space,
attr.attributeOf,
{ [attributeKey]: value },
Date.now(),
modifyBy
)
} else {
if (client.getHierarchy().isDerived(attribute.attr.type._class, core.class.ArrOf)) {
const oldValue: any[] = (object as any)[attributeKey] ?? []
const val: any[] = value
const toPull = oldValue.filter((it: any) => !val.includes(it))

const toPush = val.filter((it) => !oldValue.includes(it))
if (toPull.length > 0) {
await client.update(object, { $pull: { [attributeKey]: { $in: toPull } } }, false, Date.now(), modifyBy)
}
if (toPush.length > 0) {
await client.update(
object,
{ $push: { [attributeKey]: { $each: toPush, $position: 0 } } },
false,
Date.now(),
modifyBy
)
}
} else {
await client.update(object, { [attributeKey]: value }, false, Date.now(), modifyBy)
}
}
}
2 changes: 1 addition & 1 deletion packages/core/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@ export interface ServerStorage extends LowLevelStorage {
options?: FindOptions<T>
) => Promise<FindResult<T>>
tx: (ctx: MeasureContext, tx: Tx) => Promise<[TxResult, Tx[]]>
apply: (ctx: MeasureContext, tx: Tx[], broadcast: boolean) => Promise<Tx[]>
apply: (ctx: MeasureContext, tx: Tx[], broadcast: boolean, updateTx: boolean) => Promise<Tx[]>
close: () => Promise<void>
}
34 changes: 2 additions & 32 deletions packages/presentation/src/attributes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import core, { AnyAttribute, Class, Client, Doc, Ref, TxOperations } from '@hcengineering/core'
import { AnyAttribute, Client } from '@hcengineering/core'

/**
* @public
Expand All @@ -8,37 +8,7 @@ export interface KeyedAttribute {
attr: AnyAttribute
}

export async function updateAttribute (
client: TxOperations,
object: Doc,
_class: Ref<Class<Doc>>,
attribute: KeyedAttribute,
value: any
): Promise<void> {
const doc = object
const attributeKey = attribute.key
if ((doc as any)[attributeKey] === value) return
const attr = attribute.attr
if (client.getHierarchy().isMixin(attr.attributeOf)) {
await client.updateMixin(doc._id, _class, doc.space, attr.attributeOf, { [attributeKey]: value })
} else {
if (client.getHierarchy().isDerived(attribute.attr.type._class, core.class.ArrOf)) {
const oldvalue: any[] = (object as any)[attributeKey] ?? []
const val: any[] = value
const toPull = oldvalue.filter((it: any) => !val.includes(it))

const toPush = val.filter((it) => !oldvalue.includes(it))
if (toPull.length > 0) {
await client.update(object, { $pull: { [attributeKey]: { $in: toPull } } })
}
if (toPush.length > 0) {
await client.update(object, { $push: { [attributeKey]: { $each: toPush, $position: 0 } } })
}
} else {
await client.update(object, { [attributeKey]: value })
}
}
}
export { updateAttribute } from '@hcengineering/core'

export function getAttribute (client: Client, object: any, key: KeyedAttribute): any {
// Check if attr is mixin and return it's value
Expand Down
3 changes: 3 additions & 0 deletions packages/presentation/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ export function createQuery (dontDestroy?: boolean): LiveQuery {
* @public
*/
export function getFileUrl (file: string, size: IconSize = 'full'): string {
if (file.includes('://')) {
return file
}
const uploadUrl = getMetadata(plugin.metadata.UploadURL)
const token = getMetadata(plugin.metadata.Token)
const url = `${uploadUrl as string}?file=${file}&token=${token as string}&size=${size as string}`
Expand Down
25 changes: 23 additions & 2 deletions plugins/bitrix/src/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -840,14 +840,35 @@ async function synchronizeUsers (
let totalUsers = 1
let next = 0

const employees = new Map((await ops.client.findAll(contact.class.Employee, {})).map((it) => [it._id, it]))
const employeesList = await ops.client.findAll(
contact.class.Employee,
{},
{
lookup: {
_id: {
channels: contact.class.Channel
}
}
}
)
const employees = new Map(employeesList.map((it) => [it._id, it]))

while (userList.size < totalUsers) {
const users = await ops.bitrixClient.call('user.search', { start: next })
next = users.next
totalUsers = users.total
for (const u of users.result) {
const account = allEmployee.find((it) => it.email === u.EMAIL)
let account = allEmployee.find((it) => it.email === u.EMAIL)

if (account === undefined) {
// Try to find from employee
employeesList.forEach((it) => {
if ((it.$lookup?.channels as Channel[])?.some((q) => q.value === u.EMAIL)) {
account = allEmployee.find((qit) => qit.employee === it._id)
}
})
}

let accountId = account?._id
if (accountId === undefined) {
const employeeId = await ops.client.createDoc(contact.class.Employee, contact.space.Contacts, {
Expand Down
11 changes: 9 additions & 2 deletions plugins/chunter-resources/src/components/CommentPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@

import chunter, { Comment } from '@hcengineering/chunter'
import { createQuery } from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
import { Label, resizeObserver } from '@hcengineering/ui'
import { DocNavLink, ObjectPresenter } from '@hcengineering/view-resources'
import CommentPresenter from './CommentPresenter.svelte'
import { createEventDispatcher } from 'svelte'

export let objectId: Ref<Doc>
export let object: Doc
Expand All @@ -35,9 +36,15 @@
},
{ sort: { modifiedOn: SortingOrder.Descending } }
)
const dispatch = createEventDispatcher()
</script>

<div class="flex flex-between flex-grow p-1 mb-4">
<div
class="flex flex-between flex-grow p-1 mb-4"
use:resizeObserver={() => {
dispatch('changeContent')
}}
>
<div class="fs-title">
<Label label={chunter.string.Comments} />
</div>
Expand Down
10 changes: 7 additions & 3 deletions plugins/contact-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"Person": "Person",
"Organization": "Organization",
"Employee": "Employee",
"DeleteEmployee": "Delete",
"Value": "Value",
"FullDescription": "Full description",
"Phone": "Phone",
Expand Down Expand Up @@ -66,9 +67,9 @@
"CreateEmployee": "Create an employee",
"Inactive": "Inactive",
"Birthday": "Birthday",
"UseImage": "Upload an image",
"UseGravatar": "Use Gravatar",
"UseColor": "Use color",
"UseImage": "Attached photo",
"UseGravatar": "Gravatar",
"UseColor": "Color",
"NotSpecified": "Not specified",
"CreatedOn": "Created",
"Whatsapp": "Whatsapp",
Expand All @@ -77,8 +78,11 @@
"ProfilePlaceholder": "Profile...",
"CurrentEmployee": "Current employee",
"MergeEmployee": "Merge employee",
"MergeEmployeeFrom": "From(inactive)",
"MergeEmployeeTo": "To employee",
"DisplayName": "Display name",
"SelectAvatar": "Select avatar",
"AvatarProvider": "Avatar provider",
"GravatarsManaged": "Gravatars are managed through",
"CategoryProjectMembers": "Project members",
"AddMembersHeader": "Add members to {value}:",
Expand Down
10 changes: 7 additions & 3 deletions plugins/contact-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"Person": "Персона",
"Organization": "Организация",
"Employee": "Сотрудник",
"DeleteEmployee": "Удалить",
"Value": "Значение",
"FullDescription": "Полное описание",
"Phone": "Телефон",
Expand Down Expand Up @@ -66,9 +67,10 @@
"CreateEmployee": "Создать сотрудника",
"Inactive": "Не активный",
"Birthday": "День рождения",
"UseImage": "Загрузить фото",
"UseGravatar": "Использовать Gravatar",
"UseColor": "Использовать цвет",
"UseImage": "Загруженное Фото",
"UseGravatar": "Граватар",
"UseColor": "Цвет",
"AvatarProvider": "Тип аватара",
"NotSpecified": "Не указан",
"CreatedOn": "Создан",
"Whatsapp": "Whatsapp",
Expand All @@ -77,6 +79,8 @@
"ProfilePlaceholder": "Профиль...",
"CurrentEmployee": "Текущий сотрудник",
"MergeEmployee": "Объеденить сотрудника",
"MergeEmployeeFrom": "Из (неактивный)",
"MergeEmployeeTo": "В сотрудника",
"DisplayName": "Отображаемое имя",
"SelectAvatar": "Выбрать аватар",
"GravatarsManaged": "Граватары управляются через",
Expand Down
2 changes: 1 addition & 1 deletion plugins/contact-resources/src/components/Avatar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

if (!avatarProvider || avatarProvider.type === AvatarType.COLOR) {
url = undefined
} else if (avatarProvider.type === AvatarType.IMAGE) {
} else if (avatarProvider?.type === AvatarType.IMAGE) {
url = (await getResource(avatarProvider.getUrl))(avatar, size)
} else {
const uri = avatar.split('://')[1]
Expand Down
Loading