diff --git a/services/web/frontend/js/features/ide-react/components/layout/editor.tsx b/services/web/frontend/js/features/ide-react/components/layout/editor.tsx
index deab008812..e534dc6a06 100644
--- a/services/web/frontend/js/features/ide-react/components/layout/editor.tsx
+++ b/services/web/frontend/js/features/ide-react/components/layout/editor.tsx
@@ -10,6 +10,7 @@ import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
import SymbolPalettePane from '@/features/ide-react/components/editor/symbol-palette-pane'
import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
import { PythonEditorSplit } from '@/features/ide-react/components/layout/python-editor-split'
+import { isInExperiment } from '@/utils/labs-utils'
export const Editor = () => {
const { opening, errorState, showSymbolPalette } =
@@ -19,6 +20,7 @@ export const Editor = () => {
const isPythonDocument =
openEntity?.type === 'doc' &&
openEntity.entity.name.toLowerCase().endsWith('.py')
+ const pythonExecutionEnabled = isInExperiment('overleaf-code')
if (!currentDocumentId) {
return null
@@ -43,7 +45,11 @@ export const Editor = () => {
order={1}
className="ide-redesign-editor-panel"
>
- {isPythonDocument ? : }
+ {isPythonDocument && pythonExecutionEnabled ? (
+
+ ) : (
+
+ )}
{isLoading && }
{showSymbolPalette && (
diff --git a/services/web/frontend/js/features/overleaf-code/labs-widget.tsx b/services/web/frontend/js/features/overleaf-code/labs-widget.tsx
new file mode 100644
index 0000000000..f69ac9e198
--- /dev/null
+++ b/services/web/frontend/js/features/overleaf-code/labs-widget.tsx
@@ -0,0 +1,49 @@
+import LabsExperimentWidget, {
+ LabsExperimentWidgetProps,
+} from '@/shared/components/labs/labs-experiments-widget'
+import MaterialIcon from '@/shared/components/material-icon'
+import { isInExperiment } from '@/utils/labs-utils'
+import { isSplitTestEnabled } from '@/utils/splitTestUtils'
+import { useState } from 'react'
+
+type LabsWidgetProps = Pick & {
+ labsProgram: boolean
+}
+
+const LabsWidget = ({ setErrorMessage, labsProgram }: LabsWidgetProps) => {
+ const [optedIn, setOptedIn] = useState(isInExperiment('overleaf-code'))
+
+ if (!isSplitTestEnabled('overleaf-code')) {
+ return null
+ }
+
+ const description = (
+
+ Run Python code while editing .py files
+
+ )
+
+ return (
+
+ }
+ optedInDescription={description}
+ labsEnabled={labsProgram}
+ />
+ )
+}
+
+export const hidden = () => !isSplitTestEnabled('overleaf-code')
+
+export default LabsWidget
diff --git a/services/web/frontend/js/utils/labs-utils.ts b/services/web/frontend/js/utils/labs-utils.ts
index 2ea9a89e4e..7de15b7a7d 100644
--- a/services/web/frontend/js/utils/labs-utils.ts
+++ b/services/web/frontend/js/utils/labs-utils.ts
@@ -3,7 +3,10 @@ import getMeta from './meta'
// Should be `never` when no experiments are active. Otherwise it should be a
// union of active experiment names e.g. `'experiment1' | 'experiment2'`
-export type ActiveExperiment = 'monthly-texlive' | 'bibtex-visual-editor'
+export type ActiveExperiment =
+ | 'monthly-texlive'
+ | 'bibtex-visual-editor'
+ | 'overleaf-code'
export const isInExperiment = (experiment: ActiveExperiment): boolean => {
const experiments = getMeta('ol-labsExperiments')