From 355f023adb21b3fdeaa0eb00d0eb82d0e1c37fbf Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 17 Nov 2023 16:59:26 +0100 Subject: [PATCH] front: infra editor make slopes and curves optional values make slopes and curves value optional improve chart --- .../editor/components/EditorForm.tsx | 4 +- .../LinearMetadata/FormComponent.tsx | 82 ++++++++++--------- .../components/LinearMetadata/tooltip.tsx | 3 +- .../editor/tools/trackEdition/utils.ts | 2 + .../common/IntervalsDataViz/IntervalItem.tsx | 29 ++++--- front/src/common/IntervalsDataViz/data.ts | 5 ++ front/src/common/IntervalsDataViz/dataviz.tsx | 6 +- front/src/common/IntervalsDataViz/style.scss | 42 +++++----- front/src/types/editor.ts | 3 + 9 files changed, 99 insertions(+), 77 deletions(-) diff --git a/front/src/applications/editor/components/EditorForm.tsx b/front/src/applications/editor/components/EditorForm.tsx index 22272c16252..21325a1a833 100644 --- a/front/src/applications/editor/components/EditorForm.tsx +++ b/front/src/applications/editor/components/EditorForm.tsx @@ -124,9 +124,7 @@ function EditorForm & { objType: string }} onChange={(event) => { setFormData({ ...data.properties, ...event.formData }); - if (onChange) { - onChange({ ...data, properties: { ...data.properties, ...event.formData } }); - } + onChange?.({ ...data, properties: { ...data.properties, ...event.formData } }); }} > {children} diff --git a/front/src/applications/editor/components/LinearMetadata/FormComponent.tsx b/front/src/applications/editor/components/LinearMetadata/FormComponent.tsx index 606f430f95c..96b04ea591a 100644 --- a/front/src/applications/editor/components/LinearMetadata/FormComponent.tsx +++ b/front/src/applications/editor/components/LinearMetadata/FormComponent.tsx @@ -23,9 +23,9 @@ import { } from 'common/IntervalsDataViz/data'; import { LinearMetadataItem } from 'common/IntervalsDataViz/types'; import { LinearMetadataDataviz } from 'common/IntervalsDataViz/dataviz'; -import { useModal } from '../../../../common/BootstrapSNCF/ModalSNCF'; +import { useModal } from 'common/BootstrapSNCF/ModalSNCF'; +import { tooltipPosition, notEmpty } from 'common/IntervalsDataViz/utils'; import HelpModal from './HelpModal'; -import { tooltipPosition, notEmpty } from '../../../../common/IntervalsDataViz/utils'; import { LinearMetadataTooltip } from './tooltip'; import { FormBeginEndWidget } from './FormBeginEndWidget'; @@ -66,12 +66,19 @@ export const FormComponent: React.FC = (props) => { return 0; }, [formContext]); + // Remove the 'valueField' required field because it is required by the backend. However, + // the segment with missing values is filtered in 'customOnChange' before being sent to the backend, + // and then re-added by 'fixLinearMetadataItems'. + const requiredFilter = (requireds: string[]) => + requireds.filter((r) => ['end', 'begin'].includes(r)); + // Compute the JSON schema of the linear metadata item const jsonSchema = useMemo( () => getFieldJsonSchema( schema, registry.rootSchema, + requiredFilter, distance ? { begin: { @@ -108,6 +115,7 @@ export const FormComponent: React.FC = (props) => { const customOnChange = useCallback( (newData: Array) => { + // Remove item without value, it will be recreated by the fixLinearMetadataItems function onChange(newData.filter((e) => (valueField ? !isNil(e[valueField]) : true))); }, [onChange, valueField] @@ -337,7 +345,7 @@ export const FormComponent: React.FC = (props) => { noHtml5Validate tagName="div" schema={ - (getFieldJsonSchema(schema, registry.rootSchema, { + (getFieldJsonSchema(schema, registry.rootSchema, requiredFilter, { begin: { minimum: 0, maximum: fnMax([selectedData.begin, selectedData.end - SEGMENT_MIN_SIZE]), @@ -363,43 +371,41 @@ export const FormComponent: React.FC = (props) => { }} formData={selectedData} onChange={(e) => { - if (e.errors.length === 0) { - const newItem = e.formData; - const oldItem = data[selected]; - let newData = [...data]; - // we keep the old value for begin and end - // they will be change in the resize function if needed - newData[selected] = { - ...oldItem, - ...omit(newItem, ['begin', 'end']), - }; + const newItem = e.formData; + const oldItem = data[selected]; + let newData = [...data]; + // we keep the old value for begin and end + // they will be change in the resize function if needed + newData[selected] = { + ...oldItem, + ...omit(newItem, ['begin', 'end']), + }; - // Check if there is a resize - try { - if (newItem.begin !== oldItem.begin) { - const resizeBegin = resizeSegment( - [...newData], - selected, - newItem.begin - oldItem.begin, - 'begin' - ); - newData = resizeBegin.result; - } - if (oldItem.end !== newItem.end) { - const resizeEnd = resizeSegment( - [...newData], - selected, - newItem.end - oldItem.end, - 'end' - ); - newData = resizeEnd.result; - } - customOnChange(newData); - } catch (error) { - // TODO: Should we display the resize error ? - } finally { - setSelectedData(newItem); + // Check if there is a resize + try { + if (newItem.begin !== oldItem.begin) { + const resizeBegin = resizeSegment( + [...newData], + selected, + newItem.begin - oldItem.begin, + 'begin' + ); + newData = resizeBegin.result; + } + if (oldItem.end !== newItem.end) { + const resizeEnd = resizeSegment( + [...newData], + selected, + newItem.end - oldItem.end, + 'end' + ); + newData = resizeEnd.result; } + customOnChange(newData); + } catch (error) { + // TODO: Should we display the resize error ? + } finally { + setSelectedData(newItem); } }} > diff --git a/front/src/applications/editor/components/LinearMetadata/tooltip.tsx b/front/src/applications/editor/components/LinearMetadata/tooltip.tsx index 4b3fbaee6e4..e51aff2d3d4 100644 --- a/front/src/applications/editor/components/LinearMetadata/tooltip.tsx +++ b/front/src/applications/editor/components/LinearMetadata/tooltip.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { JSONSchema7 } from 'json-schema'; import { LinearMetadataItem } from 'common/IntervalsDataViz/types'; +import { isNil } from 'lodash'; interface LinearMetadataTooltipProps { item: LinearMetadataItem; @@ -38,7 +39,7 @@ export const LinearMetadataTooltip = >({ {((schema.properties || {})[k] as JSONSchema7 | undefined)?.title || k} - {`${item[k] || '-'}`} + {isNil(item[k]) ? '-' : `${item[k]}`} ))} diff --git a/front/src/applications/editor/tools/trackEdition/utils.ts b/front/src/applications/editor/tools/trackEdition/utils.ts index b0c214c7758..5f9135050c0 100644 --- a/front/src/applications/editor/tools/trackEdition/utils.ts +++ b/front/src/applications/editor/tools/trackEdition/utils.ts @@ -13,6 +13,8 @@ export function getNewLine(points: [number, number][]): TrackSectionEntity { properties: { id: NEW_ENTITY_ID, length: 0, + slopes: [], + curves: [], }, }; } diff --git a/front/src/common/IntervalsDataViz/IntervalItem.tsx b/front/src/common/IntervalsDataViz/IntervalItem.tsx index 1f84c513afe..7946978c12d 100644 --- a/front/src/common/IntervalsDataViz/IntervalItem.tsx +++ b/front/src/common/IntervalsDataViz/IntervalItem.tsx @@ -56,21 +56,27 @@ const IntervalItem = ({ valueText = `${interval[field]}`; } } + + const hasNoData = + !!field && + (segment === undefined || segment[field] === undefined || segment[field] === emptyValue); + const hasData = + !!field && + segment !== undefined && + segment[field] !== undefined && + segment[field] !== emptyValue; + const fieldValue = !!field && segment !== undefined && segment[field]; + const isDataZero = fieldValue === 0; + return (
({ )} + {hasNoData &&
} + {isDataZero &&
} + {/* Create a div for the resize */} {data[segment.index] && segment.end === data[segment.index].end && (
(entity: T, sourceLine: Li export function getFieldJsonSchema( fieldSchema: JSONSchema7, rootSchema: JSONSchema7, + requiredFilter?: (required: string[]) => string[], enhancement: { [key: string]: JSONSchema7Definition } = {} ): JSONSchema7 { let result = { ...fieldSchema }; @@ -698,6 +699,10 @@ export function getFieldJsonSchema( ...result, items: { ...itemsSchema, + required: + requiredFilter && itemsSchema.required && isArray(itemsSchema.required) + ? requiredFilter(itemsSchema.required) + : itemsSchema.required, properties: { begin: { ...(itemsSchema.properties?.begin as JSONSchema7), diff --git a/front/src/common/IntervalsDataViz/dataviz.tsx b/front/src/common/IntervalsDataViz/dataviz.tsx index 315e6c59ecf..7b4c2df611b 100644 --- a/front/src/common/IntervalsDataViz/dataviz.tsx +++ b/front/src/common/IntervalsDataViz/dataviz.tsx @@ -3,7 +3,7 @@ import { head, isNil, last, maxBy, minBy } from 'lodash'; import cx from 'classnames'; import { AdditionalDataItem } from 'common/IntervalsEditor/types'; -import { preventDefault, computeStyleForDataValue, getPositionFromMouseEvent } from './utils'; +import { preventDefault, getPositionFromMouseEvent } from './utils'; import { cropForDatavizViewbox, cropOperationPointsForDatavizViewbox, @@ -366,10 +366,6 @@ export const LinearMetadataDataviz = ({ (viewBox === null || viewBox[1] === last(data)?.end) && 'end-visible' )} > - {/* Display the 0 axis if it's necessary */} - {min < 0 && max > 0 && ( -
- )} {/* Display the Y axis if there is one */} {field && min !== max && !options.fullHeightItem && ( diff --git a/front/src/common/IntervalsDataViz/style.scss b/front/src/common/IntervalsDataViz/style.scss index 347fafc8b91..6ed56289500 100644 --- a/front/src/common/IntervalsDataViz/style.scss +++ b/front/src/common/IntervalsDataViz/style.scss @@ -153,20 +153,24 @@ $resize-width: 3px; flex-direction: row; align-items: flex-end; justify-content: flex-end; + position: relative; - &.no-data { - background-color: mixw($color, 0.9); - background-image: repeating-linear-gradient( - 45deg, - $color-nodata, - $color-nodata 1px, - transparent 2px, - transparent 10px - ); - - &.highlighted { - background-color: $color-highlight; - } + .zero-line { + position: absolute !important; + width: 100%; + right: 0; + left: 0; + z-index: 1; + border-bottom: 1px solid $color; + } + + .no-data-line { + position: absolute !important; + width: 100%; + right: 0; + left: 0; + z-index: 1; + border-bottom: 1px dashed var(--coolgray9); } &.with-data { @@ -178,6 +182,10 @@ $resize-width: 3px; div.value { background-color: $color-highlight; } + + .zero-line { + border-bottom-color: $color-highlight; + } } div.value { @@ -269,13 +277,6 @@ $resize-width: 3px; } } - .axis-zero { - position: absolute !important; - width: 100%; - border-bottom: 1px solid red; - z-index: 1; - } - .scale { display: flex; justify-content: space-between; @@ -312,6 +313,7 @@ $resize-width: 3px; align-items: center; width: 100%; height: 100%; + padding-right: 2px; div { position: relative; top: 0; diff --git a/front/src/types/editor.ts b/front/src/types/editor.ts index ca512a2f6ab..dccc317354a 100644 --- a/front/src/types/editor.ts +++ b/front/src/types/editor.ts @@ -1,6 +1,7 @@ import { JSONSchema7 } from 'json-schema'; import { Feature, GeoJsonProperties, Geometry, Point, LineString, MultiLineString } from 'geojson'; import { Direction, DirectionalTrackRange, ObjectType } from 'common/api/osrdEditoastApi'; +import { LinearMetadataItem } from 'common/IntervalsDataViz/types'; import { NullGeometry } from './geospatial'; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -22,6 +23,8 @@ export interface TrackSectionEntity LineString, { length: number; + slopes: LinearMetadataItem<{ gradient: number }>[]; + curves: LinearMetadataItem<{ radius: number }>[]; extensions?: { sncf?: { line_code?: number;