Skip to content

Commit edbf3a8

Browse files
committed
feat: getFlowConnections
1 parent 3d9f343 commit edbf3a8

File tree

5 files changed

+224
-0
lines changed

5 files changed

+224
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
3+
import getFlowConnections from '@/graphql/queries/get-flow-connections'
4+
import type Context from '@/types/express/context'
5+
6+
vi.mock('@/models/app', () => ({
7+
default: {
8+
findAll: vi.fn(() => [
9+
{ key: 'slack', name: 'Slack', iconUrl: 'https://example.com/slack.png' },
10+
{
11+
key: 'telegram-bot',
12+
name: 'Telegram',
13+
iconUrl: 'https://example.com/telegram.png',
14+
},
15+
{
16+
key: 'tiles',
17+
name: 'Tables',
18+
iconUrl: 'https://example.com/tiles.png',
19+
},
20+
]),
21+
},
22+
}))
23+
24+
const mockFlowConnectionsQuery = vi.fn()
25+
26+
vi.mock('@/models/flow-connections', () => ({
27+
default: {
28+
query: () => mockFlowConnectionsQuery(),
29+
},
30+
}))
31+
32+
const context = {
33+
currentUser: {
34+
withAccessibleFlows: vi.fn(() => Promise.resolve()),
35+
},
36+
} as unknown as Context
37+
38+
describe('getFlowConnections', () => {
39+
it('should use connection screenName and app key for regular connections', async () => {
40+
mockFlowConnectionsQuery.mockReturnValue({
41+
where: vi.fn().mockReturnThis(),
42+
withGraphFetched: vi.fn().mockResolvedValue([
43+
{
44+
flowId: 'flow-123',
45+
connectionId: 'conn-456',
46+
connectionType: 'connection',
47+
connection: {
48+
key: 'slack',
49+
formattedData: {
50+
screenName: 'My Slack Workspace',
51+
},
52+
},
53+
user: { email: '[email protected]' },
54+
},
55+
]),
56+
})
57+
58+
const result = await getFlowConnections({}, { flowId: 'flow-123' }, context)
59+
60+
expect(result).toEqual([
61+
{
62+
flowId: 'flow-123',
63+
connectionId: 'conn-456',
64+
connectionType: 'connection',
65+
addedBy: '[email protected]',
66+
appName: 'Slack',
67+
appIconUrl: 'https://example.com/slack.png',
68+
connectionName: 'My Slack Workspace',
69+
},
70+
])
71+
})
72+
73+
it('should use table name and "tiles" as appKey for table connections', async () => {
74+
mockFlowConnectionsQuery.mockReturnValue({
75+
where: vi.fn().mockReturnThis(),
76+
withGraphFetched: vi.fn().mockResolvedValue([
77+
{
78+
flowId: 'flow-123',
79+
connectionId: 'table-789',
80+
connectionType: 'table',
81+
table: {
82+
name: 'My Customer Table',
83+
},
84+
user: { email: '[email protected]' },
85+
},
86+
]),
87+
})
88+
89+
const result = await getFlowConnections({}, { flowId: 'flow-123' }, context)
90+
91+
expect(result).toEqual([
92+
{
93+
flowId: 'flow-123',
94+
connectionId: 'table-789',
95+
connectionType: 'table',
96+
addedBy: '[email protected]',
97+
appName: 'Tables',
98+
appIconUrl: 'https://example.com/tiles.png',
99+
connectionName: 'My Customer Table',
100+
},
101+
])
102+
})
103+
104+
it('should handle mixed connection types correctly', async () => {
105+
mockFlowConnectionsQuery.mockReturnValue({
106+
where: vi.fn().mockReturnThis(),
107+
withGraphFetched: vi.fn().mockResolvedValue([
108+
{
109+
flowId: 'flow-123',
110+
connectionId: 'conn-456',
111+
connectionType: 'connection',
112+
connection: {
113+
key: 'telegram-bot',
114+
formattedData: {
115+
screenName: 'My Telegram Bot',
116+
},
117+
},
118+
user: {
119+
120+
},
121+
},
122+
{
123+
flowId: 'flow-123',
124+
connectionId: 'table-789',
125+
connectionType: 'table',
126+
table: {
127+
name: 'Sales Data',
128+
},
129+
user: {
130+
131+
},
132+
},
133+
]),
134+
})
135+
136+
const result = await getFlowConnections({}, { flowId: 'flow-123' }, context)
137+
138+
expect(result).toHaveLength(2)
139+
expect(result[0]).toMatchObject({
140+
connectionType: 'connection',
141+
appName: 'Telegram',
142+
connectionName: 'My Telegram Bot',
143+
})
144+
expect(result[1]).toMatchObject({
145+
connectionType: 'table',
146+
appName: 'Tables',
147+
connectionName: 'Sales Data',
148+
})
149+
})
150+
})
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { IApp } from '@/../../types'
2+
import App from '@/models/app'
3+
import FlowConnections from '@/models/flow-connections'
4+
5+
import { QueryResolvers } from '../__generated__/types.generated'
6+
7+
const getFlowConnections: QueryResolvers['getFlowConnections'] = async (
8+
_parent,
9+
params,
10+
context,
11+
) => {
12+
const apps = await App.findAll()
13+
14+
await context.currentUser.withAccessibleFlows({
15+
requiredRole: 'editor',
16+
})
17+
18+
const rawFlowConnections = await FlowConnections.query()
19+
.where({
20+
flow_id: params.flowId,
21+
})
22+
.withGraphFetched({
23+
connection: true,
24+
user: true,
25+
table: true,
26+
})
27+
28+
const filteredFlowConnections = rawFlowConnections.filter(
29+
(flowConnection) => flowConnection.connection || flowConnection.table,
30+
)
31+
32+
const flowConnections = await Promise.all(
33+
filteredFlowConnections.map(async (flowConnection) => {
34+
let connectionName = flowConnection?.connection?.formattedData?.screenName
35+
if (flowConnection.connectionType === 'table') {
36+
connectionName = flowConnection.table?.name
37+
}
38+
39+
let appKey = flowConnection.connection?.key
40+
if (flowConnection.connectionType === 'table') {
41+
appKey = 'tiles'
42+
}
43+
const app = apps.find((app: IApp) => app.key === appKey)
44+
45+
return {
46+
flowId: flowConnection.flowId,
47+
connectionId: flowConnection.connectionId,
48+
connectionType: flowConnection.connectionType,
49+
addedBy: flowConnection?.user?.email || '',
50+
appName: app.name,
51+
appIconUrl: app.iconUrl,
52+
connectionName: connectionName as string,
53+
}
54+
}),
55+
)
56+
57+
return flowConnections
58+
}
59+
60+
export default getFlowConnections

packages/backend/src/graphql/query-resolvers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import getExecution from './queries/get-execution'
88
import getExecutionSteps from './queries/get-execution-steps'
99
import getExecutions from './queries/get-executions'
1010
import getFlow from './queries/get-flow'
11+
import getFlowConnections from './queries/get-flow-connections'
1112
import getFlowTransferDetails from './queries/get-flow-transfer-details'
1213
import getFlows from './queries/get-flows'
1314
import getPendingFlowTransfers from './queries/get-pending-flow-transfers'
@@ -43,6 +44,7 @@ export default {
4344
getCurrentUser,
4445
healthcheck,
4546
getPendingFlowTransfers,
47+
getFlowConnections,
4648
getFlowTransferDetails,
4749
getTemplates,
4850
...tilesQueryResolvers,

packages/backend/src/graphql/schema.graphql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type Query {
4141
key: String!
4242
parameters: JSONObject
4343
): [JSONObject]
44+
getFlowConnections(flowId: String!): [SharedFlowConnection!]!
4445
# Tiles
4546
getTable(tableId: String!): TableMetadata!
4647
getTableConnections(tableIds: [String!]!): JSONObject
@@ -450,6 +451,16 @@ type FlowAttachmentConfig {
450451
updatedAt: String!
451452
}
452453

454+
type SharedFlowConnection {
455+
flowId: String!
456+
connectionId: String!
457+
connectionType: String!
458+
appName: String!
459+
appIconUrl: String!
460+
addedBy: String!
461+
connectionName: String!
462+
}
463+
453464
type Execution {
454465
id: String
455466
testRun: Boolean

packages/backend/src/models/flow-connections.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class FlowConnections extends Base {
1818
connectionType!: 'connection' | 'table'
1919
connection?: Connection
2020
table?: TableMetadata
21+
user?: User
2122
metadata: Record<string, any>
2223
flow?: Flow
2324

0 commit comments

Comments
 (0)