Skip to content

Commit 9f1f34c

Browse files
committed
feat(grpc): grpc scripting implimentaion - before call start, before message send, after message receive, after call end
1 parent 5e8e234 commit 9f1f34c

54 files changed

Lines changed: 1993 additions & 1465 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/bruno-app/src/components/CodeEditor/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ class CodeEditor extends React.Component {
123123
},
124124
'Shift-Tab': 'indentLess',
125125
'Ctrl-Space': (cm) => {
126-
showRootHints(cm, this.props.showHintsFor, this.props.protocol);
126+
showRootHints(cm, this.props.showHintsFor, this.props.requestType, this.props.scriptType);
127127
},
128128
'Cmd-Space': (cm) => {
129-
showRootHints(cm, this.props.showHintsFor, this.props.protocol);
129+
showRootHints(cm, this.props.showHintsFor, this.props.requestType, this.props.scriptType);
130130
},
131131
'Ctrl-Y': 'foldAll',
132132
'Cmd-Y': 'foldAll',
@@ -255,7 +255,8 @@ class CodeEditor extends React.Component {
255255
// Setup AutoComplete Helper for all modes
256256
const autoCompleteOptions = {
257257
showHintsFor: this.props.showHintsFor,
258-
protocol: this.props.protocol,
258+
requestType: this.props.requestType,
259+
scriptType: this.props.scriptType,
259260
getAllVariables: getAllVariablesHandler
260261
};
261262

packages/bruno-app/src/components/RequestPane/GrpcRequestPane/index.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { hasEffectiveAuth } from 'utils/auth';
1616
import { AUTH_MODES_GRPC } from 'utils/common/constants';
1717
import Script from 'components/RequestPane/Script';
1818
import Tests from 'components/RequestPane/Tests';
19+
import { getPhasesByRequestType, REQUEST_TYPES } from '@usebruno/common';
1920

2021
const GrpcRequestPane = ({ item, collection, handleRun }) => {
2122
const dispatch = useDispatch();
@@ -24,6 +25,7 @@ const GrpcRequestPane = ({ item, collection, handleRun }) => {
2425
const rightContentRef = useRef(null);
2526
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
2627
const requestPaneTab = focusedTab?.requestPaneTab;
28+
const scriptPhases = getPhasesByRequestType(REQUEST_TYPES.GRPC);
2729

2830
const selectTab = useCallback((tab) => {
2931
dispatch(
@@ -49,10 +51,10 @@ const GrpcRequestPane = ({ item, collection, handleRun }) => {
4951
return <Documentation item={item} collection={collection} />;
5052
}
5153
case 'scripts': {
52-
return <Script protocol="grpc" item={item} collection={collection} />;
54+
return <Script item={item} collection={collection} />;
5355
}
5456
case 'tests': {
55-
return <Tests item={item} collection={collection} protocol="grpc" />;
57+
return <Tests item={item} collection={collection} />;
5658
}
5759
default: {
5860
return <div className="mt-4">404 | Not found</div>;
@@ -80,7 +82,7 @@ const GrpcRequestPane = ({ item, collection, handleRun }) => {
8082
const isClientStreaming = request.methodType === 'client-streaming' || request.methodType === 'bidi-streaming';
8183

8284
const allTabs = useMemo(() => {
83-
const hasScriptError = item.preRequestScriptErrorMessage || item.onMessageScriptErrorMessage || item.postResponseScriptErrorMessage;
85+
const hasScriptError = scriptPhases.some((phase) => item[`${phase.ERROR_STATE_KEY}Message`]);
8486
const getMessageIndicator = () => {
8587
if (grpcMessagesCount > 0) {
8688
return isClientStreaming ? (
@@ -116,15 +118,15 @@ const GrpcRequestPane = ({ item, collection, handleRun }) => {
116118
{
117119
key: 'scripts',
118120
label: 'Scripts',
119-
indicator: (script.req || script.stream || script.res) ? (hasScriptError ? <StatusDot type="error" /> : <StatusDot />) : null
121+
indicator: scriptPhases.some(({ FIELD }) => script?.[FIELD]) ? (hasScriptError ? <StatusDot type="error" /> : <StatusDot />) : null
120122
},
121123
{
122124
key: 'tests',
123125
label: 'Tests',
124126
indicator: tests && tests.length > 0 ? hasTestError ? <StatusDot type="error" /> : <StatusDot type="default" /> : null
125127
}
126128
];
127-
}, [grpcMessagesCount, isClientStreaming, activeHeadersLength, hasAuth, tests, hasTestError, docs, item.preRequestScriptErrorMessage, item.onMessageScriptErrorMessage, item.postResponseScriptErrorMessage]);
129+
}, [grpcMessagesCount, isClientStreaming, activeHeadersLength, hasAuth, script, tests, hasTestError, docs, ...scriptPhases.map(({ ERROR_STATE_KEY }) => item[`${ERROR_STATE_KEY}Message`])]);
128130

129131
// Initialize tab to 'body' if no tab is currently set
130132
useEffect(() => {

packages/bruno-app/src/components/RequestPane/HttpRequestPane/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import ResponsiveTabs from 'ui/ResponsiveTabs';
2020
import HeightBoundContainer from 'ui/HeightBoundContainer';
2121
import AuthMode from '../Auth/AuthMode/index';
2222
import { hasEffectiveAuth } from 'utils/auth';
23+
import { getPhasesByRequestType, REQUEST_TYPES } from '@usebruno/common';
2324

2425
const TAB_CONFIG = [
2526
{ key: 'params', label: 'Params' },
@@ -58,6 +59,7 @@ const HttpRequestPane = ({ item, collection }) => {
5859

5960
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
6061
const requestPaneTab = focusedTab?.requestPaneTab;
62+
const scriptPhases = getPhasesByRequestType(REQUEST_TYPES.HTTP);
6163
const getProperty = useCallback(
6264
(key) => (item.draft ? get(item, `draft.${key}`, []) : get(item, key, [])),
6365
[item.draft, item]
@@ -97,7 +99,7 @@ const HttpRequestPane = ({ item, collection }) => {
9799
);
98100

99101
const indicators = useMemo(() => {
100-
const hasScriptError = item.preRequestScriptErrorMessage || item.postResponseScriptErrorMessage;
102+
const hasScriptError = scriptPhases.some((phase) => item[`${phase.ERROR_STATE_KEY}Message`]);
101103
const hasTestError = item.testScriptErrorMessage;
102104

103105
return {
@@ -106,14 +108,14 @@ const HttpRequestPane = ({ item, collection }) => {
106108
headers: activeCounts.headers > 0 ? <sup className="font-medium">{activeCounts.headers}</sup> : null,
107109
auth: hasAuth ? <StatusDot dataTestId="auth" /> : null,
108110
vars: activeCounts.vars > 0 ? <sup className="font-medium">{activeCounts.vars}</sup> : null,
109-
script: (script.req || script.res) ? (hasScriptError ? <StatusDot type="error" /> : <StatusDot />) : null,
111+
script: scriptPhases.some(({ FIELD }) => script?.[FIELD]) ? (hasScriptError ? <StatusDot type="error" /> : <StatusDot />) : null,
110112
assert: activeCounts.assertions > 0 ? <sup className="font-medium">{activeCounts.assertions}</sup> : null,
111113
tests: tests?.length > 0 ? (hasTestError ? <StatusDot type="error" /> : <StatusDot />) : null,
112114
docs: docs?.length > 0 ? <StatusDot /> : null,
113115
app: app?.code?.length > 0 ? <StatusDot dataTestId="app" /> : null,
114116
settings: tags?.length > 0 ? <StatusDot /> : null
115117
};
116-
}, [activeCounts, body.mode, hasAuth, script, item.preRequestScriptErrorMessage, item.postResponseScriptErrorMessage, item.testScriptErrorMessage, tests, docs, app, tags]);
118+
}, [activeCounts, body.mode, hasAuth, script, ...scriptPhases.map(({ ERROR_STATE_KEY }) => item[`${ERROR_STATE_KEY}Message`]), item.testScriptErrorMessage, tests, docs, app, tags]);
117119

118120
const allTabs = useMemo(
119121
() => TAB_CONFIG.map(({ key, label }) => ({ key, label, indicator: indicators[key] })),

packages/bruno-app/src/components/RequestPane/Script/index.js

Lines changed: 38 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,9 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from 'components/Tabs';
1313
import StatusDot from 'components/StatusDot';
1414
import { usePersistedState } from 'hooks/usePersistedState';
1515
import { useFocusErrorLine } from 'hooks/useFocusErrorLine';
16+
import { getPhasesByRequestType } from '@usebruno/common';
1617

17-
const getScriptPhases = (protocol = 'http') => {
18-
if (protocol === 'grpc') {
19-
return [
20-
{
21-
key: 'before-invoke',
22-
label: 'Before Invoke',
23-
field: 'req',
24-
hints: ['req', 'bru']
25-
},
26-
{
27-
key: 'on-message',
28-
label: 'On Message',
29-
field: 'stream',
30-
hints: ['req', 'stream', 'bru']
31-
},
32-
{
33-
key: 'after-response',
34-
label: 'After Response',
35-
field: 'res',
36-
hints: ['req', 'res', 'bru']
37-
}
38-
];
39-
}
40-
41-
return [
42-
{
43-
key: 'pre-request',
44-
label: 'Pre Request',
45-
field: 'req',
46-
hints: ['req', 'bru']
47-
},
48-
{
49-
key: 'post-response',
50-
label: 'Post Response',
51-
field: 'res',
52-
hints: ['req', 'res', 'bru']
53-
}
54-
];
55-
};
56-
57-
const Script = ({ item, collection, protocol = 'http' }) => {
18+
const Script = ({ item, collection }) => {
5819
const dispatch = useDispatch();
5920

6021
const editorRefs = useRef({});
@@ -67,7 +28,7 @@ const Script = ({ item, collection, protocol = 'http' }) => {
6728
const { displayedTheme } = useTheme();
6829
const preferences = useSelector((state) => state.app.preferences);
6930

70-
const SCRIPT_PHASES = useMemo(() => getScriptPhases(protocol), [protocol]);
31+
const SCRIPT_PHASES = useMemo(() => getPhasesByRequestType(item?.type), [item?.type]);
7132

7233
const getEditorRef = (phaseKey) => {
7334
return (editorRefs.current[phaseKey] ??= { current: null });
@@ -80,8 +41,8 @@ const Script = ({ item, collection, protocol = 'http' }) => {
8041
};
8142

8243
const getDefaultTab = () => {
83-
const hasFirstScript = getScript(SCRIPT_PHASES[0].field);
84-
return hasFirstScript ? SCRIPT_PHASES[0].key : SCRIPT_PHASES[1]?.key;
44+
const hasFirstScript = getScript(SCRIPT_PHASES[0].FIELD);
45+
return hasFirstScript ? SCRIPT_PHASES[0].SCRIPT_TYPE : SCRIPT_PHASES[1]?.SCRIPT_TYPE;
8546
};
8647

8748
const activeTab = scriptPaneTab || getDefaultTab();
@@ -93,7 +54,7 @@ const Script = ({ item, collection, protocol = 'http' }) => {
9354

9455
useEffect(() => {
9556
const timer = setTimeout(() => {
96-
const activePhase = SCRIPT_PHASES.find((p) => p.key === activeTab);
57+
const activePhase = SCRIPT_PHASES.find(({ SCRIPT_TYPE }) => SCRIPT_TYPE === activeTab);
9758
if (!activePhase) return;
9859

9960
const editorRef = getEditorRef(activeTab);
@@ -109,12 +70,12 @@ const Script = ({ item, collection, protocol = 'http' }) => {
10970
return () => clearTimeout(timer);
11071
}, [activeTab, SCRIPT_PHASES]);
11172

112-
SCRIPT_PHASES.forEach((phase) => {
73+
SCRIPT_PHASES.forEach(({ SCRIPT_TYPE }) => {
11374
useFocusErrorLine({
11475
uid: item.uid,
115-
editorRef: getEditorRef(phase.key),
116-
scriptPhase: phase.key,
117-
isVisible: activeTab === phase.key
76+
editorRef: getEditorRef(SCRIPT_TYPE),
77+
scriptPhase: SCRIPT_TYPE,
78+
isVisible: activeTab === SCRIPT_TYPE
11879
});
11980
});
12081

@@ -138,39 +99,39 @@ const Script = ({ item, collection, protocol = 'http' }) => {
13899
dispatch(updateScriptPaneTab({ uid: item.uid, scriptPaneTab: tab }));
139100
};
140101

141-
const renderEditor = (phase) => {
142-
const value = getScript(phase.field);
102+
const renderEditor = ({ SCRIPT_TYPE, FIELD, HINTS }) => {
103+
const value = getScript(FIELD);
143104

144105
return (
145106
<div className="relative h-full">
146107
<CodeEditor
147-
ref={getEditorRef(phase.key)}
108+
ref={getEditorRef(SCRIPT_TYPE)}
148109
collection={collection}
149110
item={item}
150-
protocol={protocol}
151-
docKey={`script:${phase.key}`}
111+
requestType={item?.type}
112+
docKey={`script:${SCRIPT_TYPE}`}
152113
value={value || ''}
153114
theme={displayedTheme}
154115
font={get(preferences, 'font.codeFont', 'default')}
155116
fontSize={get(preferences, 'font.codeFontSize')}
156117
mode="javascript"
157-
onEdit={(val) => onScriptEdit(phase.field, val)}
118+
onEdit={(val) => onScriptEdit(FIELD, val)}
158119
onRun={onRun}
159120
onSave={onSave}
160-
showHintsFor={phase.hints}
161-
scriptType={phase.key}
162-
initialScroll={scrollMap?.[phase.key] || 0}
121+
showHintsFor={HINTS}
122+
scriptType={SCRIPT_TYPE}
123+
initialScroll={scrollMap?.[SCRIPT_TYPE] || 0}
163124
onScroll={(pos) =>
164125
setScrollMap({
165126
...scrollMap,
166-
[phase.key]: pos
127+
[SCRIPT_TYPE]: pos
167128
})}
168129
/>
169130
<AIAssist
170-
scriptType={phase.key}
131+
scriptType={SCRIPT_TYPE}
171132
currentScript={value || ''}
172133
requestContext={requestContext}
173-
onApply={(val) => onScriptEdit(phase.field, val)}
134+
onApply={(val) => onScriptEdit(FIELD, val)}
174135
/>
175136
</div>
176137
);
@@ -181,16 +142,16 @@ const Script = ({ item, collection, protocol = 'http' }) => {
181142
<Tabs value={activeTab} onValueChange={onScriptTabChange}>
182143
<TabsList>
183144
{SCRIPT_PHASES.map((phase) => {
184-
const value = getScript(phase.field);
145+
const value = getScript(phase.FIELD);
185146
const hasScript = value && value.trim().length > 0;
186147

187148
return (
188-
<TabsTrigger key={phase.key} value={phase.key}>
189-
{phase.label}
149+
<TabsTrigger key={phase.SCRIPT_TYPE} value={phase.SCRIPT_TYPE}>
150+
{phase.LABEL}
190151
{hasScript && (
191152
<StatusDot
192153
type={
193-
item?.[`${phase.key}ScriptErrorMessage`]
154+
item?.[`${phase.SCRIPT_TYPE}ScriptErrorMessage`]
194155
? 'error'
195156
: 'default'
196157
}
@@ -201,16 +162,18 @@ const Script = ({ item, collection, protocol = 'http' }) => {
201162
})}
202163
</TabsList>
203164

204-
{SCRIPT_PHASES.map((phase) => (
205-
<TabsContent
206-
key={phase.key}
207-
value={phase.key}
208-
className="mt-2"
209-
dataTestId={`${phase.key}-script-editor`}
210-
>
211-
{activeTab === phase.key ? renderEditor(phase) : null}
212-
</TabsContent>
213-
))}
165+
{SCRIPT_PHASES.map((phase) => {
166+
return (
167+
<TabsContent
168+
key={phase.SCRIPT_TYPE}
169+
value={phase.SCRIPT_TYPE}
170+
className="mt-2"
171+
dataTestId={`${phase.SCRIPT_TYPE}-script-editor`}
172+
>
173+
{activeTab === phase.SCRIPT_TYPE ? renderEditor(phase) : null}
174+
</TabsContent>
175+
);
176+
})}
214177
</Tabs>
215178
</div>
216179
);

packages/bruno-app/src/components/RequestPane/Tests/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ import { useFocusErrorLine } from 'hooks/useFocusErrorLine';
1414
* @typedef {Object} TestsProps
1515
* @property {Object} item - The request item (http or grpc).
1616
* @property {Object} collection - The collection the item belongs to.
17-
* @property {'http' | 'grpc'} [protocol] - Request protocol; defaults to 'http'.
1817
*/
1918

2019
/** @param {TestsProps} props */
21-
const Tests = ({ item, collection, protocol = 'http' }) => {
20+
const Tests = ({ item, collection }) => {
2221
const dispatch = useDispatch();
2322
const testsEditorRef = useRef(null);
2423
const tests = item.draft ? get(item, 'draft.request.tests') : get(item, 'request.tests');
@@ -54,7 +53,7 @@ const Tests = ({ item, collection, protocol = 'http' }) => {
5453
ref={testsEditorRef}
5554
collection={collection}
5655
item={item}
57-
protocol={protocol}
56+
requestType={item?.type}
5857
docKey="tests"
5958
value={tests || ''}
6059
theme={displayedTheme}

0 commit comments

Comments
 (0)