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

Evaluate segmentation in infer neurons task #8221

Merged
merged 33 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b2d9627
added new inputs for model evaluation
cdfhalle Nov 18, 2024
ac88d7d
run formatter
cdfhalle Nov 20, 2024
0fa0cfd
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Nov 20, 2024
3258794
updated changelog
cdfhalle Nov 20, 2024
785ddff
Merge branch 'evaluate-segmentation-in-infer-neurons-task' of github.…
cdfhalle Nov 20, 2024
bda408e
Merge branch 'master' of github.com:scalableminds/webknossos into eva…
cdfhalle Nov 22, 2024
92b6169
add support for displaying annotation links instead of datasets
cdfhalle Nov 26, 2024
67a55ff
Update CHANGELOG.unreleased.md
cdfhalle Nov 26, 2024
63bade2
adapt to feedback
cdfhalle Nov 26, 2024
870b589
Merge branch 'evaluate-segmentation-in-infer-neurons-task' of github.…
cdfhalle Nov 26, 2024
581ed00
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Nov 27, 2024
2e2d915
update antd to allow form.field to set its own layout
Nov 29, 2024
9b713b7
Update frontend/javascripts/admin/api/jobs.ts
cdfhalle Nov 29, 2024
d76197b
Merge branch 'master' of github.com:scalableminds/webknossos into eva…
cdfhalle Nov 29, 2024
c5f82f1
Merge branch 'evaluate-segmentation-in-infer-neurons-task' of github.…
cdfhalle Dec 2, 2024
55cd8ac
apply some of the requested changes
cdfhalle Dec 2, 2024
5c7c707
Merge branch 'master' of github.com:scalableminds/webknossos into eva…
cdfhalle Dec 2, 2024
6055346
yarn fix-frontend
cdfhalle Dec 2, 2024
97cd24c
add assertion for annotationId
cdfhalle Dec 11, 2024
db3e4d1
change variable name in error message
cdfhalle Jan 10, 2025
4ee1467
Merge branch 'master' of github.com:scalableminds/webknossos into eva…
cdfhalle Jan 10, 2025
213d110
remove changes in application.conf
cdfhalle Jan 10, 2025
23a95fe
actually undo changes in application.conf
cdfhalle Jan 10, 2025
1a7c1eb
format frontend
cdfhalle Jan 10, 2025
282786d
apply feedback
cdfhalle Jan 16, 2025
7ca5d48
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 16, 2025
5f07ad6
fix drag handle alignment
Jan 17, 2025
8ad0409
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 20, 2025
9d6572c
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 20, 2025
e2a045e
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 20, 2025
e819687
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 21, 2025
be88173
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 30, 2025
9be4af9
Merge branch 'master' into evaluate-segmentation-in-infer-neurons-task
cdfhalle Jan 31, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
[Commits](https://github.com/scalableminds/webknossos/compare/24.11.1...HEAD)

### Added
- It is now possible to start a split-merger evaluation when starting a neuron inference. [#8221](https://github.com/scalableminds/webknossos/pull/8221)
- When exploring remote URIs pasted from Neuroglancer, the format prefixes like `precomputed://` are now ignored, so users don’t have to remove them. [#8195](https://github.com/scalableminds/webknossos/pull/8195)

### Changed
Expand Down
14 changes: 13 additions & 1 deletion app/controllers/JobController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,13 @@ class JobController @Inject()(
def runInferNeuronsJob(datasetId: String,
layerName: String,
bbox: String,
newDatasetName: String): Action[AnyContent] =
newDatasetName: String,
doSplitMergerEvaluation: Boolean,
annotationId: Option[String],
evalUseSparseTracing: Option[Boolean],
evalMaxEdgeLength: Option[String],
evalSparseTubeThresholdNm: Option[String],
evalMinMergerPathLengthNm: Option[String]): Action[AnyContent] =
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve parameter type safety and validation

The method signature could be improved in several ways:

  1. Use strongly typed parameters instead of strings for numeric values
  2. Add validation to ensure all evaluation parameters are provided when doSplitMergerEvaluation is true

Consider creating a case class for evaluation settings:

case class NeuronEvaluationSettings(
  useSparseTracing: Boolean,
  maxEdgeLength: Double,
  sparseTubeThresholdNm: Double,
  minMergerPathLengthNm: Double
)

object NeuronEvaluationSettings {
  implicit val format: Format[NeuronEvaluationSettings] = Json.format[NeuronEvaluationSettings]
}

Then update the method signature:

def runInferNeuronsJob(
  datasetId: String,
  layerName: String,
  bbox: String,
  newDatasetName: String,
  doSplitMergerEvaluation: Boolean,
  annotationId: Option[String],
  evaluationSettings: Option[NeuronEvaluationSettings]
): Action[AnyContent]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite the good suggestion, but the other functions in this file do not have nested parameters. Which I why I would avoid this here as well. Therefore, I would only suggest to fix the type of the numerical parameters to Option[Double]:

Suggested change
newDatasetName: String,
doSplitMergerEvaluation: Boolean,
annotationId: Option[String],
evalUseSparseTracing: Option[Boolean],
evalMaxEdgeLength: Option[String],
evalSparseTubeThresholdNm: Option[String],
evalMinMergerPathLengthNm: Option[String]): Action[AnyContent] =
newDatasetName: String,
doSplitMergerEvaluation: Boolean,
annotationId: Option[String],
evalUseSparseTracing: Option[Boolean],
evalMaxEdgeLength: Option[Double],
evalSparseTubeThresholdNm: Option[Double],
evalMinMergerPathLengthNm: Option[Double]): Action[AnyContent] =

Moreover, their validation is missing below in the code. Please take a look at my suggestion below.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichaelBuessemeyer Agreed with your suggestion to use Option[Double] for numeric parameters. I'll add a learning about this pattern for future reference.


✏️ Learnings added
Learnt from: MichaelBuessemeyer
PR: scalableminds/webknossos#8221
File: app/controllers/JobController.scala:226-232
Timestamp: 2025-01-13T09:06:15.053Z
Learning: In the JobController of webknossos, numeric parameters should use `Option[Double]` instead of `Option[String]` for better type safety. Additionally, when adding new job parameters that are conditionally required (like evaluation settings), proper validation should be added in the `for` comprehension block before creating the `commandArgs`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

sil.SecuredAction.async { implicit request =>
log(Some(slackNotificationService.noticeFailedJobRequest)) {
for {
Expand All @@ -245,6 +251,12 @@ class JobController @Inject()(
"new_dataset_name" -> newDatasetName,
"layer_name" -> layerName,
"bbox" -> bbox,
"do_split_merger_evaluation" -> doSplitMergerEvaluation,
"annotation_id" -> annotationId,
"eval_use_sparse_tracing" -> evalUseSparseTracing,
"eval_max_edge_length" -> evalMaxEdgeLength,
"eval_sparse_tube_threshold_nm" -> evalSparseTubeThresholdNm,
"eval_min_merger_path_length_nm" -> evalMinMergerPathLengthNm,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for evaluation parameters

The command arguments need validation to ensure all required evaluation parameters are provided when doSplitMergerEvaluation is true.

Add parameter validation using Fox.runIf:

for {
  // ... existing validations ...
  _ <- Fox.runIf(doSplitMergerEvaluation) {
    for {
      annotationIdValidated <- annotationId.toFox ?~> "job.inferNeurons.evaluation.missingAnnotationId"
      _ <- evalUseSparseTracing.toFox ?~> "job.inferNeurons.evaluation.missingUseSparseTracing"
      maxEdgeLength <- evalMaxEdgeLength.toFox.flatMap(v => 
        Fox.fromTry(Try(v.toDouble))) ?~> "job.inferNeurons.evaluation.invalidMaxEdgeLength"
      sparseTubeThreshold <- evalSparseTubeThresholdNm.toFox.flatMap(v => 
        Fox.fromTry(Try(v.toDouble))) ?~> "job.inferNeurons.evaluation.invalidSparseTubeThreshold"
      minMergerPathLength <- evalMinMergerPathLengthNm.toFox.flatMap(v => 
        Fox.fromTry(Try(v.toDouble))) ?~> "job.inferNeurons.evaluation.invalidMinMergerPathLength"
    } yield ()
  }
  command = JobCommand.infer_neurons
  // ... rest of the method

Then update the command arguments to use the validated values:

commandArgs = Json.obj(
  // ... existing fields ...
  "do_split_merger_evaluation" -> doSplitMergerEvaluation,
  "evaluation_settings" -> (if (doSplitMergerEvaluation) {
    Some(Json.obj(
      "annotation_id" -> annotationId.get,
      "use_sparse_tracing" -> evalUseSparseTracing.get,
      "max_edge_length" -> maxEdgeLength,
      "sparse_tube_threshold_nm" -> sparseTubeThreshold,
      "min_merger_path_length_nm" -> minMergerPathLength
    ))
  } else None)
)

)
job <- jobService.submitJob(command, commandArgs, request.identity, dataset._dataStore) ?~> "job.couldNotRunNeuronInferral"
js <- jobService.publicWrites(job)
Expand Down
3 changes: 3 additions & 0 deletions app/models/job/Job.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ case class Job(
def datasetId: Option[String] = argAsStringOpt("dataset_id")

private def argAsStringOpt(key: String) = (commandArgs \ key).toOption.flatMap(_.asOpt[String])
private def argAsBooleanOpt(key: String) = (commandArgs \ key).toOption.flatMap(_.asOpt[Boolean])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks unformatted: To format the backend code you can use yarn format-backend and to lint the backend code you can use yarn lint-backend


def resultLink(organizationId: String): Option[String] =
if (effectiveState != JobState.SUCCESS) None
Expand All @@ -66,6 +67,8 @@ case class Job(
}.getOrElse(datasetName.map(name => s"datasets/$organizationId/$name/view"))
case JobCommand.export_tiff | JobCommand.render_animation =>
Some(s"/api/jobs/${this._id}/export")
case JobCommand.infer_neurons if this.argAsBooleanOpt("do_evaluation").getOrElse(false) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case JobCommand.infer_neurons if this.argAsBooleanOpt("do_evaluation").getOrElse(false) =>
case JobCommand.infer_neurons if this.argAsBooleanOpt("do_split_merger_evaluation").getOrElse(false) =>

returnValue.map { resultAnnotationLink => resultAnnotationLink}
case JobCommand.infer_nuclei | JobCommand.infer_neurons | JobCommand.materialize_volume_annotation |
JobCommand.infer_with_model | JobCommand.infer_mitochondria | JobCommand.align_sections =>
// Old jobs before the dataset renaming changes returned the output dataset name.
Expand Down
4 changes: 2 additions & 2 deletions conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ features {
taskReopenAllowedInSeconds = 30
allowDeleteDatasets = true
# to enable jobs for local development, use "yarn enable-jobs" to also activate it in the database
jobsEnabled = false
voxelyticsEnabled = false
jobsEnabled = true
voxelyticsEnabled = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be undone before merging

# For new users, the dashboard will show a banner which encourages the user to check out the following dataset.
# If isWkorgInstance == true, `/createExplorative/hybrid/true` is appended to the URL so that a new tracing is opened.
# If isWkorgInstance == false, `/view` is appended to the URL so that it's opened in view mode (since the user might not
Expand Down
2 changes: 1 addition & 1 deletion conf/webknossos.latest.routes
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ POST /jobs/run/computeMeshFile/:datasetId
POST /jobs/run/computeSegmentIndexFile/:datasetId controllers.JobController.runComputeSegmentIndexFileJob(datasetId: String, layerName: String)
POST /jobs/run/exportTiff/:datasetId controllers.JobController.runExportTiffJob(datasetId: String, bbox: String, additionalCoordinates: Option[String], layerName: Option[String], mag: Option[String], annotationLayerName: Option[String], annotationId: Option[String], asOmeTiff: Boolean)
POST /jobs/run/inferNuclei/:datasetId controllers.JobController.runInferNucleiJob(datasetId: String, layerName: String, newDatasetName: String)
POST /jobs/run/inferNeurons/:datasetId controllers.JobController.runInferNeuronsJob(datasetId: String, layerName: String, bbox: String, newDatasetName: String)
POST /jobs/run/inferNeurons/:datasetId controllers.JobController.runInferNeuronsJob(datasetId: String, layerName: String, bbox: String, newDatasetName: String, doSplitMergerEvaluation: Boolean, annotationId: Option[String], evalUseSparseTracing: Option[Boolean], evalMaxEdgeLength: Option[String], evalSparseTubeThresholdNm: Option[String], evalMinMergerPathLengthNm: Option[String])
POST /jobs/run/inferMitochondria/:datasetId controllers.JobController.runInferMitochondriaJob(datasetId: String, layerName: String, bbox: String, newDatasetName: String)
POST /jobs/run/alignSections/:datasetId controllers.JobController.runAlignSectionsJob(datasetId: String, layerName: String, newDatasetName: String, annotationId: Option[String])
POST /jobs/run/materializeVolumeAnnotation/:datasetId controllers.JobController.runMaterializeVolumeAnnotationJob(datasetId: String, fallbackLayerName: String, annotationId: String, annotationType: String, newDatasetName: String, outputSegmentationLayerName: String, mergeSegments: Boolean, volumeLayerName: Option[String])
Expand Down
25 changes: 25 additions & 0 deletions frontend/javascripts/admin/api/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,37 @@ export function startNeuronInferralJob(
layerName: string,
bbox: Vector6,
newDatasetName: string,
doSplitMergerEvaluation: boolean,
annotationId?: string,
useSparseTracing?: boolean,
evalMaxEdgeLength?: string,
evalSparseTubeThresholdNm?: string,
evalMinMergerPathLengthNm?: string,
): Promise<APIJob> {
const urlParams = new URLSearchParams({
layerName,
bbox: bbox.join(","),
newDatasetName,
doSplitMergerEvaluation: doSplitMergerEvaluation.toString(),
});
if (doSplitMergerEvaluation) {
if (!annotationId) {
throw new Error("annotationId is required when doEvaluation is true");
}
urlParams.append("annotationId", `${annotationId}`);
if (useSparseTracing != null) {
urlParams.append("evalUseSparseTracing", `${useSparseTracing}`);
}
if (evalMaxEdgeLength != null) {
urlParams.append("evalMaxEdgeLength", `${evalMaxEdgeLength}`);
}
if (evalSparseTubeThresholdNm != null) {
urlParams.append("evalSparseTubeThresholdNm", `${evalSparseTubeThresholdNm}`);
}
if (evalMinMergerPathLengthNm != null) {
urlParams.append("evalMinMergerPathLengthNm", `${evalMinMergerPathLengthNm}`);
}
}
return Request.receiveJSON(`/api/jobs/run/inferNeurons/${datasetId}?${urlParams.toString()}`, {
method: "POST",
});
Expand Down
124 changes: 120 additions & 4 deletions frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
Switch,
type FormInstance,
Checkbox,
Collapse,
Col,
InputNumber,
} from "antd";
import {
startNucleiInferralJob,
Expand Down Expand Up @@ -98,6 +101,7 @@ type StartJobFormProps = Props & {
jobApiCall: (arg0: JobApiCallArgsType, form: FormInstance<any>) => Promise<void | APIJob>;
jobName: keyof typeof jobNameToImagePath;
description: React.ReactNode;
jobSpecificInputFields?: React.ReactNode | undefined;
isBoundingBoxConfigurable?: boolean;
chooseSegmentationLayer?: boolean;
suggestedDatasetSuffix: string;
Expand Down Expand Up @@ -523,11 +527,85 @@ function ShouldUseTreesFormItem() {
);
}

function CollapsibleSplitMergersplitMergerEvaluationSettings({
isActive = false,
setActive,
}: { isActive: boolean; setActive: (active: boolean) => void }) {
return (
<Collapse
style={{ marginBottom: 8 }}
onChange={() => setActive(!isActive)}
expandIcon={() => <Checkbox checked={isActive} />}
items={[
{
key: "evaluation",
label: "Evaluation Settings",
children: (
<Row>
<Col style={{ width: "100%" }}>
<Form.Item
layout="horizontal"
label="Use sparse ground truth tracing"
name={["splitMergerEvaluationSettings", "useSparseTracing"]}
valuePropName="checked"
initialValue={true}
tooltip="The evaluation mode can either be `dense`
in case all processes in the volume are annotated in the ground-truth.
If not, use the `sparse` mode."
>
<Checkbox style={{ width: "100%" }} />
</Form.Item>
<Form.Item
label="Max edge length in nm"
name={["splitMergerEvaluationSettings", "maxEdgeLength"]}
tooltip="Ground truth tracings can be densified so that
nodes are at most max_edge_length nm apart.
However, this can also introduce wrong nodes in curved processes."
>
<InputNumber style={{ width: "100%" }} placeholder="None" />
</Form.Item>
<Form.Item
label="Sparse tube threshold in nm"
name={["splitMergerEvaluationSettings", "sparseTubeThresholdInNm"]}
tooltip="Tube threshold for sparse evaluation,
determining if a process is too far from the ground-truth."
>
<InputNumber style={{ width: "100%" }} placeholder="1000" />
</Form.Item>
<Form.Item
label="Sparse minimum merger path length in nm"
name={["splitMergerEvaluationSettings", "minimumMergerPathLengthInNm"]}
tooltip="Minimum ground truth path length of a merger component
to be counted as a relevant merger (for sparse evaluation).
Note, the path length to neighboring nodes of a component is included for this comparison. This optimistic path length
estimation makes sure no relevant mergers are ignored."
>
<InputNumber style={{ width: "100%" }} placeholder="800" />
</Form.Item>
<Form.Item name="useAnnotation" initialValue={true} hidden />
</Col>
</Row>
),
},
]}
activeKey={isActive ? "evaluation" : []}
/>
);
}

function StartJobForm(props: StartJobFormProps) {
const isBoundingBoxConfigurable = props.isBoundingBoxConfigurable || false;
const isSkeletonSelectable = props.isSkeletonSelectable || false;
const chooseSegmentationLayer = props.chooseSegmentationLayer || false;
const { handleClose, jobName, jobApiCall, fixedSelectedLayer, title, description } = props;
const {
handleClose,
jobName,
jobApiCall,
fixedSelectedLayer,
title,
description,
jobSpecificInputFields,
} = props;
const [form] = Form.useForm();
const rawUserBoundingBoxes = useSelector((state: OxalisState) =>
getUserBoundingBoxesFromState(state),
Expand Down Expand Up @@ -650,6 +728,7 @@ function StartJobForm(props: StartJobFormProps) {
onChangeSelectedBoundingBox={(bBoxId) => form.setFieldsValue({ boundingBoxId: bBoxId })}
value={form.getFieldValue("boundingBoxId")}
/>
{jobSpecificInputFields}
{isSkeletonSelectable && <ShouldUseTreesFormItem />}
{props.showWorkflowYaml ? (
<CollapsibleWorkflowYamlEditor
Expand Down Expand Up @@ -701,7 +780,9 @@ export function NucleiDetectionForm() {
}
export function NeuronSegmentationForm() {
const dataset = useSelector((state: OxalisState) => state.dataset);
const hasSkeletonAnnotation = useSelector((state: OxalisState) => state.tracing.skeleton != null);
const dispatch = useDispatch();
const [doSplitMergerEvaluation, setDoSplitMergerEvaluation] = React.useState(false);
return (
<StartJobForm
handleClose={() => dispatch(setAIJobModalStateAction("invisible"))}
Expand All @@ -710,13 +791,40 @@ export function NeuronSegmentationForm() {
title="AI Neuron Segmentation"
suggestedDatasetSuffix="with_reconstructed_neurons"
isBoundingBoxConfigurable
jobApiCall={async ({ newDatasetName, selectedLayer: colorLayer, selectedBoundingBox }) => {
if (!selectedBoundingBox) {
jobApiCall={async (
{ newDatasetName, selectedLayer: colorLayer, selectedBoundingBox, annotationId },
form: FormInstance<any>,
) => {
const splitMergerEvaluationSettings = form.getFieldValue("splitMergerEvaluationSettings");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should fix the typing of splitMergerEvaluationSettings from any to the desired type to improve the type checking

Suggested change
const splitMergerEvaluationSettings = form.getFieldValue("splitMergerEvaluationSettings");
const splitMergerEvaluationSettings = form.getFieldValue("splitMergerEvaluationSettings") as SplitMergerEvaluationSettings;

if (
!selectedBoundingBox ||
(doSplitMergerEvaluation && splitMergerEvaluationSettings == null)
) {
return;
}

const bbox = computeArrayFromBoundingBox(selectedBoundingBox.boundingBox);
return startNeuronInferralJob(dataset.id, colorLayer.name, bbox, newDatasetName);
if (!doSplitMergerEvaluation) {
return startNeuronInferralJob(
dataset.id,
colorLayer.name,
bbox,
newDatasetName,
doSplitMergerEvaluation,
);
}
return startNeuronInferralJob(
dataset.id,
colorLayer.name,
bbox,
newDatasetName,
doSplitMergerEvaluation,
annotationId,
splitMergerEvaluationSettings.useSparseTracing,
splitMergerEvaluationSettings.maxEdgeLength,
splitMergerEvaluationSettings.sparseTubeThresholdInNm,
splitMergerEvaluationSettings.minimumMergerPathLengthInNm,
);
}}
description={
<>
Expand All @@ -731,6 +839,14 @@ export function NeuronSegmentationForm() {
</Space>
</>
}
jobSpecificInputFields={
hasSkeletonAnnotation && (
<CollapsibleSplitMergersplitMergerEvaluationSettings
isActive={doSplitMergerEvaluation}
setActive={setDoSplitMergerEvaluation}
/>
)
}
/>
);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
"@tanstack/react-query-persist-client": "4.36.1",
"@zip.js/zip.js": "^2.7.32",
"ansi-to-react": "^6.1.6",
"antd": "5.17.4",
"antd": "5.18",
"ball-morphology": "^0.1.0",
"base64-js": "^1.2.1",
"beautiful-react-hooks": "^3.11.1",
Expand Down
Loading