Rework reviews (#1156)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2022-03-18 13:37:49 +07:00 committed by GitHub
parent c37d6b8e0e
commit a4af938871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 1422 additions and 522 deletions

View File

@ -13,6 +13,9 @@ specifiers:
'@rush-temp/attachment': file:./projects/attachment.tgz
'@rush-temp/attachment-assets': file:./projects/attachment-assets.tgz
'@rush-temp/attachment-resources': file:./projects/attachment-resources.tgz
'@rush-temp/calendar': file:./projects/calendar.tgz
'@rush-temp/calendar-assets': file:./projects/calendar-assets.tgz
'@rush-temp/calendar-resources': file:./projects/calendar-resources.tgz
'@rush-temp/chunter': file:./projects/chunter.tgz
'@rush-temp/chunter-assets': file:./projects/chunter-assets.tgz
'@rush-temp/chunter-resources': file:./projects/chunter-resources.tgz
@ -50,6 +53,7 @@ specifiers:
'@rush-temp/model-activity': file:./projects/model-activity.tgz
'@rush-temp/model-all': file:./projects/model-all.tgz
'@rush-temp/model-attachment': file:./projects/model-attachment.tgz
'@rush-temp/model-calendar': file:./projects/model-calendar.tgz
'@rush-temp/model-chunter': file:./projects/model-chunter.tgz
'@rush-temp/model-contact': file:./projects/model-contact.tgz
'@rush-temp/model-core': file:./projects/model-core.tgz
@ -167,7 +171,6 @@ specifiers:
'@types/koa__cors': ^3.0.3
'@types/mime-types': ~2.1.1
'@types/minio': ~7.0.11
'@types/node': ~16.11.12
'@types/pdfkit': ~0.12.3
'@types/prosemirror-model': ~1.16.0
'@types/request': ~2.48.8
@ -257,6 +260,9 @@ dependencies:
'@rush-temp/attachment': file:projects/attachment.tgz
'@rush-temp/attachment-assets': file:projects/attachment-assets.tgz_typescript@4.5.4
'@rush-temp/attachment-resources': file:projects/attachment-resources.tgz_096c09b0b673a57c275d9767a12070b1
'@rush-temp/calendar': file:projects/calendar.tgz
'@rush-temp/calendar-assets': file:projects/calendar-assets.tgz_typescript@4.5.4
'@rush-temp/calendar-resources': file:projects/calendar-resources.tgz_096c09b0b673a57c275d9767a12070b1
'@rush-temp/chunter': file:projects/chunter.tgz
'@rush-temp/chunter-assets': file:projects/chunter-assets.tgz_typescript@4.5.4
'@rush-temp/chunter-resources': file:projects/chunter-resources.tgz_096c09b0b673a57c275d9767a12070b1
@ -269,11 +275,11 @@ dependencies:
'@rush-temp/core': file:projects/core.tgz
'@rush-temp/dev-account': file:projects/dev-account.tgz
'@rush-temp/dev-client-resources': file:projects/dev-client-resources.tgz
'@rush-temp/dev-server': file:projects/dev-server.tgz_@types+node@16.11.14
'@rush-temp/dev-server': file:projects/dev-server.tgz
'@rush-temp/dev-storage': file:projects/dev-storage.tgz
'@rush-temp/devmodel': file:projects/devmodel.tgz_typescript@4.5.4
'@rush-temp/devmodel-resources': file:projects/devmodel-resources.tgz_6cae74ea501386c76c405ad0408e0339
'@rush-temp/elastic': file:projects/elastic.tgz_@types+node@16.11.14
'@rush-temp/elastic': file:projects/elastic.tgz
'@rush-temp/front': file:projects/front.tgz
'@rush-temp/generator': file:projects/generator.tgz
'@rush-temp/gmail': file:projects/gmail.tgz
@ -294,6 +300,7 @@ dependencies:
'@rush-temp/model-activity': file:projects/model-activity.tgz_typescript@4.5.4
'@rush-temp/model-all': file:projects/model-all.tgz_typescript@4.5.4
'@rush-temp/model-attachment': file:projects/model-attachment.tgz_typescript@4.5.4
'@rush-temp/model-calendar': file:projects/model-calendar.tgz_typescript@4.5.4
'@rush-temp/model-chunter': file:projects/model-chunter.tgz_typescript@4.5.4
'@rush-temp/model-contact': file:projects/model-contact.tgz_typescript@4.5.4
'@rush-temp/model-core': file:projects/model-core.tgz_typescript@4.5.4
@ -411,7 +418,6 @@ dependencies:
'@types/koa__cors': 3.1.0
'@types/mime-types': 2.1.1
'@types/minio': 7.0.11
'@types/node': 16.11.14
'@types/pdfkit': 0.12.3
'@types/prosemirror-model': 1.16.0
'@types/request': 2.48.8
@ -478,7 +484,7 @@ dependencies:
svgo-loader: 3.0.0
toposort: 2.0.2
ts-loader: 9.2.6_typescript@4.5.4+webpack@5.65.0
ts-node: 10.5.0_5d12c2add188ff0e728b4ade3dacd39b
ts-node: 10.5.0_typescript@4.5.4
typescript: 4.5.4
uuid: 8.3.2
webpack: 5.65.0_9def3870c80213359789f9191dbd286a
@ -8563,7 +8569,7 @@ packages:
dependencies:
import-cwd: 3.0.0
lilconfig: 2.0.4
ts-node: 10.5.0_5d12c2add188ff0e728b4ade3dacd39b
ts-node: 10.5.0_typescript@4.5.4
yaml: 1.10.2
dev: false
@ -10452,6 +10458,36 @@ packages:
yn: 3.1.1
dev: false
/ts-node/10.5.0_typescript@4.5.4:
resolution: {integrity: sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==}
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
'@swc/wasm': '>=1.2.50'
'@types/node': '*'
typescript: '>=2.7'
peerDependenciesMeta:
'@swc/core':
optional: true
'@swc/wasm':
optional: true
dependencies:
'@cspotcode/source-map-support': 0.7.0
'@tsconfig/node10': 1.0.8
'@tsconfig/node12': 1.0.9
'@tsconfig/node14': 1.0.1
'@tsconfig/node16': 1.0.2
acorn: 8.6.0
acorn-walk: 8.2.0
arg: 4.1.3
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
typescript: 4.5.4
v8-compile-cache-lib: 3.0.0
yn: 3.1.1
dev: false
/tsconfig-paths/3.12.0:
resolution: {integrity: sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==}
dependencies:
@ -11416,6 +11452,83 @@ packages:
- supports-color
dev: false
file:projects/calendar-assets.tgz_typescript@4.5.4:
resolution: {integrity: sha512-muyoJ0EuKPUpsAEL1bLgdR90OqIoohgdfUFDwyWP1qmtAe9k1my76bJSIiU1JSfybyssHYiR8jpM/SuIonWg3Q==, tarball: file:projects/calendar-assets.tgz}
id: file:projects/calendar-assets.tgz
name: '@rush-temp/calendar-assets'
version: 0.0.0
dependencies:
'@rushstack/heft': 0.41.8
'@types/heft-jest': 1.0.2
'@types/node': 16.11.14
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
transitivePeerDependencies:
- supports-color
- typescript
dev: false
file:projects/calendar-resources.tgz_096c09b0b673a57c275d9767a12070b1:
resolution: {integrity: sha512-UZIMmHCGB+XoLDkyP1A/+ot4oc0POAPYCVOtiPI3vQtVWuTIPquMM4pPX3HxkvfpWqblXburuJx3j18rfA5Mgw==, tarball: file:projects/calendar-resources.tgz}
id: file:projects/calendar-resources.tgz
name: '@rush-temp/calendar-resources'
version: 0.0.0
dependencies:
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
eslint-plugin-svelte3: 3.2.1_eslint@7.32.0+svelte@3.44.3
prettier: 2.5.1
prettier-plugin-svelte: 2.5.1_prettier@2.5.1+svelte@3.44.3
sass: 1.45.0
svelte: 3.44.3
svelte-check: 2.3.0_4374c622c67ed7479ff0e44c29d09bce
svelte-loader: 3.1.2_svelte@3.44.3
svelte-preprocess: 4.10.3_14d64cad431e31f100de7363af24a44f
typescript: 4.5.4
transitivePeerDependencies:
- '@babel/core'
- coffeescript
- less
- node-sass
- postcss
- postcss-load-config
- pug
- stylus
- sugarss
- supports-color
dev: false
file:projects/calendar.tgz:
resolution: {integrity: sha512-mN4GfaHpyGzuLV59eFw3c3R6p2r4ewEumsIhzyifgeXaXSD9Bnm06LG5LvFgF5G5TmDquUFcIq88w3Zzd20cQA==, tarball: file:projects/calendar.tgz}
name: '@rush-temp/calendar'
version: 0.0.0
dependencies:
'@rushstack/heft': 0.41.8
'@types/heft-jest': 1.0.2
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
typescript: 4.5.4
transitivePeerDependencies:
- supports-color
dev: false
file:projects/chunter-assets.tgz_typescript@4.5.4:
resolution: {integrity: sha512-2EQgdQ62vXKYpX9iOtOaCRt1GZliFiJpPPBZbOMHjaeWLye+/zYXlffkBbjVUSfR894cBlrtZBVRapjJU2T3uA==, tarball: file:projects/chunter-assets.tgz}
id: file:projects/chunter-assets.tgz
@ -11713,9 +11826,8 @@ packages:
- supports-color
dev: false
file:projects/dev-server.tgz_@types+node@16.11.14:
file:projects/dev-server.tgz:
resolution: {integrity: sha512-pv0DpcojPAreq3xXTnbl3Rj2UwEy97zRPmXU2lJsM0pKc6dVpmicD+/Bq4laIWx5qhvzfLurbwjBV4/0mLeuYw==, tarball: file:projects/dev-server.tgz}
id: file:projects/dev-server.tgz
name: '@rush-temp/dev-server'
version: 0.0.0
dependencies:
@ -11730,7 +11842,7 @@ packages:
eslint-plugin-promise: 5.2.0_eslint@7.32.0
jwt-simple: 0.5.6
prettier: 2.5.1
ts-node: 10.5.0_5d12c2add188ff0e728b4ade3dacd39b
ts-node: 10.5.0_typescript@4.5.4
typescript: 4.5.4
transitivePeerDependencies:
- '@swc/core'
@ -11815,9 +11927,8 @@ packages:
- typescript
dev: false
file:projects/elastic.tgz_@types+node@16.11.14:
file:projects/elastic.tgz:
resolution: {integrity: sha512-CF8tie/n08Slnvw40pFZnaS4j/2JPQzs2xAxakNqpokb5x3ci9e0z2gzXNB6otQElk1NxW69QDHqNme+jHqWPA==, tarball: file:projects/elastic.tgz}
id: file:projects/elastic.tgz
name: '@rush-temp/elastic'
version: 0.0.0
dependencies:
@ -11832,7 +11943,7 @@ packages:
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
ts-node: 10.5.0_5d12c2add188ff0e728b4ade3dacd39b
ts-node: 10.5.0_typescript@4.5.4
typescript: 4.5.4
transitivePeerDependencies:
- '@swc/core'
@ -12305,7 +12416,7 @@ packages:
dev: false
file:projects/model-all.tgz_typescript@4.5.4:
resolution: {integrity: sha512-Jll+Wp4p6/OjdvtbTqAGKbMUkOoAai5Se2+CSIOteRB6dDTgtlwy95fzQv2o5RHIBBiQXLQ2Csb8KgAluzTJ6w==, tarball: file:projects/model-all.tgz}
resolution: {integrity: sha512-LprNHSPgySvlj/zl9bkeSZ7Uh1wWyPPkQBW6knjBBD3cizpFpxPGBrSQnhDe/RP0uj6azKRYWWUcAPFOYe4TvQ==, tarball: file:projects/model-all.tgz}
id: file:projects/model-all.tgz
name: '@rush-temp/model-all'
version: 0.0.0
@ -12350,6 +12461,27 @@ packages:
- typescript
dev: false
file:projects/model-calendar.tgz_typescript@4.5.4:
resolution: {integrity: sha512-sI97CjbxdgK1qWGDrBViWm65NY+vwFzt1s94cGheRJP8CL/GqJNuaSyrJv0pqjfZgK6Z3IkcUq2ZUSSHwD+1gQ==, tarball: file:projects/model-calendar.tgz}
id: file:projects/model-calendar.tgz
name: '@rush-temp/model-calendar'
version: 0.0.0
dependencies:
'@rushstack/heft': 0.41.8
'@types/heft-jest': 1.0.2
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
eslint: 7.32.0
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
eslint-plugin-import: 2.25.3_eslint@7.32.0
eslint-plugin-node: 11.1.0_eslint@7.32.0
eslint-plugin-promise: 5.2.0_eslint@7.32.0
prettier: 2.5.1
transitivePeerDependencies:
- supports-color
- typescript
dev: false
file:projects/model-chunter.tgz_typescript@4.5.4:
resolution: {integrity: sha512-bbKuovYnIkpRkU0YhE2x6UEx2gvwKM/OkCj7SH4rQhVR3vjdWisBd0/P71NsNdfcdR7Hl4fhHSNVZfW6KNNPog==, tarball: file:projects/model-chunter.tgz}
id: file:projects/model-chunter.tgz
@ -12540,7 +12672,7 @@ packages:
dev: false
file:projects/model-recruit.tgz_typescript@4.5.4:
resolution: {integrity: sha512-t2mSCyFnB+YfsxFuAu0J8hNVhM+GP5SjiVevMe8tft+dCyyLeMpAJxTdEKkvRx6jV6yyxyPUmqZMAQCmm/pvuA==, tarball: file:projects/model-recruit.tgz}
resolution: {integrity: sha512-TtzOJVyFh5KY3RmQUTUUqeemhDDo/14R1RRrbQ7FoYun9yl+lv5b00OUuIbZ4rtYSJQLhiJaXFbZbxHl6pr3mA==, tarball: file:projects/model-recruit.tgz}
id: file:projects/model-recruit.tgz
name: '@rush-temp/model-recruit'
version: 0.0.0
@ -13235,7 +13367,7 @@ packages:
dev: false
file:projects/prod.tgz_a07ec81d4d975778878ca12202ea119e:
resolution: {integrity: sha512-R0Y2btm9DPFvRRGYAGC6ilCIcE5t+p2trcdARVBxyi+tH4XwcXZSt0NJJe+57vpiwkCV8hYPa2fI+Eul1wdrpQ==, tarball: file:projects/prod.tgz}
resolution: {integrity: sha512-mxkGGtPp108JHMkmnEgKKPNVrihu3xVv1wZqY/HTWhZ+v8Ct5RG92+Yg6NBhEsLmqCBBPTAHY/JapGi1oF9bWg==, tarball: file:projects/prod.tgz}
id: file:projects/prod.tgz
name: '@rush-temp/prod'
version: 0.0.0
@ -13329,7 +13461,7 @@ packages:
dev: false
file:projects/recruit-resources.tgz_096c09b0b673a57c275d9767a12070b1:
resolution: {integrity: sha512-EexKsB2ZRQ/VxlTABy5b5g3MLR51+549IMWW4g6+Xb/ZR6MZKCT6ocWPRgULW64EO3CTOJ37nIlXijj6Z/fPKw==, tarball: file:projects/recruit-resources.tgz}
resolution: {integrity: sha512-nvxkMBBQ9fPzCtIIQbUOlLaV+4wulVAKLg2iBOR5RuEiKZK/kwItpbzv0u6mS5Vb7/yFRp0GsRM+G7rv1tiGfg==, tarball: file:projects/recruit-resources.tgz}
id: file:projects/recruit-resources.tgz
name: '@rush-temp/recruit-resources'
version: 0.0.0
@ -13366,7 +13498,7 @@ packages:
dev: false
file:projects/recruit.tgz:
resolution: {integrity: sha512-wAgHbMEy+KVBNhYTiPdcBnN0O7BAsfxLMxK/gcjM1pkqeLbCzJ/SpRNMFpC2K0/TU+qsPqCzK3zx0VSvFXH05A==, tarball: file:projects/recruit.tgz}
resolution: {integrity: sha512-VAcfan3RLB0bq8DYryIS1waf0EiSSjbd1mdyq0IqMvlp9b8OBUGf0mOCfHDhkno9C4nf9fN8kCUDk9y82LfjZg==, tarball: file:projects/recruit.tgz}
name: '@rush-temp/recruit'
version: 0.0.0
dependencies:

View File

@ -82,7 +82,7 @@ services:
- mongodb
- elastic
- minio
- apm-server
# - apm-server
ports:
- 3333:3333
environment:
@ -94,41 +94,41 @@ services:
- MINIO_ENDPOINT=minio
- MINIO_ACCESS_KEY=minioadmin
- MINIO_SECRET_KEY=minioadmin
- APM_SERVER_URL=http://apm-server:8200
apm-server:
image: docker.elastic.co/apm/apm-server:7.14.2
depends_on:
- "elastic"
- "kibana"
cap_add: ["CHOWN", "DAC_OVERRIDE", "SETGID", "SETUID"]
cap_drop: ["ALL"]
ports:
- 8200:8200
command: |
apm-server -e
-E apm-server.rum.enabled=true
-E setup.kibana.host=kibana:5601
-E setup.template.settings.index.number_of_replicas=0
-E apm-server.kibana.enabled=true
-E apm-server.kibana.host=kibana:5601
-E output.elasticsearch.hosts=["elastic:9200"]
healthcheck:
interval: 10s
retries: 12
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8200/
kibana:
image: docker.elastic.co/kibana/kibana:7.14.2
depends_on:
- "elastic"
environment:
ELASTICSEARCH_URL: http://elastic:9200
ELASTICSEARCH_HOSTS: http://elastic:9200
ports:
- 5601:5601
healthcheck:
interval: 10s
retries: 20
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:5601/api/status
# - APM_SERVER_URL=http://apm-server:8200
# apm-server:
# image: docker.elastic.co/apm/apm-server:7.14.2
# depends_on:
# - "elastic"
# - "kibana"
# cap_add: ["CHOWN", "DAC_OVERRIDE", "SETGID", "SETUID"]
# cap_drop: ["ALL"]
# ports:
# - 8200:8200
# command: |
# apm-server -e
# -E apm-server.rum.enabled=true
# -E setup.kibana.host=kibana:5601
# -E setup.template.settings.index.number_of_replicas=0
# -E apm-server.kibana.enabled=true
# -E apm-server.kibana.host=kibana:5601
# -E output.elasticsearch.hosts=["elastic:9200"]
# healthcheck:
# interval: 10s
# retries: 12
# test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8200/
# kibana:
# image: docker.elastic.co/kibana/kibana:7.14.2
# depends_on:
# - "elastic"
# environment:
# ELASTICSEARCH_URL: http://elastic:9200
# ELASTICSEARCH_HOSTS: http://elastic:9200
# ports:
# - 5601:5601
# healthcheck:
# interval: 10s
# retries: 20
# test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:5601/api/status
volumes:
db:

View File

@ -119,6 +119,9 @@
"@anticrm/server-recruit": "~0.6.0",
"@anticrm/server-recruit-resources": "~0.6.0",
"@anticrm/server-task": "~0.6.0",
"@anticrm/server-task-resources": "~0.6.0"
"@anticrm/server-task-resources": "~0.6.0",
"@anticrm/calendar": "~0.6.0",
"@anticrm/calendar-assets": "~0.6.0",
"@anticrm/calendar-resources": "~0.6.0"
}
}

View File

@ -35,6 +35,7 @@ import { inventoryId } from '@anticrm/inventory'
import { templatesId } from '@anticrm/templates'
import { notificationId } from '@anticrm/notification'
import { tagsId } from '@anticrm/tags'
import { calendarId } from '@anticrm/calendar'
import rekoni from '@anticrm/rekoni'
import '@anticrm/login-assets'
@ -54,6 +55,7 @@ import '@anticrm/inventory-assets'
import '@anticrm/templates-assets'
import '@anticrm/notification-assets'
import '@anticrm/tags-assets'
import '@anticrm/calendar-assets'
import { setMetadata } from '@anticrm/platform'
export async function configurePlatform() {
@ -95,4 +97,5 @@ export async function configurePlatform() {
addLocation(templatesId, () => import(/* webpackChunkName: "templates" */ '@anticrm/templates-resources'))
addLocation(notificationId, () => import(/* webpackChunkName: "notification" */ '@anticrm/notification-resources'))
addLocation(tagsId, () => import(/* webpackChunkName: "tags" */ '@anticrm/tags-resources'))
addLocation(calendarId, () => import(/* webpackChunkName: "calendar" */ '@anticrm/calendar-resources'))
}

View File

@ -61,6 +61,7 @@
"@anticrm/model-notification": "~0.6.0",
"@anticrm/model-text-editor": "~0.6.0",
"@anticrm/core": "~0.6.16",
"@anticrm/model-tags": "~0.6.0"
"@anticrm/model-tags": "~0.6.0",
"@anticrm/model-calendar": "~0.6.0"
}
}

View File

@ -47,6 +47,7 @@ import { createModel as viewModel } from '@anticrm/model-view'
import { createModel as workbenchModel } from '@anticrm/model-workbench'
import { createModel as notificationModel } from '@anticrm/model-notification'
import { createModel as tagsModel } from '@anticrm/model-tags'
import { createModel as calendarModel } from '@anticrm/model-calendar'
export const version: Data<Version> = jsonVersion as Data<Version>
@ -77,6 +78,7 @@ const builders = [
serverNotificationModel,
serveSettingModel,
tagsModel,
calendarModel,
serverChunterModel,
serverInventoryModel,
serverLeadModel,

View 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'
}
}

View File

@ -0,0 +1,4 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/

View 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"
}

View File

@ -0,0 +1,46 @@
{
"name": "@anticrm/model-calendar",
"version": "0.6.0",
"main": "lib/index.js",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "heft build",
"build:watch": "tsc",
"lint:fix": "eslint --fix src",
"lint": "eslint src",
"format": "prettier --write src && eslint --fix src"
},
"devDependencies": {
"@anticrm/model-rig": "~0.6.0",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-promise": "^5.1.1",
"eslint-plugin-node": "^11.1.0",
"eslint": "^7.32.0",
"@types/heft-jest": "^1.0.2",
"@typescript-eslint/parser": "^5.4.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"prettier": "^2.4.1",
"@rushstack/heft": "^0.41.1"
},
"dependencies": {
"@anticrm/core": "~0.6.11",
"@anticrm/model": "~0.6.0",
"@anticrm/ui": "~0.6.0",
"@anticrm/view": "~0.6.0",
"@anticrm/model-attachment": "~0.6.0",
"@anticrm/model-task": "~0.6.0",
"@anticrm/calendar": "~0.6.0",
"@anticrm/calendar-resources": "~0.6.0",
"@anticrm/platform": "~0.6.5",
"@anticrm/model-core": "~0.6.0",
"@anticrm/model-view": "~0.6.0",
"@anticrm/model-workbench": "~0.6.1",
"@anticrm/activity": "~0.6.0",
"@anticrm/workbench": "~0.6.1",
"@anticrm/model-chunter": "~0.6.0",
"@anticrm/model-contact": "~0.6.1",
"@anticrm/contact": "~0.6.5"
}
}

View File

@ -0,0 +1,90 @@
//
// 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 { Calendar, Event } from '@anticrm/calendar'
import { Employee } from '@anticrm/contact'
import type { Domain, Markup, Ref, Timestamp } from '@anticrm/core'
import { IndexKind } from '@anticrm/core'
import { Builder, Collection, Index, Model, Prop, TypeDate, TypeMarkup, TypeString, UX } from '@anticrm/model'
import attachment from '@anticrm/model-attachment'
import chunter from '@anticrm/model-chunter'
import contact from '@anticrm/model-contact'
import core, { TAttachedDoc } from '@anticrm/model-core'
import { TSpaceWithStates } from '@anticrm/model-task'
import workbench from '@anticrm/model-workbench'
import calendar from './plugin'
export * from '@anticrm/calendar'
export const DOMAIN_CALENDAR = 'calendar' as Domain
@Model(calendar.class.Calendar, core.class.Space)
@UX(calendar.string.Calendar, calendar.icon.Calendar)
export class TCalendar extends TSpaceWithStates implements Calendar {}
@Model(calendar.class.Event, core.class.AttachedDoc, DOMAIN_CALENDAR)
export class TEvent extends TAttachedDoc implements Event {
@Prop(TypeString(), calendar.string.Title)
@Index(IndexKind.FullText)
title!: string
@Prop(TypeString(), calendar.string.EventNumber)
number!: number
@Prop(TypeMarkup(), calendar.string.Description)
@Index(IndexKind.FullText)
description!: Markup
@Prop(TypeString(), calendar.string.Location, calendar.icon.Location)
@Index(IndexKind.FullText)
location?: string
@Prop(TypeDate(true), calendar.string.Date)
date!: Timestamp
@Prop(TypeDate(true), calendar.string.DueTo)
dueDate!: Timestamp
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments?: number
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
comments?: number
@Prop(Collection(contact.class.Employee), calendar.string.Participants)
participants!: Ref<Employee>[]
}
export function createModel (builder: Builder): void {
builder.createModel(TCalendar, TEvent)
builder.createDoc(workbench.class.Application, core.space.Model, {
label: calendar.string.ApplicationLabelCalendar,
icon: calendar.icon.Calendar,
hidden: true,
navigatorModel: {
spaces: [
{
label: calendar.string.Calendars,
spaceClass: calendar.class.Calendar,
addSpaceLabel: calendar.string.CreateCalendar,
createComponent: calendar.component.CreateCalendar
}
]
}
}, calendar.app.Calendar)
}
export default calendar

View File

@ -0,0 +1,31 @@
//
// 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 { calendarId } from '@anticrm/calendar'
import calendar from '@anticrm/calendar-resources/src/plugin'
import type { IntlString } from '@anticrm/platform'
import { mergeIds } from '@anticrm/platform'
import { AnyComponent } from '@anticrm/ui'
export default mergeIds(calendarId, calendar, {
component: {
CreateCalendar: '' as AnyComponent
},
string: {
ApplicationLabelCalendar: '' as IntlString
},
space: {
}
})

View File

@ -0,0 +1,8 @@
{
"extends": "./node_modules/@anticrm/model-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
}
}

View File

@ -25,6 +25,7 @@ export default mergeIds(coreId, core, {
Name: '' as IntlString,
Description: '' as IntlString,
Private: '' as IntlString,
Archived: '' as IntlString
Archived: '' as IntlString,
ClassLabel: '' as IntlString
}
})

View File

@ -24,7 +24,7 @@ import {
Timestamp,
Type, Version
} from '@anticrm/core'
import { Index, Model, Prop, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
import { Index, Model, Prop, TypeIntlString, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
import type { IntlString } from '@anticrm/platform'
import core from './component'
@ -70,7 +70,10 @@ export class TAttachedDoc extends TDoc implements AttachedDoc {
@Model(core.class.Class, core.class.Doc, DOMAIN_MODEL)
export class TClass extends TDoc implements Class<Obj> {
kind!: ClassifierKind
@Prop(TypeIntlString(), core.string.ClassLabel)
label!: IntlString
extends!: Ref<Class<Obj>>
domain!: Domain
}
@ -101,6 +104,9 @@ export class TType extends TObj implements Type<any> {
@Model(core.class.TypeString, core.class.Type)
export class TTypeString extends TType {}
@Model(core.class.TypeIntlString, core.class.Type)
export class TTypeIntlString extends TType {}
@Model(core.class.TypeNumber, core.class.Type)
export class TTypeNumber extends TType {}

View File

@ -28,7 +28,7 @@ import {
TRefTo,
TType,
TTypeBoolean,
TTypeDate, TTypeMarkup, TTypeNumber, TTypeString, TTypeTimestamp,
TTypeDate, TTypeIntlString, TTypeMarkup, TTypeNumber, TTypeString, TTypeTimestamp,
TVersion
} from './core'
import { TAccount, TSpace } from './security'
@ -80,6 +80,7 @@ export function createModel (builder: Builder): void {
TTypeDate,
TArrOf,
TVersion,
TTypeNumber
TTypeNumber,
TTypeIntlString
)
}

View File

@ -44,6 +44,7 @@
"@anticrm/model-task": "~0.6.0",
"@anticrm/workbench": "~0.6.1",
"@anticrm/model-presentation": "~0.6.0",
"@anticrm/model-calendar": "~0.6.0",
"@anticrm/model-tags": "~0.6.0",
"@anticrm/skillset": "^0.6.0"
}

View File

@ -303,6 +303,10 @@ export function createModel (builder: Builder): void {
presenter: recruit.component.VacancyPresenter
})
builder.mixin(recruit.class.ReviewCategory, core.class.Class, view.mixin.AttributePresenter, {
presenter: recruit.component.ReviewCategoryPresenter
})
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ObjectValidator, {
validator: recruit.validator.ApplicantValidator
})
@ -366,6 +370,14 @@ export function createModel (builder: Builder): void {
}
})
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: recruit.class.ReviewCategory,
action: task.action.UnarchiveSpace,
query: {
archived: true
}
})
builder.createDoc(
view.class.Action,
core.space.Model,

View File

@ -17,6 +17,7 @@ import { Person } from '@anticrm/contact'
import core, { AttachedDoc, Class, Doc, DocumentQuery, DOMAIN_TX, MixinData, Ref, TxCollectionCUD, TxCreateDoc, TxMixin, TxOperations, TxUpdateDoc } from '@anticrm/core'
import { createOrUpdate, MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
import { DOMAIN_ATTACHMENT } from '@anticrm/model-attachment'
import { DOMAIN_CALENDAR } from '@anticrm/model-calendar'
import { DOMAIN_COMMENT } from '@anticrm/model-chunter'
import contact, { DOMAIN_CONTACT } from '@anticrm/model-contact'
import tags, { DOMAIN_TAGS, TagCategory, TagElement } from '@anticrm/model-tags'
@ -157,6 +158,25 @@ export const recruitOperation: MigrateOperation = {
})
}
}
// Migrate reviews
await client.update(DOMAIN_TASK, {
_class: recruit.class.Review
}, {
$rename: {
startDate: 'date'
}
})
await client.update(DOMAIN_TASK, {
_class: recruit.class.Review,
title: { $exists: false }
}, {
title: ''
})
await client.move(DOMAIN_TASK, { _class: recruit.class.Review }, DOMAIN_CALENDAR)
},
async upgrade (client: MigrationUpgradeClient): Promise<void> {
const tx = new TxOperations(client, core.account.System)

View File

@ -61,6 +61,7 @@ export default mergeIds(recruitId, recruit, {
ApplicationPresenter: '' as AnyComponent,
ApplicationsPresenter: '' as AnyComponent,
VacancyPresenter: '' as AnyComponent,
ReviewCategoryPresenter: '' as AnyComponent,
EditApplication: '' as AnyComponent,
TemplatesIcon: '' as AnyComponent,
Applications: '' as AnyComponent,

View File

@ -1,67 +1,38 @@
import { Employee, Organization } from '@anticrm/contact'
import { Domain, IndexKind, Ref, Timestamp } from '@anticrm/core'
import { Collection, Index, Model, Prop, TypeDate, TypeMarkup, TypeRef, TypeString, UX } from '@anticrm/model'
import { Organization } from '@anticrm/contact'
import { Domain, IndexKind, Ref } from '@anticrm/core'
import { Collection, Index, Model, Prop, TypeMarkup, TypeRef, TypeString, UX } from '@anticrm/model'
import attachment from '@anticrm/model-attachment'
import calendar, { TEvent } from '@anticrm/model-calendar'
import chunter from '@anticrm/model-chunter'
import contact from '@anticrm/model-contact'
import core, { TAttachedDoc } from '@anticrm/model-core'
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
import core, { TAttachedDoc, TSpace } from '@anticrm/model-core'
import task from '@anticrm/model-task'
import { Candidate, Opinion, Review, ReviewCategory } from '@anticrm/recruit'
import recruit from './plugin'
@Model(recruit.class.ReviewCategory, task.class.SpaceWithStates)
@Model(recruit.class.ReviewCategory, core.class.Space)
@UX(recruit.string.ReviewCategory, recruit.icon.Review)
export class TReviewCategory extends TSpaceWithStates implements ReviewCategory {
export class TReviewCategory extends TSpace implements ReviewCategory {
@Prop(TypeString(), recruit.string.FullDescription)
fullDescription?: string
}
@Model(recruit.class.Review, calendar.class.Event)
@UX(recruit.string.Review, recruit.icon.Review, recruit.string.ReviewShortLabel, 'number')
export class TReview extends TEvent implements Review {
// We need to declare, to provide property with label
@Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Candidate)
declare attachedTo: Ref<Candidate>
@Prop(TypeString(), recruit.string.Verdict)
@Index(IndexKind.FullText)
verdict!: string
@Prop(TypeRef(contact.class.Organization), recruit.string.Company, contact.icon.Company)
company?: Ref<Organization>
}
@Model(recruit.class.Review, task.class.Task)
@UX(recruit.string.Review, recruit.icon.Review, recruit.string.ReviewShortLabel, 'number')
export class TReview extends TTask implements Review {
// We need to declare, to provide property with label
@Prop(TypeRef(recruit.class.Applicant), recruit.string.Candidate)
declare attachedTo: Ref<Candidate>
@Prop(TypeRef(contact.class.Employee), recruit.string.AssignedRecruiter)
declare assignee: Ref<Employee> | null
@Prop(TypeMarkup(), recruit.string.Description)
@Index(IndexKind.FullText)
description!: string
@Index(IndexKind.FullText)
@Prop(TypeMarkup(), recruit.string.Verdict)
verdict!: string
@Index(IndexKind.FullText)
@Prop(TypeString(), recruit.string.Location, recruit.icon.Location)
location?: string
@Index(IndexKind.FullText)
@Prop(TypeString(), recruit.string.Company, contact.icon.Company)
company?: string
@Prop(TypeDate(), recruit.string.StartDate)
startDate!: Timestamp | null
@Prop(TypeDate(), recruit.string.DueDate)
dueDate!: Timestamp | null
@Prop(Collection(recruit.class.Opinion), recruit.string.Opinions)
opinions?: number
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments?: number
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
comments?: number
@Prop(Collection(contact.class.Employee), recruit.string.Participants)
participants!: Ref<Employee>[]
}
@Model(recruit.class.Opinion, core.class.AttachedDoc, 'recruit' as Domain)

View File

@ -6,6 +6,7 @@ import task from '@anticrm/model-task'
import view from '@anticrm/model-view'
import workbench from '@anticrm/model-workbench'
import recruit from './plugin'
import calendar from '@anticrm/model-calendar'
export function createReviewModel (builder: Builder): void {
builder.mixin(recruit.class.ReviewCategory, core.class.Class, workbench.mixin.SpaceView, {
@ -21,11 +22,21 @@ export function createReviewModel (builder: Builder): void {
})
createTableViewlet(builder)
createKanbanViewlet(builder)
createStatusTableViewlet(builder)
builder.mixin(recruit.class.Review, core.class.Class, task.mixin.KanbanCard, {
card: recruit.component.KanbanReviewCard
builder.createDoc(
view.class.Action,
core.space.Model,
{
label: recruit.string.CreateOpinion,
icon: recruit.icon.Create,
action: recruit.actionImpl.CreateOpinion
},
recruit.action.CreateOpinion
)
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: recruit.class.Review,
action: recruit.action.CreateOpinion
})
builder.mixin(recruit.class.Review, core.class.Class, view.mixin.ObjectEditor, {
@ -63,17 +74,6 @@ export function createReviewModel (builder: Builder): void {
action: recruit.action.CreateReview
})
builder.createDoc(
task.class.KanbanTemplateSpace,
core.space.Model,
{
name: recruit.string.ReviewCategory,
description: task.string.ManageStatusesWithin,
icon: recruit.component.TemplatesIcon
},
recruit.space.ReviewTemplates
)
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: recruit.class.ReviewCategory,
action: task.action.ArchiveSpace,
@ -82,69 +82,6 @@ export function createReviewModel (builder: Builder): void {
}
})
}
function createStatusTableViewlet (builder: Builder): void {
builder.createDoc(view.class.Viewlet, core.space.Model, {
attachTo: recruit.class.Review,
descriptor: task.viewlet.StatusTable,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
options: {
lookup: {
attachedTo: recruit.mixin.Candidate,
state: task.class.State,
assignee: contact.class.Employee,
doneState: task.class.DoneState,
participants: contact.class.Employee
}
} as FindOptions<Doc>,
config: [
'',
'$lookup.attachedTo',
{ key: '$lookup.participants', presenter: recruit.component.PersonsPresenter, label: recruit.string.Participants, sortingKey: '$lookup.participants' },
// 'location',
'company',
'dueDate',
{ key: '', presenter: recruit.component.OpinionsPresenter, label: recruit.string.Opinions, sortingKey: 'opinions' },
'$lookup.state',
'$lookup.doneState',
// { presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
// { presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
'modifiedOn'
]
})
builder.createDoc(
view.class.Action,
core.space.Model,
{
label: recruit.string.CreateOpinion,
icon: recruit.icon.Create,
action: recruit.actionImpl.CreateOpinion
},
recruit.action.CreateOpinion
)
builder.createDoc(view.class.ActionTarget, core.space.Model, {
target: recruit.class.Review,
action: recruit.action.CreateOpinion
})
}
function createKanbanViewlet (builder: Builder): void {
builder.createDoc(view.class.Viewlet, core.space.Model, {
attachTo: recruit.class.Review,
descriptor: task.viewlet.Kanban,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
options: {
lookup: {
attachedTo: recruit.mixin.Candidate,
state: task.class.State,
assignee: contact.class.Employee,
participants: contact.class.Employee
}
} as FindOptions<Doc>,
config: ['$lookup.attachedTo', '$lookup.state', '$lookup.participants', '$lookup.assignee']
})
}
function createTableViewlet (builder: Builder): void {
builder.createDoc(view.class.Viewlet, core.space.Model, {
@ -154,22 +91,20 @@ function createTableViewlet (builder: Builder): void {
options: {
lookup: {
attachedTo: recruit.mixin.Candidate,
state: task.class.State,
assignee: contact.class.Employee,
doneState: task.class.DoneState,
participants: contact.class.Employee
participants: contact.class.Employee,
company: contact.class.Organization
}
} as FindOptions<Doc>,
config: [
'',
'title',
'$lookup.attachedTo',
{ key: '$lookup.participants', presenter: recruit.component.PersonsPresenter, label: recruit.string.Participants, sortingKey: '$lookup.participants' },
// 'location',
'company',
'dueDate',
'verdict',
{ key: '', presenter: recruit.component.OpinionsPresenter, label: recruit.string.Opinions, sortingKey: 'opinions' },
'$lookup.state',
'$lookup.doneState',
{ key: '$lookup.participants', presenter: calendar.component.PersonsPresenter, label: calendar.string.Participants, sortingKey: '$lookup.participants' },
'$lookup.company',
'date',
'dueDate',
// { presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
// { presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
'modifiedOn'

View File

@ -142,6 +142,10 @@ export function createModel (builder: Builder): void {
presenter: view.component.StringPresenter
})
builder.mixin(core.class.TypeIntlString, core.class.Class, view.mixin.AttributePresenter, {
presenter: view.component.IntlStringPresenter
})
builder.mixin(core.class.TypeNumber, core.class.Class, view.mixin.AttributeEditor, {
editor: view.component.NumberEditor
})

View File

@ -31,6 +31,7 @@ export default mergeIds(viewId, view, {
component: {
StringEditor: '' as AnyComponent,
StringPresenter: '' as AnyComponent,
IntlStringPresenter: '' as AnyComponent,
NumberEditor: '' as AnyComponent,
NumberPresenter: '' as AnyComponent,
HTMLPresenter: '' as AnyComponent,

View File

@ -10,6 +10,7 @@
"Name": "Name",
"Description": "Description",
"Private": "Private",
"Archived": "Archived"
"Archived": "Archived",
"ClassLabel": "Label"
}
}

View File

@ -10,6 +10,7 @@
"Name": "Название",
"Description": "Описание",
"Private": "Личный",
"Archived": "Архивный"
"Archived": "Архивный",
"ClassLabel": "Тип"
}
}

View File

@ -31,6 +31,11 @@ export type PrimitiveType = number | string | boolean | undefined | Ref<Doc>
*/
export type Timestamp = number
/**
* @public
*/
export type Markup = string
/**
* @public
*/
@ -160,6 +165,15 @@ export type AttachedData<T extends AttachedDoc> = Omit<T, keyof AttachedDoc>
// T Y P E S
/**
* @public
*/
export interface TypeDate extends Type<Date> {
// If not set to true, will be false
withTime?: boolean
}
/**
* @public
*/

View File

@ -44,6 +44,7 @@ export default plugin(coreId, {
Space: '' as Ref<Class<Space>>,
Account: '' as Ref<Class<Account>>,
TypeString: '' as Ref<Class<Type<string>>>,
TypeIntlString: '' as Ref<Class<Type<IntlString>>>,
TypeNumber: '' as Ref<Class<Type<string>>>,
TypeMarkup: '' as Ref<Class<Type<string>>>,
TypeBoolean: '' as Ref<Class<Type<boolean>>>,

View File

@ -14,7 +14,7 @@
//
import core, {
Account, ArrOf as TypeArrOf, AttachedDoc, Attribute, Class, Classifier, ClassifierKind, Collection as TypeCollection, Data, Doc, Domain, generateId, IndexKind, Interface, Mixin as IMixin, MixinUpdate, Obj, PropertyType, Ref, RefTo, Space, Tx, TxCreateDoc, TxFactory, TxProcessor, Type
Account, ArrOf as TypeArrOf, AttachedDoc, Attribute, Class, Classifier, ClassifierKind, Collection as TypeCollection, Data, Doc, Domain, generateId, IndexKind, Interface, Markup, Mixin as IMixin, MixinUpdate, Obj, PropertyType, Ref, RefTo, Space, Timestamp, Tx, TxCreateDoc, TxFactory, TxProcessor, Type, TypeDate as TypeDateType
} from '@anticrm/core'
import type { Asset, IntlString } from '@anticrm/platform'
import toposort from 'toposort'
@ -331,36 +331,43 @@ export function TypeString (): Type<string> {
/**
* @public
*/
export function TypeNumber (): Type<string> {
export function TypeNumber (): Type<number> {
return { _class: core.class.TypeNumber, label: 'TypeNumber' as IntlString }
}
/**
* @public
*/
export function TypeMarkup (): Type<string> {
export function TypeMarkup (): Type<Markup> {
return { _class: core.class.TypeMarkup, label: 'TypeMarkup' as IntlString }
}
/**
* @public
*/
export function TypeBoolean (): Type<string> {
export function TypeIntlString (): Type<IntlString> {
return { _class: core.class.TypeIntlString, label: 'TypeIntlString' as IntlString }
}
/**
* @public
*/
export function TypeBoolean (): Type<boolean> {
return { _class: core.class.TypeBoolean, label: 'TypeBoolean' as IntlString }
}
/**
* @public
*/
export function TypeTimestamp (): Type<string> {
export function TypeTimestamp (): Type<Timestamp> {
return { _class: core.class.TypeTimestamp, label: 'TypeTimestamp' as IntlString }
}
/**
* @public
*/
export function TypeDate (): Type<string> {
return { _class: core.class.TypeDate, label: 'TypeDate' as IntlString }
export function TypeDate (withTime?: boolean): TypeDateType {
return { _class: core.class.TypeDate, label: 'TypeDate' as IntlString, withTime }
}
/**

View File

@ -76,6 +76,7 @@
placeholder={attribute?.label}
{maxWidth}
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
attributeType={attribute.type}
space={object.space}
{onChange}
{focus}
@ -94,6 +95,7 @@
placeholder={attribute?.label}
{maxWidth}
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
attributeType={attribute.type}
space={object.space}
{onChange}
{focus}
@ -105,6 +107,7 @@
this={instance}
{maxWidth}
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
attributeType={attribute.type}
space={object.space}
{onChange}
{focus}

View File

@ -33,6 +33,7 @@
export let labelProps: any | undefined = undefined
export let okAction: () => void
export let canSave: boolean = false
export let size: 'small'| 'medium' = 'small'
export let okLabel: IntlString = presentation.string.Create
export let cancelLabel: IntlString = presentation.string.Cancel
@ -40,7 +41,7 @@
const dispatch = createEventDispatcher()
</script>
<form class="antiCard" on:submit|preventDefault={ () => {} }>
<form class="antiCard" class:w-2125rem={size === 'small'} class:w-4125rem={size === 'medium'} on:submit|preventDefault={ () => {} }>
<div class="antiCard-header">
<div class="antiCard-header__title"><Label {label} params={labelProps ?? {}} /></div>
{#if $$slots.error}

View File

@ -35,6 +35,7 @@
export let show: boolean = false
export let allowDeselect = false
export let titleDeselect: IntlString | undefined = undefined
export let readonly = false
const dispatch = createEventDispatcher()
@ -69,7 +70,7 @@
<div class="antiSelect" bind:this={container}
on:click|preventDefault={() => {
btn.focus()
if (!opened) {
if (!opened && !readonly) {
opened = true
showPopup(UsersPopup, { _class, title, caption, allowDeselect, selected: value, titleDeselect }, container, (result) => {
if (result === null) {

View File

@ -78,7 +78,7 @@
</div>
{/if}
{#each persons as person}
<div class="antiComponentBox flex-center">
<div class="antiComponentBox flex-center margin_025 antiComponentBoxFocused">
<UserInfo value={person} size={'medium'} />
<div class="ml-1">
<ActionIcon icon={IconClose} size={'small'} action={() => removePerson(person)} />
@ -104,4 +104,7 @@
display: flex;
flex-wrap: wrap;
}
.margin_025 {
margin: 0.25rem;
}
</style>

View File

@ -1,13 +1,19 @@
<script lang="ts">
import { IntlString } from '@anticrm/platform'
import presentation, { MessageViewer } from '@anticrm/presentation'
import { ActionIcon, IconCheck, IconClose, IconEdit } from '@anticrm/ui'
import { ActionIcon, IconCheck, IconClose, IconEdit, Label } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import textEditorPlugin from '../plugin'
import StyledTextEditor from './StyledTextEditor.svelte'
export let label: IntlString | undefined = undefined
export let content: string
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
export let emphasized = false
export let alwaysEdit = false
export let showButtons = true
let rawValue: string
const Mode = {
@ -22,18 +28,41 @@
textEditor.submit()
}
const dispatch = createEventDispatcher()
let focused = false
let needFocus = false
$: if (textEditor && needFocus) {
textEditor.focus()
needFocus = false
}
</script>
<div class="antiComponent styled-box">
{#if mode !== Mode.View}
<div class="antiComponent styled-box" class:emphasized class:emphasized-focus={(mode === Mode.Edit || alwaysEdit) && focused} on:click={() => {
if (alwaysEdit && focused) {
textEditor?.focus()
}
}}>
{#if label}
<div class="label"><Label {label} /></div>
{/if}
{#if mode !== Mode.View || alwaysEdit}
<StyledTextEditor
{placeholder}
{showButtons}
bind:content={rawValue}
bind:this={textEditor}
on:focus={() => {
focused = true
}}
on:blur={() => {
focused = false
}}
on:value={(evt) => {
rawValue = evt.detail
}}
>
{#if !alwaysEdit}
<div class="flex flex-reverse flex-grow">
<div class="ml-2">
<!-- disabled={rawValue.trim().length === 0} -->
@ -59,6 +88,7 @@
}}
/>
</div>
{/if}
</StyledTextEditor>
{:else}
<div class="text">
@ -66,6 +96,7 @@
<MessageViewer message={content} />
{/if}
</div>
{#if !alwaysEdit}
<div class="flex flex-reverse">
<ActionIcon
size={'medium'}
@ -74,20 +105,49 @@
label={textEditorPlugin.string.Edit}
action={() => {
rawValue = content ?? ''
needFocus = true
mode = Mode.Edit
}}
/>
</div>
{/if}
{/if}
</div>
<style lang="scss">
.styled-box {
flex-grow: 1;
.label {
padding-bottom: 0.25rem;
font-size: 0.75rem;
color: var(--theme-caption-color);
opacity: 0.3;
transition: top 200ms;
pointer-events: none;
user-select: none;
}
.emphasized .emphasized-focus + .label {
top: 0.5rem;
}
}
.emphasized {
padding: 1rem;
background-color: var(--theme-bg-accent-color);
border: 1px solid var(--theme-bg-accent-hover);
border-radius: 0.75rem;
&.emphasized-focus {
background-color: var(--theme-bg-focused-color);
border-color: var(--theme-bg-focused-border);
}
}
.text {
overflow: auto;
flex-grow: 1;
line-height: 150%;
.nolabel {
padding-top: 0;
}
}
</style>

View File

@ -27,12 +27,16 @@
export let content: string = ''
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
export let showButtons = true
let textEditor: TextEditor
export function submit (): void {
textEditor.submit()
}
export function focus (): void {
textEditor.focus()
}
</script>
<div class="ref-container">
@ -50,12 +54,13 @@
textEditor.clear()
}}
on:blur
on:focus
supportSubmit={false}
/>
</ScrollBox>
</div>
</div>
<div class="buttons">
<div class="buttons" class:shown={showButtons}>
<div class="tool"><TextStyle size={'large'} /></div>
<div class="tool"><Emoji size={'large'} /></div>
<div class="tool"><GIF size={'large'} /></div>
@ -72,6 +77,14 @@
flex-direction: column;
min-height: 4.5rem;
.buttons {
visibility: hidden;
}
.shown {
visibility: visible;
}
.textInput {
flex-grow: 1;
display: flex;

View File

@ -53,6 +53,15 @@
export function insertText (text: string): void {
editor.commands.insertContent(text as HTMLContent)
}
let needFocus = false
export function focus (): void {
needFocus = true
}
$: if (editor && needFocus) {
editor.commands.focus()
needFocus = false
}
const Handle = Extension.create({
addKeyboardShortcuts () {
@ -98,6 +107,9 @@
onBlur: () => {
dispatch('blur', editor.getHTML())
},
onFocus: () => {
dispatch('focus', editor.getHTML())
},
onUpdate: () => {
content = editor.getHTML()
dispatch('value', content)

View File

@ -417,12 +417,14 @@
// Basic component view.
.antiComponentBox {
margin: 0.25rem;
padding: 0.5rem;
background-color: var(--theme-button-bg-focused);
background-color: var(--theme-bg-accent-color);
border: 1px solid var(--theme-button-border-enabled);
border-radius: .75rem;
box-shadow: 0px 3px 3px rgba(0, 0, 0, .2);
&.antiComponentBoxFocused {
background-color: var(--theme-button-bg-focused);
}
}
/* Select */

View File

@ -70,13 +70,11 @@
}
/* Cards */
.antiCard {
display: flex;
flex-direction: column;
width: 21.25rem;
min-width: 21.25rem;
max-width: 21.25rem;
background-color: var(--theme-card-bg);
border-radius: 1.25rem;
box-shadow: var(--theme-card-shadow);

View File

@ -28,10 +28,10 @@
const dispatch = createEventDispatcher()
const getNow = (): Date => {
let tempDate = new Date(Date.now())
const tempDate = new Date(Date.now())
return new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())
}
let today: Date = getNow()
const today: Date = getNow()
let todayString: string
async function todayStr () {
todayString = await translate(ui.string.Today, {})

View File

@ -22,7 +22,7 @@
export let withTime: boolean = false
const { currentLanguage } = getContext('lang')
let inter: boolean = (currentLanguage === 'ru') ?? false
const inter: boolean = (currentLanguage === 'ru') ?? false
const zeroLead = (n: number): string => {
if (n < 10) return '0' + n.toString()

View 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'
}
}

View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="calendar" viewBox="0 0 24 24">
<path d="M19.5,5h-2.1V4.5c0-0.3-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5V5H8.1V4.5C8.1,4.2,7.9,4,7.6,4S7.1,4.2,7.1,4.5V5H5 C4.2,5,3.5,5.7,3.5,6.5V19c0,0.8,0.7,1.5,1.5,1.5h14.5c0.8,0,1.5-0.7,1.5-1.5V6.5C21,5.7,20.3,5,19.5,5z M5,6h2.1v0.5 c0,0.3,0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5V6h8.3v0.5c0,0.3,0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5V6h2.1C19.7,6,20,6.3,20,6.5v3.1H4.5V6.5 C4.5,6.3,4.7,6,5,6z M19.5,19.5H5c-0.3,0-0.5-0.2-0.5-0.5v-8.3H20V19C20,19.2,19.7,19.5,19.5,19.5z" />
</symbol>
<symbol id="location" viewBox="0 0 16 16">
<path d="M8,4.6c-1.5,0-2.6,1.2-2.6,2.6S6.5,9.9,8,9.9s2.6-1.2,2.6-2.6S9.5,4.6,8,4.6z M8,8.9c-0.9,0-1.6-0.7-1.6-1.6 c0-0.9,0.7-1.6,1.6-1.6s1.6,0.7,1.6,1.6C9.6,8.2,8.9,8.9,8,8.9z"/>
<path d="M8,1.8c-3,0-5.5,2.5-5.5,5.5c0,1.9,0.9,3.4,2,4.5c1.1,1.1,2.3,1.8,2.9,2.1c0.4,0.2,0.9,0.2,1.3,0c0.6-0.3,1.8-1,2.9-2.1 c1.1-1.1,2-2.6,2-4.5C13.5,4.3,11,1.8,8,1.8z M10.8,11.1c-1,1-2.1,1.7-2.6,2c-0.1,0.1-0.2,0.1-0.3,0c-0.6-0.3-1.7-1-2.6-2 c-1-1-1.7-2.3-1.7-3.8c0-2.5,2-4.5,4.5-4.5s4.5,2,4.5,4.5C12.5,8.8,11.7,10.1,10.8,11.1z"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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/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"
}

View File

@ -0,0 +1,17 @@
{
"string": {
"ApplicationLabelCalendar": "Calendar",
"Calendars": "Calendars",
"Participants": "Participants",
"NoParticipants": "No participants added",
"PersonsLabel": "{name}",
"AddDescription": "Add description",
"Date": "Date",
"DueTo": "Due date",
"Description": "Description",
"Title": "Title",
"Location": "Location",
"Company": "Company",
"CreateCalendar": "Create Calendar"
}
}

View File

@ -0,0 +1,17 @@
{
"string": {
"ApplicationLabelCalendar": "Календарь",
"Calendars": "Календари",
"Participants": "Участники",
"NoParticipants": "Участники не добавлены",
"PersonsLabel": "{name}",
"AddDescription": "Добавить описание",
"Date": "Дата",
"DueTo": "Дата конца",
"Description": "Описание",
"Title": "Название",
"Location": "Местоположение",
"Company": "Компания",
"CreateCalendar": "Новый Калеедарь"
}
}

View File

@ -0,0 +1,33 @@
{
"name": "@anticrm/calendar-assets",
"version": "0.6.0",
"main": "lib/index.js",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "heft build",
"build:docs": "",
"lint": "eslint src",
"lint:fix": "eslint --fix src",
"format": "prettier --write src && eslint --fix src",
"build:watch": "tsc"
},
"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",
"@types/node": "^16.4.10"
},
"dependencies": {
"@anticrm/platform": "~0.6.5",
"@anticrm/calendar": "~0.6.0"
}
}

View File

@ -0,0 +1,25 @@
//
// 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 { addStringsLoader, loadMetadata } from '@anticrm/platform'
import calendar, { calendarId } from '@anticrm/calendar'
const icons = require('../assets/icons.svg') as string // eslint-disable-line
loadMetadata(calendar.icon, {
Calendar: `${icons}#calendar`,
Location: `${icons}#location`
})
addStringsLoader(calendarId, async (lang: string) => await import(`../lang/${lang}.json`))

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",
"module": "esnext",
"declaration": true,
"outDir": "./lib",
"strict": true,
"esModuleInterop": true,
"lib": [
"esnext",
"dom"
]
}
}

View 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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,47 @@
{
"name": "@anticrm/calendar-resources",
"version": "0.6.0",
"main": "src/index.ts",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "echo 'no build for ui'",
"build:docs": "api-extractor run --local",
"lint": "svelte-check && eslint",
"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.10.3",
"@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",
"typescript": "^4.3.5"
},
"dependencies": {
"@anticrm/core": "~0.6.11",
"@anticrm/platform": "~0.6.5",
"@anticrm/ui": "~0.6.0",
"@anticrm/presentation": "~0.6.2",
"@anticrm/calendar": "~0.6.0",
"svelte": "^3.37.0",
"@anticrm/text-editor": "~0.6.0",
"@anticrm/contact": "~0.6.2",
"@anticrm/contact-resources": "~0.6.0",
"@anticrm/view-resources": "~0.6.0",
"@anticrm/view": "~0.6.0",
"@anticrm/workbench": "~0.6.1"
}
}

View File

@ -0,0 +1,5 @@
module.exports = {
plugins: [
require('autoprefixer')
]
}

View File

@ -0,0 +1,56 @@
<!--
// 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 { formatName, Person } from '@anticrm/contact'
import { Hierarchy } from '@anticrm/core'
import { Avatar } from '@anticrm/presentation'
import calendar from '../plugin'
import { showPanel, Tooltip } from '@anticrm/ui'
import view from '@anticrm/view'
export let value: Person | Person[]
export let inline: boolean = false
let persons: Person[] = []
$: persons = Array.isArray(value) ? value : [value]
async function onClick (p: Person) {
showPanel(view.component.EditDoc, p._id, Hierarchy.mixinOrClass(p), 'full')
}
</script>
{#if value}
<div class='flex persons'>
{#each persons as p}
<Tooltip label={calendar.string.PersonsLabel} props={{ name: formatName(p.name) }}>
<div class="flex-presenter" class:inline-presenter={inline} on:click={() => onClick(p)}>
<div class="icon">
<Avatar size={'x-small'} avatar={p.avatar} />
</div>
</div>
</Tooltip>
{/each}
</div>
{/if}
<style lang="scss">
.persons {
display: grid;
grid-template-columns: repeat(4, min-content);
.icon {
margin: 0.25rem;
}
}
</style>

View 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 { Resources } from '@anticrm/platform'
import PersonsPresenter from './components/PersonsPresenter.svelte'
export default async (): Promise<Resources> => ({
component: {
PersonsPresenter
}
})

View 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 calendar, { calendarId } from '@anticrm/calendar'
import { mergeIds } from '@anticrm/platform'
export default mergeIds(calendarId, calendar, {
component: {
},
string: {
}
})

View File

@ -0,0 +1,5 @@
const sveltePreprocess = require('svelte-preprocess')
module.exports = {
preprocess: sveltePreprocess()
};

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"moduleResolution": "node",
"target": "esnext",
"module": "esnext",
"declaration": true,
"outDir": "./lib",
"strict": true,
"esModuleInterop": true,
"lib": [
"esnext",
"dom"
]
}
}

View 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'
}
}

View File

@ -0,0 +1,4 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/

View 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/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"
}

View File

@ -0,0 +1,34 @@
{
"name": "@anticrm/calendar",
"version": "0.6.0",
"main": "lib/index.js",
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "heft build",
"build:watch": "tsc",
"lint:fix": "eslint --fix src",
"lint": "eslint src",
"format": "prettier --write src && eslint --fix src"
},
"devDependencies": {
"@anticrm/platform-rig": "~0.6.0",
"@types/heft-jest": "^1.0.2",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-promise": "^5.1.1",
"eslint-plugin-node": "^11.1.0",
"eslint": "^7.32.0",
"@typescript-eslint/parser": "^5.4.0",
"eslint-config-standard-with-typescript": "^21.0.1",
"prettier": "^2.4.1",
"@rushstack/heft": "^0.41.1",
"typescript": "^4.3.5"
},
"dependencies": {
"@anticrm/platform": "~0.6.5",
"@anticrm/ui": "~0.6.0",
"@anticrm/core": "~0.6.11",
"@anticrm/contact": "~0.6.5"
}
}

View File

@ -0,0 +1,90 @@
// Copyright © 2022 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
import { Employee } from '@anticrm/contact'
import type { AttachedDoc, Class, Doc, Markup, Ref, Space, Timestamp } from '@anticrm/core'
import type { Asset, IntlString, Plugin } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import { AnyComponent } from '@anticrm/ui'
/**
* @public
*/
export interface Calendar extends Space {}
/**
* @public
*/
export interface Event extends AttachedDoc {
title: string
number: number
description: Markup
location?: string
// Event scheduled date
date: Timestamp
// Event due date for long events.
dueDate?: Timestamp
attachments?: number
comments?: number
participants?: Ref<Employee>[]
}
/**
* @public
*/
export const calendarId = 'calendar' as Plugin
/**
* @public
*/
const calendarPlugin = plugin(calendarId, {
class: {
Calendar: '' as Ref<Class<Calendar>>,
Event: '' as Ref<Class<Event>>
},
icon: {
Calendar: '' as Asset,
Location: '' as Asset
},
space: {
// Space for all personal events.
PersonalEvents: '' as Ref<Space>
},
app: {
Calendar: '' as Ref<Doc>
},
component: {
PersonsPresenter: '' as AnyComponent
},
string: {
Title: '' as IntlString,
Calendar: '' as IntlString,
Description: '' as IntlString,
Date: '' as IntlString,
DueTo: '' as IntlString,
Calendars: '' as IntlString,
CreateCalendar: '' as IntlString,
Location: '' as IntlString,
Participants: '' as IntlString,
NoParticipants: '' as IntlString,
PersonsLabel: '' as IntlString,
EventNumber: '' as IntlString
}
})
export default calendarPlugin

View File

@ -0,0 +1,9 @@
{
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"lib": ["esnext", "dom"]
}
}

View File

@ -20,6 +20,7 @@
import { createQuery } from '@anticrm/presentation'
import { Dropdown } from '@anticrm/ui'
import { ListItem } from '@anticrm/ui/src/types'
import { createEventDispatcher } from 'svelte'
import contact from '../plugin'
import Company from './icons/Company.svelte'
@ -27,6 +28,7 @@
export let label: IntlString = contact.string.Organization
const query = createQuery()
const dispatch = createEventDispatcher()
query.query(contact.class.Organization, {}, (res) => {
items = res.map((org) => {
@ -52,6 +54,7 @@
} else {
value = selected._id as Ref<Organization>
}
dispatch('change', value)
}
</script>

View File

@ -62,7 +62,7 @@
"ReviewCategory": "Reviews",
"ReviewCategoryDescription": "Description",
"ThisReviewCategoryIsPrivate": "This category is private",
"CreateReview": "Create review",
"CreateReview": "Schedule {label}",
"SelectReviewCategory": "select category",
"Reviews": "Reviews",
"Review": "Review",
@ -84,7 +84,8 @@
"OpinionValuePlaceholder": "10/10",
"Participants": "Participants",
"NoParticipants": "No participants added",
"PersonsLabel": "{name}"
"PersonsLabel": "{name}",
"AddDescription": "Add description"
},
"status": {
"CandidateRequired": "Please select candidate",

View File

@ -63,7 +63,7 @@
"ReviewCategory": "Оценки",
"ReviewCategoryDescription": "Описание",
"ThisReviewCategoryIsPrivate": "Эта категория личная",
"CreateReview": "Запланировать оценку",
"CreateReview": "Запланировать {label}",
"SelectReviewCategory": "выбрать категорию",
"Reviews": "Оценки",
"Review": "Оценка",
@ -85,7 +85,8 @@
"OpinionValuePlaceholder": "10/10",
"Participants": "Участники",
"NoParticipants": "Участники не добавлены",
"PersonsLabel": "{name}"
"PersonsLabel": "{name}",
"AddDescription": "Add description"
},
"status": {
"CandidateRequired": "Пожалуйста выберите кандидата",

View File

@ -55,6 +55,7 @@
"@anticrm/contact-resources": "~0.6.0",
"@anticrm/rekoni": "~0.6.0",
"@anticrm/notification": "~0.6.0",
"@anticrm/tags": "~0.6.0"
"@anticrm/tags": "~0.6.0",
"@anticrm/calendar": "~0.6.0"
}
}

View File

@ -13,36 +13,36 @@
// limitations under the License.
-->
<script lang="ts">
import type { Contact, Employee, Person } from '@anticrm/contact'
import type { Contact, Organization, Person } from '@anticrm/contact'
import contact from '@anticrm/contact'
import { Account, Class, Client, Doc, generateId, Ref, SortingOrder } from '@anticrm/core'
import { OrganizationSelector } from '@anticrm/contact-resources'
import { Account, Class, Client, Doc, generateId, Ref } from '@anticrm/core'
import { getResource, OK, Resource, Severity, Status } from '@anticrm/platform'
import { Card, getClient, UserBox } from '@anticrm/presentation'
import type { Candidate, Review } from '@anticrm/recruit'
import task, { calcRank, SpaceWithStates, State } from '@anticrm/task'
import { Grid, Status as StatusControl } from '@anticrm/ui'
import {DatePicker} from '@anticrm/ui'
import task, { SpaceWithStates } from '@anticrm/task'
import { StyledTextBox } from '@anticrm/text-editor'
import { DatePicker, Grid, Status as StatusControl, StylishEdit } from '@anticrm/ui'
import view from '@anticrm/view'
import { createEventDispatcher } from 'svelte'
import recruit from '../../plugin'
export let space: Ref<SpaceWithStates>
export let candidate: Ref<Person>
export let assignee: Ref<Employee>
export let preserveCandidate = false
let status: Status = OK
let title: string = ''
let description: string = ''
let startDate: Date = new Date()
let dueDate: Date = new Date()
let location: string = ''
let company: Ref<Organization> | undefined = undefined
const doc: Review = {
state: '' as Ref<State>,
doneState: null,
number: 0,
assignee: assignee,
rank: '',
attachedTo: candidate,
attachedToClass: recruit.mixin.Candidate,
_class: recruit.class.Review,
@ -51,10 +51,12 @@
collection: 'reviews',
modifiedOn: Date.now(),
modifiedBy: '' as Ref<Account>,
startDate: null,
dueDate: null,
description: '',
verdict: ''
date: 0,
dueDate: undefined,
description,
company,
verdict: '',
title
}
const dispatch = createEventDispatcher()
@ -62,9 +64,17 @@
const hierarchy = client.getHierarchy()
export function canClose (): boolean {
return candidate === undefined && assignee === undefined
return candidate === undefined
}
let spaceLabel: string = ''
$: client.findOne(recruit.class.ReviewCategory, { _id: doc.space }).then((res) => {
if (res !== undefined) {
spaceLabel = res.name
}
})
async function createReview () {
const state = await client.findOne(task.class.State, { space: doc.space })
if (state === undefined) {
@ -75,11 +85,6 @@
throw new Error('sequence object not found')
}
const lastOne = await client.findOne(
recruit.class.Review,
{ state: state._id },
{ sort: { rank: SortingOrder.Descending } }
)
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
const candidateInstance = await client.findOne(contact.class.Person, { _id: doc.attachedTo as Ref<Person> })
@ -87,24 +92,25 @@
throw new Error('contact not found')
}
if (!client.getHierarchy().hasMixin(candidateInstance, recruit.mixin.Candidate)) {
await client.createMixin<Contact, Candidate>(candidateInstance._id, candidateInstance._class, candidateInstance.space, recruit.mixin.Candidate, {})
await client.createMixin<Contact, Candidate>(
candidateInstance._id,
candidateInstance._class,
candidateInstance.space,
recruit.mixin.Candidate,
{}
)
}
await client.addCollection(
recruit.class.Review,
doc.space, doc.attachedTo, doc.attachedToClass, 'reviews',
{
state: state._id,
doneState: null,
await client.addCollection(recruit.class.Review, doc.space, doc.attachedTo, doc.attachedToClass, 'reviews', {
number: (incResult as any).object.sequence,
assignee: doc.assignee,
rank: calcRank(lastOne, undefined),
startDate: startDate?.getTime() ?? null,
date: startDate?.getTime() ?? null,
dueDate: dueDate?.getTime() ?? null,
description: '',
verdict: ''
}
)
description,
verdict: '',
title,
company,
location
})
}
async function invokeValidate (
@ -130,9 +136,11 @@
</script>
<Card
size={'medium'}
label={recruit.string.CreateReview}
labelProps={{ label: spaceLabel }}
okAction={createReview}
canSave={status.severity === Severity.OK}
canSave={status.severity === Severity.OK && title.trim().length > 0}
spaceClass={recruit.class.ReviewCategory}
spaceQuery={{ archived: false }}
spaceLabel={recruit.string.ReviewCategory}
@ -143,19 +151,38 @@
}}
>
<StatusControl slot="error" {status} />
<Grid column={1} rowGap={1.75}>
<Grid column={!preserveCandidate ? 2 : 1}>
<StylishEdit bind:value={title} label={recruit.string.Title} />
{#if !preserveCandidate}
<UserBox _class={contact.class.Person} title={recruit.string.Candidate} caption={recruit.string.Candidates} bind:value={doc.attachedTo} />
{/if}
<div class="antiComponentBox">
<UserBox
_class={contact.class.Employee}
title={recruit.string.AssignRecruiter}
caption={recruit.string.Recruiters}
bind:value={doc.assignee}
allowDeselect
titleDeselect={recruit.string.UnAssignRecruiter}
_class={contact.class.Person}
title={recruit.string.Candidate}
caption={recruit.string.Candidates}
bind:value={doc.attachedTo}
/>
</div>
{/if}
</Grid>
<StyledTextBox
emphasized
showButtons={false}
bind:content={description}
label={recruit.string.Description}
alwaysEdit
placeholder={recruit.string.AddDescription}
/>
<Grid column={2}>
<StylishEdit bind:value={location} label={recruit.string.Location} />
<OrganizationSelector bind:value={company} label={recruit.string.Company} />
</Grid>
<div class="antiComponentBox">
<DatePicker title={recruit.string.StartDate} bind:value={startDate} withTime />
</div>
<div class="antiComponentBox">
<DatePicker title={recruit.string.DueDate} bind:value={dueDate} withTime />
</div>
</Grid>
</Card>

View File

@ -14,44 +14,32 @@
-->
<script lang="ts">
import core, { Ref } from '@anticrm/core'
import core from '@anticrm/core'
import { getClient, SpaceCreateCard } from '@anticrm/presentation'
import task,{ createKanban,KanbanTemplate } from '@anticrm/task'
import { Component,EditBox,Grid } from '@anticrm/ui'
import { EditBox, Grid } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import recruit from '../../plugin'
import Review from '../icons/Review.svelte'
import { Organization } from '@anticrm/contact'
import { OrganizationSelector } from '@anticrm/contact-resources'
const dispatch = createEventDispatcher()
let name: string = ''
const description: string = ''
let templateId: Ref<KanbanTemplate> | undefined
let company: Ref<Organization> | undefined
export function canClose (): boolean {
return name === '' && templateId !== undefined
return name === ''
}
const client = getClient()
async function createReviewCategory () {
if (templateId !== undefined && await client.findOne(task.class.KanbanTemplate, { _id: templateId }) === undefined) {
throw Error(`Failed to find target kanban template: ${templateId}`)
}
const id = await client.createDoc(recruit.class.ReviewCategory, core.space.Space, {
await client.createDoc(recruit.class.ReviewCategory, core.space.Space, {
name,
description,
private: false,
archived: false,
company,
members: []
})
await createKanban(client, id, templateId)
}
</script>
@ -63,13 +51,5 @@
>
<Grid column={1} rowGap={1.5}>
<EditBox label={recruit.string.ReviewCategoryName} bind:value={name} icon={Review} placeholder={recruit.string.ReviewCategoryPlaceholder} maxWidth={'16rem'} focus/>
<OrganizationSelector bind:value={company} label={recruit.string.Company} />
<Component is={task.component.KanbanTemplateSelector} props={{
folders: [recruit.space.ReviewTemplates],
template: templateId
}} on:change={(evt) => {
templateId = evt.detail
}}/>
</Grid>
</SpaceCreateCard>

View File

@ -14,98 +14,65 @@
// limitations under the License.
-->
<script lang="ts">
import contact from '@anticrm/contact'
import { createQuery, getClient, UserBoxList } from '@anticrm/presentation'
import type { Candidate, Review, ReviewCategory } from '@anticrm/recruit'
import calendar from '@anticrm/calendar'
import contact, { Contact } from '@anticrm/contact'
import { OrganizationSelector } from '@anticrm/contact-resources'
import { getClient, UserBox, UserBoxList, UserInfo } from '@anticrm/presentation'
import type { Review } from '@anticrm/recruit'
import { StyledTextBox } from '@anticrm/text-editor'
import { EditBox, Grid, Label } from '@anticrm/ui'
import { Grid, Label, showPanel, StylishEdit } from '@anticrm/ui'
import { createEventDispatcher, onMount } from 'svelte'
import recruit from '../../plugin'
import CandidateCard from '../CandidateCard.svelte'
import ExpandRightDouble from '../icons/ExpandRightDouble.svelte'
import ReviewCategoryCard from './ReviewCategoryCard.svelte'
import view from '@anticrm/view'
export let object: Review
let candidate: Candidate
let reviewCategory: ReviewCategory
const candidateQuery = createQuery()
$: if (object !== undefined) {
candidateQuery.query(recruit.mixin.Candidate, { _id: object.attachedTo }, (result) => {
candidate = result[0]
})
}
const reviewCategoryQuery = createQuery()
$: if (candidate !== undefined) {
reviewCategoryQuery.query(recruit.class.ReviewCategory, { _id: object.space }, (result) => {
reviewCategory = result[0]
})
}
const dispatch = createEventDispatcher()
const client = getClient()
onMount(() => {
dispatch('open', {
ignoreKeys: ['location', 'company', 'number', 'comments', 'startDate', 'description', 'verdict']
ignoreKeys: ['number', 'comments', 'title', 'description', 'verdict']
})
})
let candidate: Contact | undefined = undefined
async function updateSelected (object: Review) {
candidate = await client.findOne<Contact>(object.attachedToClass, { _id: object.attachedTo })
}
$: updateSelected(object)
</script>
{#if object !== undefined && candidate !== undefined}
<div class="flex-between">
<div class="card"><CandidateCard {candidate} /></div>
<div class="arrows"><ExpandRightDouble /></div>
<div class="card"><ReviewCategoryCard category={reviewCategory} /></div>
</div>
<div class="mt-6 mb-2">
{#if object !== undefined}
<div class="mb-2">
<div class="mb-2">
<Grid column={2}>
<EditBox
label={recruit.string.Company}
bind:value={object.company}
icon={contact.icon.Company}
placeholder={recruit.string.Company}
maxWidth="39rem"
focus
on:change={() => client.update(object, { company: object.company })}
<StylishEdit
label={calendar.string.Title}
bind:value={object.title}
on:change={() => client.update(object, { title: object.title })}
/>
<EditBox
label={recruit.string.Location}
bind:value={object.location}
icon={recruit.icon.Location}
placeholder={recruit.string.Location}
maxWidth="39rem"
focus
on:change={() => client.update(object, { location: object.location })}
<div class="antiComponentBox over-underline" on:click={() => {
if (candidate !== undefined) {
showPanel(view.component.EditDoc, candidate._id, candidate._class, 'full')
}
}}>
<UserBox
readonly
_class={contact.class.Person}
title={recruit.string.Candidate}
caption={recruit.string.Candidates}
value={object.attachedTo}
/>
</div>
</Grid>
<div class="flex-row">
<div class="mt-4 mb-2">
<Label label={recruit.string.Participants} />
</div>
<UserBoxList
_class={contact.class.Employee}
items={object.participants}
title={recruit.string.Participants}
on:open={(evt) => {
client.update(object, { $push: { participants: evt.detail._id } })
}}
on:delete={(evt) => {
client.update(object, { $pull: { participants: evt.detail._id } })
}}
noItems={recruit.string.NoParticipants}
/>
</div>
</div>
<div class="mt-4 mb-1">
<Label label={recruit.string.Description} />
</div>
<div class="description flex">
<div class="mt-2 mb-2">
<StyledTextBox
label={recruit.string.Description}
emphasized
content={object.description}
on:value={(evt) => {
console.log(evt.detail)
@ -114,17 +81,44 @@
/>
</div>
<div class="mt-4 mb-1">
<Label label={recruit.string.Verdict} />
</div>
<div class="description flex">
<StyledTextBox
content={object.verdict}
on:value={(evt) => {
client.update(object, { verdict: evt.detail })
}}
<Grid column={2}>
<StylishEdit
label={calendar.string.Location}
bind:value={object.location}
on:change={() => client.update(object, { location: object.location })}
/>
<div class="antiComponentBox">
<OrganizationSelector
bind:value={object.company}
label={recruit.string.Company}
on:change={() => client.update(object, { company: object.company })}
/>
</div>
</Grid>
<div class="flex-row">
<div class="mt-4 mb-2">
<Label label={calendar.string.Participants} />
</div>
<UserBoxList
_class={contact.class.Employee}
items={object.participants}
title={calendar.string.Participants}
on:open={(evt) => {
client.update(object, { $push: { participants: evt.detail._id } })
}}
on:delete={(evt) => {
client.update(object, { $pull: { participants: evt.detail._id } })
}}
noItems={calendar.string.NoParticipants}
/>
</div>
</div>
<StylishEdit
label={recruit.string.Verdict}
bind:value={object.verdict}
on:change={() => client.update(object, { verdict: object.verdict })}
/>
{/if}
<style lang="scss">
@ -138,8 +132,6 @@
.description {
height: 10rem;
padding: 1rem;
border: 1px solid var(--theme-menu-divider);
border-radius: 8px;
margin-bottom: 1rem;
}
</style>

View File

@ -1,90 +0,0 @@
<!--
// 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 { AttachmentsPresenter } from '@anticrm/attachment-resources'
import { CommentsPresenter } from '@anticrm/chunter-resources'
import { Employee, formatName, Person } from '@anticrm/contact'
import type { WithLookup } from '@anticrm/core'
import { Avatar } from '@anticrm/presentation'
import type { Review } from '@anticrm/recruit'
import { ActionIcon, IconMoreH, showPanel } from '@anticrm/ui'
import view from '@anticrm/view'
import PersonsPresenter from './PersonsPresenter.svelte'
import ReviewPresenter from './ReviewPresenter.svelte'
export let object: WithLookup<Review>
export let draggable: boolean
function showCandidate () {
showPanel(view.component.EditDoc, object.attachedTo, object.attachedToClass, 'full')
}
function getPersons (object: WithLookup<Review>): Person[] {
const r = (object.$lookup?.participants as unknown as Employee[] ?? [])
const assignee = object.$lookup?.assignee as Employee
if (assignee != null && r.findIndex(it => it._id === assignee._id) === -1) {
return [...r, assignee]
}
return r
}
</script>
<div class="card-container" {draggable} class:draggable on:dragstart on:dragend>
<div class="flex-between mb-3">
<Avatar avatar={object.$lookup?.attachedTo?.avatar} size={'medium'} />
<div class="flex-grow flex-col min-w-0 ml-2">
<div class="fs-title over-underline lines-limit-2" on:click={showCandidate}>
{#if object.$lookup?.attachedTo}
{formatName(object.$lookup?.attachedTo?.name)}
{/if}
</div>
<div class="small-text lines-limit-2">{object.$lookup?.attachedTo?.title ?? ''}</div>
</div>
<div class="tool"><ActionIcon label={undefined} icon={IconMoreH} size={'small'} /></div>
</div>
<div class="flex-between">
<div class="flex-row-center">
<div class="sm-tool-icon step-lr75">
<ReviewPresenter value={object} />
</div>
{#if (object.attachments ?? 0) > 0}
<div class="step-lr75"><AttachmentsPresenter value={object} /></div>
{/if}
{#if (object.comments ?? 0) > 0}
<div class="step-lr75"><CommentsPresenter value={object} /></div>
{/if}
</div>
{#if object.$lookup?.participants || object.$lookup?.assignee}
<PersonsPresenter value={getPersons(object)}></PersonsPresenter>
{/if}
</div>
</div>
<style lang="scss">
.card-container {
display: flex;
flex-direction: column;
padding: 1rem 1.25rem;
background-color: rgba(222, 222, 240, 0.06);
border-radius: 0.75rem;
user-select: none;
&.draggable {
cursor: grab;
}
}
.tool {
align-self: start;
}
</style>

View File

@ -0,0 +1,37 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021, 2022 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import type { ReviewCategory } from '@anticrm/recruit'
import { Icon } from '@anticrm/ui'
import { showPanel } from '@anticrm/ui/src/panelup'
import recruit from '../../plugin'
export let value: ReviewCategory
export let inline: boolean = false
function show () {
// showPanel(recruit.component.EditVacancy, value._id, value._class, 'right')
}
</script>
{#if value}
<div class="flex-presenter" class:inline-presenter={inline} on:click={show}>
<div class="icon">
<Icon icon={recruit.icon.Vacancy} size={'small'} />
</div>
<span class="label">{value.name}</span>
</div>
{/if}

View File

@ -37,7 +37,7 @@
function show () {
closeTooltip()
showPanel(view.component.EditDoc, value._id, value._class, 'full')
showPanel(view.component.EditDoc, value._id, value._class, 'right')
}
</script>

View File

@ -43,21 +43,19 @@
config={[
'',
{ key: '$lookup.space.name', label: recruit.string.ReviewCategoryTitle },
'dueDate',
'verdict',
{
key: '',
presenter: recruit.component.OpinionsPresenter,
label: recruit.string.Opinions,
sortingKey: 'opinions'
},
'$lookup.state',
'$lookup.doneState'
'date',
'dueDate'
]}
options={{
lookup: {
state: task.class.State,
space: core.class.Space,
doneState: task.class.DoneState
space: core.class.Space
}
}}
query={{ attachedTo: objectId }}

View File

@ -35,7 +35,6 @@ import CreateOpinion from './components/review/CreateOpinion.svelte'
import CreateReviewCategory from './components/review/CreateReviewCategory.svelte'
import EditReview from './components/review/EditReview.svelte'
import EditReviewCategory from './components/review/EditReviewCategory.svelte'
import KanbanReviewCard from './components/review/KanbanReviewCard.svelte'
import OpinionPresenter from './components/review/OpinionPresenter.svelte'
import OpinionsPresenter from './components/review/OpinionsPresenter.svelte'
import Opinions from './components/review/Opinions.svelte'
@ -48,8 +47,8 @@ import VacancyItemPresenter from './components/VacancyItemPresenter.svelte'
import VacancyPresenter from './components/VacancyPresenter.svelte'
import VacancyCountPresenter from './components/VacancyCountPresenter.svelte'
import VacancyModifiedPresenter from './components/VacancyModifiedPresenter.svelte'
import ReviewCategoryPresenter from './components/review/ReviewCategoryPresenter.svelte'
import recruit from './plugin'
import PersonsPresenter from './components/review/PersonsPresenter.svelte'
async function createApplication (object: Doc): Promise<void> {
showPopup(CreateApplication, { candidate: object._id, preserveCandidate: true })
@ -163,12 +162,11 @@ export default async (): Promise<Resources> => ({
CreateReview,
ReviewPresenter,
EditReview,
KanbanReviewCard,
Reviews,
Opinions,
OpinionPresenter,
OpinionsPresenter,
PersonsPresenter
ReviewCategoryPresenter
},
completion: {
ApplicationQuery: async (client: Client, query: string) => await queryApplication(client, query)

View File

@ -101,9 +101,7 @@ export default mergeIds(recruitId, recruit, {
StartDate: '' as IntlString,
DueDate: '' as IntlString,
CandidateReviews: '' as IntlString,
Participants: '' as IntlString,
NoParticipants: '' as IntlString,
PersonsLabel: '' as IntlString
AddDescription: '' as IntlString
},
space: {
CandidatesPublic: '' as Ref<Space>
@ -116,7 +114,6 @@ export default mergeIds(recruitId, recruit, {
VacancyItemPresenter: '' as AnyComponent,
VacancyCountPresenter: '' as AnyComponent,
OpinionsPresenter: '' as AnyComponent,
PersonsPresenter: '' as AnyComponent,
VacancyModifiedPresenter: '' as AnyComponent
}
})

View File

@ -31,6 +31,7 @@
"@anticrm/contact": "~0.6.5",
"@anticrm/chunter": "~0.6.1",
"@anticrm/task": "~0.6.0",
"@anticrm/calendar": "~0.6.0",
"@anticrm/ui": "~0.6.0"
}
}

View File

@ -13,7 +13,8 @@
// limitations under the License.
//
import type { Employee, Organization, Person } from '@anticrm/contact'
import { Calendar, Event } from '@anticrm/calendar'
import type { Organization, Person } from '@anticrm/contact'
import type { AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestamp } from '@anticrm/core'
import type { Asset, Plugin } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
@ -34,10 +35,10 @@ export interface Vacancy extends SpaceWithStates {
/**
* @public
*/
export interface ReviewCategory extends SpaceWithStates {
export interface ReviewCategory extends Calendar {
fullDescription?: string
attachments?: number
company?: Ref<Organization>
comments?: number
}
/**
@ -70,22 +71,14 @@ export interface Applicant extends Task {
/**
* @public
*/
export interface Review extends Task {
export interface Review extends Event {
attachedTo: Ref<Candidate>
attachments?: number
comments?: number
description: string
verdict: string
location?: string
company?: string
startDate: Timestamp | null
dueDate: Timestamp | null
company?: Ref<Organization>
opinions?: number
participants?: Ref<Employee>[]
}
/**

View File

@ -15,6 +15,7 @@
-->
<script lang="ts">
import { TypeDate } from '@anticrm/core'
import { IntlString } from '@anticrm/platform'
import { DatePopup, showPopup } from '@anticrm/ui'
import DatePresenter from './DatePresenter.svelte'
@ -22,6 +23,9 @@
export let value: number | Date | undefined
export let label: IntlString
export let onChange: (value: any) => void
export let attributeType: TypeDate | undefined
$: date = value ? new Date(value) : new Date()
let container: HTMLElement
let opened: boolean = false
@ -31,7 +35,7 @@
on:click|preventDefault={() => {
if (!opened) {
opened = true
showPopup(DatePopup, { selected: date, title: label }, container, (result) => {
showPopup(DatePopup, { value: date, title: label, withTime: attributeType?.withTime ?? false }, container, (result) => {
if (result) {
value = result.getTime()
onChange(value)
@ -40,5 +44,5 @@
})
}
}} >
<DatePresenter {value} />
<DatePresenter {value} {attributeType} />
</div>

View File

@ -15,16 +15,18 @@
-->
<script lang="ts">
import { TypeDate } from '@anticrm/core'
import { DatePresenter } from '@anticrm/ui'
export let value: number | Date | undefined
export let attributeType: TypeDate | undefined
$: date = value ? new Date(value) : undefined
</script>
<div class="antiSelect">
{#if date}
<DatePresenter value={date} />
<DatePresenter value={date} withTime={attributeType?.withTime ?? false} />
{:else}
No date
{/if}

View File

@ -0,0 +1,26 @@
<!--
// 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 { IntlString } from '@anticrm/platform'
import { Label } from '@anticrm/ui'
export let value: IntlString
</script>
<span class="lines-limit-2">
<Label label={value}/>
</span>

View File

@ -23,6 +23,7 @@ import DateEditor from './components/DateEditor.svelte'
import DatePresenter from './components/DatePresenter.svelte'
import StringEditor from './components/StringEditor.svelte'
import StringPresenter from './components/StringPresenter.svelte'
import IntlStringPresenter from './components/IntlStringPresenter.svelte'
import NumberEditor from './components/NumberEditor.svelte'
import NumberPresenter from './components/NumberPresenter.svelte'
import Table from './components/Table.svelte'
@ -80,6 +81,7 @@ export default async (): Promise<Resources> => ({
RolePresenter,
ObjectPresenter,
EditDoc,
HTMLPresenter
HTMLPresenter,
IntlStringPresenter
}
})

View File

@ -98,12 +98,14 @@ async function getAttributePresenter (
const resultKey = preserveKey.sortingKey ?? preserveKey.key
const sortingKey = attribute.type._class === core.class.ArrOf ? resultKey + '.length' : resultKey
const presenter = await getResource(presenterMixin.presenter)
return {
key: preserveKey.key,
sortingKey,
_class: attrClass,
label: preserveKey.label ?? attribute.label,
presenter,
props: { attributeType: attribute.type },
icon: presenterMixin.icon,
attribute
}
@ -215,7 +217,7 @@ export async function getActions (
export async function deleteObject (client: TxOperations, object: Doc): Promise<void> {
const hierarchy = client.getHierarchy()
const promises: Promise<any>[] = []
const promises: Array<Promise<any>> = []
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
promises.push(client.removeCollection(object._class, object.space, adoc._id, adoc.attachedTo, adoc.attachedToClass, adoc.collection).catch(err => console.error(err)))
@ -261,7 +263,7 @@ function getParentClass (hierarchy: Hierarchy, _class: Ref<Class<Doc>>): Ref<Cla
return result
}
function getMixins (hierarchy: Hierarchy, _class: Ref<Class<Doc>>, object: Doc): Ref<Mixin<Doc>>[] {
function getMixins (hierarchy: Hierarchy, _class: Ref<Class<Doc>>, object: Doc): Array<Ref<Mixin<Doc>>> {
const parentClass = getParentClass(hierarchy, _class)
const descendants = hierarchy.getDescendants(parentClass)
return descendants.filter(

View File

@ -65,8 +65,12 @@
{#if spaceSample !== undefined && model}
<Table
_class={spaceSample._class}
config={['', 'company', 'location', 'modifiedOn']}
options={{}}
config={['', '$lookup._class.label', 'modifiedOn']}
options={{
lookup: {
_class: core.class.Class
}
}}
showNotification
baseMenuClass={core.class.Space}
query={{

View File

@ -1131,5 +1131,25 @@
"projectFolder": "server-plugins/setting-resources",
"shouldPublish": true
},
{
"packageName": "@anticrm/calendar",
"projectFolder": "plugins/calendar",
"shouldPublish": true
},
{
"packageName": "@anticrm/calendar-assets",
"projectFolder": "plugins/calendar-assets",
"shouldPublish": true
},
{
"packageName": "@anticrm/calendar-resources",
"projectFolder": "plugins/calendar-resources",
"shouldPublish": true
},
{
"packageName": "@anticrm/model-calendar",
"projectFolder": "models/calendar",
"shouldPublish": true
},
]
}