mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Activity support
Initial Activity support Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
dbd8c870d6
commit
3f066c718f
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -40,14 +40,14 @@ jobs:
|
||||
run: node common/scripts/install-run-rush.js rebuild --verbose
|
||||
|
||||
- name: Checking svelte sources...
|
||||
run: common/scripts/each.sh svelte-check
|
||||
run: node common/scripts/install-run-rush.js svelte-check
|
||||
|
||||
- name: Testing...
|
||||
uses: paambaati/codeclimate-action@v2.7.5
|
||||
env:
|
||||
CC_TEST_REPORTER_ID: 346a83855d7124e9da8e6ec36a4fd01dc432f5cdc755eb28da7d9c44da9d1142
|
||||
with:
|
||||
coverageCommand: common/scripts/each.sh test
|
||||
coverageCommand: node common/scripts/install-run-rush.js test
|
||||
coverageLocations: |
|
||||
${{github.workspace}}/packages/*/coverage/lcov.info:lcov
|
||||
${{github.workspace}}/server/*/coverage/lcov.info:lcov
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -70,3 +70,4 @@ common/autoinstallers/*/.npmrc
|
||||
**/.rush/temp/
|
||||
bundle.js
|
||||
dist
|
||||
tsconfig.tsbuildinfo
|
@ -184,7 +184,28 @@
|
||||
"enableParallelism": true,
|
||||
"incremental": true,
|
||||
"ignoreMissingScript": true,
|
||||
"watchForChanges": true
|
||||
"watchForChanges": true,
|
||||
"safeForSimultaneousRushProcesses": true
|
||||
},
|
||||
{
|
||||
"commandKind": "bulk",
|
||||
"name": "svelte-check",
|
||||
"summary": "svelte-check",
|
||||
"description": "Perform svelte-check",
|
||||
"enableParallelism": true,
|
||||
"incremental": true,
|
||||
"ignoreDependencyOrder": false,
|
||||
"ignoreMissingScript": true
|
||||
},
|
||||
{
|
||||
"commandKind": "bulk",
|
||||
"name": "test",
|
||||
"summary": "test",
|
||||
"description": "Perform testing",
|
||||
"enableParallelism": true,
|
||||
"incremental": true,
|
||||
"ignoreDependencyOrder": false,
|
||||
"ignoreMissingScript": true
|
||||
},
|
||||
],
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
sourceDir=$(dirname "$0")
|
||||
sourceDir=$(realpath "$sourceDir")
|
||||
runScript=$sourceDir/install-run-rushx.js
|
||||
|
||||
roots=$(node $sourceDir/install-run-rush.js list -f --json | grep "fullPath" | cut -f 2 -d ':' | cut -f 2 -d '"')
|
||||
for i in $roots
|
||||
do
|
||||
pushd ${i}
|
||||
checkScript=$(cat package.json | grep \"$1\": | wc -l)
|
||||
if [ $checkScript -gt 0 ]; then
|
||||
node ${runScript} $@
|
||||
retVal=$?
|
||||
if [ $retVal -ne 0 ]; then
|
||||
echo "Error"
|
||||
exit $retVal
|
||||
fi
|
||||
fi
|
||||
popd
|
||||
done
|
@ -68,6 +68,9 @@
|
||||
"@anticrm/server-recruit": "~0.6.1",
|
||||
"@anticrm/server-recruit-resources": "~0.6.0",
|
||||
"@anticrm/server-view": "~0.6.0",
|
||||
"@anticrm/server-view-resources": "~0.6.0"
|
||||
"@anticrm/server-view-resources": "~0.6.0",
|
||||
"@anticrm/activity": "~0.6.0",
|
||||
"@anticrm/activity-assets": "~0.6.0",
|
||||
"@anticrm/activity-resources": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import { taskId } from '@anticrm/task'
|
||||
import { contactId } from '@anticrm/contact'
|
||||
import { chunterId } from '@anticrm/chunter'
|
||||
import { recruitId } from '@anticrm/recruit'
|
||||
import { activityId } from '@anticrm/activity'
|
||||
|
||||
import { serverChunterId } from '@anticrm/server-chunter'
|
||||
import { serverRecruitId } from '@anticrm/server-recruit'
|
||||
@ -34,6 +35,7 @@ import '@anticrm/view-assets'
|
||||
import '@anticrm/chunter-assets'
|
||||
import '@anticrm/contact-assets'
|
||||
import '@anticrm/recruit-assets'
|
||||
import '@anticrm/activity-assets'
|
||||
|
||||
import { setMetadata } from '@anticrm/platform'
|
||||
|
||||
@ -60,4 +62,5 @@ export function configurePlatform() {
|
||||
addLocation(contactId, () => import(/* webpackChunkName: "contact" */ '@anticrm/contact-resources'))
|
||||
addLocation(chunterId, () => import(/* webpackChunkName: "chunter" */ '@anticrm/chunter-resources'))
|
||||
addLocation(recruitId, () => import(/* webpackChunkName: "recruit" */ '@anticrm/recruit-resources'))
|
||||
addLocation(activityId, () => import(/*webpackChunkName: "activity" */ '@anticrm/activity-resources'))
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
7
models/activity/.eslintrc.js
Normal file
7
models/activity/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/model-rig/profiles/default/config/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
4
models/activity/.npmignore
Normal file
4
models/activity/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
18
models/activity/config/rig.json
Normal file
18
models/activity/config/rig.json
Normal file
@ -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"
|
||||
}
|
29
models/activity/package.json
Normal file
29
models/activity/package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@anticrm/model-activity",
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/model-rig":"~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin":"4",
|
||||
"eslint-plugin-import":"2",
|
||||
"eslint-plugin-promise":"4",
|
||||
"eslint-plugin-node":"11",
|
||||
"eslint":"^7.32.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/model": "~0.6.0",
|
||||
"@anticrm/contact": "~0.6.2",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/model-core": "~0.6.0",
|
||||
"@anticrm/activity": "~0.6.0",
|
||||
"@anticrm/ui": "~0.6.0"
|
||||
}
|
||||
}
|
39
models/activity/src/index.ts
Normal file
39
models/activity/src/index.ts
Normal file
@ -0,0 +1,39 @@
|
||||
//
|
||||
// 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 type { TxViewlet } from '@anticrm/activity'
|
||||
import activity from '@anticrm/activity'
|
||||
import core, { Class, Doc, DocumentQuery, DOMAIN_MODEL, Ref, Tx } from '@anticrm/core'
|
||||
import { Builder, Model } from '@anticrm/model'
|
||||
import { TDoc } from '@anticrm/model-core'
|
||||
import type { Asset, IntlString } from '@anticrm/platform'
|
||||
import { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
@Model(activity.class.TxViewlet, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TTxViewlet extends TDoc implements TxViewlet {
|
||||
icon!: Asset
|
||||
objectClass!: Ref<Class<Doc>>
|
||||
txClass!: Ref<Class<Tx>>
|
||||
// Component to display on.
|
||||
component!: AnyComponent
|
||||
// Filter
|
||||
match!: DocumentQuery<Tx>
|
||||
label!: IntlString
|
||||
display!: 'inline' | 'content' | 'emphasized'
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TTxViewlet)
|
||||
}
|
8
models/activity/tsconfig.json
Normal file
8
models/activity/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./node_modules/@anticrm/model-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@
|
||||
"@anticrm/model-server-core": "~0.6.0",
|
||||
"@anticrm/model-server-chunter": "~0.6.0",
|
||||
"@anticrm/model-server-recruit": "~0.6.0",
|
||||
"@anticrm/model-server-view": "~0.6.0"
|
||||
"@anticrm/model-server-view": "~0.6.0",
|
||||
"@anticrm/model-activity": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,14 @@ import { createModel as serverCoreModel } from '@anticrm/model-server-core'
|
||||
import { createModel as serverChunterModel } from '@anticrm/model-server-chunter'
|
||||
import { createModel as serverRecruitModel } from '@anticrm/model-server-recruit'
|
||||
import { createModel as serverViewModel } from '@anticrm/model-server-view'
|
||||
import { createModel as activityModel } from '@anticrm/model-activity'
|
||||
|
||||
import { createDemo } from '@anticrm/model-demo'
|
||||
|
||||
const builder = new Builder()
|
||||
|
||||
coreModel(builder)
|
||||
activityModel(builder)
|
||||
viewModel(builder)
|
||||
workbenchModel(builder)
|
||||
contactModel(builder)
|
||||
|
@ -27,6 +27,7 @@
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/model-core": "~0.6.0",
|
||||
"@anticrm/model-view": "~0.6.0",
|
||||
"@anticrm/model-workbench": "~0.6.1"
|
||||
"@anticrm/model-workbench": "~0.6.1",
|
||||
"@anticrm/activity": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import { IndexKind } from '@anticrm/core'
|
||||
import core, { TSpace, TDoc, TAttachedDoc } from '@anticrm/model-core'
|
||||
import type { Backlink, Channel, Message, Comment, Attachment } from '@anticrm/chunter'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import activity from '@anticrm/activity'
|
||||
|
||||
import workbench from '@anticrm/model-workbench'
|
||||
|
||||
@ -124,6 +125,24 @@ export function createModel (builder: Builder): void {
|
||||
builder.mixin(chunter.class.Attachment, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: chunter.component.AttachmentPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
|
||||
objectClass: chunter.class.Comment,
|
||||
icon: chunter.icon.Chunter,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
component: chunter.activity.TxCommentCreate,
|
||||
label: chunter.string.LeftComment,
|
||||
display: 'content'
|
||||
}, chunter.ids.TxCommentCreate)
|
||||
|
||||
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
|
||||
objectClass: chunter.class.Attachment,
|
||||
icon: chunter.icon.Attachment,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
component: chunter.activity.TxAttachmentCreate,
|
||||
label: chunter.string.AddAttachment,
|
||||
display: 'emphasized'
|
||||
}, chunter.ids.TxAttachmentCreate)
|
||||
}
|
||||
|
||||
export default chunter
|
||||
|
@ -20,6 +20,7 @@ import { mergeIds } from '@anticrm/platform'
|
||||
import type { Ref } from '@anticrm/core'
|
||||
import { ViewletDescriptor } from '@anticrm/view'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import type { TxViewlet } from '@anticrm/activity'
|
||||
|
||||
export default mergeIds(chunterId, chunter, {
|
||||
component: {
|
||||
@ -27,9 +28,19 @@ export default mergeIds(chunterId, chunter, {
|
||||
AttachmentPresenter: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
ApplicationLabelChunter: '' as IntlString
|
||||
ApplicationLabelChunter: '' as IntlString,
|
||||
LeftComment: '' as IntlString,
|
||||
AddAttachment: '' as IntlString
|
||||
},
|
||||
viewlet: {
|
||||
Chat: '' as Ref<ViewletDescriptor>
|
||||
},
|
||||
ids: {
|
||||
TxCommentCreate: '' as Ref<TxViewlet>,
|
||||
TxAttachmentCreate: '' as Ref<TxViewlet>
|
||||
},
|
||||
activity: {
|
||||
TxCommentCreate: '' as AnyComponent,
|
||||
TxAttachmentCreate: '' as AnyComponent
|
||||
}
|
||||
})
|
||||
|
@ -22,6 +22,7 @@
|
||||
"@anticrm/model": "~0.6.0",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/model-recruit": "~0.6.0",
|
||||
"@anticrm/model-contact": "~0.6.1"
|
||||
"@anticrm/model-contact": "~0.6.1",
|
||||
"@anticrm/contact": "~0.6.2"
|
||||
}
|
||||
}
|
||||
|
@ -14,26 +14,27 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
import core, { generateId, Ref } from '@anticrm/core'
|
||||
import { Builder } from '@anticrm/model'
|
||||
import core, { generateId } from '@anticrm/core'
|
||||
|
||||
import contact from '@anticrm/model-contact'
|
||||
import recruit from '@anticrm/model-recruit'
|
||||
|
||||
export function createDemo (builder: Builder): void {
|
||||
const rosamund = generateId()
|
||||
const account: Ref<EmployeeAccount> = generateId()
|
||||
|
||||
builder.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name: 'Chen,Rosamund',
|
||||
city: 'Mountain View',
|
||||
channels: []
|
||||
}, rosamund)
|
||||
}, rosamund, account)
|
||||
|
||||
builder.createDoc(contact.class.EmployeeAccount, core.space.Model, {
|
||||
builder.createDoc<EmployeeAccount>(contact.class.EmployeeAccount, core.space.Model, {
|
||||
email: 'rosamund@hc.engineering',
|
||||
employee: rosamund as any,
|
||||
employee: rosamund as Ref<Employee>,
|
||||
name: 'Chen,Rosamund'
|
||||
})
|
||||
}, account, account)
|
||||
|
||||
builder.createDoc(recruit.class.Candidate, recruit.space.CandidatesPublic, {
|
||||
name: 'P.,Andrey',
|
||||
@ -45,7 +46,7 @@ export function createDemo (builder: Builder): void {
|
||||
value: 'andrey@hc.engineering'
|
||||
}
|
||||
]
|
||||
})
|
||||
}, undefined, account)
|
||||
|
||||
builder.createDoc(recruit.class.Candidate, recruit.space.CandidatesPublic, {
|
||||
name: 'M.,Marina',
|
||||
@ -57,7 +58,7 @@ export function createDemo (builder: Builder): void {
|
||||
value: 'marina@hc.engineering'
|
||||
}
|
||||
]
|
||||
})
|
||||
}, undefined, account)
|
||||
|
||||
builder.createDoc(recruit.class.Candidate, recruit.space.CandidatesPublic, {
|
||||
name: 'P.,Alex',
|
||||
@ -69,5 +70,5 @@ export function createDemo (builder: Builder): void {
|
||||
value: 'alex@hc.engineering'
|
||||
}
|
||||
]
|
||||
})
|
||||
}, undefined, account)
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
"@anticrm/recruit-resources": "~0.6.0",
|
||||
"@anticrm/chunter": "~0.6.0",
|
||||
"@anticrm/model-chunter": "~0.6.0",
|
||||
"@anticrm/view": "~0.6.0"
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/activity": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import { Builder, Model, UX, Prop, TypeString, TypeBoolean } from '@anticrm/mode
|
||||
import type { Ref, FindOptions, Doc, Domain, Class } from '@anticrm/core'
|
||||
import core, { TSpace, TSpaceWithStates, TDocWithState } from '@anticrm/model-core'
|
||||
import type { Vacancy, Candidates, Candidate, Applicant } from '@anticrm/recruit'
|
||||
import activity from '@anticrm/activity'
|
||||
|
||||
import workbench from '@anticrm/model-workbench'
|
||||
|
||||
@ -194,6 +195,32 @@ export function createModel (builder: Builder): void {
|
||||
attachedTo: recruit.class.Applicant,
|
||||
sequence: 0
|
||||
})
|
||||
|
||||
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
|
||||
objectClass: recruit.class.Applicant,
|
||||
icon: recruit.icon.RecruitApplication,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
component: recruit.activity.TxApplicantCreate,
|
||||
label: recruit.string.TxApplicantCreate,
|
||||
display: 'emphasized'
|
||||
}, recruit.ids.TxApplicantCreate)
|
||||
|
||||
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
|
||||
objectClass: recruit.class.Applicant,
|
||||
icon: recruit.icon.RecruitApplication,
|
||||
txClass: core.class.TxUpdateDoc,
|
||||
component: recruit.activity.TxApplicantUpdate,
|
||||
label: recruit.string.TxApplicantUpdate,
|
||||
display: 'inline'
|
||||
}, recruit.ids.TxApplicantUpdate)
|
||||
|
||||
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
|
||||
objectClass: recruit.class.Candidate,
|
||||
icon: recruit.icon.RecruitApplication,
|
||||
txClass: core.class.TxCreateDoc,
|
||||
label: recruit.string.TxCandidateCreate,
|
||||
display: 'emphasized'
|
||||
}, recruit.ids.TxCandidateCreate)
|
||||
}
|
||||
|
||||
export { default } from './plugin'
|
||||
|
@ -20,6 +20,7 @@ import type { AnyComponent } from '@anticrm/ui'
|
||||
import type { Action } from '@anticrm/view'
|
||||
import { recruitId } from '@anticrm/recruit'
|
||||
import recruit from '@anticrm/recruit-resources/src/plugin'
|
||||
import { TxViewlet } from '../../chunter/node_modules/@anticrm/activity/lib'
|
||||
|
||||
export default mergeIds(recruitId, recruit, {
|
||||
action: {
|
||||
@ -32,7 +33,10 @@ export default mergeIds(recruitId, recruit, {
|
||||
RecruitApplication: '' as IntlString,
|
||||
Vacancies: '' as IntlString,
|
||||
CandidatePools: '' as IntlString,
|
||||
Vacancy: '' as IntlString
|
||||
Vacancy: '' as IntlString,
|
||||
TxApplicantCreate: '' as IntlString,
|
||||
TxCandidateCreate: '' as IntlString,
|
||||
TxApplicantUpdate: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
CreateVacancy: '' as AnyComponent,
|
||||
@ -46,5 +50,14 @@ export default mergeIds(recruitId, recruit, {
|
||||
},
|
||||
space: {
|
||||
CandidatesPublic: '' as Ref<Space>
|
||||
},
|
||||
ids: {
|
||||
TxApplicantCreate: '' as Ref<TxViewlet>,
|
||||
TxCandidateCreate: '' as Ref<TxViewlet>,
|
||||
TxApplicantUpdate: '' as Ref<TxViewlet>
|
||||
},
|
||||
activity: {
|
||||
TxApplicantCreate: '' as AnyComponent,
|
||||
TxApplicantUpdate: '' as AnyComponent
|
||||
}
|
||||
})
|
||||
|
@ -15,22 +15,30 @@
|
||||
//
|
||||
|
||||
import type { Doc } from './classes'
|
||||
import { getNestedValue } from './query'
|
||||
|
||||
type Predicate = (docs: Doc[]) => Doc[]
|
||||
type PredicateFactory = (pred: any, propertyKey: string) => Predicate
|
||||
|
||||
type ExecPredicate = (value: any) => boolean
|
||||
|
||||
function execPredicate (docs: Doc[], propertyKey: string, pred: ExecPredicate): Doc[] {
|
||||
const result: Doc[] = []
|
||||
for (const doc of docs) {
|
||||
const value = getNestedValue(propertyKey, doc)
|
||||
if (pred(value)) {
|
||||
result.push(doc)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const predicates: Record<string, PredicateFactory> = {
|
||||
$in: (o: any, propertyKey: string): Predicate => {
|
||||
$in: (o, propertyKey) => {
|
||||
if (!Array.isArray(o)) {
|
||||
throw new Error('$in predicate requires array')
|
||||
}
|
||||
return (docs: Doc[]): Doc[] => {
|
||||
const result: Doc[] = []
|
||||
for (const doc of docs) {
|
||||
if (o.includes((doc as any)[propertyKey])) result.push(doc)
|
||||
}
|
||||
return result
|
||||
}
|
||||
return (docs) => execPredicate(docs, propertyKey, (value) => o.includes(value))
|
||||
},
|
||||
|
||||
$like: (query: string, propertyKey: string): Predicate => {
|
||||
|
@ -15,13 +15,60 @@ export function findProperty (objects: Doc[], propertyKey: string, value: any):
|
||||
}
|
||||
const result: Doc[] = []
|
||||
for (const object of objects) {
|
||||
if ((object as any)[propertyKey] === value) {
|
||||
const val = getNestedValue(propertyKey, object)
|
||||
if ((val === value) || isArrayValueCheck(val, value)) {
|
||||
result.push(object)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function isArrayValueCheck<T, P> (val: T, value: P): boolean {
|
||||
return Array.isArray(val) && !Array.isArray(value) && val.includes(value)
|
||||
}
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getNestedValue (key: string, doc: Doc): any {
|
||||
// Check dot notation
|
||||
if (key.length === 0) {
|
||||
return doc
|
||||
}
|
||||
key = key.split('\\$').join('$')
|
||||
const dots = key.split('.')
|
||||
// Replace escapting, since memdb is not escape keys
|
||||
|
||||
// We have dots, so iterate in depth
|
||||
let pos = 0
|
||||
let value = doc as any
|
||||
for (const d of dots) {
|
||||
if (Array.isArray(value) && isNestedArrayQuery(value, d)) {
|
||||
// Array and d is not an indexed field.
|
||||
// So return array of nested values.
|
||||
return getNestedArrayValue(value, dots.slice(pos).join('.'))
|
||||
}
|
||||
value = value?.[d]
|
||||
pos++
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function isNestedArrayQuery (value: any, d: string): boolean {
|
||||
return Number.isNaN(Number.parseInt(d)) && value?.[d as any] === undefined
|
||||
}
|
||||
|
||||
function getNestedArrayValue (value: any[], name: string): any[] {
|
||||
const result = []
|
||||
for (const v of value) {
|
||||
result.push(...arrayOrValue(getNestedValue(name, v)))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function arrayOrValue (vv: any): any[] {
|
||||
return Array.isArray(vv) ? vv : [vv]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -40,6 +40,9 @@ export type DocumentQuery<T extends Doc> = {
|
||||
[P in keyof T]?: ObjQueryType<T[P]>
|
||||
} & {
|
||||
$search?: string
|
||||
// support nested queries e.g. 'user.friends.name'
|
||||
// this will mark all unrecognized properties as any (including nested queries)
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,24 +13,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type {
|
||||
Ref,
|
||||
Doc,
|
||||
Type,
|
||||
PropertyType,
|
||||
Attribute,
|
||||
Tx,
|
||||
Class,
|
||||
Obj,
|
||||
Data,
|
||||
TxCreateDoc,
|
||||
Domain,
|
||||
Mixin as IMixin,
|
||||
Space,
|
||||
ExtendedAttributes
|
||||
import core, {
|
||||
Account,
|
||||
Attribute, Class, ClassifierKind, Data, Doc, Domain, ExtendedAttributes, generateId, IndexKind, Mixin as IMixin, Obj, PropertyType, Ref, Space, Tx, TxCreateDoc, TxFactory, TxProcessor, Type
|
||||
} from '@anticrm/core'
|
||||
import core, { ClassifierKind, IndexKind, generateId, TxFactory } from '@anticrm/core'
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { Asset, IntlString } from '@anticrm/platform'
|
||||
import toposort from 'toposort'
|
||||
|
||||
type NoIDs<T extends Tx> = Omit<T, '_id' | 'objectId'>
|
||||
@ -240,16 +227,20 @@ export class Builder {
|
||||
_class: Ref<Class<T>>,
|
||||
space: Ref<Space>,
|
||||
attributes: Data<T>,
|
||||
objectId?: Ref<T>
|
||||
): void {
|
||||
this.txes.push(
|
||||
txFactory.createTxCreateDoc(
|
||||
objectId?: Ref<T>,
|
||||
modifiedBy?: Ref<Account>
|
||||
): T {
|
||||
const tx = txFactory.createTxCreateDoc(
|
||||
_class,
|
||||
space,
|
||||
attributes,
|
||||
objectId
|
||||
)
|
||||
)
|
||||
if (modifiedBy !== undefined) {
|
||||
tx.modifiedBy = modifiedBy
|
||||
}
|
||||
this.txes.push(tx)
|
||||
return TxProcessor.createDoc2Doc(tx)
|
||||
}
|
||||
|
||||
mixin<D extends Doc, M extends D> (
|
||||
|
@ -25,6 +25,7 @@
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/chunter": "~0.6.0",
|
||||
"@anticrm/presentation": "~0.6.2"
|
||||
"@anticrm/presentation": "~0.6.2",
|
||||
"@anticrm/activity": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '@anticrm/ui'
|
||||
import { Icon } from '@anticrm/ui'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
</script>
|
||||
|
||||
<div class="flex-col msg-container">
|
||||
<div class="flex-between">
|
||||
<div class="flex-center icon">
|
||||
<div class="scale-75">
|
||||
{#if typeof (icon) === 'string'}
|
||||
<Icon {icon} size={'small'}/>
|
||||
{:else}
|
||||
<svelte:component this={icon} size={'small'} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow label"><slot /></div>
|
||||
<div class="content-trans-color">Yesterday, 3:20 PM</div>
|
||||
</div>
|
||||
{#if $$slots.content}
|
||||
<div class="content"><slot name="content" /></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.msg-container {
|
||||
position: relative;
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2.25rem;
|
||||
left: 1.125rem;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background-color: var(--theme-card-divider);
|
||||
}
|
||||
}
|
||||
:global(.msg-container + .msg-container::before) {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -1.5rem;
|
||||
left: 1.125rem;
|
||||
height: 1.5rem;
|
||||
width: 1px;
|
||||
background-color: var(--theme-card-divider);
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
border: 1px solid var(--theme-card-divider);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: .5rem 0 .5rem 3.25rem;
|
||||
padding: 1rem;
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: .75rem;
|
||||
}
|
||||
|
||||
.label {
|
||||
flex-wrap: wrap;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
:global(.label b) { color: var(--theme-caption-color); }
|
||||
:global(.label span) {
|
||||
display: inline-block;
|
||||
padding: .125rem .25rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-bg-focused-color);
|
||||
border-radius: .25rem;
|
||||
}
|
||||
:global(.label span.bar) {
|
||||
padding: .25rem .5rem;
|
||||
font-weight: 500;
|
||||
font-size: .625rem;
|
||||
background-color: var(--primary-button-enabled);
|
||||
}
|
||||
</style>
|
@ -15,19 +15,12 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import type { Doc } from '@anticrm/core'
|
||||
import { SortingOrder } from '@anticrm/core'
|
||||
import { getClient, createQuery, Backlink } from '@anticrm/presentation'
|
||||
import type { AnySvelteComponent } from '@anticrm/ui'
|
||||
import { ReferenceInput } from '@anticrm/text-editor'
|
||||
import { IconClose, IconExpand, IconActivity, ScrollBox, Grid, Icon, IconToDo } from '@anticrm/ui'
|
||||
import type { Comment } from '@anticrm/chunter'
|
||||
import ActivityMsg from './ActivityMsg.svelte'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import chunter from '@anticrm/chunter'
|
||||
import activity from '@anticrm/activity'
|
||||
import type { Doc } from '@anticrm/core';
|
||||
import type { Asset } from '@anticrm/platform';
|
||||
import type { AnySvelteComponent } from '@anticrm/ui';
|
||||
import { Icon,IconClose,IconExpand, Component } from '@anticrm/ui';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
export let title: string
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
@ -35,19 +28,6 @@
|
||||
export let object: Doc
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let comments: Comment[]
|
||||
|
||||
const client = getClient()
|
||||
const query = createQuery()
|
||||
$: query.query(chunter.class.Comment, { attachedTo: object._id }, result => { comments = result }, { sort: { modifiedOn: SortingOrder.Descending } })
|
||||
|
||||
function onMessage(event: CustomEvent) {
|
||||
client.addCollection(chunter.class.Comment, object.space, object._id, object._class, 'comments', {
|
||||
message: event.detail
|
||||
})
|
||||
console.log(event.detail)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="overlay" on:click={() => { dispatch('close') }}/>
|
||||
@ -73,22 +53,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="rightSection">
|
||||
<div class="flex-row-center header">
|
||||
<div class="icon"><IconActivity size={'small'} /></div>
|
||||
<div class="title">Activity</div>
|
||||
</div>
|
||||
<div class="flex-col h-full content">
|
||||
<ScrollBox vertical stretch>
|
||||
{#if comments}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
{#each comments as comment}
|
||||
<Backlink {comment} />
|
||||
{/each}
|
||||
</Grid>
|
||||
{/if}
|
||||
</ScrollBox>
|
||||
</div>
|
||||
<div class="ref-input"><ReferenceInput on:message={onMessage}/></div>
|
||||
<Component is={activity.component.Activity} props={{object, fullSize}}/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="unionSection">
|
||||
@ -103,40 +68,10 @@
|
||||
<div class="title">{title}</div>
|
||||
</div>
|
||||
{#if $$slots.subtitle}<div class="flex-row-center subtitle"><slot name="subtitle" /></div>{/if}
|
||||
<ScrollBox vertical stretch noShift>
|
||||
<div class="flex-col content">
|
||||
|
||||
<Component is={activity.component.Activity} props={{object, fullSize}}>
|
||||
<slot />
|
||||
</div>
|
||||
<div class="flex-row-center activity header">
|
||||
<div class="icon"><IconActivity size={'small'} /></div>
|
||||
<div class="title">Activity</div>
|
||||
</div>
|
||||
<div class="flex-col activity content">
|
||||
{#if comments}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
|
||||
<!-- Start Demo -->
|
||||
<ActivityMsg icon={IconToDo}><span>Task TAS189</span> was created by <b>Tim Ferris</b> test</ActivityMsg>
|
||||
<ActivityMsg icon={IconToDo}>
|
||||
<b>Rosamund Chen</b> changed status from <span>IN PROGRESS</span> to <span class="bar">ON HOLD</span>
|
||||
<svelte:fragment slot="content">Content</svelte:fragment>
|
||||
</ActivityMsg>
|
||||
<ActivityMsg icon={IconToDo}>Task TAS189 was created by <b>Tim Ferris</b></ActivityMsg>
|
||||
<ActivityMsg icon={IconToDo}>
|
||||
Testing <b>Rosamund Chen</b> changed status from <span>IN PROGRESS</span> to <span class="bar">ON HOLD</span>.
|
||||
<div slot="content">Content</div>
|
||||
</ActivityMsg>
|
||||
<ActivityMsg icon={IconToDo}>Task TAS189 was created by <b>Tim Ferris</b></ActivityMsg>
|
||||
<!-- End Demo -->
|
||||
|
||||
{#each comments as comment}
|
||||
<Backlink {comment} />
|
||||
{/each}
|
||||
</Grid>
|
||||
{/if}
|
||||
</div>
|
||||
</ScrollBox>
|
||||
<div class="ref-input"><ReferenceInput on:message={onMessage}/></div>
|
||||
</Component>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -194,23 +129,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: max-content;
|
||||
|
||||
.content {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1.5rem 2.5rem;
|
||||
height: max-content;
|
||||
}
|
||||
.activity {
|
||||
background-color: var(--theme-dialog-accent);
|
||||
&.header { border-bottom: none; }
|
||||
&.content {
|
||||
flex-grow: 1;
|
||||
padding-bottom: 0;
|
||||
background-color: var(--theme-dialog-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fullSize {
|
||||
@ -236,17 +154,6 @@
|
||||
}
|
||||
.rightSection {
|
||||
background-color: transparent;
|
||||
.header { border-bottom: 1px solid var(--theme-dialog-divider); }
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
padding: 2.5rem 2.5rem 0;
|
||||
background-color: var(--theme-dialog-accent);
|
||||
}
|
||||
}
|
||||
|
||||
.ref-input {
|
||||
background-color: var(--theme-dialog-accent);
|
||||
padding: 1.5rem 2.5rem;
|
||||
}
|
||||
|
||||
.tools {
|
||||
|
44
packages/platform-rig/profiles/ui/config/eslint.config.json
Normal file
44
packages/platform-rig/profiles/ui/config/eslint.config.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"standard-with-typescript"
|
||||
],
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"project": [
|
||||
"**/tsconfig.json"
|
||||
],
|
||||
"extraFileExtensions": [".svelte"]
|
||||
},
|
||||
"plugins": ["svelte3", "@typescript-eslint", "import"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.svelte"],
|
||||
"processor" : "svelte3/svelte3",
|
||||
"rules" : {
|
||||
"import/first": "off",
|
||||
"import/no-duplicates": "off",
|
||||
"import/no-mutable-exports": "off",
|
||||
"import/no-unresolved": "off",
|
||||
"no-multiple-empty-lines": "off",
|
||||
"no-undef-init": "off",
|
||||
"no-use-before-define": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"svelte3/typescript": true
|
||||
}
|
||||
}
|
||||
|
17
packages/platform-rig/profiles/ui/config/heft.json
Normal file
17
packages/platform-rig/profiles/ui/config/heft.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/heft/heft.schema.json",
|
||||
|
||||
"eventActions": [
|
||||
{
|
||||
"actionKind": "deleteGlobs",
|
||||
"heftEvent": "clean",
|
||||
"actionId": "defaultClean",
|
||||
"globsToDelete": ["dist", "lib", "temp"]
|
||||
}
|
||||
],
|
||||
"heftPlugins": [
|
||||
{
|
||||
"plugin": "@rushstack/heft-jest-plugin"
|
||||
}
|
||||
]
|
||||
}
|
1
packages/platform-rig/profiles/ui/config/jest.config.js
Normal file
1
packages/platform-rig/profiles/ui/config/jest.config.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require("@anticrm/platform-rig/profiles/default/config/jest.config")
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"projectOutputFolderNames": ["lib", "dist"]
|
||||
}
|
76
packages/platform-rig/profiles/ui/config/typescript.json
Normal file
76
packages/platform-rig/profiles/ui/config/typescript.json
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Configures the TypeScript plugin for Heft. This plugin also manages linting.
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/heft/typescript.schema.json",
|
||||
|
||||
/**
|
||||
* Can be set to "copy" or "hardlink". If set to "copy", copy files from cache.
|
||||
* If set to "hardlink", files will be hardlinked to the cache location.
|
||||
* This option is useful when producing a tarball of build output as TAR files don't
|
||||
* handle these hardlinks correctly. "hardlink" is the default behavior.
|
||||
*/
|
||||
// "copyFromCacheMode": "copy",
|
||||
|
||||
/**
|
||||
* If provided, emit these module kinds in addition to the modules specified in the tsconfig.
|
||||
* Note that this option only applies to the main tsconfig.json configuration.
|
||||
*/
|
||||
"additionalModuleKindsToEmit": [
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Must be one of "commonjs", "amd", "umd", "system", "es2015", "esnext"
|
||||
// */
|
||||
// "moduleKind": "amd",
|
||||
//
|
||||
// /**
|
||||
// * (Required) The name of the folder where the output will be written.
|
||||
// */
|
||||
// "outFolderName": "lib-amd"
|
||||
// }
|
||||
],
|
||||
|
||||
/**
|
||||
* Specifies the intermediary folder that tests will use. Because Jest uses the
|
||||
* Node.js runtime to execute tests, the module format must be CommonJS.
|
||||
*
|
||||
* The default value is "lib".
|
||||
*/
|
||||
// "emitFolderNameForTests": "lib-commonjs",
|
||||
|
||||
/**
|
||||
* If set to "true", the TSlint task will not be invoked.
|
||||
*/
|
||||
// "disableTslint": true,
|
||||
|
||||
/**
|
||||
* Set this to change the maximum number of file handles that will be opened concurrently for writing.
|
||||
* The default is 50.
|
||||
*/
|
||||
// "maxWriteParallelism": 50,
|
||||
|
||||
/**
|
||||
* Describes the way files should be statically coped from src to TS output folders
|
||||
*/
|
||||
"staticAssetsToCopy": {
|
||||
/**
|
||||
* File extensions that should be copied from the src folder to the destination folder(s).
|
||||
*/
|
||||
"fileExtensions": [".json"]
|
||||
|
||||
/**
|
||||
* Glob patterns that should be explicitly included.
|
||||
*/
|
||||
// "includeGlobs": [
|
||||
// "some/path/*.js"
|
||||
// ],
|
||||
|
||||
/**
|
||||
* Glob patterns that should be explicitly excluded. This takes precedence over globs listed
|
||||
* in "includeGlobs" and files that match the file extensions provided in "fileExtensions".
|
||||
*/
|
||||
// "excludeGlobs": [
|
||||
// "some/path/*.css"
|
||||
// ]
|
||||
}
|
||||
}
|
11
packages/platform-rig/profiles/ui/tsconfig-base.json
Normal file
11
packages/platform-rig/profiles/ui/tsconfig-base.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"types": ["heft-jest"]
|
||||
}
|
||||
}
|
@ -100,6 +100,7 @@ table {
|
||||
}
|
||||
|
||||
.flex { display: flex; }
|
||||
.inline-flex { display: inline-flex; }
|
||||
.flex-grow { flex-grow: 1; }
|
||||
.flex-no-shrink { flex-shrink: 0; }
|
||||
.flex-nowrap {
|
||||
|
@ -31,7 +31,9 @@
|
||||
<Loading/>
|
||||
{:then Ctor}
|
||||
<ErrorBoundary>
|
||||
<Ctor {...props} on:change on:close on:open on:click/>
|
||||
<Ctor {...props} on:change on:close on:open on:click>
|
||||
<slot />
|
||||
</Ctor>
|
||||
</ErrorBoundary>
|
||||
{:catch err}
|
||||
ERROR: {console.log(err, JSON.stringify(component))}
|
||||
|
@ -12,22 +12,34 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
import { Asset, getMetadata } from '@anticrm/platform'
|
||||
import { AnySvelteComponent } from '../types';
|
||||
|
||||
export let icon: Asset
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let fill = 'currentColor'
|
||||
export let filled: boolean = false
|
||||
|
||||
function isAsset (icon: Asset | AnySvelteComponent): boolean {
|
||||
return typeof icon === 'string'
|
||||
}
|
||||
|
||||
function toAsset (icon: AnySvelteComponent | Asset): Asset {
|
||||
return icon as Asset
|
||||
}
|
||||
|
||||
let url: string
|
||||
$: url = getMetadata(icon) ?? 'https://anticrm.org/logo.svg'
|
||||
$: url = isAsset(icon) ? getMetadata(toAsset(icon)) ?? 'https://anticrm.org/logo.svg' : ''
|
||||
</script>
|
||||
|
||||
<svg class={size} {fill}>
|
||||
{#if isAsset(icon)}
|
||||
<svg class={size} {fill}>
|
||||
<use href={url} />
|
||||
</svg>
|
||||
</svg>
|
||||
{:else}
|
||||
<svelte:component this={icon} {size} {fill} {filled} />
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.small {
|
||||
|
7
plugins/activity-assets/assets/icons.svg
Normal file
7
plugins/activity-assets/assets/icons.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||
<symbol id="activity" viewBox="0 0 20 20">
|
||||
<path d="M8.4,8.5C8.2,8.4,8,8.3,7.9,8.3c-0.2,0-0.4,0.1-0.5,0.3l-2.9,3.8c-0.2,0.3-0.2,0.7,0.1,1c0.1,0.1,0.3,0.1,0.4,0.1 c0.2,0,0.4-0.1,0.6-0.3L8.1,10l2.8,2.2c0.1,0.1,0.3,0.2,0.5,0.1c0.2,0,0.4-0.1,0.5-0.3l2.8-3.7c0.2-0.3,0.2-0.7-0.1-1 c-0.3-0.2-0.7-0.2-1,0.1l-2.4,3.1L8.4,8.5z"/>
|
||||
<path d="M17.4,0c-1.4,0-2.6,1.2-2.6,2.6c0,1.4,1.2,2.6,2.6,2.6C18.8,5.1,20,4,20,2.5C20,1.1,18.8,0,17.4,0z M17.4,3.7 c-0.6,0-1.2-0.5-1.2-1.2c0-0.6,0.5-1.2,1.2-1.2c0.6,0,1.2,0.5,1.2,1.2C18.6,3.2,18.1,3.7,17.4,3.7z"/>
|
||||
<path d="M18.5,6.8c-0.4,0-0.7,0.3-0.7,0.7v6.8c0,2.6-1.6,4.3-4,4.3H5.4c-2.5,0-4-1.6-4-4.3V6.5c0-2.6,1.6-4.3,4-4.3h7.1 c0.4,0,0.7-0.3,0.7-0.7s-0.3-0.7-0.7-0.7H5.4C2.2,0.8,0,3.1,0,6.5v7.9C0,17.7,2.2,20,5.4,20h8.4c3.3,0,5.4-2.3,5.4-5.7V7.5 C19.2,7.1,18.9,6.8,18.5,6.8z"/>
|
||||
</symbol>
|
||||
</svg>
|
After Width: | Height: | Size: 900 B |
28
plugins/activity-assets/package.json
Normal file
28
plugins/activity-assets/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@anticrm/activity-assets",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"format": "prettier --write src && eslint --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/platform-rig":"~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/platform":"~0.6.5",
|
||||
"@anticrm/activity":"~0.6.0"
|
||||
}
|
||||
}
|
22
plugins/activity-assets/src/index.ts
Normal file
22
plugins/activity-assets/src/index.ts
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// 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 { loadMetadata } from '@anticrm/platform'
|
||||
import activity from '@anticrm/activity'
|
||||
|
||||
const icons = require('../assets/icons.svg') // eslint-disable-line
|
||||
loadMetadata(activity.icon, {
|
||||
Activity: `${icons}#activity` // eslint-disable-line
|
||||
})
|
15
plugins/activity-assets/tsconfig.json
Normal file
15
plugins/activity-assets/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
7
plugins/activity-resources/.eslintrc.js
Normal file
7
plugins/activity-resources/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/platform-rig/profiles/ui/config/eslint.config.json'],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
settings: {
|
||||
'svelte3/ignore-styles': () => true
|
||||
}
|
||||
};
|
43
plugins/activity-resources/package.json
Normal file
43
plugins/activity-resources/package.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@anticrm/activity-resources",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "svelte-check",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"format": "prettier --write --plugin-search-dir=. src && eslint --fix src",
|
||||
"svelte-check": "svelte-check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"svelte-loader":"^3.1.2",
|
||||
"sass":"^1.37.5",
|
||||
"svelte-preprocess":"^4.7.4",
|
||||
"@anticrm/platform-rig":"~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-svelte3": "~3.2.1",
|
||||
"prettier-plugin-svelte": "^2.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.4.1",
|
||||
"svelte-check": "^2.2.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/core":"~0.6.11",
|
||||
"@anticrm/platform":"~0.6.5",
|
||||
"@anticrm/ui":"~0.6.0",
|
||||
"@anticrm/presentation":"~0.6.2",
|
||||
"@anticrm/activity":"~0.6.0",
|
||||
"svelte":"^3.37.0",
|
||||
"@anticrm/chunter":"~0.6.1",
|
||||
"@anticrm/text-editor":"~0.6.0",
|
||||
"@anticrm/contact":"~0.6.2",
|
||||
"@anticrm/view": "~0.6.0"
|
||||
}
|
||||
}
|
5
plugins/activity-resources/postcss.config.js
Normal file
5
plugins/activity-resources/postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
195
plugins/activity-resources/src/components/Activity.svelte
Normal file
195
plugins/activity-resources/src/components/Activity.svelte
Normal file
@ -0,0 +1,195 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import activity, { TxViewlet } from '@anticrm/activity'
|
||||
import chunter from '@anticrm/chunter'
|
||||
import type { AttachedDoc, Doc, Ref, TxCollectionCUD, TxCUD } from '@anticrm/core'
|
||||
import core, { SortingOrder } from '@anticrm/core'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { ReferenceInput } from '@anticrm/text-editor'
|
||||
import { Grid, IconActivity, ScrollBox } from '@anticrm/ui'
|
||||
import { ActivityKey, activityKey } from '../utils'
|
||||
import TxView from './TxView.svelte'
|
||||
|
||||
export let fullSize: boolean = false
|
||||
export let object: Doc
|
||||
|
||||
let txes1: TxCUD<Doc>[] = []
|
||||
let txes2: TxCUD<Doc>[] = []
|
||||
|
||||
let txes: TxCUD<Doc>[]
|
||||
|
||||
$: txes = Array.from(txes1).concat(txes2).sort((a, b) => b.modifiedOn - a.modifiedOn)
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const txQuery1 = createQuery()
|
||||
const txQuery2 = createQuery()
|
||||
|
||||
let isAttached = false
|
||||
|
||||
$: isAttached = client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)
|
||||
$: txQuery1.query<TxCollectionCUD<Doc, AttachedDoc>>(
|
||||
isAttached ? core.class.TxCollectionCUD : core.class.TxCUD,
|
||||
isAttached
|
||||
? { 'tx.objectId': object._id as Ref<AttachedDoc> }
|
||||
: {
|
||||
objectId: object._id,
|
||||
_class: { $in: [core.class.TxCreateDoc, core.class.TxUpdateDoc, core.class.TxRemoveDoc] }
|
||||
},
|
||||
(result) => {
|
||||
txes1 = result
|
||||
},
|
||||
{ sort: { modifiedOn: SortingOrder.Descending } }
|
||||
)
|
||||
|
||||
$: txQuery2.query<TxCUD<Doc>>(
|
||||
core.class.TxCollectionCUD,
|
||||
{
|
||||
objectId: object._id,
|
||||
'tx._class': { $in: [core.class.TxCreateDoc, core.class.TxRemoveDoc] }
|
||||
},
|
||||
(result) => {
|
||||
txes2 = result
|
||||
},
|
||||
{ sort: { modifiedOn: SortingOrder.Descending } }
|
||||
)
|
||||
|
||||
function onMessage (event: CustomEvent) {
|
||||
client.addCollection(chunter.class.Comment, object.space, object._id, object._class, 'comments', {
|
||||
message: event.detail
|
||||
})
|
||||
console.log(event.detail)
|
||||
}
|
||||
|
||||
let viewlets: Map<ActivityKey, TxViewlet>
|
||||
|
||||
const descriptors = createQuery()
|
||||
$: descriptors.query(activity.class.TxViewlet, {}, (result) => {
|
||||
viewlets = new Map(result.map(r => ([activityKey(r.objectClass, r.txClass), r])))
|
||||
})
|
||||
|
||||
</script>
|
||||
{#if fullSize}
|
||||
<div class="flex-row-center header">
|
||||
<div class="icon"><IconActivity size={'small'} /></div>
|
||||
<div class="title">Activity</div>
|
||||
</div>
|
||||
<div class="flex-col h-full right-content">
|
||||
<ScrollBox vertical stretch>
|
||||
{#if txes}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
{#each txes as tx}
|
||||
<TxView {tx} {viewlets}/>
|
||||
{/each}
|
||||
</Grid>
|
||||
{/if}
|
||||
</ScrollBox>
|
||||
</div>
|
||||
<div class="ref-input"><ReferenceInput on:message={onMessage} /></div>
|
||||
{:else}
|
||||
<div class="unionSection">
|
||||
<ScrollBox vertical stretch noShift>
|
||||
<div class="flex-col content">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="flex-row-center activity header">
|
||||
<div class="icon"><IconActivity size={'small'} /></div>
|
||||
<div class="title">Activity</div>
|
||||
</div>
|
||||
<div class="flex-col activity content">
|
||||
{#if txes}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
{#each txes as tx}
|
||||
<TxView {tx} {viewlets}/>
|
||||
{/each}
|
||||
</Grid>
|
||||
{/if}
|
||||
</div>
|
||||
</ScrollBox>
|
||||
<div class="ref-input"><ReferenceInput on:message={onMessage} /></div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.header {
|
||||
flex-shrink: 0;
|
||||
padding: 0 2.5rem;
|
||||
height: 4.5rem;
|
||||
border-bottom: 1px solid var(--theme-card-divider);
|
||||
|
||||
.icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
margin-left: 0.5rem;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
color: var(--theme-caption-color);
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
.activity {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
&.header {
|
||||
border-bottom: none;
|
||||
}
|
||||
&.content {
|
||||
flex-grow: 1;
|
||||
padding-bottom: 0;
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
.ref-input {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
padding: 1.5rem 2.5rem;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
flex-grow: 1;
|
||||
padding: 2.5rem 2.5rem 0;
|
||||
background-color: var(--theme-dialog-accent);
|
||||
}
|
||||
|
||||
.unionSection {
|
||||
flex-grow: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: max-content;
|
||||
|
||||
.content {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1.5rem 2.5rem;
|
||||
height: max-content;
|
||||
}
|
||||
.activity {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
&.header {
|
||||
border-bottom: none;
|
||||
}
|
||||
&.content {
|
||||
flex-grow: 1;
|
||||
padding-bottom: 0;
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
202
plugins/activity-resources/src/components/TxView.svelte
Normal file
202
plugins/activity-resources/src/components/TxView.svelte
Normal file
@ -0,0 +1,202 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { TxViewlet } from '@anticrm/activity'
|
||||
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
||||
import type { AttachedDoc, Doc, Ref, Tx, TxCollectionCUD, TxCUD, TxUpdateDoc } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import { Component, Icon, Label, TimeSince } from '@anticrm/ui'
|
||||
import type { AttributeModel } from '@anticrm/view'
|
||||
import view, { BuildModelOptions } from '@anticrm/view'
|
||||
import { activityKey, ActivityKey } from '../utils'
|
||||
import activity from '@anticrm/activity'
|
||||
|
||||
export let tx: Tx
|
||||
export let viewlets: Map<ActivityKey, TxViewlet>
|
||||
|
||||
let viewlet: TxViewlet | undefined
|
||||
let displayTx: TxCUD<Doc> | undefined
|
||||
let utx: TxUpdateDoc<Doc> | undefined
|
||||
|
||||
const client = getClient()
|
||||
|
||||
$: if (client.getHierarchy().isDerived(tx._class, core.class.TxCollectionCUD)) {
|
||||
const colCUD = (tx as TxCollectionCUD<Doc, AttachedDoc>)
|
||||
displayTx = colCUD.tx
|
||||
} else if (client.getHierarchy().isDerived(tx._class, core.class.TxCUD)) {
|
||||
displayTx = tx as TxCUD<Doc>
|
||||
}
|
||||
|
||||
$: if (displayTx !== undefined) {
|
||||
const key = activityKey(displayTx.objectClass, displayTx._class)
|
||||
viewlet = viewlets.get(key)
|
||||
} else {
|
||||
viewlet = undefined
|
||||
}
|
||||
|
||||
let employee: EmployeeAccount | undefined
|
||||
$: client.findOne(contact.class.EmployeeAccount, { _id: tx.modifiedBy as Ref<EmployeeAccount> }).then(account => { employee = account })
|
||||
|
||||
$: client.findAll(contact.class.EmployeeAccount, { }).then(accounts => { console.log(tx.modifiedBy, 'accounts', accounts) })
|
||||
let model: AttributeModel[] = []
|
||||
|
||||
let buildModel: ((options: BuildModelOptions) => Promise<AttributeModel[]>)|undefined
|
||||
getResource(view.api.buildModel).then(bm => {
|
||||
buildModel = bm
|
||||
})
|
||||
|
||||
$: if (displayTx !== undefined && displayTx._class === core.class.TxUpdateDoc) {
|
||||
utx = displayTx as TxUpdateDoc<Doc>
|
||||
const ops = { client, _class: utx.objectClass, keys: Object.keys(utx.operations), ignoreMissing: true }
|
||||
model = []
|
||||
buildModel?.(ops).then(m => {
|
||||
model = m
|
||||
})
|
||||
} else {
|
||||
model = []
|
||||
utx = undefined
|
||||
}
|
||||
|
||||
function getValue (utx: TxUpdateDoc<Doc>, key: string): any {
|
||||
return (utx.operations as any)[key]
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if displayTx && (viewlet !== undefined || model.length > 0)}
|
||||
<div class="flex-col msg-container">
|
||||
<div class="flex-between">
|
||||
<div class="flex-center icon">
|
||||
<div class="scale-75">
|
||||
{#if viewlet}
|
||||
<Icon icon={viewlet.icon} size='medium'/>
|
||||
{:else}
|
||||
<Icon icon={activity.icon.Activity} size='medium'/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-grow label">
|
||||
<b>
|
||||
{#if employee}
|
||||
{formatName(employee.name)}
|
||||
{:else}
|
||||
No employee
|
||||
{/if}
|
||||
</b>
|
||||
{#if viewlet}
|
||||
<Label label={viewlet.label}/>
|
||||
{/if}
|
||||
{#if viewlet === undefined && model.length > 0 && utx}
|
||||
{#each model as m}
|
||||
<div class='change'>
|
||||
changed {m.label} to
|
||||
<div class='value'>
|
||||
<svelte:component this={m.presenter} value={getValue(utx, m.key)}/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
||||
<Component is={viewlet.component} props={{ tx: displayTx }} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="content-trans-color"><TimeSince value={tx.modifiedOn}/></div>
|
||||
</div>
|
||||
{#if viewlet && viewlet.component && viewlet.display !== 'inline'}
|
||||
<div class='content' class:emphasize={viewlet.display === 'emphasized'}>
|
||||
<Component is={viewlet.component} props={{ tx: displayTx }} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<style lang="scss">
|
||||
.change {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
.value {
|
||||
gap: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.msg-container {
|
||||
position: relative;
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2.25rem;
|
||||
left: 1.125rem;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background-color: var(--theme-card-divider);
|
||||
}
|
||||
}
|
||||
:global(.msg-container + .msg-container::before) {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -1.5rem;
|
||||
left: 1.125rem;
|
||||
height: 1.5rem;
|
||||
width: 1px;
|
||||
background-color: var(--theme-card-divider);
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
border: 1px solid var(--theme-card-divider);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 0.5rem 0 0.5rem 3.25rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
.emphasize {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
:global(.label b) {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
:global(.label span) {
|
||||
display: inline-block;
|
||||
padding: 0.125rem 0.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-bg-focused-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
:global(.label span.bar) {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-weight: 500;
|
||||
font-size: 0.625rem;
|
||||
background-color: var(--primary-button-enabled);
|
||||
}
|
||||
</style>
|
23
plugins/activity-resources/src/index.ts
Normal file
23
plugins/activity-resources/src/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// 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 { Resources } from '@anticrm/platform'
|
||||
import Activity from './components/Activity.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
Activity
|
||||
}
|
||||
})
|
24
plugins/activity-resources/src/plugin.ts
Normal file
24
plugins/activity-resources/src/plugin.ts
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// 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 chunter, { chunterId } from '@anticrm/chunter'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { mergeIds } from '@anticrm/platform'
|
||||
|
||||
export default mergeIds(chunterId, chunter, {
|
||||
string: {
|
||||
Activity: '' as IntlString
|
||||
}
|
||||
})
|
7
plugins/activity-resources/src/utils.ts
Normal file
7
plugins/activity-resources/src/utils.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Class, Doc, Ref, Tx } from '@anticrm/core'
|
||||
|
||||
export type ActivityKey = string
|
||||
|
||||
export function activityKey (objectClass: Ref<Class<Doc>>, txClass: Ref<Class<Tx>>): ActivityKey {
|
||||
return objectClass + ':' + txClass
|
||||
}
|
5
plugins/activity-resources/svelte.config.js
Normal file
5
plugins/activity-resources/svelte.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
15
plugins/activity-resources/tsconfig.json
Normal file
15
plugins/activity-resources/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
7
plugins/activity/.eslintrc.js
Normal file
7
plugins/activity/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
4
plugins/activity/.npmignore
Normal file
4
plugins/activity/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
5
plugins/activity/config/rig.json
Normal file
5
plugins/activity/config/rig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@anticrm/platform-rig",
|
||||
"rigProfile": "default"
|
||||
}
|
31
plugins/activity/package.json
Normal file
31
plugins/activity/package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "@anticrm/activity",
|
||||
"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",
|
||||
"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",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.4.1",
|
||||
"@rushstack/heft": "^0.41.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/platform":"~0.6.5",
|
||||
"@anticrm/core":"~0.6.12",
|
||||
"@anticrm/ui": "~0.6.0"
|
||||
}
|
||||
}
|
54
plugins/activity/src/index.ts
Normal file
54
plugins/activity/src/index.ts
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// 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 type { Class, Doc, DocumentQuery, Ref, Tx } from '@anticrm/core'
|
||||
import type { Asset, IntlString, Plugin } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
/**
|
||||
* Define an display for all transaction kinds for particular class.
|
||||
* @public
|
||||
*/
|
||||
export interface TxViewlet extends Doc {
|
||||
icon: Asset
|
||||
objectClass: Ref<Class<Doc>>
|
||||
txClass: Ref<Class<Tx>>
|
||||
// Component to display on.
|
||||
component?: AnyComponent
|
||||
// Filter
|
||||
match?: DocumentQuery<Tx>
|
||||
|
||||
// Label will be displayed right after author
|
||||
label: IntlString
|
||||
// Do component need to be emphasized or not.
|
||||
display: 'inline' | 'content' | 'emphasized'
|
||||
}
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const activityId = 'activity' as Plugin
|
||||
|
||||
export default plugin(activityId, {
|
||||
icon: {
|
||||
Activity: '' as Asset
|
||||
},
|
||||
class: {
|
||||
TxViewlet: '' as Ref<Class<TxViewlet>>
|
||||
},
|
||||
component: {
|
||||
Activity: '' as AnyComponent
|
||||
}
|
||||
})
|
9
plugins/activity/tsconfig.json
Normal file
9
plugins/activity/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"lib": ["esnext", "dom"]
|
||||
}
|
||||
}
|
7
plugins/chunter-assets/lang/en.json
Normal file
7
plugins/chunter-assets/lang/en.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"string": {
|
||||
"ApplicationLabelChunter": "Chat",
|
||||
"LeftComment": "left a comment",
|
||||
"AddAttachment": "uploaded an attachment"
|
||||
}
|
||||
}
|
@ -13,12 +13,15 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { loadMetadata } from '@anticrm/platform'
|
||||
import chunter from '@anticrm/chunter'
|
||||
import { addStringsLoader, loadMetadata } from '@anticrm/platform'
|
||||
import chunter, {chunterId} from '@anticrm/chunter'
|
||||
|
||||
const icons = require('../assets/icons.svg')
|
||||
loadMetadata(chunter.icon, {
|
||||
Chunter: `${icons}#chunter`,
|
||||
Hashtag: `${icons}#hashtag`,
|
||||
Lock: `${icons}#lock`
|
||||
Lock: `${icons}#lock`,
|
||||
Attachment: `${icons}#chunter`
|
||||
})
|
||||
|
||||
addStringsLoader(chunterId, async (lang: string) => await import(`../lang/${lang}.json`))
|
||||
|
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Attachment } from "@anticrm/chunter";
|
||||
import type { TxCreateDoc } from "@anticrm/core";
|
||||
import { TxProcessor } from '@anticrm/core';
|
||||
import AttachmentPresenter from "../AttachmentPresenter.svelte";
|
||||
|
||||
export let tx: TxCreateDoc<Attachment>
|
||||
</script>
|
||||
|
||||
<AttachmentPresenter value={TxProcessor.createDoc2Doc(tx)}/>
|
@ -0,0 +1,33 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Comment } from "@anticrm/chunter"
|
||||
import type { TxCreateDoc } from "@anticrm/core"
|
||||
import { MessageViewer } from '@anticrm/presentation'
|
||||
|
||||
export let tx: TxCreateDoc<Comment>
|
||||
</script>
|
||||
|
||||
<div class="text">
|
||||
<MessageViewer message={tx.attributes.message}/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.text {
|
||||
line-height: 150%;
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
</style>
|
@ -18,6 +18,8 @@ import ChannelView from './components/ChannelView.svelte'
|
||||
import Activity from './components/Activity.svelte'
|
||||
import AttachmentsPresenter from './components/AttachmentsPresenter.svelte'
|
||||
import AttachmentPresenter from './components/AttachmentPresenter.svelte'
|
||||
import TxCommentCreate from './components/activity/TxCommentCreate.svelte'
|
||||
import TxAttachmentCreate from './components/activity/TxAttachmentCreate.svelte'
|
||||
|
||||
export { AttachmentsPresenter }
|
||||
|
||||
@ -28,5 +30,9 @@ export default async () => ({
|
||||
Activity,
|
||||
AttachmentsPresenter,
|
||||
AttachmentPresenter
|
||||
},
|
||||
activity: {
|
||||
TxCommentCreate: TxCommentCreate,
|
||||
TxAttachmentCreate
|
||||
}
|
||||
})
|
||||
|
@ -64,7 +64,8 @@ export default plugin(chunterId, {
|
||||
icon: {
|
||||
Chunter: '' as Asset,
|
||||
Hashtag: '' as Asset,
|
||||
Lock: '' as Asset
|
||||
Lock: '' as Asset,
|
||||
Attachment: '' as Asset
|
||||
},
|
||||
class: {
|
||||
Message: '' as Ref<Class<Message>>,
|
||||
|
@ -6,6 +6,9 @@
|
||||
"VacancyDescription": "Vacancy Description",
|
||||
"CreateVacancy": "Create Vacancy",
|
||||
"CreateCandidate": "Create Candidate",
|
||||
"MakePrivate": "Make Private"
|
||||
"MakePrivate": "Make Private",
|
||||
"TxApplicantCreate": "created application",
|
||||
"TxApplicantUpdate": "",
|
||||
"TxCandidateCreate": "created candidate"
|
||||
}
|
||||
}
|
7
plugins/recruit-resources/.eslintrc.js
Normal file
7
plugins/recruit-resources/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/platform-rig/profiles/ui/config/eslint.config.json'],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
settings: {
|
||||
'svelte3/ignore-styles': () => true
|
||||
}
|
||||
};
|
@ -15,6 +15,18 @@
|
||||
"svelte-loader":"^3.1.2",
|
||||
"sass":"^1.37.5",
|
||||
"svelte-preprocess":"^4.7.4",
|
||||
"@anticrm/platform-rig":"~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-svelte3": "~3.2.1",
|
||||
"prettier-plugin-svelte": "^2.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"prettier": "^2.4.1",
|
||||
"svelte-check": "^2.2.10",
|
||||
"@types/deep-equal":"^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -94,13 +94,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Start Demo -->
|
||||
<div class="group cards-container">
|
||||
<PluginCard icon={Telegram} />
|
||||
<PluginCard icon={Gmail} />
|
||||
</div>
|
||||
<!-- End Demo -->
|
||||
|
||||
<div class="flex-col group">
|
||||
<div class="flex-row-center">
|
||||
<div class="caption">Applications</div>
|
||||
|
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Applicant } from '@anticrm/recruit'
|
||||
import type { TxCreateDoc } from '@anticrm/core'
|
||||
import { TxProcessor } from '@anticrm/core'
|
||||
import ApplicationPresenter from '../ApplicationPresenter.svelte'
|
||||
|
||||
export let tx: TxCreateDoc<Applicant>
|
||||
</script>
|
||||
|
||||
<ApplicationPresenter value={TxProcessor.createDoc2Doc(tx)}/>
|
@ -0,0 +1,55 @@
|
||||
<!--
|
||||
// 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.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Class, State, TxUpdateDoc } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import type { Applicant } from '@anticrm/recruit'
|
||||
import { Component } from '@anticrm/ui'
|
||||
import view from '@anticrm/view'
|
||||
|
||||
export let tx: TxUpdateDoc<Applicant>
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const stateClass = client.getModel().getObject(core.class.State) as Class<State>
|
||||
const statePresenter = client.getHierarchy().as(stateClass, view.mixin.AttributePresenter)
|
||||
|
||||
</script>
|
||||
|
||||
{#if tx.operations.state}
|
||||
updated State to
|
||||
{#if statePresenter?.presenter}
|
||||
{#await client.findOne(core.class.State, { _id: tx.operations.state }) then st}
|
||||
{#if st}
|
||||
<Component is={statePresenter.presenter} props={{ value: st }}/>
|
||||
{/if}
|
||||
{/await}
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang='scss'>
|
||||
.state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -25,13 +25,17 @@ import KanbanCard from './components/KanbanCard.svelte'
|
||||
import ApplicationPresenter from './components/ApplicationPresenter.svelte'
|
||||
import ApplicationsPresenter from './components/ApplicationsPresenter.svelte'
|
||||
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import TxApplicantCreate from './components/activity/TxApplicantCreate.svelte'
|
||||
import TxApplicantUpdate from './components/activity/TxApplicantUpdate.svelte'
|
||||
|
||||
async function createApplication(object: Doc): Promise<void> {
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import { Resources } from '@anticrm/platform'
|
||||
|
||||
async function createApplication (object: Doc): Promise<void> {
|
||||
showPopup(CreateApplication, { candidate: object._id, preserveCandidate: true })
|
||||
}
|
||||
|
||||
export default async () => ({
|
||||
export default async (): Promise<Resources> => ({
|
||||
actionImpl: {
|
||||
CreateApplication: createApplication
|
||||
},
|
||||
@ -44,6 +48,10 @@ export default async () => ({
|
||||
Attachments,
|
||||
KanbanCard,
|
||||
ApplicationPresenter,
|
||||
ApplicationsPresenter,
|
||||
ApplicationsPresenter
|
||||
},
|
||||
activity: {
|
||||
TxApplicantCreate,
|
||||
TxApplicantUpdate
|
||||
}
|
||||
})
|
||||
|
@ -70,7 +70,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await buildModel(client, _class, config, options)}
|
||||
{#await buildModel({client, _class, keys: config, options})}
|
||||
<Loading/>
|
||||
{:then model}
|
||||
<table class="table-body">
|
||||
|
@ -73,7 +73,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await buildModel(client, _class, config, options)}
|
||||
{#await buildModel({client, _class, keys: config, options})}
|
||||
<Loading/>
|
||||
{:then model}
|
||||
<div class="container">
|
||||
|
@ -26,8 +26,10 @@ import KanbanView from './components/KanbanView.svelte'
|
||||
|
||||
import { getClient, MessageBox } from '@anticrm/presentation'
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
import {buildModel} from './utils'
|
||||
|
||||
export { Table }
|
||||
export { buildModel } from './utils'
|
||||
|
||||
function Delete(object: Doc): void {
|
||||
showPopup(MessageBox, {
|
||||
@ -54,4 +56,7 @@ export default async () => ({
|
||||
KanbanView,
|
||||
TimestampPresenter
|
||||
},
|
||||
api: {
|
||||
buildModel
|
||||
}
|
||||
})
|
||||
|
@ -18,15 +18,9 @@ import type { IntlString } from '@anticrm/platform'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import type { Ref, Class, Obj, FindOptions, Doc, Client } from '@anticrm/core'
|
||||
import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
|
||||
import type { Action, ActionTarget } from '@anticrm/view'
|
||||
import type { Action, ActionTarget, BuildModelOptions } from '@anticrm/view'
|
||||
|
||||
import view from '@anticrm/view'
|
||||
|
||||
export interface AttributeModel {
|
||||
key: string
|
||||
label: IntlString
|
||||
presenter: AnySvelteComponent
|
||||
}
|
||||
import view, { AttributeModel } from '@anticrm/view'
|
||||
|
||||
async function getObjectPresenter(client: Client, _class: Ref<Class<Obj>>, preserveKey: string): Promise<AttributeModel> {
|
||||
const clazz = client.getHierarchy().getClass(_class)
|
||||
@ -94,11 +88,20 @@ async function getPresenter(client: Client, _class: Ref<Class<Obj>>, key: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function buildModel(client: Client, _class: Ref<Class<Obj>>, keys: string[], options?: FindOptions<Doc>): Promise<AttributeModel[]> {
|
||||
console.log('building table model for', _class)
|
||||
const model = keys.map(key => getPresenter(client, _class, key, key, options))
|
||||
export async function buildModel(options: BuildModelOptions): Promise<AttributeModel[]> {
|
||||
console.log('building table model for', options._class)
|
||||
const model = options.keys.map(key => {
|
||||
try {
|
||||
const result = getPresenter(options.client, options._class, key, key, options.options)
|
||||
return result
|
||||
} catch(err: any) {
|
||||
if (!(options.ignoreMissing ?? false)) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
})
|
||||
console.log(model)
|
||||
return await Promise.all(model)
|
||||
return (await Promise.all(model)).filter(a => a !== undefined) as AttributeModel[]
|
||||
}
|
||||
|
||||
function filterActions(client: Client, _class: Ref<Class<Obj>>, targets: ActionTarget[]): Ref<Action>[] {
|
||||
|
@ -14,11 +14,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Plugin, Asset, Resource } from '@anticrm/platform'
|
||||
import type { Plugin, Asset, Resource, IntlString } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Ref, Mixin, UXObject, Space, FindOptions, Class, Doc, Arr, State } from '@anticrm/core'
|
||||
import type { Ref, Mixin, UXObject, Space, FindOptions, Class, Doc, Arr, State, Client, Obj } from '@anticrm/core'
|
||||
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -103,6 +103,26 @@ export interface Sequence extends Doc {
|
||||
*/
|
||||
export const viewId = 'view' as Plugin
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface AttributeModel {
|
||||
key: string
|
||||
label: IntlString
|
||||
presenter: AnySvelteComponent
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface BuildModelOptions {
|
||||
client: Client
|
||||
_class: Ref<Class<Obj>>
|
||||
keys: string[]
|
||||
options?: FindOptions<Doc>
|
||||
ignoreMissing?: boolean
|
||||
}
|
||||
|
||||
export default plugin(viewId, {
|
||||
mixin: {
|
||||
AttributeEditor: '' as Ref<Mixin<AttributeEditor>>,
|
||||
@ -128,5 +148,8 @@ export default plugin(viewId, {
|
||||
icon: {
|
||||
Table: '' as Asset,
|
||||
Kanban: '' as Asset
|
||||
},
|
||||
api: {
|
||||
buildModel: '' as Resource<(options: BuildModelOptions) => Promise<AttributeModel[]>>
|
||||
}
|
||||
})
|
||||
|
20
rush.json
20
rush.json
@ -796,5 +796,25 @@
|
||||
"projectFolder": "packages/panel",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/activity",
|
||||
"projectFolder": "plugins/activity",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/activity-assets",
|
||||
"projectFolder": "plugins/activity-assets",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/activity-resources",
|
||||
"projectFolder": "plugins/activity-resources",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/model-activity",
|
||||
"projectFolder": "models/activity",
|
||||
"shouldPublish": true
|
||||
},
|
||||
]
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user