Skip to content

Commit 090f403

Browse files
authored
PLU-309: [TILES-ATOMIC-INCREMENT-3] enhance multirow-multicol UI with custom styles and operators (#819)
## TLDR; FRONTEND-ONLY For update-row action, allow users to set increment or decrement existing value. ![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/ycT2Xb5nBEjN2kf2gy95/5d5fd96b-f1b2-48df-867d-6eabceb77ece.png) ## What changed - Introduce 2 new attributes to dropdown fields, `isSearchable` and `subFields.customStyles` - if `isSearchable` is set to false, it prevent users from typing to search and center aligns the content (this is an existing prop that is unused) - `subFields.customStyles` allows users to override the container of the subfields in `multirow-multicol` fields ## Why This frontend change will allow users to change the way the value is modified, either set-as, add by or subtract by.
1 parent 06e4750 commit 090f403

File tree

17 files changed

+134
-107
lines changed

17 files changed

+134
-107
lines changed

packages/backend/src/apps/custom-api/actions/http-request/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ const action: IRawAction = {
6161
type: 'string' as const,
6262
required: true,
6363
variables: false,
64+
customStyle: { flex: 2 },
6465
},
6566
{
6667
placeholder: 'Value',
6768
key: 'value',
6869
type: 'string' as const,
6970
required: true,
7071
variables: true,
72+
customStyle: { flex: 3, minWidth: 0 },
7173
},
7274
],
7375
},

packages/backend/src/apps/tiles/actions/update-row/index.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const action: IRawAction = {
4949
{
5050
label: 'Row data',
5151
key: 'rowData',
52-
type: 'multirow' as const,
52+
type: 'multirow-multicol' as const,
5353
description:
5454
'Enter the data to update the row with. Columns not specified will not be updated.',
5555
required: true,
@@ -79,13 +79,34 @@ const action: IRawAction = {
7979
},
8080
],
8181
},
82+
customStyle: { flex: 2, minWidth: 0 },
83+
},
84+
{
85+
key: 'operator' as const,
86+
type: 'dropdown' as const,
87+
isSearchable: false,
88+
required: true,
89+
variables: false,
90+
showOptionValue: false,
91+
value: 'set',
92+
options: [
93+
{ label: '=', value: 'set', description: 'Set as' },
94+
{ label: '+', value: 'add', description: 'Add by (numbers only)' },
95+
{
96+
label: '-',
97+
value: 'subtract',
98+
description: 'Subtract by (numbers only)',
99+
},
100+
],
101+
customStyle: { flexBasis: '71px' },
82102
},
83103
{
84104
placeholder: 'Value',
85105
key: 'cellValue',
86106
type: 'string' as const,
87107
required: false,
88108
variables: true,
109+
customStyle: { flex: 3, minWidth: 0 },
89110
},
90111
],
91112
},

packages/backend/src/graphql/schema.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,10 @@ type ActionSubstepArgument {
183183
variables: Boolean
184184
variableTypes: [String]
185185
allowArbitrary: Boolean
186+
isSearchable: Boolean
186187
placeholder: String
187188
showOptionValue: Boolean
189+
customStyle: JSONObject
188190
options: [ArgumentOption]
189191
value: JSONObject
190192
source: ActionSubstepArgumentSource

packages/frontend/src/components/ControlledAutocomplete/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface ControlledAutocompleteProps {
2323
required?: boolean
2424
placeholder?: string
2525
addNewOption?: IFieldDropdown['addNewOption']
26+
isSearchable?: boolean
2627
}
2728

2829
const formComboboxOptions = (
@@ -62,6 +63,7 @@ function ControlledAutocomplete(
6263
required,
6364
placeholder,
6465
addNewOption,
66+
isSearchable,
6567
} = props
6668

6769
const items = useMemo(
@@ -92,6 +94,7 @@ function ControlledAutocomplete(
9294
name,
9395
control,
9496
rules: { required },
97+
// fixme: this default value is not working as expected
9598
defaultValue: defaultValue ?? '',
9699
})
97100

@@ -146,21 +149,22 @@ function ControlledAutocomplete(
146149
)}
147150
{/* Dropdown row option content */}
148151
<Flex>
149-
<Box flexGrow={1}>
152+
<Box flex={1}>
150153
<SingleSelect
151154
name="choose-dropdown-option"
152155
colorScheme="secondary"
153156
isClearable={!required}
154157
items={items}
155158
onChange={fieldOnChange}
156-
value={fieldValue}
159+
value={fieldValue ?? defaultValue}
157160
placeholder={placeholder}
158161
ref={ref}
159162
data-test={`${name}-autocomplete`}
160163
onRefresh={onRefresh}
161164
isRefreshLoading={loading}
162165
freeSolo={freeSolo}
163166
isReadOnly={isCreatingNewOption}
167+
isSearchable={isSearchable}
164168
addNew={
165169
addNewOption
166170
? {

packages/frontend/src/components/InputCreator/index.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export default function InputCreator(props: InputCreatorProps): JSX.Element {
8787
const preparedOptions = schema.options || optionGenerator(data)
8888
return (
8989
<ControlledAutocomplete
90+
isSearchable={schema.isSearchable ?? true}
9091
name={computedName}
9192
required={required}
9293
freeSolo={schema.allowArbitrary}
@@ -130,29 +131,21 @@ export default function InputCreator(props: InputCreatorProps): JSX.Element {
130131
disabled={disabled}
131132
placeholder={placeholder}
132133
isSingleLine={parentType === 'multicol'}
133-
customStyle={
134-
parentType === 'multicol' ? { flex: 1, minWidth: 0 } : {}
135-
}
136134
variablesEnabled
137135
/>
138136
)
139137
}
140138

141139
return (
142140
<TextField
143-
defaultValue={value}
144141
required={required}
145142
placeholder={placeholder}
146143
readOnly={readOnly || disabled}
147144
name={computedName}
148-
size="small"
149145
label={label}
150-
fullWidth
151146
multiline={type === 'multiline'}
152147
description={description}
153148
clickToCopy={clickToCopy}
154-
autoComplete={schema.autoComplete}
155-
customStyle={parentType === 'multicol' ? { flex: 0.5 } : {}}
156149
/>
157150
)
158151
}

packages/frontend/src/components/MultiCol.tsx/index.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import type { IField } from '@plumber/types'
1+
import type { IFieldMultiRowMultiColSubField } from '@plumber/types'
22

33
import { BiTrash } from 'react-icons/bi'
4-
import { Flex } from '@chakra-ui/react'
4+
import { Flex, useBreakpointValue } from '@chakra-ui/react'
55
import { IconButton } from '@opengovsg/design-system-react'
66

77
import InputCreator from '@/components/InputCreator'
88

99
type MultiColProps = {
1010
name: string
11-
subFields: IField[]
11+
subFields: IFieldMultiRowMultiColSubField[]
1212
canRemoveRow?: boolean
1313
isEditorReadOnly?: boolean
1414
remove?: (index?: number | number[]) => void
@@ -25,17 +25,23 @@ export default function MultiCol(props: MultiColProps) {
2525
index,
2626
...forwardedInputCreatorProps
2727
} = props
28+
29+
const isMobile = useBreakpointValue({ base: true, sm: false })
2830
return (
29-
<Flex flexDir="row" gap={2}>
31+
<Flex flexDir={isMobile ? 'column' : 'row'} gap={2}>
3032
{subFields.map((subF) => {
3133
return (
32-
<InputCreator
34+
<div
3335
key={`${name}.${subF.key}`}
34-
schema={subF}
35-
namePrefix={name}
36-
parentType="multicol"
37-
{...forwardedInputCreatorProps}
38-
/>
36+
style={isMobile ? { flex: 1 } : subF.customStyle}
37+
>
38+
<InputCreator
39+
schema={subF}
40+
namePrefix={name}
41+
parentType="multicol"
42+
{...forwardedInputCreatorProps}
43+
/>
44+
</div>
3945
)
4046
})}
4147
{canRemoveRow && (

packages/frontend/src/components/MultiRow/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ function MultiRow(props: MultiRowProps): JSX.Element {
108108
isEditorReadOnly={isEditorReadOnly}
109109
remove={remove}
110110
index={index}
111+
{...forwardedInputCreatorProps}
111112
/>
112113
{/*
113114
* "And" divider

packages/frontend/src/components/RichTextEditor/RichTextEditor.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@
203203
height: 100%;
204204
justify-content: center;
205205

206+
&:focus-within {
207+
border-color: var(--chakra-colors-primary-500);
208+
box-shadow: 0 0 0 1px var(--chakra-colors-primary-500);
209+
}
210+
206211
.tiptap p.is-editor-empty:first-child::before {
207212
color: #adb5bd;
208213
content: attr(data-placeholder);

packages/frontend/src/components/RichTextEditor/index.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ interface RichTextEditorProps {
260260
description?: string
261261
disabled?: boolean
262262
placeholder?: string
263-
customStyle?: React.CSSProperties
264263
variablesEnabled?: boolean
265264
isRich?: boolean
266265
isSingleLine?: boolean
@@ -273,15 +272,14 @@ const RichTextEditor = ({
273272
description,
274273
disabled,
275274
placeholder,
276-
customStyle,
277275
variablesEnabled,
278276
isRich,
279277
isSingleLine,
280278
}: RichTextEditorProps) => {
281279
const { control } = useFormContext()
282280

283281
return (
284-
<FormControl flex={1} style={customStyle} data-test="text-input-group">
282+
<FormControl flex={1} data-test="text-input-group">
285283
{label && (
286284
<FormLabel
287285
isRequired={required}

packages/frontend/src/components/SingleSelect/SingleSelectProvider.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export interface SingleSelectProviderProps<
6161
onSelected: (value: string) => void
6262
isCreating: boolean
6363
}
64+
isSearchable?: boolean
6465
}
6566

6667
function constructFreeSoloItem(freeSoloValue: string) {
@@ -371,6 +372,7 @@ export const SingleSelectProvider = ({
371372
return (
372373
<SelectContext.Provider
373374
value={{
375+
isSearchable,
374376
size,
375377
isOpen,
376378
selectedItem,
@@ -387,7 +389,6 @@ export const SingleSelectProvider = ({
387389
items: filteredItems,
388390
nothingFoundLabel,
389391
inputValue,
390-
isSearchable,
391392
isClearable,
392393
isInvalid,
393394
isDisabled,

0 commit comments

Comments
 (0)