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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.

## [7.26.1](https://github.com/opengovsg/formsg/compare/v7.26.0...v7.26.1) (2026-06-09)


### Bug Fixes

* add replyTo and X-Formsg-Submission-ID headers to MRF outcome emails (#9570) ([#9570](https://github.com/opengovsg/formsg/commit/b7e9c320686c326dc9c6518da4b3a97875cdc980))


### Miscellaneous

* Merge pull request #9568 from opengovsg/chore/revert-number-field-buttons-removal ([#9568](https://github.com/opengovsg/formsg/commit/d1698445285a9b0be20d5ecf02d955cbb2500081))

## [7.26.0](https://github.com/opengovsg/formsg/compare/v7.25.0...v7.26.0) (2026-06-08)


Expand Down
2 changes: 1 addition & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-backend",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"homepage": ".",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import { reportSubmissionResponseTime } from '../submissions.statsd-client'

import { MultirespondentSubmissionContent } from './multirespondent-submission.types'
import {
extractEmailAnswersFromResponses,
extractRespondentCopyEmailDatas,
formatSubmittedStepTimestamp,
getEmailFromResponses,
Expand Down Expand Up @@ -524,13 +525,17 @@ const sendMrfOutcomeEmails = ({
if (isApproval) {
return MailService.sendMrfApprovalEmail({
emails: destinationEmails,
formId: form._id,
formId: String(form._id),
formTitle: form.title,
responseId: submissionId,
submissionId,
timestamp: latestSubmissionTimestamp,
isRejected,
formQuestionAnswers,
attachments: emailAttachments,
replyTo:
extractEmailAnswersFromResponses(responses).join(', ') ||
undefined,
}).orElse((error) => {
logger.error({
message: 'Failed to send approval email',
Expand All @@ -547,12 +552,15 @@ const sendMrfOutcomeEmails = ({

return MailService.sendMrfWorkflowCompletionEmail({
emails: destinationEmails,
formId: form._id,
formId: String(form._id),
formTitle: form.title,
responseId: submissionId,
submissionId,
timestamp: latestSubmissionTimestamp,
formQuestionAnswers,
attachments: emailAttachments,
replyTo:
extractEmailAnswersFromResponses(responses).join(', ') || undefined,
}).orElse((error) => {
logger.error({
message: 'Failed to send workflow completion email',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,23 @@ export const getEmailFromResponses = (
return field.answer.value
}

export const extractEmailAnswersFromResponses = (
responses: FieldResponsesV3,
): string[] => {
if (!responses) return []
return Object.values(responses)
.filter(
(
response,
): response is Extract<
FieldResponseV3,
{ fieldType: BasicField.Email }
> => response.fieldType === BasicField.Email,
)
.map((response) => response.answer.value)
.filter(Boolean)
}

const getConditionalFieldEmailRecipient = (
form_fields: FormFieldSchema[] | FormFieldDto[],
fieldId: string,
Expand Down
12 changes: 12 additions & 0 deletions apps/backend/src/app/services/mail/mail.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1186,17 +1186,21 @@ export class MailService {
formId,
formTitle,
responseId,
submissionId,
timestamp,
formQuestionAnswers,
attachments,
replyTo,
}: {
emails: string[]
formId: string
formTitle: string
responseId: string
submissionId?: string
timestamp: string
formQuestionAnswers: QuestionAnswer[]
attachments?: Mail.Attachment[]
replyTo?: string
}): ResultAsync<true, MailGenerationError | MailSendError> => {
const emailTemplateData: EmailData = {
formTitle,
Expand All @@ -1213,6 +1217,8 @@ export class MailService {
attachments,
emailType: EmailType.WorkflowCompletion,
actionName: 'sendMrfWorkflowCompletionEmail',
submissionId,
replyTo,
})
}

Expand All @@ -1221,19 +1227,23 @@ export class MailService {
formId,
formTitle,
responseId,
submissionId,
timestamp,
isRejected,
formQuestionAnswers,
attachments,
replyTo,
}: {
emails: string[]
formId: string
formTitle: string
responseId: string
submissionId?: string
timestamp: string
isRejected: boolean
formQuestionAnswers: QuestionAnswer[]
attachments?: Mail.Attachment[]
replyTo?: string
}): ResultAsync<true, MailGenerationError | MailSendError> => {
const outcome = isRejected
? WorkflowOutcome.NOT_APPROVED
Expand All @@ -1255,6 +1265,8 @@ export class MailService {
attachments,
emailType: EmailType.WorkflowApproval,
actionName: 'sendMrfApprovalEmail',
submissionId,
replyTo,
})
}

Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-frontend",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"homepage": ".",
"type": "module",
Expand Down
10 changes: 0 additions & 10 deletions apps/frontend/src/templates/Field/Number/NumberField.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ import * as stories from './NumberField.stories'
const { ValidationRequired, ValidationOptional } = composeStories(stories)

describe('validation required', () => {
it('does not render stepper buttons', () => {
render(<ValidationRequired />)
expect(
screen.queryByRole('button', { name: /increment/i, hidden: true }),
).toBeNull()
expect(
screen.queryByRole('button', { name: /decrement/i, hidden: true }),
).toBeNull()
})

it('renders error when field is not filled before submitting', async () => {
// Arrange
const user = userEvent.setup()
Expand Down
1 change: 0 additions & 1 deletion apps/frontend/src/templates/Field/Number/NumberField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const NumberField = ({
defaultValue=""
render={({ field: { value, onChange, ...rest } }) => (
<NumberInput
showSteppers={false}
min={0}
inputMode="numeric"
colorScheme={`theme-${colorTheme}`}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-monorepo",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"description": "Form Manager for Government",
"homepage": "https://form.gov.sg",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-email-preview/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-react-email-preview",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"scripts": {
"build": "email build",
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-shared",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"description": "",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion services/form-payment-reconciliation/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-payment-reconciliation",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"description": "Lambda function for payment reconciliation",
"main": "index.js",
Expand Down
2 changes: 1 addition & 1 deletion services/pdf-gen-sparticuz/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-pdf-gen-sparticuz",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"description": "<!-- title: 'AWS NodeJS Example' description: 'This template demonstrates how to deploy a simple NodeJS function running on AWS Lambda using the Serverless Framework.' layout: Doc framework: v4 platform: AWS language: nodeJS priority: 1 authorLink: 'https://github.com/serverless' authorName: 'Serverless, Inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' -->",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion services/virus-scanner-guardduty/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formsg-virus-scanner-guardduty",
"version": "7.26.0",
"version": "7.26.1",
"private": true,
"description": "",
"scripts": {
Expand Down
Loading