Merge pull request #264 from omnivore-app/fix/elastic-update-conflict

Fix/elastic update conflict
This commit is contained in:
Jackson Harper 2022-03-18 16:33:45 -07:00 committed by GitHub
commit efc9a30d1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 37 deletions

View file

@ -201,6 +201,7 @@ export const updatePage = async (
},
},
refresh: ctx.refresh,
retry_on_conflict: 3,
})
if (body.result !== 'updated') return false
@ -237,6 +238,7 @@ export const addLabelInPage = async (
},
},
refresh: ctx.refresh,
retry_on_conflict: 3,
})
return body.result === 'updated'

View file

@ -707,9 +707,9 @@ export const saveArticleReadingProgressResolver = authorized<
{ input: { id, readingProgressPercent, readingProgressAnchorIndex } },
{ claims: { uid }, pubsub }
) => {
const userArticleRecord = await getPageByParam({ userId: uid, _id: id })
const page = await getPageByParam({ userId: uid, _id: id })
if (!userArticleRecord) {
if (!page) {
return { errorCodes: [SaveArticleReadingProgressErrorCode.NotFound] }
}
@ -725,26 +725,25 @@ export const saveArticleReadingProgressResolver = authorized<
// be greater than the current reading progress.
const shouldUpdate =
readingProgressPercent === 0 ||
(userArticleRecord.readingProgressPercent || 0) <
readingProgressPercent ||
(userArticleRecord.readingProgressAnchorIndex || 0) <
readingProgressAnchorIndex
page.readingProgressPercent < readingProgressPercent ||
page.readingProgressAnchorIndex < readingProgressAnchorIndex
const updatedArticle = Object.assign(userArticleRecord, {
const updatedPart = {
readingProgressPercent: shouldUpdate
? readingProgressPercent
: userArticleRecord.readingProgressPercent,
: page.readingProgressPercent,
readingProgressAnchorIndex: shouldUpdate
? readingProgressAnchorIndex
: userArticleRecord.readingProgressAnchorIndex,
})
: page.readingProgressAnchorIndex,
}
shouldUpdate && (await updatePage(id, updatedArticle, { pubsub, uid }))
shouldUpdate && (await updatePage(id, updatedPart, { pubsub, uid }))
return {
updatedArticle: {
...updatedArticle,
isArchived: !!updatedArticle.archivedAt,
...page,
...updatedPart,
isArchived: !!page.archivedAt,
},
}
}

View file

@ -1,21 +1,22 @@
import { Box } from './../../../components/elements/LayoutPrimitives'
import { Box } from '../../elements/LayoutPrimitives'
import { useReadingProgressAnchor } from '../../../lib/hooks/useReadingProgressAnchor'
import {
useScrollWatcher,
ScrollOffsetChangeset,
useScrollWatcher,
} from '../../../lib/hooks/useScrollWatcher'
import {
useRef,
useState,
useEffect,
MutableRefObject,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import { articleReadingProgressMutation } from '../../../lib/networking/mutations/articleReadingProgressMutation'
import { Tweet } from 'react-twitter-widgets'
import { render } from 'react-dom'
import { isDarkTheme } from '../../../lib/themeUpdater'
import useDebounce from '../../../lib/hooks/useDebounce'
import { debounce } from 'lodash'
export type ArticleProps = {
articleId: string
@ -28,7 +29,9 @@ export type ArticleProps = {
export function Article(props: ArticleProps): JSX.Element {
const highlightTheme = isDarkTheme() ? 'dark' : 'default'
const [readingProgress, setReadingProgress] = useState(props.initialReadingProgress)
const [readingProgress, setReadingProgress] = useState(
props.initialReadingProgress
)
const [readingAnchorIndex, setReadingAnchorIndex] = useState(
props.initialAnchorIndex
@ -41,14 +44,30 @@ export function Article(props: ArticleProps): JSX.Element {
useReadingProgressAnchor(articleContentRef, setReadingAnchorIndex)
const debouncedReadingProgress = useDebounce(readingProgress, 1000);
const debouncedSetReadingProgress = useMemo(
() =>
debounce((readingProgress: number) => {
console.log('setReadingProgress', readingProgress)
setReadingProgress(readingProgress)
}, 2000),
[]
)
// Stop the invocation of the debounced function
// after unmounting
useEffect(() => {
return () => {
debouncedSetReadingProgress.cancel()
}
}, [])
useEffect(() => {
;(async () => {
if (!debouncedReadingProgress) return
if (!readingProgress) return
await articleReadingProgressMutation({
id: props.articleId,
readingProgressPercent: debouncedReadingProgress,
// round reading progress to 100% if more than that
readingProgressPercent: readingProgress > 100 ? 100 : readingProgress,
readingProgressAnchorIndex: readingAnchorIndex,
})
})()
@ -56,20 +75,16 @@ export function Article(props: ArticleProps): JSX.Element {
// We don't react to changes to readingAnchorIndex we
// only care about the progress (scroll position) changed.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
props.articleId,
debouncedReadingProgress,
readingAnchorIndex,
])
}, [props.articleId, readingProgress])
// Post message to webkit so apple app embeds get progress updates
useEffect(() => {
if (typeof window?.webkit != 'undefined') {
window.webkit.messageHandlers.readingProgressUpdate?.postMessage({
progress: debouncedReadingProgress,
progress: readingProgress,
})
}
}, [readingProgress, debouncedReadingProgress])
}, [readingProgress])
const setScrollWatchedElement = useScrollWatcher(
(changeset: ScrollOffsetChangeset) => {
@ -79,13 +94,13 @@ export function Article(props: ArticleProps): JSX.Element {
(changeset.current.y + scrollContainer.clientHeight) /
scrollContainer.scrollHeight
setReadingProgress(newReadingProgress * 100)
debouncedSetReadingProgress(newReadingProgress * 100)
} else if (window && window.document.scrollingElement) {
const newReadingProgress =
window.scrollY / window.document.scrollingElement.scrollHeight
const adjustedReadingProgress =
newReadingProgress > 0.92 ? 1 : newReadingProgress
setReadingProgress(adjustedReadingProgress * 100)
debouncedSetReadingProgress(adjustedReadingProgress * 100)
}
},
1000
@ -152,9 +167,15 @@ export function Article(props: ArticleProps): JSX.Element {
}
if (props.scrollElementRef.current) {
props.scrollElementRef.current?.scroll(0, calculateOffset(anchorElement))
props.scrollElementRef.current?.scroll(
0,
calculateOffset(anchorElement)
)
} else {
window.document.documentElement.scroll(0, calculateOffset(anchorElement))
window.document.documentElement.scroll(
0,
calculateOffset(anchorElement)
)
}
}
}, [

View file

@ -206,9 +206,12 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
if (activeCardId && !alreadyScrolled.current) {
scrollToActiveCard(activeCardId)
alreadyScrolled.current = true
}
if (activeItem) {
performActionOnItem('refresh', activeItem)
if (activeItem) {
console.log('refreshing')
// refresh items on home feed
performActionOnItem('refresh', activeItem)
}
}
}, [activeCardId, scrollToActiveCard])

View file

@ -50,6 +50,7 @@
"@types/cookie": "^0.4.1",
"@types/diff-match-patch": "^1.0.32",
"@types/jest": "^27.0.2",
"@types/lodash.debounce": "^4.0.6",
"@types/react": "17.0.2",
"@types/react-dom": "^17.0.2",
"@types/segment-analytics": "^0.0.34",

View file

@ -5443,6 +5443,18 @@
"@types/interpret" "*"
"@types/node" "*"
"@types/lodash.debounce@^4.0.6":
version "4.0.6"
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz#c5a2326cd3efc46566c47e4c0aa248dc0ee57d60"
integrity sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==
dependencies:
"@types/lodash" "*"
"@types/lodash@*":
version "4.14.180"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670"
integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==
"@types/long@^4.0.0", "@types/long@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"