mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
Introduce image cropper (#805)
Signed-off-by: Ilya Sumbatyants <ilya.sumb@gmail.com>
This commit is contained in:
parent
0567bdbb31
commit
2bccea9078
@ -34,6 +34,8 @@ specifiers:
|
||||
'@rush-temp/gmail': file:./projects/gmail.tgz
|
||||
'@rush-temp/gmail-assets': file:./projects/gmail-assets.tgz
|
||||
'@rush-temp/gmail-resources': file:./projects/gmail-resources.tgz
|
||||
'@rush-temp/image-cropper': file:./projects/image-cropper.tgz
|
||||
'@rush-temp/image-cropper-resources': file:./projects/image-cropper-resources.tgz
|
||||
'@rush-temp/lead': file:./projects/lead.tgz
|
||||
'@rush-temp/lead-assets': file:./projects/lead-assets.tgz
|
||||
'@rush-temp/lead-resources': file:./projects/lead-resources.tgz
|
||||
@ -127,6 +129,7 @@ specifiers:
|
||||
commander: ^8.1.0
|
||||
compression-webpack-plugin: ~9.0.0
|
||||
cors: ^2.8.5
|
||||
cropperjs: ~1.5.12
|
||||
cross-env: ^7.0.3
|
||||
css-loader: ^5.2.1
|
||||
deep-equal: ^2.0.5
|
||||
@ -163,6 +166,7 @@ specifiers:
|
||||
sass: ^1.37.5
|
||||
sass-loader: ^12.1.0
|
||||
simplytyped: ^3.3.0
|
||||
smartcrop: ~2.0.5
|
||||
style-loader: ^3.2.1
|
||||
svelte-check: ^2.2.10
|
||||
svelte-preprocess: ^4.7.4
|
||||
@ -211,6 +215,8 @@ dependencies:
|
||||
'@rush-temp/gmail': file:projects/gmail.tgz
|
||||
'@rush-temp/gmail-assets': file:projects/gmail-assets.tgz
|
||||
'@rush-temp/gmail-resources': file:projects/gmail-resources.tgz_096c09b0b673a57c275d9767a12070b1
|
||||
'@rush-temp/image-cropper': file:projects/image-cropper.tgz
|
||||
'@rush-temp/image-cropper-resources': file:projects/image-cropper-resources.tgz_096c09b0b673a57c275d9767a12070b1
|
||||
'@rush-temp/lead': file:projects/lead.tgz
|
||||
'@rush-temp/lead-assets': file:projects/lead-assets.tgz
|
||||
'@rush-temp/lead-resources': file:projects/lead-resources.tgz_096c09b0b673a57c275d9767a12070b1
|
||||
@ -304,6 +310,7 @@ dependencies:
|
||||
commander: 8.3.0
|
||||
compression-webpack-plugin: 9.0.1_webpack@5.65.0
|
||||
cors: 2.8.5
|
||||
cropperjs: 1.5.12
|
||||
cross-env: 7.0.3
|
||||
css-loader: 5.2.7_webpack@5.65.0
|
||||
deep-equal: 2.0.5
|
||||
@ -340,6 +347,7 @@ dependencies:
|
||||
sass: 1.45.0
|
||||
sass-loader: 12.4.0_sass@1.45.0+webpack@5.65.0
|
||||
simplytyped: 3.3.0_typescript@4.5.4
|
||||
smartcrop: 2.0.5
|
||||
style-loader: 3.3.1_webpack@5.65.0
|
||||
svelte-check: 2.2.11_ac194b5590200ebf8338e0f86ec190f4
|
||||
svelte-preprocess: 4.10.1_3ae2e5fc7d8fb60bbcea513ad0b15c0f
|
||||
@ -3530,6 +3538,10 @@ packages:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
dev: false
|
||||
|
||||
/cropperjs/1.5.12:
|
||||
resolution: {integrity: sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw==}
|
||||
dev: false
|
||||
|
||||
/cross-env/7.0.3:
|
||||
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
|
||||
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
|
||||
@ -8877,6 +8889,10 @@ packages:
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
dev: false
|
||||
|
||||
/smartcrop/2.0.5:
|
||||
resolution: {integrity: sha512-aXoHTM8XlC51g96kgZkYxZ2mx09/ibOrIVLiUNOFozV/MHmFSgEr1/5CKVBoFD5vd+re2wSy0xra21CyjRITzA==}
|
||||
dev: false
|
||||
|
||||
/snapdragon-node/2.1.1:
|
||||
resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -10926,7 +10942,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/contact-resources.tgz_096c09b0b673a57c275d9767a12070b1:
|
||||
resolution: {integrity: sha512-5c2Hkvtnj+3t/r1Z+RFQuoxDwYm6ndTPCxFns6PK3SqCs/KfWREism8tiswJXrB2FNSQkb2CE7yvsftKZFcbPQ==, tarball: file:projects/contact-resources.tgz}
|
||||
resolution: {integrity: sha512-5m/Rr4eGcqsTpvxL8nYdwl7Vn74QrZXdcgIDGbOJaRWh8uXuQBsDIUgE4wCrL49sgOJQEq/dUIfJVA9ndBOd5A==, tarball: file:projects/contact-resources.tgz}
|
||||
id: file:projects/contact-resources.tgz
|
||||
name: '@rush-temp/contact-resources'
|
||||
version: 0.0.0
|
||||
@ -11363,6 +11379,63 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/image-cropper-resources.tgz_096c09b0b673a57c275d9767a12070b1:
|
||||
resolution: {integrity: sha512-ljTYKZOYl34hx76ETCFNAcExK+MP6WSS09tbRRixWxD7SYc7NmBeMntGyZTy3qNu4/jAwNaDAIH52kXQg9ktXQ==, tarball: file:projects/image-cropper-resources.tgz}
|
||||
id: file:projects/image-cropper-resources.tgz
|
||||
name: '@rush-temp/image-cropper-resources'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
|
||||
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
|
||||
cropperjs: 1.5.12
|
||||
eslint: 7.32.0
|
||||
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
|
||||
eslint-plugin-import: 2.25.3_eslint@7.32.0
|
||||
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||
eslint-plugin-svelte3: 3.2.1_eslint@7.32.0+svelte@3.44.3
|
||||
prettier: 2.5.1
|
||||
prettier-plugin-svelte: 2.5.1_prettier@2.5.1+svelte@3.44.3
|
||||
sass: 1.45.0
|
||||
smartcrop: 2.0.5
|
||||
svelte: 3.44.3
|
||||
svelte-check: 2.2.11_4374c622c67ed7479ff0e44c29d09bce
|
||||
svelte-loader: 3.1.2_svelte@3.44.3
|
||||
svelte-preprocess: 4.10.1_14d64cad431e31f100de7363af24a44f
|
||||
typescript: 4.5.4
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- coffeescript
|
||||
- less
|
||||
- node-sass
|
||||
- postcss
|
||||
- postcss-load-config
|
||||
- pug
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/image-cropper.tgz:
|
||||
resolution: {integrity: sha512-7Fj5//tMmR0uKUwcnFrk1KHmI+N+CLNmOiNPApLUtdK7q6clzFT8LMTDZapnbh93NdTCVXa+DxVLwzNGaeqsQA==, tarball: file:projects/image-cropper.tgz}
|
||||
name: '@rush-temp/image-cropper'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@rushstack/heft': 0.41.8
|
||||
'@types/heft-jest': 1.0.2
|
||||
'@typescript-eslint/eslint-plugin': 5.7.0_c25e8c1f4f4f7aaed27aa6f9ce042237
|
||||
'@typescript-eslint/parser': 5.7.0_eslint@7.32.0+typescript@4.5.4
|
||||
eslint: 7.32.0
|
||||
eslint-config-standard-with-typescript: 21.0.1_ce2fa0c4dfa1c256100cababd749a13a
|
||||
eslint-plugin-import: 2.25.3_eslint@7.32.0
|
||||
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||
eslint-plugin-promise: 5.2.0_eslint@7.32.0
|
||||
prettier: 2.5.1
|
||||
typescript: 4.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
file:projects/lead-assets.tgz:
|
||||
resolution: {integrity: sha512-cRYB8PutP6HmaJjoEMLIEyMQEhKAQaCu0w2NJMF5TUW9vokia/22TXsHo1+xEGI1rx2epywbGXet/fL40tdbDw==, tarball: file:projects/lead-assets.tgz}
|
||||
name: '@rush-temp/lead-assets'
|
||||
@ -12045,7 +12118,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/presentation.tgz_096c09b0b673a57c275d9767a12070b1:
|
||||
resolution: {integrity: sha512-tpa5gk8H/quPYXkpBhp5jS0bp/E+Jk7mTGhfE54q4RTr5LOYGTCg2HKmxZWqRV1N3g1Jk7nKAZHWMxMSGHCuKw==, tarball: file:projects/presentation.tgz}
|
||||
resolution: {integrity: sha512-QhfoHLyegkl3JsleXaZkSWsVQgikJM9jdqkla2mRW3kHyQAYWPBITUnVVWu1qBADViJupNZdYmYEcm7oeMF5og==, tarball: file:projects/presentation.tgz}
|
||||
id: file:projects/presentation.tgz
|
||||
name: '@rush-temp/presentation'
|
||||
version: 0.0.0
|
||||
@ -12081,7 +12154,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/prod.tgz_sass@1.45.0+typescript@4.5.4:
|
||||
resolution: {integrity: sha512-XgKxpfDD6oNTIijCj64CrOXM6sYgZhDuDoy5wWIrr/4Y5QFn7TWpOnSjIgmIXMtLUCGk4L55CAZBK+okRGX25Q==, tarball: file:projects/prod.tgz}
|
||||
resolution: {integrity: sha512-7OeW4OKQlYw/FrF1rSmbwacpTXSVzNnIPCb/mIP/Q4Kc+uxroItvCRRYUqVH/V9u8W7nyTE7CjDM+KrADL/BAg==, tarball: file:projects/prod.tgz}
|
||||
id: file:projects/prod.tgz
|
||||
name: '@rush-temp/prod'
|
||||
version: 0.0.0
|
||||
|
@ -88,6 +88,8 @@
|
||||
"@anticrm/lead-resources": "~0.6.0",
|
||||
"@anticrm/gmail": "~0.6.0",
|
||||
"@anticrm/gmail-assets": "~0.6.0",
|
||||
"@anticrm/gmail-resources": "~0.6.0"
|
||||
"@anticrm/gmail-resources": "~0.6.0",
|
||||
"@anticrm/image-cropper": "~0.6.0",
|
||||
"@anticrm/image-cropper-resources": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import { attachmentId } from '@anticrm/attachment'
|
||||
import { leadId } from '@anticrm/lead'
|
||||
import { clientId } from '@anticrm/client'
|
||||
import { gmailId } from '@anticrm/gmail'
|
||||
import { imageCropperId } from '@anticrm/image-cropper'
|
||||
|
||||
import '@anticrm/login-assets'
|
||||
import '@anticrm/task-assets'
|
||||
@ -71,4 +72,5 @@ export async function configurePlatform() {
|
||||
addLocation(telegramId, () => import(/* webpackChunkName: "telegram" */ '@anticrm/telegram-resources'))
|
||||
addLocation(attachmentId, () => import(/* webpackChunkName: "attachment" */ '@anticrm/attachment-resources'))
|
||||
addLocation(gmailId, () => import(/* webpackChunkName: "gmail" */ '@anticrm/gmail-resources'))
|
||||
addLocation(imageCropperId, () => import(/* webpackChunkName: "image-cropper" */ '@anticrm/image-cropper-resources'))
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"svelte": "^3.37.0",
|
||||
"@anticrm/contact": "~0.6.2",
|
||||
"@anticrm/login": "~0.6.1"
|
||||
"@anticrm/login": "~0.6.1",
|
||||
"@anticrm/image-cropper": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,22 @@
|
||||
<script lang="ts">
|
||||
import Avatar from './icons/Avatar.svelte'
|
||||
|
||||
import { getFileUrl } from '../utils'
|
||||
import { getBlobURL, getFileUrl } from '../utils'
|
||||
|
||||
export let avatar: string | undefined = undefined
|
||||
export let direct: Blob | undefined = undefined
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
|
||||
$: url = avatar ? getFileUrl(avatar) : undefined
|
||||
let url: string | undefined
|
||||
$: if (direct !== undefined) {
|
||||
getBlobURL(direct).then((blobURL) => {
|
||||
url = blobURL
|
||||
})
|
||||
} else if (avatar !== undefined) {
|
||||
url = getFileUrl(avatar)
|
||||
} else {
|
||||
url = undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ava-{size} flex-center avatar-container" class:no-img={!url}>
|
||||
|
88
packages/presentation/src/components/EditAvatarPopup.svelte
Normal file
88
packages/presentation/src/components/EditAvatarPopup.svelte
Normal file
@ -0,0 +1,88 @@
|
||||
<!--
|
||||
// Copyright © 2021, 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { Button } from '@anticrm/ui'
|
||||
import imageCropper from '@anticrm/image-cropper'
|
||||
|
||||
export let file: File
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const CropperP = getResource(imageCropper.component.Cropper)
|
||||
let cropper: any
|
||||
|
||||
async function onCrop () {
|
||||
const res = await cropper.crop()
|
||||
|
||||
dispatch('close', res)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="overlay" on:click={() => { dispatch('close') }} />
|
||||
<div class="root">
|
||||
{#await CropperP then Cropper}
|
||||
<div class="cropper">
|
||||
<Cropper bind:this={cropper} image={file} />
|
||||
</div>
|
||||
<div class="footer ml-6 mr-6 mt-4 mb-4">
|
||||
<Button label={"Save"} primary on:click={onCrop} />
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
|
||||
background: var(--theme-menu-color);
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.root {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
overflow: auto;
|
||||
|
||||
width: 75vw;
|
||||
height: 75vh;
|
||||
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
background: var(--theme-bg-color);
|
||||
border-radius: 1.25rem;
|
||||
box-shadow: 0px 44px 154px rgba(0, 0, 0, .75);
|
||||
|
||||
display: grid;
|
||||
grid-template-rows: minmax(min-content, 1fr) auto;
|
||||
}
|
||||
|
||||
.cropper {
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
</style>
|
58
packages/presentation/src/components/EditableAvatar.svelte
Normal file
58
packages/presentation/src/components/EditableAvatar.svelte
Normal file
@ -0,0 +1,58 @@
|
||||
<!--
|
||||
// Copyright © 2021, 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { showPopup } from '@anticrm/ui'
|
||||
|
||||
import Avatar from './Avatar.svelte'
|
||||
import EditAvatarPopup from './EditAvatarPopup.svelte'
|
||||
|
||||
export let avatar: string | undefined = undefined
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let inputRef: HTMLInputElement
|
||||
const targetMimes = ['image/png', 'image/jpg', 'image/jpeg']
|
||||
function onClick () {
|
||||
inputRef.click()
|
||||
}
|
||||
|
||||
let direct: Blob | undefined
|
||||
|
||||
function onSelect (e: any) {
|
||||
const file = e.target?.files[0] as File | undefined
|
||||
if (file === undefined || !targetMimes.includes(file.type)) {
|
||||
return
|
||||
}
|
||||
|
||||
showPopup(EditAvatarPopup, { file }, undefined, (blob) => {
|
||||
if (blob === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
direct = blob
|
||||
dispatch('done', { file: new File([blob], file.name) })
|
||||
})
|
||||
e.target.value = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="cursor-pointer" on:click={onClick}>
|
||||
<Avatar {avatar} {direct} {size} />
|
||||
<input style="display: none;" type="file" bind:this={inputRef} on:change={onSelect} accept={targetMimes.join(',')}/>
|
||||
</div>
|
@ -23,6 +23,7 @@ export * from './attributes'
|
||||
export { default as UserBox } from './components/UserBox.svelte'
|
||||
export { default as UserInfo } from './components/UserInfo.svelte'
|
||||
export { default as Avatar } from './components/Avatar.svelte'
|
||||
export { default as EditableAvatar } from './components/EditableAvatar.svelte'
|
||||
export { default as MessageViewer } from './components/MessageViewer.svelte'
|
||||
export { default as AttributesBar } from './components/AttributesBar.svelte'
|
||||
export { default as AttributeBarEditor } from './components/AttributeBarEditor.svelte'
|
||||
|
@ -114,6 +114,15 @@ export function getFileUrl (file: string): string {
|
||||
return url
|
||||
}
|
||||
|
||||
export async function getBlobURL (blob: Blob): Promise<string> {
|
||||
return await new Promise((resolve) => {
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.addEventListener('load', () => resolve(reader.result as string), false)
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -38,7 +38,7 @@
|
||||
async function createAttachment (file: File) {
|
||||
loading++
|
||||
try {
|
||||
const uuid = await uploadFile(space, file, objectId)
|
||||
const uuid = await uploadFile(file, space, objectId)
|
||||
console.log('uploaded file uuid', uuid)
|
||||
client.addCollection(attachment.class.Attachment, space, objectId, _class, 'attachments', {
|
||||
name: file.name,
|
||||
|
@ -17,6 +17,7 @@ import AttachmentsPresenter from './components/AttachmentsPresenter.svelte'
|
||||
import AttachmentPresenter from './components/AttachmentPresenter.svelte'
|
||||
import TxAttachmentCreate from './components/activity/TxAttachmentCreate.svelte'
|
||||
import Attachments from './components/Attachments.svelte'
|
||||
import { uploadFile } from './utils'
|
||||
|
||||
export { Attachments, AttachmentsPresenter }
|
||||
|
||||
@ -28,5 +29,8 @@ export default async () => ({
|
||||
},
|
||||
activity: {
|
||||
TxAttachmentCreate
|
||||
},
|
||||
helper: {
|
||||
UploadFile: uploadFile
|
||||
}
|
||||
})
|
||||
|
@ -18,14 +18,19 @@ import type { Doc, Ref, Space } from '@anticrm/core'
|
||||
import login from '@anticrm/login'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
|
||||
export async function uploadFile (space: Ref<Space>, file: File, attachedTo: Ref<Doc>): Promise<string> {
|
||||
export async function uploadFile (file: File, space?: Ref<Space>, attachedTo?: Ref<Doc>): Promise<string> {
|
||||
console.log(file)
|
||||
const uploadUrl = getMetadata(login.metadata.UploadUrl)
|
||||
|
||||
const data = new FormData()
|
||||
data.append('file', file)
|
||||
|
||||
const url = `${uploadUrl as string}?space=${space}&name=${encodeURIComponent(file.name)}&attachedTo=${attachedTo}`
|
||||
const params = [['space', space], ['attachedTo', attachedTo]]
|
||||
.filter((x): x is [string, Ref<any>] => x[1] !== undefined)
|
||||
.map(([name, value]) => `${name}=${value}`)
|
||||
.join('&')
|
||||
|
||||
const url = `${uploadUrl as string}?name=${encodeURIComponent(file.name)}&${params}`
|
||||
const resp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Ref, Class, AttachedDoc } from '@anticrm/core'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Ref, Class, AttachedDoc, Space, Doc } from '@anticrm/core'
|
||||
import { plugin, Resource } from '@anticrm/platform'
|
||||
import type { Asset, Plugin } from '@anticrm/platform'
|
||||
import { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
@ -44,5 +44,8 @@ export default plugin(attachmentId, {
|
||||
},
|
||||
class: {
|
||||
Attachment: '' as Ref<Class<Attachment>>
|
||||
},
|
||||
helper: {
|
||||
UploadFile: '' as Resource<(file: File, space?: Ref<Space>, attachedTo?: Ref<Doc>) => Promise<string>>
|
||||
}
|
||||
})
|
||||
|
@ -41,6 +41,7 @@
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/attachment-resources": "~0.6.0",
|
||||
"@anticrm/panel": "~0.6.0",
|
||||
"@anticrm/view-resources": "~0.6.0"
|
||||
"@anticrm/view-resources": "~0.6.0",
|
||||
"@anticrm/attachment": "~0.6.1"
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,11 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { Data } from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform';
|
||||
|
||||
import { getClient, Card, Channels, Avatar } from '@anticrm/presentation'
|
||||
import { getClient, Card, Channels, EditableAvatar } from '@anticrm/presentation'
|
||||
|
||||
import attachment from '@anticrm/attachment'
|
||||
import { EditBox, showPopup, CircleButton, IconEdit, IconAdd, Label } from '@anticrm/ui'
|
||||
import SocialEditor from './SocialEditor.svelte'
|
||||
|
||||
@ -37,10 +39,25 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
let avatar: File | undefined
|
||||
|
||||
function onAvatarDone (e: any) {
|
||||
const { file } = e.detail
|
||||
|
||||
avatar = file
|
||||
}
|
||||
|
||||
async function createPerson () {
|
||||
const uploadFile = await getResource(attachment.helper.UploadFile)
|
||||
const avatarUUID = avatar !== undefined
|
||||
? await uploadFile(avatar)
|
||||
: undefined
|
||||
|
||||
console.warn('avatar', avatar, avatarUUID)
|
||||
const person: Data<Person> = {
|
||||
name: combineName(firstName, lastName),
|
||||
city: object.city,
|
||||
avatar: avatarUUID,
|
||||
channels: object.channels
|
||||
}
|
||||
|
||||
@ -61,7 +78,7 @@
|
||||
>
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-4">
|
||||
<Avatar avatar={object.avatar} size={'large'} />
|
||||
<EditableAvatar avatar={object.avatar} size={'large'} on:done={onAvatarDone} />
|
||||
</div>
|
||||
<div class="flex-col">
|
||||
<div class="fs-title"><EditBox placeholder="John" maxWidth="12rem" bind:value={firstName} label={undefined} /></div>
|
||||
|
@ -16,8 +16,10 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount, afterUpdate } from 'svelte'
|
||||
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
|
||||
import { getClient, createQuery, Channels, Avatar, AttributeEditor } from '@anticrm/presentation'
|
||||
import { CircleButton, EditBox, showPopup, IconAdd, Label, IconActivity } from '@anticrm/ui'
|
||||
import { getClient, createQuery, Channels, EditableAvatar, AttributeEditor } from '@anticrm/presentation'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import attachment from '@anticrm/attachment'
|
||||
import setting from '@anticrm/setting'
|
||||
import { IntegrationType } from '@anticrm/setting'
|
||||
import contact from '../plugin'
|
||||
@ -61,12 +63,22 @@
|
||||
const sendOpen = () => dispatch('open', { ignoreKeys: ['comments', 'name', 'channels', 'city'] })
|
||||
onMount(sendOpen)
|
||||
afterUpdate(sendOpen)
|
||||
|
||||
async function onAvatarDone (e: any) {
|
||||
const uploadFile = await getResource(attachment.helper.UploadFile)
|
||||
const { file: avatar } = e.detail
|
||||
|
||||
const uuid = await uploadFile(avatar)
|
||||
await client.updateDoc(object._class, object.space, object._id, {
|
||||
avatar: uuid
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if object !== undefined}
|
||||
<div class="flex-row-streach flex-grow">
|
||||
<div class="mr-8">
|
||||
<Avatar avatar={object.avatar} size={'x-large'} />
|
||||
<EditableAvatar avatar={object.avatar} size={'x-large'} on:done={onAvatarDone} />
|
||||
</div>
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="flex-grow flex-col">
|
||||
|
7
plugins/image-cropper-resources/.eslintrc.js
Normal file
7
plugins/image-cropper-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
|
||||
}
|
||||
}
|
38
plugins/image-cropper-resources/package.json
Normal file
38
plugins/image-cropper-resources/package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@anticrm/image-cropper-resources",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "echo 'no build for ui'",
|
||||
"build:docs": "api-extractor run --local",
|
||||
"lint": "svelte-check && eslint",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"format": "prettier --write --plugin-search-dir=. src && eslint --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/platform-rig": "~0.6.0",
|
||||
"svelte-loader": "^3.1.2",
|
||||
"sass": "^1.37.5",
|
||||
"svelte-preprocess": "^4.7.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint": "^7.32.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"eslint-plugin-svelte3": "~3.2.1",
|
||||
"prettier-plugin-svelte": "^2.2.0",
|
||||
"prettier": "^2.4.1",
|
||||
"svelte-check": "^2.2.10",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"svelte": "^3.37.0",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"cropperjs": "~1.5.12",
|
||||
"smartcrop": "~2.0.5"
|
||||
}
|
||||
}
|
5
plugins/image-cropper-resources/postcss.config.js
Normal file
5
plugins/image-cropper-resources/postcss.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
102
plugins/image-cropper-resources/src/components/Cropper.svelte
Normal file
102
plugins/image-cropper-resources/src/components/Cropper.svelte
Normal file
@ -0,0 +1,102 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import Cropper from 'cropperjs'
|
||||
import smartcrop from 'smartcrop'
|
||||
|
||||
export let image: File
|
||||
export let cropSize = 1200
|
||||
|
||||
let imgRef: HTMLImageElement
|
||||
let cropper: Cropper | undefined
|
||||
|
||||
async function init () {
|
||||
const bitmap = await createImageBitmap(image)
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.height = bitmap.height
|
||||
canvas.width = bitmap.width
|
||||
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
if (ctx == null) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.drawImage(bitmap, 0, 0)
|
||||
|
||||
imgRef.src = canvas.toDataURL('image/jpeg', 1.0)
|
||||
imgRef.width = bitmap.width
|
||||
imgRef.height = bitmap.height
|
||||
|
||||
const initialArea = (await smartcrop.crop(canvas, { width: 100, height: 100 })).topCrop
|
||||
|
||||
const cropperInst = new Cropper(imgRef, {
|
||||
aspectRatio: 1,
|
||||
viewMode: 1,
|
||||
autoCrop: true,
|
||||
rotatable: false,
|
||||
ready: () => {
|
||||
const imgData = cropperInst.getImageData()
|
||||
const xC = imgData.width / bitmap.width
|
||||
const yC = imgData.height / bitmap.height
|
||||
|
||||
cropperInst.setCropBoxData({
|
||||
left: initialArea.x * xC,
|
||||
top: initialArea.y * yC,
|
||||
height: initialArea.height * yC,
|
||||
width: initialArea.width * yC
|
||||
})
|
||||
cropper = cropperInst
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function crop () {
|
||||
if (cropper === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const res = cropper.getCroppedCanvas({ maxWidth: cropSize, maxHeight: cropSize, imageSmoothingQuality: 'high' })
|
||||
|
||||
return new Promise(
|
||||
(resolve) => res.toBlob(
|
||||
(blob) => {
|
||||
resolve(blob)
|
||||
},
|
||||
'image/jpeg',
|
||||
0.95))
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full h-full flex">
|
||||
<img class="image" bind:this={imgRef} alt="img"/>
|
||||
{#await init()}
|
||||
Waiting...
|
||||
{/await}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'cropperjs/dist/cropper.min.css';
|
||||
|
||||
:global(.cropper-view-box, .cropper-face) {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.image {
|
||||
max-width: 100%;
|
||||
object-fit: contain;
|
||||
display: none;
|
||||
}
|
||||
</style>
|
25
plugins/image-cropper-resources/src/index.ts
Normal file
25
plugins/image-cropper-resources/src/index.ts
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Resources } from '@anticrm/platform'
|
||||
|
||||
import Cropper from './components/Cropper.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
Cropper
|
||||
}
|
||||
})
|
5
plugins/image-cropper-resources/svelte.config.js
Normal file
5
plugins/image-cropper-resources/svelte.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
const sveltePreprocess = require('svelte-preprocess')
|
||||
|
||||
module.exports = {
|
||||
preprocess: sveltePreprocess()
|
||||
};
|
15
plugins/image-cropper-resources/tsconfig.json
Normal file
15
plugins/image-cropper-resources/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"declaration": true,
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
7
plugins/image-cropper/.eslintrc.js
Normal file
7
plugins/image-cropper/.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/image-cropper/.npmignore
Normal file
4
plugins/image-cropper/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
18
plugins/image-cropper/config/rig.json
Normal file
18
plugins/image-cropper/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"
|
||||
}
|
32
plugins/image-cropper/package.json
Normal file
32
plugins/image-cropper/package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@anticrm/image-cropper",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "heft build",
|
||||
"build:watch": "tsc",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"lint": "eslint src",
|
||||
"format": "prettier --write src && eslint --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/platform-rig": "~0.6.0",
|
||||
"@types/heft-jest": "^1.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint": "^7.32.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"prettier": "^2.4.1",
|
||||
"@rushstack/heft": "^0.41.1",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/ui": "~0.6.0"
|
||||
}
|
||||
}
|
29
plugins/image-cropper/src/index.ts
Normal file
29
plugins/image-cropper/src/index.ts
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { Plugin } from '@anticrm/platform'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const imageCropperId = 'image-cropper' as Plugin
|
||||
|
||||
export default plugin(imageCropperId, {
|
||||
component: {
|
||||
Cropper: '' as AnyComponent
|
||||
}
|
||||
})
|
9
plugins/image-cropper/tsconfig.json
Normal file
9
plugins/image-cropper/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"]
|
||||
}
|
||||
}
|
@ -18,13 +18,12 @@
|
||||
import contact, { combineName, Person } from '@anticrm/contact'
|
||||
import type { Data, MixinData, Ref } from '@anticrm/core'
|
||||
import { generateId } from '@anticrm/core'
|
||||
import { setPlatformStatus, unknownError } from '@anticrm/platform'
|
||||
import { Avatar, Card, Channels, getClient, PDFViewer } from '@anticrm/presentation'
|
||||
import { getResource, setPlatformStatus, unknownError } from '@anticrm/platform'
|
||||
import { EditableAvatar, Card, Channels, getClient, PDFViewer } from '@anticrm/presentation'
|
||||
import type { Candidate } from '@anticrm/recruit'
|
||||
import { CircleButton, EditBox, IconAdd, IconFile as FileIcon, Label, Link, showPopup, Spinner } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import recruit from '../plugin'
|
||||
import { uploadFile } from '../utils'
|
||||
import FileUpload from './icons/FileUpload.svelte'
|
||||
import YesNo from './YesNo.svelte'
|
||||
|
||||
@ -50,10 +49,15 @@
|
||||
const candidateId = generateId()
|
||||
|
||||
async function createCandidate () {
|
||||
const uploadFile = await getResource(attachment.helper.UploadFile)
|
||||
const avatarUUID = avatar !== undefined
|
||||
? await uploadFile(avatar)
|
||||
: undefined
|
||||
const candidate: Data<Person> = {
|
||||
name: combineName(firstName, lastName),
|
||||
city: object.city,
|
||||
channels: object.channels
|
||||
channels: object.channels,
|
||||
avatar: avatarUUID
|
||||
}
|
||||
const candidateData: MixinData<Person, Candidate> = {
|
||||
title: object.title,
|
||||
@ -86,7 +90,9 @@
|
||||
async function createAttachment (file: File) {
|
||||
loading = true
|
||||
try {
|
||||
resume.uuid = await uploadFile(space, file, candidateId)
|
||||
const uploadFile = await getResource(attachment.helper.UploadFile)
|
||||
|
||||
resume.uuid = await uploadFile(file, space, candidateId)
|
||||
resume.name = file.name
|
||||
resume.size = file.size
|
||||
resume.type = file.type
|
||||
@ -111,6 +117,15 @@
|
||||
const file = inputFile.files?.[0]
|
||||
if (file !== undefined) { createAttachment(file) }
|
||||
}
|
||||
|
||||
let avatar: File | undefined
|
||||
|
||||
function onAvatarDone (e: any) {
|
||||
const { file } = e.detail
|
||||
|
||||
avatar = file
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- <DialogHeader {space} {object} {newValue} {resume} create={true} on:save={createCandidate}/> -->
|
||||
@ -124,7 +139,7 @@
|
||||
<!-- <StatusComponent slot="error" status={{ severity: Severity.ERROR, code: 'Can’t save the object because it already exists' }} /> -->
|
||||
<div class="flex-row-center">
|
||||
<div class="mr-4">
|
||||
<Avatar avatar={object.avatar} size={'large'} />
|
||||
<EditableAvatar avatar={object.avatar} size={'large'} on:done={onAvatarDone}/>
|
||||
</div>
|
||||
<div class="flex-col">
|
||||
<div class="fs-title"><EditBox placeholder="John" maxWidth="10rem" bind:value={firstName}/></div>
|
||||
|
@ -1,43 +0,0 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Ref, Doc, Space } from '@anticrm/core'
|
||||
import { getMetadata, PlatformError } from '@anticrm/platform'
|
||||
|
||||
import login from '@anticrm/login'
|
||||
|
||||
export async function uploadFile(space: Ref<Space>, file: File, attachedTo: Ref<Doc>): Promise<string> {
|
||||
console.log(file)
|
||||
const uploadUrl = getMetadata(login.metadata.UploadUrl)
|
||||
|
||||
const data = new FormData()
|
||||
data.append('file', file)
|
||||
|
||||
const url = `${uploadUrl}?space=${space}&name=${encodeURIComponent(file.name)}&attachedTo=${attachedTo}`
|
||||
const resp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + getMetadata(login.metadata.LoginToken)
|
||||
},
|
||||
body: data
|
||||
})
|
||||
if (resp.status !== 200) {
|
||||
throw new Error('Can\'t upload file.')
|
||||
}
|
||||
const uuid = await resp.text()
|
||||
console.log(uuid)
|
||||
return uuid
|
||||
}
|
10
rush.json
10
rush.json
@ -691,6 +691,16 @@
|
||||
"projectFolder": "models/demo",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/image-cropper",
|
||||
"projectFolder": "plugins/image-cropper",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/image-cropper-resources",
|
||||
"projectFolder": "plugins/image-cropper-resources",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/dev-server-chunter-resources",
|
||||
"projectFolder": "dev/server-chunter-resources",
|
||||
|
@ -159,9 +159,9 @@ export function start (config: { transactorEndpoint: string, elasticUrl: string,
|
||||
const uuid = await minioUpload(config.minio, payload.workspace, file)
|
||||
console.log('uploaded uuid', uuid)
|
||||
|
||||
const name = req.query.name as string
|
||||
const space = req.query.space as Ref<Space>
|
||||
const attachedTo = req.query.attachedTo as Ref<Doc>
|
||||
const name = req.query.name as string | undefined
|
||||
const space = req.query.space as Ref<Space> | undefined
|
||||
const attachedTo = req.query.attachedTo as Ref<Doc> | undefined
|
||||
// const name = req.query.name as string
|
||||
|
||||
// await createAttachment(
|
||||
@ -175,20 +175,22 @@ export function start (config: { transactorEndpoint: string, elasticUrl: string,
|
||||
// fileId
|
||||
// )
|
||||
|
||||
const elastic = await createElasticAdapter(config.elasticUrl, payload.workspace)
|
||||
if (name !== undefined && space !== undefined && attachedTo !== undefined) {
|
||||
const elastic = await createElasticAdapter(config.elasticUrl, payload.workspace)
|
||||
|
||||
const indexedDoc: IndexedDoc = {
|
||||
id: generateId() + '/attachments/' + name as Ref<Doc>,
|
||||
_class: attachment.class.Attachment,
|
||||
space,
|
||||
modifiedOn: Date.now(),
|
||||
modifiedBy: 'core:account:System' as Ref<Account>,
|
||||
attachedTo,
|
||||
data: file.data.toString('base64')
|
||||
const indexedDoc: IndexedDoc = {
|
||||
id: generateId() + '/attachments/' + name as Ref<Doc>,
|
||||
_class: attachment.class.Attachment,
|
||||
space,
|
||||
modifiedOn: Date.now(),
|
||||
modifiedBy: 'core:account:System' as Ref<Account>,
|
||||
attachedTo,
|
||||
data: file.data.toString('base64')
|
||||
}
|
||||
|
||||
await elastic.index(indexedDoc)
|
||||
}
|
||||
|
||||
await elastic.index(indexedDoc)
|
||||
|
||||
res.status(200).send(uuid)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
|
Loading…
Reference in New Issue
Block a user