Delete object fix (#1093)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2022-03-04 15:02:13 +06:00 committed by GitHub
parent 25df15e34a
commit 748ad4d258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 128 additions and 40 deletions

View File

@ -76,8 +76,6 @@ export default mergeIds(taskId, task, {
KanbanTemplateTitle: '' as IntlString,
Rank: '' as IntlString,
EditStates: '' as IntlString,
Archive: '' as IntlString,
Unarchive: '' as IntlString,
MarkAsDone: '' as IntlString,
MarkAsUndone: '' as IntlString,
Kanban: '' as IntlString,

View File

@ -2,7 +2,7 @@
"status": {
"RequiredField": "Требуется заполнить {field}",
"FieldsDoNotMatch": "{field} не совпадает {field2}",
"ConnectingToServer": "Подключение к серверуConnecting to server....",
"ConnectingToServer": "Подключение к серверу....",
"IncorrectValue": "Неправильное значение {field}"
},
"string": {

View File

@ -22,6 +22,8 @@
"EnterNewPassword": "Enter new password",
"RepeatNewPassword": "Repeat new password",
"Signout": "Sign out",
"Settings": "Settings"
"Settings": "Settings",
"DeleteStatus": "Delete status",
"DeleteStatusConfirm": "Do you want to delete this status?"
}
}

View File

@ -22,6 +22,8 @@
"EnterNewPassword": "Введите новый пароль",
"RepeatNewPassword": "Повторите новый пароль",
"Signout": "Выйти",
"Settings": "Настройки"
"Settings": "Настройки",
"DeleteStatus": "Удаление статуса",
"DeleteStatusConfirm": "Вы действительно хотите удалить этот статус?"
}
}

View File

@ -19,7 +19,7 @@
import { getClient, MessageBox } from '@anticrm/presentation'
import { Label, Icon, showPopup, Component } from '@anticrm/ui'
import type { KanbanTemplate, KanbanTemplateSpace, StateTemplate } from '@anticrm/task'
import setting from '@anticrm/setting'
import setting from '../../plugin'
import task from '@anticrm/task'
import Folders from './Folders.svelte'
@ -40,8 +40,8 @@
}
showPopup(MessageBox, {
label: 'Delete status',
message: 'Do you want to delete this status?'
label: setting.string.DeleteStatus,
message: setting.string.DeleteStatusConfirm
}, undefined, async (result) => {
if (result && template !== undefined) {
await client.updateDoc(template._class, template.space, template._id, { $pull: { states: state._id } })

View File

@ -0,0 +1,25 @@
//
// Copyright © 2022 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { IntlString } from '@anticrm/platform'
import { mergeIds } from '@anticrm/platform'
import setting, { settingId } from '@anticrm/setting'
export default mergeIds(settingId, setting, {
string: {
DeleteStatus: '' as IntlString,
DeleteStatusConfirm: '' as IntlString
}
})

View File

@ -65,6 +65,12 @@
"SearchTask": "Search for task...",
"NoDoneState": "Not done",
"ManageStatusesWithin": "Manage application statuses within",
"ManageProjectStatues": "Manage project statues"
"ManageProjectStatues": "Manage project statues",
"UnarchiveConfirm": "Do you want to unarchive?",
"ArchiveConfirm": "Do you want to archive?",
"StatusDelete": "Delete status",
"StatusDeleteConfirm": "Do you want to delete this status?",
"CantStatusDelete": "Can't delete status",
"CantStatusDeleteError": "There are objects in the given state. Move or delete them first."
}
}

View File

@ -65,6 +65,12 @@
"SearchTask": "Поиск задачи...",
"NoDoneState": "Не завершено",
"ManageStatusesWithin": "Управление статусами для",
"ManageProjectStatues": "Управление статусами задачи"
"ManageProjectStatues": "Управление статусами задачи",
"UnarchiveConfirm": "Вы действительно хотите архивировать?",
"ArchiveConfirm": "Вы действительно хотите разархивировать?",
"StatusDelete": "Удалить статус",
"StatusDeleteConfirm": "Вы действительно хотите удалить этот статус?",
"CantStatusDelete": "Невозможно удалить статус",
"CantStatusDeleteError": "Есть объекты с данным статусом. Сначала переместите или удалите их. "
}
}

View File

@ -57,13 +57,13 @@
if (objectsInThisState.length > 0) {
showPopup(MessageBox, {
label: 'Can\'t delete status',
message: `There are ${objectsInThisState.length} objects in the given state. Move or delete them first.`
label: task.string.CantStatusDelete,
message: task.string.CantStatusDeleteError
})
} else {
showPopup(MessageBox, {
label: 'Delete status',
message: 'Do you want to delete this status?'
label: task.string.StatusDelete,
message: task.string.StatusDeleteConfirm
}, undefined, async (result) => {
if (result && kanban !== undefined) {
await client.updateDoc(kanban._class, kanban.space, kanban._id, { $pull: { states: state._id } })

View File

@ -15,14 +15,10 @@
//
import { Class, Client, Doc, Ref } from '@anticrm/core'
import login from '@anticrm/login'
import { getMetadata, IntlString, Resources, translate } from '@anticrm/platform'
import { IntlString, Resources, translate } from '@anticrm/platform'
import { getClient, MessageBox, ObjectSearchResult } from '@anticrm/presentation'
import { Issue, SpaceWithStates, Task, TodoItem } from '@anticrm/task'
import task from './plugin'
import { SpaceWithStates, Task, TodoItem } from '@anticrm/task'
import { showPopup } from '@anticrm/ui'
import view from '@anticrm/view'
import workbench from '@anticrm/workbench'
import CreateProject from './components/CreateProject.svelte'
import CreateTask from './components/CreateTask.svelte'
import EditIssue from './components/EditIssue.svelte'
@ -43,6 +39,7 @@ import TemplatesIcon from './components/TemplatesIcon.svelte'
import TodoItemPresenter from './components/todos/TodoItemPresenter.svelte'
import Todos from './components/todos/Todos.svelte'
import TodoStatePresenter from './components/todos/TodoStatePresenter.svelte'
import task from './plugin'
async function createTask (object: Doc): Promise<void> {
showPopup(CreateTask, { parent: object._id, space: object.space })
@ -60,8 +57,8 @@ async function ArchiveSpace (object: SpaceWithStates): Promise<void> {
showPopup(
MessageBox,
{
label: 'Archive',
message: `Do you want to archive ${object.name}?`
label: task.string.Archive,
message: task.string.ArchiveConfirm
},
undefined,
(result: boolean) => {
@ -79,8 +76,8 @@ async function UnarchiveSpace (object: SpaceWithStates): Promise<void> {
showPopup(
MessageBox,
{
label: 'Unarchive',
message: `Do you want to unarchive ${object.name}?`
label: task.string.Unarchive,
message: task.string.UnarchiveConfirm
},
undefined,
(result: boolean) => {

View File

@ -59,7 +59,15 @@ export default mergeIds(taskId, task, {
DoneStatesLost: '' as IntlString,
AllStates: '' as IntlString,
NoDoneState: '' as IntlString,
ManageStatusesWithin: '' as IntlString
ManageStatusesWithin: '' as IntlString,
ArchiveConfirm: '' as IntlString,
UnarchiveConfirm: '' as IntlString,
StatusDeleteConfirm: '' as IntlString,
StatusDelete: '' as IntlString,
CantStatusDelete: '' as IntlString,
CantStatusDeleteError: '' as IntlString,
Archive: '' as IntlString,
Unarchive: '' as IntlString
},
status: {
AssigneeRequired: '' as IntlString

View File

@ -10,6 +10,8 @@
"LabelNA": "N/A",
"ChooseAColor": "Choose a color",
"Table": "Table",
"Role": "Role"
"Role": "Role",
"DeleteObject": "Delete object",
"DeleteObjectConfirm": "Do you want to delete this object?"
}
}

View File

@ -2,7 +2,7 @@
"string": {
"MoveClass": "Переместить {class}",
"SelectToMove": "Выберите {classLabel} который вы хотите переместить в {class}.",
"Delete": "Удалть",
"Delete": "Удалить",
"Move": "Переместить",
"Cancel": "Отменть",
"LabelYes": "Да",
@ -10,6 +10,8 @@
"LabelNA": "Н/Д",
"ChooseAColor": "Выбрать цвет",
"Table": "Таблица",
"Role": "Роль"
"Role": "Роль",
"DeleteObject": "Удалить объект",
"DeleteObjectConfirm": "Вы действительно хотите удалить этот объект?"
}
}

View File

@ -35,6 +35,7 @@ import RolePresenter from './components/RolePresenter.svelte'
import ObjectPresenter from './components/ObjectPresenter.svelte'
import HTMLPresenter from './components/HTMLPresenter.svelte'
import ColorsPopup from './components/ColorsPopup.svelte'
import view from './plugin'
export { default as ContextMenu } from './components/Menu.svelte'
export { buildModel, getActions, getObjectPresenter, LoadingProps, getCollectionCounter } from './utils'
@ -44,8 +45,8 @@ function Delete (object: Doc): void {
showPopup(
MessageBox,
{
label: 'Delete object',
message: 'Do you want to delete this object?'
label: view.string.DeleteObject,
message: view.string.DeleteObjectConfirm
},
undefined,
(result?: boolean) => {

View File

@ -26,6 +26,8 @@ export default mergeIds(viewId, view, {
LabelYes: '' as IntlString,
LabelNo: '' as IntlString,
LabelNA: '' as IntlString,
ChooseAColor: '' as IntlString
ChooseAColor: '' as IntlString,
DeleteObject: '' as IntlString,
DeleteObjectConfirm: '' as IntlString
}
})

View File

@ -17,6 +17,7 @@
import core, {
AttachedDoc,
Class,
ClassifierKind,
Client,
Collection,
Doc,
@ -24,6 +25,7 @@ import core, {
Hierarchy,
Lookup,
matchQuery,
Mixin,
Obj,
Ref,
TxOperations
@ -213,7 +215,26 @@ export async function getActions (
export async function deleteObject (client: TxOperations, object: Doc): Promise<void> {
const hierarchy = client.getHierarchy()
const attributes = hierarchy.getAllAttributes(object._class)
const promises: Promise<any>[] = []
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
promises.push(client.removeCollection(object._class, object.space, adoc._id, adoc.attachedTo, adoc.attachedToClass, adoc.collection).catch(err => console.error(err)))
} else {
promises.push(client.removeDoc(object._class, object.space, object._id).catch(err => console.error(err)))
}
promises.push(deleteClassCollections(client, object._class, object))
const mixins = getMixins(hierarchy, object._class, object)
for (const mixin of mixins) {
promises.push(deleteClassCollections(client, mixin, object))
}
promises.push(deleteRelatedDocuments(hierarchy, object, client))
await Promise.all(promises)
}
async function deleteClassCollections (client: TxOperations, _class: Ref<Class<Doc>>, object: Doc): Promise<void> {
const hierarchy = client.getHierarchy()
const attributes = hierarchy.getAllAttributes(_class)
for (const [name, attribute] of attributes) {
if (hierarchy.isDerived(attribute.type._class, core.class.Collection)) {
const collection = attribute.type as Collection<AttachedDoc>
@ -223,15 +244,31 @@ export async function deleteObject (client: TxOperations, object: Doc): Promise<
}
}
}
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
await client.removeCollection(object._class, object.space, adoc._id, adoc.attachedTo, adoc.attachedToClass, adoc.collection).catch(err => console.error(err))
} else {
await client.removeDoc(object._class, object.space, object._id).catch(err => console.error(err))
}
await deleteRelatedDocuments(hierarchy, object, client)
}
function getParentClass (hierarchy: Hierarchy, _class: Ref<Class<Doc>>): Ref<Class<Doc>> {
const baseDomain = hierarchy.getDomain(_class)
const ancestors = hierarchy.getAncestors(_class)
let result: Ref<Class<Doc>> = _class
for (const ancestor of ancestors) {
try {
const domain = hierarchy.getClass(ancestor).domain
if (domain === baseDomain) {
result = ancestor
}
} catch {}
}
return result
}
function getMixins (hierarchy: Hierarchy, _class: Ref<Class<Doc>>, object: Doc): Ref<Mixin<Doc>>[] {
const parentClass = getParentClass(hierarchy, _class)
const descendants = hierarchy.getDescendants(parentClass)
return descendants.filter(
(m) => hierarchy.getClass(m).kind === ClassifierKind.MIXIN && hierarchy.hasMixin(object, m)
)
}
async function deleteRelatedDocuments (hierarchy: Hierarchy, object: Doc, client: TxOperations): Promise<void> {
const objectClass = hierarchy.getClass(object._class)
if (hierarchy.hasMixin(objectClass, view.mixin.ObjectDDParticipant)) {