import React, { useEffect, useMemo, useRef } from 'react'; import get from 'lodash/get'; import find from 'lodash/find'; import { useDispatch, useSelector } from 'react-redux'; import CodeEditor from 'components/CodeEditor'; import AIAssist from 'components/AIAssist'; import { buildAiVariablesPayload } from 'utils/ai'; import { updateFolderRequestScript, updateFolderResponseScript } from 'providers/ReduxStore/slices/collections'; import { saveFolderRoot } from 'providers/ReduxStore/slices/collections/actions'; import { updateScriptPaneTab } from 'providers/ReduxStore/slices/tabs'; import { useTheme } from 'providers/Theme'; import { Tabs, TabsList, TabsTrigger, TabsContent } from 'components/Tabs'; import StatusDot from 'components/StatusDot'; import { flattenItems, isItemARequest } from 'utils/collections'; import StyledWrapper from './StyledWrapper'; import Button from 'ui/Button'; import { usePersistedState } from 'hooks/usePersistedState'; import { useFocusErrorLine } from 'hooks/useFocusErrorLine'; const Script = ({ collection, folder }) => { const dispatch = useDispatch(); const preRequestEditorRef = useRef(null); const postResponseEditorRef = useRef(null); const requestScript = folder.draft ? get(folder, 'draft.request.script.req', '') : get(folder, 'root.request.script.req', ''); const responseScript = folder.draft ? get(folder, 'draft.request.script.res', '') : get(folder, 'root.request.script.res', ''); const tabs = useSelector((state) => state.tabs.tabs); const focusedTab = find(tabs, (tab) => tab.type === 'folder-settings' && (tab.uid === folder.uid || tab.folderUid === folder.uid)) || find(tabs, (tab) => tab.type === 'folder-settings' && tab.pathname === folder.pathname); const tabUid = focusedTab?.uid || folder.uid; const scriptPaneTab = focusedTab?.scriptPaneTab; // Default to post-response if pre-request script is empty (only when scriptPaneTab is null/undefined) const getDefaultTab = () => { const hasPreRequestScript = requestScript && requestScript.trim().length > 0; return hasPreRequestScript ? 'pre-request' : 'post-response'; }; const activeTab = scriptPaneTab || getDefaultTab(); const setActiveTab = (tab) => { dispatch(updateScriptPaneTab({ uid: tabUid, scriptPaneTab: tab })); }; const { displayedTheme } = useTheme(); const preferences = useSelector((state) => state.app.preferences); const [preReqScroll, setPreReqScroll] = usePersistedState({ key: `folder-pre-req-scroll-${folder.uid}`, default: 0 }); const [postResScroll, setPostResScroll] = usePersistedState({ key: `folder-post-res-scroll-${folder.uid}`, default: 0 }); // Refresh CodeMirror when tab becomes visible and restore scroll position. // CodeMirror's scrollTo() is silently ignored when the editor is inside a display:none container // (TabsContent hides inactive tabs via display:none). After refresh() recalculates layout, we re-apply scrollTo(). useEffect(() => { const timer = setTimeout(() => { if (activeTab === 'pre-request' && preRequestEditorRef.current?.editor) { preRequestEditorRef.current.editor.refresh(); preRequestEditorRef.current.editor.scrollTo(null, preReqScroll); } else if (activeTab === 'post-response' && postResponseEditorRef.current?.editor) { postResponseEditorRef.current.editor.refresh(); postResponseEditorRef.current.editor.scrollTo(null, postResScroll); } }, 0); return () => clearTimeout(timer); }, [activeTab]); useFocusErrorLine({ uid: folder.uid, editorRef: preRequestEditorRef, scriptPhase: 'pre-request', isVisible: activeTab === 'pre-request' }); useFocusErrorLine({ uid: folder.uid, editorRef: postResponseEditorRef, scriptPhase: 'post-response', isVisible: activeTab === 'post-response' }); const onRequestScriptEdit = (value) => { dispatch( updateFolderRequestScript({ script: value, collectionUid: collection.uid, folderUid: folder.uid }) ); }; const onResponseScriptEdit = (value) => { dispatch( updateFolderResponseScript({ script: value, collectionUid: collection.uid, folderUid: folder.uid }) ); }; const handleSave = () => { dispatch(saveFolderRoot(collection.uid, folder.uid)); }; const aiVariables = useMemo(() => buildAiVariablesPayload(collection, folder), [collection, folder]); const items = flattenItems(folder.items || []); const hasPreRequestScriptError = items.some((i) => isItemARequest(i) && i.preRequestScriptErrorMessage); const hasPostResponseScriptError = items.some((i) => isItemARequest(i) && i.postResponseScriptErrorMessage); return (
Pre and post-request scripts that will run before and after any request inside this folder is sent.
Pre Request {requestScript && requestScript.trim().length > 0 && ( )} Post Response {responseScript && responseScript.trim().length > 0 && ( )}
); }; export default Script;