From a89d814191c9b9547c9b044afb55afc048fed1f6 Mon Sep 17 00:00:00 2001 From: "christopher@aitmed.com" Date: Sat, 11 Jan 2020 09:43:55 -0800 Subject: [PATCH 1/5] WIP-checkboxes checkable in previewer --- src/components/atoms/MarkdownPreviewer.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/atoms/MarkdownPreviewer.tsx b/src/components/atoms/MarkdownPreviewer.tsx index 1ae569c06c..c10d5788a9 100644 --- a/src/components/atoms/MarkdownPreviewer.tsx +++ b/src/components/atoms/MarkdownPreviewer.tsx @@ -214,6 +214,11 @@ const MarkdownPreviewer = ({ {children} ) + }, + input: (props: any) => { + return ( + + ) } } }) From e758eef0f694b5892fbbbb66c8f828485eb53232 Mon Sep 17 00:00:00 2001 From: "christopher@aitmed.com" Date: Mon, 13 Jan 2020 21:10:24 -0800 Subject: [PATCH 2/5] update content props --- .../atoms/CustomizedMarkdownPreviewer.tsx | 5 ++- src/components/atoms/MarkdownPreviewer.tsx | 33 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/components/atoms/CustomizedMarkdownPreviewer.tsx b/src/components/atoms/CustomizedMarkdownPreviewer.tsx index b1ac17e2b9..46372fb515 100644 --- a/src/components/atoms/CustomizedMarkdownPreviewer.tsx +++ b/src/components/atoms/CustomizedMarkdownPreviewer.tsx @@ -6,11 +6,13 @@ import { usePreviewStyle } from '../../lib/preview' interface CustomizedMarkdownPreviewer { content: string storageId?: string + updateContent?: any } const CustomizedMarkdownPreviewer = ({ content, - storageId + storageId, + updateContent }: CustomizedMarkdownPreviewer) => { const { preferences } = usePreferences() const { previewStyle } = usePreviewStyle() @@ -22,6 +24,7 @@ const CustomizedMarkdownPreviewer = ({ codeBlockTheme={preferences['markdown.codeBlockTheme']} theme={preferences['general.theme']} style={previewStyle} + updateContent={updateContent} /> ) } diff --git a/src/components/atoms/MarkdownPreviewer.tsx b/src/components/atoms/MarkdownPreviewer.tsx index c10d5788a9..5ba6c9d039 100644 --- a/src/components/atoms/MarkdownPreviewer.tsx +++ b/src/components/atoms/MarkdownPreviewer.tsx @@ -159,6 +159,14 @@ interface MarkdownPreviewerProps { style?: string theme?: string storageId?: string + updateContent?: any +} + +const regex = { + check: /\[x]/i, + uncheck: /\[ ]/, + checked: /^(\s*>?)*\s*[+\-*] \[x]/i, + unchecked: /^(\s*>?)*\s*[+\-*] \[ ]/ } const MarkdownPreviewer = ({ @@ -166,14 +174,17 @@ const MarkdownPreviewer = ({ codeBlockTheme, style, theme, - storageId + storageId, + updateContent }: MarkdownPreviewerProps) => { const forceUpdate = useForceUpdate() const [rendering, setRendering] = useState(false) const previousContentRef = useRef('') const previousThemeRef = useRef('') + const checkboxIndexes = React.useRef(0) const [renderedContent, setRenderedContent] = useState([]) const { storageMap } = useDb() + console.log(content) const markdownProcessor = useMemo(() => { const options = { codeBlockTheme, storageId } @@ -216,8 +227,26 @@ const MarkdownPreviewer = ({ ) }, input: (props: any) => { + console.log(props) return ( - + { + const lines = content.split('\n') + const currIndex = checkboxIndexes.current + let targetLine = lines[currIndex] + targetLine = regex.checked.test(targetLine) + ? targetLine.replace(regex.check, '[ ]') + : targetLine.replace(regex.uncheck, '[x]') + const nextContent = lines + .splice(currIndex, 1, targetLine) + .join('\n') + updateContent(nextContent) + }} + id={`checkbox[${checkboxIndexes.current++}]`} + readOnly + {...props} + disabled={props.type !== 'checkbox'} + /> ) } } From f0d46d48ae0f4c35eadb441c5b164e3ac9769777 Mon Sep 17 00:00:00 2001 From: Christopher Tran Date: Mon, 13 Jan 2020 23:14:03 -0800 Subject: [PATCH 3/5] saved --- .../NotePage/NoteDetail/NoteDetail.tsx | 9 ++- src/components/atoms/MarkdownPreviewer.tsx | 60 +++++++++++++------ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/components/NotePage/NoteDetail/NoteDetail.tsx b/src/components/NotePage/NoteDetail/NoteDetail.tsx index 2200fe80cb..8c95c25283 100644 --- a/src/components/NotePage/NoteDetail/NoteDetail.tsx +++ b/src/components/NotePage/NoteDetail/NoteDetail.tsx @@ -300,8 +300,12 @@ export default class NoteDetail extends React.Component< } appendNewTag = () => { - if (includes(this.state.newTagName, this.state.tags)) { return } - if (!isTagNameValid(this.state.newTagName)) { return } + if (includes(this.state.newTagName, this.state.tags)) { + return + } + if (!isTagNameValid(this.state.newTagName)) { + return + } this.setState( prevState => ({ newTagName: '', @@ -469,6 +473,7 @@ export default class NoteDetail extends React.Component< ) diff --git a/src/components/atoms/MarkdownPreviewer.tsx b/src/components/atoms/MarkdownPreviewer.tsx index 5ba6c9d039..f0bed14594 100644 --- a/src/components/atoms/MarkdownPreviewer.tsx +++ b/src/components/atoms/MarkdownPreviewer.tsx @@ -162,13 +162,6 @@ interface MarkdownPreviewerProps { updateContent?: any } -const regex = { - check: /\[x]/i, - uncheck: /\[ ]/, - checked: /^(\s*>?)*\s*[+\-*] \[x]/i, - unchecked: /^(\s*>?)*\s*[+\-*] \[ ]/ -} - const MarkdownPreviewer = ({ content, codeBlockTheme, @@ -184,7 +177,7 @@ const MarkdownPreviewer = ({ const checkboxIndexes = React.useRef(0) const [renderedContent, setRenderedContent] = useState([]) const { storageMap } = useDb() - console.log(content) + // console.log(content) const markdownProcessor = useMemo(() => { const options = { codeBlockTheme, storageId } @@ -227,19 +220,48 @@ const MarkdownPreviewer = ({ ) }, input: (props: any) => { - console.log(props) return ( { + onChange={e => { + const regex = { + check: /\[x]/i, + uncheck: /\[ ]/, + checked: /^(\s*>?)*\s*[+\-*] \[x]/i, + unchecked: /^(\s*>?)*\s*[+\-*] \[ ]/, + checkedAndUnchecked: /^(\s*>?)*\s*[+\-*] (\[x]|\[ ])/i + } + const lines = content.split('\n') - const currIndex = checkboxIndexes.current - let targetLine = lines[currIndex] - targetLine = regex.checked.test(targetLine) - ? targetLine.replace(regex.check, '[ ]') - : targetLine.replace(regex.uncheck, '[x]') - const nextContent = lines - .splice(currIndex, 1, targetLine) - .join('\n') + let checkboxIndex: any = e.target.getAttribute('id') || '' + checkboxIndex = Number( + checkboxIndex.replace(/^checkbox|(\[|\])/gi, '') + ) + + let currCheckboxIndex = 0 + + for (let index = 0; index < lines.length; index++) { + const line = lines[index] + const matches = line.match(regex.checkedAndUnchecked) + if (matches) { + if (currCheckboxIndex === checkboxIndex) { + const isChecked = regex.checked.test(matches[0]) + lines.splice( + index, + 1, + line.replace( + isChecked ? '[x]' : '[ ]', + isChecked ? '[ ]' : '[x]' + ) + ) + // Bail out early since we're done + break + } else { + currCheckboxIndex++ + } + } + } + const nextContent = lines.join('\n') + console.log(nextContent) updateContent(nextContent) }} id={`checkbox[${checkboxIndexes.current++}]`} @@ -251,7 +273,7 @@ const MarkdownPreviewer = ({ } } }) - }, [codeBlockTheme, storageId, storageMap]) + }, [codeBlockTheme, content, storageId, storageMap, updateContent]) const renderContent = useCallback( async (content: string) => { From 865c78f90e918d03d0ae97034ccd33c61536c693 Mon Sep 17 00:00:00 2001 From: Christopher Tran Date: Mon, 13 Jan 2020 23:33:53 -0800 Subject: [PATCH 4/5] reg --- resources/favicon.ico | Bin 0 -> 370070 bytes src/components/atoms/MarkdownPreviewer.tsx | 22 ++++++++------------- src/lib/db/NoteDb.ts | 2 ++ 3 files changed, 10 insertions(+), 14 deletions(-) create mode 100644 resources/favicon.ico diff --git a/resources/favicon.ico b/resources/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..061f41394366e7070717e6336db72e4cd27fbe02 GIT binary patch literal 370070 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 Gx&IGR;vumB literal 0 HcmV?d00001 diff --git a/src/components/atoms/MarkdownPreviewer.tsx b/src/components/atoms/MarkdownPreviewer.tsx index f0bed14594..4c59a518e3 100644 --- a/src/components/atoms/MarkdownPreviewer.tsx +++ b/src/components/atoms/MarkdownPreviewer.tsx @@ -224,39 +224,33 @@ const MarkdownPreviewer = ({ { const regex = { - check: /\[x]/i, - uncheck: /\[ ]/, checked: /^(\s*>?)*\s*[+\-*] \[x]/i, - unchecked: /^(\s*>?)*\s*[+\-*] \[ ]/, checkedAndUnchecked: /^(\s*>?)*\s*[+\-*] (\[x]|\[ ])/i } - const lines = content.split('\n') let checkboxIndex: any = e.target.getAttribute('id') || '' + checkboxIndex = Number( checkboxIndex.replace(/^checkbox|(\[|\])/gi, '') ) - let currCheckboxIndex = 0 + let current = 0 for (let index = 0; index < lines.length; index++) { const line = lines[index] const matches = line.match(regex.checkedAndUnchecked) + console.log(`matches: ${!!matches}`) if (matches) { - if (currCheckboxIndex === checkboxIndex) { + if (current === checkboxIndex) { const isChecked = regex.checked.test(matches[0]) - lines.splice( - index, - 1, - line.replace( - isChecked ? '[x]' : '[ ]', - isChecked ? '[ ]' : '[x]' - ) + lines[index] = line.replace( + isChecked ? '[x]' : '[ ]', + isChecked ? '[ ]' : '[x]' ) // Bail out early since we're done break } else { - currCheckboxIndex++ + current++ } } } diff --git a/src/lib/db/NoteDb.ts b/src/lib/db/NoteDb.ts index c7c01c07df..3ba41df4e2 100644 --- a/src/lib/db/NoteDb.ts +++ b/src/lib/db/NoteDb.ts @@ -1,4 +1,6 @@ +// @ts-ignore import dashify from 'dashify' +// @ts-ignore import parsePath from 'path-parse' import { AllDocsMap, From ac0734f62605e933fa8228fa69638a7d9a9b983c Mon Sep 17 00:00:00 2001 From: Christopher Tran Date: Mon, 13 Jan 2020 23:35:20 -0800 Subject: [PATCH 5/5] Delete NoteDb.ts --- src/lib/db/NoteDb.ts | 568 ------------------------------------------- 1 file changed, 568 deletions(-) delete mode 100644 src/lib/db/NoteDb.ts diff --git a/src/lib/db/NoteDb.ts b/src/lib/db/NoteDb.ts deleted file mode 100644 index 3ba41df4e2..0000000000 --- a/src/lib/db/NoteDb.ts +++ /dev/null @@ -1,568 +0,0 @@ -// @ts-ignore -import dashify from 'dashify' -// @ts-ignore -import parsePath from 'path-parse' -import { - AllDocsMap, - FolderDoc, - FolderDocEditibleProps, - TagDocEditibleProps, - TagDoc, - NoteDoc, - NoteDocEditibleProps, - ExceptRev, - ObjectMap, - Attachment, - PopulatedNoteDoc -} from './types' -import { - getFolderId, - createUnprocessableEntityError, - isFolderPathnameValid, - getParentFolderPathname, - getTagId, - isTagNameValid, - generateNoteId, - getNow, - createNotFoundError, - getFolderPathname, - isNoteDoc, - isFolderDoc, - isTagDoc, - getTagName, - values -} from './utils' -import { FOLDER_ID_PREFIX, ATTACHMENTS_ID } from './consts' -import PouchDB from './PouchDB' -import { buildCloudSyncUrl, User } from '../accounts' -import { setHeader } from '../utils/http' - -export default class NoteDb { - public initialized = false - - constructor( - public pouchDb: PouchDB.Database, - public id: string, - public name: string - ) {} - - async init() { - await this.upsertNoteListViews() - - const { noteMap, folderMap, tagMap } = await this.getAllDocsMap() - const { missingPathnameSet, missingTagNameSet, requiresUpdate } = values( - noteMap - ).reduce<{ - missingPathnameSet: Set - missingTagNameSet: Set - requiresUpdate: NoteDoc[] - }>( - (obj, noteDoc) => { - if (noteDoc.trashed) { - return obj - } - - if (noteDoc.folderPathname === '/') { - noteDoc.folderPathname = '/default' - obj.requiresUpdate.push(noteDoc) - } - - if (folderMap[noteDoc.folderPathname] == null) { - obj.missingPathnameSet.add(noteDoc.folderPathname) - } - noteDoc.tags.forEach(tagName => { - if (tagMap[tagName] == null) { - obj.missingTagNameSet.add(tagName) - } - }) - return obj - }, - { - missingPathnameSet: new Set(), - missingTagNameSet: new Set(), - requiresUpdate: [] - } - ) - - await Promise.all([ - ...[...missingPathnameSet].map(pathname => this.upsertFolder(pathname)), - ...[...missingTagNameSet].map(tagName => this.upsertTag(tagName)), - ...requiresUpdate.map(note => this.updateNote(note._id, note)) - ]) - - if (folderMap['/'] != null) { - await this.removeFolder('/') - } - } - - async getFolder(path: string): Promise { - return this.getDoc(getFolderId(path)) - } - - async upsertFolder( - pathname: string, - props?: Partial - ): Promise { - if (!isFolderPathnameValid(pathname)) { - throw createUnprocessableEntityError( - `pathname is invalid, got \`${pathname}\`` - ) - } - if (pathname !== '/') { - await this.doesParentFolderExistOrCreate(pathname) - } - const folder = await this.getFolder(pathname) - if (folder != null && props == null) { - return folder - } - const now = getNow() - const folderDocProps = { - ...(folder || { - _id: getFolderId(pathname), - createdAt: now, - data: {} - }), - ...props, - updatedAt: now - } - const { rev } = await this.pouchDb.put(folderDocProps) - - return { - _id: folderDocProps._id, - createdAt: folderDocProps.createdAt, - updatedAt: folderDocProps.updatedAt, - data: folderDocProps.data, - _rev: rev - } - } - - async doesParentFolderExistOrCreate(pathname: string) { - const parentPathname = getParentFolderPathname(pathname) - if (parentPathname !== '/') { - await this.upsertFolder(parentPathname) - } - } - - async getAllDocsMap(): Promise { - const allDocsResponse = await this.pouchDb.allDocs({ - include_docs: true - }) - - const map: AllDocsMap = { - noteMap: {}, - folderMap: {}, - tagMap: {} - } - - return allDocsResponse.rows.reduce((map, row) => { - const { doc } = row - if (isNoteDoc(doc)) { - map.noteMap[doc._id] = { - ...doc, - storageId: this.id - } as PopulatedNoteDoc - } else if (isFolderDoc(doc)) { - map.folderMap[getFolderPathname(doc._id)] = doc - } else if (isTagDoc(doc)) { - map.tagMap[getTagName(doc._id)] = doc - } - return map - }, map) - } - - async getTag(tagName: string): Promise { - return this.getDoc(getTagId(tagName)) - } - - async getDoc( - docId: string - ): Promise { - try { - return await this.pouchDb.get(docId) - } catch (error) { - switch (error.name) { - case 'not_found': - return null - default: - throw error - } - } - } - - async upsertTag(tagName: string, props?: Partial) { - if (!isTagNameValid(tagName)) { - throw createUnprocessableEntityError( - `tag name is invalid, got \`${tagName}\`` - ) - } - - const tag = await this.getTag(tagName) - if (tag != null && props == null) { - return tag - } - - const now = getNow() - const tagDocProps = { - ...(tag || { - _id: getTagId(tagName), - createdAt: now, - data: {} - }), - ...props, - updatedAt: now - } - const { rev } = await this.pouchDb.put(tagDocProps) - - return { - _id: tagDocProps._id, - createdAt: tagDocProps.createdAt, - updatedAt: tagDocProps.updatedAt, - data: tagDocProps.data, - _rev: rev - } - } - - async getNote(noteId: string): Promise { - return this.getDoc(noteId) - } - - async createNote( - noteProps: Partial = {} - ): Promise { - const now = getNow() - const noteDocProps: ExceptRev = { - _id: generateNoteId(), - title: '', - content: '', - tags: [], - folderPathname: '/default', - data: {}, - bookmarked: false, - ...noteProps, - createdAt: now, - updatedAt: now, - trashed: false - } - - await this.upsertFolder(noteDocProps.folderPathname) - await Promise.all(noteDocProps.tags.map(tagName => this.upsertTag(tagName))) - - const { rev } = await this.pouchDb.put(noteDocProps) - - return { - ...noteDocProps, - _rev: rev - } - } - - async updateNote(noteId: string, noteProps: Partial) { - const note = await this.getNote(noteId) - if (note == null) - throw createNotFoundError(`The note \`${noteId}\` does not exist`) - - if (noteProps.folderPathname) { - await this.upsertFolder(noteProps.folderPathname) - } - if (noteProps.tags) { - await Promise.all(noteProps.tags.map(tagName => this.upsertTag(tagName))) - } - - const now = getNow() - const noteDocProps = { - ...note, - ...noteProps, - updatedAt: now - } - const { rev } = await this.pouchDb.put(noteDocProps) - - return { - ...noteDocProps, - _rev: rev - } - } - - async findNotesByFolder(folderPathname: string): Promise { - const { rows } = await this.pouchDb.query('notes/by_folder', { - key: folderPathname, - include_docs: true - }) - - return rows.map(row => row.doc!) - } - - async findNotesByTag(tagName: string): Promise { - const { rows } = await this.pouchDb.query('notes/by_tag', { - key: tagName, - include_docs: true - }) - - return rows.map(row => row.doc!) - } - - async upsertNoteListViews() { - const ddoc = await this.getDoc< - { - views: { [key: string]: { map: string } } - } & PouchDB.Core.GetMeta & - PouchDB.Core.IdMeta - >('_design/notes') - const byFolderMap = `function(doc) { - if (doc._id.startsWith('note:')) { - emit(doc.folderPathname); - } - }` - const byTagMap = `function(doc) { - if (doc._id.startsWith('note:')) { - doc.tags.forEach(function(tag){ - emit(tag); - }); - } - }` - if (ddoc != null) { - if ( - ddoc.views.by_folder.map === byFolderMap && - ddoc.views.by_tag.map === byTagMap - ) { - return ddoc - } - } - - return this.pouchDb.put({ - ...(ddoc || { - _id: '_design/notes' - }), - views: { - by_folder: { - map: byFolderMap - }, - by_tag: { - map: byTagMap - } - } - }) - } - - async trashNote(noteId: string): Promise { - const note = await this.getNote(noteId) - if (note == null) - throw createNotFoundError(`The note \`${noteId}\` does not exist`) - - const noteDocProps = { - ...note, - trashed: true - } - const { rev } = await this.pouchDb.put(noteDocProps) - - return { - ...noteDocProps, - _rev: rev - } - } - - async untrashNote(noteId: string): Promise { - const note = await this.getNote(noteId) - if (note == null) - throw createNotFoundError(`The note \`${noteId}\` does not exist`) - - await this.upsertFolder(note.folderPathname) - - await Promise.all( - note.tags.map(tag => { - this.upsertTag(tag) - }) - ) - - const noteDocProps = { - ...note, - trashed: false - } - const { rev } = await this.pouchDb.put(noteDocProps) - - return { - ...noteDocProps, - _rev: rev - } - } - - async purgeNote(noteId: string): Promise { - const note = await this.getNote(noteId) - if (note == null) - throw createNotFoundError(`The note \`${noteId}\` does not exist`) - - await this.pouchDb.remove(note) - } - - async removeTag(tagName: string): Promise { - const notes = await this.findNotesByTag(tagName) - await Promise.all( - notes.map(note => { - return this.updateNote(note._id, { - tags: note.tags.filter(tag => tag !== tagName) - }) - }) - ) - - const tag = await this.getTag(tagName) - if (tag != null) { - this.pouchDb.remove(tag) - } - } - - async removeFolder(folderPathname: string): Promise { - const foldersToDelete = await this.getAllFolderUnderPathname(folderPathname) - - await Promise.all( - foldersToDelete.map(folder => - this.trashAllNotesInFolder(getFolderPathname(folder._id)) - ) - ) - - await Promise.all( - foldersToDelete.map(folder => this.pouchDb.remove(folder)) - ) - } - - async getAllFolderUnderPathname( - folderPathname: string - ): Promise { - const [folder, { rows }] = await Promise.all([ - this.getFolder(folderPathname), - this.pouchDb.allDocs({ - startkey: `${getFolderId(folderPathname)}/`, - endkey: `${getFolderId(folderPathname)}/\ufff0`, - include_docs: true - }) - ]) - const folderList = rows.map(row => row.doc!) - if (folder != null) { - folderList.unshift(folder) - } - - return folderList - } - - async trashAllNotesInFolder(folderPathname: string): Promise { - const notes = await this.findNotesByFolder(folderPathname) - - await Promise.all( - notes.filter(note => !note.trashed).map(note => this.trashNote(note._id)) - ) - } - - async getAllFolders(): Promise { - const allDocsResponse = await this.pouchDb.allDocs({ - startkey: `${FOLDER_ID_PREFIX}/`, - endkey: `${FOLDER_ID_PREFIX}/\ufff0`, - include_docs: true - }) - return allDocsResponse.rows.map(row => row.doc!) - } - - async getFoldersByPathnames(pathnames: string[]): Promise { - if (pathnames.length === 0) { - return [] - } - const allDocsResponse = await this.pouchDb.allDocs({ - keys: pathnames.map(pathname => getFolderId(pathname)), - include_docs: true - }) - return allDocsResponse.rows.map(row => row.doc!) - } - - async sync( - user: User, - cloudStorage: { id: number } - ): Promise> { - const cloudPouch = new PouchDB( - buildCloudSyncUrl(cloudStorage.id, user.id), - { - fetch: (url, opts = {}) => { - if (opts.headers == null) { - opts.headers = new Headers() - } - - opts.headers = setHeader( - 'Authorization', - `Bearer ${user.token}`, - opts.headers - ) - - return PouchDB.fetch(url, opts) - } - } - ) - - return new Promise((resolve, reject) => { - this.pouchDb - .sync(cloudPouch, { live: false }) - .on('error', reject) - .on('complete', resolve) - }) - } - - async upsertAttachments(files: File[]): Promise { - const { _rev } = await this.pouchDb.get(ATTACHMENTS_ID) - let currentRev = _rev - const attachments: Attachment[] = [] - for (const file of files) { - const { name, ext } = parsePath(file.name) - const fileName = `${dashify(name)}${ext}` - const response = await this.pouchDb.putAttachment( - ATTACHMENTS_ID, - fileName, - currentRev, - file, - file.type - ) - currentRev = response.rev - const data = await this.pouchDb.getAttachment(ATTACHMENTS_ID, fileName) - attachments.push({ - name: fileName, - type: file.type, - blob: data as Blob - }) - } - - return attachments - } - - async removeAttachment(fileName: string): Promise { - const { _rev } = await this.pouchDb.get(ATTACHMENTS_ID) - await this.pouchDb.removeAttachment(ATTACHMENTS_ID, fileName, _rev) - } - - async getAttachmentMap(): Promise> { - let attachmentDoc - try { - attachmentDoc = await this.pouchDb.get(ATTACHMENTS_ID, { - attachments: true, - binary: true - }) - } catch (error) { - if (error.name !== 'not_found') { - throw error - } - await this.pouchDb.put({ _id: ATTACHMENTS_ID }) - attachmentDoc = await this.pouchDb.get(ATTACHMENTS_ID, { - attachments: true, - binary: true - }) - } - - const { _attachments } = attachmentDoc - if (_attachments == null) { - return {} - } - return Object.entries(_attachments).reduce( - (map, [key, attachment]) => { - map[key] = { - name: key, - type: attachment.content_type, - blob: (attachment as PouchDB.Core.FullAttachment).data as Blob - } - return map - }, - {} as ObjectMap - ) - } -}