Merge pull request #19448 from overleaf/jdt-experiments-max-subscribers

Enforce a maximum participant cap on experiments

GitOrigin-RevId: 1d9263cd34a3d0c831c0ed43867bb4e6430eb06c
This commit is contained in:
Jimmy Domagala-Tang
2024-07-30 08:05:34 +00:00
committed by Copybot
parent 01b7896717
commit 837fea03b9
6 changed files with 64 additions and 21 deletions
@@ -1,14 +1,11 @@
import { ReactNode, useCallback, useState } from 'react'
import { ReactNode, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import Badge from '@/shared/components/badge'
import Tooltip from '@/shared/components/tooltip'
import { postJSON } from '@/infrastructure/fetch-json'
import { Button } from 'react-bootstrap'
import getMeta from '@/utils/meta'
export type UserFeatures = {
[key: string]: boolean
}
type IntegrationLinkingWidgetProps = {
logo: ReactNode
title: string
@@ -17,6 +14,8 @@ type IntegrationLinkingWidgetProps = {
labsEnabled?: boolean
experimentName: string
setErrorMessage: (message: string) => void
optedIn: boolean
setOptedIn: (optedIn: boolean) => void
}
export function LabsExperimentWidget({
@@ -27,45 +26,47 @@ export function LabsExperimentWidget({
labsEnabled,
experimentName,
setErrorMessage,
optedIn,
setOptedIn,
}: IntegrationLinkingWidgetProps) {
const { t } = useTranslation()
const userFeatures = getMeta('ol-features') as UserFeatures
const [enabled, setEnabled] = useState(() => {
return userFeatures[experimentName] === true
})
const experimentsErrorMessage = t(
'we_are_unable_to_opt_you_into_this_experiment'
)
const allowedExperiments = getMeta('ol-allowedExperiments')
const disabled = !allowedExperiments.includes(experimentName) && !optedIn
const handleEnable = useCallback(async () => {
try {
const enablePath = `/labs/participate/experiments/${experimentName}/opt-in`
await postJSON(enablePath)
setEnabled(true)
setOptedIn(true)
} catch (err) {
setErrorMessage(experimentsErrorMessage)
}
}, [experimentName, setErrorMessage, experimentsErrorMessage])
}, [experimentName, setErrorMessage, experimentsErrorMessage, setOptedIn])
const handleDisable = useCallback(async () => {
try {
const disablePath = `/labs/participate/experiments/${experimentName}/opt-out`
await postJSON(disablePath)
setEnabled(false)
setOptedIn(false)
} catch (err) {
setErrorMessage(experimentsErrorMessage)
}
}, [experimentName, setErrorMessage, experimentsErrorMessage])
}, [experimentName, setErrorMessage, experimentsErrorMessage, setOptedIn])
return (
<div className="labs-experiment-widget-container">
<div
className={`labs-experiment-widget-container ${disabled ? 'disabled-experiment' : ''}`}
>
<div className="p-2">{logo}</div>
<div className="description-container">
<div className="title-row">
<h3 className="h4">{title}</h3>
{enabled && <Badge bsStyle="info">{t('enabled')}</Badge>}
{optedIn && <Badge bsStyle="info">{t('enabled')}</Badge>}
</div>
<p className="small">
{description}{' '}
@@ -76,12 +77,16 @@ export function LabsExperimentWidget({
)}
</p>
</div>
{disabled && (
<div className="disabled-explanation">{t('experiment_full')}</div>
)}
<div>
{labsEnabled && (
<ActionButton
enabled={enabled}
optedIn={optedIn}
handleDisable={handleDisable}
handleEnable={handleEnable}
disabled={disabled}
/>
)}
</div>
@@ -90,19 +95,21 @@ export function LabsExperimentWidget({
}
type ActionButtonProps = {
enabled?: boolean
optedIn?: boolean
disabled?: boolean
handleEnable: () => void
handleDisable: () => void
}
function ActionButton({
enabled,
optedIn,
disabled,
handleEnable,
handleDisable,
}: ActionButtonProps) {
const { t } = useTranslation()
if (enabled) {
if (optedIn) {
return (
<Button
bsStyle="secondary"
@@ -112,6 +119,18 @@ function ActionButton({
{t('turn_off')}
</Button>
)
} else if (disabled) {
return (
<Tooltip
id="experiment-disabled"
description={t('this_experiment_isnt_accepting_new_participants')}
overlayProps={{ delay: 0 }}
>
<Button bsStyle="secondary" className="btn btn-primary" disabled>
{t('turn_on')}
</Button>
</Tooltip>
)
} else {
return (
<Button