From ad325a1d078039429aa2fe8dbe50f4e73fee6ee0 Mon Sep 17 00:00:00 2001 From: Andrey Platov Date: Fri, 6 Aug 2021 12:18:50 +0200 Subject: [PATCH] add more packages to compile `workbench` Signed-off-by: Andrey Platov --- common/config/rush/pnpm-lock.yaml | 65 ++++- packages/core/src/client.ts | 4 +- packages/presentation/img/chen.png | Bin 0 -> 34129 bytes packages/presentation/package.json | 4 + packages/presentation/src/utils.ts | 15 +- packages/query/.eslintrc.js | 6 + packages/query/.npmignore | 4 + packages/query/config/rig.json | 18 ++ packages/query/package.json | 25 ++ packages/query/src/__tests__/connection.txt | 50 ++++ packages/query/src/__tests__/query.test.txt | 263 ++++++++++++++++++ packages/query/src/index.ts | 202 ++++++++++++++ packages/query/tsconfig.json | 8 + plugins/client/.eslintrc.js | 6 + plugins/client/.npmignore | 4 + plugins/client/config/rig.json | 18 ++ plugins/client/package.json | 24 ++ plugins/client/src/index.ts | 37 +++ plugins/client/tsconfig.json | 9 + plugins/view/.eslintrc.js | 6 + plugins/view/.npmignore | 4 + plugins/view/config/rig.json | 18 ++ plugins/view/package.json | 25 ++ plugins/view/src/index.ts | 60 ++++ plugins/view/tsconfig.json | 9 + plugins/workbench-resources/img/avatar.png | Bin 0 -> 2799 bytes plugins/workbench-resources/img/voltron.png | Bin 0 -> 957 bytes plugins/workbench-resources/package.json | 2 + .../src/components/WorkbenchApp.svelte | 4 +- plugins/workbench-resources/src/utils.ts | 4 +- rush.json | 15 + 31 files changed, 894 insertions(+), 15 deletions(-) create mode 100755 packages/presentation/img/chen.png create mode 100644 packages/query/.eslintrc.js create mode 100644 packages/query/.npmignore create mode 100644 packages/query/config/rig.json create mode 100644 packages/query/package.json create mode 100644 packages/query/src/__tests__/connection.txt create mode 100644 packages/query/src/__tests__/query.test.txt create mode 100644 packages/query/src/index.ts create mode 100644 packages/query/tsconfig.json create mode 100644 plugins/client/.eslintrc.js create mode 100644 plugins/client/.npmignore create mode 100644 plugins/client/config/rig.json create mode 100644 plugins/client/package.json create mode 100644 plugins/client/src/index.ts create mode 100644 plugins/client/tsconfig.json create mode 100644 plugins/view/.eslintrc.js create mode 100644 plugins/view/.npmignore create mode 100644 plugins/view/config/rig.json create mode 100644 plugins/view/package.json create mode 100644 plugins/view/src/index.ts create mode 100644 plugins/view/tsconfig.json create mode 100644 plugins/workbench-resources/img/avatar.png create mode 100644 plugins/workbench-resources/img/voltron.png diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 00b1ff93cb..c0a3e82da1 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -2,6 +2,7 @@ lockfileVersion: 5.3 specifiers: '@microsoft/api-extractor': ^7.18.4 + '@rush-temp/client': file:./projects/client.tgz '@rush-temp/core': file:./projects/core.tgz '@rush-temp/dev-server': file:./projects/dev-server.tgz '@rush-temp/dev-storage': file:./projects/dev-storage.tgz @@ -12,11 +13,13 @@ specifiers: '@rush-temp/platform-rig': file:./projects/platform-rig.tgz '@rush-temp/presentation': file:./projects/presentation.tgz '@rush-temp/prod': file:./projects/prod.tgz + '@rush-temp/query': file:./projects/query.tgz '@rush-temp/server': file:./projects/server.tgz '@rush-temp/server-core': file:./projects/server-core.tgz '@rush-temp/server-ws': file:./projects/server-ws.tgz '@rush-temp/theme': file:./projects/theme.tgz '@rush-temp/ui': file:./projects/ui.tgz + '@rush-temp/view': file:./projects/view.tgz '@rush-temp/workbench': file:./projects/workbench.tgz '@rush-temp/workbench-resources': file:./projects/workbench-resources.tgz '@rushstack/heft': ^0.35.0 @@ -57,6 +60,7 @@ specifiers: dependencies: '@microsoft/api-extractor': 7.18.4 + '@rush-temp/client': file:projects/client.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/core': file:projects/core.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/dev-server': file:projects/dev-server.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/dev-storage': file:projects/dev-storage.tgz_6c259fadfeb3a4b20890aefe87070b8b @@ -67,11 +71,13 @@ dependencies: '@rush-temp/platform-rig': file:projects/platform-rig.tgz_6ab28797e7a22071465f7d680ae81ae5 '@rush-temp/presentation': file:projects/presentation.tgz_c38cf1a7a413db8918b0b4754c21e4c5 '@rush-temp/prod': file:projects/prod.tgz_sass@1.37.5+typescript@4.3.5 + '@rush-temp/query': file:projects/query.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/server': file:projects/server.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/server-core': file:projects/server-core.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/server-ws': file:projects/server-ws.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/theme': file:projects/theme.tgz_c38cf1a7a413db8918b0b4754c21e4c5 '@rush-temp/ui': file:projects/ui.tgz_c38cf1a7a413db8918b0b4754c21e4c5 + '@rush-temp/view': file:projects/view.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/workbench': file:projects/workbench.tgz_6c259fadfeb3a4b20890aefe87070b8b '@rush-temp/workbench-resources': file:projects/workbench-resources.tgz_c38cf1a7a413db8918b0b4754c21e4c5 '@rushstack/heft': 0.35.0 @@ -7680,6 +7686,24 @@ packages: commander: 2.20.3 dev: false + file:projects/client.tgz_6c259fadfeb3a4b20890aefe87070b8b: + resolution: {integrity: sha512-8YJou7AitxzzH2roWCno/zgd27SiQXlqrdDVyhAAvZrBZY7KGbxw4OxGkI+6eVK+Lk/zajS2FkGZ+oyZ+Bxe6g==, tarball: file:projects/client.tgz} + id: file:projects/client.tgz + name: '@rush-temp/client' + version: 0.0.0 + dependencies: + '@types/heft-jest': 1.0.2 + '@typescript-eslint/eslint-plugin': 4.28.5_a8e83fcad666e1ba86be4b2e27a20aea + eslint: 7.32.0 + eslint-plugin-import: 2.23.4_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 4.3.1 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - supports-color + - typescript + dev: false + file:projects/core.tgz_6c259fadfeb3a4b20890aefe87070b8b: resolution: {integrity: sha512-H49oedby3HV+eR2uQZAI0kIJ8Yxh8uIR+sLg4Ox0JAy4UJtfP5AmyWltddqaUdQIcfYrb2BrhDSDSxddlDWhpg==, tarball: file:projects/core.tgz} id: file:projects/core.tgz @@ -7827,7 +7851,7 @@ packages: dev: false file:projects/presentation.tgz_c38cf1a7a413db8918b0b4754c21e4c5: - resolution: {integrity: sha512-y4BqVd0TM1NHy74NaREi5s26qWOro+kn+dVogNYFm3mkuVEqHwv/ZzivbLI9X7Ti7IbuG8FeCy2N1r9Cs6XUJg==, tarball: file:projects/presentation.tgz} + resolution: {integrity: sha512-v1qRQGQrWDFfME4IEpK6bM0E3IQljeG2+Ft/YVPM/Fbf/y3e+28AvI3nyvLn+1N6gY+5faEAHLE4M9vBbR+A1A==, tarball: file:projects/presentation.tgz} id: file:projects/presentation.tgz name: '@rush-temp/presentation' version: 0.0.0 @@ -7887,6 +7911,25 @@ packages: - utf-8-validate dev: false + file:projects/query.tgz_6c259fadfeb3a4b20890aefe87070b8b: + resolution: {integrity: sha512-9CUYPnThJmot4jmOsi6R7ugG/yTz+6emWtPfhSTK+1hqr3hXaYSXIXuYirvqpa6a434uRTUAe362U5VuNi4xdA==, tarball: file:projects/query.tgz} + id: file:projects/query.tgz + name: '@rush-temp/query' + version: 0.0.0 + dependencies: + '@types/heft-jest': 1.0.2 + '@typescript-eslint/eslint-plugin': 4.28.5_a8e83fcad666e1ba86be4b2e27a20aea + eslint: 7.32.0 + eslint-plugin-import: 2.23.4_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 4.3.1 + simplytyped: 3.3.0_typescript@4.3.5 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - supports-color + - typescript + dev: false + file:projects/server-core.tgz_6c259fadfeb3a4b20890aefe87070b8b: resolution: {integrity: sha512-lHE4PAWrX+WKdM9/Yy1rYZW6rCacwLMkSUIJakrXZeyGlNytXXSvH20bgfocVn73grez3Zjy6qlNm7H7EClgDQ==, tarball: file:projects/server-core.tgz} id: file:projects/server-core.tgz @@ -7997,8 +8040,26 @@ packages: - typescript dev: false + file:projects/view.tgz_6c259fadfeb3a4b20890aefe87070b8b: + resolution: {integrity: sha512-BQgcAfVRNy1QO/Z8ATfQZbm090HU2b7jl5r38stX7rjzF0udaYKci9yDb9xECP1oYCEPWXbayUPlF/AwRqxZ4g==, tarball: file:projects/view.tgz} + id: file:projects/view.tgz + name: '@rush-temp/view' + version: 0.0.0 + dependencies: + '@types/heft-jest': 1.0.2 + '@typescript-eslint/eslint-plugin': 4.28.5_a8e83fcad666e1ba86be4b2e27a20aea + eslint: 7.32.0 + eslint-plugin-import: 2.23.4_eslint@7.32.0 + eslint-plugin-node: 11.1.0_eslint@7.32.0 + eslint-plugin-promise: 4.3.1 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - supports-color + - typescript + dev: false + file:projects/workbench-resources.tgz_c38cf1a7a413db8918b0b4754c21e4c5: - resolution: {integrity: sha512-LMzBHdlTssEH28+ttT/0/eeghU3OWwwJ7AWksnnJsabUEgfjaYNZqTfsLiD6CCjMJXMVU/kUvUjBmlpB8HWUpg==, tarball: file:projects/workbench-resources.tgz} + resolution: {integrity: sha512-UZMkx/Mq9SBiSR6JFaCmJ548KfR1cSser177G9y196X9ot7EYLYHSZ0Teo9hZTwUgDU1TDkk2KW2sxuFN71naA==, tarball: file:projects/workbench-resources.tgz} id: file:projects/workbench-resources.tgz name: '@rush-temp/workbench-resources' version: 0.0.0 diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 9345ceae1b..7b82e6d306 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -20,7 +20,6 @@ import type { Storage, DocumentQuery, FindOptions, FindResult } from './storage' import { Hierarchy } from './hierarchy' import { ModelDb } from './memdb' import { DOMAIN_MODEL } from './classes' -import { TxProcessor } from './tx' import core from './component' @@ -36,9 +35,8 @@ export interface Client extends Storage { getHierarchy: () => Hierarchy } -class ClientImpl extends TxProcessor implements Storage, Client { +class ClientImpl implements Storage, Client { constructor (private readonly hierarchy: Hierarchy, private readonly model: ModelDb, private readonly conn: Storage) { - super() } getHierarchy (): Hierarchy { return this.hierarchy } diff --git a/packages/presentation/img/chen.png b/packages/presentation/img/chen.png new file mode 100755 index 0000000000000000000000000000000000000000..9f9d1107916b4ecfc042213ce50838a6a670a09f GIT binary patch literal 34129 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

^!!m`71+Dd|+rbt>uU0qoG#PlJ1%* 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 literal 0 HcmV?d00001 diff --git a/packages/presentation/package.json b/packages/presentation/package.json index 137b19cc05..88cf07199f 100644 --- a/packages/presentation/package.json +++ b/packages/presentation/package.json @@ -19,7 +19,11 @@ "svelte-preprocess":"^4.7.4" }, "dependencies": { + "@anticrm/platform": "~0.6.0", + "@anticrm/core": "~0.6.0", + "@anticrm/query": "~0.6.0", "@anticrm/ui": "~0.6.0", + "@anticrm/view": "~0.6.0", "svelte": "^3.37.0" } } diff --git a/packages/presentation/src/utils.ts b/packages/presentation/src/utils.ts index 3571530b1e..0bc324564e 100644 --- a/packages/presentation/src/utils.ts +++ b/packages/presentation/src/utils.ts @@ -16,17 +16,20 @@ import { getContext, setContext, onDestroy } from 'svelte' -import type { Doc, Ref, Class, DocumentQuery, FindOptions } from '@anticrm/core' -import type { Connection } from '@anticrm/client' +import type { Doc, Ref, Class, DocumentQuery, FindOptions, Client } from '@anticrm/core' +import { LiveQuery as LQ } from '@anticrm/query' const CLIENT_CONEXT = 'workbench.context.Client' -export function getClient(): Connection { - return getContext(CLIENT_CONEXT) +let liveQuery: LQ + +export function getClient(): Client { + return getContext(CLIENT_CONEXT) } -export function setClient(client: Connection) { +export function setClient(client: Client) { setContext(CLIENT_CONEXT, client) + liveQuery = new LQ(client) } class LiveQuery { @@ -39,7 +42,7 @@ class LiveQuery { query(_class: Ref>, query: DocumentQuery, callback: (result: T[]) => void, options?: FindOptions) { this.unsubscribe() - this.unsubscribe = this.client.query(_class, query, callback, options) + this.unsubscribe = liveQuery.query(_class, query, callback, options) } } diff --git a/packages/query/.eslintrc.js b/packages/query/.eslintrc.js new file mode 100644 index 0000000000..89f8151bd4 --- /dev/null +++ b/packages/query/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + project: './tsconfig.json' + } +} \ No newline at end of file diff --git a/packages/query/.npmignore b/packages/query/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/packages/query/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/packages/query/config/rig.json b/packages/query/config/rig.json new file mode 100644 index 0000000000..af1257a896 --- /dev/null +++ b/packages/query/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/packages/query/package.json b/packages/query/package.json new file mode 100644 index 0000000000..503b02433e --- /dev/null +++ b/packages/query/package.json @@ -0,0 +1,25 @@ +{ + "name": "@anticrm/query", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "lint:fix": "eslint --fix src" + }, + "devDependencies": { + "@anticrm/platform-rig":"~0.6.0", + "@types/heft-jest":"^1.0.2", + "@typescript-eslint/eslint-plugin":"4", + "eslint-plugin-import":"2", + "eslint-plugin-promise":"4", + "eslint-plugin-node":"11", + "eslint":"^7.32.0", + "simplytyped": "^3.3.0" + }, + "dependencies": { + "@anticrm/platform": "~0.6.3", + "@anticrm/core": "~0.6.3" + } +} diff --git a/packages/query/src/__tests__/connection.txt b/packages/query/src/__tests__/connection.txt new file mode 100644 index 0000000000..279d621538 --- /dev/null +++ b/packages/query/src/__tests__/connection.txt @@ -0,0 +1,50 @@ +// +// Copyright © 2020 Anticrm Platform Contributors. +// +// 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 { Tx, Storage, Ref, Doc, Class, DocumentQuery, FindResult } from '@anticrm/core' +import core, { ModelDb, TxDb, Hierarchy, DOMAIN_TX } from '@anticrm/core' + +import { genMinModel } from '@anticrm/core/src/__tests__/minmodel' + +export async function connect (handler: (tx: Tx) => void): Promise { + const txes = genMinModel() + + const hierarchy = new Hierarchy() + for (const tx of txes) hierarchy.tx(tx) + + const transactions = new TxDb(hierarchy) + const model = new ModelDb(hierarchy) + for (const tx of txes) { + await transactions.tx(tx) + await model.tx(tx) + } + + async function findAll (_class: Ref>, query: DocumentQuery): Promise> { + const domain = hierarchy.getClass(_class).domain + if (domain === DOMAIN_TX) return await transactions.findAll(_class, query) + return await model.findAll(_class, query) + } + + return { + findAll, + tx: async (tx: Tx): Promise => { + if (tx.objectSpace === core.space.Model) { + hierarchy.tx(tx) + } + await Promise.all([model.tx(tx), transactions.tx(tx)]) + handler(tx) + } + } +} diff --git a/packages/query/src/__tests__/query.test.txt b/packages/query/src/__tests__/query.test.txt new file mode 100644 index 0000000000..c5fe654020 --- /dev/null +++ b/packages/query/src/__tests__/query.test.txt @@ -0,0 +1,263 @@ +// +// Copyright © 2021 Anticrm Platform Contributors. +// +// 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 { Class, Client, Doc, DocumentQuery, FindOptions, FindResult, Obj, Ref, Space, Tx, TxCreateDoc } from '@anticrm/core' +import core, { createClient, DOMAIN_TX, Hierarchy, ModelDb, TxDb, withOperations, SortingOrder } from '@anticrm/core' +import { genMinModel as getModel } from '@anticrm/core/src/__tests__/minmodel' +import { LiveQuery } from '..' +import { connect } from './connection' + +interface Channel extends Space { + x: number +} +describe('query', () => { + it('findAll', async () => { + const client = await getClient() + const query = withOperations(core.account.System, new LiveQuery(client)) + const result = await query.findAll(core.class.Space, {}) + expect(result).toHaveLength(2) + }) + + it('query with param', async (done) => { + const storage = await getClient() + + let expectedLength = 0 + const txes = await getModel() + for (let i = 0; i < txes.length; i++) { + if (storage.getHierarchy().isDerived((txes[i] as TxCreateDoc).objectClass, core.class.Space)) { + expectedLength++ + } + } + + const query = new LiveQuery(storage) + query.query(core.class.Space, { private: false }, (result) => { + expect(result).toHaveLength(expectedLength) + done() + }) + }) + + it('query should be live', async (done) => { + const storage = await getClient() + + let expectedLength = 0 + const txes = await getModel() + for (let i = 0; i < txes.length; i++) { + if (storage.getHierarchy().isDerived((txes[i] as TxCreateDoc).objectClass, core.class.Space)) { + expectedLength++ + } + } + + let attempt = 0 + const query = withOperations(core.account.System, new LiveQuery(storage)) + query.query(core.class.Space, { private: false }, (result) => { + expect(result).toHaveLength(expectedLength + attempt) + if (attempt > 0) { + expect((result[expectedLength + attempt - 1] as any).x).toBe(attempt) + } + if (attempt++ === 3) { + // check underlying storage received all data. + storage + .findAll(core.class.Space, { private: false }) + .then((result) => { + expect(result).toHaveLength(expectedLength + attempt - 1) + done() + }) + .catch((err) => expect(err).toBeUndefined()) + } + }) + + await query.createDoc(core.class.Space, core.space.Model, { + private: false, + name: '#1', + description: '', + members: [], + x: 1 + }) + await query.createDoc(core.class.Space, core.space.Model, { + private: false, + name: '#2', + description: '', + members: [], + x: 2 + }) + await query.createDoc(core.class.Space, core.space.Model, { + private: false, + name: '#3', + description: '', + members: [], + x: 3 + }) + }) + + it('unsubscribe query', async () => { + const storage = await getClient() + + let expectedLength = 0 + const txes = await getModel() + for (let i = 0; i < txes.length; i++) { + if (storage.getHierarchy().isDerived((txes[i] as TxCreateDoc).objectClass, core.class.Space)) { + expectedLength++ + } + } + + const query = withOperations(core.account.System, new LiveQuery(storage)) + const unsubscribe = query.query(core.class.Space, { private: false }, (result) => { + expect(result).toHaveLength(expectedLength) + }) + + unsubscribe() + + await query.createDoc(core.class.Space, core.space.Model, { + private: false, + name: '#1', + description: '', + members: [] + }) + await query.createDoc(core.class.Space, core.space.Model, { + private: false, + name: '#2', + description: '', + members: [] + }) + await query.createDoc(core.class.Space, core.space.Model, { + private: false, + name: '#3', + description: '', + members: [] + }) + }) + + it('query against core client', async (done) => { + const client = await createClient(connect) + + const expectedLength = 2 + let attempt = 0 + const query = withOperations(core.account.System, new LiveQuery(client)) + query.query(core.class.Space, { private: false }, (result) => { + expect(result).toHaveLength(expectedLength + attempt) + if (attempt > 0) { + expect((result[expectedLength + attempt - 1] as any).x).toBe(attempt) + } + if (attempt++ === 1) done() + }) + + await query.createDoc(core.class.Space, core.space.Model, { + x: 1, + private: false, + name: '#1', + description: '', + members: [] + }) + await query.createDoc(core.class.Space, core.space.Model, { + x: 2, + private: false, + name: '#2', + description: '', + members: [] + }) + await query.createDoc(core.class.Space, core.space.Model, { + x: 3, + private: false, + name: '#3', + description: '', + members: [] + }) + }) + + it('limit and sorting', async (done) => { + const storage = await getClient() + + const limit = 1 + let attempt = 0 + let doneCount = 0 + + const query = withOperations(core.account.System, new LiveQuery(storage)) + query.query(core.class.Space, { private: true }, (result) => { + if (attempt > 0 && result.length > 0) { + expect(result.length).toEqual(limit) + expect(result[0].name).toMatch('0') + } + if (attempt === 1) doneCount++ + if (doneCount === 2) done() + }, { limit: limit, sort: { name: SortingOrder.Ascending } }) + + query.query(core.class.Space, { private: true }, (result) => { + if (attempt > 0 && result.length > 0) { + expect(result.length).toEqual(limit) + expect(result[0].name).toMatch(attempt.toString()) + } + if (attempt === 10) doneCount++ + if (doneCount === 2) done() + }, { limit: limit, sort: { name: SortingOrder.Descending } }) + + for (let i = 0; i < 10; i++) { + attempt++ + await query.createDoc(core.class.Space, core.space.Model, { + private: true, + name: i.toString(), + description: '', + members: [] + }) + } + }) + it('remove', async (done) => { + const client = await createClient(connect) + + const expectedLength = 2 + let attempt = 0 + const query = withOperations(core.account.System, new LiveQuery(client)) + query.query(core.class.Space, { private: false }, (result) => { + expect(result).toHaveLength(expectedLength - attempt) + if (attempt++ === expectedLength) done() + }) + + const spaces = await query.findAll(core.class.Space, {}) + for (const space of spaces) { + await query.removeDoc(space._class, space.space, space._id) + } + }) +}) + +class ClientImpl implements Client { + constructor ( + private readonly hierarchy: Hierarchy, + private readonly model: ModelDb, + private readonly transactions: TxDb + ) {} + + async tx (tx: Tx): Promise { + await Promise.all([this.model.tx(tx), this.transactions.tx(tx)]) + } + + getHierarchy(): Hierarchy { + return this.hierarchy + } + + async findAll(_class: Ref>, query: DocumentQuery, options?: FindOptions): Promise> { + const domain = this.hierarchy.getClass(_class).domain + if (domain === DOMAIN_TX) return await this.transactions.findAll(_class, query, options) + return await this.model.findAll(_class, query, options) + } +} + +async function getClient (): Promise { + const hierarchy = new Hierarchy() + const transactions = new TxDb(hierarchy) + const model = new ModelDb(hierarchy) + const txes = await getModel() + for (const tx of txes) hierarchy.tx(tx) + for (const tx of txes) await model.tx(tx) + return new ClientImpl(hierarchy, model, transactions) +} diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts new file mode 100644 index 0000000000..421e526210 --- /dev/null +++ b/packages/query/src/index.ts @@ -0,0 +1,202 @@ +// +// Copyright © 2020, 2021 Anticrm Platform Contributors. +// +// 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 { + Ref, Class, Doc, Tx, DocumentQuery, TxCreateDoc, TxRemoveDoc, Client, + FindOptions, TxUpdateDoc, _getOperator, TxProcessor, resultSort, SortingQuery, + FindResult, Hierarchy, Refs, WithLookup, LookupData +} from '@anticrm/core' + +interface Query { + _class: Ref> + query: DocumentQuery + result: Doc[] | Promise + options?: FindOptions + callback: (result: FindResult) => void +} + +export class LiveQuery extends TxProcessor implements Client { + private readonly client: Client + private readonly queries: Query[] = [] + + constructor (client: Client) { + super() + this.client = client + } + + getHierarchy (): Hierarchy { + return this.client.getHierarchy() + } + + private match (q: Query, doc: Doc): boolean { + if (!this.getHierarchy().isDerived(doc._class, q._class)) { + return false + } + for (const key in q.query) { + const value = (q.query as any)[key] + if ((doc as any)[key] !== value) { + return false + } + } + return true + } + + async findAll(_class: Ref>, query: DocumentQuery, options?: FindOptions): Promise> { + return await this.client.findAll(_class, query, options) + } + + query(_class: Ref>, query: DocumentQuery, callback: (result: T[]) => void, options?: FindOptions): () => void { + const result = this.client.findAll(_class, query, options) + const q: Query = { + _class, + query, + result, + options, + callback: callback as (result: Doc[]) => void + } + this.queries.push(q) + result + .then((result) => { + q.callback(result) + }) + .catch((err) => { + console.log('failed to update Live Query: ', err) + }) + + return () => { + this.queries.splice(this.queries.indexOf(q), 1) + } + } + + async txUpdateDoc (tx: TxUpdateDoc): Promise { + for (const q of this.queries) { + if (q.result instanceof Promise) { + q.result = await q.result + } + const updatedDoc = q.result.find(p => p._id === tx.objectId) + if (updatedDoc !== undefined) { + await this.__updateDoc(updatedDoc, tx) + this.sort(q, tx) + await this.callback(updatedDoc, q) + } + } + } + + private async lookup (doc: Doc, lookup: Refs): Promise { + const result: LookupData = {} + for (const key in lookup) { + const _class = (lookup as any)[key] as Ref> + const _id = (doc as any)[key] as Ref + (result as any)[key] = (await this.client.findAll(_class, { _id }))[0] + } + (doc as WithLookup).$lookup = result + } + + async txCreateDoc (tx: TxCreateDoc): Promise { + for (const q of this.queries) { + const doc = TxProcessor.createDoc2Doc(tx) + if (this.match(q, doc)) { + if (q.result instanceof Promise) { + q.result = await q.result + } + + if (q.options?.lookup !== undefined) await this.lookup(doc, q.options.lookup) + + q.result.push(doc) + + if (q.options?.sort !== undefined) resultSort(q.result, q.options?.sort) + + if (q.options?.limit !== undefined && q.result.length > q.options.limit) { + if (q.result.pop()?._id !== doc._id) { + q.callback(q.result) + } + } else { + q.callback(q.result) + } + } + } + } + + async txRemoveDoc (tx: TxRemoveDoc): Promise { + for (const q of this.queries) { + if (q.result instanceof Promise) { + q.result = await q.result + } + const index = q.result.findIndex(p => p._id === tx.objectId) + if (index > -1) { + q.result.splice(index, 1) + q.callback(q.result) + } + } + } + + async tx (tx: Tx): Promise { + await this.client.tx(tx) + await super.tx(tx) + } + + async __updateDoc (updatedDoc: Doc, tx: TxUpdateDoc): Promise { + const ops = tx.operations as any + for (const key in ops) { + if (key.startsWith('$')) { + const operator = _getOperator(key) + operator(updatedDoc, ops[key]) + } else { + (updatedDoc as any)[key] = ops[key] + } + } + updatedDoc.modifiedBy = tx.modifiedBy + updatedDoc.modifiedOn = tx.modifiedOn + } + + private sort (q: Query, tx: TxUpdateDoc): void { + const sort = q.options?.sort + if (sort === undefined) return + let needSort = sort.modifiedBy !== undefined || sort.modifiedOn !== undefined + if (!needSort) needSort = this.checkNeedSort(sort, tx) + + if (needSort) resultSort(q.result as Doc[], sort) + } + + private checkNeedSort (sort: SortingQuery, tx: TxUpdateDoc): boolean { + const ops = tx.operations as any + for (const key in ops) { + if (key.startsWith('$')) { + for (const opKey in ops[key]) { + if (opKey in sort) return true + } + } else { + if (key in sort) return true + } + } + return false + } + + async callback (updatedDoc: Doc, q: Query): Promise { + q.result = q.result as Doc[] + + if (q.options?.limit !== undefined && q.result.length > q.options.limit) { + if (q.result[q.options?.limit]._id === updatedDoc._id) { + const res = await this.findAll(q._class, q.query, q.options) + q.result = res + q.callback(res) + return + } + if (q.result.pop()?._id !== updatedDoc._id) q.callback(q.result) + } else { + q.callback(q.result) + } + } +} diff --git a/packages/query/tsconfig.json b/packages/query/tsconfig.json new file mode 100644 index 0000000000..aeb0517b13 --- /dev/null +++ b/packages/query/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/plugins/client/.eslintrc.js b/plugins/client/.eslintrc.js new file mode 100644 index 0000000000..89f8151bd4 --- /dev/null +++ b/plugins/client/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + project: './tsconfig.json' + } +} \ No newline at end of file diff --git a/plugins/client/.npmignore b/plugins/client/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/plugins/client/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/plugins/client/config/rig.json b/plugins/client/config/rig.json new file mode 100644 index 0000000000..af1257a896 --- /dev/null +++ b/plugins/client/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/plugins/client/package.json b/plugins/client/package.json new file mode 100644 index 0000000000..e42a3a5704 --- /dev/null +++ b/plugins/client/package.json @@ -0,0 +1,24 @@ +{ + "name": "@anticrm/client", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "lint:fix": "eslint --fix src" + }, + "devDependencies": { + "@anticrm/platform-rig":"~0.6.0", + "@types/heft-jest":"^1.0.2", + "@typescript-eslint/eslint-plugin":"4", + "eslint-plugin-import":"2", + "eslint-plugin-promise":"4", + "eslint-plugin-node":"11", + "eslint":"^7.32.0" + }, + "dependencies": { + "@anticrm/platform":"~0.6.3", + "@anticrm/core":"~0.6.0" + } +} diff --git a/plugins/client/src/index.ts b/plugins/client/src/index.ts new file mode 100644 index 0000000000..1f77472ca1 --- /dev/null +++ b/plugins/client/src/index.ts @@ -0,0 +1,37 @@ +// +// Copyright © 2020 Anticrm Platform Contributors. +// +// 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 { plugin } from '@anticrm/platform' +import type { Metadata, Plugin, Resource } from '@anticrm/platform' +import type { Client } from '@anticrm/core' +// import type { LiveQuery } from '@anticrm/query' + +// export type Connection = Client & LiveQuery & TxOperations + +/** + * @public + */ +export const clientId = 'client' as Plugin + +export default plugin(clientId, + { + function: { + GetClient: '' as Resource<() => Promise> + }, + metadata: { + ClientUrl: '' as Metadata + } + } +) diff --git a/plugins/client/tsconfig.json b/plugins/client/tsconfig.json new file mode 100644 index 0000000000..32045300ce --- /dev/null +++ b/plugins/client/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "lib": ["esnext", "dom"] + } +} \ No newline at end of file diff --git a/plugins/view/.eslintrc.js b/plugins/view/.eslintrc.js new file mode 100644 index 0000000000..89f8151bd4 --- /dev/null +++ b/plugins/view/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'], + parserOptions: { + project: './tsconfig.json' + } +} \ No newline at end of file diff --git a/plugins/view/.npmignore b/plugins/view/.npmignore new file mode 100644 index 0000000000..e3ec093c38 --- /dev/null +++ b/plugins/view/.npmignore @@ -0,0 +1,4 @@ +* +!/lib/** +!CHANGELOG.md +/lib/**/__tests__/ diff --git a/plugins/view/config/rig.json b/plugins/view/config/rig.json new file mode 100644 index 0000000000..af1257a896 --- /dev/null +++ b/plugins/view/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/plugins/view/package.json b/plugins/view/package.json new file mode 100644 index 0000000000..52b0f010e8 --- /dev/null +++ b/plugins/view/package.json @@ -0,0 +1,25 @@ +{ + "name": "@anticrm/view", + "version": "0.6.0", + "main": "lib/index.js", + "author": "Anticrm Platform Contributors", + "license": "EPL-2.0", + "scripts": { + "build": "heft build", + "lint:fix": "eslint --fix src" + }, + "devDependencies": { + "@anticrm/platform-rig":"~0.6.0", + "@types/heft-jest":"^1.0.2", + "@typescript-eslint/eslint-plugin":"4", + "eslint-plugin-import":"2", + "eslint-plugin-promise":"4", + "eslint-plugin-node":"11", + "eslint":"^7.32.0" + }, + "dependencies": { + "@anticrm/platform":"~0.6.3", + "@anticrm/core":"~0.6.0", + "@anticrm/ui":"~0.6.0" + } +} diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts new file mode 100644 index 0000000000..dc186b0626 --- /dev/null +++ b/plugins/view/src/index.ts @@ -0,0 +1,60 @@ +// +// Copyright © 2020, 2021 Anticrm Platform Contributors. +// Copyright © 2021 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 { Plugin, Asset } from '@anticrm/platform' +import { plugin } from '@anticrm/platform' +import type { Ref, Mixin, UXObject, Space, FindOptions, Class, Doc } from '@anticrm/core' + +import type { AnyComponent } from '@anticrm/ui' + +export interface AttributeEditor extends Class { + editor: AnyComponent +} + +export interface AttributePresenter extends Class { + presenter: AnyComponent +} + +export interface ViewletDescriptor extends Doc, UXObject { + component: AnyComponent +} + +export interface Viewlet extends Doc { + attachTo: Ref> + descriptor: Ref + open: AnyComponent + options?: FindOptions + config: any +} + +export const viewId = 'view' as Plugin + +export default plugin(viewId, { + mixin: { + AttributeEditor: '' as Ref>, + AttributePresenter: '' as Ref> + }, + class: { + ViewletDescriptor: '' as Ref>, + Viewlet: '' as Ref> + }, + viewlet: { + Table: '' as Ref + }, + icon: { + Table: '' as Asset + } +}) diff --git a/plugins/view/tsconfig.json b/plugins/view/tsconfig.json new file mode 100644 index 0000000000..32045300ce --- /dev/null +++ b/plugins/view/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json", + + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "lib": ["esnext", "dom"] + } +} \ No newline at end of file diff --git a/plugins/workbench-resources/img/avatar.png b/plugins/workbench-resources/img/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..8d61750a2c774aa174aff358765ce3e796368d79 GIT binary patch literal 2799 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 BJm>%b literal 0 HcmV?d00001 diff --git a/plugins/workbench-resources/img/voltron.png b/plugins/workbench-resources/img/voltron.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d498da92169cbecf7d39b23305620309775012 GIT binary patch literal 957 zcmV;u148_XP)-9A)Fi5v&_?~~-uIn0owVORo9PaI&6n?cp6~tM=lA@1-}fm80=wOw8W|a> zJ3BkO$8lUN{xOJ+$)lsA=MsrzgQLd7!^0P^!|(+-+-|pwJ3Ks`Ai^Vr0K{nnCE!8m z;1D6Shz&IX+z_~hKLFV;*qu}{JRT23BGE6pi=bmD=(sB(uxegKS63%9dN(5j?QLyP ztJN?XjR8h;NV$`Oj*bpQL`3{Ofz#7d^z^*N^71m1&1N$m6coT{$<#n^Z!a1e8hqiWckh*xlY@tag#lATAv^-a(7t0Ig98Ih z3=0cGR#q04mX=_#Sg>ceqh6&#adELP*OZ(jRuVAxmnJ}i`eAewR;!hfDJ?0%vw9UO zD$3z>IvFwj#028v;(~e`2!c{TJ^8-9jp5<F*~c z$N9dwQUU{mgK#-rOs;!chZ9nat*x!d%*@2?p?4S=8NtrZj*zK^5m;DQ zz%-fMLw;$gX()eO4vj`b`v_=tS~NB`vT?^JCrq!`>p{+XAyfaJz_Hs6bzdL6S#4@+ z!ut9;W$z<$3jaExb3rK?lA>b`SI@#3J6joMNSe^^=@{yOH2c=TU zqCp9~Xl`c4+S^}ZZf*`@u^8Fe*$@iee!yn4L0(zO?sVCWl2u?bn$SshLAny|=jO5< z(7WN#0`!~{XDi`6Y<#QY7N7SzosJo&&(%+=5hIR)R;%?*YT2+rA(z8v$q$t9t2eKa zl#~QM1SPPxwuZ5>G4?E#N+DM$uxs0eZO`_TAi1pDR`8*Z?2ujE-MBOX>hbvaI1&>R znWwe2wTMrMM}jl~rDbK9pPz>id?n`vE!gz*^q^yc)_^yU{s)V{UI;FJ8wf#D;D4|L z(hGr*u{SN*e?h>35JE&M^$S9WkDSZpN+r$ZA`!0r&nfAYWTL33s15o+6qC3@@H8Y2 f^3FhQQrkZOEqh^DYyVUE00000NkvXXu0mjf$LFvK literal 0 HcmV?d00001 diff --git a/plugins/workbench-resources/package.json b/plugins/workbench-resources/package.json index e0a7c7ec36..721a094b5f 100644 --- a/plugins/workbench-resources/package.json +++ b/plugins/workbench-resources/package.json @@ -22,8 +22,10 @@ "svelte": "^3.37.0", "@anticrm/platform": "~0.6.0", "@anticrm/core": "~0.6.0", + "@anticrm/client": "~0.6.0", "@anticrm/workbench": "~0.6.0", "@anticrm/ui": "~0.6.0", + "@anticrm/view": "~0.6.0", "@anticrm/presentation": "~0.6.0" } } diff --git a/plugins/workbench-resources/src/components/WorkbenchApp.svelte b/plugins/workbench-resources/src/components/WorkbenchApp.svelte index 0640b4ad09..6fce7015c4 100644 --- a/plugins/workbench-resources/src/components/WorkbenchApp.svelte +++ b/plugins/workbench-resources/src/components/WorkbenchApp.svelte @@ -16,12 +16,12 @@