mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-23 16:56:07 +00:00
TSK-461: Refactor Tracker/Remember Issues (#2425)
* Refactor: Move drafts.ts to /presentation Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com> * Refactor remember issues Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com> * Fix close issue bug Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com> * Refactor and fix draft clean Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com> * Minor handle method fix Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com> Signed-off-by: Denis Maslennikov <denis.maslennikov@gmail.com>
This commit is contained in:
parent
04206adaef
commit
8865006d3f
67
packages/presentation/src/drafts.ts
Normal file
67
packages/presentation/src/drafts.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { fetchMetadataLocalStorage, setMetadataLocalStorage } from '@hcengineering/ui'
|
||||
import { writable, get } from 'svelte/store'
|
||||
import { getClient } from '.'
|
||||
import presentation from './plugin'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
export const draftStore = writable<Record<string, any>>(fetchMetadataLocalStorage(presentation.metadata.Draft) || {})
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function updateDraftStore (id: string, draft: any): void {
|
||||
draftStore.update((drafts) => {
|
||||
drafts[id] = draft
|
||||
setMetadataLocalStorage(presentation.metadata.Draft, drafts)
|
||||
return drafts
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function updateUserDraft (id: string, draft: any): void {
|
||||
const client = getClient()
|
||||
draftStore.update((drafts) => {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
const userDrafts: Record<string, any> = drafts[client.user] || {}
|
||||
userDrafts[id] = draft
|
||||
drafts[client.user] = userDrafts
|
||||
setMetadataLocalStorage(presentation.metadata.Draft, drafts)
|
||||
return drafts
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getUserDraft (id: string): any {
|
||||
const client = getClient()
|
||||
const drafts: Record<string, any> = get(draftStore)
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
const userDrafts: Record<string, any> = drafts[client.user] || {}
|
||||
const draft: Record<string, any> = userDrafts[id]
|
||||
return draft
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function isUserDraftExists (id: string): boolean {
|
||||
const client = getClient()
|
||||
const drafts: Record<string, any> = get(draftStore)
|
||||
const userDrafts: Record<string, any> = drafts[client.user]
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (!userDrafts) {
|
||||
return false
|
||||
}
|
||||
const draftRecord: Record<string, any> = userDrafts[id]
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (!draftRecord) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
@ -47,6 +47,7 @@ export { connect, versionError } from './connect'
|
||||
export { default } from './plugin'
|
||||
export * from './types'
|
||||
export * from './utils'
|
||||
export * from './drafts'
|
||||
export { presentationId }
|
||||
|
||||
addStringsLoader(presentationId, async (lang: string) => {
|
||||
|
@ -59,6 +59,7 @@ export default plugin(presentationId, {
|
||||
GravatarsManaged: '' as IntlString
|
||||
},
|
||||
metadata: {
|
||||
RequiredVersion: '' as Metadata<string>
|
||||
RequiredVersion: '' as Metadata<string>,
|
||||
Draft: '' as Metadata<Record<string, any>>
|
||||
}
|
||||
})
|
||||
|
@ -16,10 +16,9 @@
|
||||
<script lang="ts">
|
||||
import { Comment } from '@hcengineering/chunter'
|
||||
import { Doc, generateId, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { getClient, draftStore, updateDraftStore } from '@hcengineering/presentation'
|
||||
import { AttachmentRefInput } from '@hcengineering/attachment-resources'
|
||||
import { createBacklinks } from '../backlinks'
|
||||
import { draftStore, updateDraftStore } from '../drafts'
|
||||
import chunter from '../plugin'
|
||||
|
||||
export let object: Doc
|
||||
|
@ -1,18 +0,0 @@
|
||||
import { fetchMetadataLocalStorage, setMetadataLocalStorage } from '@hcengineering/ui'
|
||||
import { writable } from 'svelte/store'
|
||||
import chunter from './plugin'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
export const draftStore = writable<Record<string, any>>(fetchMetadataLocalStorage(chunter.metadata.Draft) || {})
|
||||
console.log('draft store', draftStore)
|
||||
|
||||
export function updateDraftStore (id: string, draft: any): void {
|
||||
draftStore.update((drafts) => {
|
||||
drafts[id] = draft
|
||||
setMetadataLocalStorage(chunter.metadata.Draft, drafts)
|
||||
return drafts
|
||||
})
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
|
||||
import chunter, { chunterId } from '@hcengineering/chunter'
|
||||
import type { Client, Space } from '@hcengineering/core'
|
||||
import type { IntlString, Metadata, Resource } from '@hcengineering/platform'
|
||||
import type { IntlString, Resource } from '@hcengineering/platform'
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import type { AnyComponent } from '@hcengineering/ui'
|
||||
import { ViewAction } from '@hcengineering/view'
|
||||
@ -87,8 +87,5 @@ export default mergeIds(chunterId, chunter, {
|
||||
Messages: '' as IntlString,
|
||||
NoResults: '' as IntlString,
|
||||
CopyLink: '' as IntlString
|
||||
},
|
||||
metadata: {
|
||||
Draft: '' as Metadata<Record<string, any>>
|
||||
}
|
||||
})
|
||||
|
@ -28,7 +28,16 @@
|
||||
WithLookup
|
||||
} from '@hcengineering/core'
|
||||
import { getResource, translate } from '@hcengineering/platform'
|
||||
import { Card, createQuery, getClient, KeyedAttribute, MessageBox, SpaceSelector } from '@hcengineering/presentation'
|
||||
import {
|
||||
Card,
|
||||
createQuery,
|
||||
getClient,
|
||||
getUserDraft,
|
||||
KeyedAttribute,
|
||||
MessageBox,
|
||||
SpaceSelector,
|
||||
updateUserDraft
|
||||
} from '@hcengineering/presentation'
|
||||
import tags, { TagElement, TagReference } from '@hcengineering/tags'
|
||||
import {
|
||||
calcRank,
|
||||
@ -55,7 +64,6 @@
|
||||
IconMoreH,
|
||||
Label,
|
||||
Menu,
|
||||
setMetadataLocalStorage,
|
||||
showPopup,
|
||||
Spinner
|
||||
} from '@hcengineering/ui'
|
||||
@ -85,17 +93,19 @@
|
||||
export let sprint: Ref<Sprint> | null = $activeSprint ?? null
|
||||
export let relatedTo: Doc | undefined
|
||||
export let shouldSaveDraft: boolean = false
|
||||
export let draft: IssueDraft | null
|
||||
export let parentIssue: Issue | undefined
|
||||
export let originalIssue: Issue | undefined
|
||||
export let onDraftChanged: (draft: Data<IssueDraft>) => void
|
||||
export let onDraftChanged: () => void
|
||||
|
||||
const draft: IssueDraft | undefined = getUserDraft(tracker.class.IssueDraft)
|
||||
|
||||
let issueStatuses: WithLookup<IssueStatus>[] | undefined
|
||||
let labels: TagReference[] = draft?.labels || []
|
||||
let objectId: Ref<Issue> = draft?.issueId || generateId()
|
||||
let saveTimer: number | undefined
|
||||
let currentTeam: Team | undefined
|
||||
|
||||
function toIssue (initials: AttachedData<Issue>, draft: IssueDraft | null): AttachedData<Issue> {
|
||||
function toIssue (initials: AttachedData<Issue>, draft: IssueDraft | undefined): AttachedData<Issue> {
|
||||
if (draft == null) {
|
||||
return { ...initials }
|
||||
}
|
||||
@ -269,6 +279,36 @@
|
||||
|
||||
$: originalIssue && setPropsFromOriginalIssue()
|
||||
$: draft && setPropsFromDraft()
|
||||
$: object && updateDraft()
|
||||
|
||||
async function updateDraft () {
|
||||
if (saveTimer) {
|
||||
clearTimeout(saveTimer)
|
||||
}
|
||||
saveTimer = setTimeout(() => {
|
||||
saveDraft()
|
||||
}, 200)
|
||||
}
|
||||
|
||||
async function saveDraft () {
|
||||
if (!shouldSaveDraft) {
|
||||
return
|
||||
}
|
||||
|
||||
await descriptionBox?.createAttachments()
|
||||
|
||||
let newDraft: Data<IssueDraft> | undefined = createDraftFromObject()
|
||||
const isEmpty = await isDraftEmpty(newDraft)
|
||||
|
||||
if (isEmpty) {
|
||||
newDraft = undefined
|
||||
}
|
||||
updateUserDraft(tracker.class.IssueDraft, newDraft)
|
||||
|
||||
if (onDraftChanged) {
|
||||
return onDraftChanged()
|
||||
}
|
||||
}
|
||||
|
||||
async function updateIssueStatusId (teamId: Ref<Team>, issueStatusId?: Ref<IssueStatus>) {
|
||||
if (issueStatusId !== undefined) {
|
||||
@ -319,13 +359,17 @@
|
||||
return false
|
||||
}
|
||||
|
||||
if (draft.status === '') {
|
||||
return true
|
||||
}
|
||||
|
||||
const team = await client.findOne(tracker.class.Team, { _id: _space })
|
||||
|
||||
if (team?.defaultIssueStatus) {
|
||||
return draft.status === team.defaultIssueStatus
|
||||
}
|
||||
|
||||
return status === ''
|
||||
return false
|
||||
}
|
||||
|
||||
export function canClose (): boolean {
|
||||
@ -336,7 +380,7 @@
|
||||
const newDraft: Data<IssueDraft> = {
|
||||
issueId: objectId,
|
||||
title: getTitle(object.title),
|
||||
description: object.description,
|
||||
description: (object.description as string).replaceAll('<p></p>', ''),
|
||||
assignee: object.assignee,
|
||||
project: object.project,
|
||||
sprint: object.sprint,
|
||||
@ -355,23 +399,10 @@
|
||||
}
|
||||
|
||||
export async function onOutsideClick () {
|
||||
if (!shouldSaveDraft) {
|
||||
return
|
||||
}
|
||||
|
||||
await descriptionBox?.createAttachments()
|
||||
|
||||
const newDraft = createDraftFromObject()
|
||||
const isEmpty = await isDraftEmpty(newDraft)
|
||||
|
||||
if (isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
setMetadataLocalStorage(tracker.metadata.CreateIssueDraft, newDraft)
|
||||
saveDraft()
|
||||
|
||||
if (onDraftChanged) {
|
||||
return onDraftChanged(newDraft)
|
||||
return onDraftChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@ -523,6 +554,7 @@
|
||||
|
||||
objectId = generateId()
|
||||
resetObject()
|
||||
saveDraft()
|
||||
}
|
||||
|
||||
async function showMoreActions (ev: Event) {
|
||||
@ -631,6 +663,8 @@
|
||||
(result?: boolean) => {
|
||||
if (result === true) {
|
||||
dispatch('close')
|
||||
resetObject()
|
||||
saveDraft()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -13,10 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Data, Ref, Space } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { IssueDraft } from '@hcengineering/tracker'
|
||||
import { Button, fetchMetadataLocalStorage, setMetadataLocalStorage, showPopup } from '@hcengineering/ui'
|
||||
import { Ref, Space } from '@hcengineering/core'
|
||||
import { getClient, isUserDraftExists } from '@hcengineering/presentation'
|
||||
import { Button, showPopup } from '@hcengineering/ui'
|
||||
import tracker from '../plugin'
|
||||
import CreateIssue from './CreateIssue.svelte'
|
||||
|
||||
@ -27,10 +26,10 @@
|
||||
let space: Ref<Space> | undefined
|
||||
$: updateSpace(currentSpace)
|
||||
|
||||
let issueDraft: Data<IssueDraft> | null = fetchMetadataLocalStorage(tracker.metadata.CreateIssueDraft)
|
||||
let draftExists: boolean = isUserDraftExists(tracker.class.IssueDraft)
|
||||
|
||||
const handleDraftChanged = (draft: Data<IssueDraft>) => {
|
||||
issueDraft = draft
|
||||
const handleDraftChanged = () => {
|
||||
draftExists = isUserDraftExists(tracker.class.IssueDraft)
|
||||
}
|
||||
|
||||
async function updateSpace (spaceId: Ref<Space> | undefined): Promise<void> {
|
||||
@ -49,14 +48,7 @@
|
||||
space = team?._id
|
||||
}
|
||||
|
||||
showPopup(
|
||||
CreateIssue,
|
||||
{ space, shouldSaveDraft: true, draft: issueDraft, onDraftChanged: handleDraftChanged },
|
||||
'top'
|
||||
)
|
||||
|
||||
setMetadataLocalStorage(tracker.metadata.CreateIssueDraft, null)
|
||||
issueDraft = null
|
||||
showPopup(CreateIssue, { space, shouldSaveDraft: true, onDraftChanged: handleDraftChanged }, 'top')
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -64,13 +56,13 @@
|
||||
<div class="flex-grow text-md">
|
||||
<Button
|
||||
icon={tracker.icon.NewIssue}
|
||||
label={issueDraft ? tracker.string.ResumeDraft : tracker.string.NewIssue}
|
||||
label={draftExists ? tracker.string.ResumeDraft : tracker.string.NewIssue}
|
||||
justify={'left'}
|
||||
width={'100%'}
|
||||
on:click={newIssue}
|
||||
>
|
||||
<div slot="content" class="draft-circle-container">
|
||||
{#if issueDraft}
|
||||
{#if draftExists}
|
||||
<div class="draft-circle" />
|
||||
{/if}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user