Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLU-309: [TILES-ATOMIC-INCREMENT-3] enhance multirow-multicol UI with custom styles and operators #819

Open
wants to merge 2 commits into
base: develop-v2
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ const action: IRawAction = {
type: 'string' as const,
required: true,
variables: false,
customStyle: { flex: 2 },
},
{
placeholder: 'Value',
key: 'value',
type: 'string' as const,
required: true,
variables: true,
customStyle: { flex: 3 },
},
],
},
Expand Down
23 changes: 22 additions & 1 deletion packages/backend/src/apps/tiles/actions/update-row/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const action: IRawAction = {
{
label: 'Row data',
key: 'rowData',
type: 'multirow' as const,
type: 'multirow-multicol' as const,
description:
'Enter the data to update the row with. Columns not specified will not be updated.',
required: true,
Expand Down Expand Up @@ -79,13 +79,34 @@ const action: IRawAction = {
},
],
},
customStyle: { flex: 2 },
},
{
key: 'operator' as const,
type: 'dropdown' as const,
isSearchable: false,
required: true,
variables: false,
showOptionValue: false,
value: 'set',
options: [
{ label: '=', value: 'set', description: 'Set as' },
{ label: '+', value: 'add', description: 'Add by (numbers only)' },
{
label: '-',
value: 'subtract',
description: 'Subtract by (numbers only)',
},
],
customStyle: { flexBasis: '71px' },
},
{
placeholder: 'Value',
key: 'cellValue',
type: 'string' as const,
required: false,
variables: true,
customStyle: { flex: 3 },
},
],
},
Expand Down
2 changes: 2 additions & 0 deletions packages/backend/src/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,10 @@ type ActionSubstepArgument {
variables: Boolean
variableTypes: [String]
allowArbitrary: Boolean
isSearchable: Boolean
placeholder: String
showOptionValue: Boolean
customStyle: JSONObject
options: [ArgumentOption]
value: JSONObject
source: ActionSubstepArgumentSource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface ControlledAutocompleteProps {
required?: boolean
placeholder?: string
addNewOption?: IFieldDropdown['addNewOption']
isSearchable?: boolean
}

const formComboboxOptions = (
Expand Down Expand Up @@ -62,6 +63,7 @@ function ControlledAutocomplete(
required,
placeholder,
addNewOption,
isSearchable,
} = props

const items = useMemo(
Expand Down Expand Up @@ -92,6 +94,7 @@ function ControlledAutocomplete(
name,
control,
rules: { required },
// fixme: this default value is not working as expected
defaultValue: defaultValue ?? '',
})

Expand Down Expand Up @@ -146,21 +149,22 @@ function ControlledAutocomplete(
)}
{/* Dropdown row option content */}
<Flex>
<Box flexGrow={1}>
<Box flex={1}>
<SingleSelect
name="choose-dropdown-option"
colorScheme="secondary"
isClearable={!required}
items={items}
onChange={fieldOnChange}
value={fieldValue}
value={fieldValue ?? defaultValue}
placeholder={placeholder}
ref={ref}
data-test={`${name}-autocomplete`}
onRefresh={onRefresh}
isRefreshLoading={loading}
freeSolo={freeSolo}
isReadOnly={isCreatingNewOption}
isSearchable={isSearchable}
addNew={
addNewOption
? {
Expand Down
5 changes: 1 addition & 4 deletions packages/frontend/src/components/InputCreator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default function InputCreator(props: InputCreatorProps): JSX.Element {
const preparedOptions = schema.options || optionGenerator(data)
return (
<ControlledAutocomplete
isSearchable={schema.isSearchable ?? true}
name={computedName}
required={required}
freeSolo={schema.allowArbitrary}
Expand Down Expand Up @@ -130,9 +131,6 @@ export default function InputCreator(props: InputCreatorProps): JSX.Element {
disabled={disabled}
placeholder={placeholder}
isSingleLine={parentType === 'multicol'}
customStyle={
parentType === 'multicol' ? { flex: 1, minWidth: 0 } : {}
}
variablesEnabled
/>
)
Expand All @@ -152,7 +150,6 @@ export default function InputCreator(props: InputCreatorProps): JSX.Element {
description={description}
clickToCopy={clickToCopy}
autoComplete={schema.autoComplete}
customStyle={parentType === 'multicol' ? { flex: 0.5 } : {}}
/>
)
}
Expand Down
26 changes: 16 additions & 10 deletions packages/frontend/src/components/MultiCol.tsx/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { IField } from '@plumber/types'
import type { IFieldMultiRowMultiColSubField } from '@plumber/types'

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

import InputCreator from '@/components/InputCreator'

type MultiColProps = {
name: string
subFields: IField[]
subFields: IFieldMultiRowMultiColSubField[]
canRemoveRow?: boolean
isEditorReadOnly?: boolean
remove?: (index?: number | number[]) => void
Expand All @@ -25,17 +25,23 @@ export default function MultiCol(props: MultiColProps) {
index,
...forwardedInputCreatorProps
} = props

const isMobile = useBreakpointValue({ base: true, sm: false })
return (
<Flex flexDir="row" gap={2}>
<Flex flexDir={isMobile ? 'column' : 'row'} gap={2}>
{subFields.map((subF) => {
return (
<InputCreator
<div
key={`${name}.${subF.key}`}
schema={subF}
namePrefix={name}
parentType="multicol"
{...forwardedInputCreatorProps}
/>
style={isMobile ? { flex: 1 } : subF.customStyle}
>
<InputCreator
schema={subF}
namePrefix={name}
parentType="multicol"
{...forwardedInputCreatorProps}
/>
</div>
)
})}
{canRemoveRow && (
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/src/components/MultiRow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function MultiRow(props: MultiRowProps): JSX.Element {
isEditorReadOnly={isEditorReadOnly}
remove={remove}
index={index}
{...forwardedInputCreatorProps}
/>
{/*
* "And" divider
Expand Down
4 changes: 1 addition & 3 deletions packages/frontend/src/components/RichTextEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ interface RichTextEditorProps {
description?: string
disabled?: boolean
placeholder?: string
customStyle?: React.CSSProperties
variablesEnabled?: boolean
isRich?: boolean
isSingleLine?: boolean
Expand All @@ -273,15 +272,14 @@ const RichTextEditor = ({
description,
disabled,
placeholder,
customStyle,
variablesEnabled,
isRich,
isSingleLine,
}: RichTextEditorProps) => {
const { control } = useFormContext()

return (
<FormControl flex={1} style={customStyle} data-test="text-input-group">
<FormControl flex={1} data-test="text-input-group">
{label && (
<FormLabel
isRequired={required}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface SingleSelectProviderProps<
onSelected: (value: string) => void
isCreating: boolean
}
isSearchable?: boolean
}

function constructFreeSoloItem(freeSoloValue: string) {
Expand Down Expand Up @@ -371,6 +372,7 @@ export const SingleSelectProvider = ({
return (
<SelectContext.Provider
value={{
isSearchable,
size,
isOpen,
selectedItem,
Expand All @@ -387,7 +389,6 @@ export const SingleSelectProvider = ({
items: filteredItems,
nothingFoundLabel,
inputValue,
isSearchable,
isClearable,
isInvalid,
isDisabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,18 @@ export const SelectCombobox = forwardRef<HTMLInputElement>(
<Text noOfLines={1}>{textToDisplay}</Text>
</Stack>
<Input
isReadOnly={!isSearchable || isReadOnly}
isInvalid={isInvalid}
isDisabled={isDisabled}
placeholder={textToDisplay ? '' : placeholder}
sx={styles.field}
sx={{
...styles.field,
cursor: isSearchable ? 'text' : 'pointer',
}}
{...getInputProps({
onClick: handleToggleMenu,
onBlur: () => !isOpen && resetInputValue(),
ref: mergedInputRef,
disabled: isDisabled,
readOnly: isReadOnly,
readOnly: !isSearchable || isReadOnly,
required: isRequired,
'aria-expanded': !!isOpen,
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const SelectMenu = (): JSX.Element => {
{ suppressRefError: true },
)}
style={floatingStyles}
sx={styles.list}
sx={{ ...styles.list, minWidth: '230px' }}
zIndex="dropdown"
>
{isOpen && items.length > 0 && (
Expand Down
4 changes: 1 addition & 3 deletions packages/frontend/src/components/TextField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ type TextFieldProps = {
clickToCopy?: boolean
readOnly?: boolean
description?: string
customStyle?: React.CSSProperties
} & MuiTextFieldProps

const createCopyAdornment = (
Expand Down Expand Up @@ -51,7 +50,6 @@ export default function TextField(props: TextFieldProps): React.ReactElement {
readOnly,
onBlur,
onChange,
customStyle,
...textFieldProps
} = props

Expand All @@ -70,7 +68,7 @@ export default function TextField(props: TextFieldProps): React.ReactElement {
...field
},
}) => (
<FormControl style={customStyle}>
<FormControl>
{label && (
<FormLabel
isRequired={required}
Expand Down
5 changes: 5 additions & 0 deletions packages/frontend/src/graphql/queries/get-apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ export const GET_APPS = gql`
variables
variableTypes
allowArbitrary
isSearchable
addRowButtonText
showOptionValue
customStyle
value
options {
label
Expand Down Expand Up @@ -225,7 +227,10 @@ export const GET_APPS = gql`
variables
variableTypes
allowArbitrary
isSearchable
showOptionValue
customStyle
value
hiddenIf {
fieldKey
fieldValue
Expand Down
8 changes: 6 additions & 2 deletions packages/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ export interface IFieldDropdown extends IBaseField {
type: 'dropdown'
showOptionValue?: boolean
allowArbitrary?: boolean
isSearchable?: boolean
addNewOption?: {
id: DropdownAddNewId // identifier when add new option is selected
type: DropdownAddNewType
Expand Down Expand Up @@ -351,12 +352,15 @@ export interface IFieldMultiSelect extends IBaseField {
variableTypes?: TDataOutMetadatumType[]
}

type IFieldMultiRowMultiColSubField = IField & {
customStyle?: Record<string, string | number>
}

export interface IFieldMultiRowMultiCol extends IBaseField {
type: 'multirow-multicol'
value?: string
addRowButtonText?: string

subFields: IField[]
subFields: IFieldMultiRowMultiColSubField[]
}

export interface IFieldMultiRow extends IBaseField {
Expand Down
Loading