Merge pull request #451 from omnivore-app/fix/labels-on-library

Allow editing labels from the library view
This commit is contained in:
Jackson Harper 2022-04-19 20:13:55 -07:00 committed by GitHub
commit c99466c21e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 7 deletions

View file

@ -12,6 +12,7 @@ export type CardMenuDropdownAction =
| 'delete'
| 'share'
| 'snooze'
| 'set-labels'
type CardMenuProps = {
item: LibraryItemNode
@ -34,6 +35,12 @@ export function CardMenu(props: CardMenuProps): JSX.Element {
title="Unarchive"
/>
)}
<DropdownOption
onSelect={() => {
props.actionHandler('set-labels')
}}
title="Set Labels"
/>
{isVipUser(props.viewer) && (
<DropdownOption
onSelect={() => {

View file

@ -12,6 +12,7 @@ export type LinkedItemCardAction =
| 'mark-unread'
| 'share'
| 'snooze'
| 'set-labels'
export type LinkedItemCardProps = {
item: LibraryItemNode

View file

@ -110,6 +110,8 @@ export function ArticleActionsMenu(props: ArticleActionsMenuProps): JSX.Element
>
<SetLabelsControl
article={props.article}
linkId={props.article.linkId}
labels={props.article.labels}
articleActionHandler={props.articleActionHandler}
/>
</ActionDropdown>

View file

@ -7,7 +7,6 @@ import { CrossIcon } from '../../elements/images/CrossIcon'
import { styled, theme } from '../../tokens/stitches.config'
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { useGetLabelsQuery } from '../../../lib/networking/queries/useGetLabelsQuery'
import { ArticleAttributes } from '../../../lib/networking/queries/useGetArticleQuery'
import { Check, Circle, PencilSimple, Plus } from 'phosphor-react'
import { isTouchScreenDevice } from '../../../lib/deviceType'
import { setLabelsMutation } from '../../../lib/networking/mutations/setLabelsMutation'
@ -15,9 +14,12 @@ import { createLabelMutation } from '../../../lib/networking/mutations/createLab
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import { randomLabelColorHex } from '../../../utils/settings-page/labels/labelColorObjects'
import { useRouter } from 'next/router'
import { ArticleAttributes } from '../../../lib/networking/queries/useGetArticleQuery'
type SetLabelsControlProps = {
article: ArticleAttributes
linkId: string
labels: Label[] | undefined
article?: ArticleAttributes
articleActionHandler: (action: string, arg?: unknown) => void
}
@ -187,7 +189,7 @@ export function SetLabelsControl(props: SetLabelsControlProps): JSX.Element {
const router = useRouter()
const [filterText, setFilterText] = useState('')
const { labels, revalidate } = useGetLabelsQuery()
const [selectedLabels, setSelectedLabels] = useState<Label[]>(props.article.labels || [])
const [selectedLabels, setSelectedLabels] = useState<Label[]>(props.labels || [])
useEffect(() => {
setFocusedIndex(undefined)
@ -211,11 +213,13 @@ export function SetLabelsControl(props: SetLabelsControlProps): JSX.Element {
setSelectedLabels(newSelectedLabels)
const result = await setLabelsMutation(
props.article.linkId,
props.linkId,
newSelectedLabels.map((label) => label.id)
)
props.article.labels = result
if (props.article) {
props.article.labels = result
}
props.articleActionHandler('refreshLabels', result)
revalidate()

View file

@ -1,3 +1,4 @@
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { ArticleAttributes } from '../../../lib/networking/queries/useGetArticleQuery'
import { Button } from '../../elements/Button'
import { CrossIcon } from '../../elements/images/CrossIcon'
@ -12,7 +13,9 @@ import { theme } from '../../tokens/stitches.config'
import { SetLabelsControl } from './SetLabelsControl'
type SetLabelsModalProps = {
article: ArticleAttributes
linkId: string
labels: Label[] | undefined
article?: ArticleAttributes
onOpenChange: (open: boolean) => void
articleActionHandler: (action: string, arg?: unknown) => void
}
@ -41,6 +44,7 @@ export function SetLabelsModal(props: SetLabelsModalProps): JSX.Element {
onClick={() => {
props.onOpenChange(false)
}}
tabIndex={-1}
>
<CrossIcon
size={14}

View file

@ -35,6 +35,8 @@ import { useFetchMoreScroll } from '../../../lib/hooks/useFetchMoreScroll'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import { ConfirmationModal } from '../../patterns/ConfirmationModal'
import { SetLabelsModal } from '../article/SetLabelsModal'
import { Label } from '../../../lib/networking/fragments/labelFragment'
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
@ -61,6 +63,10 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
undefined
)
const [labelsTarget, setLabelsTarget] = useState<LibraryItem | undefined>(
undefined
)
const [showAddLinkModal, setShowAddLinkModal] = useState(false)
const [queryInputs, setQueryInputs] =
@ -230,8 +236,14 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
return
}
// If any of the modals are open we disable handling keyboard shortcuts
if (labelsTarget || snoozeTarget || shareTarget) {
return
}
switch (action) {
case 'showDetail':
const username = viewerData?.me?.profile.username
if (username) {
setActiveCardId(item.node.id)
@ -265,6 +277,9 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
case 'snooze':
setSnoozeTarget(item)
break
case 'set-labels':
setLabelsTarget(item)
break
}
}
@ -355,6 +370,9 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
case 'markItemAsUnread':
handleCardAction('mark-unread', activeItem)
break
case 'showEditLabelsModal':
handleCardAction('set-labels', activeItem)
break
case 'shareItem':
setShareTarget(activeItem)
break
@ -408,6 +426,8 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
setShareTarget={setShareTarget}
snoozeTarget={snoozeTarget}
setSnoozeTarget={setSnoozeTarget}
labelsTarget={labelsTarget}
setLabelsTarget={setLabelsTarget}
showAddLinkModal={showAddLinkModal}
setShowAddLinkModal={setShowAddLinkModal}
/>
@ -428,6 +448,8 @@ type HomeFeedContentProps = {
setShareTarget: (target: LibraryItem | undefined) => void
snoozeTarget: LibraryItem | undefined
setSnoozeTarget: (target: LibraryItem | undefined) => void
labelsTarget: LibraryItem | undefined
setLabelsTarget: (target: LibraryItem | undefined) => void
showAddLinkModal: boolean
setShowAddLinkModal: (show: boolean) => void
actionHandler: (
@ -457,6 +479,8 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
[layout, setLayout]
)
const [, updateState] = useState({})
const StyledToggleButton = styled('button', {
p: '0px',
backgroundColor: 'transparent',
@ -706,6 +730,25 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
onOpenChange={() => setShowRemoveLinkConfirmation(false)}
/>
)}
{props.labelsTarget?.node.id && (
<SetLabelsModal
linkId={props.labelsTarget.node.id}
labels={props.labelsTarget.node.labels}
articleActionHandler={(action, value) => {
switch(action) {
case 'refreshLabels':
if (props.labelsTarget) {
props.labelsTarget.node.labels = value as (Label[] | undefined)
updateState({})
}
break
}
}}
onOpenChange={() => {
props.setLabelsTarget(undefined)
}}
/>
)}
</>
)
}

View file

@ -86,6 +86,7 @@ type LibraryListKeyboardAction =
| 'sortAscending'
| 'shareItem'
| 'showAddLinkModal'
| 'showEditLabelsModal'
export function libraryListCommands(
actionHandler: (action: LibraryListKeyboardAction) => void
@ -127,6 +128,12 @@ export function libraryListCommands(
shortcutKeyDescription: 'e',
callback: () => actionHandler('archiveItem'),
},
{
shortcutKeys: ['l'],
actionDescription: 'Edit item labels',
shortcutKeyDescription: 'l',
callback: () => actionHandler('showEditLabelsModal'),
},
{
shortcutKeys: ['shift', 'i'],
actionDescription: 'Mark item as read',

View file

@ -2,7 +2,6 @@ import { gql } from 'graphql-request'
import useSWRInfinite from 'swr/infinite'
import { gqlFetcher } from '../networkHelpers'
import type { ArticleFragmentData } from '../fragments/articleFragment'
import { articleFragment } from '../fragments/articleFragment'
import { setLinkArchivedMutation } from '../mutations/setLinkArchivedMutation'
import { deleteLinkMutation } from '../mutations/deleteLinkMutation'
import { articleReadingProgressMutation } from '../mutations/articleReadingProgressMutation'

View file

@ -254,6 +254,8 @@ export default function Home(): JSX.Element {
{showSetLabelsModal && (
<SetLabelsModal
article={article}
linkId={article.id}
labels={article.labels}
articleActionHandler={actionHandler}
onOpenChange={() => setShowSetLabelsModal(false)}
/>