Skip to content

Commit e194b4d

Browse files
authored
Sync view updates from extension, CMD + S to save View (#403)
#403 * CMD + S to save view, Sync view updates from extension * Changeset added * Table overlay fixes
1 parent 1d8ec7c commit e194b4d

File tree

16 files changed

+170
-57
lines changed

16 files changed

+170
-57
lines changed

.changeset/old-balloons-play.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'mexit': patch
3+
'mexit-webapp': patch
4+
---
5+
6+
Sync Views From Extension, CMD + S To Save Views

apps/extension/src/Hooks/useSaveChanges.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ import useDataStore from '../Stores/useDataStore'
1717
import { useHighlightStore } from '../Stores/useHighlightStore'
1818
import { useRecentsStore } from '../Stores/useRecentsStore'
1919
import { useSputlitStore } from '../Stores/useSputlitStore'
20-
import { wUpdateDoc } from '../Sync/invokeOnWorker'
2120

2221
import { useAuthStore } from './useAuth'
2322
import { useEditorStore } from './useEditorStore'
2423
import { useHighlights } from './useHighlights'
2524
import { useInternalLinks } from './useInternalLinks'
2625
import { useNamespaces } from './useNamespaces'
2726
import { useNodes } from './useNodes'
27+
import { useSearch } from './useSearch'
2828
import { useSputlitContext, VisualState } from './useSputlitContext'
2929

3030
export interface AppendAndSaveProps {
@@ -40,6 +40,7 @@ export function useSaveChanges() {
4040
const { setPreviewMode, setNodeContent } = useEditorStore()
4141
const { getParentILink, getEntirePathILinks, updateMultipleILinks, updateSingleILink, createNoteHierarchyString } =
4242
useInternalLinks()
43+
const { updateDocument, updateBlocks } = useSearch()
4344
const { setVisualState } = useSputlitContext()
4445
const setNode = useSputlitStore((s) => s.setNode)
4546
const setSelection = useSputlitStore((s) => s.setSelection)
@@ -127,7 +128,7 @@ export function useSaveChanges() {
127128
setContent(nodeid, content)
128129

129130
const title = !bulkCreateRequest ? message.title : message.node.title
130-
wUpdateDoc({ id: nodeid, contents: content, title })
131+
updateDocument({ id: nodeid, contents: content, title })
131132

132133
mog('DispatchAfterSave', { response, nodeid, content, metadata, highlight, blockHighlightMap })
133134
dispatchAfterSave({ nodeid, content, metadata, highlight, blockHighlightMap }, saveAndExit, notification)
@@ -271,10 +272,9 @@ export function useSaveChanges() {
271272
const bulkCreateRequest = request.subType === 'BULK_CREATE_NODES'
272273
const nodeid = !bulkCreateRequest ? message.id : message.node.id
273274
const content = message.content ?? request.body.content
274-
275275
appendContent(node.nodeid, content)
276276
const title = !bulkCreateRequest ? message.title : message.node.title
277-
wUpdateDoc({
277+
updateBlocks({
278278
id: node.nodeid,
279279
contents: content,
280280
title

apps/extension/src/Hooks/useSearch.ts

+28-5
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@ import {
1818
ListItemType,
1919
QuickLinkType,
2020
SearchRepExtra,
21-
sortByCreated
21+
sortByCreated,
22+
useContentStore
2223
} from '@mexit/core'
2324
import { useQuery } from '@mexit/shared'
2425

2526
import useDataStore from '../Stores/useDataStore'
2627
import { useLinkStore } from '../Stores/useLinkStore'
2728
import { useMentionStore } from '../Stores/useMentionStore'
2829
import { useSputlitStore } from '../Stores/useSputlitStore'
29-
import { wAddDoc, wRemoveDoc, wSearchIndexWithRanking, wUpdateDoc } from '../Sync/invokeOnWorker'
30+
import { wAddDoc, wRemoveDoc, wSearchIndexWithRanking, wUpdateDoc, wUpdateOrAppendBlocks } from '../Sync/invokeOnWorker'
3031
import { getListItemFromNode, getListItemFromSnippet } from '../Utils/helper'
3132

3233
import { useAuthStore } from './useAuth'
@@ -71,10 +72,11 @@ export const useSearch = () => {
7172
const { getQuickLinks } = useQuickLinks()
7273
const { getSnippet } = useSnippets()
7374
const { generateSearchQuery } = useQuery()
75+
const setDocUpdated = useContentStore((store) => store.setDocUpdated)
7476

7577
const { getSearchExtra } = useSearchExtra()
7678

77-
const { getPathFromNodeid } = useLinks()
79+
const { getTitleFromNoteId } = useLinks()
7880

7981
const searchInList = async (actionType?: ActionType) => {
8082
const ilinks = useDataStore.getState().ilinks
@@ -156,34 +158,55 @@ export const useSearch = () => {
156158
const extra = getSearchExtra()
157159
await wAddDoc({
158160
...doc,
159-
title: doc.title ?? getPathFromNodeid(doc.id),
161+
title: doc.title ?? getTitleFromNoteId(doc.id, { includeArchived: true, includeShared: true }),
160162
options: {
161163
...(doc.options ?? {}),
162164
extra
163165
}
164166
})
167+
168+
setDocUpdated()
169+
}
170+
171+
const updateBlocks = async (doc: IUpdateDoc) => {
172+
const extra = getSearchExtra()
173+
174+
await wUpdateOrAppendBlocks({
175+
...doc,
176+
title: doc.title ?? getTitleFromNoteId(doc.id, { includeArchived: true, includeShared: true }),
177+
options: {
178+
...(doc.options ?? {}),
179+
extra
180+
}
181+
})
182+
183+
setDocUpdated()
165184
}
166185

167186
const updateDocument = async (doc: IUpdateDoc) => {
168187
const extra = getSearchExtra()
169188

170189
await wUpdateDoc({
171190
...doc,
172-
title: doc.title ?? getPathFromNodeid(doc.id),
191+
title: doc.title ?? getTitleFromNoteId(doc.id, { includeArchived: true, includeShared: true }),
173192
options: {
174193
...(doc.options ?? {}),
175194
extra
176195
}
177196
})
197+
198+
setDocUpdated()
178199
}
179200

180201
const removeDocument = async (key: Indexes, id: string) => {
181202
await wRemoveDoc(key, id)
203+
setDocUpdated()
182204
}
183205

184206
return {
185207
addDocument,
186208
searchInList,
209+
updateBlocks,
187210
updateDocument,
188211
removeDocument
189212
}

apps/extension/src/Hooks/useSnippets.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
extractMetadata,
99
getSnippetCommand,
1010
Snippet,
11-
SnippetID
11+
SnippetID,
12+
useContentStore
1213
} from '@mexit/core'
1314
import { useSlashCommands } from '@mexit/shared'
1415

@@ -28,6 +29,7 @@ export const useSnippets = () => {
2829
const updateDescription = useDescriptionStore((store) => store.updateDescription)
2930
const getWorkspaceId = useAuthStore((store) => store.getWorkspaceId)
3031
const { setVisualState } = useSputlitContext()
32+
3133
const setPreviewMode = useEditorStore((s) => s.setPreviewMode)
3234
const addMetadata = useMetadataStore((s) => s.addMetadata)
3335
const setSlashCommands = useDataStore((store) => store.setSlashCommands)
@@ -73,6 +75,8 @@ export const useSnippets = () => {
7375
id: message.id,
7476
contents: request.data.content,
7577
title: message.title
78+
}).then(() => {
79+
useContentStore.getState().setDocUpdated()
7680
})
7781

7882
if (notify) {

apps/extension/src/Sync/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const messagePassing = () => {
5858
useContentStore,
5959
{
6060
name: BroadcastSyncedChannel.CONTENTS,
61-
sync: [{ field: 'contents' }]
61+
sync: [{ field: 'contents' }, { field: 'docUpdated' }]
6262
},
6363
onStateChange
6464
)

apps/extension/src/Sync/invokeOnWorker.ts

+4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ export const wUpdateDoc = async (doc: IUpdateDoc) => {
6262
if (childIframe) return childIframe.updateDoc(doc)
6363
}
6464

65+
export const wUpdateOrAppendBlocks = async (doc: IUpdateDoc) => {
66+
if (childIframe) return childIframe.updateOrAppendBlocks(doc)
67+
}
68+
6569
export const wRemoveDoc = async (key: Indexes, id: string) => {
6670
if (childIframe) return childIframe.removeDoc(key, id)
6771
}

apps/webapp/src/Components/TaskHeader.tsx

+68-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useMemo, useState } from 'react'
1+
import { useCallback, useEffect, useMemo, useState } from 'react'
2+
import { toast } from 'react-hot-toast'
23

34
import trashIcon from '@iconify/icons-codicon/trash'
45
import arrowLeftRightLine from '@iconify/icons-ri/arrow-left-right-line'
@@ -17,8 +18,10 @@ import {
1718
LoadingButton,
1819
ToolbarTooltip
1920
} from '@workduck-io/mex-components'
21+
import { tinykeys } from '@workduck-io/tinykeys'
2022

2123
import {
24+
PrimaryText,
2225
ShortcutToken,
2326
ShortcutTokens,
2427
TaskHeader as StyledTaskHeader,
@@ -40,6 +43,68 @@ interface ViewHeaderProps {
4043
cardSelected?: boolean // * To show actions related to selected Item
4144
}
4245

46+
const ViewChangeStatus = ({ viewId }) => {
47+
const views = useViewStore((store) => store.views)
48+
49+
const { viewType, sortOrder, globalJoin, sortType, entities, currentFilters, groupBy } = useViewFilters()
50+
const { getView, updateView } = useViews()
51+
52+
const isCurrentViewChanged = useMemo(() => {
53+
const currentView = getView(viewId)
54+
return !(
55+
JSON.stringify(currentFilters) === JSON.stringify(currentView?.filters) &&
56+
viewType === currentView?.viewType &&
57+
groupBy === currentView?.groupBy &&
58+
sortType === currentView?.sortType &&
59+
sortOrder === currentView?.sortOrder &&
60+
entities === currentView?.entities
61+
)
62+
}, [currentFilters, viewType, entities, groupBy, sortType, sortOrder, views, viewId])
63+
64+
const onSaveView = useCallback(
65+
async (viewId: string) => {
66+
const oldview = getView(viewId)
67+
68+
const newView = {
69+
...oldview,
70+
filters: currentFilters,
71+
viewType,
72+
globalJoin,
73+
groupBy,
74+
entities,
75+
sortOrder,
76+
sortType
77+
}
78+
79+
try {
80+
await updateView(newView)
81+
toast('View Saved')
82+
} catch (err) {
83+
console.error('Unable to save view', err)
84+
toast('Unable to save view')
85+
}
86+
},
87+
[currentFilters, viewType, groupBy, sortType, sortOrder, entities]
88+
)
89+
90+
useEffect(() => {
91+
const unsubscribe = tinykeys(window, {
92+
'$mod+KeyS': (e) => {
93+
e.stopPropagation()
94+
e.preventDefault()
95+
96+
if (isCurrentViewChanged) {
97+
onSaveView(viewId)
98+
}
99+
}
100+
})
101+
102+
return () => unsubscribe()
103+
}, [viewId, onSaveView, isCurrentViewChanged])
104+
105+
return <PrimaryText>{isCurrentViewChanged && '*'}</PrimaryText>
106+
}
107+
43108
const ViewHeader = ({ cardSelected = false }: ViewHeaderProps) => {
44109
const [deleting, setDeleting] = useState(false)
45110

@@ -50,20 +115,10 @@ const ViewHeader = ({ cardSelected = false }: ViewHeaderProps) => {
50115

51116
const { goTo } = useRouting()
52117
const { deleteView } = useViews()
118+
53119
const [source, target] = useSingleton()
54120
const { viewType, sortOrder, globalJoin, sortType, entities, currentFilters, groupBy } = useViewFilters()
55121

56-
const isCurrentViewChanged = useMemo(() => {
57-
return !(
58-
JSON.stringify(currentFilters) === JSON.stringify(view?.filters) &&
59-
viewType === view?.viewType &&
60-
groupBy === view?.groupBy &&
61-
sortType === view?.sortType &&
62-
sortOrder === view?.sortOrder &&
63-
entities === view?.entities
64-
)
65-
}, [currentFilters, viewType, groupBy, sortType, sortOrder])
66-
67122
const handleUpdateView = () => {
68123
openTaskViewModal({
69124
filters: currentFilters,
@@ -96,7 +151,6 @@ const ViewHeader = ({ cardSelected = false }: ViewHeaderProps) => {
96151

97152
const handleCloneView = () => {
98153
const { id, filters, ...properties } = view
99-
console.log('cloning')
100154
openTaskViewModal({
101155
cloneViewId: view?.id,
102156
filters,
@@ -128,7 +182,7 @@ const ViewHeader = ({ cardSelected = false }: ViewHeaderProps) => {
128182
<TaskViewTitle>
129183
<Icon icon={stackLine} />
130184
<span>{view?.title}</span>
131-
{isCurrentViewChanged && !isDefault && '*'}
185+
{view?.id && !isDefault && <ViewChangeStatus viewId={view?.id} />}
132186
</TaskViewTitle>
133187
<TaskViewControls>
134188
{!isDefault && (

apps/webapp/src/IFrame/extensionConnector.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
searchIndexWithRanking,
2020
startRequestsWorkerService,
2121
startSearchWorker,
22-
updateDoc
22+
updateDoc,
23+
updateOrAppendBlocks
2324
} from '../Workers/controller'
2425

2526
import { broadCastMessage } from './channels'
@@ -55,6 +56,7 @@ export const webExtensionConnector = async () => {
5556
startRequestsWorkerService,
5657
addDoc,
5758
updateDoc,
59+
updateOrAppendBlocks,
5860
removeDoc,
5961
initHighlightsExtension,
6062
initLinksExtension,

apps/webapp/src/Views/SearchFilters.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,12 @@ const SearchFilters = ({
9191
</FilterValuesWrapper>
9292
<NewFilterMenu filters={filters} addFilter={(f) => addCurrentFilter(f)} removeLastFilter={removeLastFilter} />
9393
</SearchFiltersWrapper>
94-
{onGroupByChange && <GroupByMenu onChange={onGroupByChange} />}
95-
{sortMenuProps && <SortMenu {...sortMenuProps} />}
96-
{onEntityFilterChange && <EntityFilterMenu onChange={onEntityFilterChange} />}
97-
{viewSelectorProps && <ViewSelector {...viewSelectorProps} />}
94+
<SearchFilterLabel flexStart>
95+
{onGroupByChange && <GroupByMenu onChange={onGroupByChange} />}
96+
{sortMenuProps && <SortMenu {...sortMenuProps} />}
97+
{onEntityFilterChange && <EntityFilterMenu onChange={onEntityFilterChange} />}
98+
{viewSelectorProps && <ViewSelector {...viewSelectorProps} />}
99+
</SearchFilterLabel>
98100
</SearchFilterWrapper>
99101
)
100102
}

0 commit comments

Comments
 (0)