Explorar o código

feat: implement Overleaf Code experiment with Python execution support

GitOrigin-RevId: 54ca98525b2ae056fb34b3713320e868b8c19613
Domagoj Kriskovic hai 7 meses
pai
achega
3b17b0a46a

+ 7 - 1
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 SymbolPalettePane from '@/features/ide-react/components/editor/symbol-palette-pane'
 import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
 import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context'
 import { PythonEditorSplit } from '@/features/ide-react/components/layout/python-editor-split'
 import { PythonEditorSplit } from '@/features/ide-react/components/layout/python-editor-split'
+import { isInExperiment } from '@/utils/labs-utils'
 
 
 export const Editor = () => {
 export const Editor = () => {
   const { opening, errorState, showSymbolPalette } =
   const { opening, errorState, showSymbolPalette } =
@@ -19,6 +20,7 @@ export const Editor = () => {
   const isPythonDocument =
   const isPythonDocument =
     openEntity?.type === 'doc' &&
     openEntity?.type === 'doc' &&
     openEntity.entity.name.toLowerCase().endsWith('.py')
     openEntity.entity.name.toLowerCase().endsWith('.py')
+  const pythonExecutionEnabled = isInExperiment('overleaf-code')
 
 
   if (!currentDocumentId) {
   if (!currentDocumentId) {
     return null
     return null
@@ -43,7 +45,11 @@ export const Editor = () => {
           order={1}
           order={1}
           className="ide-redesign-editor-panel"
           className="ide-redesign-editor-panel"
         >
         >
-          {isPythonDocument ? <PythonEditorSplit /> : <SourceEditor />}
+          {isPythonDocument && pythonExecutionEnabled ? (
+            <PythonEditorSplit />
+          ) : (
+            <SourceEditor />
+          )}
           {isLoading && <EditorLoadingPane />}
           {isLoading && <EditorLoadingPane />}
         </Panel>
         </Panel>
         {showSymbolPalette && (
         {showSymbolPalette && (

+ 49 - 0
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<LabsExperimentWidgetProps, 'setErrorMessage'> & {
+  labsProgram: boolean
+}
+
+const LabsWidget = ({ setErrorMessage, labsProgram }: LabsWidgetProps) => {
+  const [optedIn, setOptedIn] = useState(isInExperiment('overleaf-code'))
+
+  if (!isSplitTestEnabled('overleaf-code')) {
+    return null
+  }
+
+  const description = (
+    <span>
+      Run Python code while editing <code>.py</code> files
+    </span>
+  )
+
+  return (
+    <LabsExperimentWidget
+      description={description}
+      experimentName="overleaf-code"
+      title="Overleaf Code (Python execution)"
+      setOptedIn={setOptedIn}
+      setErrorMessage={setErrorMessage}
+      optedIn={optedIn}
+      logo={
+        <MaterialIcon
+          type="code"
+          size="2x"
+          className="rounded bg-primary-subtle"
+        />
+      }
+      optedInDescription={description}
+      labsEnabled={labsProgram}
+    />
+  )
+}
+
+export const hidden = () => !isSplitTestEnabled('overleaf-code')
+
+export default LabsWidget

+ 4 - 1
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
 // Should be `never` when no experiments are active. Otherwise it should be a
 // union of active experiment names e.g. `'experiment1' | 'experiment2'`
 // 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 => {
 export const isInExperiment = (experiment: ActiveExperiment): boolean => {
   const experiments = getMeta('ol-labsExperiments')
   const experiments = getMeta('ol-labsExperiments')