diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 8258147c6b..2310f42d92 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -32,6 +32,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released - Fixed a bug in ND volume annotation downloads where the additionalAxes metadata had wrong indices. [#7592](https://github.com/scalableminds/webknossos/pull/7592) - Fixed a bug in proofreading aka editable mapping annotations where splitting would sometimes give the new id to the selected segment rather than to the split-off one. [#7608](https://github.com/scalableminds/webknossos/pull/7608) - Fixed small styling errors as a follow up to the antd v5 upgrade [#7612](https://github.com/scalableminds/webknossos/pull/7612) +-Fixed deprecation warnings caused by Antd components. [#7610](https://github.com/scalableminds/webknossos/pull/7610) ### Removed diff --git a/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx b/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx index e725619c4e..ad6ad9c004 100644 --- a/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx +++ b/frontend/javascripts/admin/dataset/dataset_add_remote_view.tsx @@ -39,7 +39,6 @@ import { Unicode } from "oxalis/constants"; import { readFileAsText } from "libs/read_file"; import * as Utils from "libs/utils"; -const { Panel } = Collapse; const FormItem = Form.Item; const RadioGroup = Radio.Group; @@ -552,13 +551,20 @@ function AddZarrLayer({ {exploreLog ? ( - - - -
{exploreLog}
-
-
-
+ +
{exploreLog}
+ + ), + }, + ]} + />
) : null} diff --git a/frontend/javascripts/admin/tasktype/recommended_configuration_view.tsx b/frontend/javascripts/admin/tasktype/recommended_configuration_view.tsx index 6d926cd90a..b15bf6badd 100644 --- a/frontend/javascripts/admin/tasktype/recommended_configuration_view.tsx +++ b/frontend/javascripts/admin/tasktype/recommended_configuration_view.tsx @@ -1,4 +1,4 @@ -import { Checkbox, Col, Collapse, Form, Input, Row, Table, Button } from "antd"; +import { Checkbox, Col, Collapse, Form, Input, Row, Table, Button, CollapseProps } from "antd"; import { FormInstance } from "antd/lib/form"; import * as React from "react"; import _ from "lodash"; @@ -9,7 +9,6 @@ import { validateUserSettingsJSON } from "types/validation"; import { TDViewDisplayModeEnum } from "oxalis/constants"; import features from "features"; const FormItem = Form.Item; -const { Panel } = Collapse; function getRecommendedConfigByCategory() { return { @@ -138,79 +137,84 @@ export default function RecommendedConfigurationView({ }; }); + const recommendedSettingsView = ( + + +
+ The recommended configuration will be displayed to users when starting to work on a task + with this task type. The user is able to accept or decline this recommendation. +
+
+ + enabled ? validateUserSettingsJSON(rule, value) : Promise.resolve(), + }, + ]} + > + + +
+ + + + + + Valid settings and their default values:
+
+ + + + ); + + const collapseItems: CollapseProps["items"] = [ + { + key: "config", + label: ( + + {" "} + Add Recommended User Settings + + ), + showArrow: false, + children: recommendedSettingsView, + }, + ]; + return ( onChangeEnabled(openedPanels.length === 1)} - // @ts-expect-error ts-migrate(2322) FIXME: Type 'string | null' is not assignable to type 'st... Remove this comment to see the full error message - activeKey={enabled ? "config" : null} - > - - {" "} - Add Recommended User Settings - - } - showArrow={false} - > - - -
- The recommended configuration will be displayed to users when starting to work on a - task with this task type. The user is able to accept or decline this recommendation. -
-
- - enabled ? validateUserSettingsJSON(rule, value) : Promise.resolve(), - }, - ]} - > - - -
- - - - - - Valid settings and their default values:
-
-
- - - - + activeKey={enabled ? "config" : undefined} + items={collapseItems} + /> ); } diff --git a/frontend/javascripts/admin/voxelytics/task_list_view.tsx b/frontend/javascripts/admin/voxelytics/task_list_view.tsx index a560c66700..3da4e52ad2 100644 --- a/frontend/javascripts/admin/voxelytics/task_list_view.tsx +++ b/frontend/javascripts/admin/voxelytics/task_list_view.tsx @@ -13,6 +13,7 @@ import { Select, MenuProps, App, + CollapseProps, } from "antd"; import { ClockCircleOutlined, @@ -50,8 +51,8 @@ import { addAfterPadding, addBeforePadding } from "./utils"; import { LOG_LEVELS } from "oxalis/constants"; import { getVoxelyticsLogs } from "admin/admin_rest_api"; import ArtifactsDiskUsageList from "./artifacts_disk_usage_list"; +import { ArrayElement, notEmpty } from "libs/utils"; -const { Panel } = Collapse; const { Search } = Input; function getFilteredTasks( @@ -441,97 +442,101 @@ export default function TaskListView({ ], }; - const renderTaskGroupOrTask = (taskGroup: VoxelyticsTaskConfigWithHierarchy) => { + type ItemType = ArrayElement; + + const getTaskGroupOrTaskItem = ( + taskGroup: VoxelyticsTaskConfigWithHierarchy, + ): ItemType | undefined => { const taskInfo = aggregateTaskInfos(taskGroup, report.tasks, runId); if (taskGroup.isMetaTask) { // If tasks are filtered away by the search query, it can happen that a meta task // has "no children", anymore. In that case, don't render the entire meta task. const subtasks = taskGroup.subtasks; - const children = subtasks.map(renderTaskGroupOrTask).filter((c) => c != null); - if (children.length === 0) { - return null; + const collapseItems = subtasks.map(getTaskGroupOrTaskItem).filter(notEmpty); + if (collapseItems.length === 0) { + return undefined; } - return ( - -
- {taskGroup.key} - - - - -
- } - key={taskGroup.key} - id={`task-panel-${taskGroup.key}`} - > - {openMetatask !== taskGroup.key && ( -
- { - ev.preventDefault(); - onToggleExpandedMetaTaskKey(taskGroup.key); - }} - > - {expandedMetaTaskKeys[taskGroup.key] ? "Collapse in DAG" : "Expand in DAG"} - - Open in extra View -
- )} - {children} -
- ); - } - const task = taskGroup; - - const isInFilteredTasks = filteredTasks.find((t) => t.taskName === task.taskName); - if (!isInFilteredTasks) { - return null; - } - - return ( -
- {task.taskName} - - {task.config.name != null && ( - {task.config.name} - )} + {taskGroup.key}
- } - key={task.taskName} - id={`task-panel-${task.taskName}`} - > + ), + children: ( + + {openMetatask !== taskGroup.key && ( + + )} + + + ), + }; + } + const task = taskGroup; + + const isInFilteredTasks = filteredTasks.find((t) => t.taskName === task.taskName); + if (!isInFilteredTasks) { + return undefined; + } + + return { + key: task.taskName, + id: `task-panel-${task.taskName}`, + label: ( +
+
+ {task.taskName} + + {task.config.name != null && {task.config.name}} + + + + +
+ ), + children: ( - - ); + ), + }; }; const totalRuntime = report.tasks.reduce((sum, t) => { @@ -649,9 +654,11 @@ export default function TaskListView({
- - {tasksWithHierarchy.map(renderTaskGroupOrTask)} - +
diff --git a/frontend/javascripts/dashboard/dataset/color_layer_ordering_component.tsx b/frontend/javascripts/dashboard/dataset/color_layer_ordering_component.tsx index 666e41fc66..2d9fc09f44 100644 --- a/frontend/javascripts/dashboard/dataset/color_layer_ordering_component.tsx +++ b/frontend/javascripts/dashboard/dataset/color_layer_ordering_component.tsx @@ -1,12 +1,11 @@ import { MenuOutlined, InfoCircleOutlined } from "@ant-design/icons"; -import { List, Collapse, Tooltip } from "antd"; +import { List, Collapse, Tooltip, CollapseProps } from "antd"; import React from "react"; import { SortEnd } from "react-sortable-hoc"; import { SortableContainer, SortableElement, SortableHandle } from "react-sortable-hoc"; import { settings, settingsTooltips } from "messages"; // Example taken and modified from https://4x.ant.design/components/table/#components-table-demo-drag-sorting-handler. -const { Panel } = Collapse; const DragHandle = SortableHandle(() => ); @@ -52,9 +51,11 @@ export default function ColorLayerOrderingTable({ ); - return ( - - + const collapseItems: CollapseProps["items"] = [ + { + label: panelTitle, + key: "1", + children: ( @@ -68,7 +69,15 @@ export default function ColorLayerOrderingTable({ ))} - - + ), + }, + ]; + + return ( + ); } diff --git a/frontend/javascripts/dashboard/dataset/dataset_settings_sharing_tab.tsx b/frontend/javascripts/dashboard/dataset/dataset_settings_sharing_tab.tsx index 0ba10062ff..a363418e30 100644 --- a/frontend/javascripts/dashboard/dataset/dataset_settings_sharing_tab.tsx +++ b/frontend/javascripts/dashboard/dataset/dataset_settings_sharing_tab.tsx @@ -84,7 +84,7 @@ function DatasetSettingsSharingTab({ form, datasetId, dataset, activeUser }: Pro if (!activeUser || !dataset) return undefined; if (!isUserAdminOrTeamManager(activeUser)) return undefined; - const header = ( + const panelLabel = ( All users with access permission to work with this dataset{" "} @@ -94,11 +94,16 @@ function DatasetSettingsSharingTab({ form, datasetId, dataset, activeUser }: Pro ); return ( - - - - - + , + }, + ]} + /> ); } diff --git a/frontend/javascripts/libs/toast.tsx b/frontend/javascripts/libs/toast.tsx index 18eaecfdec..5aeb5aa806 100644 --- a/frontend/javascripts/libs/toast.tsx +++ b/frontend/javascripts/libs/toast.tsx @@ -1,7 +1,6 @@ import { notification, Collapse } from "antd"; import { CloseCircleOutlined } from "@ant-design/icons"; import React from "react"; -const { Panel } = Collapse; export type ToastStyle = "info" | "warning" | "success" | "error"; export type Message = { @@ -59,19 +58,19 @@ const Toast = { background: "transparent", marginLeft: -16, }} - > - - {details} - - + items={[ + { + key: "toast-panel", + label: "Show more information", + style: { + background: "transparent", + border: 0, + fontSize: 10, + }, + children: details, + }, + ]} + /> ); }, diff --git a/frontend/javascripts/libs/utils.ts b/frontend/javascripts/libs/utils.ts index 449d5e57a1..e7459cb1eb 100644 --- a/frontend/javascripts/libs/utils.ts +++ b/frontend/javascripts/libs/utils.ts @@ -16,6 +16,7 @@ import type { import window, { document, location } from "libs/window"; export type Comparator = (arg0: T, arg1: T) => -1 | 0 | 1; +export type ArrayElement = A extends readonly (infer T)[] ? T : never; type UrlParams = Record; // Fix JS modulo bug @@ -1180,3 +1181,10 @@ export function getFileExtension(fileName: string): string { } export class SoftError extends Error {} + +export function notEmpty(value: TValue | null | undefined): value is TValue { + // Strongly typed helper to filter any non empty values from an array + // e.g. [1, 2, undefined].filter(notEmpty) => type should be number[] + // Source https://github.com/microsoft/TypeScript/issues/45097#issuecomment-882526325 + return value !== null && value !== undefined; +} diff --git a/frontend/javascripts/oxalis/view/left-border-tabs/controls_and_rendering_settings_tab.tsx b/frontend/javascripts/oxalis/view/left-border-tabs/controls_and_rendering_settings_tab.tsx index cd8fca5328..044a865dc2 100644 --- a/frontend/javascripts/oxalis/view/left-border-tabs/controls_and_rendering_settings_tab.tsx +++ b/frontend/javascripts/oxalis/view/left-border-tabs/controls_and_rendering_settings_tab.tsx @@ -1,4 +1,4 @@ -import { Collapse, Tooltip } from "antd"; +import { Collapse, CollapseProps, Tooltip } from "antd"; import type { Dispatch } from "redux"; import { connect } from "react-redux"; import React, { PureComponent } from "react"; @@ -28,8 +28,7 @@ import Toast from "libs/toast"; import { ExclamationCircleOutlined } from "@ant-design/icons"; import { PricingPlanEnum } from "admin/organization/pricing_plan_utils"; import { PricingEnforcedSwitchSetting } from "components/pricing_enforcers"; - -const { Panel } = Collapse; +import { ArrayElement } from "libs/utils"; type ControlsAndRenderingSettingsTabProps = { activeUser: APIUser | null | undefined; @@ -76,120 +75,128 @@ class ControlsAndRenderingSettingsTab extends PureComponent { + getViewportOptions = (): ArrayElement => { if ( this.props.viewMode === Constants.MODE_ARBITRARY || this.props.viewMode === Constants.MODE_ARBITRARY_PLANE ) { - return ( - - {settingsLabels.zoom}} - roundTo={3} - min={this.props.validZoomRange[0]} - max={this.props.validZoomRange[1]} - value={this.props.zoomStep} - onChange={this.props.onChangeZoomStep} - /> - - {settingsLabels.mouseRotateValue} - - } - min={userSettings.mouseRotateValue.minimum} - max={userSettings.mouseRotateValue.maximum} - step={0.001} - value={this.props.userConfiguration.mouseRotateValue} - onChange={this.onChangeUser.mouseRotateValue} - /> - {settingsLabels.rotateValue} - } - min={userSettings.rotateValue.minimum} - max={userSettings.rotateValue.maximum} - step={0.001} - value={this.props.userConfiguration.rotateValue} - onChange={this.onChangeUser.rotateValue} - /> - - {settingsLabels.crosshairSize} - - } - min={userSettings.crosshairSize.minimum} - max={userSettings.crosshairSize.maximum} - step={0.01} - value={this.props.userConfiguration.crosshairSize} - onChange={this.onChangeUser.crosshairSize} - /> - - {settingsLabels.sphericalCapRadius} - - } - min={userSettings.sphericalCapRadius.minimum} - max={userSettings.sphericalCapRadius.maximum} - step={1} - value={this.props.userConfiguration.sphericalCapRadius} - onChange={this.onChangeUser.sphericalCapRadius} - /> - - {settingsLabels.displayCrosshair} - - } - value={this.props.userConfiguration.displayCrosshair} - onChange={this.onChangeUser.displayCrosshair} - /> -
- ); + return { + label: "Flight Options", + key: "2", + children: ( + + {settingsLabels.zoom}} + roundTo={3} + min={this.props.validZoomRange[0]} + max={this.props.validZoomRange[1]} + value={this.props.zoomStep} + onChange={this.props.onChangeZoomStep} + /> + + {settingsLabels.mouseRotateValue} + + } + min={userSettings.mouseRotateValue.minimum} + max={userSettings.mouseRotateValue.maximum} + step={0.001} + value={this.props.userConfiguration.mouseRotateValue} + onChange={this.onChangeUser.mouseRotateValue} + /> + {settingsLabels.rotateValue} + } + min={userSettings.rotateValue.minimum} + max={userSettings.rotateValue.maximum} + step={0.001} + value={this.props.userConfiguration.rotateValue} + onChange={this.onChangeUser.rotateValue} + /> + + {settingsLabels.crosshairSize} + + } + min={userSettings.crosshairSize.minimum} + max={userSettings.crosshairSize.maximum} + step={0.01} + value={this.props.userConfiguration.crosshairSize} + onChange={this.onChangeUser.crosshairSize} + /> + + {settingsLabels.sphericalCapRadius} + + } + min={userSettings.sphericalCapRadius.minimum} + max={userSettings.sphericalCapRadius.maximum} + step={1} + value={this.props.userConfiguration.sphericalCapRadius} + onChange={this.onChangeUser.sphericalCapRadius} + /> + + {settingsLabels.displayCrosshair} + + } + value={this.props.userConfiguration.displayCrosshair} + onChange={this.onChangeUser.displayCrosshair} + /> + + ), + }; } else { - return ( - - {settingsLabels.zoom}} - roundTo={3} - min={this.props.validZoomRange[0]} - max={this.props.validZoomRange[1]} - value={this.props.zoomStep} - onChange={this.props.onChangeZoomStep} - /> - - {settingsLabels.displayCrosshair} - - } - value={this.props.userConfiguration.displayCrosshair} - onChange={this.onChangeUser.displayCrosshair} - /> - - {settingsLabels.displayScalebars} - - } - value={this.props.userConfiguration.displayScalebars} - onChange={this.onChangeUser.displayScalebars} - /> - - {settingsLabels.renderWatermark} - - } - value={this.props.userConfiguration.renderWatermark} - onChange={this.onChangeUser.renderWatermark} - requiredPricingPlan={PricingPlanEnum.Team} - defaultValue={true} - /> - - ); + return { + label: "Viewport Options", + key: "2", + children: ( + + {settingsLabels.zoom}} + roundTo={3} + min={this.props.validZoomRange[0]} + max={this.props.validZoomRange[1]} + value={this.props.zoomStep} + onChange={this.props.onChangeZoomStep} + /> + + {settingsLabels.displayCrosshair} + + } + value={this.props.userConfiguration.displayCrosshair} + onChange={this.onChangeUser.displayCrosshair} + /> + + {settingsLabels.displayScalebars} + + } + value={this.props.userConfiguration.displayScalebars} + onChange={this.onChangeUser.displayScalebars} + /> + + {settingsLabels.renderWatermark} + + } + value={this.props.userConfiguration.renderWatermark} + onChange={this.onChangeUser.renderWatermark} + requiredPricingPlan={PricingPlanEnum.Team} + defaultValue={true} + /> + + ), + }; } }; @@ -240,6 +247,168 @@ class ControlsAndRenderingSettingsTab extends PureComponent ); + + const collapseItems: CollapseProps["items"] = [ + { + label: "Controls", + key: "1", + children: ( + + + {settingsLabels.keyboardDelay} + + } + min={userSettings.keyboardDelay.minimum} + max={userSettings.keyboardDelay.maximum} + value={this.props.userConfiguration.keyboardDelay} + onChange={this.onChangeUser.keyboardDelay} + /> + {moveValueSetting} + + {settingsLabels.dynamicSpaceDirection} + + } + value={this.props.userConfiguration.dynamicSpaceDirection} + onChange={this.onChangeUser.dynamicSpaceDirection} + /> + + {settingsLabels.useLegacyBindings} + + } + value={this.props.userConfiguration.useLegacyBindings} + onChange={this.onChangeUser.useLegacyBindings} + /> + + ), + }, + this.getViewportOptions(), + { + label: "Data Rendering", + key: "3", + children: ( + + {" "} + + {settingsLabels.gpuMemoryFactor} + + } + value={( + this.props.userConfiguration.gpuMemoryFactor || Constants.DEFAULT_GPU_MEMORY_FACTOR + ).toString()} + onChange={this.onChangeGpuFactor} + disabled={this.props.activeUser == null} + disabledReason={ + this.props.activeUser == null ? "Log in to change this setting." : null + } + options={getGpuFactorsWithLabels().map(([factor, label]) => ({ + label, + value: factor.toString(), + }))} + /> + + {settingsLabels.loadingStrategy} + + } + value={this.props.datasetConfiguration.loadingStrategy} + onChange={this.onChangeDataset.loadingStrategy} + options={[ + { + value: "BEST_QUALITY_FIRST", + label: "Best quality first", + }, + { + value: "PROGRESSIVE_QUALITY", + label: "Progressive quality", + }, + ]} + /> + {settingsLabels.blendMode} + } + value={this.props.datasetConfiguration.blendMode} + onChange={this.onChangeDataset.blendMode} + options={[ + { + value: BLEND_MODES.Additive, + label: "Additive", + }, + { + value: BLEND_MODES.Cover, + label: "Cover", + }, + ]} + /> + {settingsLabels.fourBit}} + value={this.props.datasetConfiguration.fourBit} + onChange={this.onChangeDataset.fourBit} + /> + {Constants.MODES_ARBITRARY.includes(this.props.viewMode) ? null : ( +
+ + {settingsLabels.interpolation} + + } + value={this.props.datasetConfiguration.interpolation} + onChange={this.onChangeDataset.interpolation} + > + {this.props.datasetConfiguration.interpolation && ( + + {PERFORMANCE_WARNING_ICON} + + )} + +
+ )} + + {settingsLabels.antialiasRendering} + + } + value={this.props.userConfiguration.antialiasRendering} + disabled={this.props.activeUser == null} + disabledReason={ + this.props.activeUser == null ? "Log in to change this setting." : null + } + onChange={(arg) => { + askUserToReload(); + this.onChangeUser.antialiasRendering(arg); + }} + > + {this.props.userConfiguration.antialiasRendering && ( + + {PERFORMANCE_WARNING_ICON} + + )} + + + {settingsLabels.renderMissingDataBlack}{" "} + + } + value={this.props.datasetConfiguration.renderMissingDataBlack} + onChange={this.onChangeRenderMissingDataBlack} + /> +
+ ), + }, + ]; + return ( - - - {settingsLabels.keyboardDelay} - - } - min={userSettings.keyboardDelay.minimum} - max={userSettings.keyboardDelay.maximum} - value={this.props.userConfiguration.keyboardDelay} - onChange={this.onChangeUser.keyboardDelay} - /> - {moveValueSetting} - - {settingsLabels.dynamicSpaceDirection} - - } - value={this.props.userConfiguration.dynamicSpaceDirection} - onChange={this.onChangeUser.dynamicSpaceDirection} - /> - - {settingsLabels.useLegacyBindings} - - } - value={this.props.userConfiguration.useLegacyBindings} - onChange={this.onChangeUser.useLegacyBindings} - /> - - {this.getViewportOptions()} - - - {settingsLabels.gpuMemoryFactor} - - } - value={( - this.props.userConfiguration.gpuMemoryFactor || Constants.DEFAULT_GPU_MEMORY_FACTOR - ).toString()} - onChange={this.onChangeGpuFactor} - disabled={this.props.activeUser == null} - disabledReason={this.props.activeUser == null ? "Log in to change this setting." : null} - options={getGpuFactorsWithLabels().map(([factor, label]) => ({ - label, - value: factor.toString(), - }))} - /> - - {settingsLabels.loadingStrategy} - - } - value={this.props.datasetConfiguration.loadingStrategy} - onChange={this.onChangeDataset.loadingStrategy} - options={[ - { - value: "BEST_QUALITY_FIRST", - label: "Best quality first", - }, - { - value: "PROGRESSIVE_QUALITY", - label: "Progressive quality", - }, - ]} - /> - {settingsLabels.blendMode}} - value={this.props.datasetConfiguration.blendMode} - onChange={this.onChangeDataset.blendMode} - options={[ - { - value: BLEND_MODES.Additive, - label: "Additive", - }, - { - value: BLEND_MODES.Cover, - label: "Cover", - }, - ]} - /> - {settingsLabels.fourBit}} - value={this.props.datasetConfiguration.fourBit} - onChange={this.onChangeDataset.fourBit} - /> - {Constants.MODES_ARBITRARY.includes(this.props.viewMode) ? null : ( -
- - {settingsLabels.interpolation} - - } - value={this.props.datasetConfiguration.interpolation} - onChange={this.onChangeDataset.interpolation} - > - {this.props.datasetConfiguration.interpolation && ( - - {PERFORMANCE_WARNING_ICON} - - )} - -
- )} - - {settingsLabels.antialiasRendering} - - } - value={this.props.userConfiguration.antialiasRendering} - disabled={this.props.activeUser == null} - disabledReason={this.props.activeUser == null ? "Log in to change this setting." : null} - onChange={(arg) => { - askUserToReload(); - this.onChangeUser.antialiasRendering(arg); - }} - > - {this.props.userConfiguration.antialiasRendering && ( - - {PERFORMANCE_WARNING_ICON} - - )} - - - {settingsLabels.renderMissingDataBlack}{" "} - - } - value={this.props.datasetConfiguration.renderMissingDataBlack} - onChange={this.onChangeRenderMissingDataBlack} - /> -
-
+ items={collapseItems} + /> ); } }