diff --git a/.changeset/swift-starfishes-learn.md b/.changeset/swift-starfishes-learn.md
new file mode 100644
index 00000000..7341dca5
--- /dev/null
+++ b/.changeset/swift-starfishes-learn.md
@@ -0,0 +1,6 @@
+---
+'@boostv/process-optimizer-frontend-core': minor
+'@boostv/process-optimizer-frontend-ui': minor
+---
+
+Cap suggestion count
diff --git a/package-lock.json b/package-lock.json
index c3a5ec7e..890903e9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8396,6 +8396,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
+ },
"node_modules/lodash.get": {
"version": "4.4.2",
"dev": true,
@@ -12709,7 +12714,7 @@
},
"packages/core": {
"name": "@boostv/process-optimizer-frontend-core",
- "version": "2.9.0",
+ "version": "2.9.2",
"license": "BSD-3-Clause",
"dependencies": {
"@boostv/process-optimizer-frontend-api": "*",
@@ -12862,11 +12867,12 @@
},
"packages/ui": {
"name": "@boostv/process-optimizer-frontend-ui",
- "version": "2.8.0",
+ "version": "2.9.0",
"license": "BSD-3-Clause",
"dependencies": {
"@boostv/process-optimizer-frontend-core": "*",
"@boostv/process-optimizer-frontend-plots": "*",
+ "lodash.debounce": "^4.0.8",
"react-hook-form": "^7.33.0",
"remeda": "^1.12.0",
"tss-react": "^4.8.2"
@@ -13563,6 +13569,7 @@
"@types/uuid": "^9.0.0",
"@vitejs/plugin-react": "^3.1.0",
"jsdom": "^21.1.0",
+ "lodash.debounce": "^4.0.8",
"node-mocks-http": "^1.12.1",
"react-devtools": "^4.27.1",
"react-hook-form": "^7.33.0",
@@ -18565,6 +18572,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
+ },
"lodash.get": {
"version": "4.4.2",
"dev": true
diff --git a/packages/core/src/context/experiment/experiment-reducers.ts b/packages/core/src/context/experiment/experiment-reducers.ts
index f9a9a287..512388f7 100644
--- a/packages/core/src/context/experiment/experiment-reducers.ts
+++ b/packages/core/src/context/experiment/experiment-reducers.ts
@@ -140,7 +140,10 @@ export type ExperimentAction =
}
| {
type: 'updateSuggestionCount'
- payload: string
+ payload: {
+ suggestionCount: string
+ maxSuggestionCount?: number
+ }
}
| {
type: 'copySuggestedToDataPoints'
@@ -182,9 +185,17 @@ export const experimentReducer = produce(
state.info.description =
experimentSchema.shape.info.shape.description.parse(action.payload)
break
- case 'updateSuggestionCount':
- state.extras.experimentSuggestionCount = Number(action.payload)
+ case 'updateSuggestionCount': {
+ const payloadVal = Number(action.payload.suggestionCount)
+ // TODO: Move max out of reducer if used in application settings
+ const maxSuggestionCount =
+ action.payload.maxSuggestionCount ?? Number.MAX_VALUE
+ state.extras.experimentSuggestionCount = Math.max(
+ 1,
+ Math.min(maxSuggestionCount, payloadVal)
+ )
break
+ }
case 'copySuggestedToDataPoints': {
const nextValues = selectNextValues(state)
const variables = selectActiveVariablesFromExperiment(state)
diff --git a/packages/core/src/context/experiment/reducers.test.ts b/packages/core/src/context/experiment/reducers.test.ts
index 1ce136d1..bd04a546 100644
--- a/packages/core/src/context/experiment/reducers.test.ts
+++ b/packages/core/src/context/experiment/reducers.test.ts
@@ -197,16 +197,36 @@ describe('experiment reducer', () => {
})
describe('updateSuggestionCount', () => {
- it('should change suggestion count', () => {
+ it('should cap suggestion count to max', () => {
const actual = rootReducer(initState, {
type: 'updateSuggestionCount',
- payload: '42',
+ payload: { suggestionCount: '42', maxSuggestionCount: 10 },
+ })
+ expect(actual.experiment.extras).toMatchObject({
+ experimentSuggestionCount: 10,
+ })
+ expect(actual.experiment.changedSinceLastEvaluation).toBeTruthy()
+ })
+ it('should not cap suggestion count to max when unset', () => {
+ const actual = rootReducer(initState, {
+ type: 'updateSuggestionCount',
+ payload: { suggestionCount: '42' },
})
expect(actual.experiment.extras).toMatchObject({
experimentSuggestionCount: 42,
})
expect(actual.experiment.changedSinceLastEvaluation).toBeTruthy()
})
+ it('should set suggestion count to min 1', () => {
+ const actual = rootReducer(initState, {
+ type: 'updateSuggestionCount',
+ payload: { suggestionCount: '0' },
+ })
+ expect(actual.experiment.extras).toMatchObject({
+ experimentSuggestionCount: 1,
+ })
+ expect(actual.experiment.changedSinceLastEvaluation).toBeTruthy()
+ })
})
describe('Constraints', () => {
diff --git a/packages/core/src/context/experiment/test-utils.ts b/packages/core/src/context/experiment/test-utils.ts
index f425f260..b2733af7 100644
--- a/packages/core/src/context/experiment/test-utils.ts
+++ b/packages/core/src/context/experiment/test-utils.ts
@@ -124,7 +124,9 @@ export const dummyPayloads: Payloads = {
updateExperimentDescription: '',
updateConfiguration: initialState.experiment.optimizerConfig,
updateDataPoints: initialState.experiment.dataPoints,
- updateSuggestionCount: '',
+ updateSuggestionCount: {
+ suggestionCount: '',
+ },
copySuggestedToDataPoints: [],
'experiment/toggleMultiObjective': undefined,
'experiment/setConstraintSum': 0,
diff --git a/packages/ui/package.json b/packages/ui/package.json
index d8449d4e..6b2894dc 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -37,6 +37,7 @@
"dependencies": {
"@boostv/process-optimizer-frontend-core": "*",
"@boostv/process-optimizer-frontend-plots": "*",
+ "lodash.debounce": "^4.0.8",
"react-hook-form": "^7.33.0",
"remeda": "^1.12.0",
"tss-react": "^4.8.2"
diff --git a/packages/ui/src/containers/result-data/experimentation-guide.tsx b/packages/ui/src/containers/result-data/experimentation-guide.tsx
index ddf57d2a..dca4f1ca 100644
--- a/packages/ui/src/containers/result-data/experimentation-guide.tsx
+++ b/packages/ui/src/containers/result-data/experimentation-guide.tsx
@@ -29,6 +29,7 @@ import { ReactNode } from 'react'
import { experimentResultSchema } from '@boostv/process-optimizer-frontend-core'
import { z } from 'zod'
import { isArray } from 'remeda'
+import _ from 'lodash'
interface ResultDataProps {
id?: string
@@ -39,6 +40,7 @@ interface ResultDataProps {
warning?: string
padding?: number
allowIndividualSuggestionCopy?: boolean
+ maxSuggestionCount?: number
toggleUISize?: () => void
onMouseEnterExpand?: () => void
onMouseLeaveExpand?: () => void
@@ -54,6 +56,7 @@ export const ExperimentationGuide = (props: ResultDataProps) => {
padding,
loadingMode,
allowIndividualSuggestionCopy = true,
+ maxSuggestionCount,
toggleUISize,
onMouseEnterExpand,
onMouseLeaveExpand,
@@ -112,6 +115,14 @@ export const ExperimentationGuide = (props: ResultDataProps) => {
) : (
Please run optimizer
)
+
+ const debouncedUpdate = _.debounce(suggestionCount => {
+ dispatchExperiment({
+ type: 'updateSuggestionCount',
+ payload: { suggestionCount, maxSuggestionCount },
+ })
+ }, 1000)
+
return (
{
{!isInitializing && (
- dispatchExperiment({
- type: 'updateSuggestionCount',
- payload: suggestionCount,
- })
+ debouncedUpdate(suggestionCount)
}
/>
diff --git a/packages/ui/src/features/result-data/next-experiments.tsx b/packages/ui/src/features/result-data/next-experiments.tsx
index 8a9b191a..7246eee4 100644
--- a/packages/ui/src/features/result-data/next-experiments.tsx
+++ b/packages/ui/src/features/result-data/next-experiments.tsx
@@ -1,5 +1,5 @@
import { TextField, Tooltip } from '@mui/material'
-import { ChangeEvent, FC } from 'react'
+import { ChangeEvent, FC, useState } from 'react'
import {
selectIsSuggestionCountEditable,
selectCalculatedSuggestionCount,
@@ -7,12 +7,17 @@ import {
} from '@boostv/process-optimizer-frontend-core'
type Props = {
+ maxSuggestionCount?: number
onSuggestionChange: (suggestionCount: string) => void
}
-export const NextExperiments: FC = ({ onSuggestionChange }) => {
+export const NextExperiments: FC = ({
+ onSuggestionChange,
+ maxSuggestionCount,
+}) => {
const isSuggestionCountEditable = useSelector(selectIsSuggestionCountEditable)
const suggestionCount = useSelector(selectCalculatedSuggestionCount)
+ const [suggestionCountUI, setSuggestionCountUI] = useState(suggestionCount)
const handleSuggestionChange = (
e: ChangeEvent
@@ -29,11 +34,16 @@ export const NextExperiments: FC = ({ onSuggestionChange }) => {
>
{
+ setSuggestionCountUI(Number(val.target.value))
+ handleSuggestionChange(val)
+ }}
disabled={!isSuggestionCountEditable}
/>