Files
omnivore/packages/web/lib/networking/queries/useGetArticleQuery.tsx
Hongbo Wu 2b70d480d2 Remove article saving request (#493)
* Add state and taskName in elastic page mappings

* Add state and taskName in elastic page interface

* Create page with PROCESSING state before scrapping

* Update createArticleRequest API

* Fix tests

* Add default state for pages

* Update createArticle API

* Update save page

* Update save file

* Update saving item description

* Show unable to parse content for failed page

* Fix date parsing

* Search for not failed pages

* Fix tests

* Add test for saveUrl

* Update get article saving request api

* Update get article test

* Add test for articleSavingRequest API

* Add test for failure

* Return new page id if clientRequestId empty

* Update clientRequestId in savePage

* Update clientRequestId in saveFile

* Replace article with slug in articleSavingRequest

* Add slug in articleSavingRequest response

* Depreciate article

* Use slug in web

* Remove article and highlight fragments

* Query article.slug on Prod

* Show unable to parse description for failed page

* Fix a bug having duplicate pages when saving the same url multiple times

* Add state in response

* Rename variables in removeArticle API

* Rename state

* Add state in response in web

* Make state an enum

* Open temporary page by link id

* Use an empty reader view as the background for loading pages

* Progressively load the article page as content is loaded

* Add includePending flag in getArticles API

* Set includePending = true in web

* Add elastic update mappings in migration script

* Add elastic mappings in docker image

* Move index_settings.json to migrate package

* Remove elastic index creation in api

* Move elastic migrations to a separate directory

* Remove index_settings from api docker image

Co-authored-by: Jackson Harper <jacksonh@gmail.com>
2022-04-29 13:41:06 +08:00

174 lines
4.2 KiB
TypeScript

import { gql } from 'graphql-request'
import useSWRImmutable, { Cache } from 'swr'
import { makeGqlFetcher, RequestContext, ssrFetcher } from '../networkHelpers'
import {
articleFragment,
ContentReader,
State,
} from '../fragments/articleFragment'
import { Highlight, highlightFragment } from '../fragments/highlightFragment'
import { ScopedMutator } from 'swr/dist/types'
import { Label, labelFragment } from '../fragments/labelFragment'
import { LibraryItems } from './useGetLibraryItemsQuery'
type ArticleQueryInput = {
username?: string
slug?: string
includeFriendsHighlights?: boolean
}
type ArticleQueryOutput = {
articleData?: ArticleData
articleFetchError: unknown
isLoading: boolean
}
type ArticleData = {
article: NestedArticleData
}
type NestedArticleData = {
article: ArticleAttributes
errorCodes?: string[]
}
export type ArticleAttributes = {
id: string
title: string
url: string
originalArticleUrl: string
author?: string
image?: string
savedAt: string
createdAt: string
publishedAt?: string
description?: string
contentReader: ContentReader
readingProgressPercent: number
readingProgressAnchorIndex: number
slug: string
savedByViewer?: boolean
content: string
highlights: Highlight[]
linkId: string
labels?: Label[]
state?: State
}
const query = gql`
query GetArticle(
$username: String!
$slug: String!
$includeFriendsHighlights: Boolean
) {
article(username: $username, slug: $slug) {
... on ArticleSuccess {
article {
...ArticleFields
content
highlights(input: { includeFriends: $includeFriendsHighlights }) {
...HighlightFields
}
labels {
...LabelFields
}
}
}
... on ArticleError {
errorCodes
}
}
}
${articleFragment}
${highlightFragment}
${labelFragment}
`
export function useGetArticleQuery({
username,
slug,
includeFriendsHighlights,
}: ArticleQueryInput): ArticleQueryOutput {
const variables = {
username,
slug,
includeFriendsHighlights,
}
const { data, error, mutate } = useSWRImmutable(
slug ? [query, username, slug, includeFriendsHighlights] : null,
makeGqlFetcher(variables)
)
let resultData: ArticleData | undefined = data as ArticleData
let resultError = error
// We need to check the response errors here and return the error
// it will be nested in the data pages, if there is one error,
// we invalidate the data and return the error. We also zero out
// the response in the case of an error.
if (!error && resultData && resultData.article.errorCodes) {
resultError = resultData.article.errorCodes
resultData = undefined
}
return {
articleData: resultData,
articleFetchError: resultError as unknown,
isLoading: !error && !data,
}
}
export async function articleQuery(
context: RequestContext,
input: ArticleQueryInput
): Promise<ArticleAttributes> {
const result = (await ssrFetcher(context, query, input)) as ArticleData
if (result.article) {
return result.article.article
}
return Promise.reject()
}
export const cacheArticle = (
mutate: ScopedMutator,
username: string,
article: ArticleAttributes,
includeFriendsHighlights = false
) => {
mutate([query, username, article.slug, includeFriendsHighlights], {
article: { article: { ...article, cached: true } },
})
}
export const removeItemFromCache = (
cache: Cache<unknown>,
mutate: ScopedMutator,
itemId: string
) => {
try {
const mappedCache = cache as Map<string, unknown>
mappedCache.forEach((value: any, key) => {
if (typeof value == 'object' && 'articles' in value) {
const articles = value.articles as LibraryItems
const idx = articles.edges.findIndex((edge) => edge.node.id == itemId)
if (idx > -1) {
value.articles.edges.splice(idx, 1)
mutate(key, value, false)
}
}
})
mappedCache.forEach((value: any, key) => {
if (Array.isArray(value)) {
const idx = value.findIndex((item) => 'articles' in item)
if (idx > -1) {
mutate(key, value, false)
}
}
})
} catch (error) {
console.log('error removing item from cache', error)
}
}