Merge remote-tracking branch 'origin/develop'

This commit is contained in:
Denis Bykhov 2024-08-28 11:58:52 +05:00
commit 702e8b4eb6
33 changed files with 372 additions and 462 deletions

View File

@ -16,6 +16,7 @@
"_phase:docker-staging": "rushx docker:staging", "_phase:docker-staging": "rushx docker:staging",
"bundle": "mkdir -p bundle && esbuild src/__start.ts --bundle --minify --platform=node --define:process.env.MODEL_VERSION=$(node ../../common/scripts/show_version.js) --define:process.env.GIT_REVISION=$(../../common/scripts/git_version.sh) > bundle/bundle.js", "bundle": "mkdir -p bundle && esbuild src/__start.ts --bundle --minify --platform=node --define:process.env.MODEL_VERSION=$(node ../../common/scripts/show_version.js) --define:process.env.GIT_REVISION=$(../../common/scripts/git_version.sh) > bundle/bundle.js",
"docker:build": "../../common/scripts/docker_build.sh hardcoreeng/tool", "docker:build": "../../common/scripts/docker_build.sh hardcoreeng/tool",
"docker:tbuild": "docker build -t hardcoreeng/tool . --platform=linux/amd64 && ../../common/scripts/docker_tag_push.sh hardcoreeng/tool",
"docker:staging": "../../common/scripts/docker_tag.sh hardcoreeng/tool staging", "docker:staging": "../../common/scripts/docker_tag.sh hardcoreeng/tool staging",
"docker:push": "../../common/scripts/docker_tag.sh hardcoreeng/tool", "docker:push": "../../common/scripts/docker_tag.sh hardcoreeng/tool",
"run-local": "rush bundle --to @hcengineering/tool >/dev/null && cross-env SERVER_SECRET=secret ACCOUNTS_URL=http://localhost:3000 TRANSACTOR_URL=ws://localhost:3333 MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_ENDPOINT=localhost MONGO_URL=mongodb://localhost:27017 TELEGRAM_DATABASE=telegram-service ELASTIC_URL=http://localhost:9200 REKONI_URL=http://localhost:4004 MODEL_VERSION=$(node ../../common/scripts/show_version.js) GIT_REVISION=$(git describe --all --long) node --max-old-space-size=18000 ./bundle/bundle.js", "run-local": "rush bundle --to @hcengineering/tool >/dev/null && cross-env SERVER_SECRET=secret ACCOUNTS_URL=http://localhost:3000 TRANSACTOR_URL=ws://localhost:3333 MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_ENDPOINT=localhost MONGO_URL=mongodb://localhost:27017 TELEGRAM_DATABASE=telegram-service ELASTIC_URL=http://localhost:9200 REKONI_URL=http://localhost:4004 MODEL_VERSION=$(node ../../common/scripts/show_version.js) GIT_REVISION=$(git describe --all --long) node --max-old-space-size=18000 ./bundle/bundle.js",

View File

@ -1300,19 +1300,19 @@ export function devTool (
await withDatabase(mongodbUri, async (db, client) => { await withDatabase(mongodbUri, async (db, client) => {
await withStorage(mongodbUri, async (adapter) => { await withStorage(mongodbUri, async (adapter) => {
const workspaces = await listWorkspacesPure(db) const workspaces = await listWorkspacesPure(db)
let index = 0
for (const workspace of workspaces) { for (const workspace of workspaces) {
if (cmd.workspace !== '' && workspace.workspace !== cmd.workspace) { if (cmd.workspace !== '' && workspace.workspace !== cmd.workspace) {
continue continue
} }
const wsId = getWorkspaceId(workspace.workspace) const wsId = getWorkspaceId(workspace.workspace)
const endpoint = await getTransactorEndpoint(generateToken(systemAccountEmail, wsId), 'external') console.log('processing workspace', workspace.workspace, index, workspaces.length)
console.log('processing workspace', workspace.workspace) await migrateMarkup(toolCtx, adapter, wsId, client, mongodbUri, parseInt(cmd.concurrency))
await migrateMarkup(toolCtx, adapter, wsId, client, endpoint, parseInt(cmd.concurrency))
console.log('...done', workspace.workspace) console.log('...done', workspace.workspace)
index++
} }
}) })
}) })

View File

@ -15,7 +15,7 @@ import core, {
} from '@hcengineering/core' } from '@hcengineering/core'
import { getMongoClient, getWorkspaceDB } from '@hcengineering/mongo' import { getMongoClient, getWorkspaceDB } from '@hcengineering/mongo'
import { type StorageAdapter } from '@hcengineering/server-core' import { type StorageAdapter } from '@hcengineering/server-core'
import { connect } from '@hcengineering/server-tool' import { connect, fetchModelFromMongo } from '@hcengineering/server-tool'
import { jsonToText, markupToYDoc } from '@hcengineering/text' import { jsonToText, markupToYDoc } from '@hcengineering/text'
import { type Db, type FindCursor, type MongoClient } from 'mongodb' import { type Db, type FindCursor, type MongoClient } from 'mongodb'
@ -120,18 +120,13 @@ export async function migrateMarkup (
storageAdapter: StorageAdapter, storageAdapter: StorageAdapter,
workspaceId: WorkspaceId, workspaceId: WorkspaceId,
client: MongoClient, client: MongoClient,
transactorUrl: string, mongodbUri: string,
concurrency: number concurrency: number
): Promise<void> { ): Promise<void> {
const connection = (await connect(transactorUrl, workspaceId, undefined, { const { hierarchy } = await fetchModelFromMongo(ctx, mongodbUri, workspaceId)
mode: 'backup'
})) as unknown as CoreClient
const hierarchy = connection.getHierarchy()
const workspaceDb = client.db(workspaceId.name) const workspaceDb = client.db(workspaceId.name)
try {
const classes = hierarchy.getDescendants(core.class.Doc) const classes = hierarchy.getDescendants(core.class.Doc)
for (const _class of classes) { for (const _class of classes) {
const domain = hierarchy.findDomain(_class) const domain = hierarchy.findDomain(_class)
@ -159,9 +154,6 @@ export async function migrateMarkup (
await iterator.close() await iterator.close()
} }
} }
} finally {
await connection.close()
}
} }
async function processMigrateMarkupFor ( async function processMigrateMarkupFor (

View File

@ -360,8 +360,10 @@ table.proseTable {
padding: .5rem; padding: .5rem;
user-select: text; user-select: text;
cursor: auto; cursor: auto;
}
pre { white-space: pre-wrap; } pre.proseCodeBlock {
white-space: pre-wrap;
} }
// Fixes for MessageViewer // Fixes for MessageViewer

View File

@ -12,31 +12,31 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
import notification, { type DocNotifyContext } from '@hcengineering/notification' import attachment, { type SavedAttachments } from '@hcengineering/attachment'
import { type DirectMessage } from '@hcengineering/chunter'
import contact, { type PersonAccount } from '@hcengineering/contact'
import core, { import core, {
type Account,
AccountRole,
generateId, generateId,
getCurrentAccount,
hasAccountRole,
type IdMap,
type Ref, type Ref,
SortingOrder, SortingOrder,
type WithLookup, type UserStatus,
hasAccountRole, type WithLookup
getCurrentAccount,
AccountRole,
type IdMap,
type Account,
type UserStatus
} from '@hcengineering/core' } from '@hcengineering/core'
import notification, { type DocNotifyContext } from '@hcengineering/notification'
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
import { createQuery, getClient, MessageBox } from '@hcengineering/presentation' import { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
import { get, writable } from 'svelte/store' import { type Action, showPopup } from '@hcengineering/ui'
import view from '@hcengineering/view' import view from '@hcengineering/view'
import workbench, { type SpecialNavModel } from '@hcengineering/workbench' import workbench, { type SpecialNavModel } from '@hcengineering/workbench'
import attachment, { type SavedAttachments } from '@hcengineering/attachment' import { get, writable } from 'svelte/store'
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
import { type Action, showPopup } from '@hcengineering/ui'
import contact, { type PersonAccount } from '@hcengineering/contact'
import { type DirectMessage } from '@hcengineering/chunter'
import { type ChatNavGroupModel, type ChatNavItemModel, type SortFnOptions } from './types'
import chunter from '../../plugin' import chunter from '../../plugin'
import { type ChatNavGroupModel, type ChatNavItemModel, type SortFnOptions } from './types'
const navigatorStateStorageKey = 'chunter.navigatorState' const navigatorStateStorageKey = 'chunter.navigatorState'
@ -356,14 +356,12 @@ function archiveActivityChannels (contexts: DocNotifyContext[]): void {
MessageBox, MessageBox,
{ {
label: chunter.string.ArchiveActivityConfirmationTitle, label: chunter.string.ArchiveActivityConfirmationTitle,
message: chunter.string.ArchiveActivityConfirmationMessage message: chunter.string.ArchiveActivityConfirmationMessage,
action: async () => {
await removeActivityChannels(contexts)
}
}, },
'top', 'top'
(result?: boolean) => {
if (result === true) {
void removeActivityChannels(contexts)
}
}
) )
} }

View File

@ -13,86 +13,81 @@
// limitations under the License. // limitations under the License.
// //
import { writable } from 'svelte/store' import { type ActivityMessage } from '@hcengineering/activity'
import chunter, { type Channel, type ChatMessage, type DirectMessage } from '@hcengineering/chunter' import chunter, { type Channel, type ChatMessage, type DirectMessage } from '@hcengineering/chunter'
import { type Resources } from '@hcengineering/platform' import { type Resources } from '@hcengineering/platform'
import { MessageBox, getClient } from '@hcengineering/presentation' import { MessageBox, getClient } from '@hcengineering/presentation'
import { getLocation, navigate, showPopup } from '@hcengineering/ui' import { getLocation, navigate, showPopup } from '@hcengineering/ui'
import { type ActivityMessage } from '@hcengineering/activity' import { writable } from 'svelte/store'
import ChannelPresenter from './components/ChannelPresenter.svelte' import ChannelCreatedMessage from './components/activity/ChannelCreatedMessage.svelte'
import MembersChangedMessage from './components/activity/MembersChangedMessage.svelte'
import ChannelHeader from './components/ChannelHeader.svelte'
import ChannelIcon from './components/ChannelIcon.svelte'
import ChannelPanel from './components/ChannelPanel.svelte' import ChannelPanel from './components/ChannelPanel.svelte'
import ChunterBrowser from './components/chat/specials/ChunterBrowser.svelte' import ChannelPresenter from './components/ChannelPresenter.svelte'
import ConvertDmToPrivateChannelModal from './components/ConvertDmToPrivateChannel.svelte' import ChannelPreview from './components/ChannelPreview.svelte'
import ChatMessageInput from './components/chat-message/ChatMessageInput.svelte'
import ChatMessagePresenter from './components/chat-message/ChatMessagePresenter.svelte'
import ChatMessagePreview from './components/chat-message/ChatMessagePreview.svelte'
import ChatMessagesPresenter from './components/chat-message/ChatMessagesPresenter.svelte'
import Chat from './components/chat/Chat.svelte'
import ChatAside from './components/chat/ChatAside.svelte'
import CreateChannel from './components/chat/create/CreateChannel.svelte' import CreateChannel from './components/chat/create/CreateChannel.svelte'
import CreateDirectChat from './components/chat/create/CreateDirectChat.svelte' import CreateDirectChat from './components/chat/create/CreateDirectChat.svelte'
import ChunterBrowser from './components/chat/specials/ChunterBrowser.svelte'
import SavedMessages from './components/chat/specials/SavedMessages.svelte'
import ConvertDmToPrivateChannelModal from './components/ConvertDmToPrivateChannel.svelte'
import DirectIcon from './components/DirectIcon.svelte'
import DmHeader from './components/DmHeader.svelte' import DmHeader from './components/DmHeader.svelte'
import DmPresenter from './components/DmPresenter.svelte' import DmPresenter from './components/DmPresenter.svelte'
import EditChannel from './components/EditChannel.svelte' import EditChannel from './components/EditChannel.svelte'
import ChannelPreview from './components/ChannelPreview.svelte' import ChatMessageNotificationLabel from './components/notification/ChatMessageNotificationLabel.svelte'
import JoinChannelNotificationPresenter from './components/notification/JoinChannelNotificationPresenter.svelte'
import ThreadNotificationPresenter from './components/notification/ThreadNotificationPresenter.svelte'
import ThreadMessagePresenter from './components/threads/ThreadMessagePresenter.svelte'
import ThreadMessagePreview from './components/threads/ThreadMessagePreview.svelte'
import ThreadParentPresenter from './components/threads/ThreadParentPresenter.svelte'
import Threads from './components/threads/Threads.svelte'
import ThreadView from './components/threads/ThreadView.svelte' import ThreadView from './components/threads/ThreadView.svelte'
import ThreadViewPanel from './components/threads/ThreadViewPanel.svelte' import ThreadViewPanel from './components/threads/ThreadViewPanel.svelte'
import ChatMessagePresenter from './components/chat-message/ChatMessagePresenter.svelte'
import ChatMessageInput from './components/chat-message/ChatMessageInput.svelte'
import ChatMessagesPresenter from './components/chat-message/ChatMessagesPresenter.svelte'
import Chat from './components/chat/Chat.svelte'
import ThreadMessagePresenter from './components/threads/ThreadMessagePresenter.svelte'
import ThreadParentPresenter from './components/threads/ThreadParentPresenter.svelte'
import ChannelHeader from './components/ChannelHeader.svelte'
import SavedMessages from './components/chat/specials/SavedMessages.svelte'
import Threads from './components/threads/Threads.svelte'
import DirectIcon from './components/DirectIcon.svelte'
import ChannelIcon from './components/ChannelIcon.svelte'
import ThreadNotificationPresenter from './components/notification/ThreadNotificationPresenter.svelte'
import ChatMessageNotificationLabel from './components/notification/ChatMessageNotificationLabel.svelte'
import ChatAside from './components/chat/ChatAside.svelte'
import ThreadMessagePreview from './components/threads/ThreadMessagePreview.svelte'
import ChatMessagePreview from './components/chat-message/ChatMessagePreview.svelte'
import ChannelCreatedMessage from './components/activity/ChannelCreatedMessage.svelte'
import MembersChangedMessage from './components/activity/MembersChangedMessage.svelte'
import JoinChannelNotificationPresenter from './components/notification/JoinChannelNotificationPresenter.svelte'
import {
chunterSpaceLinkFragmentProvider,
getMessageLink,
getMessageLocation,
getThreadLink,
replyToThread
} from './navigation'
import { import {
ChannelTitleProvider, ChannelTitleProvider,
DirectTitleProvider, DirectTitleProvider,
canCopyMessageLink,
canDeleteMessage, canDeleteMessage,
canReplyToThread,
dmIdentifierProvider, dmIdentifierProvider,
getDmName, getDmName,
getTitle, getTitle,
getUnreadThreadsCount, getUnreadThreadsCount,
canCopyMessageLink,
leaveChannelAction, leaveChannelAction,
removeChannelAction, removeChannelAction
canReplyToThread
} from './utils' } from './utils'
import {
chunterSpaceLinkFragmentProvider,
getThreadLink,
getMessageLink,
replyToThread,
getMessageLocation
} from './navigation'
export { default as ChatMessagesPresenter } from './components/chat-message/ChatMessagesPresenter.svelte'
export { default as ChatMessagePopup } from './components/chat-message/ChatMessagePopup.svelte'
export { default as ChatMessageInput } from './components/chat-message/ChatMessageInput.svelte' export { default as ChatMessageInput } from './components/chat-message/ChatMessageInput.svelte'
export { default as ChatMessagePopup } from './components/chat-message/ChatMessagePopup.svelte'
export { default as ChatMessagesPresenter } from './components/chat-message/ChatMessagesPresenter.svelte'
export { default as Header } from './components/Header.svelte' export { default as Header } from './components/Header.svelte'
export { default as ThreadView } from './components/threads/ThreadView.svelte' export { default as ThreadView } from './components/threads/ThreadView.svelte'
export async function ArchiveChannel (channel: Channel, evt: any, afterArchive?: () => void): Promise<void> { export async function ArchiveChannel (channel: Channel, evt: any, afterArchive?: () => void): Promise<void> {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: chunter.string.ArchiveChannel, label: chunter.string.ArchiveChannel,
message: chunter.string.ArchiveConfirm message: chunter.string.ArchiveConfirm,
}, action: async () => {
undefined,
(result: boolean) => {
if (result) {
const client = getClient() const client = getClient()
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
client.update(channel, { archived: true }) await client.update(channel, { archived: true })
if (afterArchive != null) afterArchive() if (afterArchive != null) afterArchive()
const loc = getLocation() const loc = getLocation()
@ -101,27 +96,18 @@ export async function ArchiveChannel (channel: Channel, evt: any, afterArchive?:
navigate(loc) navigate(loc)
} }
} }
} })
)
} }
async function UnarchiveChannel (channel: Channel): Promise<void> { async function UnarchiveChannel (channel: Channel): Promise<void> {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: chunter.string.UnarchiveChannel, label: chunter.string.UnarchiveChannel,
message: chunter.string.UnarchiveConfirm message: chunter.string.UnarchiveConfirm,
}, action: async () => {
undefined,
(result: boolean) => {
if (result) {
const client = getClient() const client = getClient()
await client.update(channel, { archived: false })
// eslint-disable-next-line @typescript-eslint/no-floating-promises
client.update(channel, { archived: false })
} }
} })
)
} }
async function ConvertDmToPrivateChannel (dm: DirectMessage): Promise<void> { async function ConvertDmToPrivateChannel (dm: DirectMessage): Promise<void> {

View File

@ -272,27 +272,18 @@ async function kickEmployee (doc: Person): Promise<void> {
if (accounts.length === 0) { if (accounts.length === 0) {
await client.update(employee, { active: false }) await client.update(employee, { active: false })
} else { } else {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: contact.string.KickEmployee, label: contact.string.KickEmployee,
message: contact.string.KickEmployeeDescr message: contact.string.KickEmployeeDescr,
}, action: async () => {
undefined, const leaveWorkspace = await getResource(login.function.LeaveWorkspace)
(res?: boolean) => {
if (res === true) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
const p = getResource(login.function.LeaveWorkspace)
for (const i of accounts) { for (const i of accounts) {
void p.then(async (f) => { await leaveWorkspace(i.email)
await f(i.email) }
}
}) })
} }
} }
}
)
}
}
async function openChannelURL (doc: Channel): Promise<void> { async function openChannelURL (doc: Channel): Promise<void> {
const url = parseURL(doc.value) const url = parseURL(doc.value)
if (url.startsWith('http://') || url.startsWith('https://')) { if (url.startsWith('http://') || url.startsWith('https://')) {

View File

@ -77,13 +77,15 @@
MessageBox, MessageBox,
{ {
label: guest.string.Revoke, label: guest.string.Revoke,
message: guest.string.RevokeConfirmation message: guest.string.RevokeConfirmation,
action: async () => {
if (link !== undefined) {
await client.remove(link)
}
}
}, },
'top', 'top',
(res) => { (res) => {
if (res === true && link !== undefined) {
client.remove(link)
}
dispatch('close') dispatch('close')
} }
) )

View File

@ -35,21 +35,16 @@ export async function addMember (client: TxOperations, employee?: Employee, valu
params: { params: {
current: current.name, current: current.name,
department: value.name department: value.name
},
action: async () => {
await client.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
department: value._id
})
} }
}, },
undefined, undefined,
(res?: boolean) => { (res?: boolean) => {
if (res === true && value !== undefined) {
void client
.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
department: value._id
})
.then(() => {
resolve(null) resolve(null)
})
} else {
resolve(null)
}
} }
) )
}) })

View File

@ -25,6 +25,8 @@ import {
isReactionMessage, isReactionMessage,
messageInFocus messageInFocus
} from '@hcengineering/activity-resources' } from '@hcengineering/activity-resources'
import { Analytics } from '@hcengineering/analytics'
import chunter, { type ThreadMessage } from '@hcengineering/chunter'
import core, { import core, {
SortingOrder, SortingOrder,
getCurrentAccount, getCurrentAccount,
@ -39,17 +41,18 @@ import notification, {
NotificationStatus, NotificationStatus,
notificationId, notificationId,
type ActivityInboxNotification, type ActivityInboxNotification,
type BaseNotificationType,
type Collaborators, type Collaborators,
type DisplayInboxNotification, type DisplayInboxNotification,
type DocNotifyContext, type DocNotifyContext,
type InboxNotification, type InboxNotification,
type MentionInboxNotification, type MentionInboxNotification,
type BaseNotificationType,
type NotificationProvider, type NotificationProvider,
type NotificationProviderSetting, type NotificationProviderSetting,
type NotificationTypeSetting type NotificationTypeSetting
} from '@hcengineering/notification' } from '@hcengineering/notification'
import { MessageBox, getClient, createQuery } from '@hcengineering/presentation' import { getMetadata } from '@hcengineering/platform'
import { MessageBox, createQuery, getClient } from '@hcengineering/presentation'
import { import {
getCurrentLocation, getCurrentLocation,
getLocation, getLocation,
@ -60,12 +63,9 @@ import {
type Location, type Location,
type ResolvedLocation type ResolvedLocation
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { get, writable } from 'svelte/store'
import chunter, { type ThreadMessage } from '@hcengineering/chunter'
import { getMetadata } from '@hcengineering/platform'
import { decodeObjectURI, encodeObjectURI, type LinkIdProvider } from '@hcengineering/view' import { decodeObjectURI, encodeObjectURI, type LinkIdProvider } from '@hcengineering/view'
import { getObjectLinkId } from '@hcengineering/view-resources' import { getObjectLinkId } from '@hcengineering/view-resources'
import { Analytics } from '@hcengineering/analytics' import { get, writable } from 'svelte/store'
import { InboxNotificationsClientImpl } from './inboxNotificationsClient' import { InboxNotificationsClientImpl } from './inboxNotificationsClient'
import { type InboxData, type InboxNotificationsFilter } from './types' import { type InboxData, type InboxNotificationsFilter } from './types'
@ -311,14 +311,12 @@ export async function archiveAll (): Promise<void> {
MessageBox, MessageBox,
{ {
label: notification.string.ArchiveAllConfirmationTitle, label: notification.string.ArchiveAllConfirmationTitle,
message: notification.string.ArchiveAllConfirmationMessage message: notification.string.ArchiveAllConfirmationMessage,
action: async () => {
await client.archiveAllNotifications()
}
}, },
'top', 'top'
(result?: boolean) => {
if (result === true) {
void client.archiveAllNotifications()
}
}
) )
} }

View File

@ -2,8 +2,9 @@
// Copyright @ 2024 Hardcore Engineering Inc. // Copyright @ 2024 Hardcore Engineering Inc.
// //
import type { Question } from '@hcengineering/questions' import { generateId } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import type { Question } from '@hcengineering/questions'
import { canUpdateQuestion, findNextQuestion, updateQuestion } from '../utils' import { canUpdateQuestion, findNextQuestion, updateQuestion } from '../utils'
import { focusActionWithAvailability } from './ActionWithAvailability' import { focusActionWithAvailability } from './ActionWithAvailability'
@ -20,7 +21,7 @@ export const questionMoveDownAction = focusActionWithAvailability<Question<unkno
if (nextQuestion === undefined) { if (nextQuestion === undefined) {
return return
} }
const ops = getClient().apply('down') const ops = getClient().apply(generateId() + 'down')
await updateQuestion(ops, object, { rank: nextQuestion.rank }) await updateQuestion(ops, object, { rank: nextQuestion.rank })
await updateQuestion(ops, nextQuestion, { rank: object.rank }) await updateQuestion(ops, nextQuestion, { rank: object.rank })
await ops.commit() await ops.commit()

View File

@ -2,8 +2,9 @@
// Copyright @ 2024 Hardcore Engineering Inc. // Copyright @ 2024 Hardcore Engineering Inc.
// //
import type { Question } from '@hcengineering/questions' import { generateId } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import type { Question } from '@hcengineering/questions'
import { canUpdateQuestion, findPreviousQuestion, updateQuestion } from '../utils' import { canUpdateQuestion, findPreviousQuestion, updateQuestion } from '../utils'
import { focusActionWithAvailability } from './ActionWithAvailability' import { focusActionWithAvailability } from './ActionWithAvailability'
@ -20,7 +21,7 @@ export const questionMoveUpAction = focusActionWithAvailability<Question<unknown
if (prevQuestion === undefined) { if (prevQuestion === undefined) {
return return
} }
const ops = getClient().apply('up') const ops = getClient().apply(generateId() + 'up')
await updateQuestion(ops, object, { rank: prevQuestion.rank }) await updateQuestion(ops, object, { rank: prevQuestion.rank })
await updateQuestion(ops, prevQuestion, { rank: object.rank }) await updateQuestion(ops, prevQuestion, { rank: object.rank })
await ops.commit() await ops.commit()

View File

@ -40,16 +40,16 @@
} from '@hcengineering/core' } from '@hcengineering/core'
import { getMetadata, getResource, setPlatformStatus, unknownError } from '@hcengineering/platform' import { getMetadata, getResource, setPlatformStatus, unknownError } from '@hcengineering/platform'
import presentation, { import presentation, {
FilePreviewPopup,
Card, Card,
createQuery, createQuery,
deleteFile,
DraftController, DraftController,
FilePreviewPopup,
getClient, getClient,
InlineAttributeBar, InlineAttributeBar,
KeyedAttribute, KeyedAttribute,
MessageBox, MessageBox,
MultipleDraftController, MultipleDraftController
deleteFile
} from '@hcengineering/presentation' } from '@hcengineering/presentation'
import { Candidate, CandidateDraft, RecruitEvents } from '@hcengineering/recruit' import { Candidate, CandidateDraft, RecruitEvents } from '@hcengineering/recruit'
import { recognizeDocument } from '@hcengineering/rekoni' import { recognizeDocument } from '@hcengineering/rekoni'
@ -65,14 +65,14 @@
IconAttachment, IconAttachment,
IconInfo, IconInfo,
Label, Label,
MiniToggle,
showPopup, showPopup,
Spinner, Spinner
MiniToggle
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { createEventDispatcher, onDestroy } from 'svelte' import { createEventDispatcher, onDestroy } from 'svelte'
import recruit from '../plugin' import recruit from '../plugin'
import YesNo from './YesNo.svelte'
import { getCandidateIdentifier } from '../utils' import { getCandidateIdentifier } from '../utils'
import YesNo from './YesNo.svelte'
export let shouldSaveDraft: boolean = true export let shouldSaveDraft: boolean = true
@ -523,9 +523,8 @@
] ]
} }
$: object.firstName && $: if (object.firstName != null && object.lastName != null) {
object.lastName && void findContacts(
findContacts(
client, client,
contact.class.Person, contact.class.Person,
combineName(object.firstName.trim(), object.lastName.trim()), combineName(object.firstName.trim(), object.lastName.trim()),
@ -534,6 +533,7 @@
matches = p.contacts matches = p.contacts
matchedChannels = p.channels matchedChannels = p.channels
}) })
}
const manager = createFocusManager() const manager = createFocusManager()
@ -542,13 +542,13 @@
fillDefaults(hierarchy, object, recruit.mixin.Candidate) fillDefaults(hierarchy, object, recruit.mixin.Candidate)
} }
export async function onOutsideClick () { export async function onOutsideClick (): Promise<void> {
if (shouldSaveDraft) { if (shouldSaveDraft) {
draftController.save(object, empty) draftController.save(object, empty)
} }
} }
async function showConfirmationDialog () { async function showConfirmationDialog (): Promise<void> {
draftController.save(object, empty) draftController.save(object, empty)
const isFormEmpty = draft === undefined const isFormEmpty = draft === undefined
@ -559,15 +559,17 @@
MessageBox, MessageBox,
{ {
label: recruit.string.CreateTalentDialogClose, label: recruit.string.CreateTalentDialogClose,
message: recruit.string.CreateTalentDialogCloseNote message: recruit.string.CreateTalentDialogCloseNote,
action: async () => {
await deleteResume()
resetObject()
draftController.remove()
}
}, },
'top', 'top',
(result?: boolean) => { (result?: boolean) => {
if (result === true) { if (result === true) {
dispatch('close') dispatch('close')
deleteResume()
resetObject()
draftController.remove()
} }
} }
) )

View File

@ -65,7 +65,7 @@
throw new Error(`create application: state not found space:${_space}`) throw new Error(`create application: state not found space:${_space}`)
} }
const op = client.apply('application.states') const op = client.apply(_space + 'application.states')
for (const a of selected) { for (const a of selected) {
await moveToSpace(op, a, _space, { status: selectedState._id }) await moveToSpace(op, a, _space, { status: selectedState._id })

View File

@ -86,15 +86,13 @@
MessageBox, MessageBox,
{ {
label: settings.string.DeleteAttribute, label: settings.string.DeleteAttribute,
message: exist ? settings.string.DeleteAttributeExistConfirm : settings.string.DeleteAttributeConfirm message: exist ? settings.string.DeleteAttributeExistConfirm : settings.string.DeleteAttributeConfirm,
}, action: async () => {
'top',
async (result) => {
if (result != null) {
await client.remove(attribute) await client.remove(attribute)
update() update()
} }
} },
'top'
) )
} }

View File

@ -55,20 +55,14 @@
const manager = createFocusManager() const manager = createFocusManager()
async function leave (): Promise<void> { async function leave (): Promise<void> {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: setting.string.Leave, label: setting.string.Leave,
message: setting.string.LeaveDescr message: setting.string.LeaveDescr,
}, action: async () => {
undefined,
async (res?: boolean) => {
if (res === true) {
const leaveWorkspace = await getResource(login.function.LeaveWorkspace) const leaveWorkspace = await getResource(login.function.LeaveWorkspace)
await leaveWorkspace(getCurrentAccount().email) await leaveWorkspace(getCurrentAccount().email)
} }
} })
)
} }
async function nameChange (): Promise<void> { async function nameChange (): Promise<void> {

View File

@ -98,14 +98,12 @@
MessageBox, MessageBox,
{ {
label: settingRes.string.DeleteRole, label: settingRes.string.DeleteRole,
message: settingRes.string.DeleteRoleConfirmation message: settingRes.string.DeleteRoleConfirmation,
action: async () => {
await performDeleteRole()
}
}, },
'top', 'top'
(result?: boolean) => {
if (result === true) {
void performDeleteRole()
}
}
) )
} }

View File

@ -29,63 +29,60 @@ import Privacy from './components/Privacy.svelte'
import Profile from './components/Profile.svelte' import Profile from './components/Profile.svelte'
import Settings from './components/Settings.svelte' import Settings from './components/Settings.svelte'
import { Analytics } from '@hcengineering/analytics'
import ClassAttributes from './components/ClassAttributes.svelte'
import ClassAttributesList from './components/ClassAttributesList.svelte'
import Configure from './components/Configure.svelte'
import IntegrationPanel from './components/IntegrationPanel.svelte'
import InviteSetting from './components/InviteSetting.svelte'
import PermissionPresenter from './components/presenters/PermissionPresenter.svelte'
import SpaceTypeDescriptorPresenter from './components/presenters/SpaceTypeDescriptorPresenter.svelte'
import Spaces from './components/Spaces.svelte'
import SpaceTypeGeneralSectionEditor from './components/spaceTypes/editor/SpaceTypeGeneralSectionEditor.svelte'
import SpaceTypePropertiesSectionEditor from './components/spaceTypes/editor/SpaceTypePropertiesSectionEditor.svelte'
import SpaceTypeRolesSectionEditor from './components/spaceTypes/editor/SpaceTypeRolesSectionEditor.svelte'
import ManageSpaceTypeContent from './components/spaceTypes/ManageSpaceTypeContent.svelte'
import ManageSpaceTypes from './components/spaceTypes/ManageSpaceTypes.svelte'
import ManageSpaceTypesTools from './components/spaceTypes/ManageSpaceTypesTools.svelte'
import RoleEditor from './components/spaceTypes/RoleEditor.svelte'
import Support from './components/Support.svelte' import Support from './components/Support.svelte'
import Terms from './components/Terms.svelte' import Terms from './components/Terms.svelte'
import ArrayEditor from './components/typeEditors/ArrayEditor.svelte'
import BooleanTypeEditor from './components/typeEditors/BooleanTypeEditor.svelte' import BooleanTypeEditor from './components/typeEditors/BooleanTypeEditor.svelte'
import DateTypeEditor from './components/typeEditors/DateTypeEditor.svelte' import DateTypeEditor from './components/typeEditors/DateTypeEditor.svelte'
import EnumTypeEditor from './components/typeEditors/EnumTypeEditor.svelte' import EnumTypeEditor from './components/typeEditors/EnumTypeEditor.svelte'
import HyperlinkTypeEditor from './components/typeEditors/HyperlinkTypeEditor.svelte' import HyperlinkTypeEditor from './components/typeEditors/HyperlinkTypeEditor.svelte'
import NumberTypeEditor from './components/typeEditors/NumberTypeEditor.svelte' import NumberTypeEditor from './components/typeEditors/NumberTypeEditor.svelte'
import ArrayEditor from './components/typeEditors/ArrayEditor.svelte'
import RefEditor from './components/typeEditors/RefEditor.svelte' import RefEditor from './components/typeEditors/RefEditor.svelte'
import RoleAssignmentEditor from './components/typeEditors/RoleAssignmentEditor.svelte'
import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte' import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte'
import WorkspaceSetting from './components/WorkspaceSetting.svelte' import WorkspaceSetting from './components/WorkspaceSetting.svelte'
import WorkspaceSettings from './components/WorkspaceSettings.svelte' import WorkspaceSettings from './components/WorkspaceSettings.svelte'
import InviteSetting from './components/InviteSetting.svelte'
import Configure from './components/Configure.svelte'
import Spaces from './components/Spaces.svelte'
import setting from './plugin' import setting from './plugin'
import IntegrationPanel from './components/IntegrationPanel.svelte' import { filterDescendants, getOwnerFirstName, getOwnerLastName, getOwnerPosition, getValue } from './utils'
import { getOwnerFirstName, getOwnerLastName, getOwnerPosition, getValue, filterDescendants } from './utils'
import ClassAttributes from './components/ClassAttributes.svelte'
import ClassAttributesList from './components/ClassAttributesList.svelte'
import ManageSpaceTypes from './components/spaceTypes/ManageSpaceTypes.svelte'
import ManageSpaceTypesTools from './components/spaceTypes/ManageSpaceTypesTools.svelte'
import ManageSpaceTypeContent from './components/spaceTypes/ManageSpaceTypeContent.svelte'
import PermissionPresenter from './components/presenters/PermissionPresenter.svelte'
import SpaceTypeDescriptorPresenter from './components/presenters/SpaceTypeDescriptorPresenter.svelte'
import SpaceTypeGeneralSectionEditor from './components/spaceTypes/editor/SpaceTypeGeneralSectionEditor.svelte'
import SpaceTypePropertiesSectionEditor from './components/spaceTypes/editor/SpaceTypePropertiesSectionEditor.svelte'
import SpaceTypeRolesSectionEditor from './components/spaceTypes/editor/SpaceTypeRolesSectionEditor.svelte'
import RoleEditor from './components/spaceTypes/RoleEditor.svelte'
import RoleAssignmentEditor from './components/typeEditors/RoleAssignmentEditor.svelte'
export { ClassSetting, filterDescendants, ClassAttributes, ClassAttributesList, SpaceTypeGeneralSectionEditor }
export * from './store' export * from './store'
export { ClassAttributes, ClassAttributesList, ClassSetting, filterDescendants, SpaceTypeGeneralSectionEditor }
async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> { async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> {
const docs = await getClient().findAll(object._id, {}, { limit: 1 }) const docs = await getClient().findAll(object._id, {}, { limit: 1 })
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: setting.string.DeleteMixin, label: setting.string.DeleteMixin,
message: docs.length > 0 ? setting.string.DeleteMixinExistConfirm : setting.string.DeleteMixinConfirm, message: docs.length > 0 ? setting.string.DeleteMixinExistConfirm : setting.string.DeleteMixinConfirm,
params: { count: docs.length } params: { count: docs.length },
}, action: async () => {
undefined,
(result?: boolean) => {
if (result === true) {
const objs = Array.isArray(object) ? object : [object] const objs = Array.isArray(object) ? object : [object]
for (const o of objs) { for (const o of objs) {
deleteObject(getClient(), o).catch((err) => { try {
console.error(err) await deleteObject(getClient(), o)
} catch (err: any) {
Analytics.handleError(err)
}
}
}
}) })
} }
}
}
)
}
export default async (): Promise<Resources> => ({ export default async (): Promise<Resources> => ({
component: { component: {

View File

@ -128,14 +128,12 @@
MessageBox, MessageBox,
{ {
label: timeRes.string.ReassignToDo, label: timeRes.string.ReassignToDo,
message: timeRes.string.ReassignToDoConfirm message: timeRes.string.ReassignToDoConfirm,
}, action: async () => {
'top',
async (result?: boolean) => {
if (result === true) {
await assignTodo(user) await assignTodo(user)
} }
} },
'top'
) )
} }
@ -144,14 +142,12 @@
MessageBox, MessageBox,
{ {
label: timeRes.string.UnassignToDo, label: timeRes.string.UnassignToDo,
message: timeRes.string.UnassignToDoConfirm message: timeRes.string.UnassignToDoConfirm,
}, action: async () => {
'top',
async (result?: boolean) => {
if (result === true) {
await unassignTodo() await unassignTodo()
} }
} },
'top'
) )
} }

View File

@ -30,24 +30,26 @@
const client = getClient() const client = getClient()
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
async function showConfirmationDialog () { async function showConfirmationDialog (): Promise<void> {
showPopup( showPopup(
MessageBox, MessageBox,
{ {
label: tracker.string.RemoveComponentDialogClose, label: tracker.string.RemoveComponentDialogClose,
message: tracker.string.RemoveComponentDialogCloseNote message: tracker.string.RemoveComponentDialogCloseNote,
action: async () => {
await removeComponent()
}
}, },
'top', 'top',
(result?: boolean) => { (result) => {
if (result === true) { if (result === true) {
dispatch('close') dispatch('close')
removeComponent()
} }
} }
) )
} }
async function removeComponent () { async function removeComponent (): Promise<void> {
await client.remove(value) await client.remove(value)
} }
</script> </script>

View File

@ -14,27 +14,27 @@
// //
import { Analytics } from '@hcengineering/analytics' import { Analytics } from '@hcengineering/analytics'
import chunter, { type ChatMessage } from '@hcengineering/chunter'
import core, { import core, {
AccountRole,
type AttachedDoc,
type Attribute, type Attribute,
type Class,
ClassifierKind, ClassifierKind,
type Client,
type Doc,
type DocManager,
type DocumentQuery,
DOMAIN_CONFIGURATION, DOMAIN_CONFIGURATION,
DOMAIN_MODEL, DOMAIN_MODEL,
getCurrentAccount, getCurrentAccount,
type Space,
toIdMap,
type AttachedDoc,
type Class,
type Client,
type Doc,
type DocumentQuery,
type Ref, type Ref,
type RelatedDocument, type RelatedDocument,
type TxOperations, type Space,
type DocManager, toIdMap,
AccountRole type TxOperations
} from '@hcengineering/core' } from '@hcengineering/core'
import chunter, { type ChatMessage } from '@hcengineering/chunter' import { type Resources, type Status, translate } from '@hcengineering/platform'
import { type Status, translate, type Resources } from '@hcengineering/platform'
import { getClient, MessageBox, type ObjectSearchResult } from '@hcengineering/presentation' import { getClient, MessageBox, type ObjectSearchResult } from '@hcengineering/presentation'
import { type Component, type Issue, type Milestone, type Project } from '@hcengineering/tracker' import { type Component, type Issue, type Milestone, type Project } from '@hcengineering/tracker'
import { closePanel, getCurrentLocation, navigate, showPopup, themeStore } from '@hcengineering/ui' import { closePanel, getCurrentLocation, navigate, showPopup, themeStore } from '@hcengineering/ui'
@ -55,11 +55,13 @@ import Inbox from './components/inbox/Inbox.svelte'
import AssigneeEditor from './components/issues/AssigneeEditor.svelte' import AssigneeEditor from './components/issues/AssigneeEditor.svelte'
import DueDatePresenter from './components/issues/DueDatePresenter.svelte' import DueDatePresenter from './components/issues/DueDatePresenter.svelte'
import EditIssue from './components/issues/edit/EditIssue.svelte' import EditIssue from './components/issues/edit/EditIssue.svelte'
import IssueExtra from './components/issues/IssueExtra.svelte'
import IssueItem from './components/issues/IssueItem.svelte' import IssueItem from './components/issues/IssueItem.svelte'
import IssuePresenter from './components/issues/IssuePresenter.svelte' import IssuePresenter from './components/issues/IssuePresenter.svelte'
import IssuePreview from './components/issues/IssuePreview.svelte' import IssuePreview from './components/issues/IssuePreview.svelte'
import Issues from './components/issues/Issues.svelte' import Issues from './components/issues/Issues.svelte'
import IssueSearchIcon from './components/issues/IssueSearchIcon.svelte' import IssueSearchIcon from './components/issues/IssueSearchIcon.svelte'
import IssueStatusPresenter from './components/issues/IssueStatusPresenter.svelte'
import IssuesView from './components/issues/IssuesView.svelte' import IssuesView from './components/issues/IssuesView.svelte'
import KanbanView from './components/issues/KanbanView.svelte' import KanbanView from './components/issues/KanbanView.svelte'
import ModificationDatePresenter from './components/issues/ModificationDatePresenter.svelte' import ModificationDatePresenter from './components/issues/ModificationDatePresenter.svelte'
@ -87,8 +89,6 @@ import SetDueDateActionPopup from './components/SetDueDateActionPopup.svelte'
import SetParentIssueActionPopup from './components/SetParentIssueActionPopup.svelte' import SetParentIssueActionPopup from './components/SetParentIssueActionPopup.svelte'
import SettingsRelatedTargets from './components/SettingsRelatedTargets.svelte' import SettingsRelatedTargets from './components/SettingsRelatedTargets.svelte'
import CreateIssueTemplate from './components/templates/CreateIssueTemplate.svelte' import CreateIssueTemplate from './components/templates/CreateIssueTemplate.svelte'
import IssueExtra from './components/issues/IssueExtra.svelte'
import IssueStatusPresenter from './components/issues/IssueStatusPresenter.svelte'
import { import {
getIssueIdByIdentifier, getIssueIdByIdentifier,
getIssueTitle, getIssueTitle,
@ -123,7 +123,7 @@ import ComponentSelector from './components/components/ComponentSelector.svelte'
import IssueTemplatePresenter from './components/templates/IssueTemplatePresenter.svelte' import IssueTemplatePresenter from './components/templates/IssueTemplatePresenter.svelte'
import IssueTemplates from './components/templates/IssueTemplates.svelte' import IssueTemplates from './components/templates/IssueTemplates.svelte'
import { deleteObject, deleteObjects, AggregationManager } from '@hcengineering/view-resources' import { AggregationManager, deleteObject, deleteObjects } from '@hcengineering/view-resources'
import MoveAndDeleteMilestonePopup from './components/milestones/MoveAndDeleteMilestonePopup.svelte' import MoveAndDeleteMilestonePopup from './components/milestones/MoveAndDeleteMilestonePopup.svelte'
import EditIssueTemplate from './components/templates/EditIssueTemplate.svelte' import EditIssueTemplate from './components/templates/EditIssueTemplate.svelte'
import TemplateEstimationEditor from './components/templates/EstimationEditor.svelte' import TemplateEstimationEditor from './components/templates/EstimationEditor.svelte'
@ -162,14 +162,14 @@ import ProjectSpacePresenter from './components/projects/ProjectSpacePresenter.s
import { get } from 'svelte/store' import { get } from 'svelte/store'
import contact, { AvatarType } from '@hcengineering/contact'
import { personAccountByIdStore, personAccountPersonByIdStore, personByIdStore } from '@hcengineering/contact-resources'
import notification, { type Collaborators } from '@hcengineering/notification'
import { settingId } from '@hcengineering/setting' import { settingId } from '@hcengineering/setting'
import task, { type TaskType } from '@hcengineering/task'
import { getAllStates } from '@hcengineering/task-resources' import { getAllStates } from '@hcengineering/task-resources'
import EstimationValueEditor from './components/issues/timereport/EstimationValueEditor.svelte' import EstimationValueEditor from './components/issues/timereport/EstimationValueEditor.svelte'
import TimePresenter from './components/issues/timereport/TimePresenter.svelte' import TimePresenter from './components/issues/timereport/TimePresenter.svelte'
import { personAccountByIdStore, personAccountPersonByIdStore, personByIdStore } from '@hcengineering/contact-resources'
import contact, { AvatarType } from '@hcengineering/contact'
import task, { type TaskType } from '@hcengineering/task'
import notification, { type Collaborators } from '@hcengineering/notification'
export { default as AssigneeEditor } from './components/issues/AssigneeEditor.svelte' export { default as AssigneeEditor } from './components/issues/AssigneeEditor.svelte'
export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte' export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte'
@ -250,28 +250,24 @@ async function deleteIssue (issue: Issue | Issue[]): Promise<void> {
} else { } else {
subissues = issue.subIssues subissues = issue.subIssues
} }
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: tracker.string.DeleteIssue, label: tracker.string.DeleteIssue,
labelProps: { issueCount }, labelProps: { issueCount },
message: tracker.string.DeleteIssueConfirm, message: tracker.string.DeleteIssueConfirm,
params: { params: {
issueCount, issueCount,
subIssueCount: subissues subIssueCount: subissues
}
}, },
undefined, action: async () => {
async (result?: boolean) => {
if (result === true) {
const objs = Array.isArray(issue) ? issue : [issue] const objs = Array.isArray(issue) ? issue : [issue]
await deleteObjects(getClient(), objs as unknown as Doc[]).catch((err) => { try {
console.error(err) await deleteObjects(getClient(), objs as unknown as Doc[])
}) } catch (err: any) {
Analytics.handleError(err)
}
closePanel() closePanel()
} }
} })
)
} }
async function deleteProject (project: Project | undefined): Promise<void> { async function deleteProject (project: Project | undefined): Promise<void> {
@ -280,16 +276,11 @@ async function deleteProject (project: Project | undefined): Promise<void> {
if (project.archived) { if (project.archived) {
// Clean project and all issues // Clean project and all issues
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: tracker.string.DeleteProject, label: tracker.string.DeleteProject,
labelProps: { name: project.name }, labelProps: { name: project.name },
message: tracker.string.ArchiveProjectConfirm message: tracker.string.ArchiveProjectConfirm,
}, action: async () => {
undefined,
async (result?: boolean) => {
if (result === true) {
// void client.update(project, { archived: true }) // void client.update(project, { archived: true })
const client = getClient() const client = getClient()
const classes = await client.findAll(core.class.Class, {}) const classes = await client.findAll(core.class.Class, {})
@ -306,7 +297,7 @@ async function deleteProject (project: Project | undefined): Promise<void> {
if (docs.length === 0) { if (docs.length === 0) {
break break
} }
const ops = client.apply('delete') const ops = client.apply('delete' + project._id)
for (const object of docs) { for (const object of docs) {
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) { if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc const adoc = object as AttachedDoc
@ -338,40 +329,27 @@ async function deleteProject (project: Project | undefined): Promise<void> {
} }
await client.remove(project) await client.remove(project)
} }
} })
)
} else { } else {
const anyIssue = await client.findOne(tracker.class.Issue, { space: project._id }) const anyIssue = await client.findOne(tracker.class.Issue, { space: project._id })
if (anyIssue !== undefined) { if (anyIssue !== undefined) {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: tracker.string.ArchiveProjectName, label: tracker.string.ArchiveProjectName,
labelProps: { name: project.name }, labelProps: { name: project.name },
message: tracker.string.ProjectHasIssues message: tracker.string.ProjectHasIssues,
}, action: async () => {
undefined, await client.update(project, { archived: true })
(result?: boolean) => {
if (result === true) {
void client.update(project, { archived: true })
} }
} })
)
} else { } else {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: tracker.string.ArchiveProjectName, label: tracker.string.ArchiveProjectName,
labelProps: { name: project.name }, labelProps: { name: project.name },
message: tracker.string.ArchiveProjectConfirm message: tracker.string.ArchiveProjectConfirm,
}, action: async () => {
undefined, await client.update(project, { archived: true })
(result?: boolean) => {
if (result === true) {
void client.update(project, { archived: true })
} }
} })
)
} }
} }
} }
@ -384,19 +362,14 @@ async function moveAndDeleteMilestones (
): Promise<void> { ): Promise<void> {
const noMilestoneLabel = await translate(tracker.string.NoMilestone, {}, get(themeStore).language) const noMilestoneLabel = await translate(tracker.string.NoMilestone, {}, get(themeStore).language)
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: tracker.string.MoveAndDeleteMilestone, label: tracker.string.MoveAndDeleteMilestone,
message: tracker.string.MoveAndDeleteMilestoneConfirm, message: tracker.string.MoveAndDeleteMilestoneConfirm,
labelProps: { labelProps: {
newMilestone: newMilestone?.label ?? noMilestoneLabel, newMilestone: newMilestone?.label ?? noMilestoneLabel,
deleteMilestone: oldMilestones.map((p) => p.label) deleteMilestone: oldMilestones.map((p) => p.label)
}
}, },
undefined, action: async () => {
(result?: boolean) => {
if (result === true) {
for (const oldMilestone of oldMilestones) { for (const oldMilestone of oldMilestones) {
void moveIssuesToAnotherMilestone(client, oldMilestone, newMilestone).then((success) => { void moveIssuesToAnotherMilestone(client, oldMilestone, newMilestone).then((success) => {
if (success) { if (success) {
@ -405,8 +378,7 @@ async function moveAndDeleteMilestones (
}) })
} }
} }
} })
)
} }
async function deleteMilestone (milestones: Milestone | Milestone[]): Promise<void> { async function deleteMilestone (milestones: Milestone | Milestone[]): Promise<void> {

View File

@ -454,19 +454,13 @@ function UpdateDocument (doc: Doc | Doc[], evt: Event, props: Record<string, any
} }
} }
if (props?.ask === true) { if (props?.ask === true) {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: props.label ?? view.string.LabelYes, label: props.label ?? view.string.LabelYes,
message: props.message ?? view.string.LabelYes message: props.message ?? view.string.LabelYes,
}, action: async () => {
undefined, await update()
(result: boolean) => {
if (result) {
void update()
} }
} })
)
} else { } else {
void update() void update()
} }

View File

@ -22,6 +22,7 @@ import core, {
Hierarchy, Hierarchy,
SortingOrder, SortingOrder,
TxProcessor, TxProcessor,
generateId,
getCurrentAccount, getCurrentAccount,
getObjectValue, getObjectValue,
type Account, type Account,
@ -582,7 +583,7 @@ export async function deleteObjects (client: TxOperations, objects: Doc[], skipC
} else { } else {
realObjects = objects realObjects = objects
} }
const ops = client.apply('delete') const ops = client.apply('delete' + generateId())
for (const object of realObjects) { for (const object of realObjects) {
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) { if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc const adoc = object as AttachedDoc

View File

@ -1887,7 +1887,7 @@ async function replaceCurrentAccount (
contact.class.Channel, contact.class.Channel,
contact.space.Contacts, contact.space.Contacts,
employee._id, employee._id,
contact.mixin.Employee, contact.class.Person,
'channels', 'channels',
{ {
provider: contact.channelProvider.Email, provider: contact.channelProvider.Email,
@ -1926,10 +1926,11 @@ async function createPersonAccount (
const currentAccount = await ops.findOne(contact.class.PersonAccount, {}) const currentAccount = await ops.findOne(contact.class.PersonAccount, {})
if (currentAccount !== undefined) { if (currentAccount !== undefined) {
await replaceCurrentAccount(ops, account, currentAccount, name) await replaceCurrentAccount(ops, account, currentAccount, name)
await ops.commit()
return return
} }
} }
const shouldCreateEmployee = roleOrder[role] >= roleOrder[AccountRole.User] const shouldCreateEmployee = roleOrder[role] >= roleOrder[AccountRole.Guest]
const existingAccount = await ops.findOne(contact.class.PersonAccount, { email: account.email }) const existingAccount = await ops.findOne(contact.class.PersonAccount, { email: account.email })
if (existingAccount === undefined) { if (existingAccount === undefined) {
let person: Ref<Person> | undefined let person: Ref<Person> | undefined

View File

@ -469,7 +469,7 @@ async function prepareMigrationClient (
return { migrateClient, migrateState } return { migrateClient, migrateState }
} }
async function fetchModelFromMongo ( export async function fetchModelFromMongo (
ctx: MeasureContext, ctx: MeasureContext,
mongodbUri: string, mongodbUri: string,
workspaceId: WorkspaceId, workspaceId: WorkspaceId,

View File

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { AttachedDoc, Ref, WithLookup } from '@hcengineering/core' import { AttachedDoc, Ref, WithLookup } from '@hcengineering/core'
import { GithubIntegration, GithubIntegrationRepository, GithubProject } from '@hcengineering/github'
import { getMetadata } from '@hcengineering/platform' import { getMetadata } from '@hcengineering/platform'
import presentation, { NavLink, getClient, isAdminUser } from '@hcengineering/presentation' import presentation, { NavLink, getClient, isAdminUser } from '@hcengineering/presentation'
import MessageBox from '@hcengineering/presentation/src/components/MessageBox.svelte' import MessageBox from '@hcengineering/presentation/src/components/MessageBox.svelte'
@ -19,7 +20,6 @@
showPopup showPopup
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { ObjectPresenter } from '@hcengineering/view-resources' import { ObjectPresenter } from '@hcengineering/view-resources'
import { GithubIntegration, GithubIntegrationRepository, GithubProject } from '@hcengineering/github'
import github from '../plugin' import github from '../plugin'
import ConnectProject from './ConnectProject.svelte' import ConnectProject from './ConnectProject.svelte'
import { githubLanguageColors } from './languageColors' import { githubLanguageColors } from './languageColors'
@ -85,21 +85,15 @@
}, },
{ total: true, limit: 1 } { total: true, limit: 1 }
) )
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: github.string.UnlinkRepository, label: github.string.UnlinkRepository,
message: github.string.UnlinkMessage, message: github.string.UnlinkMessage,
params: { repositoryName: repository.name, prjName: prj.name, total: issuesQuery.total }, params: { repositoryName: repository.name, prjName: prj.name, total: issuesQuery.total },
richMessage: true richMessage: true,
}, action: async () => {
undefined, await disconnect(prj, repository)
async (res) => {
if (res === true) {
void disconnect(prj, repository)
} }
} })
)
} }
$: repos = asRepos(integration.$lookup?.repositories ?? []) $: repos = asRepos(integration.$lookup?.repositories ?? [])
@ -165,24 +159,18 @@
kind={'dangerous'} kind={'dangerous'}
label={github.string.RemoveInstallation} label={github.string.RemoveInstallation}
on:click={() => { on:click={() => {
showPopup( showPopup(MessageBox, {
MessageBox,
{
label: github.string.UnlinkInstallationTitle, label: github.string.UnlinkInstallationTitle,
message: github.string.UnlinkInstallation, message: github.string.UnlinkInstallation,
params: {}, params: {},
richMessage: true richMessage: true,
}, action: async () => {
undefined,
async (res) => {
if (res !== null) {
await sendGHServiceRequest('installation-remove', { await sendGHServiceRequest('installation-remove', {
installationId: integration.installationId, installationId: integration.installationId,
token: getMetadata(presentation.metadata.Token) ?? '' token: getMetadata(presentation.metadata.Token) ?? ''
}) })
} }
} })
)
}} }}
/> />
</svelte:fragment> </svelte:fragment>

View File

@ -434,7 +434,7 @@ export class CommentSyncManager implements DocSyncManager {
project: GithubProject project: GithubProject
): Promise<void> { ): Promise<void> {
// No need to perform external sync for comments, so let's update marks // No need to perform external sync for comments, so let's update marks
const tx = derivedClient.apply('comments_github') const tx = derivedClient.apply('comments_github' + project._id)
for (const d of syncDocs) { for (const d of syncDocs) {
await tx.update(d, { externalVersion: githubExternalSyncVersion }) await tx.update(d, { externalVersion: githubExternalSyncVersion })
} }

View File

@ -402,7 +402,7 @@ export abstract class IssueSyncManagerBase {
return true return true
}) })
const updateTodos = this.client.apply('todos') const updateTodos = this.client.apply('todos' + account)
for (const [k, v] of Object.entries(todos)) { for (const [k, v] of Object.entries(todos)) {
await updateTodos.updateDoc(time.class.ToDo, time.space.ToDos, k as Ref<ToDo>, { await updateTodos.updateDoc(time.class.ToDo, time.space.ToDos, k as Ref<ToDo>, {
doneOn: v ? Date.now() : null doneOn: v ? Date.now() : null

View File

@ -1302,7 +1302,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
) )
} }
const tx = derivedClient.apply('pullrequests_github') const tx = derivedClient.apply('pullrequests_github' + prj._id)
for (const d of syncDocs) { for (const d of syncDocs) {
await tx.update(d, { derivedVersion: githubDerivedSyncVersion }) await tx.update(d, { derivedVersion: githubDerivedSyncVersion })
} }

View File

@ -560,7 +560,7 @@ export class ReviewCommentSyncManager implements DocSyncManager {
project: GithubProject project: GithubProject
): Promise<void> { ): Promise<void> {
// No need to perform external sync for reviews, so let's update marks // No need to perform external sync for reviews, so let's update marks
const tx = derivedClient.apply('reviews_github') const tx = derivedClient.apply('reviews_github' + project._id)
for (const d of syncDocs) { for (const d of syncDocs) {
await tx.update(d, { externalVersion: githubExternalSyncVersion }) await tx.update(d, { externalVersion: githubExternalSyncVersion })
} }

View File

@ -499,7 +499,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
): Promise<void> { ): Promise<void> {
if (kind === 'externalVersion') { if (kind === 'externalVersion') {
// No need to perform external sync for review threads, so let's update marks // No need to perform external sync for review threads, so let's update marks
const tx = derivedClient.apply('review_threads_github') const tx = derivedClient.apply('review_threads_github' + prj._id)
for (const d of syncDocs) { for (const d of syncDocs) {
await tx.update(d, { externalVersion: githubExternalSyncVersion }) await tx.update(d, { externalVersion: githubExternalSyncVersion })
} }
@ -545,7 +545,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
{ reviewThreadId: ext.id } { reviewThreadId: ext.id }
) )
} }
const tx = derivedClient.apply('reviewThread_github') const tx = derivedClient.apply('reviewThread_github' + prj._id)
for (const d of syncDocs) { for (const d of syncDocs) {
await tx.update(d, { derivedVersion: githubDerivedSyncVersion }) await tx.update(d, { derivedVersion: githubDerivedSyncVersion })
} }

View File

@ -473,7 +473,7 @@ export class ReviewSyncManager implements DocSyncManager {
project: GithubProject project: GithubProject
): Promise<void> { ): Promise<void> {
// No need to perform external sync for reviews, so let's update marks // No need to perform external sync for reviews, so let's update marks
const tx = derivedClient.apply('reviews_github') const tx = derivedClient.apply('reviews_github' + project._id)
for (const d of syncDocs) { for (const d of syncDocs) {
await tx.update(d, { externalVersion: githubExternalSyncVersion }) await tx.update(d, { externalVersion: githubExternalSyncVersion })
} }

View File

@ -299,7 +299,7 @@ export async function deleteObjects (
objects: Doc[], objects: Doc[],
account: Ref<Account> account: Ref<Account>
): Promise<void> { ): Promise<void> {
const ops = client.apply('delete') const ops = client.apply('delete' + account)
for (const object of objects) { for (const object of objects) {
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) { if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc const adoc = object as AttachedDoc