-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathTrackEditionLeftPanel.tsx
168 lines (157 loc) · 5.77 KB
/
TrackEditionLeftPanel.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import React, { useContext, useEffect, useRef, useMemo } from 'react';
import type { WidgetProps } from '@rjsf/utils';
import { isNil, omit } from 'lodash';
import { useTranslation } from 'react-i18next';
import EditorForm from 'applications/editor/components/EditorForm';
import EntityError from 'applications/editor/components/EntityError';
import EditorContext from 'applications/editor/context';
import {
NEW_ENTITY_ID,
getJsonSchemaForLayer,
getLayerForObjectType,
} from 'applications/editor/data/utils';
import type {
TrackEditionState,
TrackSectionEntity,
} from 'applications/editor/tools/trackEdition/types';
import { injectGeometry, removeInvalidRanges } from 'applications/editor/tools/trackEdition/utils';
import type { ExtendedEditorContextType } from 'applications/editor/types';
import DebouncedNumberInputSNCF from 'common/BootstrapSNCF/FormSNCF/DebouncedNumberInputSNCF';
import { useInfraID } from 'common/osrdContext';
import { save } from 'reducers/editor/thunkActions';
import { useAppDispatch } from 'store';
import AttachedRangesItemsList from './AttachedRangesItemsList';
const CustomLengthInput: React.FC<WidgetProps> = (props) => {
const { onChange, value } = props;
return (
<DebouncedNumberInputSNCF debouncedDelay={1500} input={value} setInput={onChange} label="" />
);
};
const TrackEditionLeftPanel: React.FC = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const infraID = useInfraID();
const { state, setState, isFormSubmited, setIsFormSubmited, editorState } = useContext(
EditorContext
) as ExtendedEditorContextType<TrackEditionState>;
const submitBtnRef = useRef<HTMLButtonElement>(null);
const { track, initialTrack } = state;
const isNew = track.properties.id === NEW_ENTITY_ID;
// Hack to be able to launch the submit event from the rjsf form by using
// the toolbar button instead of the form one.
// See https://github.com/rjsf-team/react-jsonschema-form/issues/500
useEffect(() => {
if (isFormSubmited && setIsFormSubmited && submitBtnRef.current) {
submitBtnRef.current.click();
setIsFormSubmited(false);
}
}, [isFormSubmited]);
const schema = useMemo(
() =>
getJsonSchemaForLayer(
editorState.editorSchema,
getLayerForObjectType(editorState.editorSchema, track.objType) || ''
),
[editorState.editorSchema, track.objType]
);
return (
<>
<EditorForm
data={track}
// Remove the source from schema if there is no source in the object
// To avoid to display it on the form
overrideSchema={
isNil(track.properties.extensions?.source)
? omit(schema, ['$defs.TrackSectionExtensions.properties.source'])
: schema
}
overrideUiSchema={{
length: {
'ui:widget': CustomLengthInput,
},
extensions: {
source: {
id: {
'ui:readonly': true,
},
name: {
'ui:readonly': true,
},
},
},
}}
onSubmit={async (savedEntity) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const res: any = await dispatch(
save(
infraID,
track.properties.id !== NEW_ENTITY_ID
? {
update: [
{
source: state.initialTrack,
target: injectGeometry(savedEntity),
},
],
}
: { create: [injectGeometry(savedEntity)] }
)
);
const { railjson } = res[0];
const savedTrack = {
objType: 'TrackSection',
type: 'Feature',
properties: railjson,
geometry: railjson.geo,
} as TrackSectionEntity;
setState({
...state,
initialTrack: savedTrack,
track: savedTrack,
});
}}
onChange={(newTrack) => {
let checkedTrack = { ...newTrack };
if (initialTrack.properties.length !== newTrack.properties.length) {
const { loading_gauge_limits, slopes, curves, length: newLength } = newTrack.properties;
const validLoadingGaugeLimits = removeInvalidRanges(loading_gauge_limits, newLength);
const validCurves = removeInvalidRanges(curves, newLength);
const validSlopes = removeInvalidRanges(slopes, newLength);
checkedTrack = {
...checkedTrack,
properties: {
...checkedTrack.properties,
loading_gauge_limits: validLoadingGaugeLimits,
slopes: validSlopes,
curves: validCurves,
},
};
}
setState({
...state,
track: checkedTrack as TrackSectionEntity,
});
}}
>
<div>
{/* We don't want to see the button but just be able to click on it */}
<button type="submit" ref={submitBtnRef} style={{ display: 'none' }}>
{t('common.save')}
</button>
</div>
</EditorForm>
<div className="border-bottom" />
{!isNew && (
<>
{!isNew && <EntityError className="border-bottom mb-1" entity={track} />}
<h3>{t('Editor.tools.track-edition.attached-speed-sections')}</h3>
<AttachedRangesItemsList id={track.properties.id} itemType="SpeedSection" />
<div className="border-bottom" />
<h3>{t('Editor.tools.track-edition.attached-electrifications')}</h3>
<AttachedRangesItemsList id={track.properties.id} itemType="Electrification" />
</>
)}
</>
);
};
export default TrackEditionLeftPanel;