From 7690eec5457f26dea15b998d22022696c1e3b0b9 Mon Sep 17 00:00:00 2001 From: Jack Ord Date: Thu, 2 Nov 2023 10:31:06 +0000 Subject: [PATCH 1/8] Cap suggestion count and debounce input --- package-lock.json | 6 ++++-- .../src/context/experiment/experiment-reducers.ts | 7 +++++-- packages/ui/package.json | 1 + .../result-data/experimentation-guide.tsx | 14 ++++++++++---- .../src/features/result-data/next-experiments.tsx | 12 ++++++++---- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3a5ec7e..bf2ceaf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12709,7 +12709,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 +12862,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": "^4.17.21", "react-hook-form": "^7.33.0", "remeda": "^1.12.0", "tss-react": "^4.8.2" @@ -13563,6 +13564,7 @@ "@types/uuid": "^9.0.0", "@vitejs/plugin-react": "^3.1.0", "jsdom": "^21.1.0", + "lodash": "^4.17.21", "node-mocks-http": "^1.12.1", "react-devtools": "^4.27.1", "react-hook-form": "^7.33.0", diff --git a/packages/core/src/context/experiment/experiment-reducers.ts b/packages/core/src/context/experiment/experiment-reducers.ts index f9a9a287..ace17aa7 100644 --- a/packages/core/src/context/experiment/experiment-reducers.ts +++ b/packages/core/src/context/experiment/experiment-reducers.ts @@ -182,9 +182,12 @@ 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) + const actualVal = payloadVal <= 10 ? payloadVal : 10 + state.extras.experimentSuggestionCount = actualVal >= 1 ? actualVal : 1 break + } case 'copySuggestedToDataPoints': { const nextValues = selectNextValues(state) const variables = selectActiveVariablesFromExperiment(state) diff --git a/packages/ui/package.json b/packages/ui/package.json index d8449d4e..84a90fac 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": "^4.17.21", "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 20060411..0b86cd04 100644 --- a/packages/ui/src/containers/result-data/experimentation-guide.tsx +++ b/packages/ui/src/containers/result-data/experimentation-guide.tsx @@ -28,6 +28,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 @@ -110,6 +111,14 @@ export const ExperimentationGuide = (props: ResultDataProps) => { ) : ( Please run optimizer ) + + const debouncedUpdate = _.debounce(suggestionCount => { + dispatchExperiment({ + type: 'updateSuggestionCount', + payload: suggestionCount, + }) + }, 500) + return ( { - 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..fed79e49 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, @@ -13,6 +13,7 @@ type Props = { export const NextExperiments: FC = ({ onSuggestionChange }) => { const isSuggestionCountEditable = useSelector(selectIsSuggestionCountEditable) const suggestionCount = useSelector(selectCalculatedSuggestionCount) + const [suggestionCountUI, setSuggestionCountUI] = useState(suggestionCount) const handleSuggestionChange = ( e: ChangeEvent @@ -29,11 +30,14 @@ export const NextExperiments: FC = ({ onSuggestionChange }) => { > { + setSuggestionCountUI(Number(val.target.value)) + handleSuggestionChange(val) + }} disabled={!isSuggestionCountEditable} /> From 9a4cdedd412460258132a1622481f2a3dcde7ebd Mon Sep 17 00:00:00 2001 From: Jack Ord Date: Thu, 2 Nov 2023 10:31:53 +0000 Subject: [PATCH 2/8] Add changeset --- .changeset/swift-starfishes-learn.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/swift-starfishes-learn.md 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 From 4ff8b762302d28e0330ca26c99792787038a0dd0 Mon Sep 17 00:00:00 2001 From: Jack Ord Date: Thu, 2 Nov 2023 10:36:18 +0000 Subject: [PATCH 3/8] Increase debounce delay --- .../ui/src/containers/result-data/experimentation-guide.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/containers/result-data/experimentation-guide.tsx b/packages/ui/src/containers/result-data/experimentation-guide.tsx index 0b86cd04..090cb3dc 100644 --- a/packages/ui/src/containers/result-data/experimentation-guide.tsx +++ b/packages/ui/src/containers/result-data/experimentation-guide.tsx @@ -117,7 +117,7 @@ export const ExperimentationGuide = (props: ResultDataProps) => { type: 'updateSuggestionCount', payload: suggestionCount, }) - }, 500) + }, 1000) return ( Date: Fri, 3 Nov 2023 12:45:26 +0000 Subject: [PATCH 4/8] Fix test --- packages/core/src/context/experiment/reducers.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/context/experiment/reducers.test.ts b/packages/core/src/context/experiment/reducers.test.ts index 1ce136d1..1dd002ed 100644 --- a/packages/core/src/context/experiment/reducers.test.ts +++ b/packages/core/src/context/experiment/reducers.test.ts @@ -197,13 +197,13 @@ describe('experiment reducer', () => { }) describe('updateSuggestionCount', () => { - it('should change suggestion count', () => { + it('should change suggestion count (min 1, max 10)', () => { const actual = rootReducer(initState, { type: 'updateSuggestionCount', payload: '42', }) expect(actual.experiment.extras).toMatchObject({ - experimentSuggestionCount: 42, + experimentSuggestionCount: 10, }) expect(actual.experiment.changedSinceLastEvaluation).toBeTruthy() }) From 98a0d4c8c27fe1d36c81a4bcf30a381b4ecbe357 Mon Sep 17 00:00:00 2001 From: Jack Ord Date: Wed, 8 Nov 2023 15:17:40 +0000 Subject: [PATCH 5/8] Move maxSuggestionCount to UI prop --- package-lock.json | 14 +++++++++-- .../context/experiment/experiment-reducers.ts | 14 ++++++++--- .../src/context/experiment/reducers.test.ts | 24 +++++++++++++++++-- .../core/src/context/experiment/test-utils.ts | 4 +++- packages/ui/package.json | 2 +- .../result-data/experimentation-guide.tsx | 3 +++ .../features/result-data/next-experiments.tsx | 10 ++++++-- 7 files changed, 60 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf2ceaf8..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, @@ -12867,7 +12872,7 @@ "dependencies": { "@boostv/process-optimizer-frontend-core": "*", "@boostv/process-optimizer-frontend-plots": "*", - "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", "react-hook-form": "^7.33.0", "remeda": "^1.12.0", "tss-react": "^4.8.2" @@ -13564,7 +13569,7 @@ "@types/uuid": "^9.0.0", "@vitejs/plugin-react": "^3.1.0", "jsdom": "^21.1.0", - "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", "node-mocks-http": "^1.12.1", "react-devtools": "^4.27.1", "react-hook-form": "^7.33.0", @@ -18567,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 ace17aa7..08a5c3fb 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' @@ -183,8 +186,13 @@ export const experimentReducer = produce( experimentSchema.shape.info.shape.description.parse(action.payload) break case 'updateSuggestionCount': { - const payloadVal = Number(action.payload) - const actualVal = payloadVal <= 10 ? payloadVal : 10 + const payloadVal = Number(action.payload.suggestionCount) + const maxSuggestionCount = action.payload.maxSuggestionCount + let actualVal = payloadVal + if (maxSuggestionCount !== undefined) { + actualVal = + payloadVal <= maxSuggestionCount ? payloadVal : maxSuggestionCount + } state.extras.experimentSuggestionCount = actualVal >= 1 ? actualVal : 1 break } diff --git a/packages/core/src/context/experiment/reducers.test.ts b/packages/core/src/context/experiment/reducers.test.ts index 1dd002ed..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 (min 1, max 10)', () => { + 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 84a90fac..6b2894dc 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -37,7 +37,7 @@ "dependencies": { "@boostv/process-optimizer-frontend-core": "*", "@boostv/process-optimizer-frontend-plots": "*", - "lodash": "^4.17.21", + "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 090cb3dc..9437a5b3 100644 --- a/packages/ui/src/containers/result-data/experimentation-guide.tsx +++ b/packages/ui/src/containers/result-data/experimentation-guide.tsx @@ -39,6 +39,7 @@ interface ResultDataProps { warning?: string padding?: number allowIndividualSuggestionCopy?: boolean + maxSuggestionCount?: number toggleUISize?: () => void onMouseEnterExpand?: () => void onMouseLeaveExpand?: () => void @@ -54,6 +55,7 @@ export const ExperimentationGuide = (props: ResultDataProps) => { padding, loadingMode, allowIndividualSuggestionCopy = true, + maxSuggestionCount, toggleUISize, onMouseEnterExpand, onMouseLeaveExpand, @@ -181,6 +183,7 @@ export const ExperimentationGuide = (props: ResultDataProps) => { {!isInitializing && ( 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 fed79e49..7246eee4 100644 --- a/packages/ui/src/features/result-data/next-experiments.tsx +++ b/packages/ui/src/features/result-data/next-experiments.tsx @@ -7,10 +7,14 @@ 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) @@ -32,7 +36,9 @@ export const NextExperiments: FC = ({ onSuggestionChange }) => { type="number" value={suggestionCountUI + ''} name="numberOfSuggestions" - label="Suggestions (1-10)" + label={`Suggestions${ + maxSuggestionCount !== undefined ? ` (1-${maxSuggestionCount})` : '' + }`} size="small" onChange={val => { setSuggestionCountUI(Number(val.target.value)) From 724c9a8d2ef3b1635ae6a91f3d1c81906358ea8c Mon Sep 17 00:00:00 2001 From: Jack Ord Date: Thu, 9 Nov 2023 08:21:01 +0000 Subject: [PATCH 6/8] Add maxSuggestionCount to reducer call --- .../ui/src/containers/result-data/experimentation-guide.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/containers/result-data/experimentation-guide.tsx b/packages/ui/src/containers/result-data/experimentation-guide.tsx index 9437a5b3..a0341c9e 100644 --- a/packages/ui/src/containers/result-data/experimentation-guide.tsx +++ b/packages/ui/src/containers/result-data/experimentation-guide.tsx @@ -117,7 +117,7 @@ export const ExperimentationGuide = (props: ResultDataProps) => { const debouncedUpdate = _.debounce(suggestionCount => { dispatchExperiment({ type: 'updateSuggestionCount', - payload: suggestionCount, + payload: { suggestionCount, maxSuggestionCount }, }) }, 1000) From 367b4d1f006505b3c87e6add50c5611726592ac3 Mon Sep 17 00:00:00 2001 From: Jack Ord <36296721+j-or@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:14:21 +0100 Subject: [PATCH 7/8] Update packages/core/src/context/experiment/experiment-reducers.ts Refactor suggestion count logic Co-authored-by: Jakob Langdal --- .../src/context/experiment/experiment-reducers.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/core/src/context/experiment/experiment-reducers.ts b/packages/core/src/context/experiment/experiment-reducers.ts index 08a5c3fb..755b59a1 100644 --- a/packages/core/src/context/experiment/experiment-reducers.ts +++ b/packages/core/src/context/experiment/experiment-reducers.ts @@ -187,13 +187,12 @@ export const experimentReducer = produce( break case 'updateSuggestionCount': { const payloadVal = Number(action.payload.suggestionCount) - const maxSuggestionCount = action.payload.maxSuggestionCount - let actualVal = payloadVal - if (maxSuggestionCount !== undefined) { - actualVal = - payloadVal <= maxSuggestionCount ? payloadVal : maxSuggestionCount - } - state.extras.experimentSuggestionCount = actualVal >= 1 ? actualVal : 1 + const maxSuggestionCount = + action.payload.maxSuggestionCount ?? Number.MAX_VALUE + state.extras.experimentSuggestionCount = Math.max( + 1, + Math.min(maxSuggestionCount, payloadVal) + ) break } case 'copySuggestedToDataPoints': { From e5c91efbd9131d37974e945d07117346c660357b Mon Sep 17 00:00:00 2001 From: Jack Ord Date: Thu, 9 Nov 2023 09:15:46 +0000 Subject: [PATCH 8/8] Add todo about max --- packages/core/src/context/experiment/experiment-reducers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/context/experiment/experiment-reducers.ts b/packages/core/src/context/experiment/experiment-reducers.ts index 755b59a1..512388f7 100644 --- a/packages/core/src/context/experiment/experiment-reducers.ts +++ b/packages/core/src/context/experiment/experiment-reducers.ts @@ -187,6 +187,7 @@ export const experimentReducer = produce( break 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(