diff --git a/models/core/src/core.ts b/models/core/src/core.ts index b2528193da..b77aa69d48 100644 --- a/models/core/src/core.ts +++ b/models/core/src/core.ts @@ -173,6 +173,10 @@ export class TType extends TObj implements Type { @Model(core.class.TypeString, core.class.Type) export class TTypeString extends TType {} +@UX(core.string.String) +@Model(core.class.TypeRecord, core.class.Type) +export class TTypeRecord extends TType {} + @UX(core.string.String) @Model(core.class.TypeAttachment, core.class.Type) export class TTypeAttachment extends TType {} diff --git a/models/core/src/index.ts b/models/core/src/index.ts index 053f24b3f1..3ba714548b 100644 --- a/models/core/src/index.ts +++ b/models/core/src/index.ts @@ -55,6 +55,7 @@ import { TTypeIntlString, TTypeMarkup, TTypeNumber, + TTypeRecord, TTypeRelatedDocument, TTypeString, TTypeTimestamp, @@ -113,6 +114,7 @@ export function createModel (builder: Builder): void { TTypeNumber, TTypeBoolean, TTypeString, + TTypeRecord, TTypeAttachment, TTypeHyperlink, TCollection, diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index e894ad03c7..2b41cf917d 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -1221,6 +1221,26 @@ export function createModel (builder: Builder): void { }, tracker.action.DeleteProject ) + createAction( + builder, + { + action: tracker.actionImpl.DeleteProject, + label: workbench.string.Delete, + icon: view.icon.Delete, + input: 'focus', + category: tracker.category.Tracker, + target: tracker.class.Project, + query: { + archived: true + }, + context: { + mode: ['context', 'browser'], + group: 'edit' + }, + override: [view.action.Archive, view.action.Delete] + }, + tracker.action.DeleteProjectClean + ) createAction(builder, { label: tracker.string.Unarchive, icon: view.icon.Archive, diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index ba025becad..c52a3cb162 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -89,6 +89,7 @@ export default mergeIds(trackerId, tracker, { NewRelatedIssue: '' as Ref>>, DeleteMilestone: '' as Ref>>, DeleteProject: '' as Ref>>, + DeleteProjectClean: '' as Ref>>, DeleteIssue: '' as Ref>> } }) diff --git a/packages/theme/styles/components.scss b/packages/theme/styles/components.scss index c67f841c40..3d712d641d 100644 --- a/packages/theme/styles/components.scss +++ b/packages/theme/styles/components.scss @@ -288,6 +288,7 @@ grid-auto-rows: minmax(12.5rem, auto); grid-gap: 1.5rem; padding: 3rem; + overflow: auto ; } &__space-3 { flex-shrink: 0; diff --git a/plugins/contact-resources/src/components/DeleteConfirmationPopup.svelte b/plugins/contact-resources/src/components/DeleteConfirmationPopup.svelte index e180f7fff3..42c8aebc48 100644 --- a/plugins/contact-resources/src/components/DeleteConfirmationPopup.svelte +++ b/plugins/contact-resources/src/components/DeleteConfirmationPopup.svelte @@ -22,6 +22,7 @@ import ui, { Button, Label } from '@hcengineering/ui' import PersonAccountRefPresenter from './PersonAccountRefPresenter.svelte' import PersonAccountPresenter from './PersonAccountPresenter.svelte' + import { ObjectPresenter } from '@hcengineering/view-resources' export let object: Doc | Doc[] export let deleteAction: () => void @@ -53,6 +54,9 @@ {#if canDelete}
{:else}
diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 82cba7b83e..0771eecd93 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -180,6 +180,7 @@ "DeleteProject": "Delete project", "ArchiveProjectName": "Archive project {name}?", "ArchiveProjectConfirm": "Do you want to archive this project?", + "DeleteProjectConfirm": "Do you want to delete this project and all issues?", "ProjectHasIssues": "There are existing issues in this project, are you sure that you want to archive?", "ManageWorkflowStatuses": "Manage issue statuses within project", "AddWorkflowStatus": "Add issue status", diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json index 064501f218..356c3a22ca 100644 --- a/plugins/tracker-assets/lang/ru.json +++ b/plugins/tracker-assets/lang/ru.json @@ -180,6 +180,7 @@ "DeleteProject": "Удалить проект", "ArchiveProjectName": "Архивировать проект {name}?", "ArchiveProjectConfirm": "Вы действительно хотите заархивировать этот проект?", + "DeleteProjectConfirm": "Вы действительно хотите удалить этот проект со всем содержимым?", "ProjectHasIssues": "Для данного проекта существуют задачи, уверены, что хотите заархивировать?", "ManageWorkflowStatuses": "Управлять статусами задач для команды", "AddWorkflowStatus": "Добавить статус задачи", diff --git a/plugins/tracker-resources/src/index.ts b/plugins/tracker-resources/src/index.ts index bec49268bb..57237a1be8 100644 --- a/plugins/tracker-resources/src/index.ts +++ b/plugins/tracker-resources/src/index.ts @@ -13,11 +13,14 @@ // limitations under the License. // -import { +import core, { + AttachedDoc, Class, + ClassifierKind, Client, Doc, DocumentQuery, + DOMAIN_MODEL, getCurrentAccount, Ref, RelatedDocument, @@ -29,6 +32,7 @@ import { getClient, MessageBox, ObjectSearchResult } from '@hcengineering/presen import { Issue, Milestone, Project } from '@hcengineering/tracker' import { showPopup, themeStore } from '@hcengineering/ui' import ComponentEditor from './components/components/ComponentEditor.svelte' +import ComponentFilterValuePresenter from './components/components/ComponentFilterValuePresenter.svelte' import ComponentPresenter from './components/components/ComponentPresenter.svelte' import ComponentRefPresenter from './components/components/ComponentRefPresenter.svelte' import Components from './components/components/Components.svelte' @@ -66,7 +70,6 @@ import MyIssues from './components/myissues/MyIssues.svelte' import NewIssueHeader from './components/NewIssueHeader.svelte' import NopeComponent from './components/NopeComponent.svelte' import ProjectFilterValuePresenter from './components/projects/ProjectFilterValuePresenter.svelte' -import ComponentFilterValuePresenter from './components/components/ComponentFilterValuePresenter.svelte' import RelationsPopup from './components/RelationsPopup.svelte' import SetDueDateActionPopup from './components/SetDueDateActionPopup.svelte' import SetParentIssueActionPopup from './components/SetParentIssueActionPopup.svelte' @@ -141,7 +144,7 @@ import { get } from 'svelte/store' export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte' export { default as IssueStatusIcon } from './components/issues/IssueStatusIcon.svelte' -export { IssuePresenter, TitlePresenter, CreateProject } +export { CreateProject, IssuePresenter, TitlePresenter } export async function queryIssue ( _class: Ref>, @@ -251,37 +254,93 @@ async function deleteIssue (issue: Issue | Issue[]): Promise { async function deleteProject (project: Project | undefined): Promise { if (project !== undefined) { const client = getClient() - const anyIssue = await client.findOne(tracker.class.Issue, { space: project._id }) - if (anyIssue !== undefined) { + + if (project.archived) { + // Clean project and all issues 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 }) - } - } - ) - } else { - showPopup( - MessageBox, - { - label: tracker.string.ArchiveProjectName, + label: tracker.string.DeleteProject, labelProps: { name: project.name }, message: tracker.string.ArchiveProjectConfirm }, undefined, - (result?: boolean) => { + async (result?: boolean) => { if (result === true) { - void client.update(project, { archived: 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) { + 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) => console.error(err)) + } + } + await ops.commit() + } + } + } + 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 }) + } + } + ) + } 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 }) + } + } + ) + } } } } diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index 473ac1797f..8f5e2a7e08 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -113,6 +113,7 @@ export default mergeIds(trackerId, tracker, { DeleteIssueConfirm: '' as IntlString, ArchiveProjectName: '' as IntlString, ArchiveProjectConfirm: '' as IntlString, + DeleteProjectConfirm: '' as IntlString, ProjectHasIssues: '' as IntlString, ManageWorkflowStatuses: '' as IntlString, AddWorkflowStatus: '' as IntlString,