mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Add feedback link in spelling suggestion footer (#20867)
GitOrigin-RevId: 3bef428f810b88f56a76e3645cebcf22dd5ad9e3
This commit is contained in:
parent
e99ae3a459
commit
139fde750a
6 changed files with 98 additions and 49 deletions
|
@ -0,0 +1,56 @@
|
||||||
|
import { FC, memo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useSplitTest } from '@/shared/context/split-test-context'
|
||||||
|
import { chooseBadgeClass } from '@/shared/components/beta-badge'
|
||||||
|
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
|
const SpellingSuggestionsFeedback: FC = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { info } = useSplitTest('spell-check-client')
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tooltipText, url } = info.badgeInfo ?? {}
|
||||||
|
const badgeClass = chooseBadgeClass(info.phase)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OLTooltip
|
||||||
|
id="spell-check-client-tooltip"
|
||||||
|
description={
|
||||||
|
tooltipText || (
|
||||||
|
<>
|
||||||
|
We are testing an updated spellchecker.
|
||||||
|
<br />
|
||||||
|
Click to give feedback
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
tooltipProps={{ className: 'split-test-badge-tooltip' }}
|
||||||
|
overlayProps={{ placement: 'bottom', delay: 100 }}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={url || '/beta/participate'}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<span className={classnames('badge', badgeClass)} />}
|
||||||
|
bs5={
|
||||||
|
<MaterialIcon
|
||||||
|
type="info"
|
||||||
|
className={classnames('align-middle', badgeClass)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span className="mx-2">{t('give_feedback')}</span>
|
||||||
|
</a>
|
||||||
|
</OLTooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(SpellingSuggestionsFeedback)
|
|
@ -8,19 +8,14 @@ import {
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { SpellChecker, Word } from './spellchecker'
|
import { SpellChecker, Word } from './spellchecker'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import SplitTestBadge from '@/shared/components/split-test-badge'
|
|
||||||
import getMeta from '@/utils/meta'
|
import getMeta from '@/utils/meta'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { SpellCheckLanguage } from '../../../../../../types/project-settings'
|
|
||||||
import Icon from '@/shared/components/icon'
|
|
||||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||||
import { sendMB } from '@/infrastructure/event-tracking'
|
import { sendMB } from '@/infrastructure/event-tracking'
|
||||||
|
import SpellingSuggestionsFeedback from './spelling-suggestions-feedback'
|
||||||
|
|
||||||
const ITEMS_TO_SHOW = 8
|
const ITEMS_TO_SHOW = 8
|
||||||
|
|
||||||
// TODO: messaging below the spelling suggestions
|
|
||||||
const SHOW_FOOTER = false
|
|
||||||
|
|
||||||
// (index % length) that works for negative index
|
// (index % length) that works for negative index
|
||||||
const wrapArrayIndex = (index: number, length: number) =>
|
const wrapArrayIndex = (index: number, length: number) =>
|
||||||
((index % length) + length) % length
|
((index % length) + length) % length
|
||||||
|
@ -76,6 +71,8 @@ export const SpellingSuggestions: FC<{
|
||||||
}
|
}
|
||||||
}, [spellCheckLanguage])
|
}, [spellCheckLanguage])
|
||||||
|
|
||||||
|
const spellCheckClientEnabled = useFeatureFlag('spell-check-client')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul
|
<ul
|
||||||
className={classnames('dropdown-menu', 'dropdown-menu-unpositioned', {
|
className={classnames('dropdown-menu', 'dropdown-menu-unpositioned', {
|
||||||
|
@ -125,11 +122,11 @@ export const SpellingSuggestions: FC<{
|
||||||
handleLearnWord()
|
handleLearnWord()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{SHOW_FOOTER && language && (
|
{spellCheckClientEnabled && language?.dic && (
|
||||||
<>
|
<>
|
||||||
<li className="divider" />
|
<li className="divider" />
|
||||||
<li>
|
<li>
|
||||||
<Footer language={language} />
|
<SpellingSuggestionsFeedback />
|
||||||
</li>
|
</li>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -137,28 +134,6 @@ export const SpellingSuggestions: FC<{
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Footer: FC<{ language: SpellCheckLanguage }> = ({ language }) => {
|
|
||||||
const spellCheckClientEnabled = useFeatureFlag('spell-check-client')
|
|
||||||
|
|
||||||
if (!spellCheckClientEnabled) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return language.dic ? (
|
|
||||||
<div>
|
|
||||||
<SplitTestBadge
|
|
||||||
splitTestName="spell-check-client"
|
|
||||||
displayOnVariants={['enabled']}
|
|
||||||
/>{' '}
|
|
||||||
<small>{language?.name}</small>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<Icon type="warning" fw /> <small>{language?.name}</small>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListItem: FC<{
|
const ListItem: FC<{
|
||||||
content: string
|
content: string
|
||||||
selected: boolean
|
selected: boolean
|
||||||
|
|
|
@ -18,19 +18,7 @@ const BetaBadge: FC<{
|
||||||
url?: string
|
url?: string
|
||||||
phase?: string
|
phase?: string
|
||||||
}> = ({ tooltip, url = '/beta/participate', phase = 'beta' }) => {
|
}> = ({ tooltip, url = '/beta/participate', phase = 'beta' }) => {
|
||||||
let badgeClass: 'info-badge' | 'alpha-badge' | 'beta-badge'
|
const badgeClass = chooseBadgeClass(phase)
|
||||||
switch (phase) {
|
|
||||||
case 'release':
|
|
||||||
badgeClass = 'info-badge'
|
|
||||||
break
|
|
||||||
case 'alpha':
|
|
||||||
badgeClass = 'alpha-badge'
|
|
||||||
break
|
|
||||||
case 'beta':
|
|
||||||
default:
|
|
||||||
badgeClass = 'beta-badge'
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OLTooltip
|
<OLTooltip
|
||||||
id={tooltip.id}
|
id={tooltip.id}
|
||||||
|
@ -57,4 +45,16 @@ const BetaBadge: FC<{
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const chooseBadgeClass = (phase?: string) => {
|
||||||
|
switch (phase) {
|
||||||
|
case 'release':
|
||||||
|
return 'info-badge'
|
||||||
|
case 'alpha':
|
||||||
|
return 'alpha-badge'
|
||||||
|
case 'beta':
|
||||||
|
default:
|
||||||
|
return 'beta-badge'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default BetaBadge
|
export default BetaBadge
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import { createContext, FC, useContext, useMemo } from 'react'
|
import { createContext, FC, useContext, useMemo } from 'react'
|
||||||
import getMeta from '../../utils/meta'
|
import getMeta from '../../utils/meta'
|
||||||
|
import { SplitTestInfo } from '../../../../types/split-test'
|
||||||
type SplitTestVariants = Record<string, any>
|
|
||||||
type SplitTestInfo = Record<string, any>
|
|
||||||
|
|
||||||
export const SplitTestContext = createContext<
|
export const SplitTestContext = createContext<
|
||||||
| {
|
| {
|
||||||
splitTestVariants: SplitTestVariants
|
splitTestVariants: Record<string, string>
|
||||||
splitTestInfo: SplitTestInfo
|
splitTestInfo: Record<string, SplitTestInfo>
|
||||||
}
|
}
|
||||||
| undefined
|
| undefined
|
||||||
>(undefined)
|
>(undefined)
|
||||||
|
@ -44,3 +42,15 @@ export function useFeatureFlag(name: string) {
|
||||||
const { splitTestVariants } = useSplitTestContext()
|
const { splitTestVariants } = useSplitTestContext()
|
||||||
return splitTestVariants[name] === 'enabled'
|
return splitTestVariants[name] === 'enabled'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useSplitTest(name: string): {
|
||||||
|
variant: string | undefined
|
||||||
|
info: SplitTestInfo | undefined
|
||||||
|
} {
|
||||||
|
const { splitTestVariants, splitTestInfo } = useSplitTestContext()
|
||||||
|
|
||||||
|
return {
|
||||||
|
variant: splitTestVariants[name],
|
||||||
|
info: splitTestInfo[name],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,11 @@ forEach(Object.keys(suggestions)).describe(
|
||||||
win.metaAttributesCache.set('ol-splitTestVariants', {
|
win.metaAttributesCache.set('ol-splitTestVariants', {
|
||||||
'spell-check-client': 'enabled',
|
'spell-check-client': 'enabled',
|
||||||
})
|
})
|
||||||
win.metaAttributesCache.set('ol-splitTestInfo', {})
|
win.metaAttributesCache.set('ol-splitTestInfo', {
|
||||||
|
'spell-check-client': {
|
||||||
|
phase: 'release',
|
||||||
|
},
|
||||||
|
})
|
||||||
win.metaAttributesCache.set('ol-learnedWords', ['baz'])
|
win.metaAttributesCache.set('ol-learnedWords', ['baz'])
|
||||||
win.metaAttributesCache.set(
|
win.metaAttributesCache.set(
|
||||||
'ol-dictionariesRoot',
|
'ol-dictionariesRoot',
|
||||||
|
|
|
@ -8,4 +8,8 @@ export type SplitTestInfo = {
|
||||||
rolloutPercent: number
|
rolloutPercent: number
|
||||||
}[]
|
}[]
|
||||||
hasOverride?: boolean
|
hasOverride?: boolean
|
||||||
|
badgeInfo?: {
|
||||||
|
url?: string
|
||||||
|
tooltipText?: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue