Fix attachments in drafts (#2451)

Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com>
This commit is contained in:
Denis Maslennikov 2022-12-20 11:25:45 +07:00 committed by GitHub
parent 12292dbf46
commit 69a229efef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 56 deletions

View File

@ -14,7 +14,12 @@ export const draftStore = writable<Record<string, any>>(fetchMetadataLocalStorag
*/
export function updateDraftStore (id: string, draft: any): void {
draftStore.update((drafts) => {
drafts[id] = draft
if (draft === undefined) {
drafts[id] = draft
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete drafts[id]
}
setMetadataLocalStorage(presentation.metadata.Draft, drafts)
return drafts
})

View File

@ -142,7 +142,7 @@
</Scroller>
{#if showCommenInput}
<div class="ref-input">
<Component is={chunter.component.CommentInput} props={{ object, shouldUseDraft: true }} />
<Component is={chunter.component.CommentInput} props={{ object, shouldSaveDraft: true }} />
</div>
{/if}
</div>
@ -164,7 +164,7 @@
</div>
{#if showCommenInput}
<div class="ref-input">
<Component is={chunter.component.CommentInput} props={{ object, shouldUseDraft: true }} />
<Component is={chunter.component.CommentInput} props={{ object, shouldSaveDraft: true }} />
</div>
{/if}
<div class="p-activity select-text" id={activity.string.Activity}>

View File

@ -13,7 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { createQuery, getClient } from '@hcengineering/presentation'
import { createQuery, getClient, draftStore, updateDraftStore } from '@hcengineering/presentation'
import { ReferenceInput } from '@hcengineering/text-editor'
import { deleteFile, uploadFile } from '../utils'
import attachment from '../plugin'
@ -28,7 +28,8 @@
export let _class: Ref<Class<Doc>>
export let content: string = ''
export let showSend = true
export let shouldUseDraft: boolean = false
export let shouldSaveDraft: boolean = false
export let attachments: Map<Ref<Attachment>, Attachment> = new Map<Ref<Attachment>, Attachment>()
export function submit (): void {
refInput.submit()
}
@ -41,24 +42,48 @@
const client = getClient()
const query = createQuery()
let attachments: Map<Ref<Attachment>, Attachment> = new Map<Ref<Attachment>, Attachment>()
let draftAttachments: Record<Ref<Attachment>, Attachment> | undefined = undefined
let originalAttachments: Set<Ref<Attachment>> = new Set<Ref<Attachment>>()
const newAttachments: Set<Ref<Attachment>> = new Set<Ref<Attachment>>()
const removedAttachments: Set<Attachment> = new Set<Attachment>()
let refContainer: HTMLElement
$: objectId &&
query.query(
attachment.class.Attachment,
{
attachedTo: objectId
},
(res) => {
originalAttachments = new Set(res.map((p) => p._id))
attachments = new Map(res.map((p) => [p._id, p]))
}
)
$: objectId && updateAttachments(objectId)
async function updateAttachments (objectId: Ref<Doc>) {
draftAttachments = $draftStore[objectId]
if (draftAttachments && shouldSaveDraft) {
attachments.clear()
newAttachments.clear()
Object.entries(draftAttachments).map((file) => {
return attachments.set(file[0] as Ref<Attachment>, file[1])
})
Object.entries(draftAttachments).map((file) => {
return newAttachments.add(file[0] as Ref<Attachment>)
})
originalAttachments.clear()
removedAttachments.clear()
} else {
query.query(
attachment.class.Attachment,
{
attachedTo: objectId
},
(res) => {
originalAttachments = new Set(res.map((p) => p._id))
attachments = new Map(res.map((p) => [p._id, p]))
}
)
}
}
async function saveDraft () {
if (objectId && shouldSaveDraft) {
draftAttachments = Object.fromEntries(attachments)
updateDraftStore(objectId, draftAttachments)
}
}
async function createAttachment (file: File) {
try {
@ -81,9 +106,7 @@
})
newAttachments.add(_id)
attachments = attachments
if (shouldUseDraft) {
await createAttachments()
}
saveDraft()
} catch (err: any) {
setPlatformStatus(unknownError(err))
}
@ -115,10 +138,11 @@
async function removeAttachment (attachment: Attachment): Promise<void> {
removedAttachments.add(attachment)
attachments.delete(attachment._id)
if (shouldUseDraft) {
if (shouldSaveDraft) {
await createAttachments()
}
attachments = attachments
saveDraft()
}
async function deleteAttachment (attachment: Attachment): Promise<void> {
@ -137,7 +161,7 @@
}
onDestroy(() => {
if (!saved) {
if (!saved && !shouldSaveDraft) {
newAttachments.forEach(async (p) => {
const attachment = attachments.get(p)
if (attachment !== undefined) {
@ -147,6 +171,20 @@
}
})
export function removeDraft (removeFiles: boolean) {
if (objectId) {
updateDraftStore(objectId, undefined)
}
if (removeFiles) {
newAttachments.forEach(async (p) => {
const attachment = attachments.get(p)
if (attachment !== undefined) {
await deleteFile(attachment.file)
}
})
}
}
export function createAttachments (): Promise<void> {
saved = true
const promises: Promise<any>[] = []

View File

@ -16,7 +16,7 @@
import { Attachment } from '@hcengineering/attachment'
import { Account, Class, Doc, generateId, Ref, Space } from '@hcengineering/core'
import { IntlString, setPlatformStatus, unknownError } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import { createQuery, getClient, draftStore, updateDraftStore } from '@hcengineering/presentation'
import { StyledTextBox } from '@hcengineering/text-editor'
import { IconSize } from '@hcengineering/ui'
import { createEventDispatcher, onDestroy } from 'svelte'
@ -37,6 +37,7 @@
export let focusable: boolean = false
export let fakeAttach: 'fake' | 'hidden' | 'normal' = 'normal'
export let refContainer: HTMLElement | undefined = undefined
export let shouldSaveDraft: boolean = false
const dispatch = createEventDispatcher()
@ -62,6 +63,7 @@
let refInput: StyledTextBox
let inputFile: HTMLInputElement
let draftAttachments: Record<Ref<Attachment>, Attachment> | undefined = undefined
let saved = false
const client = getClient()
@ -71,17 +73,41 @@
const newAttachments: Set<Ref<Attachment>> = new Set<Ref<Attachment>>()
const removedAttachments: Set<Attachment> = new Set<Attachment>()
$: objectId &&
query.query(
attachment.class.Attachment,
{
attachedTo: objectId
},
(res) => {
originalAttachments = new Set(res.map((p) => p._id))
attachments = new Map(res.map((p) => [p._id, p]))
}
)
$: objectId && updateAttachments(objectId)
async function updateAttachments (objectId: Ref<Doc>) {
draftAttachments = $draftStore[objectId]
if (draftAttachments && shouldSaveDraft) {
attachments.clear()
newAttachments.clear()
Object.entries(draftAttachments).map((file) => {
return attachments.set(file[0] as Ref<Attachment>, file[1])
})
Object.entries(draftAttachments).map((file) => {
return newAttachments.add(file[0] as Ref<Attachment>)
})
originalAttachments.clear()
removedAttachments.clear()
} else {
query.query(
attachment.class.Attachment,
{
attachedTo: objectId
},
(res) => {
originalAttachments = new Set(res.map((p) => p._id))
attachments = new Map(res.map((p) => [p._id, p]))
}
)
}
}
async function saveDraft () {
if (objectId && shouldSaveDraft) {
draftAttachments = Object.fromEntries(attachments)
updateDraftStore(objectId, draftAttachments)
}
}
async function createAttachment (file: File) {
if (space === undefined || objectId === undefined || _class === undefined) return
@ -105,6 +131,7 @@
})
newAttachments.add(_id)
attachments = attachments
saveDraft()
} catch (err: any) {
setPlatformStatus(unknownError(err))
}
@ -139,6 +166,7 @@
removedAttachments.add(attachment)
attachments.delete(attachment._id)
attachments = attachments
saveDraft()
}
async function deleteAttachment (attachment: Attachment): Promise<void> {
@ -157,7 +185,7 @@
}
onDestroy(() => {
if (!saved) {
if (!saved && !shouldSaveDraft) {
newAttachments.forEach(async (p) => {
const attachment = attachments.get(p)
if (attachment !== undefined) {
@ -167,6 +195,20 @@
}
})
export function removeDraft (removeFiles: boolean) {
if (objectId) {
updateDraftStore(objectId, undefined)
}
if (removeFiles) {
newAttachments.forEach(async (p) => {
const attachment = attachments.get(p)
if (attachment !== undefined) {
await deleteFile(attachment.file)
}
})
}
}
export function createAttachments (): Promise<void> {
saved = true
const promises: Promise<any>[] = []

View File

@ -22,7 +22,7 @@
import chunter from '../plugin'
export let object: Doc
export let shouldUseDraft: boolean = false
export let shouldSaveDraft: boolean = false
const client = getClient()
const _class = chunter.class.Comment
@ -37,7 +37,7 @@
$: updateCommentFromDraft(draftComment)
async function updateDraft (object: Doc) {
if (!shouldUseDraft) {
if (!shouldSaveDraft) {
return
}
draftComment = $draftStore[object._id]
@ -47,7 +47,7 @@
}
async function updateCommentFromDraft (draftComment: Comment | undefined) {
if (!shouldUseDraft) {
if (!shouldSaveDraft) {
return
}
inputContent = draftComment ? draftComment.message : ''
@ -59,12 +59,6 @@
}
async function saveDraft (object: Doc) {
if (draftComment) {
draftComment._id = _id
$draftStore[object._id] = draftComment
} else {
delete $draftStore[object._id]
}
updateDraftStore(object._id, draftComment)
}
@ -86,7 +80,7 @@
}
async function onUpdate (event: CustomEvent) {
if (!shouldUseDraft) {
if (!shouldSaveDraft) {
return
}
const { message, attachments } = event.detail
@ -133,6 +127,7 @@
_id = generateId()
draftComment = undefined
await saveDraft(object)
commentInputBox.removeDraft(false)
}
</script>
@ -142,7 +137,7 @@
{_class}
space={object.space}
bind:objectId={_id}
shouldUseDraft
{shouldSaveDraft}
on:message={onMessage}
on:update={onUpdate}
/>

View File

@ -82,7 +82,6 @@
import SetParentIssueActionPopup from './SetParentIssueActionPopup.svelte'
import SprintSelector from './sprints/SprintSelector.svelte'
import IssueTemplateChilds from './templates/IssueTemplateChilds.svelte'
import attachment from '@hcengineering/attachment-resources/src/plugin'
import IssueNotification from './issues/IssueNotification.svelte'
export let space: Ref<Team>
@ -97,7 +96,7 @@
export let originalIssue: Issue | undefined
export let onDraftChanged: () => void
const draft: IssueDraft | undefined = getUserDraft(tracker.class.IssueDraft)
const draft: IssueDraft | undefined = shouldSaveDraft ? getUserDraft(tracker.class.IssueDraft) : undefined
let issueStatuses: WithLookup<IssueStatus>[] | undefined
let labels: TagReference[] = draft?.labels || []
@ -106,7 +105,7 @@
let currentTeam: Team | undefined
function toIssue (initials: AttachedData<Issue>, draft: IssueDraft | undefined): AttachedData<Issue> {
if (draft == null) {
if (draft === undefined) {
return { ...initials }
}
const { labels, subIssues, ...issue } = draft
@ -125,6 +124,7 @@
priority,
dueDate: null,
comments: 0,
attachments: 0,
subIssues: 0,
parents: [],
reportedTime: 0,
@ -295,8 +295,6 @@
return
}
await descriptionBox?.createAttachments()
let newDraft: Data<IssueDraft> | undefined = createDraftFromObject()
const isEmpty = await isDraftEmpty(newDraft)
@ -337,6 +335,7 @@
description: '',
dueDate: null,
estimation: 0,
attachments: 0,
labels: [],
parentIssue: undefined,
priority: 0,
@ -351,11 +350,9 @@
}
}
const attachmentResult = await client.findOne(attachment.class.Attachment, { attachedTo: objectId })
if (attachmentResult) {
return false
}
// if (object.attachments && object.attachments > 0) {
// return false
// }
if (draft.project && draft.project !== defaultIssue.project) {
return false
@ -395,6 +392,7 @@
dueDate: object.dueDate,
estimation: object.estimation,
template: object.template,
attachments: object.attachments,
labels,
parentIssue: parentIssue?._id,
team: _space,
@ -562,6 +560,7 @@
objectId = generateId()
resetObject()
saveDraft()
descriptionBox?.removeDraft(false)
}
async function showMoreActions (ev: Event) {
@ -672,6 +671,7 @@
dispatch('close')
resetObject()
saveDraft()
descriptionBox?.removeDraft(true)
}
}
)
@ -738,6 +738,7 @@
<AttachmentStyledBox
bind:this={descriptionBox}
{objectId}
{shouldSaveDraft}
_class={tracker.class.Issue}
space={_space}
alwaysEdit
@ -746,6 +747,11 @@
bind:content={object.description}
placeholder={tracker.string.IssueDescriptionPlaceholder}
on:changeSize={() => dispatch('changeContent')}
on:attach={(ev) => {
if (ev.detail.action === 'saved') {
object.attachments = ev.detail.value
}
}}
/>
{/key}
<IssueTemplateChilds bind:children={subIssues} sprint={object.sprint} project={object.project} isScrollable />

View File

@ -222,6 +222,7 @@ export interface IssueDraft extends Doc {
// Estimation in man days
estimation: number
parentIssue?: string
attachments?: number
labels?: TagReference[]
subIssues?: IssueTemplateChild[]
template?: {