mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 09:09:36 +02:00
Merge pull request #31737 from overleaf/mg-shared-ai-consent
Migrate Writefull AI consent to shared tutorial system GitOrigin-RevId: c9298a177c9f1aa1a941c96599d6d854591f8a76
This commit is contained in:
@@ -219,7 +219,6 @@
|
||||
"buy_licenses": "",
|
||||
"buy_more_licenses": "",
|
||||
"buy_now_no_exclamation_mark": "",
|
||||
"by_continuing_you_agree_to_use_this_feature_in_line_with_your_institutions_policies": "",
|
||||
"by_email": "",
|
||||
"by_sharing_link": "",
|
||||
"by_subscribing_you_agree_to_our_terms_of_service": "",
|
||||
@@ -284,7 +283,6 @@
|
||||
"choose_how_you_search_your_references": "",
|
||||
"choose_which_experiments": "",
|
||||
"citation": "",
|
||||
"citation_checks_are_powered_by_trusted_sources_from_dimensions": "",
|
||||
"cite_a_reference_from_your_reference_manager_to_automatically_add_it_to_your_bib_file": "",
|
||||
"cite_directly_or_import_references": "",
|
||||
"cite_faster": "",
|
||||
@@ -756,6 +754,7 @@
|
||||
"github_workflow_files_delete_github_repo": "",
|
||||
"github_workflow_files_error": "",
|
||||
"github_workflow_files_error_non_owner": "",
|
||||
"give-ai-consent": "",
|
||||
"give_feedback": "",
|
||||
"go_next_page": "",
|
||||
"go_page": "",
|
||||
@@ -1839,7 +1838,6 @@
|
||||
"suggestion_applied": "",
|
||||
"suggests_code_completions_while_typing": "",
|
||||
"support_for_your_browser_is_ending_soon": "",
|
||||
"supporting_your_research_respecting_your_privacy": "",
|
||||
"supports_up_to_x_licenses": "",
|
||||
"sure_you_want_to_cancel_plan_change": "",
|
||||
"sure_you_want_to_change_plan": "",
|
||||
@@ -2318,7 +2316,6 @@
|
||||
"you_have_x_licenses_and_your_plan_supports_up_to_y": "",
|
||||
"you_have_x_licenses_on_your_subscription": "",
|
||||
"you_need_to_configure_your_sso_settings": "",
|
||||
"you_remain_in_control_please_review_all_suggestions_carefully": "",
|
||||
"you_unpaused_your_subscription": "",
|
||||
"you_will_be_able_to_reassign_subscription": "",
|
||||
"youll_get_best_results_in_visual_but_can_be_used_in_source": "",
|
||||
@@ -2355,7 +2352,6 @@
|
||||
"your_plan_is_limited_to_n_editors": "",
|
||||
"your_plan_is_limited_to_n_editors_plural": "",
|
||||
"your_premium_plan_is_paused": "",
|
||||
"your_project_content_is_never_used_for_model_training": "",
|
||||
"your_project_exceeded_collaborator_limit": "",
|
||||
"your_project_exceeded_compile_timeout_limit_on_free_plan": "",
|
||||
"your_project_near_compile_timeout_limit": "",
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import React from 'react'
|
||||
|
||||
interface ConsentPromptMessageBodyProps {
|
||||
className?: string
|
||||
listClassName?: string
|
||||
}
|
||||
|
||||
interface ConsentPromptMessageHeaderProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const AiConsentPromptMessageHeader = ({
|
||||
className,
|
||||
}: ConsentPromptMessageHeaderProps) => {
|
||||
return (
|
||||
<div className={className}>
|
||||
Supporting your research and protecting your privacy
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const AiConsentPromptMessageBody = ({
|
||||
className,
|
||||
listClassName,
|
||||
}: ConsentPromptMessageBodyProps) => {
|
||||
return (
|
||||
<div className={className}>
|
||||
<ul className={listClassName}>
|
||||
<li>
|
||||
AI features in Overleaf, like this one, can help you with writing your
|
||||
document and fixing errors.
|
||||
</li>
|
||||
<li>
|
||||
As some AI features are powered by third parties, your project
|
||||
content/data will be sent to those third parties in order to provide
|
||||
those features to you. However, your project content/data will not be
|
||||
used for model training. There are more details about how we use your
|
||||
data in{' '}
|
||||
<a
|
||||
href="https://docs.overleaf.com/integrations-and-add-ons/ai-features#data-privacy-and-responsible-use"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
our docs
|
||||
</a>
|
||||
.
|
||||
</li>
|
||||
<li>
|
||||
Like any AI, AI features in Overleaf can make mistakes, so please
|
||||
review all suggestions carefully before accepting them.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
By using these features, you approve the use and sharing of your data in
|
||||
this way.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
33
services/web/frontend/js/shared/hooks/use-ai-consent.ts
Normal file
33
services/web/frontend/js/shared/hooks/use-ai-consent.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import useTutorial from '@/shared/hooks/promotions/use-tutorial'
|
||||
|
||||
const AI_CONSENT_TUTORIAL_KEY = 'workbench-consent-release'
|
||||
const eventData = { name: AI_CONSENT_TUTORIAL_KEY }
|
||||
|
||||
export { AI_CONSENT_TUTORIAL_KEY }
|
||||
|
||||
export default function useAiConsent() {
|
||||
const { completeTutorial, checkCompletion } = useTutorial(
|
||||
AI_CONSENT_TUTORIAL_KEY,
|
||||
eventData
|
||||
)
|
||||
|
||||
const hasGivenAiConsent = useMemo(() => checkCompletion(), [checkCompletion])
|
||||
const [consentError, setConsentError] = useState(false)
|
||||
|
||||
const giveAiConsent = useCallback(async () => {
|
||||
setConsentError(false)
|
||||
try {
|
||||
await completeTutorial(
|
||||
{ event: 'promo-click', action: 'complete' },
|
||||
{ failSilently: false }
|
||||
)
|
||||
return true
|
||||
} catch {
|
||||
setConsentError(true)
|
||||
return false
|
||||
}
|
||||
}, [completeTutorial])
|
||||
|
||||
return { hasGivenAiConsent, giveAiConsent, consentError }
|
||||
}
|
||||
@@ -277,7 +277,6 @@
|
||||
"buy_more_licenses": "Buy more licenses",
|
||||
"buy_now_no_exclamation_mark": "Buy now",
|
||||
"by": "by",
|
||||
"by_continuing_you_agree_to_use_this_feature_in_line_with_your_institutions_policies": "By continuing, you agree to use this feature in line with your institution’s policies.",
|
||||
"by_email": "By email",
|
||||
"by_joining_labs": "By joining Labs, you agree to receive occasional emails and updates from Overleaf—for example, to request your feedback. You also agree to our <0>terms of service</0> and <1>privacy notice</1>.",
|
||||
"by_registering_you_agree_to_our_terms_of_service": "By registering, you agree to our <0>terms of service</0> and <1>privacy notice</1>.",
|
||||
@@ -356,7 +355,6 @@
|
||||
"choose_which_experiments": "Choose which experiments you’d like to try.",
|
||||
"choose_your_plan": "Choose your plan",
|
||||
"citation": "Citation",
|
||||
"citation_checks_are_powered_by_trusted_sources_from_dimensions": "Citation checks are powered by trusted sources from Dimensions.",
|
||||
"cite_a_reference_from_your_reference_manager_to_automatically_add_it_to_your_bib_file": "Cite a reference from your reference manager to automatically add it to your .bib file.",
|
||||
"cite_directly_or_import_references": "Cite directly or import references",
|
||||
"cite_faster": "Cite faster",
|
||||
@@ -963,6 +961,7 @@
|
||||
"github_workflow_files_delete_github_repo": "The repository has been created on GitHub but linking was unsuccessful. You will have to delete GitHub repository or choose a new name.",
|
||||
"github_workflow_files_error": "The __appName__ GitHub sync service couldn’t sync GitHub Workflow files (in .github/workflows/). Please authorize __appName__ to edit your GitHub workflow files and try again.",
|
||||
"github_workflow_files_error_non_owner": "The __appName__ GitHub sync service couldn’t sync GitHub Workflow files (in .github/workflows/). Please ensure the project owner has authorized __appName__ to edit this project’s GitHub workflow files and try again.",
|
||||
"give-ai-consent": "Give AI consent",
|
||||
"give_feedback": "Give feedback",
|
||||
"global": "global",
|
||||
"go_back_and_link_accts": "<a href=\"__link__\">Go back</a> and link your accounts",
|
||||
@@ -2343,7 +2342,6 @@
|
||||
"suggests_code_completions_while_typing": "Suggests code completions while typing",
|
||||
"support": "Support",
|
||||
"support_for_your_browser_is_ending_soon": "Support for your browser is ending soon",
|
||||
"supporting_your_research_respecting_your_privacy": "Supporting your research, respecting your privacy",
|
||||
"supports_up_to_x_licenses": "Supports up to <0>__count__ licenses</0>",
|
||||
"sure_you_want_to_cancel_plan_change": "Are you sure you want to revert your scheduled plan change? You will remain subscribed to the <0>__planName__</0> plan.",
|
||||
"sure_you_want_to_change_plan": "Are you sure you want to change plan to <0>__planName__</0>?",
|
||||
@@ -2891,7 +2889,6 @@
|
||||
"you_have_x_licenses_and_your_plan_supports_up_to_y": "You have allocated __addedUsersSize__ licenses and your plan supports up to __groupSize__.",
|
||||
"you_have_x_licenses_on_your_subscription": "You have __groupSize__ licenses on your subscription.",
|
||||
"you_need_to_configure_your_sso_settings": "You need to configure and test your SSO settings before enabling SSO",
|
||||
"you_remain_in_control_please_review_all_suggestions_carefully": "You remain in control, so please review all suggestions carefully before accepting them.",
|
||||
"you_unpaused_your_subscription": "You unpaused your subscription.",
|
||||
"you_will_be_able_to_contact_us_any_time_to_share_your_feedback": "<0>You will be able to contact us</0> any time to share your feedback",
|
||||
"you_will_be_able_to_reassign_subscription": "You will be able to reassign their subscription membership to another person in your organization",
|
||||
@@ -2932,7 +2929,6 @@
|
||||
"your_plan_is_limited_to_n_editors": "Your plan allows __count__ collaborator with edit access and unlimited viewers.",
|
||||
"your_plan_is_limited_to_n_editors_plural": "Your plan allows __count__ collaborators with edit access and unlimited viewers.",
|
||||
"your_premium_plan_is_paused": "Your Premium plan is <0>paused</0>.",
|
||||
"your_project_content_is_never_used_for_model_training": "Your project content is never used for model training. There are more details about how we use your data in <0>our docs</0>.",
|
||||
"your_project_exceeded_collaborator_limit": "Your project exceeded the collaborator limit and access levels were changed. Select a new access level for your collaborators, or upgrade to add more editors or reviewers.",
|
||||
"your_project_exceeded_compile_timeout_limit_on_free_plan": "Your project exceeded the compile timeout limit on our free plan.",
|
||||
"your_project_near_compile_timeout_limit": "Your project is near the compile timeout limit for our free plan.",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { consentTutorialKey } from '@modules/workbench/frontend/js/components/chat'
|
||||
import { AI_CONSENT_TUTORIAL_KEY } from '@/shared/hooks/use-ai-consent'
|
||||
import Workbench from '@modules/workbench/frontend/js/components/workbench'
|
||||
import { EditorProviders } from '../../helpers/editor-providers'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
@@ -13,7 +13,9 @@ describe('Workbench', { scrollBehavior: false }, function () {
|
||||
win.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'ai-workbench-release': 'enabled',
|
||||
})
|
||||
win.metaAttributesCache.set('ol-inactiveTutorials', [consentTutorialKey])
|
||||
win.metaAttributesCache.set('ol-inactiveTutorials', [
|
||||
AI_CONSENT_TUTORIAL_KEY,
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ import { DetachCompileContext } from '@/shared/context/detach-compile-context'
|
||||
import { type CompileContext } from '@/shared/context/local-compile-context'
|
||||
import { EditorContext } from '@/shared/context/editor-context'
|
||||
import { Cobranding } from '@ol-types/cobranding'
|
||||
import { TutorialContext } from '@/shared/context/tutorial-context'
|
||||
import { EDITOR_SESSION_ID } from '@/features/pdf-preview/util/metrics'
|
||||
|
||||
// these constants can be imported in tests instead of
|
||||
@@ -311,25 +310,6 @@ export function makeEditorProvider({
|
||||
return EditorProvider
|
||||
}
|
||||
|
||||
export const makeTutorialProvider = (opts?: {
|
||||
inactiveTutorials: string[]
|
||||
}) => {
|
||||
const TutorialProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
const value = {
|
||||
deactivateTutorial: () => {},
|
||||
inactiveTutorials: opts?.inactiveTutorials ?? [],
|
||||
currentPopup: null,
|
||||
setCurrentPopup: () => {},
|
||||
}
|
||||
return (
|
||||
<TutorialContext.Provider value={value}>
|
||||
{children}
|
||||
</TutorialContext.Provider>
|
||||
)
|
||||
}
|
||||
return TutorialProvider
|
||||
}
|
||||
|
||||
const makeReferencesProvider = () => {
|
||||
const ReferencesProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import React, {
|
||||
type FC,
|
||||
type PropsWithChildren,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { TutorialContext } from '@/shared/context/tutorial-context'
|
||||
|
||||
export const makeTutorialProvider = (opts?: {
|
||||
inactiveTutorials: string[]
|
||||
}) => {
|
||||
const TutorialProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
const [inactiveTutorials, setInactiveTutorials] = useState<string[]>(
|
||||
opts?.inactiveTutorials ?? []
|
||||
)
|
||||
const deactivateTutorial = useCallback((key: string) => {
|
||||
setInactiveTutorials(prev => (prev.includes(key) ? prev : [...prev, key]))
|
||||
}, [])
|
||||
const value = {
|
||||
deactivateTutorial,
|
||||
inactiveTutorials,
|
||||
currentPopup: null,
|
||||
setCurrentPopup: () => {},
|
||||
}
|
||||
return (
|
||||
<TutorialContext.Provider value={value}>
|
||||
{children}
|
||||
</TutorialContext.Provider>
|
||||
)
|
||||
}
|
||||
return TutorialProvider
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import useTutorial from '@/shared/hooks/promotions/use-tutorial'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
EditorProviders,
|
||||
makeTutorialProvider,
|
||||
} from '../../helpers/editor-providers'
|
||||
import { EditorProviders } from '../../helpers/editor-providers'
|
||||
import { makeTutorialProvider } from '../../helpers/make-tutorial-provider'
|
||||
|
||||
const TutorialTester = ({
|
||||
tutorial,
|
||||
|
||||
Reference in New Issue
Block a user