mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Hr (#2100)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
da07828036
commit
5e38409a88
@ -41,6 +41,9 @@ specifiers:
|
|||||||
'@rush-temp/gmail': file:./projects/gmail.tgz
|
'@rush-temp/gmail': file:./projects/gmail.tgz
|
||||||
'@rush-temp/gmail-assets': file:./projects/gmail-assets.tgz
|
'@rush-temp/gmail-assets': file:./projects/gmail-assets.tgz
|
||||||
'@rush-temp/gmail-resources': file:./projects/gmail-resources.tgz
|
'@rush-temp/gmail-resources': file:./projects/gmail-resources.tgz
|
||||||
|
'@rush-temp/hr': file:./projects/hr.tgz
|
||||||
|
'@rush-temp/hr-assets': file:./projects/hr-assets.tgz
|
||||||
|
'@rush-temp/hr-resources': file:./projects/hr-resources.tgz
|
||||||
'@rush-temp/image-cropper': file:./projects/image-cropper.tgz
|
'@rush-temp/image-cropper': file:./projects/image-cropper.tgz
|
||||||
'@rush-temp/image-cropper-resources': file:./projects/image-cropper-resources.tgz
|
'@rush-temp/image-cropper-resources': file:./projects/image-cropper-resources.tgz
|
||||||
'@rush-temp/inventory': file:./projects/inventory.tgz
|
'@rush-temp/inventory': file:./projects/inventory.tgz
|
||||||
@ -65,6 +68,7 @@ specifiers:
|
|||||||
'@rush-temp/model-core': file:./projects/model-core.tgz
|
'@rush-temp/model-core': file:./projects/model-core.tgz
|
||||||
'@rush-temp/model-demo': file:./projects/model-demo.tgz
|
'@rush-temp/model-demo': file:./projects/model-demo.tgz
|
||||||
'@rush-temp/model-gmail': file:./projects/model-gmail.tgz
|
'@rush-temp/model-gmail': file:./projects/model-gmail.tgz
|
||||||
|
'@rush-temp/model-hr': file:./projects/model-hr.tgz
|
||||||
'@rush-temp/model-inventory': file:./projects/model-inventory.tgz
|
'@rush-temp/model-inventory': file:./projects/model-inventory.tgz
|
||||||
'@rush-temp/model-lead': file:./projects/model-lead.tgz
|
'@rush-temp/model-lead': file:./projects/model-lead.tgz
|
||||||
'@rush-temp/model-notification': file:./projects/model-notification.tgz
|
'@rush-temp/model-notification': file:./projects/model-notification.tgz
|
||||||
@ -79,6 +83,7 @@ specifiers:
|
|||||||
'@rush-temp/model-server-contact': file:./projects/model-server-contact.tgz
|
'@rush-temp/model-server-contact': file:./projects/model-server-contact.tgz
|
||||||
'@rush-temp/model-server-core': file:./projects/model-server-core.tgz
|
'@rush-temp/model-server-core': file:./projects/model-server-core.tgz
|
||||||
'@rush-temp/model-server-gmail': file:./projects/model-server-gmail.tgz
|
'@rush-temp/model-server-gmail': file:./projects/model-server-gmail.tgz
|
||||||
|
'@rush-temp/model-server-hr': file:./projects/model-server-hr.tgz
|
||||||
'@rush-temp/model-server-inventory': file:./projects/model-server-inventory.tgz
|
'@rush-temp/model-server-inventory': file:./projects/model-server-inventory.tgz
|
||||||
'@rush-temp/model-server-lead': file:./projects/model-server-lead.tgz
|
'@rush-temp/model-server-lead': file:./projects/model-server-lead.tgz
|
||||||
'@rush-temp/model-server-notification': file:./projects/model-server-notification.tgz
|
'@rush-temp/model-server-notification': file:./projects/model-server-notification.tgz
|
||||||
@ -131,6 +136,8 @@ specifiers:
|
|||||||
'@rush-temp/server-core': file:./projects/server-core.tgz
|
'@rush-temp/server-core': file:./projects/server-core.tgz
|
||||||
'@rush-temp/server-gmail': file:./projects/server-gmail.tgz
|
'@rush-temp/server-gmail': file:./projects/server-gmail.tgz
|
||||||
'@rush-temp/server-gmail-resources': file:./projects/server-gmail-resources.tgz
|
'@rush-temp/server-gmail-resources': file:./projects/server-gmail-resources.tgz
|
||||||
|
'@rush-temp/server-hr': file:./projects/server-hr.tgz
|
||||||
|
'@rush-temp/server-hr-resources': file:./projects/server-hr-resources.tgz
|
||||||
'@rush-temp/server-inventory': file:./projects/server-inventory.tgz
|
'@rush-temp/server-inventory': file:./projects/server-inventory.tgz
|
||||||
'@rush-temp/server-inventory-resources': file:./projects/server-inventory-resources.tgz
|
'@rush-temp/server-inventory-resources': file:./projects/server-inventory-resources.tgz
|
||||||
'@rush-temp/server-lead': file:./projects/server-lead.tgz
|
'@rush-temp/server-lead': file:./projects/server-lead.tgz
|
||||||
@ -331,6 +338,9 @@ dependencies:
|
|||||||
'@rush-temp/gmail': file:projects/gmail.tgz
|
'@rush-temp/gmail': file:projects/gmail.tgz
|
||||||
'@rush-temp/gmail-assets': file:projects/gmail-assets.tgz
|
'@rush-temp/gmail-assets': file:projects/gmail-assets.tgz
|
||||||
'@rush-temp/gmail-resources': file:projects/gmail-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c
|
'@rush-temp/gmail-resources': file:projects/gmail-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c
|
||||||
|
'@rush-temp/hr': file:projects/hr.tgz
|
||||||
|
'@rush-temp/hr-assets': file:projects/hr-assets.tgz_typescript@4.7.2
|
||||||
|
'@rush-temp/hr-resources': file:projects/hr-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c
|
||||||
'@rush-temp/image-cropper': file:projects/image-cropper.tgz
|
'@rush-temp/image-cropper': file:projects/image-cropper.tgz
|
||||||
'@rush-temp/image-cropper-resources': file:projects/image-cropper-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c
|
'@rush-temp/image-cropper-resources': file:projects/image-cropper-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c
|
||||||
'@rush-temp/inventory': file:projects/inventory.tgz
|
'@rush-temp/inventory': file:projects/inventory.tgz
|
||||||
@ -355,6 +365,7 @@ dependencies:
|
|||||||
'@rush-temp/model-core': file:projects/model-core.tgz_typescript@4.7.2
|
'@rush-temp/model-core': file:projects/model-core.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-demo': file:projects/model-demo.tgz_typescript@4.7.2
|
'@rush-temp/model-demo': file:projects/model-demo.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-gmail': file:projects/model-gmail.tgz_typescript@4.7.2
|
'@rush-temp/model-gmail': file:projects/model-gmail.tgz_typescript@4.7.2
|
||||||
|
'@rush-temp/model-hr': file:projects/model-hr.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-inventory': file:projects/model-inventory.tgz_typescript@4.7.2
|
'@rush-temp/model-inventory': file:projects/model-inventory.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-lead': file:projects/model-lead.tgz_typescript@4.7.2
|
'@rush-temp/model-lead': file:projects/model-lead.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-notification': file:projects/model-notification.tgz_typescript@4.7.2
|
'@rush-temp/model-notification': file:projects/model-notification.tgz_typescript@4.7.2
|
||||||
@ -369,6 +380,7 @@ dependencies:
|
|||||||
'@rush-temp/model-server-contact': file:projects/model-server-contact.tgz_typescript@4.7.2
|
'@rush-temp/model-server-contact': file:projects/model-server-contact.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-server-core': file:projects/model-server-core.tgz_typescript@4.7.2
|
'@rush-temp/model-server-core': file:projects/model-server-core.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-server-gmail': file:projects/model-server-gmail.tgz_typescript@4.7.2
|
'@rush-temp/model-server-gmail': file:projects/model-server-gmail.tgz_typescript@4.7.2
|
||||||
|
'@rush-temp/model-server-hr': file:projects/model-server-hr.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-server-inventory': file:projects/model-server-inventory.tgz_typescript@4.7.2
|
'@rush-temp/model-server-inventory': file:projects/model-server-inventory.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-server-lead': file:projects/model-server-lead.tgz_typescript@4.7.2
|
'@rush-temp/model-server-lead': file:projects/model-server-lead.tgz_typescript@4.7.2
|
||||||
'@rush-temp/model-server-notification': file:projects/model-server-notification.tgz_typescript@4.7.2
|
'@rush-temp/model-server-notification': file:projects/model-server-notification.tgz_typescript@4.7.2
|
||||||
@ -421,6 +433,8 @@ dependencies:
|
|||||||
'@rush-temp/server-core': file:projects/server-core.tgz
|
'@rush-temp/server-core': file:projects/server-core.tgz
|
||||||
'@rush-temp/server-gmail': file:projects/server-gmail.tgz
|
'@rush-temp/server-gmail': file:projects/server-gmail.tgz
|
||||||
'@rush-temp/server-gmail-resources': file:projects/server-gmail-resources.tgz
|
'@rush-temp/server-gmail-resources': file:projects/server-gmail-resources.tgz
|
||||||
|
'@rush-temp/server-hr': file:projects/server-hr.tgz
|
||||||
|
'@rush-temp/server-hr-resources': file:projects/server-hr-resources.tgz
|
||||||
'@rush-temp/server-inventory': file:projects/server-inventory.tgz
|
'@rush-temp/server-inventory': file:projects/server-inventory.tgz
|
||||||
'@rush-temp/server-inventory-resources': file:projects/server-inventory-resources.tgz
|
'@rush-temp/server-inventory-resources': file:projects/server-inventory-resources.tgz
|
||||||
'@rush-temp/server-lead': file:projects/server-lead.tgz
|
'@rush-temp/server-lead': file:projects/server-lead.tgz
|
||||||
@ -10925,6 +10939,89 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
file:projects/hr-assets.tgz_typescript@4.7.2:
|
||||||
|
resolution: {integrity: sha512-Or7JUoPjJeVKIbJt6RExTLlWhvCJxWe1dZBA0332S7HIUgWDnev8Qx0EzBxV1FKXne/XV1w8ZEusJXPReGz3mw==, tarball: file:projects/hr-assets.tgz}
|
||||||
|
id: file:projects/hr-assets.tgz
|
||||||
|
name: '@rush-temp/hr-assets'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@rushstack/heft': 0.45.5
|
||||||
|
'@types/heft-jest': 1.0.2
|
||||||
|
'@types/node': 16.11.38
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
- typescript
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
file:projects/hr-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
||||||
|
resolution: {integrity: sha512-sYnkYAs2h/gH6VD8c6+QBHMemRZfIMVthpYzi1+TXliv/EmebzxdFyPCPjLbxgQxpq4mUwuMLlAusMIrmpVNrg==, tarball: file:projects/hr-resources.tgz}
|
||||||
|
id: file:projects/hr-resources.tgz
|
||||||
|
name: '@rush-temp/hr-resources'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
eslint-plugin-svelte3: 4.0.0_eslint@7.32.0+svelte@3.48.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.48.0
|
||||||
|
sass: 1.52.2
|
||||||
|
svelte: 3.48.0
|
||||||
|
svelte-check: 2.7.2_c1788f0bf13b393830d6c30602bd01af
|
||||||
|
svelte-loader: 3.1.3_svelte@3.48.0
|
||||||
|
svelte-preprocess: 4.10.6_0757fe126296bf9639251bcd13609b29
|
||||||
|
typescript: 4.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@babel/core'
|
||||||
|
- coffeescript
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- less
|
||||||
|
- node-sass
|
||||||
|
- postcss
|
||||||
|
- postcss-load-config
|
||||||
|
- pug
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
file:projects/hr.tgz:
|
||||||
|
resolution: {integrity: sha512-8jSKJNCIhxfPjP8hislK8NLocwO4VwDJ/jjYzq6tlRwgiI3pMAuftX/NsZEKARgHcHebssy63acqJNImdp2ALQ==, tarball: file:projects/hr.tgz}
|
||||||
|
name: '@rush-temp/hr'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@rushstack/heft': 0.45.5
|
||||||
|
'@types/heft-jest': 1.0.2
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
typescript: 4.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
file:projects/image-cropper-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
file:projects/image-cropper-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
||||||
resolution: {integrity: sha512-8whE1ZAsPDruwYl6MT6HEWi5zFPGLg3fsYmvdDL2cx1KmDH421bm+M5kkq+Ok5HUV8jYoQRK00zvX8Awz4e+lQ==, tarball: file:projects/image-cropper-resources.tgz}
|
resolution: {integrity: sha512-8whE1ZAsPDruwYl6MT6HEWi5zFPGLg3fsYmvdDL2cx1KmDH421bm+M5kkq+Ok5HUV8jYoQRK00zvX8Awz4e+lQ==, tarball: file:projects/image-cropper-resources.tgz}
|
||||||
id: file:projects/image-cropper-resources.tgz
|
id: file:projects/image-cropper-resources.tgz
|
||||||
@ -11318,7 +11415,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/model-all.tgz_typescript@4.7.2:
|
file:projects/model-all.tgz_typescript@4.7.2:
|
||||||
resolution: {integrity: sha512-3KLZ8VdyN6qL7q5SOOeD9sU9xUoDeqJRxAbyLtFhAgaTU1tX9n3C+cnmlDZhXq8kcK/Ss/xK2hrHfq0kOI7ILw==, tarball: file:projects/model-all.tgz}
|
resolution: {integrity: sha512-VrR3QpQKo2qizq7xi/uS9Jj+OyrB/mPDLnAc8/pvwEx8jF5PwySSsP63uSNGcO3fwv7ZjZvAiuvEnaIHUZ5Ivg==, tarball: file:projects/model-all.tgz}
|
||||||
id: file:projects/model-all.tgz
|
id: file:projects/model-all.tgz
|
||||||
name: '@rush-temp/model-all'
|
name: '@rush-temp/model-all'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -11528,6 +11625,29 @@ packages:
|
|||||||
- typescript
|
- typescript
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
file:projects/model-hr.tgz_typescript@4.7.2:
|
||||||
|
resolution: {integrity: sha512-HtAgUigvoyvjSpGUHwcRfTqM+RpMKyvDrieHpRBIvFans/2Kg3FPlacTHa9vhBilcze0pNBDrlSXyGuKMBLl8g==, tarball: file:projects/model-hr.tgz}
|
||||||
|
id: file:projects/model-hr.tgz
|
||||||
|
name: '@rush-temp/model-hr'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@rushstack/heft': 0.45.5
|
||||||
|
'@types/heft-jest': 1.0.2
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
- typescript
|
||||||
|
dev: false
|
||||||
|
|
||||||
file:projects/model-inventory.tgz_typescript@4.7.2:
|
file:projects/model-inventory.tgz_typescript@4.7.2:
|
||||||
resolution: {integrity: sha512-ZrDM3hzsPJZPI1EGZpP4sEkEnJmmfzW77c2g7JejOCROBy6gd7237XN/SPjPk85CcSg7iHyueJiG9QGgoRB5SQ==, tarball: file:projects/model-inventory.tgz}
|
resolution: {integrity: sha512-ZrDM3hzsPJZPI1EGZpP4sEkEnJmmfzW77c2g7JejOCROBy6gd7237XN/SPjPk85CcSg7iHyueJiG9QGgoRB5SQ==, tarball: file:projects/model-inventory.tgz}
|
||||||
id: file:projects/model-inventory.tgz
|
id: file:projects/model-inventory.tgz
|
||||||
@ -11847,6 +11967,29 @@ packages:
|
|||||||
- typescript
|
- typescript
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
file:projects/model-server-hr.tgz_typescript@4.7.2:
|
||||||
|
resolution: {integrity: sha512-jSk/2YD9iHX6gPWUlc+RstSQVCpJGeoEsRNyaI3MMPtwytRCNa6Bdp1FjwFr3WId2wFQ+eHdpg9EtGr5ooGhUg==, tarball: file:projects/model-server-hr.tgz}
|
||||||
|
id: file:projects/model-server-hr.tgz
|
||||||
|
name: '@rush-temp/model-server-hr'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@rushstack/heft': 0.45.5
|
||||||
|
'@types/heft-jest': 1.0.2
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
- typescript
|
||||||
|
dev: false
|
||||||
|
|
||||||
file:projects/model-server-inventory.tgz_typescript@4.7.2:
|
file:projects/model-server-inventory.tgz_typescript@4.7.2:
|
||||||
resolution: {integrity: sha512-fEZjpHFjw7k95RXySO8e9RpoaicF9jI2fVN9SSDEFUSmBsUKz3yR1wa1JrALrsH0YjcKzL1dWQK6AIJj4PuMCA==, tarball: file:projects/model-server-inventory.tgz}
|
resolution: {integrity: sha512-fEZjpHFjw7k95RXySO8e9RpoaicF9jI2fVN9SSDEFUSmBsUKz3yR1wa1JrALrsH0YjcKzL1dWQK6AIJj4PuMCA==, tarball: file:projects/model-server-inventory.tgz}
|
||||||
id: file:projects/model-server-inventory.tgz
|
id: file:projects/model-server-inventory.tgz
|
||||||
@ -12193,7 +12336,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/model-tracker.tgz_typescript@4.7.2:
|
file:projects/model-tracker.tgz_typescript@4.7.2:
|
||||||
resolution: {integrity: sha512-3giT5Ql8N6I6UaeU038P16HSmmhnQdy2eIYaKok1cF+AX0Z/0dXcR/bSvgQ88WJxMrtAsusZkOkF+PyvUUJOYg==, tarball: file:projects/model-tracker.tgz}
|
resolution: {integrity: sha512-3NvQ5qG0MQi1q/7nydGTluAJYjDlwLDG+AZXSG3I0tMEG5YpQguM399GXlGlWZzhFAc++KUK1nDR7JWtaPmXcA==, tarball: file:projects/model-tracker.tgz}
|
||||||
id: file:projects/model-tracker.tgz
|
id: file:projects/model-tracker.tgz
|
||||||
name: '@rush-temp/model-tracker'
|
name: '@rush-temp/model-tracker'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -12679,7 +12822,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/prod.tgz_d1c3762ecb2c185353d3f02936f6ec22:
|
file:projects/prod.tgz_d1c3762ecb2c185353d3f02936f6ec22:
|
||||||
resolution: {integrity: sha512-PehFsaG21mA1q8ou+ldHAfMX0O+nPv2zVXTuj/K5TPMZ/DEkCtQHZtaVElryGq4xD1PlMyaID/1mqppbYEpbPQ==, tarball: file:projects/prod.tgz}
|
resolution: {integrity: sha512-Ruj8noHdrzO1bGVEYxLSgza5VdloFea3VbtIutq8UnZThqIzyBmJRsEo1lLmN5WAKBW50oEBKsKDZxuXB/ZuYQ==, tarball: file:projects/prod.tgz}
|
||||||
id: file:projects/prod.tgz
|
id: file:projects/prod.tgz
|
||||||
name: '@rush-temp/prod'
|
name: '@rush-temp/prod'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -13182,6 +13325,51 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
file:projects/server-hr-resources.tgz:
|
||||||
|
resolution: {integrity: sha512-D073FS8B1EjB1D7fFgFm1Tdq6u69DaNcLVx65szIypERkUyFKyNr5KXqSyHSeDbwPWwz7nyOw2ecN8rlCPHnJg==, tarball: file:projects/server-hr-resources.tgz}
|
||||||
|
name: '@rush-temp/server-hr-resources'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@rushstack/heft': 0.45.5
|
||||||
|
'@types/heft-jest': 1.0.2
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
typescript: 4.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
file:projects/server-hr.tgz:
|
||||||
|
resolution: {integrity: sha512-VPn9I/49Q/15y/R3yinhsKHb5CwTxzHZFemEfj0b/sALUamdf3S3sJpdMorZkNI44hFOns6LzHRRKUf/ka9zOA==, tarball: file:projects/server-hr.tgz}
|
||||||
|
name: '@rush-temp/server-hr'
|
||||||
|
version: 0.0.0
|
||||||
|
dependencies:
|
||||||
|
'@rushstack/heft': 0.45.5
|
||||||
|
'@types/heft-jest': 1.0.2
|
||||||
|
'@types/node': 16.11.38
|
||||||
|
'@typescript-eslint/eslint-plugin': 5.27.0_738fa17fa57f8a69ace69c90e5cfa1d5
|
||||||
|
'@typescript-eslint/parser': 5.27.0_eslint@7.32.0+typescript@4.7.2
|
||||||
|
eslint: 7.32.0
|
||||||
|
eslint-config-standard-with-typescript: 21.0.1_99a5fe2f2ae1dc64d6b59974c931eb2a
|
||||||
|
eslint-plugin-import: 2.26.0_c21022bc9feaeb7b200d3d631eeae46c
|
||||||
|
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||||
|
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||||
|
prettier: 2.6.2
|
||||||
|
typescript: 4.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- eslint-import-resolver-typescript
|
||||||
|
- eslint-import-resolver-webpack
|
||||||
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
file:projects/server-inventory-resources.tgz:
|
file:projects/server-inventory-resources.tgz:
|
||||||
resolution: {integrity: sha512-QXv09ktLX1fL3VlWS5ofrZxuL21p9T0IWM0X+hLCpoqmxPA/Bhpi52CtRM/89DsgohhEPPpWNG9byQci8A5vOw==, tarball: file:projects/server-inventory-resources.tgz}
|
resolution: {integrity: sha512-QXv09ktLX1fL3VlWS5ofrZxuL21p9T0IWM0X+hLCpoqmxPA/Bhpi52CtRM/89DsgohhEPPpWNG9byQci8A5vOw==, tarball: file:projects/server-inventory-resources.tgz}
|
||||||
name: '@rush-temp/server-inventory-resources'
|
name: '@rush-temp/server-inventory-resources'
|
||||||
@ -13693,7 +13881,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/server.tgz:
|
file:projects/server.tgz:
|
||||||
resolution: {integrity: sha512-YMw6QleaQlQlzkQhIncun4YVr77XcZSRLy8xzfJiy6X1PaBSve9WY9mGkKiiw119bo2/72HEHEHMnsHQU3VtSQ==, tarball: file:projects/server.tgz}
|
resolution: {integrity: sha512-xJg2GMws1k8PADTrUVUbp6eEynFM+iEVYmsaU5lWpPk2nz4MrDTnirbDITNKPbmKlTdODDWJSaT6zIjhi+GRMg==, tarball: file:projects/server.tgz}
|
||||||
name: '@rush-temp/server'
|
name: '@rush-temp/server'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -14252,7 +14440,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/tool.tgz:
|
file:projects/tool.tgz:
|
||||||
resolution: {integrity: sha512-cLyyAtdkGqG4pxA7QhbNhoNwhIoxpUktmo6OA8kJzcjisF23dXsuuDv097gM6Y0IOdIRGWET8XRaM1sIE/4ogQ==, tarball: file:projects/tool.tgz}
|
resolution: {integrity: sha512-gvdRnHRhzst5gkHEFg9GVc3D04b+BAks8qPdrVxHQSWvWiiUmh3kG+uNWQKklSa9rtRzlSHUrf6NvUvgEg2c5w==, tarball: file:projects/tool.tgz}
|
||||||
name: '@rush-temp/tool'
|
name: '@rush-temp/tool'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -14321,7 +14509,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/tracker-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
file:projects/tracker-resources.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
||||||
resolution: {integrity: sha512-z3TfQ4BzAQK48+svzVwLJMfJP8kF7Skk6XgUYiW6NGYmWTsauxTAO43pbnH0+zrx112vGahLduOnBsYNURRLXQ==, tarball: file:projects/tracker-resources.tgz}
|
resolution: {integrity: sha512-bNqQvwzdPa61s2z+M0xrwW5bSvv46yBY8BXt6cqKEHwp1Zv78P5NHU/ScAgVRuJSvwknhrykBK1mK7zghMr3Hg==, tarball: file:projects/tracker-resources.tgz}
|
||||||
id: file:projects/tracker-resources.tgz
|
id: file:projects/tracker-resources.tgz
|
||||||
name: '@rush-temp/tracker-resources'
|
name: '@rush-temp/tracker-resources'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
@ -14358,7 +14546,7 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/tracker.tgz:
|
file:projects/tracker.tgz:
|
||||||
resolution: {integrity: sha512-fj497PawVB5mdi7yIw96vQs81XXIcJ3SzrQe0UHyb4IqTbFCoN4/HHGnZ6JXrUY/wdPLHfJzUVMlZKZVKcjD6A==, tarball: file:projects/tracker.tgz}
|
resolution: {integrity: sha512-wGhZrDr9Vkg1fm9mUcBfkmQXKQlFpiUUOVIa3WEzoIlCzuAzSs4RiAk5XtVeryvQziu6G0dAzbOka9lV9Fxa+A==, tarball: file:projects/tracker.tgz}
|
||||||
name: '@rush-temp/tracker'
|
name: '@rush-temp/tracker'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -144,6 +144,11 @@
|
|||||||
"@anticrm/text-editor": "~0.6.0",
|
"@anticrm/text-editor": "~0.6.0",
|
||||||
"@anticrm/board": "~0.6.0",
|
"@anticrm/board": "~0.6.0",
|
||||||
"@anticrm/board-assets": "~0.6.0",
|
"@anticrm/board-assets": "~0.6.0",
|
||||||
"@anticrm/board-resources": "~0.6.0"
|
"@anticrm/board-resources": "~0.6.0",
|
||||||
|
"@anticrm/hr": "~0.6.0",
|
||||||
|
"@anticrm/hr-assets": "~0.6.0",
|
||||||
|
"@anticrm/hr-resources": "~0.6.0",
|
||||||
|
"@anticrm/server-hr": "~0.6.0",
|
||||||
|
"@anticrm/server-hr-resources": "~0.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ import { serverTagsId } from '@anticrm/server-tags'
|
|||||||
import { serverCalendarId } from '@anticrm/server-calendar'
|
import { serverCalendarId } from '@anticrm/server-calendar'
|
||||||
import { serverGmailId } from '@anticrm/server-gmail'
|
import { serverGmailId } from '@anticrm/server-gmail'
|
||||||
import { serverTelegramId } from '@anticrm/server-telegram'
|
import { serverTelegramId } from '@anticrm/server-telegram'
|
||||||
|
import { serverHrId } from '@anticrm/server-hr'
|
||||||
|
|
||||||
import { setMetadata } from '@anticrm/platform'
|
import { setMetadata } from '@anticrm/platform'
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ export function configurePlatformDev() {
|
|||||||
addLocation(serverCalendarId, () => import/* webpackChunkName: "server-calendar" */ ('@anticrm/server-calendar-resources'))
|
addLocation(serverCalendarId, () => import/* webpackChunkName: "server-calendar" */ ('@anticrm/server-calendar-resources'))
|
||||||
addLocation(serverGmailId, () => import/* webpackChunkName: "server-gmail" */ ('@anticrm/server-gmail-resources'))
|
addLocation(serverGmailId, () => import/* webpackChunkName: "server-gmail" */ ('@anticrm/server-gmail-resources'))
|
||||||
addLocation(serverTelegramId, () => import/* webpackChunkName: "server-telegram" */ ('@anticrm/server-telegram-resources'))
|
addLocation(serverTelegramId, () => import/* webpackChunkName: "server-telegram" */ ('@anticrm/server-telegram-resources'))
|
||||||
|
addLocation(serverHrId, () => import(/* webpackChunkName: "server-attachment" */ '@anticrm/server-hr-resources'))
|
||||||
// Set devmodel to hook client to be able to present all activity
|
// Set devmodel to hook client to be able to present all activity
|
||||||
enableDevModel()
|
enableDevModel()
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import { tagsId } from '@anticrm/tags'
|
|||||||
import { calendarId } from '@anticrm/calendar'
|
import { calendarId } from '@anticrm/calendar'
|
||||||
import { trackerId } from '@anticrm/tracker'
|
import { trackerId } from '@anticrm/tracker'
|
||||||
import { boardId } from '@anticrm/board'
|
import { boardId } from '@anticrm/board'
|
||||||
|
import { hrId } from '@anticrm/hr'
|
||||||
import rekoni from '@anticrm/rekoni'
|
import rekoni from '@anticrm/rekoni'
|
||||||
|
|
||||||
import '@anticrm/login-assets'
|
import '@anticrm/login-assets'
|
||||||
@ -62,6 +63,7 @@ import '@anticrm/calendar-assets'
|
|||||||
import '@anticrm/tracker-assets'
|
import '@anticrm/tracker-assets'
|
||||||
import '@anticrm/board-assets'
|
import '@anticrm/board-assets'
|
||||||
import '@anticrm/preference-assets'
|
import '@anticrm/preference-assets'
|
||||||
|
import '@anticrm/hr-assets'
|
||||||
import presentation, { presentationId } from '@anticrm/presentation'
|
import presentation, { presentationId } from '@anticrm/presentation'
|
||||||
import { coreId } from '@anticrm/core'
|
import { coreId } from '@anticrm/core'
|
||||||
import { textEditorId } from '@anticrm/text-editor'
|
import { textEditorId } from '@anticrm/text-editor'
|
||||||
@ -115,6 +117,7 @@ export async function configurePlatform() {
|
|||||||
|
|
||||||
addLocation(trackerId, () => import(/* webpackChunkName: "tracker" */ '@anticrm/tracker-resources'))
|
addLocation(trackerId, () => import(/* webpackChunkName: "tracker" */ '@anticrm/tracker-resources'))
|
||||||
addLocation(boardId, () => import(/* webpackChunkName: "board" */ '@anticrm/board-resources'))
|
addLocation(boardId, () => import(/* webpackChunkName: "board" */ '@anticrm/board-resources'))
|
||||||
|
addLocation(hrId, () => import(/* webpackChunkName: "hr" */ '@anticrm/hr-resources'))
|
||||||
|
|
||||||
setMetadata(workbench.metadata.PlatformTitle, 'Platform')
|
setMetadata(workbench.metadata.PlatformTitle, 'Platform')
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,8 @@
|
|||||||
"@anticrm/server-gmail-resources": "~0.6.0",
|
"@anticrm/server-gmail-resources": "~0.6.0",
|
||||||
"@anticrm/server-telegram": "~0.6.0",
|
"@anticrm/server-telegram": "~0.6.0",
|
||||||
"@anticrm/server-telegram-resources": "~0.6.0",
|
"@anticrm/server-telegram-resources": "~0.6.0",
|
||||||
|
"@anticrm/server-hr": "~0.6.0",
|
||||||
|
"@anticrm/server-hr-resources": "~0.6.0",
|
||||||
"@anticrm/rekoni": "~0.6.0",
|
"@anticrm/rekoni": "~0.6.0",
|
||||||
"got": "^11.8.3",
|
"got": "^11.8.3",
|
||||||
"@anticrm/tags": "~0.6.2",
|
"@anticrm/tags": "~0.6.2",
|
||||||
|
@ -70,6 +70,7 @@ import { serverTagsId } from '@anticrm/server-tags'
|
|||||||
import { serverTaskId } from '@anticrm/server-task'
|
import { serverTaskId } from '@anticrm/server-task'
|
||||||
import { serverTrackerId } from '@anticrm/server-tracker'
|
import { serverTrackerId } from '@anticrm/server-tracker'
|
||||||
import { serverTelegramId } from '@anticrm/server-telegram'
|
import { serverTelegramId } from '@anticrm/server-telegram'
|
||||||
|
import { serverHrId } from '@anticrm/server-hr'
|
||||||
import { Client as ElasticClient } from '@elastic/elasticsearch'
|
import { Client as ElasticClient } from '@elastic/elasticsearch'
|
||||||
import { Client } from 'minio'
|
import { Client } from 'minio'
|
||||||
import { Db, MongoClient } from 'mongodb'
|
import { Db, MongoClient } from 'mongodb'
|
||||||
@ -139,6 +140,7 @@ export class ElasticTool {
|
|||||||
addLocation(serverCalendarId, () => import('@anticrm/server-calendar-resources'))
|
addLocation(serverCalendarId, () => import('@anticrm/server-calendar-resources'))
|
||||||
addLocation(serverGmailId, () => import('@anticrm/server-gmail-resources'))
|
addLocation(serverGmailId, () => import('@anticrm/server-gmail-resources'))
|
||||||
addLocation(serverTelegramId, () => import('@anticrm/server-telegram-resources'))
|
addLocation(serverTelegramId, () => import('@anticrm/server-telegram-resources'))
|
||||||
|
addLocation(serverHrId, () => import('@anticrm/server-hr-resources'))
|
||||||
this.mongoClient = new MongoClient(mongoUrl)
|
this.mongoClient = new MongoClient(mongoUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,8 @@
|
|||||||
"@anticrm/model-server-telegram": "~0.6.0",
|
"@anticrm/model-server-telegram": "~0.6.0",
|
||||||
"@anticrm/model-tracker": "~0.6.0",
|
"@anticrm/model-tracker": "~0.6.0",
|
||||||
"@anticrm/model-board": "~0.6.0",
|
"@anticrm/model-board": "~0.6.0",
|
||||||
"@anticrm/model-preference": "~0.6.0"
|
"@anticrm/model-preference": "~0.6.0",
|
||||||
|
"@anticrm/model-hr": "~0.6.0",
|
||||||
|
"@anticrm/model-server-hr": "~0.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,8 @@ import { createModel as serverTelegramModel } from '@anticrm/model-server-telegr
|
|||||||
import { createModel as trackerModel } from '@anticrm/model-tracker'
|
import { createModel as trackerModel } from '@anticrm/model-tracker'
|
||||||
import { createModel as boardModel } from '@anticrm/model-board'
|
import { createModel as boardModel } from '@anticrm/model-board'
|
||||||
import { createModel as preferenceModel } from '@anticrm/model-preference'
|
import { createModel as preferenceModel } from '@anticrm/model-preference'
|
||||||
|
import { createModel as hrModel } from '@anticrm/model-hr'
|
||||||
|
import { createModel as serverHrModel } from '@anticrm/model-server-hr'
|
||||||
|
|
||||||
export const version: Data<Version> = jsonVersion as Data<Version>
|
export const version: Data<Version> = jsonVersion as Data<Version>
|
||||||
|
|
||||||
@ -82,6 +84,7 @@ const builders: [(b: Builder) => void, string][] = [
|
|||||||
[textEditorModel, 'text-editor'],
|
[textEditorModel, 'text-editor'],
|
||||||
[notificationModel, 'notification'],
|
[notificationModel, 'notification'],
|
||||||
[preferenceModel, 'preference'],
|
[preferenceModel, 'preference'],
|
||||||
|
[hrModel, 'hr'],
|
||||||
|
|
||||||
[serverCoreModel, 'server-core'],
|
[serverCoreModel, 'server-core'],
|
||||||
[serverAttachmentModel, 'server-attachment'],
|
[serverAttachmentModel, 'server-attachment'],
|
||||||
@ -99,6 +102,7 @@ const builders: [(b: Builder) => void, string][] = [
|
|||||||
[serverCalendarModel, 'server-calendar'],
|
[serverCalendarModel, 'server-calendar'],
|
||||||
[serverGmailModel, 'server-gmail'],
|
[serverGmailModel, 'server-gmail'],
|
||||||
[serverTelegramModel, 'server-telegram'],
|
[serverTelegramModel, 'server-telegram'],
|
||||||
|
[serverHrModel, 'server-hr'],
|
||||||
[trackerModel, 'tracker'],
|
[trackerModel, 'tracker'],
|
||||||
[boardModel, 'board'],
|
[boardModel, 'board'],
|
||||||
[calendarModel, 'calendar']
|
[calendarModel, 'calendar']
|
||||||
|
@ -32,6 +32,7 @@ import { viewOperation } from '@anticrm/model-view'
|
|||||||
import { trackerOperation } from '@anticrm/model-tracker'
|
import { trackerOperation } from '@anticrm/model-tracker'
|
||||||
import { boardOperation } from '@anticrm/model-board'
|
import { boardOperation } from '@anticrm/model-board'
|
||||||
import { demoOperation } from '@anticrm/model-demo'
|
import { demoOperation } from '@anticrm/model-demo'
|
||||||
|
import { hrOperation } from '@anticrm/model-hr'
|
||||||
|
|
||||||
export const migrateOperations: MigrateOperation[] = [
|
export const migrateOperations: MigrateOperation[] = [
|
||||||
coreOperation,
|
coreOperation,
|
||||||
@ -50,5 +51,6 @@ export const migrateOperations: MigrateOperation[] = [
|
|||||||
notificationOperation,
|
notificationOperation,
|
||||||
settingOperation,
|
settingOperation,
|
||||||
trackerOperation,
|
trackerOperation,
|
||||||
boardOperation
|
boardOperation,
|
||||||
|
hrOperation
|
||||||
]
|
]
|
||||||
|
7
models/hr/.eslintrc.js
Normal file
7
models/hr/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/model-rig/profiles/default/config/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
4
models/hr/.npmignore
Normal file
4
models/hr/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!/lib/**
|
||||||
|
!CHANGELOG.md
|
||||||
|
/lib/**/__tests__/
|
18
models/hr/config/rig.json
Normal file
18
models/hr/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||||
|
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Required) The name of the rig package to inherit from.
|
||||||
|
* It should be an NPM package name with the "-rig" suffix.
|
||||||
|
*/
|
||||||
|
"rigPackageName": "@anticrm/model-rig"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Optional) Selects a config profile from the rig package. The name must consist of
|
||||||
|
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
|
||||||
|
* If omitted, then the "default" profile will be used."
|
||||||
|
*/
|
||||||
|
// "rigProfile": "your-profile-name"
|
||||||
|
}
|
41
models/hr/package.json
Normal file
41
models/hr/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/model-hr",
|
||||||
|
"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.21.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.45.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/core": "~0.6.16",
|
||||||
|
"@anticrm/model": "~0.6.0",
|
||||||
|
"@anticrm/ui": "~0.6.0",
|
||||||
|
"@anticrm/contact": "~0.6.5",
|
||||||
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"@anticrm/model-core": "~0.6.0",
|
||||||
|
"@anticrm/model-view": "~0.6.0",
|
||||||
|
"@anticrm/model-workbench": "~0.6.1",
|
||||||
|
"@anticrm/model-contact": "~0.6.1",
|
||||||
|
"@anticrm/hr": "~0.6.0",
|
||||||
|
"@anticrm/hr-resources": "~0.6.0",
|
||||||
|
"@anticrm/view": "~0.6.0"
|
||||||
|
}
|
||||||
|
}
|
137
models/hr/src/index.ts
Normal file
137
models/hr/src/index.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
//
|
||||||
|
// 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 contact, { TEmployee } from '@anticrm/model-contact'
|
||||||
|
import { IndexKind, Ref } from '@anticrm/core'
|
||||||
|
import type { Department, Staff } from '@anticrm/hr'
|
||||||
|
import { Builder, Index, Mixin, Model, Prop, TypeRef, TypeString, UX } from '@anticrm/model'
|
||||||
|
import core, { TSpace } from '@anticrm/model-core'
|
||||||
|
import workbench from '@anticrm/model-workbench'
|
||||||
|
import hr from './plugin'
|
||||||
|
import view, { createAction } from '@anticrm/model-view'
|
||||||
|
|
||||||
|
@Model(hr.class.Department, core.class.Space)
|
||||||
|
@UX(hr.string.Department, hr.icon.Department)
|
||||||
|
export class TDepartment extends TSpace implements Department {
|
||||||
|
@Prop(TypeRef(hr.class.Department), hr.string.ParentDepartmentLabel)
|
||||||
|
declare space: Ref<Department>
|
||||||
|
|
||||||
|
@Prop(TypeString(), core.string.Name)
|
||||||
|
@Index(IndexKind.FullText)
|
||||||
|
name!: string
|
||||||
|
|
||||||
|
avatar?: string | null
|
||||||
|
|
||||||
|
@Prop(TypeRef(contact.class.Employee), hr.string.TeamLead)
|
||||||
|
teamLead!: Ref<Employee> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mixin(hr.mixin.Staff, contact.class.Employee)
|
||||||
|
@UX(contact.string.Employee, hr.icon.HR)
|
||||||
|
export class TStaff extends TEmployee implements Staff {
|
||||||
|
@Prop(TypeRef(hr.class.Department), hr.string.Department)
|
||||||
|
department!: Ref<Department>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createModel (builder: Builder): void {
|
||||||
|
builder.createModel(TDepartment, TStaff)
|
||||||
|
|
||||||
|
builder.createDoc(
|
||||||
|
workbench.class.Application,
|
||||||
|
core.space.Model,
|
||||||
|
{
|
||||||
|
label: hr.string.HRApplication,
|
||||||
|
icon: hr.icon.HR,
|
||||||
|
hidden: false,
|
||||||
|
navigatorModel: {
|
||||||
|
specials: [
|
||||||
|
{
|
||||||
|
id: 'structure',
|
||||||
|
component: hr.component.Structure,
|
||||||
|
icon: hr.icon.Structure,
|
||||||
|
label: hr.string.Structure,
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
spaces: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hr.app.HR
|
||||||
|
)
|
||||||
|
|
||||||
|
builder.mixin(hr.class.Department, core.class.Class, view.mixin.AttributeEditor, {
|
||||||
|
inlineEditor: hr.component.DepartmentEditor
|
||||||
|
})
|
||||||
|
|
||||||
|
createAction(
|
||||||
|
builder,
|
||||||
|
{
|
||||||
|
action: view.actionImpl.ShowPanel,
|
||||||
|
actionProps: {
|
||||||
|
component: hr.component.EditDepartment
|
||||||
|
},
|
||||||
|
label: view.string.Open,
|
||||||
|
icon: view.icon.Open,
|
||||||
|
keyBinding: ['e'],
|
||||||
|
input: 'any',
|
||||||
|
category: hr.category.HR,
|
||||||
|
target: hr.class.Department,
|
||||||
|
context: { mode: 'context', application: hr.app.HR, group: 'top' }
|
||||||
|
},
|
||||||
|
hr.action.EditDepartment
|
||||||
|
)
|
||||||
|
|
||||||
|
createAction(
|
||||||
|
builder,
|
||||||
|
{
|
||||||
|
action: view.actionImpl.ShowPopup,
|
||||||
|
actionProps: {
|
||||||
|
component: hr.component.DepartmentStaff,
|
||||||
|
element: 'float'
|
||||||
|
},
|
||||||
|
label: hr.string.ShowEmployees,
|
||||||
|
icon: contact.icon.Person,
|
||||||
|
keyBinding: ['m'],
|
||||||
|
input: 'any',
|
||||||
|
category: hr.category.HR,
|
||||||
|
target: hr.class.Department,
|
||||||
|
context: { mode: 'context', application: hr.app.HR, group: 'top' }
|
||||||
|
},
|
||||||
|
hr.action.ShowEmployees
|
||||||
|
)
|
||||||
|
|
||||||
|
createAction(
|
||||||
|
builder,
|
||||||
|
{
|
||||||
|
action: view.actionImpl.Delete,
|
||||||
|
label: view.string.Delete,
|
||||||
|
icon: view.icon.Delete,
|
||||||
|
input: 'any',
|
||||||
|
category: hr.category.HR,
|
||||||
|
keyBinding: ['Meta + Backspace', 'Ctrl + Backspace'],
|
||||||
|
query: {
|
||||||
|
'members.length': 0,
|
||||||
|
_id: { $nin: [hr.ids.Head] }
|
||||||
|
},
|
||||||
|
target: hr.class.Department,
|
||||||
|
context: { mode: 'context', application: hr.app.HR, group: 'top' }
|
||||||
|
},
|
||||||
|
hr.action.DeleteDepartment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { hrOperation } from './migration'
|
||||||
|
export { default } from './plugin'
|
48
models/hr/src/migration.ts
Normal file
48
models/hr/src/migration.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// 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 { TxOperations } from '@anticrm/core'
|
||||||
|
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model'
|
||||||
|
import core from '@anticrm/model-core'
|
||||||
|
import hr from './index'
|
||||||
|
|
||||||
|
async function createSpace (tx: TxOperations): Promise<void> {
|
||||||
|
const current = await tx.findOne(core.class.Space, {
|
||||||
|
_id: hr.ids.Head
|
||||||
|
})
|
||||||
|
if (current === undefined) {
|
||||||
|
await tx.createDoc(
|
||||||
|
hr.class.Department,
|
||||||
|
core.space.Space,
|
||||||
|
{
|
||||||
|
name: 'Organization',
|
||||||
|
description: '',
|
||||||
|
private: false,
|
||||||
|
archived: false,
|
||||||
|
members: [],
|
||||||
|
teamLead: null
|
||||||
|
},
|
||||||
|
hr.ids.Head
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hrOperation: MigrateOperation = {
|
||||||
|
async migrate (client: MigrationClient): Promise<void> {},
|
||||||
|
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||||
|
const tx = new TxOperations(client, core.account.System)
|
||||||
|
await createSpace(tx)
|
||||||
|
}
|
||||||
|
}
|
43
models/hr/src/plugin.ts
Normal file
43
models/hr/src/plugin.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// 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 { Ref } from '@anticrm/core'
|
||||||
|
import { hrId } from '@anticrm/hr'
|
||||||
|
import hr from '@anticrm/hr-resources/src/plugin'
|
||||||
|
import { IntlString, mergeIds } from '@anticrm/platform'
|
||||||
|
import { AnyComponent } from '@anticrm/ui'
|
||||||
|
import { Action, ActionCategory } from '@anticrm/view'
|
||||||
|
|
||||||
|
export default mergeIds(hrId, hr, {
|
||||||
|
string: {
|
||||||
|
HRApplication: '' as IntlString,
|
||||||
|
Departments: '' as IntlString,
|
||||||
|
ShowEmployees: '' as IntlString
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
Structure: '' as AnyComponent,
|
||||||
|
EditDepartment: '' as AnyComponent,
|
||||||
|
DepartmentStaff: '' as AnyComponent,
|
||||||
|
DepartmentEditor: '' as AnyComponent
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
HR: '' as Ref<ActionCategory>
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
EditDepartment: '' as Ref<Action>,
|
||||||
|
ShowEmployees: '' as Ref<Action>,
|
||||||
|
DeleteDepartment: '' as Ref<Action>
|
||||||
|
}
|
||||||
|
})
|
8
models/hr/tsconfig.json
Normal file
8
models/hr/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@anticrm/model-rig/profiles/default/tsconfig.json",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./lib",
|
||||||
|
}
|
||||||
|
}
|
7
models/server-hr/.eslintrc.js
Normal file
7
models/server-hr/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/model-rig/profiles/default/config/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
4
models/server-hr/.npmignore
Normal file
4
models/server-hr/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!/lib/**
|
||||||
|
!CHANGELOG.md
|
||||||
|
/lib/**/__tests__/
|
18
models/server-hr/config/rig.json
Normal file
18
models/server-hr/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||||
|
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Required) The name of the rig package to inherit from.
|
||||||
|
* It should be an NPM package name with the "-rig" suffix.
|
||||||
|
*/
|
||||||
|
"rigPackageName": "@anticrm/model-rig"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Optional) Selects a config profile from the rig package. The name must consist of
|
||||||
|
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
|
||||||
|
* If omitted, then the "default" profile will be used."
|
||||||
|
*/
|
||||||
|
// "rigProfile": "your-profile-name"
|
||||||
|
}
|
34
models/server-hr/package.json
Normal file
34
models/server-hr/package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/model-server-hr",
|
||||||
|
"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.21.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.45.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/core": "~0.6.16",
|
||||||
|
"@anticrm/model": "~0.6.0",
|
||||||
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"@anticrm/server-hr": "~0.6.0",
|
||||||
|
"@anticrm/server-core": "~0.6.1"
|
||||||
|
}
|
||||||
|
}
|
26
models/server-hr/src/index.ts
Normal file
26
models/server-hr/src/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { Builder } from '@anticrm/model'
|
||||||
|
|
||||||
|
import serverCore from '@anticrm/server-core'
|
||||||
|
import core from '@anticrm/core'
|
||||||
|
import serverHr from '@anticrm/server-hr'
|
||||||
|
|
||||||
|
export function createModel (builder: Builder): void {
|
||||||
|
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||||
|
trigger: serverHr.trigger.OnDepartmentStaff
|
||||||
|
})
|
||||||
|
}
|
8
models/server-hr/tsconfig.json
Normal file
8
models/server-hr/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@anticrm/model-rig/profiles/default/tsconfig.json",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./lib",
|
||||||
|
}
|
||||||
|
}
|
@ -14,11 +14,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { PlatformError, Severity, Status } from '@anticrm/platform'
|
import { PlatformError, Severity, Status } from '@anticrm/platform'
|
||||||
import { Lookup, ReverseLookups } from '.'
|
import { getObjectValue, Lookup, ReverseLookups } from '.'
|
||||||
import type { Class, Doc, Ref } from './classes'
|
import type { Class, Doc, Ref } from './classes'
|
||||||
import core from './component'
|
import core from './component'
|
||||||
import { Hierarchy } from './hierarchy'
|
import { Hierarchy } from './hierarchy'
|
||||||
import { matchQuery, resultSort } from './query'
|
import { matchQuery, resultSort, checkMixinKey } from './query'
|
||||||
import type { DocumentQuery, FindOptions, FindResult, LookupData, Storage, TxResult, WithLookup } from './storage'
|
import type { DocumentQuery, FindOptions, FindResult, LookupData, Storage, TxResult, WithLookup } from './storage'
|
||||||
import type { Tx, TxCreateDoc, TxMixin, TxPutBag, TxRemoveDoc, TxUpdateDoc } from './tx'
|
import type { Tx, TxCreateDoc, TxMixin, TxPutBag, TxRemoveDoc, TxUpdateDoc } from './tx'
|
||||||
import { TxProcessor } from './tx'
|
import { TxProcessor } from './tx'
|
||||||
@ -77,25 +77,31 @@ export abstract class MemDb extends TxProcessor {
|
|||||||
return doc as T
|
return doc as T
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getLookupValue<T extends Doc>(doc: T, lookup: Lookup<T>, result: LookupData<T>): Promise<void> {
|
private async getLookupValue<T extends Doc>(
|
||||||
|
_class: Ref<Class<T>>,
|
||||||
|
doc: T,
|
||||||
|
lookup: Lookup<T>,
|
||||||
|
result: LookupData<T>
|
||||||
|
): Promise<void> {
|
||||||
for (const key in lookup) {
|
for (const key in lookup) {
|
||||||
if (key === '_id') {
|
if (key === '_id') {
|
||||||
await this.getReverseLookupValue(doc, lookup, result)
|
await this.getReverseLookupValue(doc, lookup, result)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const value = (lookup as any)[key]
|
const value = (lookup as any)[key]
|
||||||
|
const tkey = checkMixinKey(key, _class, this.hierarchy)
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
const [_class, nested] = value
|
const [_class, nested] = value
|
||||||
const objects = await this.findAll(_class, { _id: (doc as any)[key] })
|
const objects = await this.findAll(_class, { _id: getObjectValue(tkey, doc) })
|
||||||
;(result as any)[key] = objects[0]
|
;(result as any)[key] = objects[0]
|
||||||
const nestedResult = {}
|
const nestedResult = {}
|
||||||
const parent = (result as any)[key]
|
const parent = (result as any)[key]
|
||||||
await this.getLookupValue(parent, nested, nestedResult)
|
await this.getLookupValue(_class, parent, nested, nestedResult)
|
||||||
Object.assign(parent, {
|
Object.assign(parent, {
|
||||||
$lookup: nestedResult
|
$lookup: nestedResult
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const objects = await this.findAll(value, { _id: (doc as any)[key] })
|
const objects = await this.findAll(value, { _id: getObjectValue(tkey, doc) })
|
||||||
;(result as any)[key] = objects[0]
|
;(result as any)[key] = objects[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,11 +124,11 @@ export abstract class MemDb extends TxProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async lookup<T extends Doc>(docs: T[], lookup: Lookup<T>): Promise<WithLookup<T>[]> {
|
private async lookup<T extends Doc>(_class: Ref<Class<T>>, docs: T[], lookup: Lookup<T>): Promise<WithLookup<T>[]> {
|
||||||
const withLookup: WithLookup<T>[] = []
|
const withLookup: WithLookup<T>[] = []
|
||||||
for (const doc of docs) {
|
for (const doc of docs) {
|
||||||
const result: LookupData<T> = {}
|
const result: LookupData<T> = {}
|
||||||
await this.getLookupValue(doc, lookup, result)
|
await this.getLookupValue(_class, doc, lookup, result)
|
||||||
withLookup.push(Object.assign({}, doc, { $lookup: result }))
|
withLookup.push(Object.assign({}, doc, { $lookup: result }))
|
||||||
}
|
}
|
||||||
return withLookup
|
return withLookup
|
||||||
@ -152,7 +158,7 @@ export abstract class MemDb extends TxProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options?.lookup !== undefined) {
|
if (options?.lookup !== undefined) {
|
||||||
result = await this.lookup(result as T[], options.lookup)
|
result = await this.lookup(_class, result as T[], options.lookup)
|
||||||
result = matchQuery(result, query, _class, this.hierarchy)
|
result = matchQuery(result, query, _class, this.hierarchy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,9 @@ function $push (document: Doc, keyval: Record<string, PropertyType>): void {
|
|||||||
function $pull (document: Doc, keyval: Record<string, PropertyType>): void {
|
function $pull (document: Doc, keyval: Record<string, PropertyType>): void {
|
||||||
const doc = document as any
|
const doc = document as any
|
||||||
for (const key in keyval) {
|
for (const key in keyval) {
|
||||||
|
if (doc[key] === undefined) {
|
||||||
|
doc[key] = []
|
||||||
|
}
|
||||||
const arr = doc[key] as Array<any>
|
const arr = doc[key] as Array<any>
|
||||||
if (typeof keyval[key] === 'object') {
|
if (typeof keyval[key] === 'object') {
|
||||||
const { $in } = keyval[key] as PullArray<PropertyType>
|
const { $in } = keyval[key] as PullArray<PropertyType>
|
||||||
@ -55,6 +58,9 @@ function $pull (document: Doc, keyval: Record<string, PropertyType>): void {
|
|||||||
function $move (document: Doc, keyval: Record<string, PropertyType>): void {
|
function $move (document: Doc, keyval: Record<string, PropertyType>): void {
|
||||||
const doc = document as any
|
const doc = document as any
|
||||||
for (const key in keyval) {
|
for (const key in keyval) {
|
||||||
|
if (doc[key] === undefined) {
|
||||||
|
doc[key] = []
|
||||||
|
}
|
||||||
const arr = doc[key] as Array<any>
|
const arr = doc[key] as Array<any>
|
||||||
const desc = keyval[key]
|
const desc = keyval[key]
|
||||||
doc[key] = arr.filter((val) => val !== desc.$value)
|
doc[key] = arr.filter((val) => val !== desc.$value)
|
||||||
|
@ -14,15 +14,17 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { IconSize, showPopup } from '@anticrm/ui'
|
import { AnySvelteComponent, IconSize, showPopup } from '@anticrm/ui'
|
||||||
|
|
||||||
import Avatar from './Avatar.svelte'
|
import Avatar from './Avatar.svelte'
|
||||||
import EditAvatarPopup from './EditAvatarPopup.svelte'
|
import EditAvatarPopup from './EditAvatarPopup.svelte'
|
||||||
import { getFileUrl } from '../utils'
|
import { getFileUrl } from '../utils'
|
||||||
|
import { Asset } from '@anticrm/platform'
|
||||||
|
|
||||||
export let avatar: string | null | undefined = undefined
|
export let avatar: string | null | undefined = undefined
|
||||||
export let size: IconSize
|
export let size: IconSize
|
||||||
export let direct: Blob | undefined = undefined
|
export let direct: Blob | undefined = undefined
|
||||||
|
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
@ -75,6 +77,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="cursor-pointer" on:click={onClick}>
|
<div class="cursor-pointer" on:click={onClick}>
|
||||||
<Avatar {avatar} {direct} {size} />
|
<Avatar {avatar} {direct} {size} {icon} />
|
||||||
<input style="display: none;" type="file" bind:this={inputRef} on:change={onSelect} accept={targetMimes.join(',')} />
|
<input style="display: none;" type="file" bind:this={inputRef} on:change={onSelect} accept={targetMimes.join(',')} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,11 +25,14 @@
|
|||||||
getFocusManager,
|
getFocusManager,
|
||||||
AnyComponent,
|
AnyComponent,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipAlignment
|
TooltipAlignment,
|
||||||
|
ButtonKind,
|
||||||
|
ButtonSize
|
||||||
} from '@anticrm/ui'
|
} from '@anticrm/ui'
|
||||||
import SpacesPopup from './SpacesPopup.svelte'
|
import SpacesPopup from './SpacesPopup.svelte'
|
||||||
|
|
||||||
import type { Ref, Class, Space, DocumentQuery } from '@anticrm/core'
|
import type { Ref, Class, Space, DocumentQuery } from '@anticrm/core'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
|
||||||
export let _class: Ref<Class<Space>>
|
export let _class: Ref<Class<Space>>
|
||||||
export let spaceQuery: DocumentQuery<Space> | undefined = { archived: false }
|
export let spaceQuery: DocumentQuery<Space> | undefined = { archived: false }
|
||||||
@ -44,10 +47,15 @@
|
|||||||
}
|
}
|
||||||
| undefined = undefined
|
| undefined = undefined
|
||||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||||
|
export let kind: ButtonKind = 'no-border'
|
||||||
|
export let size: ButtonSize = 'small'
|
||||||
|
export let justify: 'left' | 'center' = 'center'
|
||||||
|
export let width: string | undefined = undefined
|
||||||
|
|
||||||
let selected: Space | undefined
|
let selected: Space | undefined
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const mgr = getFocusManager()
|
const mgr = getFocusManager()
|
||||||
async function updateSelected (value: Ref<Space> | undefined) {
|
async function updateSelected (value: Ref<Space> | undefined) {
|
||||||
@ -71,6 +79,7 @@
|
|||||||
(result) => {
|
(result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
value = result._id
|
value = result._id
|
||||||
|
dispatch('change', value)
|
||||||
mgr?.setFocusPos(focusIndex)
|
mgr?.setFocusPos(focusIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,7 +88,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Tooltip {label} fill={false} direction={labelDirection}>
|
<Tooltip {label} fill={false} direction={labelDirection}>
|
||||||
<Button {focus} {focusIndex} icon={IconFolder} size={'small'} kind={'no-border'} on:click={showSpacesPopup}>
|
<Button {focus} {focusIndex} icon={IconFolder} {size} {kind} {justify} {width} on:click={showSpacesPopup}>
|
||||||
<span slot="content" class="overflow-label disabled text-sm">
|
<span slot="content" class="overflow-label disabled text-sm">
|
||||||
{#if selected}{selected.name}{:else}<Label {label} />{/if}
|
{#if selected}{selected.name}{:else}<Label {label} />{/if}
|
||||||
</span>
|
</span>
|
||||||
|
@ -15,13 +15,17 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Class, DocumentQuery, Ref, Space } from '@anticrm/core'
|
import type { Class, DocumentQuery, Ref, Space } from '@anticrm/core'
|
||||||
import type { IntlString } from '@anticrm/platform'
|
import type { IntlString } from '@anticrm/platform'
|
||||||
import { AnyComponent } from '@anticrm/ui'
|
import { AnyComponent, ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||||
import SpaceSelect from './SpaceSelect.svelte'
|
import SpaceSelect from './SpaceSelect.svelte'
|
||||||
|
|
||||||
export let space: Ref<Space> | undefined = undefined
|
export let space: Ref<Space> | undefined = undefined
|
||||||
export let _class: Ref<Class<Space>>
|
export let _class: Ref<Class<Space>>
|
||||||
export let query: DocumentQuery<Space> = { archived: false }
|
export let query: DocumentQuery<Space> = { archived: false }
|
||||||
export let label: IntlString
|
export let label: IntlString
|
||||||
|
export let kind: ButtonKind = 'no-border'
|
||||||
|
export let size: ButtonSize = 'small'
|
||||||
|
export let justify: 'left' | 'center' = 'center'
|
||||||
|
export let width: string | undefined = undefined
|
||||||
|
|
||||||
export let create:
|
export let create:
|
||||||
| {
|
| {
|
||||||
@ -31,4 +35,17 @@
|
|||||||
| undefined = undefined
|
| undefined = undefined
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SpaceSelect {create} focus focusIndex={-10} {_class} spaceQuery={query} {label} bind:value={space} />
|
<SpaceSelect
|
||||||
|
{create}
|
||||||
|
focus
|
||||||
|
focusIndex={-10}
|
||||||
|
{_class}
|
||||||
|
spaceQuery={query}
|
||||||
|
{label}
|
||||||
|
{size}
|
||||||
|
{kind}
|
||||||
|
{justify}
|
||||||
|
{width}
|
||||||
|
bind:value={space}
|
||||||
|
on:change
|
||||||
|
/>
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import core, {
|
import core, {
|
||||||
AttachedDoc,
|
AttachedDoc,
|
||||||
|
checkMixinKey,
|
||||||
Class,
|
Class,
|
||||||
Client,
|
Client,
|
||||||
Doc,
|
Doc,
|
||||||
@ -26,11 +27,13 @@ import core, {
|
|||||||
Hierarchy,
|
Hierarchy,
|
||||||
Lookup,
|
Lookup,
|
||||||
LookupData,
|
LookupData,
|
||||||
|
matchQuery,
|
||||||
ModelDb,
|
ModelDb,
|
||||||
Ref,
|
Ref,
|
||||||
resultSort,
|
resultSort,
|
||||||
ReverseLookups,
|
ReverseLookups,
|
||||||
SortingQuery,
|
SortingQuery,
|
||||||
|
toFindResult,
|
||||||
Tx,
|
Tx,
|
||||||
TxBulkWrite,
|
TxBulkWrite,
|
||||||
TxCollectionCUD,
|
TxCollectionCUD,
|
||||||
@ -41,10 +44,7 @@ import core, {
|
|||||||
TxRemoveDoc,
|
TxRemoveDoc,
|
||||||
TxResult,
|
TxResult,
|
||||||
TxUpdateDoc,
|
TxUpdateDoc,
|
||||||
WithLookup,
|
WithLookup
|
||||||
toFindResult,
|
|
||||||
checkMixinKey,
|
|
||||||
matchQuery
|
|
||||||
} from '@anticrm/core'
|
} from '@anticrm/core'
|
||||||
import { deepEqual } from 'fast-equals'
|
import { deepEqual } from 'fast-equals'
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.queries.set(_class, queries)
|
this.queries.set(_class, queries)
|
||||||
if (this.queue.length > CACHE_SIZE) {
|
while (this.queue.length > CACHE_SIZE) {
|
||||||
this.remove()
|
this.remove()
|
||||||
}
|
}
|
||||||
return q
|
return q
|
||||||
@ -271,6 +271,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
if (updatedDoc !== undefined) {
|
if (updatedDoc !== undefined) {
|
||||||
// Create or apply mixin value
|
// Create or apply mixin value
|
||||||
updatedDoc = TxProcessor.updateMixin4Doc(updatedDoc, tx)
|
updatedDoc = TxProcessor.updateMixin4Doc(updatedDoc, tx)
|
||||||
|
await this.__updateLookup(q, updatedDoc, tx.attributes)
|
||||||
await this.updatedDocCallback(updatedDoc, q)
|
await this.updatedDocCallback(updatedDoc, q)
|
||||||
} else if (isMixin) {
|
} else if (isMixin) {
|
||||||
// Mixin potentially added to object we doesn't have in out results
|
// Mixin potentially added to object we doesn't have in out results
|
||||||
@ -477,25 +478,31 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getLookupValue<T extends Doc>(doc: T, lookup: Lookup<T>, result: LookupData<T>): Promise<void> {
|
private async getLookupValue<T extends Doc>(
|
||||||
|
_class: Ref<Class<T>>,
|
||||||
|
doc: T,
|
||||||
|
lookup: Lookup<T>,
|
||||||
|
result: LookupData<T>
|
||||||
|
): Promise<void> {
|
||||||
for (const key in lookup) {
|
for (const key in lookup) {
|
||||||
if (key === '_id') {
|
if (key === '_id') {
|
||||||
await this.getReverseLookupValue(doc, lookup, result)
|
await this.getReverseLookupValue(doc, lookup, result)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const value = (lookup as any)[key]
|
const value = (lookup as any)[key]
|
||||||
|
const tkey = checkMixinKey(key, _class, this.client.getHierarchy())
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
const [_class, nested] = value
|
const [_class, nested] = value
|
||||||
const objects = await this.findAll(_class, { _id: (doc as any)[key] })
|
const objects = await this.findAll(_class, { _id: getObjectValue(tkey, doc) })
|
||||||
;(result as any)[key] = objects[0]
|
;(result as any)[key] = objects[0]
|
||||||
const nestedResult = {}
|
const nestedResult = {}
|
||||||
const parent = (result as any)[key]
|
const parent = (result as any)[key]
|
||||||
await this.getLookupValue(parent, nested, nestedResult)
|
await this.getLookupValue(_class, parent, nested, nestedResult)
|
||||||
Object.assign(parent, {
|
Object.assign(parent, {
|
||||||
$lookup: nestedResult
|
$lookup: nestedResult
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const objects = await this.findAll(value, { _id: (doc as any)[key] })
|
const objects = await this.findAll(value, { _id: getObjectValue(tkey, doc) })
|
||||||
;(result as any)[key] = objects[0]
|
;(result as any)[key] = objects[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -523,9 +530,9 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async lookup<T extends Doc>(doc: T, lookup: Lookup<T>): Promise<void> {
|
private async lookup<T extends Doc>(_class: Ref<Class<T>>, doc: T, lookup: Lookup<T>): Promise<void> {
|
||||||
const result: LookupData<Doc> = {}
|
const result: LookupData<Doc> = {}
|
||||||
await this.getLookupValue(doc, lookup, result)
|
await this.getLookupValue(_class, doc, lookup, result)
|
||||||
;(doc as WithLookup<Doc>).$lookup = result
|
;(doc as WithLookup<Doc>).$lookup = result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,7 +554,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (q.options?.lookup !== undefined) {
|
if (q.options?.lookup !== undefined) {
|
||||||
await this.lookup(doc, q.options.lookup)
|
await this.lookup(q._class, doc, q.options.lookup)
|
||||||
}
|
}
|
||||||
// We could already have document inside results, if query is created during processing of document create transaction and not yet handled on client.
|
// We could already have document inside results, if query is created during processing of document create transaction and not yet handled on client.
|
||||||
const pos = q.result.findIndex((p) => p._id === doc._id)
|
const pos = q.result.findIndex((p) => p._id === doc._id)
|
||||||
@ -751,14 +758,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
return await super.tx(tx)
|
return await super.tx(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async __updateDoc (q: Query, updatedDoc: WithLookup<Doc>, tx: TxUpdateDoc<Doc>): Promise<void> {
|
private async __updateLookup (q: Query, updatedDoc: WithLookup<Doc>, ops: any): Promise<void> {
|
||||||
TxProcessor.updateDoc2Doc(updatedDoc, tx)
|
|
||||||
|
|
||||||
const ops = {
|
|
||||||
...tx.operations,
|
|
||||||
modifiedBy: tx.modifiedBy,
|
|
||||||
modifiedOn: tx.modifiedOn
|
|
||||||
} as any
|
|
||||||
for (const key in ops) {
|
for (const key in ops) {
|
||||||
if (!key.startsWith('$')) {
|
if (!key.startsWith('$')) {
|
||||||
if (q.options !== undefined) {
|
if (q.options !== undefined) {
|
||||||
@ -783,7 +783,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (key === '$push') {
|
if (key === '$push') {
|
||||||
const pops = tx.operations[key] ?? {}
|
const pops = ops[key] ?? {}
|
||||||
for (const pkey of Object.keys(pops)) {
|
for (const pkey of Object.keys(pops)) {
|
||||||
if (q.options !== undefined) {
|
if (q.options !== undefined) {
|
||||||
const lookup = (q.options.lookup as any)?.[pkey]
|
const lookup = (q.options.lookup as any)?.[pkey]
|
||||||
@ -794,28 +794,26 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
if (pp[pkey] === undefined) {
|
if (pp[pkey] === undefined) {
|
||||||
pp[pkey] = []
|
pp[pkey] = []
|
||||||
}
|
}
|
||||||
if (Array.isArray((pops as any)[pkey])) {
|
if (Array.isArray(pops[pkey])) {
|
||||||
const pushData = await this.client.findAll(
|
const pushData = await this.client.findAll(
|
||||||
lookupClass,
|
lookupClass,
|
||||||
{ _id: { $in: (pops as any)[pkey] } },
|
{ _id: { $in: pops[pkey] } },
|
||||||
{ lookup: nestedLookup }
|
{ lookup: nestedLookup }
|
||||||
)
|
)
|
||||||
pp[pkey].push(...pushData)
|
pp[pkey].push(...pushData)
|
||||||
} else {
|
} else {
|
||||||
pp[pkey].push(
|
pp[pkey].push(await this.client.findOne(lookupClass, { _id: pops[pkey] }, { lookup: nestedLookup }))
|
||||||
await this.client.findOne(lookupClass, { _id: (pops as any)[pkey] }, { lookup: nestedLookup })
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key === '$pull') {
|
} else if (key === '$pull') {
|
||||||
const pops = tx.operations[key] ?? {}
|
const pops = ops[key] ?? {}
|
||||||
for (const pkey of Object.keys(pops)) {
|
for (const pkey of Object.keys(pops)) {
|
||||||
if (q.options !== undefined) {
|
if (q.options !== undefined) {
|
||||||
const lookup = (q.options.lookup as any)?.[pkey]
|
const lookup = (q.options.lookup as any)?.[pkey]
|
||||||
if (lookup !== undefined) {
|
if (lookup !== undefined) {
|
||||||
const pid = (pops as any)[pkey]
|
const pid = pops[pkey]
|
||||||
const pp = updatedDoc.$lookup as any
|
const pp = updatedDoc.$lookup as any
|
||||||
if (pp[pkey] === undefined) {
|
if (pp[pkey] === undefined) {
|
||||||
pp[pkey] = []
|
pp[pkey] = []
|
||||||
@ -833,6 +831,17 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async __updateDoc (q: Query, updatedDoc: WithLookup<Doc>, tx: TxUpdateDoc<Doc>): Promise<void> {
|
||||||
|
TxProcessor.updateDoc2Doc(updatedDoc, tx)
|
||||||
|
|
||||||
|
const ops = {
|
||||||
|
...tx.operations,
|
||||||
|
modifiedBy: tx.modifiedBy,
|
||||||
|
modifiedOn: tx.modifiedOn
|
||||||
|
}
|
||||||
|
await this.__updateLookup(q, updatedDoc, ops)
|
||||||
|
}
|
||||||
|
|
||||||
private sort (q: Query, tx: TxUpdateDoc<Doc>): void {
|
private sort (q: Query, tx: TxUpdateDoc<Doc>): void {
|
||||||
const sort = q.options?.sort
|
const sort = q.options?.sort
|
||||||
if (sort === undefined) return
|
if (sort === undefined) return
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
export let direction: TooltipAlignment | undefined = undefined
|
export let direction: TooltipAlignment | undefined = undefined
|
||||||
export let icon: Asset | AnySvelteComponent
|
export let icon: Asset | AnySvelteComponent
|
||||||
export let size: 'small' | 'medium' | 'large'
|
export let size: 'small' | 'medium' | 'large'
|
||||||
export let action: (ev: Event) => Promise<void> | void = async () => {}
|
export let action: (ev: MouseEvent) => Promise<void> | void = async () => {}
|
||||||
export let invisible: boolean = false
|
export let invisible: boolean = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
7
plugins/hr-assets/.eslintrc.js
Normal file
7
plugins/hr-assets/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/platform-rig/profiles/assets/config/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
13
plugins/hr-assets/assets/icons.svg
Normal file
13
plugins/hr-assets/assets/icons.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!-- ALL HASHTAGs -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||||
|
<symbol id="structure" viewBox="0 0 24 24">
|
||||||
|
<path d="M17.2,7.8h3.6c1.1,0,2-0.9,2-2V4.2c0-1.1-0.9-2-2-2h-3.6c-1.1,0-2,0.9-2,2v0H9.8V4c0-1.5-1.2-2.8-2.8-2.8H4 C2.5,1.2,1.2,2.5,1.2,4v2c0,1.5,1.2,2.8,2.8,2.8h3c1.5,0,2.8-1.2,2.8-2.8V5.8h2V18c0,1.5,1.2,2.8,2.8,2.8h0.8v0c0,1.1,0.9,2,2,2h3.6 c1.1,0,2-0.9,2-2v-1.6c0-1.1-0.9-2-2-2h-3.6c-1.1,0-2,0.9-2,2v0h-0.8c-0.7,0-1.2-0.6-1.2-1.2v-4.8h2v0c0,1.1,0.9,2,2,2h3.6 c1.1,0,2-0.9,2-2v-1.6c0-1.1-0.9-2-2-2h-3.6c-1.1,0-2,0.9-2,2v0h-2v-6h2v0C15.2,6.9,16.1,7.8,17.2,7.8z M8.2,6 c0,0.7-0.6,1.2-1.2,1.2H4C3.3,7.2,2.8,6.7,2.8,6V4c0-0.7,0.6-1.2,1.2-1.2h3c0.7,0,1.2,0.6,1.2,1.2V6z M16.8,19.2 c0-0.2,0.2-0.5,0.5-0.5h3.6c0.2,0,0.5,0.2,0.5,0.5v1.6c0,0.2-0.2,0.5-0.5,0.5h-3.6c-0.2,0-0.5-0.2-0.5-0.5V19.2z M16.8,11.7 c0-0.2,0.2-0.5,0.5-0.5h3.6c0.2,0,0.5,0.2,0.5,0.5v1.6c0,0.2-0.2,0.5-0.5,0.5h-3.6c-0.2,0-0.5-0.2-0.5-0.5V11.7z M16.8,4.2 c0-0.2,0.2-0.5,0.5-0.5h3.6c0.2,0,0.5,0.2,0.5,0.5v1.6c0,0.2-0.2,0.5-0.5,0.5h-3.6c-0.2,0-0.5-0.2-0.5-0.5V4.2z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="department" viewBox="0 0 24 24">
|
||||||
|
<path d="M17.2,7.8h3.6c1.1,0,2-0.9,2-2V4.2c0-1.1-0.9-2-2-2h-3.6c-1.1,0-2,0.9-2,2v0H9.8V4c0-1.5-1.2-2.8-2.8-2.8H4 C2.5,1.2,1.2,2.5,1.2,4v2c0,1.5,1.2,2.8,2.8,2.8h3c1.5,0,2.8-1.2,2.8-2.8V5.8h2V18c0,1.5,1.2,2.8,2.8,2.8h0.8v0c0,1.1,0.9,2,2,2h3.6 c1.1,0,2-0.9,2-2v-1.6c0-1.1-0.9-2-2-2h-3.6c-1.1,0-2,0.9-2,2v0h-0.8c-0.7,0-1.2-0.6-1.2-1.2v-4.8h2v0c0,1.1,0.9,2,2,2h3.6 c1.1,0,2-0.9,2-2v-1.6c0-1.1-0.9-2-2-2h-3.6c-1.1,0-2,0.9-2,2v0h-2v-6h2v0C15.2,6.9,16.1,7.8,17.2,7.8z M8.2,6 c0,0.7-0.6,1.2-1.2,1.2H4C3.3,7.2,2.8,6.7,2.8,6V4c0-0.7,0.6-1.2,1.2-1.2h3c0.7,0,1.2,0.6,1.2,1.2V6z M16.8,19.2 c0-0.2,0.2-0.5,0.5-0.5h3.6c0.2,0,0.5,0.2,0.5,0.5v1.6c0,0.2-0.2,0.5-0.5,0.5h-3.6c-0.2,0-0.5-0.2-0.5-0.5V19.2z M16.8,11.7 c0-0.2,0.2-0.5,0.5-0.5h3.6c0.2,0,0.5,0.2,0.5,0.5v1.6c0,0.2-0.2,0.5-0.5,0.5h-3.6c-0.2,0-0.5-0.2-0.5-0.5V11.7z M16.8,4.2 c0-0.2,0.2-0.5,0.5-0.5h3.6c0.2,0,0.5,0.2,0.5,0.5v1.6c0,0.2-0.2,0.5-0.5,0.5h-3.6c-0.2,0-0.5-0.2-0.5-0.5V4.2z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="hr" viewBox="0 0 24 24">
|
||||||
|
<path d="M12,10.8c2.6,0,4.8-2.1,4.8-4.8S14.6,1.2,12,1.2C9.4,1.2,7.2,3.4,7.2,6S9.4,10.8,12,10.8z M12,2.8 c1.8,0,3.2,1.5,3.2,3.2S13.8,9.2,12,9.2S8.8,7.8,8.8,6S10.2,2.8,12,2.8z" />
|
||||||
|
<path d="M12,12.2c-5.4,0-9.8,4.4-9.8,9.8c0,0.4,0.3,0.8,0.8,0.8s0.8-0.3,0.8-0.8c0-4.2,3.1-7.7,7.2-8.2l-1.7,5.5 c-0.1,0.2,0,0.5,0.1,0.7l2,2.5c0.1,0.2,0.4,0.3,0.6,0.3s0.4-0.1,0.6-0.3l2-2.5c0.2-0.2,0.2-0.5,0.1-0.7L13,13.8 c4.1,0.5,7.2,4,7.2,8.2c0,0.4,0.3,0.8,0.8,0.8s0.8-0.3,0.8-0.8C21.8,16.6,17.4,12.2,12,12.2z M12,20.8l-1.2-1.5l1.2-3.8l1.2,3.8 L12,20.8z" />
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
5
plugins/hr-assets/config/rig.json
Normal file
5
plugins/hr-assets/config/rig.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
"rigPackageName": "@anticrm/platform-rig",
|
||||||
|
"rigProfile": "assets"
|
||||||
|
}
|
21
plugins/hr-assets/lang/en.json
Normal file
21
plugins/hr-assets/lang/en.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"string": {
|
||||||
|
"Department": "Department",
|
||||||
|
"ParentDepartmentLabel": "Parent department",
|
||||||
|
"Structure":"Structure",
|
||||||
|
"CreateDepartment": "Create department",
|
||||||
|
"CreateDepartmentLabel": "Create department",
|
||||||
|
"DepartmentPlaceholder": "Department",
|
||||||
|
"TeamLead": "Team lead",
|
||||||
|
"UnAssignLead": "Unassign team lead",
|
||||||
|
"MemberCount": "{count, plural, =0 {no employees} =1 {1 employee} other {# employees}}",
|
||||||
|
"AssignLead": "Assign team lead",
|
||||||
|
"TeamLeadTooltip": "{value}",
|
||||||
|
"HRApplication": "Human resources",
|
||||||
|
"MoveStaff": "Employee transfer",
|
||||||
|
"MoveStaffDescr": "Do you want to transfer employee from {current} to {department}",
|
||||||
|
"Departments": "Departments",
|
||||||
|
"ShowEmployees": "Show employees",
|
||||||
|
"AddEmployee": "Add employee"
|
||||||
|
}
|
||||||
|
}
|
21
plugins/hr-assets/lang/ru.json
Normal file
21
plugins/hr-assets/lang/ru.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"string": {
|
||||||
|
"Department": "Департамент",
|
||||||
|
"ParentDepartmentLabel": "Родительский департамент",
|
||||||
|
"Structure":"Структура",
|
||||||
|
"CreateDepartment": "Создать департамент",
|
||||||
|
"CreateDepartmentLabel": "Создать департамент",
|
||||||
|
"DepartmentPlaceholder": "Департамент",
|
||||||
|
"TeamLead": "Менеджер",
|
||||||
|
"UnAssignLead": "Отменить назначение менеджера",
|
||||||
|
"MemberCount": "{count, plural, =0 {нет сотрудников} =1 {1 сотрудник} =2 {2 сотрудника} =3 {3 сотрудника} =4 {4 сотрудника} other {# сотрудников}}",
|
||||||
|
"AssignLead": "Назначить менеджера",
|
||||||
|
"TeamLeadTooltip": "{value}",
|
||||||
|
"HRApplication": "Human resources",
|
||||||
|
"MoveStaff": "Перевод сотрудника",
|
||||||
|
"MoveStaffDescr": "Вы действительно хотите перевести сотрудника из {current} в {department}",
|
||||||
|
"Departments": "Департаменты",
|
||||||
|
"ShowEmployees": "Просмотреть сотрудников",
|
||||||
|
"AddEmployee": "Добавить сотрудника"
|
||||||
|
}
|
||||||
|
}
|
34
plugins/hr-assets/package.json
Normal file
34
plugins/hr-assets/package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/hr-assets",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"author": "Anticrm Platform Contributors",
|
||||||
|
"template": "@anticrm/assets-package",
|
||||||
|
"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.21.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.45.5",
|
||||||
|
"@types/node": "~16.11.12"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"@anticrm/hr": "~0.6.0"
|
||||||
|
}
|
||||||
|
}
|
26
plugins/hr-assets/src/index.ts
Normal file
26
plugins/hr-assets/src/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { addStringsLoader, loadMetadata } from '@anticrm/platform'
|
||||||
|
import hr, { hrId } from '@anticrm/hr'
|
||||||
|
|
||||||
|
const icons = require('../assets/icons.svg') as string // eslint-disable-line
|
||||||
|
loadMetadata(hr.icon, {
|
||||||
|
HR: `${icons}#hr`,
|
||||||
|
Department: `${icons}#department`,
|
||||||
|
Structure: `${icons}#structure`
|
||||||
|
})
|
||||||
|
|
||||||
|
addStringsLoader(hrId, async (lang: string) => await import(`../lang/${lang}.json`))
|
16
plugins/hr-assets/tsconfig.json
Normal file
16
plugins/hr-assets/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "./lib",
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
7
plugins/hr-resources/.eslintrc.js
Normal file
7
plugins/hr-resources/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/platform-rig/profiles/ui/config/eslint.config.json'],
|
||||||
|
parserOptions: { tsconfigRootDir: __dirname },
|
||||||
|
settings: {
|
||||||
|
'svelte3/ignore-styles': () => true
|
||||||
|
}
|
||||||
|
}
|
5
plugins/hr-resources/config/rig.json
Normal file
5
plugins/hr-resources/config/rig.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
"rigPackageName": "@anticrm/platform-rig",
|
||||||
|
"rigProfile": "ui"
|
||||||
|
}
|
46
plugins/hr-resources/package.json
Normal file
46
plugins/hr-resources/package.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/hr-resources",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"main": "src/index.ts",
|
||||||
|
"author": "Anticrm Platform Contributors",
|
||||||
|
"license": "EPL-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc --noEmit",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"svelte-loader": "^3.1.2",
|
||||||
|
"sass": "^1.37.5",
|
||||||
|
"svelte-preprocess": "^4.10.5",
|
||||||
|
"@anticrm/platform-rig": "~0.6.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.21.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": "^4.0.0",
|
||||||
|
"prettier-plugin-svelte": "^2.7.0",
|
||||||
|
"eslint": "^7.32.0",
|
||||||
|
"prettier": "^2.4.1",
|
||||||
|
"svelte-check": "^2.7.0",
|
||||||
|
"typescript": "^4.3.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"svelte": "^3.47",
|
||||||
|
"@anticrm/hr": "~0.6.0",
|
||||||
|
"@anticrm/ui": "~0.6.0",
|
||||||
|
"@anticrm/presentation": "~0.6.2",
|
||||||
|
"@anticrm/core": "~0.6.16",
|
||||||
|
"@anticrm/panel": "~0.6.0",
|
||||||
|
"@anticrm/contact": "~0.6.5",
|
||||||
|
"@anticrm/view-resources": "~0.6.0",
|
||||||
|
"@anticrm/contact-resources": "~0.6.0",
|
||||||
|
"@anticrm/setting": "~0.6.1",
|
||||||
|
"@anticrm/attachment": "~0.6.1"
|
||||||
|
}
|
||||||
|
}
|
5
plugins/hr-resources/postcss.config.js
Normal file
5
plugins/hr-resources/postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
require('autoprefixer')
|
||||||
|
]
|
||||||
|
}
|
89
plugins/hr-resources/src/components/CreateDepartment.svelte
Normal file
89
plugins/hr-resources/src/components/CreateDepartment.svelte
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import contact, { Employee } from '@anticrm/contact'
|
||||||
|
import { Ref } from '@anticrm/core'
|
||||||
|
import { Card, getClient, SpaceSelector, UserBox } from '@anticrm/presentation'
|
||||||
|
import { Button, createFocusManager, EditBox, FocusHandler } from '@anticrm/ui'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import hr from '../plugin'
|
||||||
|
|
||||||
|
export let space = hr.ids.Head
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
let name: string = ''
|
||||||
|
let lead: Ref<Employee> | null = null
|
||||||
|
|
||||||
|
export function canClose (): boolean {
|
||||||
|
return name === ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
|
|
||||||
|
async function createDepartment () {
|
||||||
|
const id = await client.createDoc(hr.class.Department, space, {
|
||||||
|
name,
|
||||||
|
description: '',
|
||||||
|
private: false,
|
||||||
|
archived: false,
|
||||||
|
members: [],
|
||||||
|
teamLead: lead
|
||||||
|
})
|
||||||
|
|
||||||
|
dispatch('close', id)
|
||||||
|
}
|
||||||
|
const manager = createFocusManager()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FocusHandler {manager} />
|
||||||
|
<Card
|
||||||
|
label={hr.string.CreateDepartment}
|
||||||
|
okAction={createDepartment}
|
||||||
|
canSave={!!name}
|
||||||
|
on:close={() => {
|
||||||
|
dispatch('close')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="flex-row-center clear-mins">
|
||||||
|
<div class="mr-3">
|
||||||
|
<Button focusIndex={1} icon={hr.icon.Department} size={'medium'} kind={'link-bordered'} disabled />
|
||||||
|
</div>
|
||||||
|
<EditBox
|
||||||
|
focusIndex={2}
|
||||||
|
bind:value={name}
|
||||||
|
placeholder={hr.string.DepartmentPlaceholder}
|
||||||
|
maxWidth={'37.5rem'}
|
||||||
|
kind={'large-style'}
|
||||||
|
focus
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
|
<SpaceSelector _class={hr.class.Department} label={hr.string.ParentDepartmentLabel} bind:space />
|
||||||
|
</svelte:fragment>
|
||||||
|
<svelte:fragment slot="pool">
|
||||||
|
<UserBox
|
||||||
|
focusIndex={3}
|
||||||
|
_class={contact.class.Employee}
|
||||||
|
label={hr.string.TeamLead}
|
||||||
|
placeholder={hr.string.TeamLead}
|
||||||
|
bind:value={lead}
|
||||||
|
allowDeselect
|
||||||
|
titleDeselect={hr.string.UnAssignLead}
|
||||||
|
kind={'no-border'}
|
||||||
|
size={'small'}
|
||||||
|
/>
|
||||||
|
</svelte:fragment>
|
||||||
|
</Card>
|
151
plugins/hr-resources/src/components/DepartmentCard.svelte
Normal file
151
plugins/hr-resources/src/components/DepartmentCard.svelte
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { Ref, WithLookup } from '@anticrm/core'
|
||||||
|
import { Department } from '@anticrm/hr'
|
||||||
|
import { Avatar, getClient, UsersPopup } from '@anticrm/presentation'
|
||||||
|
import CreateDepartment from './CreateDepartment.svelte'
|
||||||
|
import DepartmentCard from './DepartmentCard.svelte'
|
||||||
|
import hr from '../plugin'
|
||||||
|
import { IconAdd, IconMoreV, Button, eventToHTMLElement, Label, showPopup, ActionIcon } from '@anticrm/ui'
|
||||||
|
import contact, { Employee } from '@anticrm/contact'
|
||||||
|
import { EmployeePresenter } from '@anticrm/contact-resources'
|
||||||
|
import DepartmentStaff from './DepartmentStaff.svelte'
|
||||||
|
import { Menu } from '@anticrm/view-resources'
|
||||||
|
|
||||||
|
export let value: WithLookup<Department>
|
||||||
|
export let descendants: Map<Ref<Department>, WithLookup<Department>[]>
|
||||||
|
|
||||||
|
$: currentDescendants = descendants.get(value._id) ?? []
|
||||||
|
let expand = false
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
|
|
||||||
|
function toggle () {
|
||||||
|
if (currentDescendants.length === 0) return
|
||||||
|
expand = !expand
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeLead (result: Employee | null | undefined): Promise<void> {
|
||||||
|
if (result === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const newLead = result === null ? null : result._id
|
||||||
|
if (newLead !== value.teamLead) {
|
||||||
|
await client.update(value, { teamLead: newLead })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLeadEditor (event: MouseEvent) {
|
||||||
|
showPopup(
|
||||||
|
UsersPopup,
|
||||||
|
{
|
||||||
|
_class: contact.class.Employee,
|
||||||
|
selected: value.$lookup?.teamLead,
|
||||||
|
allowDeselect: true,
|
||||||
|
placeholder: hr.string.TeamLead
|
||||||
|
},
|
||||||
|
eventToHTMLElement(event),
|
||||||
|
changeLead
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createChild (e: MouseEvent) {
|
||||||
|
showPopup(CreateDepartment, { space: value._id }, eventToHTMLElement(e), (res) => {
|
||||||
|
if (res && !expand) expand = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function editMembers (e: MouseEvent) {
|
||||||
|
showPopup(DepartmentStaff, { _id: value._id }, 'float')
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMenu (e: MouseEvent) {
|
||||||
|
showPopup(
|
||||||
|
Menu,
|
||||||
|
{ object: value, baseMenuClass: value._class },
|
||||||
|
{
|
||||||
|
getBoundingClientRect: () => DOMRect.fromRect({ width: 1, height: 1, x: e.clientX, y: e.clientY })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex-center w-full px-4">
|
||||||
|
<div
|
||||||
|
class="w-full mt-2 mb-2 container flex"
|
||||||
|
class:cursor-pointer={currentDescendants.length}
|
||||||
|
on:click|stopPropagation={toggle}
|
||||||
|
on:contextmenu|preventDefault={showMenu}
|
||||||
|
>
|
||||||
|
{#if currentDescendants.length}
|
||||||
|
<div class="verticalDivider" />
|
||||||
|
<div class="verticalDivider" />
|
||||||
|
{/if}
|
||||||
|
<div class="flex-between pt-4 pb-4 pr-4 pl-2 w-full">
|
||||||
|
<div class="flex-center">
|
||||||
|
<Avatar size={'medium'} avatar={value.avatar} icon={hr.icon.Department} />
|
||||||
|
<div class="flex-row ml-2">
|
||||||
|
<div class="fs-title">
|
||||||
|
{value.name}
|
||||||
|
</div>
|
||||||
|
<div class="cursor-pointer" on:click|stopPropagation={editMembers}>
|
||||||
|
<Label label={hr.string.MemberCount} params={{ count: value.members.length }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-center mr-2">
|
||||||
|
<div class="mr-2">
|
||||||
|
<EmployeePresenter
|
||||||
|
value={value.$lookup?.teamLead}
|
||||||
|
avatarSize={'small'}
|
||||||
|
shouldShowAvatar
|
||||||
|
shouldShowPlaceholder
|
||||||
|
shouldShowName={false}
|
||||||
|
tooltipLabels={{
|
||||||
|
personLabel: hr.string.TeamLeadTooltip,
|
||||||
|
placeholderLabel: hr.string.AssignLead
|
||||||
|
}}
|
||||||
|
onEmployeeEdit={openLeadEditor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button icon={IconAdd} on:click={createChild} />
|
||||||
|
<ActionIcon icon={IconMoreV} size={'medium'} action={showMenu} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if expand && currentDescendants.length}
|
||||||
|
<div class="ml-8">
|
||||||
|
{#each descendants.get(value._id) ?? [] as nested}
|
||||||
|
<DepartmentCard value={nested} {descendants} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid var(--theme-zone-border);
|
||||||
|
background-color: var(--board-card-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.verticalDivider {
|
||||||
|
width: 1px;
|
||||||
|
margin-left: 0.125rem;
|
||||||
|
background-color: var(--theme-zone-border);
|
||||||
|
}
|
||||||
|
</style>
|
41
plugins/hr-resources/src/components/DepartmentEditor.svelte
Normal file
41
plugins/hr-resources/src/components/DepartmentEditor.svelte
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { Ref } from '@anticrm/core'
|
||||||
|
import { Department } from '@anticrm/hr'
|
||||||
|
import { IntlString } from '@anticrm/platform'
|
||||||
|
import { SpaceSelector } from '@anticrm/presentation'
|
||||||
|
import { ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||||
|
import hr from '../plugin'
|
||||||
|
|
||||||
|
export let value: Ref<Department> | undefined
|
||||||
|
export let label: IntlString = hr.string.Department
|
||||||
|
export let onChange: (value: any) => void
|
||||||
|
export let kind: ButtonKind = 'no-border'
|
||||||
|
export let size: ButtonSize = 'small'
|
||||||
|
export let justify: 'left' | 'center' = 'center'
|
||||||
|
export let width: string | undefined = undefined
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SpaceSelector
|
||||||
|
_class={hr.class.Department}
|
||||||
|
label={hr.string.ParentDepartmentLabel}
|
||||||
|
{size}
|
||||||
|
{kind}
|
||||||
|
{justify}
|
||||||
|
{width}
|
||||||
|
bind:space={value}
|
||||||
|
on:change={(e) => onChange(e.detail)}
|
||||||
|
/>
|
162
plugins/hr-resources/src/components/DepartmentStaff.svelte
Normal file
162
plugins/hr-resources/src/components/DepartmentStaff.svelte
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||||
|
import { Ref, SortingOrder, WithLookup } from '@anticrm/core'
|
||||||
|
import { Department, Staff } from '@anticrm/hr'
|
||||||
|
import { Avatar, createQuery, MessageBox, getClient, UsersPopup } from '@anticrm/presentation'
|
||||||
|
import { Scroller, Panel, Button, showPopup, eventToHTMLElement } from '@anticrm/ui'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import StaffPresenter from './StaffPresenter.svelte'
|
||||||
|
import hr from '../plugin'
|
||||||
|
|
||||||
|
export let _id: Ref<Department> | undefined
|
||||||
|
let value: Department | undefined
|
||||||
|
let employees: WithLookup<Staff>[] = []
|
||||||
|
let accounts: EmployeeAccount[] = []
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
const departmentQuery = createQuery()
|
||||||
|
const query = createQuery()
|
||||||
|
const accountsQuery = createQuery()
|
||||||
|
const client = getClient()
|
||||||
|
|
||||||
|
$: _id &&
|
||||||
|
value === undefined &&
|
||||||
|
departmentQuery.query(
|
||||||
|
hr.class.Department,
|
||||||
|
{
|
||||||
|
_id
|
||||||
|
},
|
||||||
|
(res) => ([value] = res)
|
||||||
|
)
|
||||||
|
|
||||||
|
$: value &&
|
||||||
|
accountsQuery.query(
|
||||||
|
contact.class.EmployeeAccount,
|
||||||
|
{
|
||||||
|
_id: { $in: value.members as Ref<EmployeeAccount>[] }
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
accounts = res
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$: accounts.length &&
|
||||||
|
query.query(
|
||||||
|
hr.mixin.Staff,
|
||||||
|
{
|
||||||
|
_id: { $in: accounts.map((p) => p.employee) as Ref<Staff>[] }
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
employees = res
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sort: {
|
||||||
|
name: SortingOrder.Descending
|
||||||
|
},
|
||||||
|
lookup: {
|
||||||
|
department: hr.class.Department
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function add (e: MouseEvent) {
|
||||||
|
showPopup(
|
||||||
|
UsersPopup,
|
||||||
|
{
|
||||||
|
_class: contact.class.Employee,
|
||||||
|
ignoreUsers: employees.filter((p) => p.department === _id).map((p) => p._id)
|
||||||
|
},
|
||||||
|
eventToHTMLElement(e),
|
||||||
|
addMember
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addMember (employee: Employee | undefined): Promise<void> {
|
||||||
|
if (employee === undefined || value === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const hierarchy = client.getHierarchy()
|
||||||
|
if (!hierarchy.hasMixin(employee, hr.mixin.Staff)) {
|
||||||
|
await client.createMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
|
||||||
|
department: value._id
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const staff = hierarchy.as(employee, hr.mixin.Staff)
|
||||||
|
if (staff.department === value._id) return
|
||||||
|
const current = await client.findOne(hr.class.Department, {
|
||||||
|
_id: staff.department
|
||||||
|
})
|
||||||
|
if (current !== undefined) {
|
||||||
|
showPopup(
|
||||||
|
MessageBox,
|
||||||
|
{
|
||||||
|
label: hr.string.MoveStaff,
|
||||||
|
message: hr.string.MoveStaffDescr,
|
||||||
|
params: {
|
||||||
|
current: current.name,
|
||||||
|
department: value.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
async (res?: boolean) => {
|
||||||
|
if (res === true && value !== undefined) {
|
||||||
|
await client.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
|
||||||
|
department: value._id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
await client.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
|
||||||
|
department: value._id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Panel
|
||||||
|
isHeader={true}
|
||||||
|
isAside={false}
|
||||||
|
isFullSize
|
||||||
|
on:fullsize
|
||||||
|
on:close={() => {
|
||||||
|
dispatch('close')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="title">
|
||||||
|
<div class="antiTitle icon-wrapper">
|
||||||
|
{#if value}
|
||||||
|
<div class="wrapped-icon"><Avatar size={'medium'} avatar={value.avatar} icon={hr.icon.Department} /></div>
|
||||||
|
<div class="title-wrapper">
|
||||||
|
<span class="wrapped-title">{value.name}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</svelte:fragment>
|
||||||
|
<svelte:fragment slot="utils">
|
||||||
|
<Button label={hr.string.AddEmployee} kind={'primary'} on:click={add} />
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<Scroller>
|
||||||
|
{#each employees as value}
|
||||||
|
<StaffPresenter {value} />
|
||||||
|
{/each}
|
||||||
|
</Scroller>
|
||||||
|
</Panel>
|
164
plugins/hr-resources/src/components/EditDepartment.svelte
Normal file
164
plugins/hr-resources/src/components/EditDepartment.svelte
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { createQuery, EditableAvatar, getClient } from '@anticrm/presentation'
|
||||||
|
import { Panel } from '@anticrm/panel'
|
||||||
|
import { createFocusManager, EditBox, FocusHandler } from '@anticrm/ui'
|
||||||
|
|
||||||
|
import { ActionContext } from '@anticrm/view-resources'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import { Department } from '@anticrm/hr'
|
||||||
|
import core, { getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||||
|
import hr from '../plugin'
|
||||||
|
import { getResource } from '@anticrm/platform'
|
||||||
|
import attachment from '@anticrm/attachment'
|
||||||
|
import { ChannelsEditor } from '@anticrm/contact-resources'
|
||||||
|
import setting, { IntegrationType } from '@anticrm/setting'
|
||||||
|
|
||||||
|
export let _id: Ref<Department>
|
||||||
|
let object: Department | undefined
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const client = getClient()
|
||||||
|
const query = createQuery()
|
||||||
|
query.query(
|
||||||
|
hr.class.Department,
|
||||||
|
{ _id },
|
||||||
|
(res) => {
|
||||||
|
object = res[0]
|
||||||
|
},
|
||||||
|
{ limit: 1 }
|
||||||
|
)
|
||||||
|
|
||||||
|
async function onAvatarDone (e: any) {
|
||||||
|
if (object === undefined) return
|
||||||
|
const uploadFile = await getResource(attachment.helper.UploadFile)
|
||||||
|
const deleteFile = await getResource(attachment.helper.DeleteFile)
|
||||||
|
const { file: avatar } = e.detail
|
||||||
|
|
||||||
|
if (object.avatar != null) {
|
||||||
|
await deleteFile(object.avatar)
|
||||||
|
}
|
||||||
|
const uuid = await uploadFile(avatar)
|
||||||
|
await client.updateDoc(object._class, object.space, object._id, {
|
||||||
|
avatar: uuid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeAvatar (): Promise<void> {
|
||||||
|
if (object === undefined) return
|
||||||
|
const deleteFile = await getResource(attachment.helper.DeleteFile)
|
||||||
|
if (object.avatar != null) {
|
||||||
|
await client.updateDoc(object._class, object.space, object._id, {
|
||||||
|
avatar: null
|
||||||
|
})
|
||||||
|
await deleteFile(object.avatar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function nameChange (): Promise<void> {
|
||||||
|
if (object === undefined) return
|
||||||
|
await client.update(object, {
|
||||||
|
name: object.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const manager = createFocusManager()
|
||||||
|
|
||||||
|
const _update = (result: any): void => {
|
||||||
|
dispatch('update', result)
|
||||||
|
}
|
||||||
|
|
||||||
|
let integrations: Set<Ref<IntegrationType>> = new Set<Ref<IntegrationType>>()
|
||||||
|
const accountId = getCurrentAccount()._id
|
||||||
|
const settingsQuery = createQuery()
|
||||||
|
$: settingsQuery.query(
|
||||||
|
setting.class.Integration,
|
||||||
|
{ space: accountId as string as Ref<Space>, disabled: false },
|
||||||
|
(res) => {
|
||||||
|
integrations = new Set(res.map((p) => p.type))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ActionContext
|
||||||
|
context={{
|
||||||
|
mode: 'editor'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FocusHandler {manager} />
|
||||||
|
|
||||||
|
{#if object !== undefined}
|
||||||
|
<Panel
|
||||||
|
icon={hr.icon.Department}
|
||||||
|
title={object.name}
|
||||||
|
{object}
|
||||||
|
isHeader={false}
|
||||||
|
isAside={true}
|
||||||
|
on:update={(ev) => _update(ev.detail)}
|
||||||
|
on:close={() => {
|
||||||
|
dispatch('close')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="flex-row-stretch flex-grow">
|
||||||
|
<div class="mr-8">
|
||||||
|
{#key object}
|
||||||
|
<EditableAvatar
|
||||||
|
avatar={object.avatar}
|
||||||
|
size={'x-large'}
|
||||||
|
icon={hr.icon.Department}
|
||||||
|
on:done={onAvatarDone}
|
||||||
|
on:remove={removeAvatar}
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow flex-col">
|
||||||
|
<div class="name">
|
||||||
|
<EditBox
|
||||||
|
placeholder={core.string.Name}
|
||||||
|
maxWidth="20rem"
|
||||||
|
bind:value={object.name}
|
||||||
|
on:change={nameChange}
|
||||||
|
focusIndex={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="separator" />
|
||||||
|
<div class="flex-row-center">
|
||||||
|
<ChannelsEditor
|
||||||
|
attachedTo={object._id}
|
||||||
|
attachedClass={object._class}
|
||||||
|
{integrations}
|
||||||
|
focusIndex={10}
|
||||||
|
on:click
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.name {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--theme-caption-color);
|
||||||
|
}
|
||||||
|
.separator {
|
||||||
|
margin: 1rem 0;
|
||||||
|
height: 1px;
|
||||||
|
background-color: var(--divider-color);
|
||||||
|
}
|
||||||
|
</style>
|
36
plugins/hr-resources/src/components/StaffPresenter.svelte
Normal file
36
plugins/hr-resources/src/components/StaffPresenter.svelte
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { formatName } from '@anticrm/contact'
|
||||||
|
import { WithLookup } from '@anticrm/core'
|
||||||
|
import { Staff } from '@anticrm/hr'
|
||||||
|
import { Avatar } from '@anticrm/presentation'
|
||||||
|
|
||||||
|
export let value: WithLookup<Staff>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex-between w-full p-4">
|
||||||
|
<div class="flex-row-center">
|
||||||
|
<Avatar avatar={value.avatar} size={'medium'} />
|
||||||
|
<div class="fs-title ml-2">
|
||||||
|
{formatName(value.name)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{#if value.$lookup?.department}
|
||||||
|
{value.$lookup.department.name}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
85
plugins/hr-resources/src/components/Structure.svelte
Normal file
85
plugins/hr-resources/src/components/Structure.svelte
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!--
|
||||||
|
// 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.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { DocumentQuery, Ref } from '@anticrm/core'
|
||||||
|
import { Button, Icon, Label, Scroller, SearchEdit, showPopup, IconAdd, eventToHTMLElement } from '@anticrm/ui'
|
||||||
|
import type { Department } from '@anticrm/hr'
|
||||||
|
import hr from '../plugin'
|
||||||
|
import CreateDepartment from './CreateDepartment.svelte'
|
||||||
|
import DepartmentCard from './DepartmentCard.svelte'
|
||||||
|
import { createQuery } from '@anticrm/presentation'
|
||||||
|
import contact from '@anticrm/contact'
|
||||||
|
|
||||||
|
let search = ''
|
||||||
|
let resultQuery: DocumentQuery<Department> = {}
|
||||||
|
|
||||||
|
function updateResultQuery (search: string): void {
|
||||||
|
resultQuery = search === '' ? {} : { $search: search }
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCreateDialog (ev: MouseEvent) {
|
||||||
|
showPopup(CreateDepartment, {}, eventToHTMLElement(ev))
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = createQuery()
|
||||||
|
|
||||||
|
let descendants: Map<Ref<Department>, Department[]> = new Map<Ref<Department>, Department[]>()
|
||||||
|
let head: Department | undefined
|
||||||
|
|
||||||
|
query.query(
|
||||||
|
hr.class.Department,
|
||||||
|
resultQuery,
|
||||||
|
(res) => {
|
||||||
|
head = res.find((p) => p._id === hr.ids.Head)
|
||||||
|
descendants.clear()
|
||||||
|
for (const doc of res) {
|
||||||
|
const current = descendants.get(doc.space)
|
||||||
|
if (!current) {
|
||||||
|
descendants.set(doc.space, [doc])
|
||||||
|
} else {
|
||||||
|
current.push(doc)
|
||||||
|
descendants.set(doc.space, current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descendants = descendants
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lookup: {
|
||||||
|
teamLead: contact.class.Employee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="ac-header full divide">
|
||||||
|
<div class="ac-header__wrap-title">
|
||||||
|
<div class="ac-header__icon"><Icon icon={hr.icon.Structure} size={'small'} /></div>
|
||||||
|
<span class="ac-header__title"><Label label={hr.string.Structure} /></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SearchEdit
|
||||||
|
bind:value={search}
|
||||||
|
on:change={() => {
|
||||||
|
updateResultQuery(search)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button label={hr.string.CreateDepartmentLabel} icon={IconAdd} kind={'primary'} on:click={showCreateDialog} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Scroller>
|
||||||
|
{#if head}
|
||||||
|
<DepartmentCard value={head} {descendants} />
|
||||||
|
{/if}
|
||||||
|
</Scroller>
|
29
plugins/hr-resources/src/index.ts
Normal file
29
plugins/hr-resources/src/index.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// 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 { Resources } from '@anticrm/platform'
|
||||||
|
import Structure from './components/Structure.svelte'
|
||||||
|
import DepartmentStaff from './components/DepartmentStaff.svelte'
|
||||||
|
import EditDepartment from './components/EditDepartment.svelte'
|
||||||
|
import DepartmentEditor from './components/DepartmentEditor.svelte'
|
||||||
|
|
||||||
|
export default async (): Promise<Resources> => ({
|
||||||
|
component: {
|
||||||
|
Structure,
|
||||||
|
EditDepartment,
|
||||||
|
DepartmentStaff,
|
||||||
|
DepartmentEditor
|
||||||
|
}
|
||||||
|
})
|
36
plugins/hr-resources/src/plugin.ts
Normal file
36
plugins/hr-resources/src/plugin.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// 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 hr, { hrId } from '@anticrm/hr'
|
||||||
|
import { IntlString, mergeIds } from '@anticrm/platform'
|
||||||
|
|
||||||
|
export default mergeIds(hrId, hr, {
|
||||||
|
string: {
|
||||||
|
Department: '' as IntlString,
|
||||||
|
ParentDepartmentLabel: '' as IntlString,
|
||||||
|
Structure: '' as IntlString,
|
||||||
|
CreateDepartment: '' as IntlString,
|
||||||
|
CreateDepartmentLabel: '' as IntlString,
|
||||||
|
DepartmentPlaceholder: '' as IntlString,
|
||||||
|
TeamLead: '' as IntlString,
|
||||||
|
UnAssignLead: '' as IntlString,
|
||||||
|
MemberCount: '' as IntlString,
|
||||||
|
AssignLead: '' as IntlString,
|
||||||
|
TeamLeadTooltip: '' as IntlString,
|
||||||
|
MoveStaff: '' as IntlString,
|
||||||
|
MoveStaffDescr: '' as IntlString,
|
||||||
|
AddEmployee: '' as IntlString
|
||||||
|
}
|
||||||
|
})
|
5
plugins/hr-resources/svelte.config.js
Normal file
5
plugins/hr-resources/svelte.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const sveltePreprocess = require('svelte-preprocess')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
preprocess: sveltePreprocess()
|
||||||
|
};
|
16
plugins/hr-resources/tsconfig.json
Normal file
16
plugins/hr-resources/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "./lib",
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
7
plugins/hr/.eslintrc.js
Normal file
7
plugins/hr/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
4
plugins/hr/.npmignore
Normal file
4
plugins/hr/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!/lib/**
|
||||||
|
!CHANGELOG.md
|
||||||
|
/lib/**/__tests__/
|
18
plugins/hr/config/rig.json
Normal file
18
plugins/hr/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||||
|
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Required) The name of the rig package to inherit from.
|
||||||
|
* It should be an NPM package name with the "-rig" suffix.
|
||||||
|
*/
|
||||||
|
"rigPackageName": "@anticrm/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"
|
||||||
|
}
|
33
plugins/hr/package.json
Normal file
33
plugins/hr/package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/hr",
|
||||||
|
"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.21.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.45.5",
|
||||||
|
"typescript": "^4.3.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/contact": "~0.6.5",
|
||||||
|
"@anticrm/core": "~0.6.16",
|
||||||
|
"@anticrm/platform": "~0.6.6"
|
||||||
|
}
|
||||||
|
}
|
68
plugins/hr/src/index.ts
Normal file
68
plugins/hr/src/index.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// 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 type { Employee } from '@anticrm/contact'
|
||||||
|
import type { Class, Doc, Mixin, Ref, Space } from '@anticrm/core'
|
||||||
|
import type { Asset, Plugin } from '@anticrm/platform'
|
||||||
|
import { plugin } from '@anticrm/platform'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface Department extends Space {
|
||||||
|
space: Ref<Department>
|
||||||
|
avatar?: string | null
|
||||||
|
teamLead: Ref<Employee> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface Staff extends Employee {
|
||||||
|
department: Ref<Department>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const hrId = 'hr' as Plugin
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
const hr = plugin(hrId, {
|
||||||
|
app: {
|
||||||
|
HR: '' as Ref<Doc>
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
Department: '' as Ref<Class<Department>>
|
||||||
|
},
|
||||||
|
mixin: {
|
||||||
|
Staff: '' as Ref<Mixin<Staff>>
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
HR: '' as Asset,
|
||||||
|
Department: '' as Asset,
|
||||||
|
Structure: '' as Asset
|
||||||
|
},
|
||||||
|
ids: {
|
||||||
|
Head: '' as Ref<Department>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export default hr
|
9
plugins/hr/tsconfig.json
Normal file
9
plugins/hr/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./lib",
|
||||||
|
"lib": ["esnext", "dom"]
|
||||||
|
}
|
||||||
|
}
|
35
rush.json
35
rush.json
@ -1327,6 +1327,41 @@
|
|||||||
"packageName": "@anticrm/pod-backup",
|
"packageName": "@anticrm/pod-backup",
|
||||||
"projectFolder": "pods/backup",
|
"projectFolder": "pods/backup",
|
||||||
"shouldPublish": false
|
"shouldPublish": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/hr",
|
||||||
|
"projectFolder": "plugins/hr",
|
||||||
|
"shouldPublish": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/hr-assets",
|
||||||
|
"projectFolder": "plugins/hr-assets",
|
||||||
|
"shouldPublish": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/hr-resources",
|
||||||
|
"projectFolder": "plugins/hr-resources",
|
||||||
|
"shouldPublish": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/model-hr",
|
||||||
|
"projectFolder": "models/hr",
|
||||||
|
"shouldPublish": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/server-hr",
|
||||||
|
"projectFolder": "server-plugins/hr",
|
||||||
|
"shouldPublish": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/model-server-hr",
|
||||||
|
"projectFolder": "models/server-hr",
|
||||||
|
"shouldPublish": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"packageName": "@anticrm/server-hr-resources",
|
||||||
|
"projectFolder": "server-plugins/hr-resources",
|
||||||
|
"shouldPublish": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
7
server-plugins/hr-resources/.eslintrc.js
Normal file
7
server-plugins/hr-resources/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
4
server-plugins/hr-resources/.npmignore
Normal file
4
server-plugins/hr-resources/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!/lib/**
|
||||||
|
!CHANGELOG.md
|
||||||
|
/lib/**/__tests__/
|
18
server-plugins/hr-resources/config/rig.json
Normal file
18
server-plugins/hr-resources/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||||
|
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Required) The name of the rig package to inherit from.
|
||||||
|
* It should be an NPM package name with the "-rig" suffix.
|
||||||
|
*/
|
||||||
|
"rigPackageName": "@anticrm/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"
|
||||||
|
}
|
35
server-plugins/hr-resources/package.json
Normal file
35
server-plugins/hr-resources/package.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/server-hr-resources",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"author": "Anticrm Platform Contributors",
|
||||||
|
"license": "EPL-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "heft build",
|
||||||
|
"build:watch": "tsc",
|
||||||
|
"lint:fix": "eslint --fix src",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"format": "prettier --write src && eslint --fix src"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@anticrm/platform-rig": "~0.6.0",
|
||||||
|
"@types/heft-jest": "^1.0.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.21.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.45.5",
|
||||||
|
"typescript": "^4.3.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/core": "~0.6.16",
|
||||||
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"@anticrm/server-core": "~0.6.1",
|
||||||
|
"@anticrm/contact": "~0.6.5",
|
||||||
|
"@anticrm/hr": "~0.6.0"
|
||||||
|
}
|
||||||
|
}
|
132
server-plugins/hr-resources/src/index.ts
Normal file
132
server-plugins/hr-resources/src/index.ts
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//
|
||||||
|
// 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 contact, { Employee } from '@anticrm/contact'
|
||||||
|
import core, { Account, Ref, SortingOrder, Tx, TxFactory, TxMixin } from '@anticrm/core'
|
||||||
|
import hr, { Department, Staff } from '@anticrm/hr'
|
||||||
|
import { extractTx, TriggerControl } from '@anticrm/server-core'
|
||||||
|
|
||||||
|
async function getOldDepartment (
|
||||||
|
currentTx: TxMixin<Employee, Staff>,
|
||||||
|
control: TriggerControl
|
||||||
|
): Promise<Ref<Department> | undefined> {
|
||||||
|
const txes = await control.findAll<TxMixin<Employee, Staff>>(
|
||||||
|
core.class.TxMixin,
|
||||||
|
{
|
||||||
|
objectId: currentTx.objectId
|
||||||
|
},
|
||||||
|
{ sort: { modifiedOn: SortingOrder.Ascending } }
|
||||||
|
)
|
||||||
|
let lastDepartment: Ref<Department> | undefined
|
||||||
|
for (const tx of txes) {
|
||||||
|
if (tx._id === currentTx._id) continue
|
||||||
|
if (tx.attributes?.department !== undefined) {
|
||||||
|
lastDepartment = tx.attributes.department
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastDepartment
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildHierarchy (_id: Ref<Department>, control: TriggerControl): Promise<Ref<Department>[]> {
|
||||||
|
const res: Ref<Department>[] = []
|
||||||
|
if (_id === hr.ids.Head) return [hr.ids.Head]
|
||||||
|
const department = (
|
||||||
|
await control.findAll(hr.class.Department, {
|
||||||
|
_id
|
||||||
|
})
|
||||||
|
)[0]
|
||||||
|
if (department !== undefined) {
|
||||||
|
const ancestors = await buildHierarchy(department.space, control)
|
||||||
|
return [department._id, ...ancestors]
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
function exlude (first: Ref<Department>[], second: Ref<Department>[]): Ref<Department>[] {
|
||||||
|
const set = new Set(first)
|
||||||
|
const res: Ref<Department>[] = []
|
||||||
|
for (const department of second) {
|
||||||
|
if (!set.has(department)) {
|
||||||
|
res.push(department)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTxes (
|
||||||
|
factory: TxFactory,
|
||||||
|
account: Ref<Account>,
|
||||||
|
added: Ref<Department>[],
|
||||||
|
removed?: Ref<Department>[]
|
||||||
|
): Tx[] {
|
||||||
|
const pushTxes = added.map((dep) =>
|
||||||
|
factory.createTxUpdateDoc(hr.class.Department, core.space.Space, dep, {
|
||||||
|
$push: { members: account }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
if (removed === undefined) return pushTxes
|
||||||
|
const pullTxes = removed.map((dep) =>
|
||||||
|
factory.createTxUpdateDoc(hr.class.Department, core.space.Space, dep, {
|
||||||
|
$pull: { members: account }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return [...pullTxes, ...pushTxes]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export async function OnDepartmentStaff (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||||
|
const actualTx = extractTx(tx)
|
||||||
|
if (core.class.TxMixin !== actualTx._class) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const ctx = actualTx as TxMixin<Employee, Staff>
|
||||||
|
if (ctx.mixin !== hr.mixin.Staff) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetAccount = (
|
||||||
|
await control.modelDb.findAll(contact.class.EmployeeAccount, {
|
||||||
|
employee: ctx.objectId
|
||||||
|
})
|
||||||
|
)[0]
|
||||||
|
if (targetAccount === undefined) return []
|
||||||
|
|
||||||
|
if (ctx.attributes.department !== undefined) {
|
||||||
|
const lastDepartment = await getOldDepartment(ctx, control)
|
||||||
|
|
||||||
|
const departmentId = ctx.attributes.department
|
||||||
|
const push = await buildHierarchy(departmentId, control)
|
||||||
|
|
||||||
|
if (lastDepartment === undefined) {
|
||||||
|
return getTxes(control.txFactory, targetAccount._id, push)
|
||||||
|
}
|
||||||
|
|
||||||
|
let removed = await buildHierarchy(lastDepartment, control)
|
||||||
|
const added = exlude(removed, push)
|
||||||
|
removed = exlude(push, removed)
|
||||||
|
return getTxes(control.txFactory, targetAccount._id, added, removed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
|
export default async () => ({
|
||||||
|
trigger: {
|
||||||
|
OnDepartmentStaff
|
||||||
|
}
|
||||||
|
})
|
8
server-plugins/hr-resources/tsconfig.json
Normal file
8
server-plugins/hr-resources/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./lib"
|
||||||
|
}
|
||||||
|
}
|
7
server-plugins/hr/.eslintrc.js
Normal file
7
server-plugins/hr/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: './tsconfig.json'
|
||||||
|
}
|
||||||
|
}
|
4
server-plugins/hr/.npmignore
Normal file
4
server-plugins/hr/.npmignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*
|
||||||
|
!/lib/**
|
||||||
|
!CHANGELOG.md
|
||||||
|
/lib/**/__tests__/
|
18
server-plugins/hr/config/rig.json
Normal file
18
server-plugins/hr/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||||
|
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Required) The name of the rig package to inherit from.
|
||||||
|
* It should be an NPM package name with the "-rig" suffix.
|
||||||
|
*/
|
||||||
|
"rigPackageName": "@anticrm/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"
|
||||||
|
}
|
34
server-plugins/hr/package.json
Normal file
34
server-plugins/hr/package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "@anticrm/server-hr",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"author": "Anticrm Platform Contributors",
|
||||||
|
"license": "EPL-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "heft build",
|
||||||
|
"build:watch": "tsc",
|
||||||
|
"lint:fix": "eslint --fix src",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"format": "prettier --write src && eslint --fix src"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@anticrm/platform-rig": "~0.6.0",
|
||||||
|
"@types/heft-jest": "^1.0.2",
|
||||||
|
"@types/node": "~16.11.12",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.21.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.45.5",
|
||||||
|
"typescript": "^4.3.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@anticrm/core": "~0.6.16",
|
||||||
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"@anticrm/server-core": "~0.6.1"
|
||||||
|
}
|
||||||
|
}
|
32
server-plugins/hr/src/index.ts
Normal file
32
server-plugins/hr/src/index.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import type { Plugin, Resource } from '@anticrm/platform'
|
||||||
|
import { plugin } from '@anticrm/platform'
|
||||||
|
import type { TriggerFunc } from '@anticrm/server-core'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const serverHrId = 'server-hr' as Plugin
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export default plugin(serverHrId, {
|
||||||
|
trigger: {
|
||||||
|
OnDepartmentStaff: '' as Resource<TriggerFunc>
|
||||||
|
}
|
||||||
|
})
|
9
server-plugins/hr/tsconfig.json
Normal file
9
server-plugins/hr/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./lib",
|
||||||
|
"esModuleInterop": true
|
||||||
|
}
|
||||||
|
}
|
@ -76,6 +76,8 @@
|
|||||||
"@anticrm/server-preference": "~0.6.0",
|
"@anticrm/server-preference": "~0.6.0",
|
||||||
"@anticrm/server-telegram": "~0.6.0",
|
"@anticrm/server-telegram": "~0.6.0",
|
||||||
"@anticrm/server-telegram-resources": "~0.6.0",
|
"@anticrm/server-telegram-resources": "~0.6.0",
|
||||||
|
"@anticrm/server-hr": "~0.6.0",
|
||||||
|
"@anticrm/server-hr-resources": "~0.6.0",
|
||||||
"@anticrm/server-token": "~0.6.0",
|
"@anticrm/server-token": "~0.6.0",
|
||||||
"@anticrm/middleware": "~0.6.0"
|
"@anticrm/middleware": "~0.6.0"
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ import { serverTagsId } from '@anticrm/server-tags'
|
|||||||
import { serverTaskId } from '@anticrm/server-task'
|
import { serverTaskId } from '@anticrm/server-task'
|
||||||
import { serverTrackerId } from '@anticrm/server-tracker'
|
import { serverTrackerId } from '@anticrm/server-tracker'
|
||||||
import { serverTelegramId } from '@anticrm/server-telegram'
|
import { serverTelegramId } from '@anticrm/server-telegram'
|
||||||
|
import { serverHrId } from '@anticrm/server-hr'
|
||||||
import { Token } from '@anticrm/server-token'
|
import { Token } from '@anticrm/server-token'
|
||||||
import { BroadcastCall, ClientSession, start as startJsonRpc } from '@anticrm/server-ws'
|
import { BroadcastCall, ClientSession, start as startJsonRpc } from '@anticrm/server-ws'
|
||||||
import { Client as MinioClient } from 'minio'
|
import { Client as MinioClient } from 'minio'
|
||||||
@ -137,6 +138,7 @@ export function start (
|
|||||||
addLocation(serverCalendarId, () => import('@anticrm/server-calendar-resources'))
|
addLocation(serverCalendarId, () => import('@anticrm/server-calendar-resources'))
|
||||||
addLocation(serverGmailId, () => import('@anticrm/server-gmail-resources'))
|
addLocation(serverGmailId, () => import('@anticrm/server-gmail-resources'))
|
||||||
addLocation(serverTelegramId, () => import('@anticrm/server-telegram-resources'))
|
addLocation(serverTelegramId, () => import('@anticrm/server-telegram-resources'))
|
||||||
|
addLocation(serverHrId, () => import('@anticrm/server-hr-resources'))
|
||||||
|
|
||||||
const middlewares: MiddlewareCreator[] = [ModifiedMiddleware.create, PrivateMiddleware.create]
|
const middlewares: MiddlewareCreator[] = [ModifiedMiddleware.create, PrivateMiddleware.create]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user