mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 03:22:19 +03:00
Rework Attachments as a bag (#193)
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
parent
74d46558f1
commit
bf9f479500
@ -1,2 +1,2 @@
|
||||
|
||||
helm upgrade dev --set master.persistence.size=10Gi,data.persistence.size=10Gi,image.repository=anticrm/elasticsearch,ingest.enabled=true,data.heapSize=4096m,master.heapSize=256m,coordinating.heapSize=256m bitnami/elasticsearch
|
||||
helm upgrade dev --set master.persistence.size=10Gi,data.persistence.size=10Gi,image.repository=anticrm/elasticsearch,ingest.enabled=true,data.heapSize=8192m,master.heapSize=1024m,coordinating.heapSize=1024m bitnami/elasticsearch
|
||||
|
@ -2,6 +2,6 @@
|
||||
CLIENT_TYPE=dev
|
||||
ACCOUNTS_URL=/account
|
||||
UPLOAD_URL=/upload
|
||||
LOGIN_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6InJvc2FtdW5kQGhjLmVuZ2luZWVyaW5nIiwid29ya3NwYWNlIjoid3MxIn0.crxqT7QUkpZiTmmxouB40LpMwK2CfTf76XqPFWIMyic
|
||||
LOGIN_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6InJvc2FtdW5kQGhjLmVuZ2luZWVyaW5nIiwid29ya3NwYWNlIjoidHJ4NDAifQ.dYsCF2VRbuc-zmRt0yLAww1_--xtX4P1EqPFREEzCjQ
|
||||
# LOGIN_ENDPOINT=ws://localhost:3333
|
||||
LOGIN_ENDPOINT=wss://transactor.hc.engineering/
|
||||
|
@ -18,7 +18,7 @@ import { start } from '.'
|
||||
|
||||
import { encode } from 'jwt-simple'
|
||||
|
||||
const token = encode({ email: 'rosamund@hc.engineering', workspace: 'ws1' }, 'secret')
|
||||
const token = encode({ email: 'rosamund@hc.engineering', workspace: 'trx40' }, 'secret')
|
||||
console.log(token)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@ import type { IntlString } from '@anticrm/platform'
|
||||
import { Builder, Model, Prop, UX, TypeString, Index } from '@anticrm/model'
|
||||
import type { Ref, Doc, Class, Domain } from '@anticrm/core'
|
||||
import { IndexKind } from '@anticrm/core'
|
||||
import core, { TSpace, TDoc } from '@anticrm/model-core'
|
||||
import core, { TSpace, TDoc, TObj } from '@anticrm/model-core'
|
||||
import type { Backlink, Channel, Message, Comment, Attachment } from '@anticrm/chunter'
|
||||
import type { AnyComponent } from '@anticrm/ui'
|
||||
|
||||
@ -55,10 +55,8 @@ export class TBacklink extends TComment implements Backlink {
|
||||
backlinkClass!: Ref<Class<Doc>>
|
||||
}
|
||||
|
||||
@Model(chunter.class.Attachment, core.class.Doc, DOMAIN_ATTACHMENT)
|
||||
export class TAttachment extends TDoc implements Attachment {
|
||||
attachedTo!: Ref<Doc>
|
||||
collection!: string
|
||||
@Model(chunter.class.Attachment, core.class.Obj, DOMAIN_ATTACHMENT)
|
||||
export class TAttachment extends TObj implements Attachment {
|
||||
name!: string
|
||||
file!: string
|
||||
size!: number
|
||||
|
@ -17,7 +17,7 @@ import { Builder } from '@anticrm/model'
|
||||
import core from './component'
|
||||
import { TAttribute, TClass, TDoc, TMixin, TObj, TType, TTypeString } from './core'
|
||||
import { TSpace, TAccount, TState } from './security'
|
||||
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD } from './tx'
|
||||
import { TTx, TTxCreateDoc, TTxMixin, TTxUpdateDoc, TTxCUD, TTxPutBag } from './tx'
|
||||
|
||||
export * from './core'
|
||||
export * from './security'
|
||||
@ -33,6 +33,7 @@ export function createModel (builder: Builder): void {
|
||||
TTx,
|
||||
TTxCUD,
|
||||
TTxCreateDoc,
|
||||
TTxPutBag,
|
||||
TTxMixin,
|
||||
TTxUpdateDoc,
|
||||
TSpace,
|
||||
|
@ -27,7 +27,9 @@ import type {
|
||||
TxUpdateDoc,
|
||||
TxMixin,
|
||||
Mixin,
|
||||
ExtendedAttributes
|
||||
ExtendedAttributes,
|
||||
PropertyType,
|
||||
TxPutBag
|
||||
} from '@anticrm/core'
|
||||
import { DOMAIN_TX } from '@anticrm/core'
|
||||
import { Model } from '@anticrm/model'
|
||||
@ -52,6 +54,13 @@ export class TTxCreateDoc<T extends Doc> extends TTxCUD<T> implements TxCreateDo
|
||||
attributes!: Data<T>
|
||||
}
|
||||
|
||||
@Model(core.class.TxPutBag, core.class.TxCUD)
|
||||
export class TTxPutBag<T extends PropertyType> extends TTxCUD<Doc> implements TxPutBag<T> {
|
||||
bag!: string
|
||||
key!: string
|
||||
value!: T
|
||||
}
|
||||
|
||||
@Model(core.class.TxMixin, core.class.TxCUD)
|
||||
export class TTxMixin<D extends Doc, M extends D> extends TTxCUD<D> implements TxMixin<D, M> {
|
||||
mixin!: Ref<Mixin<M>>
|
||||
|
@ -46,7 +46,8 @@ export function createDemo (builder: Builder): void {
|
||||
provider: contact.channelProvider.Email,
|
||||
value: 'andrey@hc.engineering'
|
||||
}
|
||||
]
|
||||
],
|
||||
attachments: {}
|
||||
})
|
||||
|
||||
builder.createDoc(recruit.class.Candidate, recruit.space.CandidatesPublic, {
|
||||
@ -58,6 +59,7 @@ export function createDemo (builder: Builder): void {
|
||||
provider: contact.channelProvider.Email,
|
||||
value: 'marina@hc.engineering'
|
||||
}
|
||||
]
|
||||
],
|
||||
attachments: {}
|
||||
})
|
||||
}
|
||||
|
@ -14,8 +14,8 @@
|
||||
//
|
||||
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { Builder, Model, UX, Prop, TypeString } from '@anticrm/model'
|
||||
import type { Ref, FindOptions, Doc, Domain, State } from '@anticrm/core'
|
||||
import { Builder, Model, UX, Prop, TypeString, Bag as TypeBag } from '@anticrm/model'
|
||||
import type { Ref, FindOptions, Doc, Domain, State, Bag } from '@anticrm/core'
|
||||
import core, { TSpace, TDoc } from '@anticrm/model-core'
|
||||
import type { Vacancy, Candidates, Candidate, Applicant } from '@anticrm/recruit'
|
||||
import type { Attachment } from '@anticrm/chunter'
|
||||
@ -25,8 +25,6 @@ import workbench from '@anticrm/model-workbench'
|
||||
import view from '@anticrm/model-view'
|
||||
import contact, { TPerson } from '@anticrm/model-contact'
|
||||
import recruit from './plugin'
|
||||
import chunter from '@anticrm/chunter'
|
||||
import type { Person } from '@anticrm/contact'
|
||||
|
||||
export const DOMAIN_RECRUIT = 'recruit' as Domain
|
||||
|
||||
@ -41,17 +39,17 @@ export class TCandidates extends TSpace implements Candidates {}
|
||||
@Model(recruit.class.Candidate, contact.class.Person)
|
||||
@UX('Candidate' as IntlString)
|
||||
export class TCandidate extends TPerson implements Candidate {
|
||||
@Prop(TypeString(), 'Resume' as IntlString)
|
||||
resume?: Ref<Attachment>
|
||||
|
||||
@Prop(TypeString(), 'Title' as IntlString)
|
||||
title?: Ref<Attachment>
|
||||
title?: string
|
||||
|
||||
@Prop(TypeBag(), 'Attachments' as IntlString)
|
||||
attachments!: Bag<Attachment>
|
||||
}
|
||||
|
||||
@Model(recruit.class.Applicant, core.class.Doc, DOMAIN_RECRUIT)
|
||||
export class TApplicant extends TDoc implements Applicant {
|
||||
@Prop(TypeString(), 'Candidate' as IntlString)
|
||||
candidate!: Ref<Person>
|
||||
candidate!: Ref<Candidate>
|
||||
|
||||
@Prop(TypeString(), 'State' as IntlString)
|
||||
state!: Ref<State>
|
||||
@ -107,11 +105,11 @@ export function createModel (builder: Builder): void {
|
||||
open: recruit.component.EditCandidate,
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
options: {
|
||||
lookup: {
|
||||
resume: chunter.class.Attachment
|
||||
}
|
||||
// lookup: {
|
||||
// resume: chunter.class.Attachment
|
||||
// }
|
||||
} as FindOptions<Doc>, // TODO: fix
|
||||
config: ['', '#' + recruit.component.CreateApplicationPresenter + '/Action', 'city', '$lookup.resume', 'channels']
|
||||
config: ['', '#' + recruit.component.CreateApplicationPresenter + '/Action', 'city', 'channels']
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
|
@ -38,7 +38,8 @@ export default plugin(coreId, {
|
||||
Space: '' as Ref<Class<Space>>,
|
||||
Account: '' as Ref<Class<Account>>,
|
||||
State: '' as Ref<Class<State>>,
|
||||
TypeString: '' as Ref<Class<Type<string>>>
|
||||
TypeString: '' as Ref<Class<Type<string>>>,
|
||||
Bag: '' as Ref<Class<Type<Record<string, PropertyType>>>>
|
||||
},
|
||||
space: {
|
||||
Tx: '' as Ref<Space>,
|
||||
|
@ -266,7 +266,7 @@ export class TxFactory {
|
||||
): TxPutBag<P> {
|
||||
return {
|
||||
_id: generateId(),
|
||||
_class: core.class.TxUpdateDoc,
|
||||
_class: core.class.TxPutBag,
|
||||
space: core.space.Tx,
|
||||
modifiedBy: this.account,
|
||||
modifiedOn: Date.now(),
|
||||
|
@ -272,3 +272,10 @@ export class Builder {
|
||||
export function TypeString (): Type<string> {
|
||||
return { _class: core.class.TypeString }
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function Bag (): Type<Record<string, PropertyType>> {
|
||||
return { _class: core.class.Bag }
|
||||
}
|
||||
|
@ -87,8 +87,22 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
}
|
||||
}
|
||||
|
||||
protected txPutBag (tx: TxPutBag<any>): Promise<void> {
|
||||
throw new Error('Method not implemented.')
|
||||
protected override async txPutBag (tx: TxPutBag<any>): Promise<void> {
|
||||
for (const q of this.queries) {
|
||||
if (q.result instanceof Promise) {
|
||||
q.result = await q.result
|
||||
}
|
||||
const updatedDoc = q.result.find(p => p._id === tx.objectId)
|
||||
if (updatedDoc !== undefined) {
|
||||
const doc = updatedDoc as any
|
||||
let bag = doc[tx.bag]
|
||||
if (bag === undefined) {
|
||||
doc[tx.bag] = bag = {}
|
||||
}
|
||||
bag[tx.key] = tx.value
|
||||
await this.callback(updatedDoc, q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected txMixin (tx: TxMixin<Doc, Doc>): Promise<void> {
|
||||
|
@ -53,6 +53,7 @@ export { default as Row } from './components/Row.svelte'
|
||||
// export { default as CheckBoxList } from './components/CheckBoxList.svelte.txt'
|
||||
export { default as EditWithIcon } from './components/EditWithIcon.svelte'
|
||||
export { default as Loading } from './components/Loading.svelte'
|
||||
export { default as Spinner } from './components/Spinner.svelte'
|
||||
export { default as Popup } from './components/Popup.svelte'
|
||||
export { default as CircleButton } from './components/CircleButton.svelte'
|
||||
export { default as Link } from './components/Link.svelte'
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,8 +33,8 @@ export class FullTextIndex extends TxProcessor implements Storage {
|
||||
super()
|
||||
}
|
||||
|
||||
protected txPutBag (tx: TxPutBag<any>): Promise<void> {
|
||||
throw new Error('Method not implemented.')
|
||||
protected override async txPutBag (tx: TxPutBag<any>): Promise<void> {
|
||||
console.log('FullTextIndex.txPutBag: Method not implemented.')
|
||||
}
|
||||
|
||||
protected txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<void> {
|
||||
|
@ -34,7 +34,7 @@ export interface Trigger extends Doc {
|
||||
* @public
|
||||
*/
|
||||
export interface IndexedDoc {
|
||||
id: Ref<Doc>
|
||||
id: string
|
||||
_class: Ref<Class<Doc>>
|
||||
space: Ref<Space>
|
||||
modifiedOn: Timestamp
|
||||
|
@ -92,8 +92,10 @@ abstract class MongoAdapterBase extends TxProcessor {
|
||||
}
|
||||
|
||||
class MongoAdapter extends MongoAdapterBase {
|
||||
protected txPutBag (tx: TxPutBag<any>): Promise<void> {
|
||||
throw new Error('Method not implemented.')
|
||||
protected override async txPutBag (tx: TxPutBag<any>): Promise<void> {
|
||||
const domain = this.hierarchy.getDomain(tx.objectClass)
|
||||
console.log('mongo', { $set: { [tx.bag + '.' + tx.key]: tx.value } })
|
||||
await this.db.collection(domain).updateOne({ _id: tx.objectId }, { $set: { [tx.bag + '.' + tx.key]: tx.value } })
|
||||
}
|
||||
|
||||
protected txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<void> {
|
||||
@ -112,8 +114,7 @@ class MongoAdapter extends MongoAdapterBase {
|
||||
|
||||
protected override async txUpdateDoc (tx: TxUpdateDoc<Doc>): Promise<void> {
|
||||
const domain = this.hierarchy.getDomain(tx.objectClass)
|
||||
const result = await this.db.collection(domain).updateOne({ _id: tx.objectId }, { $set: tx.operations })
|
||||
console.log('update result', result)
|
||||
await this.db.collection(domain).updateOne({ _id: tx.objectId }, { $set: tx.operations })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ import cors from 'cors'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { decode } from 'jwt-simple'
|
||||
|
||||
import type { Space, Ref, Doc, Account } from '@anticrm/core'
|
||||
import { Space, Ref, Doc, Account, generateId } from '@anticrm/core'
|
||||
// import { TxFactory } from '@anticrm/core'
|
||||
import type { Token, IndexedDoc } from '@anticrm/server-core'
|
||||
import { createElasticAdapter } from '@anticrm/elastic'
|
||||
@ -131,7 +131,7 @@ export function start (transactorEndpoint: string, elasticUrl: string, minio: Cl
|
||||
const uuid = await minioUpload(minio, payload.workspace, file)
|
||||
console.log('uploaded uuid', uuid)
|
||||
|
||||
const id = req.query.id as Ref<Doc>
|
||||
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
|
||||
@ -150,7 +150,7 @@ export function start (transactorEndpoint: string, elasticUrl: string, minio: Cl
|
||||
const elastic = await createElasticAdapter(elasticUrl, payload.workspace)
|
||||
|
||||
const indexedDoc: IndexedDoc = {
|
||||
id,
|
||||
id: generateId() + '/attachments/' + name,
|
||||
_class: chunter.class.Attachment,
|
||||
space,
|
||||
modifiedOn: Date.now(),
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user