diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index ff44708cae..9e38179ee3 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -74,6 +74,7 @@ specifiers: '@rush-temp/model-server-notification': file:./projects/model-server-notification.tgz '@rush-temp/model-server-recruit': file:./projects/model-server-recruit.tgz '@rush-temp/model-server-setting': file:./projects/model-server-setting.tgz + '@rush-temp/model-server-tags': file:./projects/model-server-tags.tgz '@rush-temp/model-server-task': file:./projects/model-server-task.tgz '@rush-temp/model-setting': file:./projects/model-setting.tgz '@rush-temp/model-tags': file:./projects/model-tags.tgz @@ -116,6 +117,8 @@ specifiers: '@rush-temp/server-recruit-resources': file:./projects/server-recruit-resources.tgz '@rush-temp/server-setting': file:./projects/server-setting.tgz '@rush-temp/server-setting-resources': file:./projects/server-setting-resources.tgz + '@rush-temp/server-tags': file:./projects/server-tags.tgz + '@rush-temp/server-tags-resources': file:./projects/server-tags-resources.tgz '@rush-temp/server-task': file:./projects/server-task.tgz '@rush-temp/server-task-resources': file:./projects/server-task-resources.tgz '@rush-temp/server-token': file:./projects/server-token.tgz @@ -321,6 +324,7 @@ dependencies: '@rush-temp/model-server-notification': file:projects/model-server-notification.tgz_typescript@4.5.4 '@rush-temp/model-server-recruit': file:projects/model-server-recruit.tgz_typescript@4.5.4 '@rush-temp/model-server-setting': file:projects/model-server-setting.tgz_typescript@4.5.4 + '@rush-temp/model-server-tags': file:projects/model-server-tags.tgz_typescript@4.5.4 '@rush-temp/model-server-task': file:projects/model-server-task.tgz_typescript@4.5.4 '@rush-temp/model-setting': file:projects/model-setting.tgz_typescript@4.5.4 '@rush-temp/model-tags': file:projects/model-tags.tgz_typescript@4.5.4 @@ -363,6 +367,8 @@ dependencies: '@rush-temp/server-recruit-resources': file:projects/server-recruit-resources.tgz '@rush-temp/server-setting': file:projects/server-setting.tgz '@rush-temp/server-setting-resources': file:projects/server-setting-resources.tgz + '@rush-temp/server-tags': file:projects/server-tags.tgz + '@rush-temp/server-tags-resources': file:projects/server-tags-resources.tgz '@rush-temp/server-task': file:projects/server-task.tgz '@rush-temp/server-task-resources': file:projects/server-task-resources.tgz '@rush-temp/server-token': file:projects/server-token.tgz @@ -12416,7 +12422,7 @@ packages: dev: false file:projects/model-all.tgz_typescript@4.5.4: - resolution: {integrity: sha512-LprNHSPgySvlj/zl9bkeSZ7Uh1wWyPPkQBW6knjBBD3cizpFpxPGBrSQnhDe/RP0uj6azKRYWWUcAPFOYe4TvQ==, tarball: file:projects/model-all.tgz} + resolution: {integrity: sha512-CTYZ52iBQ2S06DVd6jUK+PHCpgLDvO7lrujkMWxCO3RUn+77uyDZBGK43n+7UF1HZNSHvYAhyA8fBTvp1kOylw==, tarball: file:projects/model-all.tgz} id: file:projects/model-all.tgz name: '@rush-temp/model-all' version: 0.0.0 @@ -12901,6 +12907,27 @@ packages: - typescript dev: false + file:projects/model-server-tags.tgz_typescript@4.5.4: + resolution: {integrity: sha512-TYTWiR2rFc1OE3D4m0DpKSridJKWeLfJmpK0SB0+6ibWEFUu+f9Yhs5N7j3/w1UMGKbSZ5Ere6PYVMTP3fTT5g==, tarball: file:projects/model-server-tags.tgz} + id: file:projects/model-server-tags.tgz + name: '@rush-temp/model-server-tags' + version: 0.0.0 + dependencies: + '@rushstack/heft': 0.41.8 + '@types/heft-jest': 1.0.2 + '@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237 + '@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4 + eslint: 7.32.0 + eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a + eslint-plugin-import: 2.25.3_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 5.2.0_eslint@7.32.0 + prettier: 2.5.1 + transitivePeerDependencies: + - supports-color + - typescript + dev: false + file:projects/model-server-task.tgz_typescript@4.5.4: resolution: {integrity: sha512-U7EJ1CuyupONpf97J8SfeRZT07aBNFQ3R1Wlyv7ssR6V8W4pkfjazFsfFA//pWh8ot5oWUy+8wccF7Q8TjkJWQ==, tarball: file:projects/model-server-task.tgz} id: file:projects/model-server-task.tgz @@ -13367,7 +13394,7 @@ packages: dev: false file:projects/prod.tgz_a07ec81d4d975778878ca12202ea119e: - resolution: {integrity: sha512-mxkGGtPp108JHMkmnEgKKPNVrihu3xVv1wZqY/HTWhZ+v8Ct5RG92+Yg6NBhEsLmqCBBPTAHY/JapGi1oF9bWg==, tarball: file:projects/prod.tgz} + resolution: {integrity: sha512-HHCNzvjIf/tNB1Wr5Fk4HGuoP66fHONafJd6DPh4kpTC7T8Vc5Y/UlneWS3cUjhCsB9jgYejEbu1Osp0DPXCZA==, tarball: file:projects/prod.tgz} id: file:projects/prod.tgz name: '@rush-temp/prod' version: 0.0.0 @@ -13897,6 +13924,47 @@ packages: - supports-color dev: false + file:projects/server-tags-resources.tgz: + resolution: {integrity: sha512-XrVBmPPIJCLM2reTQorx5k+xtwc6pJApXeVSksk+DeP2+lVHQBIcJwRLUHkRNBVn7kU571mw6F6J6JvCSkYhJQ==, tarball: file:projects/server-tags-resources.tgz} + name: '@rush-temp/server-tags-resources' + version: 0.0.0 + dependencies: + '@rushstack/heft': 0.41.8 + '@types/heft-jest': 1.0.2 + '@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237 + '@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4 + eslint: 7.32.0 + eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a + eslint-plugin-import: 2.25.3_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 5.2.0_eslint@7.32.0 + prettier: 2.5.1 + typescript: 4.5.4 + transitivePeerDependencies: + - supports-color + dev: false + + file:projects/server-tags.tgz: + resolution: {integrity: sha512-iDt1UvOkk+mT3l2/R0MFjgNHnGnZztfW5nuD39yeMoTIihWIfxOTO4PBCnu3dNtRL+2xIlU4pADEdyDp9AS3lg==, tarball: file:projects/server-tags.tgz} + name: '@rush-temp/server-tags' + version: 0.0.0 + dependencies: + '@rushstack/heft': 0.41.8 + '@types/heft-jest': 1.0.2 + '@types/node': 16.11.14 + '@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237 + '@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4 + eslint: 7.32.0 + eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a + eslint-plugin-import: 2.25.3_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 5.2.0_eslint@7.32.0 + prettier: 2.5.1 + typescript: 4.5.4 + transitivePeerDependencies: + - supports-color + dev: false + file:projects/server-task-resources.tgz: resolution: {integrity: sha512-OHpVWSAp1YyQ1LqJoXGRzqA8yY1BXZ5xI/P+fLUi5nk3Pz4a82H+YGw/FsNBuPWG4U25Hnnwopzl0trIXIB9jQ==, tarball: file:projects/server-task-resources.tgz} name: '@rush-temp/server-task-resources' @@ -14017,7 +14085,7 @@ packages: dev: false file:projects/server.tgz: - resolution: {integrity: sha512-1nC7oRGVjZGZ8I5tviFWIAu6++qbQ6k450Fe0fhi45pxMPuclCotH+NSS789RRpj2AhtiaghrpBZdc3CtgZOUw==, tarball: file:projects/server.tgz} + resolution: {integrity: sha512-Gx/PoIoObAiRX21Fo+Z/y7tqqgHW8URVudDz8azH/0hW25pRfR03xPw7oR0GsuF2IBZ4S8nyH1U2HSPpE76W7g==, tarball: file:projects/server.tgz} name: '@rush-temp/server' version: 0.0.0 dependencies: @@ -14536,7 +14604,7 @@ packages: dev: false file:projects/tool.tgz: - resolution: {integrity: sha512-HzyyP6uYXNTmHkn7FiZJ3vf6Oq7KzAGYWsul1AT8B54rJqZ4mTZtBhnRGdVBqEmNIUNO2Ukr5ywdvAhJfDj+Mg==, tarball: file:projects/tool.tgz} + resolution: {integrity: sha512-F3Px6/29RVwqI/G3FsImf5dKvi53Tz7R/LSRyeG81NIN0WMGEsuOB6iWE9GD8PS/W7qSnKsFC8+VWVvJN+gVeQ==, tarball: file:projects/tool.tgz} name: '@rush-temp/tool' version: 0.0.0 dependencies: diff --git a/dev/prod/package.json b/dev/prod/package.json index dc2c4e2a2e..86a72ecbd9 100644 --- a/dev/prod/package.json +++ b/dev/prod/package.json @@ -118,6 +118,8 @@ "@anticrm/server-lead-resources": "~0.6.0", "@anticrm/server-recruit": "~0.6.0", "@anticrm/server-recruit-resources": "~0.6.0", + "@anticrm/server-tags": "~0.6.0", + "@anticrm/server-tags-resources": "~0.6.0", "@anticrm/server-task": "~0.6.0", "@anticrm/server-task-resources": "~0.6.0", "@anticrm/calendar": "~0.6.0", diff --git a/dev/prod/src/platform-dev.ts b/dev/prod/src/platform-dev.ts index a2b5c40087..08da1ea233 100644 --- a/dev/prod/src/platform-dev.ts +++ b/dev/prod/src/platform-dev.ts @@ -26,6 +26,7 @@ import { serverInventoryId } from '@anticrm/server-inventory' import { serverLeadId } from '@anticrm/server-lead' import { serverRecruitId } from '@anticrm/server-recruit' import { serverTaskId } from '@anticrm/server-task' +import { serverTagsId } from '@anticrm/server-tags' import { setMetadata } from '@anticrm/platform' @@ -47,6 +48,7 @@ export function configurePlatformDev() { addLocation(serverLeadId, () => import(/* webpackChunkName: "server-lead" */ '@anticrm/server-lead-resources')) addLocation(serverRecruitId, () => import(/* webpackChunkName: "server-recruit" */ '@anticrm/server-recruit-resources')) addLocation(serverTaskId, () => import/* webpackChunkName: "server-task" */ ('@anticrm/server-task-resources')) + addLocation(serverTagsId, () => import/* webpackChunkName: "server-tags" */ ('@anticrm/server-tags-resources')) // Set devmodel to hook client to be able to present all activity enableDevModel() } diff --git a/dev/tool/package.json b/dev/tool/package.json index e6d537fed0..fea308fbfa 100644 --- a/dev/tool/package.json +++ b/dev/tool/package.json @@ -90,6 +90,8 @@ "@anticrm/server-recruit-resources": "~0.6.0", "@anticrm/server-task": "~0.6.0", "@anticrm/server-task-resources": "~0.6.0", + "@anticrm/server-tags": "~0.6.0", + "@anticrm/server-tags-resources": "~0.6.0", "@anticrm/rekoni": "~0.6.0", "request": "~2.88.2", "@anticrm/tags": "~0.6.0" diff --git a/dev/tool/src/elastic.ts b/dev/tool/src/elastic.ts index 2503f50b29..fadf20af95 100644 --- a/dev/tool/src/elastic.ts +++ b/dev/tool/src/elastic.ts @@ -56,6 +56,7 @@ import { serverInventoryId } from '@anticrm/server-inventory' import { serverLeadId } from '@anticrm/server-lead' import { serverRecruitId } from '@anticrm/server-recruit' import { serverTaskId } from '@anticrm/server-task' +import { serverTagsId } from '@anticrm/server-tags' import { Client as ElasticClient } from '@elastic/elasticsearch' import { Client } from 'minio' import { Db, MongoClient } from 'mongodb' @@ -118,6 +119,7 @@ export class ElasticTool { addLocation(serverRecruitId, () => import(/* webpackChunkName: "server-recruit" */ '@anticrm/server-recruit-resources')) addLocation(serverSettingId, () => import(/* webpackChunkName: "server-recruit" */ '@anticrm/server-setting-resources')) addLocation(serverTaskId, () => import/* webpackChunkName: "server-task" */ ('@anticrm/server-task-resources')) + addLocation(serverTagsId, () => import/* webpackChunkName: "server-tags" */ ('@anticrm/server-tags-resources')) this.mongoClient = new MongoClient(mongoUrl) } diff --git a/models/all/package.json b/models/all/package.json index 5a277c9331..e7694ff482 100644 --- a/models/all/package.json +++ b/models/all/package.json @@ -49,6 +49,7 @@ "@anticrm/model-server-setting": "~0.6.0", "@anticrm/model-server-chunter": "~0.6.0", "@anticrm/model-server-task": "~0.6.0", + "@anticrm/model-server-tags": "~0.6.0", "@anticrm/model-server-recruit": "~0.6.0", "@anticrm/model-server-lead": "~0.6.0", "@anticrm/model-server-inventory": "~0.6.0", diff --git a/models/all/src/index.ts b/models/all/src/index.ts index 1719d755c3..49740bac49 100644 --- a/models/all/src/index.ts +++ b/models/all/src/index.ts @@ -35,6 +35,7 @@ import { createModel as serverChunterModel } from '@anticrm/model-server-chunter import { createModel as serverInventoryModel } from '@anticrm/model-server-inventory' import { createModel as serverLeadModel } from '@anticrm/model-server-lead' import { createModel as serverTaskModel } from '@anticrm/model-server-task' +import { createModel as serverTagsModel } from '@anticrm/model-server-tags' import { createModel as serveSettingModel } from '@anticrm/model-server-setting' import { createModel as serverRecruitModel } from '@anticrm/model-server-recruit' import { createModel as serverCoreModel } from '@anticrm/model-server-core' @@ -82,6 +83,7 @@ const builders = [ serverChunterModel, serverInventoryModel, serverLeadModel, + serverTagsModel, serverTaskModel, serverRecruitModel, createDemo diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index ed442b326b..3403035c74 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -18,12 +18,11 @@ import type { Backlink, Channel, Comment, Message } from '@anticrm/chunter' import type { Class, Doc, Domain, Ref } from '@anticrm/core' import { IndexKind } from '@anticrm/core' import { Builder, Collection, Index, Model, Prop, TypeMarkup, UX } from '@anticrm/model' +import attachment from '@anticrm/model-attachment' import core, { TAttachedDoc, TDoc, TSpace } from '@anticrm/model-core' import view from '@anticrm/model-view' import workbench from '@anticrm/model-workbench' -import { ObjectDDParticipant } from '@anticrm/view' import chunter from './plugin' -import attachment from '@anticrm/model-attachment' export const DOMAIN_CHUNTER = 'chunter' as Domain export const DOMAIN_COMMENT = 'comment' as Domain @@ -104,10 +103,6 @@ export function createModel (builder: Builder): void { presenter: chunter.component.CommentPresenter }) - builder.mixin, ObjectDDParticipant>(chunter.class.Comment, core.class.Class, view.mixin.ObjectDDParticipant, { - collectDocs: chunter.action.CommentRemove - }) - builder.createDoc(activity.class.TxViewlet, core.space.Model, { objectClass: chunter.class.Comment, icon: chunter.icon.Chunter, diff --git a/models/chunter/src/plugin.ts b/models/chunter/src/plugin.ts index cb15c5e319..d41ab378e6 100644 --- a/models/chunter/src/plugin.ts +++ b/models/chunter/src/plugin.ts @@ -16,8 +16,8 @@ import type { TxViewlet } from '@anticrm/activity' import { Channel, chunterId } from '@anticrm/chunter' import chunter from '@anticrm/chunter-resources/src/plugin' -import type { Doc, Ref, TxOperations } from '@anticrm/core' -import type { IntlString, Resource } from '@anticrm/platform' +import type { Ref } from '@anticrm/core' +import type { IntlString } from '@anticrm/platform' import { mergeIds } from '@anticrm/platform' import type { AnyComponent } from '@anticrm/ui' import type { ViewletDescriptor } from '@anticrm/view' @@ -53,8 +53,5 @@ export default mergeIds(chunterId, chunter, { space: { General: '' as Ref, Random: '' as Ref - }, - action: { - CommentRemove: '' as Resource<(doc: Doc, client: TxOperations) => Promise> } }) diff --git a/models/server-chunter/src/index.ts b/models/server-chunter/src/index.ts index 327c76ef22..e7c487fe7c 100644 --- a/models/server-chunter/src/index.ts +++ b/models/server-chunter/src/index.ts @@ -15,9 +15,10 @@ import { Builder } from '@anticrm/model' -import core from '@anticrm/core' +import core, { Class, Doc } from '@anticrm/core' import chunter from '@anticrm/chunter' import view from '@anticrm/view' +import serverCore, { ObjectDDParticipant } from '@anticrm/server-core' import serverChunter from '@anticrm/server-chunter' export function createModel (builder: Builder): void { @@ -28,4 +29,8 @@ export function createModel (builder: Builder): void { builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.TextPresenter, { presenter: serverChunter.function.ChannelTextPresenter }) + + builder.mixin, ObjectDDParticipant>(chunter.class.Comment, core.class.Class, serverCore.mixin.ObjectDDParticipant, { + collectDocs: serverChunter.function.CommentRemove + }) } diff --git a/models/server-core/src/index.ts b/models/server-core/src/index.ts index 957f507858..9841f1eadc 100644 --- a/models/server-core/src/index.ts +++ b/models/server-core/src/index.ts @@ -16,10 +16,10 @@ import { Model, Builder } from '@anticrm/model' import type { Resource } from '@anticrm/platform' -import { TDoc } from '@anticrm/model-core' +import { TClass, TDoc } from '@anticrm/model-core' -import type { Trigger, TriggerFunc } from '@anticrm/server-core' -import core, { DOMAIN_MODEL } from '@anticrm/core' +import type { ObjectDDParticipant, Trigger, TriggerFunc } from '@anticrm/server-core' +import core, { Class, Doc, DocumentQuery, DOMAIN_MODEL, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core' import serverCore from '@anticrm/server-core' @Model(serverCore.class.Trigger, core.class.Doc, DOMAIN_MODEL) @@ -27,6 +27,11 @@ export class TTrigger extends TDoc implements Trigger { trigger!: Resource } -export function createModel (builder: Builder): void { - builder.createModel(TTrigger) +@Model(serverCore.mixin.ObjectDDParticipant, core.class.Class) +export class TObjectDDParticipant extends TClass implements ObjectDDParticipant { + collectDocs!: Resource<(doc: Doc, hiearachy: Hierarchy, findAll: (clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise>) => Promise> +} + +export function createModel (builder: Builder): void { + builder.createModel(TTrigger, TObjectDDParticipant) } diff --git a/models/server-tags/.eslintrc.js b/models/server-tags/.eslintrc.js new file mode 100644 index 0000000000..c3c2c49417 --- /dev/null +++ b/models/server-tags/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@anticrm/model-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/models/server-tags/.npmignore b/models/server-tags/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/models/server-tags/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/models/server-tags/config/rig.json b/models/server-tags/config/rig.json new file mode 100644 index 0000000000..e9a9ee9add --- /dev/null +++ b/models/server-tags/config/rig.json @@ -0,0 +1,18 @@ +// The "rig.json" file directs tools to look for their config files in an external package. +// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "@anticrm/model-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/models/server-tags/package.json b/models/server-tags/package.json new file mode 100644 index 0000000000..538180312a --- /dev/null +++ b/models/server-tags/package.json @@ -0,0 +1,35 @@ +{ + "name": "@anticrm/model-server-tags", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "build:watch": "tsc", + "lint:fix": "eslint --fix src", + "lint": "eslint src", + "format": "prettier --write src && eslint --fix src" + }, + "devDependencies": { + "@anticrm/model-rig": "~0.6.0", + "@typescript-eslint/eslint-plugin": "^5.4.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-promise": "^5.1.1", + "eslint-plugin-node": "^11.1.0", + "eslint": "^7.32.0", + "@types/heft-jest": "^1.0.2", + "@typescript-eslint/parser": "^5.4.0", + "eslint-config-standard-with-typescript": "^21.0.1", + "prettier": "^2.4.1", + "@rushstack/heft": "^0.41.1" + }, + "dependencies": { + "@anticrm/core": "~0.6.16", + "@anticrm/model": "~0.6.0", + "@anticrm/platform": "~0.6.5", + "@anticrm/server-tags": "~0.6.0", + "@anticrm/server-core": "~0.6.1", + "@anticrm/tags": "~0.6.0" + } +} diff --git a/models/server-tags/src/index.ts b/models/server-tags/src/index.ts new file mode 100644 index 0000000000..52396589b6 --- /dev/null +++ b/models/server-tags/src/index.ts @@ -0,0 +1,26 @@ +// +// 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 core, { Class, Doc } from '@anticrm/core' +import { Builder } from '@anticrm/model' +import serverCore, { ObjectDDParticipant } from '@anticrm/server-core' +import serverTags from '@anticrm/server-tags' +import tags from '@anticrm/tags' + +export function createModel (builder: Builder): void { + builder.mixin, ObjectDDParticipant>(tags.class.TagElement, core.class.Class, serverCore.mixin.ObjectDDParticipant, { + collectDocs: serverTags.function.TagElementRemove + }) +} diff --git a/models/server-tags/tsconfig.json b/models/server-tags/tsconfig.json new file mode 100644 index 0000000000..1d60db76b4 --- /dev/null +++ b/models/server-tags/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./node_modules/@anticrm/model-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + } +} \ No newline at end of file diff --git a/models/tags/src/index.ts b/models/tags/src/index.ts index c6bed58ea3..f4acc0a3d9 100644 --- a/models/tags/src/index.ts +++ b/models/tags/src/index.ts @@ -15,14 +15,14 @@ import { Class, Doc, Domain, IndexKind, Ref } from '@anticrm/core' import { Builder, Collection, Index, Model, Prop, TypeRef, TypeString, UX } from '@anticrm/model' import core, { TAttachedDoc, TDoc } from '@anticrm/model-core' -import view, { ObjectDDParticipant } from '@anticrm/model-view' +import view from '@anticrm/model-view' import { Asset, IntlString } from '@anticrm/platform' import type { TagCategory, TagElement, TagReference } from '@anticrm/tags' import tags from './plugin' +export { TagCategory, TagElement, TagReference } from '@anticrm/tags' export { tagsOperation } from './migration' export { tags as default } -export { TagElement, TagReference, TagCategory } from '@anticrm/tags' export const DOMAIN_TAGS = 'tags' as Domain @@ -94,7 +94,4 @@ export function createModel (builder: Builder): void { builder.mixin(tags.class.TagElement, core.class.Class, view.mixin.AttributePresenter, { presenter: tags.component.TagElementPresenter }) - builder.mixin, ObjectDDParticipant>(tags.class.TagElement, core.class.Class, view.mixin.ObjectDDParticipant, { - collectDocs: tags.dd.DeleteTagElement - }) } diff --git a/models/tags/src/plugin.ts b/models/tags/src/plugin.ts index 632e7002a1..71b69e680f 100644 --- a/models/tags/src/plugin.ts +++ b/models/tags/src/plugin.ts @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Doc, Ref, TxOperations } from '@anticrm/core' -import { IntlString, mergeIds, Resource } from '@anticrm/platform' +import { Ref } from '@anticrm/core' +import { IntlString, mergeIds } from '@anticrm/platform' import { TagCategory, tagsId } from '@anticrm/tags' import tags from '@anticrm/tags-resources/src/plugin' import type { AnyComponent } from '@anticrm/ui' @@ -42,9 +42,6 @@ export default mergeIds(tagsId, tags, { CategoryTagsLabel: '' as IntlString, DefaultLabel: '' as IntlString }, - dd: { - DeleteTagElement: '' as Resource<(doc: Doc, client: TxOperations) => Promise> - }, category: { Category: '' as Ref } diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 7d41f8b706..4895138cf1 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -25,7 +25,6 @@ import type { AttributeEditor, AttributePresenter, IgnoreActions, - ObjectDDParticipant, ObjectEditor, ObjectEditorHeader, ObjectFactory, @@ -37,7 +36,6 @@ import type { } from '@anticrm/view' import view from './plugin' -export { ObjectDDParticipant } from '@anticrm/view' export { viewOperation } from './migration' @Mixin(view.mixin.AttributeEditor, core.class.Class) @@ -69,10 +67,6 @@ export class TObjectValidator extends TClass implements ObjectValidator { export class TObjectFactory extends TClass implements ObjectFactory { component!: AnyComponent } -@Mixin(view.mixin.ObjectDDParticipant, core.class.Class) -export class TObjectDDParticipant extends TClass implements ObjectDDParticipant { - collectDocs!: Resource<(doc: Doc) => Promise> -} @Model(view.class.ViewletDescriptor, core.class.Doc, DOMAIN_MODEL) export class TViewletDescriptor extends TDoc implements ViewletDescriptor { @@ -128,7 +122,6 @@ export function createModel (builder: Builder): void { TObjectValidator, TObjectFactory, TObjectEditorHeader, - TObjectDDParticipant, THTMLPresenter, TTextPresenter, TIgnoreActions diff --git a/plugins/chunter-resources/src/backlinks.ts b/plugins/chunter-resources/src/backlinks.ts index ea5141789a..f80f3c1613 100644 --- a/plugins/chunter-resources/src/backlinks.ts +++ b/plugins/chunter-resources/src/backlinks.ts @@ -102,13 +102,3 @@ export async function updateBacklinks (client: TxOperations, backlinkId: Ref { - if (!client.getHierarchy().isDerived(doc._class, chunter.class.Comment)) { - return [] - } - - const comment = doc as Comment - const result = await client.findAll(chunter.class.Backlink, { backlinkId: comment.attachedTo, backlinkClass: comment.attachedToClass, attachedDocId: comment._id }) - return result -} diff --git a/plugins/chunter-resources/src/index.ts b/plugins/chunter-resources/src/index.ts index 6b2390f3fb..d450b73060 100644 --- a/plugins/chunter-resources/src/index.ts +++ b/plugins/chunter-resources/src/index.ts @@ -13,11 +13,7 @@ // limitations under the License. // -import { Channel } from '@anticrm/chunter' -import { Doc } from '@anticrm/core' -import login from '@anticrm/login' -import { getMetadata, Resources } from '@anticrm/platform' -import { collectBacklinks } from './backlinks' +import { Resources } from '@anticrm/platform' import TxBacklinkCreate from './components/activity/TxBacklinkCreate.svelte' import TxBacklinkReference from './components/activity/TxBacklinkReference.svelte' import TxCommentCreate from './components/activity/TxCommentCreate.svelte' @@ -27,8 +23,6 @@ import CommentInput from './components/CommentInput.svelte' import CommentPresenter from './components/CommentPresenter.svelte' import CommentsPresenter from './components/CommentsPresenter.svelte' import CreateChannel from './components/CreateChannel.svelte' -import chunter from './plugin' -import workbench from '@anticrm/workbench' export { CommentsPresenter } @@ -45,8 +39,5 @@ export default async (): Promise => ({ TxCommentCreate, TxBacklinkCreate, TxBacklinkReference - }, - action: { - CommentRemove: collectBacklinks } }) diff --git a/plugins/tags-resources/src/index.ts b/plugins/tags-resources/src/index.ts index 7d2136f903..8209deb729 100644 --- a/plugins/tags-resources/src/index.ts +++ b/plugins/tags-resources/src/index.ts @@ -25,10 +25,6 @@ import CategoryPresenter from './components/CategoryPresenter.svelte' import tags from './plugin' import TagsCategoryBar from './components/CategoryBar.svelte' -async function DeleteTagElement (doc: TagElement, client: TxOperations): Promise { - return await client.findAll(tags.class.TagReference, { tag: doc._id }) -} - export default async (): Promise => ({ component: { Tags, @@ -40,8 +36,5 @@ export default async (): Promise => ({ TagsItemPresenter, CategoryPresenter, TagsCategoryBar - }, - dd: { - DeleteTagElement } }) diff --git a/plugins/view-resources/src/utils.ts b/plugins/view-resources/src/utils.ts index 1fa838889d..f1920cd6c7 100644 --- a/plugins/view-resources/src/utils.ts +++ b/plugins/view-resources/src/utils.ts @@ -34,7 +34,7 @@ import type { IntlString } from '@anticrm/platform' import { getResource } from '@anticrm/platform' import { getAttributePresenterClass, KeyedAttribute } from '@anticrm/presentation' import { ErrorPresenter, getPlatformColorForText } from '@anticrm/ui' -import type { Action, ActionTarget, BuildModelOptions, ObjectDDParticipant } from '@anticrm/view' +import type { Action, ActionTarget, BuildModelOptions } from '@anticrm/view' import view, { AttributeModel, BuildModelKey } from '@anticrm/view' import plugin from './plugin' @@ -220,66 +220,9 @@ export async function deleteObject (client: TxOperations, object: Doc): Promise< const promises: Array> = [] 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))) + await 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>, object: Doc): Promise { - 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 - const allAttached = await client.findAll(collection.of, { attachedTo: object._id }) - for (const attached of allAttached) { - await deleteObject(client, attached).catch(err => console.log('failed to delete', name, err)) - } - } - } -} - -function getParentClass (hierarchy: Hierarchy, _class: Ref>): Ref> { - const baseDomain = hierarchy.getDomain(_class) - const ancestors = hierarchy.getAncestors(_class) - let result: Ref> = _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>, object: Doc): Array>> { - 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 { - const objectClass = hierarchy.getClass(object._class) - if (hierarchy.hasMixin(objectClass, view.mixin.ObjectDDParticipant)) { - const removeParticipand: ObjectDDParticipant = hierarchy.as(objectClass, view.mixin.ObjectDDParticipant) - const collector = await getResource(removeParticipand.collectDocs) - const docs = await collector(object, client) - for (const d of docs) { - await deleteObject(client, d) - } + await client.removeDoc(object._class, object.space, object._id).catch(err => console.error(err)) } } diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index d48a059c1b..1b845305e4 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -14,7 +14,7 @@ // limitations under the License. // -import type { AnyAttribute, Class, Client, Doc, DocumentQuery, FindOptions, Mixin, Obj, Ref, Space, TxOperations, UXObject } from '@anticrm/core' +import type { AnyAttribute, Class, Client, Doc, DocumentQuery, FindOptions, Mixin, Obj, Ref, Space, UXObject } from '@anticrm/core' import type { Asset, IntlString, Plugin, Resource, Status } from '@anticrm/platform' import { plugin } from '@anticrm/platform' import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui' @@ -167,15 +167,6 @@ export interface ObjectFactory extends Class { component: AnyComponent } -/** - * Allow to contribute and find all derived objects for document. - * @public - */ -export interface ObjectDDParticipant extends Class { - // Collect more items to be deleted if parent document is deleted. - collectDocs: Resource<(doc: Doc, client: TxOperations) => Promise> -} - /** * @public */ @@ -187,7 +178,6 @@ const view = plugin(viewId, { ObjectEditorHeader: '' as Ref>, ObjectValidator: '' as Ref>, ObjectFactory: '' as Ref>, - ObjectDDParticipant: '' as Ref, IgnoreActions: '' as Ref>, HTMLPresenter: '' as Ref>, TextPresenter: '' as Ref> diff --git a/rush.json b/rush.json index 5f1d831d9f..010ba67953 100644 --- a/rush.json +++ b/rush.json @@ -1151,5 +1151,20 @@ "projectFolder": "models/calendar", "shouldPublish": true }, + { + "packageName": "@anticrm/server-tags", + "projectFolder": "server-plugins/tags", + "shouldPublish": true + }, + { + "packageName": "@anticrm/model-server-tags", + "projectFolder": "models/server-tags", + "shouldPublish": true + }, + { + "packageName": "@anticrm/server-tags-resources", + "projectFolder": "server-plugins/tags-resources", + "shouldPublish": true + }, ] } diff --git a/server-plugins/chunter-resources/src/index.ts b/server-plugins/chunter-resources/src/index.ts index ef7d2ee72a..582f44a5af 100644 --- a/server-plugins/chunter-resources/src/index.ts +++ b/server-plugins/chunter-resources/src/index.ts @@ -13,8 +13,8 @@ // limitations under the License. // -import chunter, { Channel } from '@anticrm/chunter' -import { Doc } from '@anticrm/core' +import chunter, { Comment, Channel } from '@anticrm/chunter' +import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core' import login from '@anticrm/login' import { getMetadata } from '@anticrm/platform' import workbench from '@anticrm/workbench' @@ -36,9 +36,23 @@ export function channelTextPresenter (doc: Doc): string { return `${channel.name}` } +/** + * @public + */ +export async function CommentRemove (doc: Doc, hiearachy: Hierarchy, findAll: (clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise>): Promise { + if (!hiearachy.isDerived(doc._class, chunter.class.Comment)) { + return [] + } + + const comment = doc as Comment + const result = await findAll(chunter.class.Backlink, { backlinkId: comment.attachedTo, backlinkClass: comment.attachedToClass, attachedDocId: comment._id }) + return result +} + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export default async () => ({ function: { + CommentRemove, ChannelHTMLPresenter: channelHTMLPresenter, ChannelTextPresenter: channelTextPresenter } diff --git a/server-plugins/chunter/src/index.ts b/server-plugins/chunter/src/index.ts index fd9629905c..0dcee99d68 100644 --- a/server-plugins/chunter/src/index.ts +++ b/server-plugins/chunter/src/index.ts @@ -13,9 +13,9 @@ // limitations under the License. // -import type { Resource, Plugin } from '@anticrm/platform' +import { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core' +import type { Plugin, Resource } from '@anticrm/platform' import { plugin } from '@anticrm/platform' -import { Doc } from '@anticrm/core' /** * @public @@ -27,6 +27,7 @@ export const serverChunterId = 'server-chunter' as Plugin */ export default plugin(serverChunterId, { function: { + CommentRemove: '' as Resource<(doc: Doc, hiearachy: Hierarchy, findAll: (clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise>) => Promise>, ChannelHTMLPresenter: '' as Resource<(doc: Doc) => string>, ChannelTextPresenter: '' as Resource<(doc: Doc) => string> } diff --git a/server-plugins/tags-resources/.eslintrc.js b/server-plugins/tags-resources/.eslintrc.js new file mode 100644 index 0000000000..5da5872d4a --- /dev/null +++ b/server-plugins/tags-resources/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/server-plugins/tags-resources/.npmignore b/server-plugins/tags-resources/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/server-plugins/tags-resources/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/server-plugins/tags-resources/config/rig.json b/server-plugins/tags-resources/config/rig.json new file mode 100644 index 0000000000..af1257a896 --- /dev/null +++ b/server-plugins/tags-resources/config/rig.json @@ -0,0 +1,18 @@ +// The "rig.json" file directs tools to look for their config files in an external package. +// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "@anticrm/platform-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/server-plugins/tags-resources/package.json b/server-plugins/tags-resources/package.json new file mode 100644 index 0000000000..92e4ee6ee2 --- /dev/null +++ b/server-plugins/tags-resources/package.json @@ -0,0 +1,34 @@ +{ + "name": "@anticrm/server-tags-resources", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "build:watch": "tsc", + "lint:fix": "eslint --fix src", + "lint": "eslint src", + "format": "prettier --write src && eslint --fix src" + }, + "devDependencies": { + "@anticrm/platform-rig": "~0.6.0", + "@types/heft-jest": "^1.0.2", + "@typescript-eslint/eslint-plugin": "^5.4.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-promise": "^5.1.1", + "eslint-plugin-node": "^11.1.0", + "eslint": "^7.32.0", + "@typescript-eslint/parser": "^5.4.0", + "eslint-config-standard-with-typescript": "^21.0.1", + "prettier": "^2.4.1", + "@rushstack/heft": "^0.41.1", + "typescript": "^4.3.5" + }, + "dependencies": { + "@anticrm/core": "~0.6.16", + "@anticrm/platform": "~0.6.5", + "@anticrm/server-core": "~0.6.1", + "@anticrm/tags": "~0.6.0" + } +} diff --git a/server-plugins/tags-resources/src/index.ts b/server-plugins/tags-resources/src/index.ts new file mode 100644 index 0000000000..c6a3903f32 --- /dev/null +++ b/server-plugins/tags-resources/src/index.ts @@ -0,0 +1,32 @@ +// +// 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 { Class, Doc, DocumentQuery, FindOptions, FindResult, Hierarchy, Ref } from '@anticrm/core' +import tags, { TagElement } from '@anticrm/tags' + +/** + * @public + */ +export async function TagElementRemove (doc: Doc, hiearachy: Hierarchy, findAll: (clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise>): Promise { + if (hiearachy.isDerived(doc._class, tags.class.TagElement)) return [] + return await findAll(tags.class.TagReference, { tag: doc._id as Ref }) +} + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export default async () => ({ + function: { + TagElementRemove + } +}) diff --git a/server-plugins/tags-resources/tsconfig.json b/server-plugins/tags-resources/tsconfig.json new file mode 100644 index 0000000000..aeb0517b13 --- /dev/null +++ b/server-plugins/tags-resources/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib" + } +} \ No newline at end of file diff --git a/server-plugins/tags/.eslintrc.js b/server-plugins/tags/.eslintrc.js new file mode 100644 index 0000000000..5da5872d4a --- /dev/null +++ b/server-plugins/tags/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig.json' + } +} diff --git a/server-plugins/tags/.npmignore b/server-plugins/tags/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/server-plugins/tags/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/server-plugins/tags/config/rig.json b/server-plugins/tags/config/rig.json new file mode 100644 index 0000000000..af1257a896 --- /dev/null +++ b/server-plugins/tags/config/rig.json @@ -0,0 +1,18 @@ +// The "rig.json" file directs tools to look for their config files in an external package. +// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + /** + * (Required) The name of the rig package to inherit from. + * It should be an NPM package name with the "-rig" suffix. + */ + "rigPackageName": "@anticrm/platform-rig" + + /** + * (Optional) Selects a config profile from the rig package. The name must consist of + * lowercase alphanumeric words separated by hyphens, for example "sample-profile". + * If omitted, then the "default" profile will be used." + */ + // "rigProfile": "your-profile-name" +} diff --git a/server-plugins/tags/package.json b/server-plugins/tags/package.json new file mode 100644 index 0000000000..97f6628670 --- /dev/null +++ b/server-plugins/tags/package.json @@ -0,0 +1,34 @@ +{ + "name": "@anticrm/server-tags", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "build:watch": "tsc", + "lint:fix": "eslint --fix src", + "lint": "eslint src", + "format": "prettier --write src && eslint --fix src" + }, + "devDependencies": { + "@anticrm/platform-rig": "~0.6.0", + "@types/heft-jest": "^1.0.2", + "@types/node": "~16.11.12", + "@typescript-eslint/eslint-plugin": "^5.4.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-promise": "^5.1.1", + "eslint-plugin-node": "^11.1.0", + "eslint": "^7.32.0", + "@typescript-eslint/parser": "^5.4.0", + "eslint-config-standard-with-typescript": "^21.0.1", + "prettier": "^2.4.1", + "@rushstack/heft": "^0.41.1", + "typescript": "^4.3.5" + }, + "dependencies": { + "@anticrm/core": "~0.6.16", + "@anticrm/platform": "~0.6.5", + "@anticrm/server-core": "~0.6.1" + } +} diff --git a/server-plugins/tags/src/index.ts b/server-plugins/tags/src/index.ts new file mode 100644 index 0000000000..52e48f6ec0 --- /dev/null +++ b/server-plugins/tags/src/index.ts @@ -0,0 +1,32 @@ +// +// 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 { Class, Doc, Hierarchy, Ref, FindResult, FindOptions, DocumentQuery } from '@anticrm/core' +import type { Plugin, Resource } from '@anticrm/platform' +import { plugin } from '@anticrm/platform' + +/** + * @public + */ +export const serverTagsId = 'server-tags' as Plugin + +/** + * @public + */ +export default plugin(serverTagsId, { + function: { + TagElementRemove: '' as Resource<(doc: Doc, hiearachy: Hierarchy, findAll: (clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise>) => Promise> + } +}) diff --git a/server-plugins/tags/tsconfig.json b/server-plugins/tags/tsconfig.json new file mode 100644 index 0000000000..fffbf4c341 --- /dev/null +++ b/server-plugins/tags/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "esModuleInterop": true + } +} \ No newline at end of file diff --git a/server/core/src/plugin.ts b/server/core/src/plugin.ts index da9b5503c4..4f076c16ab 100644 --- a/server/core/src/plugin.ts +++ b/server/core/src/plugin.ts @@ -18,7 +18,7 @@ import type { Plugin } from '@anticrm/platform' import { plugin } from '@anticrm/platform' import type { Ref, Class } from '@anticrm/core' -import type { Trigger } from './types' +import type { ObjectDDParticipant, Trigger } from './types' /** * @public @@ -31,6 +31,9 @@ export const serverCoreId = 'server-core' as Plugin const serverCore = plugin(serverCoreId, { class: { Trigger: '' as Ref> + }, + mixin: { + ObjectDDParticipant: '' as Ref } }) diff --git a/server/core/src/storage.ts b/server/core/src/storage.ts index 77c474021f..e27d8d9f62 100644 --- a/server/core/src/storage.ts +++ b/server/core/src/storage.ts @@ -17,6 +17,8 @@ import core, { AttachedDoc, Class, + ClassifierKind, + Collection, Doc, DocumentQuery, Domain, @@ -25,21 +27,28 @@ import core, { FindOptions, FindResult, Hierarchy, - MeasureContext, ModelDb, + MeasureContext, Mixin, ModelDb, Ref, ServerStorage, Storage, Tx, TxBulkWrite, TxCollectionCUD, + TxCreateDoc, TxCUD, TxFactory, - TxResult + TxMixin, + TxProcessor, + TxRemoveDoc, + TxResult, + TxUpdateDoc } from '@anticrm/core' +import { getResource } from '@anticrm/platform' import type { Client as MinioClient } from 'minio' import { FullTextIndex } from './fulltext' +import serverCore from './plugin' import { Triggers } from './triggers' -import type { FullTextAdapter, FullTextAdapterFactory } from './types' +import type { FullTextAdapter, FullTextAdapterFactory, ObjectDDParticipant } from './types' /** * @public @@ -197,6 +206,133 @@ class TServerStorage implements ServerStorage { }) } + getParentClass (_class: Ref>): Ref> { + const baseDomain = this.hierarchy.getDomain(_class) + const ancestors = this.hierarchy.getAncestors(_class) + let result: Ref> = _class + for (const ancestor of ancestors) { + try { + const domain = this.hierarchy.getClass(ancestor).domain + if (domain === baseDomain) { + result = ancestor + } + } catch {} + } + return result + } + + getMixins (_class: Ref>, object: Doc): Array>> { + const parentClass = this.getParentClass(_class) + const descendants = this.hierarchy.getDescendants(parentClass) + return descendants.filter( + (m) => this.hierarchy.getClass(m).kind === ClassifierKind.MIXIN && this.hierarchy.hasMixin(object, m) + ) + } + + async buildRemovedDoc (ctx: MeasureContext, tx: TxRemoveDoc): Promise { + const txes = await this.findAll(ctx, core.class.TxCUD, { objectId: tx.objectId }, { sort: { modifiedOn: 1 } }) + let doc: Doc + let createTx = txes.find((tx) => tx._class === core.class.TxCreateDoc) + if (createTx === undefined) { + const collectionTxes = txes.filter((tx) => tx._class === core.class.TxCollectionCUD) as TxCollectionCUD[] + createTx = collectionTxes.find((p) => p.tx._class === core.class.TxCreateDoc) + } + if (createTx === undefined) return + doc = TxProcessor.createDoc2Doc(createTx as TxCreateDoc) + for (const tx of txes) { + if (tx._class === core.class.TxUpdateDoc) { + doc = TxProcessor.updateDoc2Doc(doc, tx as TxUpdateDoc) + } else if (tx._class === core.class.TxMixin) { + const mixinTx = tx as TxMixin + doc = TxProcessor.updateMixin4Doc(doc, mixinTx.mixin, mixinTx.attributes) + } + } + + return doc + } + + extractTx (tx: Tx): Tx { + if (tx._class === core.class.TxCollectionCUD) { + const ctx = (tx as TxCollectionCUD) + return ctx.tx + } + + return tx + } + + async processRemove (ctx: MeasureContext, tx: Tx): Promise { + const actualTx = this.extractTx(tx) + if (!this.hierarchy.isDerived(actualTx._class, core.class.TxRemoveDoc)) return [] + const rtx = actualTx as TxRemoveDoc + const result: Tx[] = [] + const object = await this.buildRemovedDoc(ctx, rtx) + if (object === undefined) return [] + result.push(...await this.deleteClassCollections(ctx, object._class, rtx.objectId)) + const mixins = this.getMixins(object._class, object) + for (const mixin of mixins) { + result.push(...await this.deleteClassCollections(ctx, mixin, rtx.objectId)) + } + result.push(...await this.deleteRelatedDocuments(ctx, object)) + return result + } + + async deleteClassCollections (ctx: MeasureContext, _class: Ref>, objectId: Ref): Promise { + const attributes = this.hierarchy.getAllAttributes(_class) + const result: Tx[] = [] + for (const attribute of attributes) { + if (this.hierarchy.isDerived(attribute[1].type._class, core.class.Collection)) { + const collection = attribute[1].type as Collection + const allAttached = await this.findAll(ctx, collection.of, { attachedTo: objectId }) + for (const attached of allAttached) { + result.push(...await this.deleteObject(ctx, attached)) + } + } + } + return result + } + + async deleteObject (ctx: MeasureContext, object: Doc): Promise { + const result: Tx[] = [] + const factory = new TxFactory(core.account.System) + if (this.hierarchy.isDerived(object._class, core.class.AttachedDoc)) { + const adoc = object as AttachedDoc + const nestedTx = factory.createTxRemoveDoc(object._class, object.space, adoc._id) as TxRemoveDoc + const tx = factory.createTxCollectionCUD( + adoc.attachedToClass, + adoc.attachedTo, + object.space, + adoc.collection, + nestedTx + ) + result.push(tx) + } else { + result.push(factory.createTxRemoveDoc(object._class, object.space, object._id)) + } + result.push(...await this.deleteClassCollections(ctx, object._class, object._id)) + const mixins = this.getMixins(object._class, object) + for (const mixin of mixins) { + result.push(...await this.deleteClassCollections(ctx, mixin, object._id)) + } + result.push(...await this.deleteRelatedDocuments(ctx, object)) + return result + } + + async deleteRelatedDocuments (ctx: MeasureContext, object: Doc): Promise { + const result: Tx[] = [] + const objectClass = this.hierarchy.getClass(object._class) + if (this.hierarchy.hasMixin(objectClass, serverCore.mixin.ObjectDDParticipant)) { + const removeParticipand: ObjectDDParticipant = this.hierarchy.as(objectClass, serverCore.mixin.ObjectDDParticipant) + const collector = await getResource(removeParticipand.collectDocs) + const docs = await collector(object, this.hierarchy, async (_class, query, options) => { + return await this.findAll(ctx, _class, query, options) + }) + for (const d of docs) { + result.push(...await this.deleteObject(ctx, d)) + } + } + return result + } + async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> { // store tx const _class = txClass(tx) @@ -227,6 +363,7 @@ class TServerStorage implements ServerStorage { // invoke triggers and store derived objects derived = [ ...(await ctx.with('process-collection', { _class }, () => this.processCollection(ctx, tx))), + ...(await ctx.with('process-remove', { _class }, () => this.processRemove(ctx, tx))), ...(await ctx.with('process-triggers', {}, (ctx) => this.triggers.apply(tx.modifiedBy, tx, { fx: triggerFx.fx, diff --git a/server/core/src/types.ts b/server/core/src/types.ts index d82e6ee39a..3a460b82b4 100644 --- a/server/core/src/types.ts +++ b/server/core/src/types.ts @@ -15,7 +15,7 @@ // import type { Client as MinioClient } from 'minio' -import type { Tx, Ref, Doc, Class, Storage, Space, Timestamp, Account, FindResult, DocumentQuery, FindOptions, TxResult, MeasureContext, ModelDb } from '@anticrm/core' +import type { Tx, Ref, Doc, Class, Storage, Space, Timestamp, Account, FindResult, DocumentQuery, FindOptions, TxResult, MeasureContext, ModelDb, Obj } from '@anticrm/core' import { TxFactory, Hierarchy } from '@anticrm/core' import type { Resource } from '@anticrm/platform' @@ -83,3 +83,12 @@ export type FullTextAdapterFactory = (url: string, workspace: string) => Promise export interface WithFind { findAll: (ctx: MeasureContext, clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise> } + +/** + * Allow to contribute and find all derived objects for document. + * @public + */ +export interface ObjectDDParticipant extends Class { + // Collect more items to be deleted if parent document is deleted. + collectDocs: Resource<(doc: Doc, hiearachy: Hierarchy, findAll: (clazz: Ref>, query: DocumentQuery, options?: FindOptions) => Promise>) => Promise> +} diff --git a/server/server/package.json b/server/server/package.json index 58e1b487ac..13df5c3ac4 100644 --- a/server/server/package.json +++ b/server/server/package.json @@ -63,6 +63,8 @@ "@anticrm/server-recruit-resources": "~0.6.0", "@anticrm/server-task": "~0.6.0", "@anticrm/server-task-resources": "~0.6.0", + "@anticrm/server-tags": "~0.6.0", + "@anticrm/server-tags-resources": "~0.6.0", "@anticrm/server-token": "~0.6.0" } } diff --git a/server/server/src/server.ts b/server/server/src/server.ts index 93bbf55258..3011797a27 100644 --- a/server/server/src/server.ts +++ b/server/server/src/server.ts @@ -32,6 +32,7 @@ import { serverInventoryId } from '@anticrm/server-inventory' import { serverLeadId } from '@anticrm/server-lead' import { serverRecruitId } from '@anticrm/server-recruit' import { serverTaskId } from '@anticrm/server-task' +import { serverTagsId } from '@anticrm/server-tags' import { metricsContext } from './metrics' @@ -68,6 +69,7 @@ export function start (dbUrl: string, fullTextUrl: string, minioConf: MinioConfi addLocation(serverLeadId, () => import('@anticrm/server-lead-resources')) addLocation(serverRecruitId, () => import('@anticrm/server-recruit-resources')) addLocation(serverTaskId, () => import('@anticrm/server-task-resources')) + addLocation(serverTagsId, () => import('@anticrm/server-tags-resources')) return startJsonRpc(metricsContext, (workspace: string) => { const conf: DbConfiguration = {