diff --git a/backend/controller/console.go b/backend/controller/console.go index 9aff7bd93f..1a7288f761 100644 --- a/backend/controller/console.go +++ b/backend/controller/console.go @@ -40,6 +40,40 @@ func (*ConsoleService) Ping(context.Context, *connect.Request[ftlv1.PingRequest] return connect.NewResponse(&ftlv1.PingResponse{}), nil } +func visitNode(sch *schema.Schema, n schema.Node, verbString *string) error { + return schema.Visit(n, func(n schema.Node, next func() error) error { + switch n := n.(type) { + case *schema.Ref: + data, err := sch.ResolveRefMonomorphised(n) + if err != nil { + return err + } + *verbString += data.String() + "\n\n" + + err = visitNode(sch, data, verbString) + if err != nil { + return err + } + default: + } + return next() + }) +} + +func verbSchemaString(sch *schema.Schema, verb *schema.Verb) (string, error) { + var verbString string + err := visitNode(sch, verb.Request, &verbString) + if err != nil { + return "", err + } + err = visitNode(sch, verb.Response, &verbString) + if err != nil { + return "", err + } + verbString += verb.String() + return verbString, nil +} + func (c *ConsoleService) GetModules(ctx context.Context, req *connect.Request[pbconsole.GetModulesRequest]) (*connect.Response[pbconsole.GetModulesResponse], error) { deployments, err := c.dal.GetDeploymentsWithMinReplicas(ctx) if err != nil { @@ -65,7 +99,7 @@ func (c *ConsoleService) GetModules(ctx context.Context, req *connect.Request[pb case *schema.Verb: //nolint:forcetypeassert v := decl.ToProto().(*schemapb.Verb) - verbSchema := schema.VerbFromProto(v) // TODO: include all of the types that the verb references + verbSchema := schema.VerbFromProto(v) var jsonRequestSchema string if requestData, ok := verbSchema.Request.(*schema.Ref); ok { jsonSchema, err := schema.DataToJSONSchema(sch, *requestData) @@ -78,9 +112,14 @@ func (c *ConsoleService) GetModules(ctx context.Context, req *connect.Request[pb } jsonRequestSchema = string(jsonData) } + + schemaString, err := verbSchemaString(sch, decl) + if err != nil { + return nil, err + } verbs = append(verbs, &pbconsole.Verb{ Verb: v, - Schema: verbSchema.String(), + Schema: schemaString, JsonRequestSchema: jsonRequestSchema, }) diff --git a/backend/controller/console_test.go b/backend/controller/console_test.go new file mode 100644 index 0000000000..95894164d4 --- /dev/null +++ b/backend/controller/console_test.go @@ -0,0 +1,76 @@ +package controller + +import ( + "testing" + + "github.com/TBD54566975/ftl/backend/schema" + "github.com/alecthomas/assert/v2" +) + +func TestVerbSchemaString(t *testing.T) { + verb := &schema.Verb{ + Name: "Echo", + Request: &schema.Ref{Module: "foo", Name: "EchoRequest"}, + Response: &schema.Ref{Module: "foo", Name: "EchoResponse"}, + } + sch := &schema.Schema{ + Modules: []*schema.Module{ + {Name: "foo", Decls: []schema.Decl{ + verb, + &schema.Data{ + Name: "EchoRequest", + Fields: []*schema.Field{ + {Name: "Name", Type: &schema.String{}}, + {Name: "Nested", Type: &schema.Ref{Module: "foo", Name: "Nested"}}, + {Name: "External", Type: &schema.Ref{Module: "bar", Name: "BarData"}}, + }, + }, + &schema.Data{ + Name: "EchoResponse", + Fields: []*schema.Field{ + {Name: "Message", Type: &schema.String{}}, + }, + }, + &schema.Data{ + Name: "Nested", + Fields: []*schema.Field{ + {Name: "Field", Type: &schema.String{}}, + }, + }, + }}, + {Name: "bar", Decls: []schema.Decl{ + verb, + &schema.Data{ + Name: "BarData", + Export: true, + Fields: []*schema.Field{ + {Name: "Name", Type: &schema.String{}}, + }, + }}, + }}, + } + + expected := `data EchoRequest { + Name String + Nested foo.Nested + External bar.BarData +} + +data Nested { + Field String +} + +export data BarData { + Name String +} + +data EchoResponse { + Message String +} + +verb Echo(foo.EchoRequest) foo.EchoResponse` + + schemaString, err := verbSchemaString(sch, verb) + assert.NoError(t, err) + assert.Equal(t, expected, schemaString) +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index aa0d2495a5..aaff944f96 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,7 +11,6 @@ "@bufbuild/protoc-gen-es": "1.9.0", "@codemirror/commands": "^6.5.0", "@codemirror/gutter": "^0.19.9", - "@codemirror/lang-json": "^6.0.1", "@codemirror/language": "^6.10.1", "@codemirror/state": "^6.4.1", "@codemirror/theme-one-dark": "^6.1.2", @@ -30,6 +29,7 @@ "@viz-js/viz": "3.4.0", "codemirror": "^5.65.16", "codemirror-json-schema": "^0.7.1", + "codemirror-json5": "^1.0.3", "elkjs": "^0.9.2", "fnv1a": "^1.1.1", "highlight.js": "^11.8.0", @@ -815,6 +815,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", + "optional": true, "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/json": "^1.0.0" @@ -1649,6 +1650,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz", "integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==", + "optional": true, "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", @@ -3828,7 +3830,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/codemirror-json5/-/codemirror-json5-1.0.3.tgz", "integrity": "sha512-HmmoYO2huQxoaoG5ARKjqQc9mz7/qmNPvMbISVfIE2Gk1+4vZQg9X3G6g49MYM5IK00Ol3aijd7OKrySuOkA7Q==", - "optional": true, "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -7153,7 +7154,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lezer-json5/-/lezer-json5-2.0.2.tgz", "integrity": "sha512-NRmtBlKW/f8mA7xatKq8IUOq045t8GVHI4kZXrUtYYUdiVeGiO6zKGAV7/nUAnf5q+rYTY+SWX/gvQdFXMjNxQ==", - "optional": true, "dependencies": { "@lezer/lr": "^1.0.0" } diff --git a/frontend/package.json b/frontend/package.json index 268b0fe491..ca1ffc6802 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,7 +27,6 @@ "@bufbuild/protoc-gen-es": "1.9.0", "@codemirror/commands": "^6.5.0", "@codemirror/gutter": "^0.19.9", - "@codemirror/lang-json": "^6.0.1", "@codemirror/language": "^6.10.1", "@codemirror/state": "^6.4.1", "@codemirror/theme-one-dark": "^6.1.2", @@ -46,6 +45,7 @@ "@viz-js/viz": "3.4.0", "codemirror": "^5.65.16", "codemirror-json-schema": "^0.7.1", + "codemirror-json5": "^1.0.3", "elkjs": "^0.9.2", "fnv1a": "^1.1.1", "highlight.js": "^11.8.0", diff --git a/frontend/src/components/CodeEditor.tsx b/frontend/src/components/CodeEditor.tsx index c517dc3cc0..6589f3b3cc 100644 --- a/frontend/src/components/CodeEditor.tsx +++ b/frontend/src/components/CodeEditor.tsx @@ -13,7 +13,6 @@ import { lintGutter } from '@codemirror/lint' import { lintKeymap } from '@codemirror/lint' import { linter } from '@codemirror/lint' import { - indentOnInput, bracketMatching, foldGutter, @@ -29,7 +28,7 @@ import { } from '@codemirror/autocomplete' import { useRef, useEffect, useCallback } from 'react' -import { json, jsonParseLinter } from '@codemirror/lang-json' +import { json5, json5ParseLinter } from 'codemirror-json5' import { jsonSchemaLinter, jsonSchemaHover, stateExtensions, handleRefresh } from 'codemirror-json-schema' import { useDarkMode } from '../providers/dark-mode-provider' import { defaultKeymap } from '@codemirror/commands' @@ -81,7 +80,7 @@ export const CodeEditor = ( indentOnInput(), drawSelection(), foldGutter(), - linter(jsonParseLinter(), { + linter(json5ParseLinter(), { delay: 300 }), linter(jsonSchemaLinter(), { @@ -101,8 +100,7 @@ export const CodeEditor = ( extensions: [ commonExtensions, isDarkMode ? atomone : githubLight, - json(), - + json5(), editingExtensions ], }) diff --git a/frontend/src/components/RightPanelAttribute.tsx b/frontend/src/components/RightPanelAttribute.tsx new file mode 100644 index 0000000000..b627501340 --- /dev/null +++ b/frontend/src/components/RightPanelAttribute.tsx @@ -0,0 +1,10 @@ +export const RightPanelAttribute = ({ name, value }: { name?: string, value?: string }) => { + return ( +
+ {name} + +
{value}
+
+
+ ) +} diff --git a/frontend/src/features/calls/CallList.tsx b/frontend/src/features/calls/CallList.tsx index c2aa53a468..9f7ad6e24b 100644 --- a/frontend/src/features/calls/CallList.tsx +++ b/frontend/src/features/calls/CallList.tsx @@ -55,9 +55,8 @@ export const CallList = ({ calls }: { calls: CallEvent[] | undefined }) => { {calls?.map((call, index) => ( handleCallClicked(call)} > @@ -66,10 +65,10 @@ export const CallList = ({ calls }: { calls: CallEvent[] | undefined }) => { {formatDuration(call.duration)} - + {call.sourceVerbRef && verbRefString(call.sourceVerbRef)} - + {call.destinationVerbRef && verbRefString(call.destinationVerbRef)} diff --git a/frontend/src/features/console/right-panel/ConfigPanels.tsx b/frontend/src/features/console/right-panel/ConfigPanels.tsx index 739ec02ecd..36f1d8eaf5 100644 --- a/frontend/src/features/console/right-panel/ConfigPanels.tsx +++ b/frontend/src/features/console/right-panel/ConfigPanels.tsx @@ -1,3 +1,4 @@ +import { RightPanelAttribute } from '../../../components/RightPanelAttribute' import { Config } from '../../../protos/xyz/block/ftl/v1/console/console_pb' import { ExpandablePanelProps } from '../ExpandablePanel' @@ -6,14 +7,7 @@ export const configPanels = (config: Config) => { { title: config.config?.name, expanded: true, - children: ( -
- Type - -
{config.config?.type?.value?.case}
-
-
- ), + children: , }, ] as ExpandablePanelProps[] } diff --git a/frontend/src/features/console/right-panel/ModulePanels.tsx b/frontend/src/features/console/right-panel/ModulePanels.tsx index 9358bc6541..1491edc5d5 100644 --- a/frontend/src/features/console/right-panel/ModulePanels.tsx +++ b/frontend/src/features/console/right-panel/ModulePanels.tsx @@ -11,14 +11,9 @@ import { import { Module } from '../../../protos/xyz/block/ftl/v1/console/console_pb' import { ExpandablePanelProps } from '../ExpandablePanel' import { CodeBlock } from '../../../components' - -import { MetadataCalls } from '../../../protos/xyz/block/ftl/v1/schema/schema_pb' import { NavigateFunction } from 'react-router-dom' - -interface InCall { - module: string - verb?: string -} +import { RightPanelAttribute } from '../../../components/RightPanelAttribute' +import { callsIn, callsOut } from '../../modules/module.utils' export const modulePanels = ( allModules: Module[], @@ -52,12 +47,7 @@ export const modulePanels = ( title: 'Secrets', expanded: false, children: module.secrets.map((s, index) => ( -
- {s.secret?.name} - -
{s.secret?.type?.value?.case}
-
-
+ )), }) } @@ -68,12 +58,7 @@ export const modulePanels = ( title: 'Configs', expanded: false, children: module.configs.map((c) => ( -
- {c.config?.name} - -
{c.config?.type?.value?.case}
-
-
+ )), }) } @@ -119,31 +104,3 @@ export const modulePanels = ( return panels } - -const callsIn = (modules: Module[], module: Module) => { - const allCalls: InCall[] = [] - modules.forEach((m) => { - m.verbs?.forEach((v) => { - v.verb?.metadata - .filter((meta) => meta.value.case === 'calls') - .map((meta) => meta.value.value as MetadataCalls) - .forEach((call) => { - call.calls.forEach((c) => { - if (c.module === module.name) { - allCalls.push({ module: m.name, verb: v.verb?.name }) - } - }) - }) - }) - }) - - return allCalls -} - -const callsOut = (module: Module) => { - const calls = module.verbs?.flatMap((v) => - v.verb?.metadata.filter((meta) => meta.value.case === 'calls').map((meta) => meta.value.value as MetadataCalls), - ) - - return calls -} diff --git a/frontend/src/features/console/right-panel/RootPanels.tsx b/frontend/src/features/console/right-panel/RootPanels.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frontend/src/features/console/right-panel/SecretPanels.tsx b/frontend/src/features/console/right-panel/SecretPanels.tsx index 516312b414..15d584d311 100644 --- a/frontend/src/features/console/right-panel/SecretPanels.tsx +++ b/frontend/src/features/console/right-panel/SecretPanels.tsx @@ -1,3 +1,4 @@ +import { RightPanelAttribute } from '../../../components/RightPanelAttribute' import { Secret } from '../../../protos/xyz/block/ftl/v1/console/console_pb' import { ExpandablePanelProps } from '../ExpandablePanel' @@ -6,14 +7,7 @@ export const secretPanels = (secret: Secret) => { { title: 'Details', expanded: true, - children: ( -
- Type - -
{secret.secret?.type?.value?.case}
-
-
- ), + children: , }, ] as ExpandablePanelProps[] } diff --git a/frontend/src/features/graph/create-layout.ts b/frontend/src/features/graph/create-layout.ts index e901c9e123..6ad9b5d5e6 100644 --- a/frontend/src/features/graph/create-layout.ts +++ b/frontend/src/features/graph/create-layout.ts @@ -1,10 +1,10 @@ import { Edge, Node } from 'reactflow' import { Module, Topology } from '../../protos/xyz/block/ftl/v1/console/console_pb' -import { MetadataCalls } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' import { groupPadding } from './GroupNode' import { verbHeight } from './VerbNode' import { secretHeight } from './SecretNode' import { configHeight } from './ConfigNode' +import { verbCalls } from '../verbs/verb.utils' const groupWidth = 200 const ITEM_SPACING = 10 @@ -78,9 +78,7 @@ export const layoutNodes = (modules: Module[], topology: Topology | undefined) = }) verbs.forEach((verb) => { - const calls = verb?.verb?.metadata - .filter((meta) => meta.value.case === 'calls') - .map((meta) => meta.value.value as MetadataCalls) + const calls = verbCalls(verb) nodes.push({ id: `${module.name}.${verb.verb?.name}`, diff --git a/frontend/src/features/modules/module.utils.ts b/frontend/src/features/modules/module.utils.ts index d407d72ebb..4e0b3d8af1 100644 --- a/frontend/src/features/modules/module.utils.ts +++ b/frontend/src/features/modules/module.utils.ts @@ -1,5 +1,11 @@ import { Module } from '../../protos/xyz/block/ftl/v1/console/console_pb' import { MetadataCalls, Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' +import { verbCalls } from '../verbs/verb.utils' + +interface InCall { + module: string + verb?: string +} export const getCalls = (module: Module) => { const verbCalls: Ref[] = [] @@ -22,3 +28,22 @@ export const getCalls = (module: Module) => { }) return calls } + +export const callsIn = (modules: Module[], module: Module) => { + const allCalls: InCall[] = [] + modules.forEach((m) => { + m.verbs?.forEach((v) => { + verbCalls(v)?.forEach((call) => { + call.calls.forEach((c) => { + if (c.module === module.name) { + allCalls.push({ module: m.name, verb: v.verb?.name }) + } + }) + }) + }) + }) + + return allCalls +} + +export const callsOut = (module: Module) => module.verbs?.flatMap((v) => verbCalls(v)) diff --git a/frontend/src/features/verbs/VerbPage.tsx b/frontend/src/features/verbs/VerbPage.tsx index 57d62ba2e5..d7b033394b 100644 --- a/frontend/src/features/verbs/VerbPage.tsx +++ b/frontend/src/features/verbs/VerbPage.tsx @@ -8,10 +8,9 @@ import { SidePanelProvider } from '../../providers/side-panel-provider' import { callFilter, eventTypesFilter, streamEvents } from '../../services/console.service' import { NotificationType, NotificationsContext } from '../../providers/notifications-provider' import { ResizablePanels } from '../../components/ResizablePanels' -import { CodeBlock } from '../../components/CodeBlock' -import { ExpandablePanelProps } from '../console/ExpandablePanel' import { CallList } from '../calls/CallList' import { VerbRequestForm } from './VerbRequestForm' +import { verbPanels } from './VerbRightPanel' export const VerbPage = () => { const { deploymentKey, verbName } = useParams() @@ -66,15 +65,6 @@ export const VerbPage = () => { } }, [module]) - const panels = [ - { - title: 'Schema', - expanded: true, - children: verb?.verb?.response?.toJsonString() && , - padding: 'p-0', - }, - ] as ExpandablePanelProps[] - const header = (
@@ -100,7 +90,7 @@ export const VerbPage = () => {
} rightPanelHeader={header} - rightPanelPanels={panels} + rightPanelPanels={verbPanels(verb)} bottomPanelContent={} /> diff --git a/frontend/src/features/verbs/VerbRequestForm.tsx b/frontend/src/features/verbs/VerbRequestForm.tsx index b9541d118a..c2ee07df56 100644 --- a/frontend/src/features/verbs/VerbRequestForm.tsx +++ b/frontend/src/features/verbs/VerbRequestForm.tsx @@ -6,7 +6,7 @@ import { CodeEditor, InitialState } from '../../components/CodeEditor' import { useClient } from '../../hooks/use-client' import { VerbService } from '../../protos/xyz/block/ftl/v1/ftl_connect' import { VerbFormInput } from './VerbFormInput' -import { createVerbRequest, defaultRequest, httpPopulatedRequestPath, isHttpIngress, requestPath, requestType, simpleJsonSchema } from './verb.utils' +import { createVerbRequest, defaultRequest, httpPopulatedRequestPath, isHttpIngress, fullRequestPath, requestType, simpleJsonSchema } from './verb.utils' export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb }) => { const client = useClient(VerbService) @@ -53,13 +53,14 @@ export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb const tabs = [ { id: 'body', name: 'Body' }, - { id: 'jsonschema', name: 'JSONSchema' } ] if (isHttpIngress(verb)) { tabs.push({ id: 'headers', name: 'Headers' }) } + tabs.push({ id: 'verbschema', name: 'Verb Schema' }, { id: 'jsonschema', name: 'JSONSchema' }) + const handleSubmit = async (path: string) => { setResponse(null) setError(null) @@ -90,7 +91,7 @@ export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb @@ -123,12 +124,16 @@ export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb {activeTabId === 'body' && ( )} - {activeTabId === 'headers' && ( - + {activeTabId === 'verbschema' && ( + )} {activeTabId === 'jsonschema' && ( )} + {activeTabId === 'headers' && ( + + )} +
diff --git a/frontend/src/features/verbs/VerbRightPanel.tsx b/frontend/src/features/verbs/VerbRightPanel.tsx new file mode 100644 index 0000000000..6d248fad11 --- /dev/null +++ b/frontend/src/features/verbs/VerbRightPanel.tsx @@ -0,0 +1,45 @@ +import { ArrowRightStartOnRectangleIcon } from '@heroicons/react/24/outline' +import { RightPanelAttribute } from '../../components/RightPanelAttribute' +import { Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' +import { ExpandablePanelProps } from '../console/ExpandablePanel' +import { ingress, isHttpIngress, httpRequestPath, verbCalls } from './verb.utils' + +export const verbPanels = (verb?: Verb) => { + const panels = [] as ExpandablePanelProps[] + + console.log(verb?.schema) + if (isHttpIngress(verb)) { + const http = ingress(verb) + const path = httpRequestPath(verb) + panels.push({ + title: 'HTTP Ingress', + expanded: true, + children: ( + <> + + + + ), + }) + } + + const calls = verbCalls(verb)?.map((c) => c.calls).flatMap((c) => c) + if (calls && calls.length > 0) { + panels.push({ + title: 'Calls', + expanded: true, + children: calls?.map((c, index) => ( +
+ +
{`${c?.module}.${c?.name}`}
+
+ + )), + }) + } + + return panels +} diff --git a/frontend/src/features/verbs/verb.utils.ts b/frontend/src/features/verbs/verb.utils.ts index daaef223d5..b5b6fac265 100644 --- a/frontend/src/features/verbs/verb.utils.ts +++ b/frontend/src/features/verbs/verb.utils.ts @@ -1,6 +1,6 @@ import { JsonValue } from 'type-fest/source/basic' import { Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb' -import { MetadataCronJob, MetadataIngress, Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' +import { MetadataCalls, MetadataCronJob, MetadataIngress, Ref } from '../../protos/xyz/block/ftl/v1/schema/schema_pb' import { JSONSchemaFaker } from 'json-schema-faker' const basePath = 'http://localhost:8892/ingress/' @@ -69,11 +69,11 @@ export const defaultRequest = (verb?: Verb): string => { return JSON.stringify(fake, null, 2) ?? '{}' } -const ingress = (verb?: Verb) => { +export const ingress = (verb?: Verb) => { return verb?.verb?.metadata?.find(meta => meta.value.case === 'ingress')?.value?.value as MetadataIngress || null } -const cron = (verb?: Verb) => { +export const cron = (verb?: Verb) => { return verb?.verb?.metadata?.find(meta => meta.value.case === 'cronJob')?.value?.value as MetadataCronJob || null } @@ -84,10 +84,10 @@ export const requestType = (verb?: Verb) => { return ingress?.method ?? cron?.cron?.toUpperCase() ?? 'CALL' } -export const requestPath = (module?: Module, verb?: Verb) => { +export const httpRequestPath = (verb?: Verb) => { const ingress = verb?.verb?.metadata?.find(meta => meta.value.case === 'ingress')?.value?.value as MetadataIngress || null if (ingress) { - return basePath + ingress.path.map(p => { + return ingress.path.map(p => { switch (p.value.case) { case 'ingressPathLiteral': return p.value.value.text @@ -98,6 +98,13 @@ export const requestPath = (module?: Module, verb?: Verb) => { } }).join('/') } +} + +export const fullRequestPath = (module?: Module, verb?: Verb) => { + const ingress = verb?.verb?.metadata?.find(meta => meta.value.case === 'ingress')?.value?.value as MetadataIngress || null + if (ingress) { + return basePath + httpRequestPath(verb) + } const cron = verb?.verb?.metadata?.find(meta => meta.value.case === 'cronJob')?.value?.value as MetadataCronJob || null if (cron) { return cron.cron @@ -107,7 +114,7 @@ export const requestPath = (module?: Module, verb?: Verb) => { } export const httpPopulatedRequestPath = ( module?: Module, verb?: Verb) => { - return requestPath(module, verb).replaceAll(/{([^}]*)}/g, '$1') + return fullRequestPath(module, verb).replaceAll(/{([^}]*)}/g, '$1') } export const isHttpIngress = (verb?: Verb) => { @@ -141,3 +148,9 @@ export const createVerbRequest = (path: string, verb?: Verb, editorText?: strin const buffer = Buffer.from(JSON.stringify(requestJson)) return new Uint8Array(buffer) } + +export const verbCalls = (verb?: Verb) => { + return verb?.verb?.metadata + .filter((meta) => meta.value.case === 'calls') + .map((meta) => meta.value.value as MetadataCalls) ?? null +}