Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,5 @@
"tsconfig-paths": "^4.2.0",
"type-fest": "4.10.3"
},
"version": "1.56.3"
"version": "1.56.4"
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ function buildTableMetadatum(fieldData: IJSONObject): IDataOutMetadata {

const tableObject = JSON.parse(fieldData.answer as string)
return {
label: `Response ${fieldData.order}`,
label: fieldData.question
? `${fieldData.order}. ${fieldData.question}`
: `Response ${fieldData.order}`,
order: fieldData.order ? (fieldData.order as number) + 0.1 : null,
type: 'table',
displayedValue: `Preview ${tableObject.rows.length} row(s)`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type FormField = {
_id: string
columns?: Array<{
_id: string
title?: string
}>
fieldType: string
fieldOptions?: string[]
Expand Down Expand Up @@ -130,8 +131,9 @@ async function getMockData($: IGlobalVariable) {
data.responses[formFields[i]._id].answer = 'Signature captured' // mock this to always be present regardless of whether the user has signed or not
}

// formsg payload doesnt contain this anyways, so we dont return in mock data
if (fieldType === 'statement') {
// formsg payload doesnt contain these fields anyways, so we dont return in mock data
// this ensures that the question numbering remains consistent with the actual submission
if (fieldType === 'statement' || fieldType === 'image') {
delete data.responses[formFields[i]._id]
continue
}
Expand Down Expand Up @@ -160,11 +162,21 @@ async function getMockData($: IGlobalVariable) {
if (fieldType === 'table') {
const answerArray = data.responses[formFields[i]._id]
.answerArray as string[][]
const question = data.responses[formFields[i]._id].question
const question = `${
data.responses[formFields[i]._id].question
} (${formFields[i].columns
?.map((column, index) => column?.title ?? `Col ${index + 1}`)
.join(', ')})`

data.responses[formFields[i]._id].question = question
data.responses[formFields[i]._id].answer =
convertTableAnswerArrayToTableObject(question, answerArray)
}

if (fieldType === 'section' || fieldType === 'image') {
data.responses[formFields[i]._id].answer = ''
}

data.responses[formFields[i]._id].order = i + 1
data.responses[formFields[i]._id].id = undefined
}
Expand Down
42 changes: 2 additions & 40 deletions packages/backend/src/apps/slack/auth/generate-auth-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,8 @@ import type {

import qs from 'qs'

const scopes = [
'channels:manage',
'channels:read',
'channels:join',
'chat:write',
'chat:write.customize',
'chat:write.public',
'files:write',
'im:write',
'mpim:write',
'team:read',
'users.profile:read',
'users:read',
'workflow.steps:execute',
'users:read.email',
'commands',
]
const userScopes = [
'channels:history',
'channels:read',
'channels:write',
'chat:write',
'emoji:read',
'files:read',
'files:write',
'groups:history',
'groups:read',
'groups:write',
'im:write',
'mpim:write',
'reactions:read',
'reminders:write',
'search:read',
'stars:read',
'team:read',
'users.profile:read',
'users.profile:write',
'users:read',
'users:read.email',
]
const scopes = ['chat:write', 'chat:write.customize', 'chat:write.public']
const userScopes = ['channels:read', 'chat:write', 'search:read', 'users:read']

export default async function generateAuthUrl($: IGlobalVariable) {
// Our own auth, so safe to cast $.app.auth
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/apps/slack/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const auth: IUserAddedConnectionAuth = {
},
{
key: 'consumerKey',
label: 'API Key',
label: 'Client ID',
type: 'string' as const,
required: true,
readOnly: false,
Expand All @@ -33,7 +33,7 @@ const auth: IUserAddedConnectionAuth = {
},
{
key: 'consumerSecret',
label: 'API Secret',
label: 'Client Secret',
type: 'string' as const,
required: true,
readOnly: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ const updateFlowTransferStatus: MutationResolvers['updateFlowTransferStatus'] =
// nullify connections for M365-excel
// excel connections cannot be shared; the new owner should use their own connection
const excelStepIds = flow.steps
.filter((step) => step.appKey === 'm365-excel')
.filter(
(step) => step.appKey === 'm365-excel' && step.connectionId != null,
)
.map((step) => step.id)
const numExcelNullified = await Step.query(trx)
.patch({ connection: null, connectionId: null, status: 'incomplete' })
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "1.56.3",
"version": "1.56.4",
"type": "module",
"scripts": {
"dev": "wait-on tcp:3000 && vite --host --force",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default function TableVariableItem(props: TableVariableItemProps) {
/>
{!onClick && (
<TableVariableModal
variableId={variable.name}
isOpen={isOpen}
onClose={onClose}
currentExecutionStep={currentTestExecutionStep}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ interface TableVariableModalProps {
isOpen: boolean
onClose: () => void
currentExecutionStep?: IExecutionStep | null
// variableName is the step variable: `step.<uuid>.xxxxx`
variableId: string
}

const TableHeader = ({ columns }: { columns: ProcessedColumn[] }) => (
Expand Down Expand Up @@ -107,12 +109,15 @@ const TableRow = ({
)

export default function TableVariableModal(props: TableVariableModalProps) {
const { isOpen, onClose, currentExecutionStep } = props
const { isOpen, onClose, currentExecutionStep, variableId } = props

if (!currentExecutionStep) {
return null
}
const { rowsFound, dataRows, columns } = processData(currentExecutionStep)
const { rowsFound, dataRows, columns } = processData(
currentExecutionStep,
variableId,
)

return (
<Modal
Expand Down
71 changes: 40 additions & 31 deletions packages/frontend/src/components/VariablesList/schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IJSONObject } from '@plumber/types'

import get from 'lodash.get'
import { z } from 'zod'

const RowDataSchema = z.object({
Expand Down Expand Up @@ -32,26 +33,31 @@ const FormSgTableFieldSchema = z.object({

const FormSgFieldSchema = z.object({
fieldType: z.string(),
answer: z.union([z.string(), z.record(z.any())]).optional(),
answer: z.union([z.string(), z.record(z.any())]).nullish(),
})

const FormSgFieldsSchema = z.record(FormSgFieldSchema).transform((fields) => {
const tableField = Object.values(fields).find(
(field) => field?.fieldType === 'table',
) as z.infer<typeof FormSgFieldSchema> | undefined
const createFormSgFieldsSchema = (variableId: string) => {
const regex = new RegExp(
/step\.[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}\.fields\.([^.]+)\.answer/,
)
const match = variableId.match(regex)
const tableFieldId = match?.[1]

if (!tableField) {
return {
fieldType: 'table',
answer: {
rows: [],
columns: [],
},
return z.record(FormSgFieldSchema).transform((fields) => {
if (!tableFieldId) {
return {
fieldType: 'table',
answer: {
rows: [],
columns: [],
},
}
}
}

return FormSgTableFieldSchema.parse(tableField)
})
const tableField = get(fields, tableFieldId)
return FormSgTableFieldSchema.parse(tableField)
})
}

/**
* FormSG has a different dataOut structure from our own apps.
Expand All @@ -60,26 +66,29 @@ const FormSgFieldsSchema = z.record(FormSgFieldSchema).transform((fields) => {
* Note: FormSG implements check to have at least 1 row in the table field.
* the cells may be empty, but there will always be at least 1 row.
*/
export const FormSgTableDataOutSchema = z
.object({
fields: FormSgFieldsSchema,
})
.transform((dataOut) => {
const parsedData = dataOut.fields.answer as z.infer<typeof RowDataSchema>
return {
rowsFound:
(parsedData.rows as z.infer<typeof RowDataSchema>['rows'])?.length ?? 0,
data: parsedData,
}
})
export const createFormSgTableDataOutSchema = (variableName: string) =>
z
.object({
fields: createFormSgFieldsSchema(variableName),
})
.transform((dataOut) => {
const parsedData = dataOut.fields.answer as z.infer<typeof RowDataSchema>
return {
rowsFound:
(parsedData.rows as z.infer<typeof RowDataSchema>['rows'])?.length ??
0,
data: parsedData,
}
})

export const MultipleRowDataOutSchema = z.object({
rowsFound: z.union([z.string(), z.number()]).default(0),
data: RowDataSchema,
})

// Enhanced schema that can handle both regular and FormSG data
export const ExecutionStepDataOutSchema = z.union([
MultipleRowDataOutSchema,
FormSgTableDataOutSchema,
])
export const createExecutionStepDataOutSchema = (variableName: string) =>
z.union([
MultipleRowDataOutSchema,
createFormSgTableDataOutSchema(variableName),
])
11 changes: 8 additions & 3 deletions packages/frontend/src/components/VariablesList/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IExecutionStep } from '@plumber/types'

import { ExecutionStepDataOutSchema } from './schema'
import { createExecutionStepDataOutSchema } from './schema'

export interface RawColumn {
id: string
Expand Down Expand Up @@ -42,9 +42,14 @@ const processColumns = (rawColumns: RawColumn[]): ProcessedColumn[] => {
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
}

export const processData = (executionStep: IExecutionStep): ProcessedData => {
export const processData = (
executionStep: IExecutionStep,
variableId: string,
): ProcessedData => {
try {
const dataOut = ExecutionStepDataOutSchema.parse(executionStep.dataOut)
const dataOut = createExecutionStepDataOutSchema(variableId).parse(
executionStep.dataOut,
)
const rowsFound = String(dataOut.rowsFound)

return {
Expand Down
2 changes: 1 addition & 1 deletion packages/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"name": "@plumber/types",
"description": "Shared types for plumber",
"types": "./index.d.ts",
"version": "1.56.3"
"version": "1.56.4"
}
Loading