Skip to content

Commit 8238d5f

Browse files
authored
Merge pull request #8862 from opengovsg/release_v6.266.0
build: release v6.266.0
2 parents c9f85a7 + c163fd9 commit 8238d5f

File tree

48 files changed

+1130
-327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1130
-327
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d
44

55
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
66

7+
#### [v6.266.0](https://github.com/opengovsg/FormSG/compare/v6.265.0...v6.266.0)
8+
9+
- feat: singpass with mrf first step [`#8729`](https://github.com/opengovsg/FormSG/pull/8729)
10+
- build: merge v6.265.0 back to develop [`#8861`](https://github.com/opengovsg/FormSG/pull/8861)
11+
- build: release v6.265.0 [`#8859`](https://github.com/opengovsg/FormSG/pull/8859)
12+
- build(deps): bump tar-fs from 2.1.3 to 2.1.4 in /frontend [`#8860`](https://github.com/opengovsg/FormSG/pull/8860)
13+
714
#### [v6.265.0](https://github.com/opengovsg/FormSG/compare/v6.264.0...v6.265.0)
815

16+
> 4 November 2025
17+
918
- fix(deps): bump playwright and @playwright/test [`#8827`](https://github.com/opengovsg/FormSG/pull/8827)
1019
- build(deps): bump tar-fs from 3.1.0 to 3.1.1 in /serverless/pdf-gen-sparticuz [`#8758`](https://github.com/opengovsg/FormSG/pull/8758)
1120
- fix(deps): bump validator from 13.15.15 to 13.15.20 in /shared [`#8840`](https://github.com/opengovsg/FormSG/pull/8840)
@@ -14,6 +23,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
1423
- feat: pinning pdf to generate from lambda [`#8858`](https://github.com/opengovsg/FormSG/pull/8858)
1524
- build: merge release v6.264.0 to develop [`#8855`](https://github.com/opengovsg/FormSG/pull/8855)
1625
- build: release v6.264.0 [`#8853`](https://github.com/opengovsg/FormSG/pull/8853)
26+
- chore: bump version to v6.265.0 [`b72e2ff`](https://github.com/opengovsg/FormSG/commit/b72e2ff92737a2663846972e41e2ccd6ae2ff063)
1727

1828
#### [v6.264.0](https://github.com/opengovsg/FormSG/compare/v6.263.0...v6.264.0)
1929

frontend/package-lock.json

Lines changed: 8 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "form-frontend",
3-
"version": "6.265.0",
3+
"version": "6.266.0",
44
"homepage": ".",
55
"type": "module",
66
"private": true,

frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/FieldListDrawer/field-panels/MyInfoPanel.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ export const MyInfoFieldPanel = ({ searchValue }: { searchValue: string }) => {
244244
</Box>
245245
)}
246246
</Droppable>
247-
{user?.betaFlags?.children ? (
247+
{user?.betaFlags?.children &&
248+
form?.responseMode === FormResponseMode.Encrypt ? (
248249
<Droppable isDropDisabled droppableId={CREATE_MYINFO_CHILDREN_DROP_ID}>
249250
{(provided) => (
250251
<Box ref={provided.innerRef} {...provided.droppableProps}>
@@ -271,13 +272,9 @@ export const MyInfoFieldPanel = ({ searchValue }: { searchValue: string }) => {
271272
)
272273
}
273274

274-
type MyInfoTextProps = Pick<
275-
AdminFormDto,
276-
'responseMode' | 'authType' | 'form_fields'
277-
>
275+
type MyInfoTextProps = Pick<AdminFormDto, 'authType' | 'form_fields'>
278276

279277
const MyInfoText = ({
280-
responseMode,
281278
authType,
282279
form_fields,
283280
}: MyInfoTextProps): JSX.Element => {
@@ -288,12 +285,6 @@ const MyInfoText = ({
288285
[form_fields],
289286
)
290287

291-
if (responseMode === FormResponseMode.Multirespondent) {
292-
return (
293-
<Text>MyInfo fields are not available in multi-respondent forms.</Text>
294-
)
295-
}
296-
297288
if (isMyInfoDisabled) {
298289
return (
299290
<Text>

frontend/src/features/admin-form/create/workflow/components/WorkflowContent/EditStepBlock/EditStepBlock.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,11 @@ export const EditStepBlock = ({
159159
isLoading={_isLoading}
160160
/>
161161
<Divider />
162-
<QuestionsBlock formMethods={formMethods} isLoading={_isLoading} />
162+
<QuestionsBlock
163+
formMethods={formMethods}
164+
isLoading={_isLoading}
165+
isFirstStep={isFirstStep}
166+
/>
163167
{!isFirstStep ? (
164168
<>
165169
<Divider />

frontend/src/features/admin-form/create/workflow/components/WorkflowContent/EditStepBlock/QuestionsBlock.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ import { EditStepBlockContainer } from './EditStepBlockContainer'
2020
interface QuestionsBlockProps {
2121
isLoading: boolean
2222
formMethods: UseFormReturn<EditStepInputs>
23+
isFirstStep: boolean
2324
}
2425

2526
export const QuestionsBlock = ({
2627
isLoading,
2728
formMethods,
29+
isFirstStep,
2830
}: QuestionsBlockProps): JSX.Element => {
2931
const { t } = useTranslation()
3032
const { formFields = [], idToFieldMap } = useAdminFormWorkflow()
@@ -34,11 +36,18 @@ export const QuestionsBlock = ({
3436
} = formMethods
3537

3638
const items = formFields
37-
.filter(
38-
(f) =>
39-
// Only retain actual inputs (exclude header, statement, image)
40-
!NON_RESPONSE_FIELD_SET.has(f.fieldType),
41-
)
39+
.filter((f) => {
40+
// Only retain actual inputs (exclude header, statement, image)
41+
const isFillableField = !NON_RESPONSE_FIELD_SET.has(f.fieldType)
42+
const isMyInfoField = 'myInfo' in f
43+
if (!isFillableField) {
44+
return false
45+
}
46+
if (isMyInfoField && !isFirstStep) {
47+
return false
48+
}
49+
return true
50+
})
4251
.map((f) => ({
4352
value: f._id,
4453
label: getLogicFieldLabel(idToFieldMap[f._id]),

frontend/src/features/admin-form/responses/AdminSubmissionsService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export const getDecryptedSubmissionById = async ({
110110
encryptedContent: encryptedSubmission.encryptedContent,
111111
encryptedSubmissionSecretKey:
112112
encryptedSubmission.encryptedSubmissionSecretKey,
113+
verifiedContent: encryptedSubmission.verifiedContent,
113114
version: encryptedSubmission.version,
114115
})
115116
if (!decryptedContent)

frontend/src/features/admin-form/responses/ResponsesPage/storage/utils/processDecryptedContent.ts

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
DecryptedContentV3,
44
FormField as VerifiedFormField,
55
} from '@opengovsg/formsg-sdk/dist/types'
6-
import { has } from 'lodash'
76

87
import {
98
AttachmentFieldResponseV3,
@@ -12,7 +11,6 @@ import {
1211
FormFieldDto,
1312
} from '~shared/types'
1413
import {
15-
CURRENT_VERIFIED_FIELDS,
1614
SgidFieldTitle,
1715
SPCPFieldTitle,
1816
VerifiedKeys,
@@ -24,48 +22,57 @@ import {
2422
} from '~features/public-form/utils'
2523

2624
/**
27-
* Returns a response matching the given type containing the given value.
28-
* @param type the field type to match
25+
* Returns a verifiedFormField matching the given verifiedKey containing the given value.
26+
* @param verifiedKey the field type to match
2927
* @param value the value to insert into the response to be returned
3028
* @returns the desired response object if type is valid. Else returns null.
3129
*/
32-
const getResponseFromVerifiedField = (
33-
type: VerifiedKeys,
30+
const getVerifiedFieldFromResponse = (
31+
singpassAuthType: VerifiedKeys | string,
3432
value: string,
3533
): VerifiedFormField | null => {
36-
switch (type) {
34+
// Extract verifiedKey and optional step number (for MRF cases) from singpassAuthType
35+
const verifiedKeyMatch = singpassAuthType.match(
36+
/^(uinFin|cpUen|cpUid|sgidUinFin)(?: \(Step (\d+)\))?$/,
37+
)
38+
if (!verifiedKeyMatch) return null
39+
40+
const [, verifiedKey, stepNumber] = verifiedKeyMatch
41+
const stepSuffix = stepNumber ? ` (Step ${stepNumber})` : ''
42+
43+
switch (verifiedKey as VerifiedKeys) {
3744
case VerifiedKeys.SpUinFin:
3845
return {
39-
question: SPCPFieldTitle.SpNric,
46+
question: SPCPFieldTitle.SpNric + stepSuffix,
4047
fieldType: BasicField.Nric,
4148
answer: value,
42-
// Just a unique identifier for CSV header uniqueness
43-
_id: SPCPFieldTitle.SpNric,
49+
_id: SPCPFieldTitle.SpNric + stepSuffix,
4450
}
4551

4652
case VerifiedKeys.CpUen:
4753
return {
48-
question: SPCPFieldTitle.CpUen,
54+
question: SPCPFieldTitle.CpUen + stepSuffix,
4955
fieldType: BasicField.ShortText,
5056
answer: value,
51-
_id: SPCPFieldTitle.CpUen,
57+
_id: SPCPFieldTitle.CpUen + stepSuffix,
5258
}
5359

5460
case VerifiedKeys.CpUid:
5561
return {
56-
question: SPCPFieldTitle.CpUid,
62+
question: SPCPFieldTitle.CpUid + stepSuffix,
5763
fieldType: BasicField.Nric,
5864
answer: value,
59-
_id: SPCPFieldTitle.CpUid,
65+
_id: SPCPFieldTitle.CpUid + stepSuffix,
6066
}
67+
6168
case VerifiedKeys.SgidUinFin:
6269
return {
63-
question: SgidFieldTitle.SgidNric,
70+
question: SgidFieldTitle.SgidNric + stepSuffix,
6471
fieldType: 'nric',
6572
answer: value,
66-
// Just a unique identifier for CSV header uniqueness
67-
_id: SgidFieldTitle.SgidNric,
73+
_id: SgidFieldTitle.SgidNric + stepSuffix,
6874
}
75+
6976
default:
7077
return null
7178
}
@@ -82,15 +89,12 @@ const getResponseFromVerifiedField = (
8289
const convertToResponseArray = (
8390
verifiedObj: Record<string, string>,
8491
): VerifiedFormField[] => {
85-
return CURRENT_VERIFIED_FIELDS.filter((fieldType) =>
86-
has(verifiedObj, fieldType),
87-
)
88-
.map((fieldType) =>
89-
getResponseFromVerifiedField(fieldType, verifiedObj[fieldType]),
92+
return Object.keys(verifiedObj)
93+
.filter((key) =>
94+
Object.values(VerifiedKeys).some((baseKey) => key.startsWith(baseKey)),
9095
)
91-
.filter((field): field is VerifiedFormField => {
92-
return !!field
93-
})
96+
.map((key) => getVerifiedFieldFromResponse(key, verifiedObj[key]))
97+
.filter((field): field is VerifiedFormField => !!field)
9498
}
9599

96100
/**
@@ -122,8 +126,7 @@ export const processDecryptedContentV3 = async (
122126
form_fields: FormFieldDto[],
123127
decrypted: DecryptedContentV3,
124128
): Promise<VerifiedFormField[]> => {
125-
const { responses } = decrypted
126-
129+
const { responses, verified } = decrypted
127130
// Convert decrypted content into displayable object.
128131
const displayedContent = form_fields
129132
.map((ff) => {
@@ -138,9 +141,17 @@ export const processDecryptedContentV3 = async (
138141
answer: answer.answer,
139142
}
140143
}
141-
return transformInputsToOutputs(ff, response.answer)
142-
})
143-
.filter((output): output is FieldResponse => output !== null)
144144

145-
return displayedContent as VerifiedFormField[]
145+
const decryptedResponse = transformInputsToOutputs(ff, response.answer)
146+
if (decryptedResponse && 'myInfo' in ff) {
147+
decryptedResponse.question = `[MyInfo] ${decryptedResponse.question} `
148+
}
149+
return decryptedResponse
150+
})
151+
.filter(
152+
(output): output is FieldResponse => output !== null,
153+
) as VerifiedFormField[]
154+
return verified
155+
? displayedContent.concat(convertToResponseArray(verified))
156+
: displayedContent
146157
}

frontend/src/features/admin-form/responses/ResponsesPage/storage/worker/decryption.worker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ async function decryptIntoCsv(
122122
encryptedSubmissionSecretKey:
123123
submission.encryptedSubmissionSecretKey,
124124
encryptedContent: submission.encryptedContent,
125+
verifiedContent: submission.verifiedContent,
125126
version: submission.version,
126127
})
127128
if (!decryptedObject) {

frontend/src/features/admin-form/settings/SettingsAuthPage.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { FormResponseMode } from '~shared/types'
22

3+
import { useUser } from '~features/user/queries'
4+
35
import AuthSettingsSection from './components/AuthSettingsSection'
46
import { AuthUnsupportedMsg } from './components/AuthSettingsSection/AuthUnsupportedMsg'
57
import { CategoryHeader } from './components/CategoryHeader'
68
import { useAdminFormSettings } from './queries'
79

810
export const SettingsAuthPage = (): JSX.Element => {
911
const { data: settings, isLoading } = useAdminFormSettings()
12+
const { user } = useUser()
1013

11-
// Form auth is unsupported in MRF; show message.
14+
// TODO: FRM-2151 remove when Singpass MRF is out of beta
1215
if (
1316
!isLoading &&
14-
settings?.responseMode === FormResponseMode.Multirespondent
17+
settings?.responseMode === FormResponseMode.Multirespondent &&
18+
!user?.betaFlags?.singpassMrf
1519
) {
1620
return <AuthUnsupportedMsg />
1721
}

0 commit comments

Comments
 (0)