Skip to content

Commit 7b32b33

Browse files
committed
feat: introduce mrf action that cannot be added by user
1 parent 9142e15 commit 7b32b33

File tree

11 files changed

+71
-5
lines changed

11 files changed

+71
-5
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import mrfSubmission from './mrf-submission'
2+
3+
export default [mrfSubmission]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { IGlobalVariable, IRawAction } from '@plumber/types'
2+
3+
import getDataOutMetadata from '../../triggers/new-submission/get-data-out-metadata'
4+
5+
const action: IRawAction = {
6+
name: 'New form response',
7+
key: 'mrfSubmission',
8+
hiddenFromUser: true,
9+
description:
10+
'This is a hidden action that signifies a subsequent MRF submission',
11+
getDataOutMetadata,
12+
13+
async testRun(_$: IGlobalVariable) {
14+
// TODO: this should run testRun for the trigger execution step
15+
},
16+
}
17+
18+
export default action

packages/backend/src/apps/formsg/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { IApp } from '@plumber/types'
22

33
import beforeRequest from './common/before-request'
4+
import actions from './actions'
45
import auth from './auth'
56
import triggers from './triggers'
67

@@ -16,7 +17,7 @@ const app: IApp = {
1617
beforeRequest,
1718
auth,
1819
triggers,
19-
actions: [],
20+
actions,
2021
demoVideoDetails: {
2122
url: 'https://demo.arcade.software/6cWULLTHkTH4XsSB1rs1?embed&show_copy_link=true',
2223
title: 'Setting up FormSG',

packages/backend/src/graphql/mutations/create-step.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { raw } from 'objection'
22

33
import { BadUserInputError } from '@/errors/graphql-errors'
4+
import App from '@/models/app'
45
import Step from '@/models/step'
56

67
import type { MutationResolvers } from '../__generated__/types.generated'
@@ -12,6 +13,18 @@ const createStep: MutationResolvers['createStep'] = async (
1213
) => {
1314
const { input } = params
1415

16+
const triggerOrAction = await App.findTriggerOrActionByKey(
17+
input.appKey,
18+
input.key,
19+
)
20+
21+
if (!triggerOrAction) {
22+
throw new BadUserInputError('No such trigger or action')
23+
}
24+
if ('hiddenFromUser' in triggerOrAction && triggerOrAction.hiddenFromUser) {
25+
throw new BadUserInputError('Action can only be created by system')
26+
}
27+
1528
return await Step.transaction(async (trx) => {
1629
await trx.raw('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;')
1730

packages/backend/src/graphql/mutations/update-step.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { IAction } from '@/../../types'
12
import { BadUserInputError } from '@/errors/graphql-errors'
23
import App from '@/models/app'
34
import Step from '@/models/step'
@@ -11,6 +12,14 @@ const updateStep: MutationResolvers['updateStep'] = async (
1112
) => {
1213
const { input } = params
1314

15+
const triggerOrAction = await App.findTriggerOrActionByKey(
16+
input.appKey,
17+
input.key,
18+
)
19+
if (!triggerOrAction) {
20+
throw new BadUserInputError('No such trigger or action')
21+
}
22+
1423
const step = await Step.transaction(async (trx) => {
1524
const step = await context.currentUser
1625
.$relatedQuery('steps', trx)
@@ -34,8 +43,10 @@ const updateStep: MutationResolvers['updateStep'] = async (
3443
// NOTE: we use this function to first validate the step parameters
3544
// to avoid misuse and saving invalid step parameters
3645
if (step.type === 'action') {
37-
const app = await App.findOneByKey(input.appKey)
38-
const action = app?.actions?.find((action) => action.key === step.key)
46+
const action = triggerOrAction as IAction
47+
if (action?.hiddenFromUser) {
48+
throw new BadUserInputError('Action can only be updated by system')
49+
}
3950
action?.validateStepParameters?.(input.parameters)
4051
}
4152

packages/backend/src/graphql/queries/get-apps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const ACTION_APPS_RANKING = [
5656
customApiApp.key,
5757
vaultWorkspaceApp.key,
5858
twilioApp.key,
59+
formsgApp.key,
5960
]
6061

6162
function sortApps(apps: IApp[]): IApp[] {

packages/backend/src/graphql/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ type Action {
166166
name: String
167167
key: String
168168
description: String
169+
hiddenFromUser: Boolean
169170
groupsLaterSteps: Boolean
170171
setupMessage: SetupMessage
171172
isNew: Boolean

packages/backend/src/models/app.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IApp } from '@plumber/types'
1+
import { IAction, IApp, ITrigger } from '@plumber/types'
22

33
import { memoize } from 'lodash'
44

@@ -37,6 +37,17 @@ class App {
3737
return appInfoConverter(rawAppData)
3838
}
3939

40+
static async findTriggerOrActionByKey(
41+
appKey: string,
42+
key: string,
43+
): Promise<ITrigger | IAction> {
44+
const app = await this.findOneByKey(appKey)
45+
return (
46+
app.triggers?.find((trigger) => trigger.key === key) ||
47+
app.actions?.find((action) => action.key === key)
48+
)
49+
}
50+
4051
static getAllAppsWithFunctions = memoize(async () => {
4152
return await this.findAll(null, false)
4253
})

packages/frontend/src/components/FlowStepConfigurationModal/ChooseAppAndEvent/ChooseApp.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,14 +275,18 @@ export default function ChooseApp(props: ChooseAppProps) {
275275

276276
const triggersOrActions = isTrigger
277277
? app.triggers
278-
: app.actions
278+
: app.actions?.filter((action) => !action.hiddenFromUser)
279279
const singleTriggerOrAction =
280280
triggersOrActions?.length === 1
281281
? triggersOrActions[0]
282282
: null
283283

284284
const isAppDisabled = appSelectableMap?.[app.key] === false
285285

286+
if (!triggersOrActions?.length) {
287+
return null
288+
}
289+
286290
return (
287291
<Flex
288292
key={app.key}

packages/frontend/src/graphql/queries/get-apps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ export const GET_APPS = gql`
177177
groupsLaterSteps
178178
isNew
179179
linkToGuide
180+
hiddenFromUser
180181
substeps {
181182
key
182183
name

0 commit comments

Comments
 (0)