Rework Attachments as a bag (#193)

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov
2021-09-15 19:03:34 +02:00
committed by GitHub
parent 74d46558f1
commit bf9f479500
27 changed files with 923 additions and 833 deletions
+2 -3
View File
@@ -15,7 +15,7 @@
import { plugin } from '@anticrm/platform'
import type { Asset, Plugin } from '@anticrm/platform'
import type { Space, Doc, Ref, Class, AttachedDoc } from '@anticrm/core'
import type { Space, Obj, Doc, Ref, Class, AttachedDoc } from '@anticrm/core'
/**
* @public
@@ -47,8 +47,7 @@ export interface Backlink extends Comment {
/**
* @public
*/
export interface Attachment extends AttachedDoc {
collection: string
export interface Attachment extends Obj {
name: string
file: string
size: number
@@ -29,7 +29,7 @@ async function onClick() {
const clazz = hierarchy.getClass(value._class)
const editorMixin = hierarchy.as(clazz, view.mixin.ObjectEditor)
const editor = await getResource(editorMixin.editor)
showPopup(editor, { object: value }, 'full')
showPopup(editor, { _id: value._id }, 'full')
}
</script>
@@ -14,9 +14,10 @@
-->
<script lang="ts">
import { CircleButton, IconAdd, showPopup } from '@anticrm/ui'
import { CircleButton, IconAdd, showPopup, Spinner } from '@anticrm/ui'
import type { Doc, Ref, Space } from '@anticrm/core'
import type { Doc, Ref, Space, Class, Bag } from '@anticrm/core'
import { setPlatformStatus, unknownError } from '@anticrm/platform'
import { generateId } from '@anticrm/core'
import { createQuery, getClient } from '@anticrm/presentation'
import type { Attachment } from '@anticrm/chunter'
@@ -26,13 +27,14 @@
import chunter from '@anticrm/chunter'
export let object: Doc
// export let space: Ref<Space>
export let objectId: Ref<Doc & { attachments: Bag<Attachment> }>
export let space: Ref<Space>
export let _class: Ref<Class<Doc & { attachments: Bag<Attachment> }>>
let files: Attachment[] = []
export let object: Doc & { attachments: Bag<Attachment> } | undefined = undefined
const query = createQuery()
$: query.query(chunter.class.Attachment, { attachedTo: object._id }, result => { files = result})
// const query = createQuery()
// $: query.query(_class, { _id: objectId }, result => { object = result[0] })
let inputFile: HTMLInputElement
let loading = false
@@ -40,20 +42,19 @@
const client = getClient()
async function createAttachment(file: File) {
console.log('CREATE ATTACHMENT')
loading = true
try {
const id = generateId<Attachment>()
const uuid = await uploadFile(id, object.space, file, object._id)
const uuid = await uploadFile(space, file, objectId)
console.log('uploaded file uuid', uuid)
client.createDoc(chunter.class.Attachment, object.space, {
attachedTo: object._id,
collection: 'attachment',
client.putBag(_class, space, objectId, 'attachments', encodeURIComponent(uuid), {
_class: chunter.class.Attachment,
name: file.name,
file: uuid,
type: file.type,
size: file.size,
})
})
} catch (err: any) {
setPlatformStatus(unknownError(err))
} finally {
loading = false
}
@@ -70,10 +71,14 @@
<div class="attachments-container">
<div class="flex-row-center">
<span class="title">Attachments</span>
<a href={'#'} on:click={ () => { inputFile.click() } }><CircleButton icon={IconAdd} size={'small'} /></a>
{#if loading}
<Spinner/>
{:else}
<a href={'#'} on:click={ () => { inputFile.click() } }><CircleButton icon={IconAdd} size={'small'} /></a>
{/if}
<input bind:this={inputFile} type="file" name="file" id="file" style="display: none" on:change={fileSelected}/>
</div>
{#if files.length > 0}
{#if object?.attachments !== undefined}
<table class="table-body">
<thead>
<tr class="tr-head">
@@ -82,7 +87,7 @@
</tr>
</thead>
<tbody>
{#each files as file}
{#each Object.values(object.attachments) as file}
<tr class="tr-body">
<td class="item flex-row-center">
<div class="flex-center file-icon">pdf</div>
@@ -15,8 +15,9 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import type { Ref, Space } from '@anticrm/core'
import type { Ref, Space, Data } from '@anticrm/core'
import { generateId } from '@anticrm/core'
import { setPlatformStatus, unknownError } from '@anticrm/platform'
import { getClient, Card, Channels } from '@anticrm/presentation'
import { uploadFile } from '../utils'
@@ -26,7 +27,7 @@
import type { Candidate } from '@anticrm/recruit'
import type { Attachment } from '@anticrm/chunter'
import { EditBox, Link, showPopup, Component, CircleButton, IconFile as FileIcon } from '@anticrm/ui'
import { EditBox, Link, showPopup, Component, CircleButton, IconFile as FileIcon, Spinner } from '@anticrm/ui'
import FileUpload from './icons/FileUpload.svelte'
import Avatar from './icons/Avatar.svelte'
import Edit from './icons/Edit.svelte'
@@ -49,7 +50,6 @@
} as Candidate
let resume = {} as {
id: Ref<Attachment> | undefined
name: string
uuid: string
size: number
@@ -58,36 +58,46 @@
const dispatch = createEventDispatcher()
const client = getClient()
const candidateId = generateId<Candidate>()
const candidateId = generateId()
async function createCandidate() {
console.log(_space)
// create candidate
await client.createDoc(recruit.class.Candidate, _space, {
const candidate: Data<Candidate> = {
firstName: object.firstName,
lastName: object.lastName,
city: object.city,
channels: object.channels,
}, candidateId)
attachments: {}
}
if (resume.uuid !== undefined) {
candidate.attachments[encodeURIComponent(resume.uuid)] = {
_class: chunter.class.Attachment,
name: resume.name,
file: resume.uuid,
size: resume.size,
type: resume.type
}
}
await client.createDoc(recruit.class.Candidate, _space, candidate, candidateId)
console.log('resume name', resume.name)
if (resume.id !== undefined) {
// create attachment
console.log('creaing attachment space', _space)
client.createDoc(chunter.class.Attachment, _space, {
attachedTo: candidateId,
collection: 'resume',
name: resume.name,
file: resume.uuid,
type: resume.type,
size: resume.size,
}, resume.id)
// if (resume.id !== undefined) {
// // create attachment
// console.log('creaing attachment space', _space)
// client.createDoc(chunter.class.Attachment, _space, {
// attachedTo: candidateId,
// collection: 'resume',
// name: resume.name,
// file: resume.uuid,
// type: resume.type,
// size: resume.size,
// }, resume.id)
client.updateDoc(recruit.class.Candidate, _space, candidateId, {
resume: resume.id
})
}
// client.updateDoc(recruit.class.Candidate, _space, candidateId, {
// resume: resume.id
// })
// }
dispatch('close')
}
@@ -98,17 +108,14 @@
async function createAttachment(file: File) {
loading = true
try {
const id = generateId<Attachment>()
resume.uuid = await uploadFile(id, space, file, candidateId)
resume.id = id
resume.uuid = await uploadFile(space, file, candidateId)
resume.name = file.name
resume.size = file.size
resume.type = file.type
object.resume = id
console.log('uploaded file uuid', resume.uuid)
} catch (err: any) {
setPlatformStatus(unknownError(err))
} finally {
loading = false
}
@@ -154,10 +161,15 @@
<div class="name"><EditBox placeholder="Appleseed" maxWidth="9.5rem" bind:value={object.lastName}/></div>
<div class="city"><EditBox placeholder="Location" maxWidth="9.5rem" bind:value={object.city}/></div>
<div class="flex resume">
{#if resume.id}
{#if resume.uuid}
<Link label={resume.name} href={'#'} icon={FileIcon} on:click={ () => { showPopup(PDFViewer, { file: resume.uuid }, 'right') } }/>
{:else}
<a href={'#'} on:click={ () => { inputFile.click() } }>Upload resume</a>
{#if loading}
<Spinner/> Uploading...
{:else}
<FileUpload size='small'/>
<a href={'#'} on:click={ () => { inputFile.click() } }>Upload resume</a>
{/if}
<input bind:this={inputFile} type="file" name="file" id="file" style="display: none" on:change={fileSelected}/>
{/if}
</div>
@@ -15,14 +15,14 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import type { Ref, Space, Doc } from '@anticrm/core'
import type { Ref, Space, Doc, Class } from '@anticrm/core'
import { CircleButton, EditBox, Link, showPopup, IconFile as FileIcon } from '@anticrm/ui'
import type { Attachment } from '@anticrm/chunter'
import FileUpload from './icons/FileUpload.svelte'
import PDFViewer from './PDFViewer.svelte'
import { getClient, Channels, AttributeEditor } from '@anticrm/presentation'
import { getClient, createQuery, Channels, AttributeEditor } from '@anticrm/presentation'
import { Panel } from '@anticrm/panel'
import type { Candidate } from '@anticrm/recruit'
import type { Candidate, Candidate } from '@anticrm/recruit'
import DialogHeader from './DialogHeader.svelte'
import Contact from './icons/Contact.svelte'
import Avatar from './icons/Avatar.svelte'
@@ -34,10 +34,14 @@
import recruit from '../plugin'
export let object: Candidate
export let _id: Ref<Candidate>
let object: Candidate
const client = getClient()
const query = createQuery()
$: query.query(recruit.class.Candidate, { _id }, result => { object = result[0] })
const dispatch = createEventDispatcher()
function saveChannels(result: any) {
@@ -47,6 +51,7 @@
</script>
{#if object !== undefined}
<Panel icon={Contact} title={object.firstName + ' ' + object.lastName} {object} on:close={() => { dispatch('close') }}>
<svelte:fragment slot="subtitle">
<div class="flex-between flex-reverse" style="width: 100%">
@@ -69,10 +74,11 @@
</div>
<div class="attachments">
<Attachments {object}/>
<Attachments objectId={object._id} _class={object._class} space={object.space} {object}/>
</div>
</Panel>
{/if}
<style lang="scss">
@import '../../../../packages/theme/styles/mixins.scss';
+6 -3
View File
@@ -15,18 +15,18 @@
//
import type { Ref, Doc, Space } from '@anticrm/core'
import { getMetadata } from '@anticrm/platform'
import { getMetadata, PlatformError } from '@anticrm/platform'
import login from '@anticrm/login'
export async function uploadFile(id: Ref<Doc>, space: Ref<Space>, file: File, attachedTo: Ref<Doc>): Promise<string> {
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}?id=${id}&space=${space}&attachedTo=${attachedTo}`
const url = `${uploadUrl}?space=${space}&name=${encodeURIComponent(file.name)}&attachedTo=${attachedTo}`
const resp = await fetch(url, {
method: 'POST',
headers: {
@@ -34,6 +34,9 @@ export async function uploadFile(id: Ref<Doc>, space: Ref<Space>, file: File, at
},
body: data
})
if (resp.status !== 200) {
throw new Error('Can\t upload file.')
}
const uuid = await resp.text()
console.log(uuid)
return uuid
+2 -2
View File
@@ -15,7 +15,7 @@
import { plugin } from '@anticrm/platform'
import type { Plugin, Asset } from '@anticrm/platform'
import type { Space, Doc, Ref, State } from '@anticrm/core'
import type { Space, Doc, Ref, State, Bag } from '@anticrm/core'
import type { Person } from '@anticrm/contact'
import type { Attachment } from '@anticrm/chunter'
@@ -33,8 +33,8 @@ export interface Candidates extends Space {}
* @public
*/
export interface Candidate extends Person {
resume?: Ref<Attachment>
title?: string
attachments: Bag<Attachment>
}
/**