From 2995e65d294fa87df940c7d390acc4644bc2597e Mon Sep 17 00:00:00 2001 From: Dinesh Singh Date: Tue, 21 Jun 2022 10:19:01 +0530 Subject: [PATCH 1/6] Unique note path, short block Ids added --- apps/webapp/src/Hooks/useNewNodes.ts | 2 +- libs/core/src/Utils/idGenerator.ts | 2 +- libs/shared/src/Stores/dataStoreConstructor.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/webapp/src/Hooks/useNewNodes.ts b/apps/webapp/src/Hooks/useNewNodes.ts index 3a0c66b30..4f758e42f 100644 --- a/apps/webapp/src/Hooks/useNewNodes.ts +++ b/apps/webapp/src/Hooks/useNewNodes.ts @@ -23,7 +23,7 @@ export const useNewNodes = () => { const addNodeOrNodes = async (ilink, showAlert, parentId?, content?: any[], save?: boolean) => { try { - ilink = checkValidILink({ ilink, parentId, showAlert }) + ilink = checkValidILink({ ilink, parentId, showAlert: false }) const nodeUID = generateNodeUID() const parentILink = getParentILink(ilink) diff --git a/libs/core/src/Utils/idGenerator.ts b/libs/core/src/Utils/idGenerator.ts index 462667523..f607e8a4d 100644 --- a/libs/core/src/Utils/idGenerator.ts +++ b/libs/core/src/Utils/idGenerator.ts @@ -25,7 +25,7 @@ export const generateNodeId = () => `${NODE_ID_PREFIX}${ID_SEPARATOR}${nanoid()} export const generateWorkspaceId = () => `${WORKSPACE_ID_PREFIX}${ID_SEPARATOR}${nanoid()}` export const generateIgId = () => `${IG_ID_PREFIX}${ID_SEPARATOR}${nanoid()}` export const generateSyncBlockId = () => `${SYNC_BLOCK_ID_PREFIX}${ID_SEPARATOR}${nanoid()}` -export const generateTempId = () => `${TEMP_ID_PREFIX}${ID_SEPARATOR}${nanoid()}` +export const generateTempId = () => `${TEMP_ID_PREFIX}${ID_SEPARATOR}${shortId()}` export const generateSnippetId = () => `${SNIPPET_PREFIX}${ID_SEPARATOR}${nanoid()}` export const generateSyncTempId = () => `${SYNCTEMP_PREFIX}${ID_SEPARATOR}${nanoid()}` export const generateTodoId = () => `${TODO_PREFIX}${ID_SEPARATOR}${nanoid()}` diff --git a/libs/shared/src/Stores/dataStoreConstructor.ts b/libs/shared/src/Stores/dataStoreConstructor.ts index 240169c67..c369bd855 100644 --- a/libs/shared/src/Stores/dataStoreConstructor.ts +++ b/libs/shared/src/Stores/dataStoreConstructor.ts @@ -123,7 +123,8 @@ export const dataStoreConstructor = (set, get) => ({ if (!reservedOrUnique) { throw Error(`ERROR-RESERVED: PATH (${ilink}) IS RESERVED. YOU DUMB`) } - return ilink + + return reservedOrUnique.unique }, setIlinks: (ilinks) => { From 18fc67905c5d5eeb853ab45de6ef9e420805422f Mon Sep 17 00:00:00 2001 From: Dinesh Singh Date: Tue, 21 Jun 2022 19:55:44 +0530 Subject: [PATCH 2/6] Multiple save Snippet API calls fixed --- apps/webapp/src/Components/Editor/SnippetEditor.tsx | 3 --- apps/webapp/src/Hooks/useEditorBuffer.tsx | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/webapp/src/Components/Editor/SnippetEditor.tsx b/apps/webapp/src/Components/Editor/SnippetEditor.tsx index 35c157105..2050aa957 100644 --- a/apps/webapp/src/Components/Editor/SnippetEditor.tsx +++ b/apps/webapp/src/Components/Editor/SnippetEditor.tsx @@ -13,7 +13,6 @@ import tinykeys from 'tinykeys' import { useSnippetBuffer, useSnippetBufferStore } from '../../Hooks/useEditorBuffer' import { useRouting, ROUTE_PATHS, NavigationType } from '../../Hooks/useRouting' import { SnippetSaverButton } from '../Saver' -import { useApi } from '../../Hooks/useApi' import { useSnippetStore } from '../../Stores/useSnippetStore' type Inputs = { @@ -24,7 +23,6 @@ const SnippetEditor = () => { const snippet = useSnippetStore((store) => store.editor.snippet) const { goTo } = useRouting() - const api = useApi() const { register, formState: { errors } @@ -69,7 +67,6 @@ const SnippetEditor = () => { mog('onChangeSave', { val }) if (val) { addOrUpdateValBuffer(snippet.id, val) - api.saveSnippetAPI(snippet.id, snippet.title, val) } } diff --git a/apps/webapp/src/Hooks/useEditorBuffer.tsx b/apps/webapp/src/Hooks/useEditorBuffer.tsx index ee1a27241..f611301cf 100644 --- a/apps/webapp/src/Hooks/useEditorBuffer.tsx +++ b/apps/webapp/src/Hooks/useEditorBuffer.tsx @@ -7,6 +7,7 @@ import { useSnippets } from './useSnippets' import { useDataSaverFromContent } from './useSave' import { getContent } from '../Stores/useEditorStore' import { useSnippetStore } from '../Stores/useSnippetStore' +import { useApi } from './useApi' interface BufferStore { buffer: Record @@ -94,6 +95,7 @@ export const useSnippetBufferStore = create((set, get) => ({ })) export const useSnippetBuffer = () => { + const api = useApi() const add2Buffer = useSnippetBufferStore((s) => s.add) const clearBuffer = useSnippetBufferStore((s) => s.clear) const updateSnippetContent = useSnippetStore((s) => s.updateSnippetContentAndTitle) @@ -112,8 +114,10 @@ export const useSnippetBuffer = () => { if (Object.keys(buffer).length > 0) { const saved = Object.entries(buffer) .map(([snippetId, val]) => { + api.saveSnippetAPI(snippetId, val.title, val?.content) updateSnippetContent(snippetId, val.content, val.title, val.isTemplate) const snippet = getSnippet(snippetId) + // TODO: Switch snippet to template index if (snippet) updateSnippetIndex({ ...snippet, content: val.content, title: val.title }) return true From 4c5a0d1442d088ab661d4a517155d075bd21b3c2 Mon Sep 17 00:00:00 2001 From: Dinesh Singh Date: Tue, 21 Jun 2022 19:55:54 +0530 Subject: [PATCH 3/6] Empty notes content, search-snippet broken ui fixed --- apps/webapp/src/Components/Editor/ContentEditor.tsx | 2 +- libs/shared/src/Style/Search.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/webapp/src/Components/Editor/ContentEditor.tsx b/apps/webapp/src/Components/Editor/ContentEditor.tsx index 92e6e7a2e..da01a548a 100644 --- a/apps/webapp/src/Components/Editor/ContentEditor.tsx +++ b/apps/webapp/src/Components/Editor/ContentEditor.tsx @@ -107,7 +107,7 @@ const ContentEditor = () => { readOnly={readOnly} nodeUID={nodeId} nodePath={node.path} - content={fsContent?.content ?? defaultContent.content} + content={fsContent?.content?.length ? fsContent?.content : defaultContent.content} onChange={onChangeSave} /> diff --git a/libs/shared/src/Style/Search.tsx b/libs/shared/src/Style/Search.tsx index 9cbdd75b1..67be5a0c0 100644 --- a/libs/shared/src/Style/Search.tsx +++ b/libs/shared/src/Style/Search.tsx @@ -202,6 +202,7 @@ export const SearchViewContainer = styled.div` export const SearchContainer = styled.div` margin: ${({ theme: { spacing } }) => `calc(2 * ${spacing.large}) ${spacing.large} ${spacing.medium}`}; position: relative; + width: 100%; min-height: 60vh; ` From 79014f3c62a55f5d5f274f407ce92dbeeec13a2a Mon Sep 17 00:00:00 2001 From: Dinesh Singh Date: Wed, 22 Jun 2022 14:58:00 +0530 Subject: [PATCH 4/6] Auto save, snippet & editor unmount save added --- .../src/Components/Editor/ContentEditor.tsx | 9 +++- apps/webapp/src/Components/Editor/Editor.tsx | 25 +++++++-- .../src/Components/Editor/SnippetEditor.tsx | 7 ++- apps/webapp/src/Components/Saver.tsx | 9 +++- .../src/Editor/Actions/withDraggables.tsx | 13 +++-- apps/webapp/src/Hooks/useApi.ts | 4 +- apps/webapp/src/Stores/useAuth.ts | 3 +- apps/webapp/src/Views/SearchView.tsx | 4 +- apps/webapp/src/Views/Snippets.tsx | 53 ++++++++++++++----- libs/core/src/Types/Snippet.ts | 4 +- libs/shared/src/Style/Search.tsx | 2 + 11 files changed, 100 insertions(+), 33 deletions(-) diff --git a/apps/webapp/src/Components/Editor/ContentEditor.tsx b/apps/webapp/src/Components/Editor/ContentEditor.tsx index da01a548a..0a4c1c81e 100644 --- a/apps/webapp/src/Components/Editor/ContentEditor.tsx +++ b/apps/webapp/src/Components/Editor/ContentEditor.tsx @@ -34,7 +34,7 @@ const ContentEditor = () => { const isBlockMode = useBlockStore((store) => store.isBlockMode) const { setShowLoader } = useLayoutStore() - const { addOrUpdateValBuffer, getBufferVal } = useEditorBuffer() + const { addOrUpdateValBuffer, saveAndClearBuffer, getBufferVal } = useEditorBuffer() const { node, fsContent } = useEditorStore( (state) => ({ nodeid: state.node.nodeid, node: state.node, fsContent: state.content }), shallow @@ -95,6 +95,10 @@ const ContentEditor = () => { } }, []) + useEffect(() => { + return () => saveAndClearBuffer() + }, []) + return ( @@ -107,6 +111,9 @@ const ContentEditor = () => { readOnly={readOnly} nodeUID={nodeId} nodePath={node.path} + onAutoSave={(val) => { + saveAndClearBuffer() + }} content={fsContent?.content?.length ? fsContent?.content : defaultContent.content} onChange={onChangeSave} /> diff --git a/apps/webapp/src/Components/Editor/Editor.tsx b/apps/webapp/src/Components/Editor/Editor.tsx index 121054c55..20f925101 100644 --- a/apps/webapp/src/Components/Editor/Editor.tsx +++ b/apps/webapp/src/Components/Editor/Editor.tsx @@ -7,7 +7,7 @@ import { LinkElement, MediaEmbedElement, TableWrapper } from '@mexit/shared' import TagWrapper from './TagWrapper' import BallonMarkToolbarButtons from './BalloonToolbar/EditorBalloonToolbar' -import { ELEMENT_ILINK, ELEMENT_INLINE_BLOCK, ELEMENT_TAG, ELEMENT_TODO_LI } from '@mexit/core' +import { ELEMENT_ILINK, ELEMENT_INLINE_BLOCK, ELEMENT_TAG, ELEMENT_TODO_LI, NodeEditorContent } from '@mexit/core' import Todo from '../Todo' import { useEditorChange } from '@mexit/shared' import { EditorStyles } from '@mexit/shared' @@ -38,9 +38,10 @@ interface EditorProps { readOnly?: boolean onChange?: any // eslint-disable-line @typescript-eslint/no-explicit-any autoFocus?: boolean + onAutoSave?: (content: NodeEditorContent) => void } -const Editor: React.FC = ({ nodeUID, nodePath, content, readOnly, onChange, autoFocus }) => { +const Editor: React.FC = ({ nodeUID, nodePath, content, readOnly, onChange, autoFocus, onAutoSave }) => { const tags = useDataStore((store) => store.tags) const addTag = useDataStore((store) => store.addTag) const ilinks = useDataStore((store) => store.ilinks) @@ -179,10 +180,24 @@ const Editor: React.FC = ({ nodeUID, nodePath, content, readOnly, o withBalloonToolbar: true } - const debounced = useDebouncedCallback((value) => { + const onDelayPerform = useDebouncedCallback((value) => { const f = !readOnly && typeof onChange === 'function' ? onChange : () => undefined f(value) - }, 1000) + }, 500) + + const saveAfterDelay = useDebouncedCallback( + typeof onAutoSave === 'function' ? onAutoSave : () => undefined, + 30 * 1000 // After 30 seconds + ) + + const onChangeContent = (val: NodeEditorContent) => { + onDelayPerform(val) + + if (onAutoSave) { + saveAfterDelay.cancel() + saveAfterDelay(val) + } + } const comboboxConfig: ComboboxConfig = { onChangeConfig: comboOnChangeConfig, @@ -199,7 +214,7 @@ const Editor: React.FC = ({ nodeUID, nodePath, content, readOnly, o }} BalloonMarkToolbarButtons={} // debug - onChange={debounced} + onChange={onChangeContent} options={editorOptions} editorId={nodeUID} value={content} diff --git a/apps/webapp/src/Components/Editor/SnippetEditor.tsx b/apps/webapp/src/Components/Editor/SnippetEditor.tsx index 2050aa957..bcf445b0e 100644 --- a/apps/webapp/src/Components/Editor/SnippetEditor.tsx +++ b/apps/webapp/src/Components/Editor/SnippetEditor.tsx @@ -101,6 +101,7 @@ const SnippetEditor = () => { }) return () => { + saveSnippet() unsubscribe() } }, []) @@ -112,12 +113,13 @@ const SnippetEditor = () => { // const snippet = useSnippetStore.getState().sn } - const returnToSnippets = () => { + const saveSnippet = () => { saveAndClearBuffer() // updater() - goTo(ROUTE_PATHS.snippets, NavigationType.push) } + const returnToSnippets = () => goTo(ROUTE_PATHS.snippets, NavigationType.push) + const defaultValue = snippet && snippet.title !== DRAFT_NODE ? snippet.title : '' const onDelay = debounce((value) => onChangeTitle(value), 250) @@ -158,6 +160,7 @@ const SnippetEditor = () => { /> */} diff --git a/apps/webapp/src/Components/Saver.tsx b/apps/webapp/src/Components/Saver.tsx index 427db2fea..6e6a5f075 100644 --- a/apps/webapp/src/Components/Saver.tsx +++ b/apps/webapp/src/Components/Saver.tsx @@ -203,7 +203,12 @@ interface SnippetSaverButtonProps extends SaverButtonProps { getSnippetExtras: () => SnippetExtras } -export const SnippetSaverButton = ({ callbackAfterSave, title, getSnippetExtras }: SnippetSaverButtonProps) => { +export const SnippetSaverButton = ({ + callbackAfterSave, + title, + getSnippetExtras, + noButton +}: SnippetSaverButtonProps) => { const { onSave: onSaveFs } = useSnippetSaver() const shortcuts = useHelpStore((state) => state.shortcuts) const { trackEvent } = useAnalytics() @@ -229,6 +234,8 @@ export const SnippetSaverButton = ({ callbackAfterSave, title, getSnippetExtras } }) + if (noButton) return <> + return ( { <>
Drag to move
Click to select
-
- - {element && element.id} - {element && element.type} - -
+ {IS_DEV && ( +
+ + {element && element.id} - {element && element.type} + +
+ )} ) } diff --git a/apps/webapp/src/Hooks/useApi.ts b/apps/webapp/src/Hooks/useApi.ts index a3f965918..02fadfbc1 100644 --- a/apps/webapp/src/Hooks/useApi.ts +++ b/apps/webapp/src/Hooks/useApi.ts @@ -339,8 +339,10 @@ export const useApi = () => { } const getSnippetById = async (id: string) => { + const url = apiURLs.getSnippetById(id) + const data = await client - .get(apiURLs.getSnippetById(id), { + .get(url, { headers: { [WORKSPACE_HEADER]: getWorkspaceId(), Accept: 'application/json, text/plain, */*' diff --git a/apps/webapp/src/Stores/useAuth.ts b/apps/webapp/src/Stores/useAuth.ts index 564458f3b..2cf5206a5 100644 --- a/apps/webapp/src/Stores/useAuth.ts +++ b/apps/webapp/src/Stores/useAuth.ts @@ -76,8 +76,7 @@ export const useAuthentication = () => { res.map((item) => ({ icon: 'ri:quill-pen-line', id: item.snippetID, - title: item.title, - content: [{ children: [{ text: '' }] }] + title: item.title })) ) }) diff --git a/apps/webapp/src/Views/SearchView.tsx b/apps/webapp/src/Views/SearchView.tsx index 47a95fa28..ae67b0504 100644 --- a/apps/webapp/src/Views/SearchView.tsx +++ b/apps/webapp/src/Views/SearchView.tsx @@ -356,7 +356,7 @@ const SearchView = ({ const ResultsView = ( {view === View.Card && RenderStartCard && } - {result.map((c, i) => { + {result?.map((c, i) => { return ( ({ {RenderFilters && filters.length > 0 ? : null} - {result.length > 0 ? ( + {result?.length > 0 ? ( view === View.List && RenderPreview && options?.splitOptions?.type !== SplitType.NONE ? ( { // const { getNode } = useNodes() const { goTo } = useRouting() const api = useApi() + const initialSnippets: any[] = snippets.map((snippet) => ({ id: snippet.id, title: snippet.title, text: parseBlock(snippet.content || [{ text: '' }]) })) + mog('Initial snippets', { snippets }) + const onSearch = async (newSearchTerm: string): Promise => { const res = await queryIndex(['template', 'snippet'], newSearchTerm) - if (newSearchTerm === '' && res.length === 0) { + mog('new search is here', { newSearchTerm, res }) + if (!newSearchTerm && res?.length === 0) { + mog('Inside', {}) return initialSnippets } @@ -97,12 +111,20 @@ const Snippets = () => { useEffect(() => { const snippets = getSnippets() - - snippets.forEach(async (item) => { - await api.getSnippetById(item.id).then((response) => { - updateSnippet(response as Snippet) - }) - }) + const unfetchedSnippets = snippets.filter((snippet) => !snippet.content) + + try { + Promise.allSettled( + unfetchedSnippets.map( + async (item) => + await api.getSnippetById(item.id).then((response) => { + updateSnippet(response as Snippet) + }) + ) + ) + } catch (err) { + mog('Failed to fetch snippets', { err }) + } }, []) // Forwarding ref to focus on the selected result @@ -171,7 +193,10 @@ const Snippets = () => { {snip.title} - + ) } else @@ -182,6 +207,8 @@ const Snippets = () => { ) } + const randId = useMemo(() => generateTempId(), [initialSnippets]) + return ( @@ -192,8 +219,8 @@ const Snippets = () => { i.id} onSelect={onSelect} @@ -201,7 +228,7 @@ const Snippets = () => { onSearch={onSearch} RenderItem={RenderItem} RenderPreview={RenderPreview} - RenderStartCard={RenderStartCard} + // RenderStartCard={RenderStartCard} /> ) diff --git a/libs/core/src/Types/Snippet.ts b/libs/core/src/Types/Snippet.ts index 0b4862f82..fa12de5b6 100644 --- a/libs/core/src/Types/Snippet.ts +++ b/libs/core/src/Types/Snippet.ts @@ -1,8 +1,10 @@ +import { NodeEditorContent } from './Editor' + export interface Snippet { id: string title: string icon?: string - content: any[] + content?: NodeEditorContent isTemplate?: boolean } diff --git a/libs/shared/src/Style/Search.tsx b/libs/shared/src/Style/Search.tsx index 67be5a0c0..2dfc3f280 100644 --- a/libs/shared/src/Style/Search.tsx +++ b/libs/shared/src/Style/Search.tsx @@ -323,6 +323,8 @@ export const ResultMetaData = styled.div` export const Result = styled(animated.div)<{ selected?: boolean; view?: View }>` background-color: ${({ theme }) => theme.colors.gray[9]}; + user-select: none; + :hover { cursor: pointer; } From 9fa39cb3244a60b43c0726d6d9de607da324f417 Mon Sep 17 00:00:00 2001 From: Dinesh Singh Date: Wed, 22 Jun 2022 20:39:11 +0530 Subject: [PATCH 5/6] Combobox create tags, list all tags fixed --- apps/webapp/src/Actions/Components/Tags.tsx | 11 +++++------ apps/webapp/src/Components/Editor/Editor.tsx | 4 ++-- .../MultiCombobox/useMultiComboboxChange.ts | 7 +++++-- apps/webapp/src/Hooks/useApi.ts | 5 ++++- apps/webapp/src/Hooks/useTags.ts | 13 +++++++++++-- apps/webapp/src/Stores/useDataStore.ts | 4 ++-- apps/webapp/src/Views/Snippets.tsx | 9 +++++++++ apps/webapp/src/Views/ViewSelector.tsx | 5 +---- libs/core/src/Types/Editor.ts | 3 +-- libs/core/src/Types/Store.ts | 1 + libs/core/src/Utils/parsers.ts | 2 +- libs/shared/src/Stores/dataStoreConstructor.ts | 17 +++++++++++------ libs/shared/src/Style/ViewSelector.ts | 1 + 13 files changed, 54 insertions(+), 28 deletions(-) diff --git a/apps/webapp/src/Actions/Components/Tags.tsx b/apps/webapp/src/Actions/Components/Tags.tsx index 2b116486d..e26a1a40c 100644 --- a/apps/webapp/src/Actions/Components/Tags.tsx +++ b/apps/webapp/src/Actions/Components/Tags.tsx @@ -47,13 +47,12 @@ export const Tags: React.FC = ({ userTags, addNewTag, removeTag }: Ta const { key } = e const trimmedInput = input.trim() const tagTexts = new Array() - userTags.forEach((tag) => tagTexts.push(tag.text)) + userTags.forEach((tag) => tagTexts.push(tag.value)) if (key === 'Enter' && trimmedInput.length && !tagTexts.includes(trimmedInput)) { e.preventDefault() const t: Tag = { - id: `TAG_${nanoid()}`, - text: trimmedInput + value: trimmedInput } addNewTag(t) setInput('') @@ -64,7 +63,7 @@ export const Tags: React.FC = ({ userTags, addNewTag, removeTag }: Ta const poppedTag = tagsCopy.pop() e.preventDefault() removeTag(poppedTag) - setInput(poppedTag.text) + setInput(poppedTag.value) } setIsKeyReleased(false) @@ -89,8 +88,8 @@ export const Tags: React.FC = ({ userTags, addNewTag, removeTag }: Ta {/* TODO: recommend and show recent used tags */} {userTags.map((tag) => ( - - {tag.text} + + {tag.value} ))} diff --git a/apps/webapp/src/Components/Editor/Editor.tsx b/apps/webapp/src/Components/Editor/Editor.tsx index 20f925101..b0bfeab54 100644 --- a/apps/webapp/src/Components/Editor/Editor.tsx +++ b/apps/webapp/src/Components/Editor/Editor.tsx @@ -153,7 +153,7 @@ const Editor: React.FC = ({ nodeUID, nodePath, content, readOnly, o tag: { cbKey: ComboboxKey.TAG, trigger: '#', - data: tags.map((t) => ({ ...t, value: t.text })), + data: tags.map((t) => ({ ...t, text: t.value })), icon: 'ri:hashtag' }, slash_command: { @@ -183,7 +183,7 @@ const Editor: React.FC = ({ nodeUID, nodePath, content, readOnly, o const onDelayPerform = useDebouncedCallback((value) => { const f = !readOnly && typeof onChange === 'function' ? onChange : () => undefined f(value) - }, 500) + }, 400) const saveAfterDelay = useDebouncedCallback( typeof onAutoSave === 'function' ? onAutoSave : () => undefined, diff --git a/apps/webapp/src/Editor/Components/MultiCombobox/useMultiComboboxChange.ts b/apps/webapp/src/Editor/Components/MultiCombobox/useMultiComboboxChange.ts index 99951e413..676f30331 100644 --- a/apps/webapp/src/Editor/Components/MultiCombobox/useMultiComboboxChange.ts +++ b/apps/webapp/src/Editor/Components/MultiCombobox/useMultiComboboxChange.ts @@ -1,7 +1,7 @@ import { useCallback } from 'react' import { OnChange, usePlateEditorRef } from '@udecode/plate' -import { getTimeInText, isReservedOrClash, toLocaleString, withoutContinuousDelimiter } from '@mexit/core' +import { getTimeInText, isReservedOrClash, mog, toLocaleString, withoutContinuousDelimiter } from '@mexit/core' import { useLinks } from '../../../Hooks/useLinks' import { useRouting } from '../../../Hooks/useRouting' @@ -71,6 +71,7 @@ const useMultiComboboxOnChange = (editorId: string, keys: Record item.text) + mog('data', { data }) + + const searchItems = fuzzySearch(data, searchTerm || '', (item) => item?.text || '') const { isExtended, extendedCommands } = getCommandExtended(search.textAfterTrigger, keys) diff --git a/apps/webapp/src/Hooks/useApi.ts b/apps/webapp/src/Hooks/useApi.ts index 02fadfbc1..7ffb1a58b 100644 --- a/apps/webapp/src/Hooks/useApi.ts +++ b/apps/webapp/src/Hooks/useApi.ts @@ -11,12 +11,14 @@ import { useInternalLinks } from './useInternalLinks' import { useContentStore } from '../Stores/useContentStore' import { useDataStore } from '../Stores/useDataStore' import { useLinks } from './useLinks' +import { useTags } from './useTags' export const useApi = () => { const getWorkspaceId = useAuthStore((store) => store.getWorkspaceId) const setMetadata = useContentStore((store) => store.setMetadata) const setContent = useContentStore((store) => store.setContent) const userDetails = useAuthStore((store) => store.userDetails) + const { getTags } = useTags() const { getPathFromNodeid, getNodeidFromPath, getTitleFromPath } = useLinks() const { updateILinksFromAddedRemovedPaths, updateSingleILink } = useInternalLinks() const { setNodePublic, setNodePrivate, checkNodePublic } = useDataStore( @@ -147,7 +149,8 @@ export const useApi = () => { title: path.slice(-1)[0], lastEditedBy: useAuthStore.getState().userDetails.email, namespaceIdentifier: DEFAULT_NAMESPACE, - data: serializeContent(content ?? defaultContent.content, nodeid) + data: serializeContent(content ?? defaultContent.content, nodeid), + tags: getTags(nodeid) } if (path.length > 1) { diff --git a/apps/webapp/src/Hooks/useTags.ts b/apps/webapp/src/Hooks/useTags.ts index 264e0cca3..fe6c225fe 100644 --- a/apps/webapp/src/Hooks/useTags.ts +++ b/apps/webapp/src/Hooks/useTags.ts @@ -1,4 +1,5 @@ import { getTagsFromContent, TagsCache } from '@mexit/core' +import { generateTag } from '@mexit/shared' import { useAnalysisStore } from '../Stores/useAnalysis' import { useDataStore } from '../Stores/useDataStore' @@ -19,6 +20,7 @@ export interface RelatedNodes { export const useTags = () => { // const contents = useContentStore((state) => state.contents) + const setTags = useDataStore((store) => store.setTags) const updateTagsCache = useDataStore((state) => state.updateTagsCache) const { getPathFromNodeid } = useLinks() const { isInArchive } = useNodes() @@ -114,6 +116,7 @@ export const useTags = () => { const updateTagsFromContent = (nodeid: string, content: any[]) => { const tagsCache = useDataStore.getState().tagsCache + const oldTags = useDataStore.getState().tags if (content) { const tags: string[] = getTagsFromContent(content) @@ -167,8 +170,14 @@ export const useTags = () => { } }, {}) - // console.log('We are updating', { nodeid, content, tagsCache, updatedTags, newCacheTags }) - updateTagsCache({ ...updatedTags, ...newCacheTags }) + const newTagsCache = { ...updatedTags, ...newCacheTags } + const newTagsForStore = Object.keys(newTagsCache) + const oldTagsFromStore = oldTags.map((t) => t.value) + const alltags = Settify([...oldTagsFromStore, ...newTagsForStore]).map(generateTag) + + console.log('We are updating', { nodeid, content, tagsCache, updatedTags, newCacheTags, alltags }) + setTags(alltags) + updateTagsCache(newTagsCache) } } diff --git a/apps/webapp/src/Stores/useDataStore.ts b/apps/webapp/src/Stores/useDataStore.ts index d1beaf643..f85b26630 100644 --- a/apps/webapp/src/Stores/useDataStore.ts +++ b/apps/webapp/src/Stores/useDataStore.ts @@ -1,11 +1,11 @@ import create from 'zustand' -import { persist } from 'zustand/middleware' +import { devtools, persist } from 'zustand/middleware' import { DataStoreState, IDBStorage } from '@mexit/core' import { dataStoreConstructor } from '@mexit/shared' const useDataStore = create( - persist(dataStoreConstructor, { name: 'mexit-data-store', getStorage: () => IDBStorage }) + persist(devtools(dataStoreConstructor), { name: 'mexit-data-store', getStorage: () => IDBStorage }) ) export { useDataStore } diff --git a/apps/webapp/src/Views/Snippets.tsx b/apps/webapp/src/Views/Snippets.tsx index e9f9e8870..be5857d6d 100644 --- a/apps/webapp/src/Views/Snippets.tsx +++ b/apps/webapp/src/Views/Snippets.tsx @@ -161,6 +161,15 @@ const Snippets = () => { {snip.title} {parseBlock(snip.content, ' ')} + { + ev.stopPropagation() + onDeleteSnippet(snip.id) + }} + /> ) diff --git a/apps/webapp/src/Views/ViewSelector.tsx b/apps/webapp/src/Views/ViewSelector.tsx index d83e11c67..534266e7f 100644 --- a/apps/webapp/src/Views/ViewSelector.tsx +++ b/apps/webapp/src/Views/ViewSelector.tsx @@ -10,16 +10,13 @@ const ViewSelector = ({ onChangeView, currentView }: { onChangeView: (view: View // mog('ViewSelector', { currentView, entries: Object.entries(View) }) return ( -
View:
- {Object.entries(View).map(([view, val]) => ( onChangeView(View[view])} > - - {view} + ))}
diff --git a/libs/core/src/Types/Editor.ts b/libs/core/src/Types/Editor.ts index f1a93fbe6..a0d46951b 100644 --- a/libs/core/src/Types/Editor.ts +++ b/libs/core/src/Types/Editor.ts @@ -96,8 +96,7 @@ export interface ILink { /** Tags */ export interface Tag { - id: string - text: string + value: string } export interface FlexSearchResult { diff --git a/libs/core/src/Types/Store.ts b/libs/core/src/Types/Store.ts index 99ff19086..fca857836 100644 --- a/libs/core/src/Types/Store.ts +++ b/libs/core/src/Types/Store.ts @@ -32,6 +32,7 @@ export interface DataStoreState { // adds tag for combobox addTag: (tag: string) => void + setTags?: (tags: Array) => void setIlinks: (ilinks: ILink[]) => void setBaseNodeId: (baseNodeId: string) => void diff --git a/libs/core/src/Utils/parsers.ts b/libs/core/src/Utils/parsers.ts index e06f79f5c..35068265e 100644 --- a/libs/core/src/Utils/parsers.ts +++ b/libs/core/src/Utils/parsers.ts @@ -3,7 +3,7 @@ import { Snippet } from '../Types/Snippet' export const parseBlock = (content: any[], join?: string): string => { const text: string[] = [] - content.forEach((n) => { + content?.forEach((n) => { if (n.text && n.text !== '') text.push(n.text) if (n.children && n.children.length > 0) { const childText = parseBlock(n.children) diff --git a/libs/shared/src/Stores/dataStoreConstructor.ts b/libs/shared/src/Stores/dataStoreConstructor.ts index c369bd855..48fe6875d 100644 --- a/libs/shared/src/Stores/dataStoreConstructor.ts +++ b/libs/shared/src/Stores/dataStoreConstructor.ts @@ -9,15 +9,12 @@ import { removeLink, Tag, typeInvert, - defaultCommands, - CheckValidILinkProps + defaultCommands } from '@mexit/core' -import { nanoid } from 'nanoid' import { getAllParentIds, getNodeIcon } from '../Utils/treeUtils' export const generateTag = (item: string): Tag => ({ - id: nanoid(), - text: item + value: item }) export const dataStoreConstructor = (set, get) => ({ @@ -53,12 +50,20 @@ export const dataStoreConstructor = (set, get) => ({ }, addTag: (tag) => { - const Tags = Settify([...get().tags.map((t) => t.value), tag]) + const currentTags = get().tags + mog('currentTags', { currentTags, tag }) + + const Tags = Settify([...currentTags.map((t) => t.value), tag]) + set({ tags: Tags.map(generateTag) }) }, + setTags: (tags) => { + set({ tags }) + }, + /* * Add a new ILink to the store * ## Rules diff --git a/libs/shared/src/Style/ViewSelector.ts b/libs/shared/src/Style/ViewSelector.ts index f33ba5e92..f8903d655 100644 --- a/libs/shared/src/Style/ViewSelector.ts +++ b/libs/shared/src/Style/ViewSelector.ts @@ -19,6 +19,7 @@ export const ViewSelectorWrapper = styled.div` export const ViewSelectorButton = styled.div<{ selected: boolean }>` display: flex; align-items: center; + cursor: pointer; justify-content: center; gap: ${({ theme }) => theme.spacing.tiny}; padding: ${({ theme }) => theme.spacing.tiny}; From 8064b2584fb02e39c229fb2327f65697ffecd87e Mon Sep 17 00:00:00 2001 From: Dinesh Singh Date: Thu, 23 Jun 2022 03:59:39 +0530 Subject: [PATCH 6/6] base node load fixed, Update info from content on load --- apps/webapp/src/Components/Editor/Toolbar.tsx | 15 +++++++++-- .../src/Components/EditorInfobar/index.tsx | 18 ++++++++++--- apps/webapp/src/Data/links.tsx | 11 ++++++-- apps/webapp/src/Hooks/useLayout.ts | 3 +++ apps/webapp/src/Hooks/useLoad.ts | 4 +++ apps/webapp/src/Hooks/useNewNodes.ts | 22 +++------------ apps/webapp/src/Hooks/useUpdater.ts | 27 +++++++++++++++++++ apps/webapp/src/Stores/useLayoutStore.ts | 5 ++++ apps/webapp/src/Views/EditorView.tsx | 5 +++- libs/shared/src/Style/Editor.tsx | 2 +- 10 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 apps/webapp/src/Hooks/useUpdater.ts diff --git a/apps/webapp/src/Components/Editor/Toolbar.tsx b/apps/webapp/src/Components/Editor/Toolbar.tsx index 3cb6de0b9..8b7a21ecd 100644 --- a/apps/webapp/src/Components/Editor/Toolbar.tsx +++ b/apps/webapp/src/Components/Editor/Toolbar.tsx @@ -1,6 +1,7 @@ import React from 'react' import focusLine from '@iconify/icons-ri/focus-line' import { useSingleton } from '@tippyjs/react' +import shareLine from '@iconify/icons-ri/share-line' import { Loading, ToolbarTooltip, IconButton } from '@mexit/shared' @@ -19,6 +20,8 @@ const Toolbar = () => { const nodeid = useEditorStore((state) => state.node.nodeid) const [source, target] = useSingleton() const shortcuts = useHelpStore((store) => store.shortcuts) + const showShareOptions = useLayoutStore((store) => store.showShareOptions) + const toggleShareOptions = useLayoutStore((store) => store.toggleShareOptions) return ( @@ -26,11 +29,19 @@ const Toolbar = () => { {fetchingContent && } - + + {/* - + */} { + const showShareOptions = useLayoutStore((store) => store.showShareOptions) + + const transition = useSpring({ + opacity: showShareOptions ? 1 : 0, + height: showShareOptions ? '4rem' : '0rem', + y: showShareOptions ? 0 : 5 + }) + return ( - <> + - + ) } diff --git a/apps/webapp/src/Data/links.tsx b/apps/webapp/src/Data/links.tsx index 3edc08927..507000e3a 100644 --- a/apps/webapp/src/Data/links.tsx +++ b/apps/webapp/src/Data/links.tsx @@ -10,7 +10,7 @@ import searchLine from '@iconify/icons-ri/search-line' import { ROUTE_PATHS } from '../Hooks/useRouting' import { useHelpStore } from '../Stores/useHelpStore' import { NavLinkData } from '../Types/Nav' -import { useLinks } from '../Hooks/useLinks' +import { getNodeidFromPathAndLinks, useLinks } from '../Hooks/useLinks' import { useDataStore } from '../Stores/useDataStore' import { useEditorStore } from '../Stores/useEditorStore' import { useReminderStore } from '../Stores/useReminderStore' @@ -27,12 +27,19 @@ export const GetIcon = (icon: any): React.ReactNode => const useNavlinks = () => { const shortcuts = useHelpStore((store) => store.shortcuts) const nodeid = useEditorStore((store) => store.node.nodeid) + const baseNodeId = useDataStore((store) => store.baseNodeId) + const reminders = useReminderStore((store) => store.reminders) const ilinks = useDataStore((store) => store.ilinks) const archive = useDataStore((store) => store.archive) const tasks = useTodoStore((store) => store.todos) const { getLinkCount } = useLinks() + const noteId = useMemo(() => { + const currentNotId = nodeid === '__null__' ? getNodeidFromPathAndLinks(ilinks, baseNodeId) : nodeid + return currentNotId + }, [nodeid, ilinks]) + const count = useMemo(() => getLinkCount(), [reminders, ilinks, archive, tasks]) const getLinks = () => { @@ -51,7 +58,7 @@ const useNavlinks = () => { // }, { title: 'Notes', - path: `${ROUTE_PATHS.node}/${nodeid}`, + path: `${ROUTE_PATHS.node}/${noteId}`, shortcut: shortcuts.showEditor.keystrokes, icon: GetIcon(fileDocument), count: count.notes diff --git a/apps/webapp/src/Hooks/useLayout.ts b/apps/webapp/src/Hooks/useLayout.ts index 7d18b9010..0ef60b957 100644 --- a/apps/webapp/src/Hooks/useLayout.ts +++ b/apps/webapp/src/Hooks/useLayout.ts @@ -5,11 +5,14 @@ const useLayout = () => { const setFocusMode = useLayoutStore((store) => store.setFocusMode) const showInfobar = useLayoutStore((store) => store.showInfobar) const hideInfobar = useLayoutStore((store) => store.hideInfobar) + const showShareOptions = useLayoutStore((store) => store.showShareOptions) + const toggleShareOptions = useLayoutStore((store) => store.toggleShareOptions) const toggleFocusMode = () => { if (useLayoutStore.getState().focusMode) { toggleFocusModeBool() showInfobar() + if (showShareOptions) toggleShareOptions() } else { toggleFocusModeBool() hideInfobar() diff --git a/apps/webapp/src/Hooks/useLoad.ts b/apps/webapp/src/Hooks/useLoad.ts index 2a873e4ed..6dd1bc565 100644 --- a/apps/webapp/src/Hooks/useLoad.ts +++ b/apps/webapp/src/Hooks/useLoad.ts @@ -21,6 +21,7 @@ import { useContentStore } from '../Stores/useContentStore' import { useDataStore } from '../Stores/useDataStore' import { useEditorStore, getContent } from '../Stores/useEditorStore' import { getPathFromNodeIdHookless } from './useLinks' +import { useUpdater } from './useUpdater' export interface LoadNodeOptions { savePrev?: boolean @@ -49,6 +50,7 @@ const useLoad = () => { const setLoadingNodeid = useEditorStore((store) => store.setLoadingNodeid) const { saveAndClearBuffer } = useEditorBuffer() const { execRefactor } = useRefactor() + const { updateFromContent } = useUpdater() const saveNodeName = (nodeId: string, title?: string) => { const draftNodeTitle = title ?? useAnalysisStore.getState().analysis.title @@ -158,7 +160,9 @@ const useLoad = () => { } else { mog('CurrentNode is not same for loadNode', { node, loadingNodeid }) } + setContent(node.nodeid, content, metadata) + updateFromContent(node.nodeid, content) } } if (withLoading) setFetchingContent(false) diff --git a/apps/webapp/src/Hooks/useNewNodes.ts b/apps/webapp/src/Hooks/useNewNodes.ts index 4f758e42f..f77680dab 100644 --- a/apps/webapp/src/Hooks/useNewNodes.ts +++ b/apps/webapp/src/Hooks/useNewNodes.ts @@ -1,25 +1,17 @@ import { toast } from 'react-hot-toast' -import { generateNodeUID, getTodosFromContent, mog } from '@mexit/core' +import { generateNodeUID, mog } from '@mexit/core' import { useInternalLinks } from './useInternalLinks' import { useApi } from './useApi' import { useDataStore } from '../Stores/useDataStore' -import { useTodoStore } from '../Stores/useTodoStore' -import { useLinks } from './useLinks' -import { useTags } from './useTags' -import { useSearch } from './useSearch' +import { useUpdater } from './useUpdater' export const useNewNodes = () => { const checkValidILink = useDataStore((s) => s.checkValidILink) const { getParentILink } = useInternalLinks() const { saveSingleNewNode, bulkCreateNodes } = useApi() - - const { updateLinksFromContent } = useLinks() - const updateNodeTodos = useTodoStore((store) => store.replaceContentOfTodos) - - const { updateTagsFromContent } = useTags() - const { updateDocument } = useSearch() + const { updateFromContent } = useUpdater() const addNodeOrNodes = async (ilink, showAlert, parentId?, content?: any[], save?: boolean) => { try { @@ -35,13 +27,7 @@ export const useNewNodes = () => { ? await saveSingleNewNode(nodeUID, ilink, parentILink.nodeid, content) : await bulkCreateNodes(nodeUID, ilink, content) - if (content) { - updateLinksFromContent(nodeUID, content) - updateTagsFromContent(nodeUID, content) - updateNodeTodos(nodeUID, getTodosFromContent(content)) - - await updateDocument('node', nodeUID, content) - } + updateFromContent(nodeUID, content) return node } catch (error) { diff --git a/apps/webapp/src/Hooks/useUpdater.ts b/apps/webapp/src/Hooks/useUpdater.ts new file mode 100644 index 000000000..b65b74e5a --- /dev/null +++ b/apps/webapp/src/Hooks/useUpdater.ts @@ -0,0 +1,27 @@ +import { getTodosFromContent, NodeEditorContent } from '@mexit/core' +import { useTodoStore } from '../Stores/useTodoStore' +import { useLinks } from './useLinks' +import { useSearch } from './useSearch' +import { useTags } from './useTags' + +export const useUpdater = () => { + const { updateLinksFromContent } = useLinks() + const updateNodeTodos = useTodoStore((store) => store.replaceContentOfTodos) + + const { updateTagsFromContent } = useTags() + const { updateDocument } = useSearch() + + const updateFromContent = async (noteId: string, content: NodeEditorContent) => { + if (content) { + updateLinksFromContent(noteId, content) + updateTagsFromContent(noteId, content) + updateNodeTodos(noteId, getTodosFromContent(content)) + + await updateDocument('node', noteId, content) + } + } + + return { + updateFromContent + } +} diff --git a/apps/webapp/src/Stores/useLayoutStore.ts b/apps/webapp/src/Stores/useLayoutStore.ts index e1388c5d3..cb4cfd333 100644 --- a/apps/webapp/src/Stores/useLayoutStore.ts +++ b/apps/webapp/src/Stores/useLayoutStore.ts @@ -19,6 +19,8 @@ interface LayoutState { setInfobarMode: (mode: InfobarMode) => void showInfobar: () => void hideInfobar: () => void + showShareOptions?: boolean + toggleShareOptions: () => void showLoader?: boolean setShowLoader?: (showLoader: boolean) => void } @@ -37,6 +39,9 @@ export const useLayoutStore = create((set, get) => ({ }, toggleSidebar: () => set((state) => ({ sidebar: { ...state.sidebar, expanded: !state.sidebar.expanded } })), + // Note Share + toggleShareOptions: () => set({ showShareOptions: !get().showShareOptions }), + // Infobar infobar: { visible: true, diff --git a/apps/webapp/src/Views/EditorView.tsx b/apps/webapp/src/Views/EditorView.tsx index a3b92920f..6ebdb5fb9 100644 --- a/apps/webapp/src/Views/EditorView.tsx +++ b/apps/webapp/src/Views/EditorView.tsx @@ -19,6 +19,7 @@ import { useRouting, ROUTE_PATHS, NavigationType } from '../Hooks/useRouting' import { useKeyListener } from '../Hooks/useShortcutListener' import useBlockStore from '../Stores/useBlockStore' import { useLayoutStore } from '../Stores/useLayoutStore' +import { getNodeidFromPathAndLinks } from '../Hooks/useLinks' export const EditorViewWrapper = styled.div` display: flex; @@ -69,8 +70,10 @@ const EditorView = () => { event.preventDefault() shortcutHandler(shortcuts.showEditor, () => { if (node.nodeid === '__null__') { - loadNode(ilinks.find((ilink) => ilink.path === '@').nodeid) + const baseNodeId = getNodeidFromPathAndLinks(ilinks, node.path) + loadNode(baseNodeId) } + loadNode(node.nodeid) goTo(ROUTE_PATHS.node, NavigationType.push, node.nodeid) }) diff --git a/libs/shared/src/Style/Editor.tsx b/libs/shared/src/Style/Editor.tsx index a7e6295ab..6e076dfb9 100644 --- a/libs/shared/src/Style/Editor.tsx +++ b/libs/shared/src/Style/Editor.tsx @@ -68,7 +68,7 @@ export const StyledEditor = styled.div` display: flex; flex-direction: column; align-items: flex-start; - gap: ${({ theme }) => theme.spacing.large}; + gap: ${({ theme }) => theme.spacing.medium}; padding: 0 ${({ theme }) => theme.spacing.medium}; margin: calc(${({ theme }) => theme.spacing.large}) auto 0; width: 100%;