UBERF-7959: Fix async issues (#6409)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-08-28 13:51:20 +07:00 committed by GitHub
parent c2d0aad760
commit 4cce003364
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 338 additions and 424 deletions

View File

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

View File

@ -13,115 +13,101 @@
// 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 { type Resources } from '@hcengineering/platform'
import { MessageBox, getClient } from '@hcengineering/presentation'
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 ChunterBrowser from './components/chat/specials/ChunterBrowser.svelte'
import ConvertDmToPrivateChannelModal from './components/ConvertDmToPrivateChannel.svelte'
import ChannelPresenter from './components/ChannelPresenter.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 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 DmPresenter from './components/DmPresenter.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 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 {
ChannelTitleProvider,
DirectTitleProvider,
canCopyMessageLink,
canDeleteMessage,
canReplyToThread,
dmIdentifierProvider,
getDmName,
getTitle,
getUnreadThreadsCount,
canCopyMessageLink,
leaveChannelAction,
removeChannelAction,
canReplyToThread
removeChannelAction
} 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 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 ThreadView } from './components/threads/ThreadView.svelte'
export async function ArchiveChannel (channel: Channel, evt: any, afterArchive?: () => void): Promise<void> {
showPopup(
MessageBox,
{
label: chunter.string.ArchiveChannel,
message: chunter.string.ArchiveConfirm
},
undefined,
(result: boolean) => {
if (result) {
const client = getClient()
showPopup(MessageBox, {
label: chunter.string.ArchiveChannel,
message: chunter.string.ArchiveConfirm,
action: async () => {
const client = getClient()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
client.update(channel, { archived: true })
if (afterArchive != null) afterArchive()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
await client.update(channel, { archived: true })
if (afterArchive != null) afterArchive()
const loc = getLocation()
if (loc.path[3] === channel._id) {
loc.path.length = 3
navigate(loc)
}
const loc = getLocation()
if (loc.path[3] === channel._id) {
loc.path.length = 3
navigate(loc)
}
}
)
})
}
async function UnarchiveChannel (channel: Channel): Promise<void> {
showPopup(
MessageBox,
{
label: chunter.string.UnarchiveChannel,
message: chunter.string.UnarchiveConfirm
},
undefined,
(result: boolean) => {
if (result) {
const client = getClient()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
client.update(channel, { archived: false })
}
showPopup(MessageBox, {
label: chunter.string.UnarchiveChannel,
message: chunter.string.UnarchiveConfirm,
action: async () => {
const client = getClient()
await client.update(channel, { archived: false })
}
)
})
}
async function ConvertDmToPrivateChannel (dm: DirectMessage): Promise<void> {

View File

@ -272,25 +272,16 @@ async function kickEmployee (doc: Person): Promise<void> {
if (accounts.length === 0) {
await client.update(employee, { active: false })
} else {
showPopup(
MessageBox,
{
label: contact.string.KickEmployee,
message: contact.string.KickEmployeeDescr
},
undefined,
(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) {
void p.then(async (f) => {
await f(i.email)
})
}
showPopup(MessageBox, {
label: contact.string.KickEmployee,
message: contact.string.KickEmployeeDescr,
action: async () => {
const leaveWorkspace = await getResource(login.function.LeaveWorkspace)
for (const i of accounts) {
await leaveWorkspace(i.email)
}
}
)
})
}
}
async function openChannelURL (doc: Channel): Promise<void> {

View File

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

View File

@ -35,21 +35,16 @@ export async function addMember (client: TxOperations, employee?: Employee, valu
params: {
current: current.name,
department: value.name
},
action: async () => {
await client.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
department: value._id
})
}
},
undefined,
(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)
})
} else {
resolve(null)
}
resolve(null)
}
)
})

View File

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

View File

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

View File

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

View File

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

View File

@ -65,7 +65,7 @@
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) {
await moveToSpace(op, a, _space, { status: selectedState._id })

View File

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

View File

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

View File

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

View File

@ -29,62 +29,59 @@ import Privacy from './components/Privacy.svelte'
import Profile from './components/Profile.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 Terms from './components/Terms.svelte'
import ArrayEditor from './components/typeEditors/ArrayEditor.svelte'
import BooleanTypeEditor from './components/typeEditors/BooleanTypeEditor.svelte'
import DateTypeEditor from './components/typeEditors/DateTypeEditor.svelte'
import EnumTypeEditor from './components/typeEditors/EnumTypeEditor.svelte'
import HyperlinkTypeEditor from './components/typeEditors/HyperlinkTypeEditor.svelte'
import NumberTypeEditor from './components/typeEditors/NumberTypeEditor.svelte'
import ArrayEditor from './components/typeEditors/ArrayEditor.svelte'
import RefEditor from './components/typeEditors/RefEditor.svelte'
import RoleAssignmentEditor from './components/typeEditors/RoleAssignmentEditor.svelte'
import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte'
import WorkspaceSetting from './components/WorkspaceSetting.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 IntegrationPanel from './components/IntegrationPanel.svelte'
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'
import { filterDescendants, getOwnerFirstName, getOwnerLastName, getOwnerPosition, getValue } from './utils'
export { ClassSetting, filterDescendants, ClassAttributes, ClassAttributesList, SpaceTypeGeneralSectionEditor }
export * from './store'
export { ClassAttributes, ClassAttributesList, ClassSetting, filterDescendants, SpaceTypeGeneralSectionEditor }
async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> {
const docs = await getClient().findAll(object._id, {}, { limit: 1 })
showPopup(
MessageBox,
{
label: setting.string.DeleteMixin,
message: docs.length > 0 ? setting.string.DeleteMixinExistConfirm : setting.string.DeleteMixinConfirm,
params: { count: docs.length }
},
undefined,
(result?: boolean) => {
if (result === true) {
const objs = Array.isArray(object) ? object : [object]
for (const o of objs) {
deleteObject(getClient(), o).catch((err) => {
console.error(err)
})
showPopup(MessageBox, {
label: setting.string.DeleteMixin,
message: docs.length > 0 ? setting.string.DeleteMixinExistConfirm : setting.string.DeleteMixinConfirm,
params: { count: docs.length },
action: async () => {
const objs = Array.isArray(object) ? object : [object]
for (const o of objs) {
try {
await deleteObject(getClient(), o)
} catch (err: any) {
Analytics.handleError(err)
}
}
}
)
})
}
export default async (): Promise<Resources> => ({

View File

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

View File

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

View File

@ -14,27 +14,27 @@
//
import { Analytics } from '@hcengineering/analytics'
import chunter, { type ChatMessage } from '@hcengineering/chunter'
import core, {
AccountRole,
type AttachedDoc,
type Attribute,
type Class,
ClassifierKind,
type Client,
type Doc,
type DocManager,
type DocumentQuery,
DOMAIN_CONFIGURATION,
DOMAIN_MODEL,
getCurrentAccount,
type Space,
toIdMap,
type AttachedDoc,
type Class,
type Client,
type Doc,
type DocumentQuery,
type Ref,
type RelatedDocument,
type TxOperations,
type DocManager,
AccountRole
type Space,
toIdMap,
type TxOperations
} from '@hcengineering/core'
import chunter, { type ChatMessage } from '@hcengineering/chunter'
import { type Status, translate, type Resources } from '@hcengineering/platform'
import { type Resources, type Status, translate } from '@hcengineering/platform'
import { getClient, MessageBox, type ObjectSearchResult } from '@hcengineering/presentation'
import { type Component, type Issue, type Milestone, type Project } from '@hcengineering/tracker'
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 DueDatePresenter from './components/issues/DueDatePresenter.svelte'
import EditIssue from './components/issues/edit/EditIssue.svelte'
import IssueExtra from './components/issues/IssueExtra.svelte'
import IssueItem from './components/issues/IssueItem.svelte'
import IssuePresenter from './components/issues/IssuePresenter.svelte'
import IssuePreview from './components/issues/IssuePreview.svelte'
import Issues from './components/issues/Issues.svelte'
import IssueSearchIcon from './components/issues/IssueSearchIcon.svelte'
import IssueStatusPresenter from './components/issues/IssueStatusPresenter.svelte'
import IssuesView from './components/issues/IssuesView.svelte'
import KanbanView from './components/issues/KanbanView.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 SettingsRelatedTargets from './components/SettingsRelatedTargets.svelte'
import CreateIssueTemplate from './components/templates/CreateIssueTemplate.svelte'
import IssueExtra from './components/issues/IssueExtra.svelte'
import IssueStatusPresenter from './components/issues/IssueStatusPresenter.svelte'
import {
getIssueIdByIdentifier,
getIssueTitle,
@ -123,7 +123,7 @@ import ComponentSelector from './components/components/ComponentSelector.svelte'
import IssueTemplatePresenter from './components/templates/IssueTemplatePresenter.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 EditIssueTemplate from './components/templates/EditIssueTemplate.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 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 task, { type TaskType } from '@hcengineering/task'
import { getAllStates } from '@hcengineering/task-resources'
import EstimationValueEditor from './components/issues/timereport/EstimationValueEditor.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 SubIssueList } from './components/issues/edit/SubIssueList.svelte'
@ -250,28 +250,24 @@ async function deleteIssue (issue: Issue | Issue[]): Promise<void> {
} else {
subissues = issue.subIssues
}
showPopup(
MessageBox,
{
label: tracker.string.DeleteIssue,
labelProps: { issueCount },
message: tracker.string.DeleteIssueConfirm,
params: {
issueCount,
subIssueCount: subissues
}
showPopup(MessageBox, {
label: tracker.string.DeleteIssue,
labelProps: { issueCount },
message: tracker.string.DeleteIssueConfirm,
params: {
issueCount,
subIssueCount: subissues
},
undefined,
async (result?: boolean) => {
if (result === true) {
const objs = Array.isArray(issue) ? issue : [issue]
await deleteObjects(getClient(), objs as unknown as Doc[]).catch((err) => {
console.error(err)
})
closePanel()
action: async () => {
const objs = Array.isArray(issue) ? issue : [issue]
try {
await deleteObjects(getClient(), objs as unknown as Doc[])
} catch (err: any) {
Analytics.handleError(err)
}
closePanel()
}
)
})
}
async function deleteProject (project: Project | undefined): Promise<void> {
@ -280,98 +276,80 @@ async function deleteProject (project: Project | undefined): Promise<void> {
if (project.archived) {
// Clean project and all issues
showPopup(
MessageBox,
{
label: tracker.string.DeleteProject,
labelProps: { name: project.name },
message: tracker.string.ArchiveProjectConfirm
},
undefined,
async (result?: boolean) => {
if (result === true) {
// void client.update(project, { archived: true })
const client = getClient()
const classes = await client.findAll(core.class.Class, {})
const h = client.getHierarchy()
for (const c of classes) {
if (c.kind !== ClassifierKind.CLASS) {
continue
}
const d = h.findDomain(c._id)
if (d !== undefined && d !== DOMAIN_MODEL && d !== DOMAIN_CONFIGURATION) {
try {
while (true) {
const docs = await client.findAll(c._id, { space: project._id }, { limit: 50 })
if (docs.length === 0) {
break
}
const ops = client.apply('delete')
for (const object of docs) {
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
await ops
.removeCollection(
object._class,
object.space,
adoc._id,
adoc.attachedTo,
adoc.attachedToClass,
adoc.collection
)
.catch((err) => {
console.error(err)
})
} else {
await ops.removeDoc(object._class, object.space, object._id).catch((err) => {
showPopup(MessageBox, {
label: tracker.string.DeleteProject,
labelProps: { name: project.name },
message: tracker.string.ArchiveProjectConfirm,
action: async () => {
// void client.update(project, { archived: true })
const client = getClient()
const classes = await client.findAll(core.class.Class, {})
const h = client.getHierarchy()
for (const c of classes) {
if (c.kind !== ClassifierKind.CLASS) {
continue
}
const d = h.findDomain(c._id)
if (d !== undefined && d !== DOMAIN_MODEL && d !== DOMAIN_CONFIGURATION) {
try {
while (true) {
const docs = await client.findAll(c._id, { space: project._id }, { limit: 50 })
if (docs.length === 0) {
break
}
const ops = client.apply('delete' + project._id)
for (const object of docs) {
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
await ops
.removeCollection(
object._class,
object.space,
adoc._id,
adoc.attachedTo,
adoc.attachedToClass,
adoc.collection
)
.catch((err) => {
console.error(err)
})
}
} else {
await ops.removeDoc(object._class, object.space, object._id).catch((err) => {
console.error(err)
})
}
await ops.commit()
}
} catch (err: any) {
console.error(err)
Analytics.handleError(err)
await ops.commit()
}
} catch (err: any) {
console.error(err)
Analytics.handleError(err)
}
}
await client.remove(project)
}
await client.remove(project)
}
)
})
} else {
const anyIssue = await client.findOne(tracker.class.Issue, { space: project._id })
if (anyIssue !== undefined) {
showPopup(
MessageBox,
{
label: tracker.string.ArchiveProjectName,
labelProps: { name: project.name },
message: tracker.string.ProjectHasIssues
},
undefined,
(result?: boolean) => {
if (result === true) {
void client.update(project, { archived: true })
}
showPopup(MessageBox, {
label: tracker.string.ArchiveProjectName,
labelProps: { name: project.name },
message: tracker.string.ProjectHasIssues,
action: async () => {
await client.update(project, { archived: true })
}
)
})
} else {
showPopup(
MessageBox,
{
label: tracker.string.ArchiveProjectName,
labelProps: { name: project.name },
message: tracker.string.ArchiveProjectConfirm
},
undefined,
(result?: boolean) => {
if (result === true) {
void client.update(project, { archived: true })
}
showPopup(MessageBox, {
label: tracker.string.ArchiveProjectName,
labelProps: { name: project.name },
message: tracker.string.ArchiveProjectConfirm,
action: async () => {
await client.update(project, { archived: true })
}
)
})
}
}
}
@ -384,29 +362,23 @@ async function moveAndDeleteMilestones (
): Promise<void> {
const noMilestoneLabel = await translate(tracker.string.NoMilestone, {}, get(themeStore).language)
showPopup(
MessageBox,
{
label: tracker.string.MoveAndDeleteMilestone,
message: tracker.string.MoveAndDeleteMilestoneConfirm,
labelProps: {
newMilestone: newMilestone?.label ?? noMilestoneLabel,
deleteMilestone: oldMilestones.map((p) => p.label)
}
showPopup(MessageBox, {
label: tracker.string.MoveAndDeleteMilestone,
message: tracker.string.MoveAndDeleteMilestoneConfirm,
labelProps: {
newMilestone: newMilestone?.label ?? noMilestoneLabel,
deleteMilestone: oldMilestones.map((p) => p.label)
},
undefined,
(result?: boolean) => {
if (result === true) {
for (const oldMilestone of oldMilestones) {
void moveIssuesToAnotherMilestone(client, oldMilestone, newMilestone).then((success) => {
if (success) {
void deleteObject(client, oldMilestone)
}
})
}
action: async () => {
for (const oldMilestone of oldMilestones) {
void moveIssuesToAnotherMilestone(client, oldMilestone, newMilestone).then((success) => {
if (success) {
void deleteObject(client, oldMilestone)
}
})
}
}
)
})
}
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) {
showPopup(
MessageBox,
{
label: props.label ?? view.string.LabelYes,
message: props.message ?? view.string.LabelYes
},
undefined,
(result: boolean) => {
if (result) {
void update()
}
showPopup(MessageBox, {
label: props.label ?? view.string.LabelYes,
message: props.message ?? view.string.LabelYes,
action: async () => {
await update()
}
)
})
} else {
void update()
}

View File

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

View File

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

View File

@ -434,7 +434,7 @@ export class CommentSyncManager implements DocSyncManager {
project: GithubProject
): Promise<void> {
// 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) {
await tx.update(d, { externalVersion: githubExternalSyncVersion })
}

View File

@ -402,7 +402,7 @@ export abstract class IssueSyncManagerBase {
return true
})
const updateTodos = this.client.apply('todos')
const updateTodos = this.client.apply('todos' + account)
for (const [k, v] of Object.entries(todos)) {
await updateTodos.updateDoc(time.class.ToDo, time.space.ToDos, k as Ref<ToDo>, {
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) {
await tx.update(d, { derivedVersion: githubDerivedSyncVersion })
}

View File

@ -560,7 +560,7 @@ export class ReviewCommentSyncManager implements DocSyncManager {
project: GithubProject
): Promise<void> {
// 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) {
await tx.update(d, { externalVersion: githubExternalSyncVersion })
}

View File

@ -499,7 +499,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
): Promise<void> {
if (kind === 'externalVersion') {
// 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) {
await tx.update(d, { externalVersion: githubExternalSyncVersion })
}
@ -545,7 +545,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
{ reviewThreadId: ext.id }
)
}
const tx = derivedClient.apply('reviewThread_github')
const tx = derivedClient.apply('reviewThread_github' + prj._id)
for (const d of syncDocs) {
await tx.update(d, { derivedVersion: githubDerivedSyncVersion })
}

View File

@ -473,7 +473,7 @@ export class ReviewSyncManager implements DocSyncManager {
project: GithubProject
): Promise<void> {
// 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) {
await tx.update(d, { externalVersion: githubExternalSyncVersion })
}

View File

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