diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml
index be86cba360e..a62eb35d12d 100644
--- a/editoast/openapi.yaml
+++ b/editoast/openapi.yaml
@@ -2486,6 +2486,22 @@ paths:
description: Check if Editoast is running correctly
/infra/:
get:
+ parameters:
+ - description: Page number
+ in: query
+ name: page
+ schema:
+ default: 1
+ minimum: 1
+ type: integer
+ - description: Number of elements by page
+ in: query
+ name: page_size
+ schema:
+ default: 25
+ maximum: 10000
+ minimum: 1
+ type: integer
responses:
'200':
content:
@@ -2505,8 +2521,8 @@ paths:
- next
- previous
type: object
- description: The infra list
- summary: List all available infra
+ description: The infras list
+ summary: Paginated list of all available infras
tags:
- infra
post:
diff --git a/editoast/openapi_legacy.yaml b/editoast/openapi_legacy.yaml
index 49e367d48ba..7ddb3c226fa 100644
--- a/editoast/openapi_legacy.yaml
+++ b/editoast/openapi_legacy.yaml
@@ -173,10 +173,26 @@ paths:
get:
tags:
- infra
- summary: List all available infra
+ summary: Paginated list of all available infras
+ parameters:
+ - description: Page number
+ in: query
+ name: page
+ schema:
+ default: 1
+ minimum: 1
+ type: integer
+ - description: Number of elements by page
+ in: query
+ name: page_size
+ schema:
+ default: 25
+ maximum: 10000
+ minimum: 1
+ type: integer
responses:
200:
- description: The infra list
+ description: The infras list
content:
application/json:
schema:
diff --git a/front/public/locales/fr/infraManagement.json b/front/public/locales/fr/infraManagement.json
index 2e9908802bc..b470e045c64 100644
--- a/front/public/locales/fr/infraManagement.json
+++ b/front/public/locales/fr/infraManagement.json
@@ -24,6 +24,7 @@
"goToEditionMode": "Éditer",
"goToStandardMode": "Retour à la sélection",
"infraChoice": "Infrastructures",
+ "infraDeleted": "L'infrastructure {{name}} a bien été supprimée.",
"infraManagement": "Gestion des infrastructures",
"infraName": "Nom de l'infrastructure",
"infrasFound_zero": "Aucune insfrastructure trouvée",
diff --git a/front/src/common/InfraSelector/Consts.jsx b/front/src/common/InfraSelector/Consts.jsx
deleted file mode 100644
index a3ca67aaa44..00000000000
--- a/front/src/common/InfraSelector/Consts.jsx
+++ /dev/null
@@ -1,2 +0,0 @@
-export const INFRA_URL = '/editoast/infra/';
-export const INFRA_URL_OLD = '/infra/';
diff --git a/front/src/common/InfraSelector/InfraSelectorEditionActionsBar.tsx b/front/src/common/InfraSelector/InfraSelectorEditionActionsBar.tsx
index a2630becba9..0b0001466f8 100644
--- a/front/src/common/InfraSelector/InfraSelectorEditionActionsBar.tsx
+++ b/front/src/common/InfraSelector/InfraSelectorEditionActionsBar.tsx
@@ -1,40 +1,51 @@
import React, { useState } from 'react';
import { FaCopy, FaDownload, FaLock, FaLockOpen, FaPencilAlt } from 'react-icons/fa';
import { useTranslation } from 'react-i18next';
-import { post, get, put } from 'common/requests';
import { MdCancel, MdCheck } from 'react-icons/md';
import fileDownload from 'js-file-download';
import { Infra, osrdEditoastApi } from 'common/api/osrdEditoastApi';
-import { INFRA_URL } from './Consts';
+import { useDispatch } from 'react-redux';
+import { setFailure } from 'reducers/main';
+import InfraLockState from './consts';
type ActionBarProps = {
infra: Infra;
isFocused?: number;
setIsFocused: (focus?: number) => void;
- getInfrasList: () => void;
inputValue: string;
};
-export default function ActionsBar({
- infra,
- isFocused,
- setIsFocused,
- getInfrasList,
- inputValue,
-}: ActionBarProps) {
+export default function ActionsBar({ infra, isFocused, setIsFocused, inputValue }: ActionBarProps) {
const { t } = useTranslation('infraManagement');
const [isWaiting, setIsWaiting] = useState(false);
+ const dispatch = useDispatch();
+ const [lockInfra] = osrdEditoastApi.usePostInfraByIdLockMutation();
+ const [unlockInfra] = osrdEditoastApi.usePostInfraByIdUnlockMutation();
+ const [getRailjson] = osrdEditoastApi.useLazyGetInfraByIdRailjsonQuery();
const [cloneInfra] = osrdEditoastApi.usePostInfraByIdCloneMutation();
+ const [updateInfra] = osrdEditoastApi.usePutInfraByIdMutation();
- async function handleLockedState(action: string) {
+ async function handleLockedState(action: InfraLockState) {
if (!isWaiting) {
setIsWaiting(true);
try {
- await post(`${INFRA_URL}${infra.id}/${action}/`, {});
- getInfrasList();
- setIsWaiting(false);
+ if (action === InfraLockState.LOCK) {
+ await lockInfra({ id: infra.id });
+ }
+ if (action === InfraLockState.UNLOCK) {
+ await unlockInfra({ id: infra.id });
+ }
} catch (e) {
+ if (e instanceof Error) {
+ dispatch(
+ setFailure({
+ name: e.name,
+ message: e.message,
+ })
+ );
+ }
+ } finally {
setIsWaiting(false);
}
}
@@ -44,10 +55,18 @@ export default function ActionsBar({
if (!isWaiting) {
setIsWaiting(true);
try {
- const railjson = await get(`${INFRA_URL}${infra.id}/railjson/`);
+ const railjson = await getRailjson({ id: infra.id });
fileDownload(JSON.stringify(railjson), `${infra.name}.id${infra.id}.railjson.json`);
- setIsWaiting(false);
} catch (e) {
+ if (e instanceof Error) {
+ dispatch(
+ setFailure({
+ name: e.name,
+ message: e.message,
+ })
+ );
+ }
+ } finally {
setIsWaiting(false);
}
}
@@ -57,14 +76,19 @@ export default function ActionsBar({
if (!isWaiting) {
setIsWaiting(true);
try {
- await cloneInfra({ id: infra.id, name: `${infra.name}_copy` }).unwrap();
- setIsWaiting(false);
+ await cloneInfra({ id: infra.id, name: `${infra.name}_copy` });
} catch (e) {
+ if (e instanceof Error) {
+ dispatch(
+ setFailure({
+ name: e.name,
+ message: e.message,
+ })
+ );
+ }
+ } finally {
setIsWaiting(false);
}
- setTimeout(() => {
- getInfrasList();
- }, 1000);
}
}
@@ -72,11 +96,18 @@ export default function ActionsBar({
if (!isWaiting) {
setIsWaiting(true);
try {
- await put(`${INFRA_URL}${infra.id}/`, { name: inputValue });
- getInfrasList();
+ await updateInfra({ id: infra.id, body: { name: inputValue } });
setIsFocused(undefined);
- setIsWaiting(false);
} catch (e) {
+ if (e instanceof Error) {
+ dispatch(
+ setFailure({
+ name: e.name,
+ message: e.message,
+ })
+ );
+ }
+ } finally {
setIsWaiting(false);
}
}
@@ -122,7 +153,7 @@ export default function ActionsBar({
className="infraslist-item-action unlock"
type="button"
title={t('infraManagement:actions.unlock')}
- onClick={() => handleLockedState('unlock')}
+ onClick={() => handleLockedState(InfraLockState.UNLOCK)}
>
@@ -131,7 +162,7 @@ export default function ActionsBar({
className="infraslist-item-action lock"
type="button"
title={t('infraManagement:actions.lock')}
- onClick={() => handleLockedState('lock')}
+ onClick={() => handleLockedState(InfraLockState.LOCK)}
>
diff --git a/front/src/common/InfraSelector/InfraSelectorEditionActionsBarDelete.jsx b/front/src/common/InfraSelector/InfraSelectorEditionActionsBarDelete.tsx
similarity index 53%
rename from front/src/common/InfraSelector/InfraSelectorEditionActionsBarDelete.jsx
rename to front/src/common/InfraSelector/InfraSelectorEditionActionsBarDelete.tsx
index 5772f9af00f..1d32117bdd0 100644
--- a/front/src/common/InfraSelector/InfraSelectorEditionActionsBarDelete.jsx
+++ b/front/src/common/InfraSelector/InfraSelectorEditionActionsBarDelete.tsx
@@ -1,31 +1,53 @@
import React from 'react';
-import PropTypes from 'prop-types';
-import { deleteRequest } from 'common/requests';
import { useTranslation } from 'react-i18next';
import Countdown from 'react-countdown';
-import { INFRA_URL } from './Consts';
+import { Infra, osrdEditoastApi } from 'common/api/osrdEditoastApi';
+import { useDispatch } from 'react-redux';
+import { setFailure, setSuccess } from 'reducers/main';
-export default function InfraSelectorEditionActionsBarDelete(props) {
- const { getInfrasList, setRunningDelete, infra } = props;
+type InfraSelectorEditionActionsBarDeleteProps = {
+ infra: Infra;
+ setRunningDelete: (infraId?: number) => void;
+};
+
+export default function InfraSelectorEditionActionsBarDelete({
+ infra,
+ setRunningDelete,
+}: InfraSelectorEditionActionsBarDeleteProps) {
const { t } = useTranslation('infraManagement');
+ const dispatch = useDispatch();
+
+ const [deleteInfra] = osrdEditoastApi.useDeleteInfraByIdMutation();
- async function deleteInfra() {
+ async function handleDeleteInfra() {
try {
- await deleteRequest(`${INFRA_URL}${infra.id}/`);
+ await deleteInfra({ id: infra.id });
setRunningDelete(undefined);
- getInfrasList();
+ dispatch(
+ setSuccess({
+ title: t('infraDeleted', { name: infra.name }),
+ text: '',
+ })
+ );
} catch (e) {
- /* empty */
+ if (e instanceof Error) {
+ dispatch(
+ setFailure({
+ name: e.name,
+ message: e.message,
+ })
+ );
+ }
}
}
- const countDownDelete = ({ seconds, completed }) => {
+ const countDownDelete = ({ seconds, completed }: { seconds: number; completed: boolean }) => {
if (completed) {
return (
@@ -59,9 +81,3 @@ export default function InfraSelectorEditionActionsBarDelete(props) {
);
}
-
-InfraSelectorEditionActionsBarDelete.propTypes = {
- getInfrasList: PropTypes.func.isRequired,
- infra: PropTypes.object.isRequired,
- setRunningDelete: PropTypes.func.isRequired,
-};
diff --git a/front/src/common/InfraSelector/InfraSelectorEditionItem.jsx b/front/src/common/InfraSelector/InfraSelectorEditionItem.tsx
similarity index 77%
rename from front/src/common/InfraSelector/InfraSelectorEditionItem.jsx
rename to front/src/common/InfraSelector/InfraSelectorEditionItem.tsx
index 626bdd61caf..fadeadc9ec7 100644
--- a/front/src/common/InfraSelector/InfraSelectorEditionItem.jsx
+++ b/front/src/common/InfraSelector/InfraSelectorEditionItem.tsx
@@ -1,16 +1,26 @@
import React, { useState } from 'react';
-import PropTypes from 'prop-types';
import nextId from 'react-id-generator';
import { FaLock, FaTrash } from 'react-icons/fa';
import InputSNCF from 'common/BootstrapSNCF/InputSNCF';
import { useTranslation } from 'react-i18next';
-import { editoastUpToDateIndicator } from './InfraSelectorModalBodyStandard';
+import { Infra } from 'common/api/osrdEditoastApi';
import ActionsBar from './InfraSelectorEditionActionsBar';
+import { editoastUpToDateIndicator } from './InfraSelectorModalBodyStandard';
import InfraSelectorEditionActionsBarDelete from './InfraSelectorEditionActionsBarDelete';
-export default function InfraSelectorEditionItem(props) {
- const { infra, isFocused, setIsFocused, runningDelete, setRunningDelete, getInfrasList } = props;
+type InfraSelectorEditionItemProps = {
+ infra: Infra;
+ isFocused?: number;
+ setIsFocused: (infraId?: number) => void;
+};
+
+export default function InfraSelectorEditionItem({
+ infra,
+ isFocused,
+ setIsFocused,
+}: InfraSelectorEditionItemProps) {
const [value, setValue] = useState(infra.name);
+ const [runningDelete, setRunningDelete] = useState(undefined);
const { t } = useTranslation('infraManagement');
const handleRunningDelete = () => {
@@ -24,11 +34,7 @@ export default function InfraSelectorEditionItem(props) {
) : null}
{runningDelete === infra.id ? (
-
+
) : null}
{isFocused === infra.id ? null : (
);
}
-
-InfraSelectorEditionItem.defaultProps = {
- isFocused: undefined,
- runningDelete: undefined,
-};
-
-InfraSelectorEditionItem.propTypes = {
- infra: PropTypes.object.isRequired,
- isFocused: PropTypes.number,
- setIsFocused: PropTypes.func.isRequired,
- runningDelete: PropTypes.number,
- setRunningDelete: PropTypes.func.isRequired,
- getInfrasList: PropTypes.func.isRequired,
-};
diff --git a/front/src/common/InfraSelector/InfraSelectorModal.tsx b/front/src/common/InfraSelector/InfraSelectorModal.tsx
index 4a5d50042ae..e8cd1d81735 100644
--- a/front/src/common/InfraSelector/InfraSelectorModal.tsx
+++ b/front/src/common/InfraSelector/InfraSelectorModal.tsx
@@ -20,52 +20,41 @@ const InfraSelectorModal = ({
onInfraChange,
onlySelectionMode = false,
}: InfraSelectorModalProps) => {
- const [infrasList, setInfrasList] = useState([]);
const { t } = useTranslation(['translation', 'infraManagement']);
const [filter, setFilter] = useState('');
const [filteredInfrasList, setFilteredInfrasList] = useState([]);
const [editionMode, setEditionMode] = useState(false);
- const [isFetching, setIsFetching] = useState(false);
- const [getInfra] = osrdEditoastApi.endpoints.getInfra.useLazyQuery();
+ const {
+ data: infrasList,
+ isSuccess,
+ isLoading,
+ } = osrdEditoastApi.useGetInfraQuery({ pageSize: 1000 });
const debouncedFilter = useDebounce(filter, 250);
function filterInfras(infrasListLocal: Infra[]) {
if (debouncedFilter && debouncedFilter !== '') {
- infrasListLocal = infrasList.filter((infra) =>
+ infrasListLocal = infrasListLocal.filter((infra) =>
infra.name.toLowerCase().includes(debouncedFilter.toLowerCase())
);
}
const filteredInfrasListLocal = infrasListLocal
.slice()
.sort((a, b) => a.name.localeCompare(b.name));
-
setFilteredInfrasList(filteredInfrasListLocal);
}
- const getInfrasList = () => {
- setIsFetching(true);
- getInfra()
- .unwrap()
- .then(({ results }) => {
- setInfrasList(results as Infra[]);
- filterInfras(results as Infra[]);
- setIsFetching(false);
- })
- .catch(() => setIsFetching(false));
- };
-
useEffect(() => {
- if (infrasList) {
- filterInfras(infrasList);
+ if (infrasList?.results) {
+ filterInfras(infrasList.results);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedFilter]);
useEffect(() => {
- getInfrasList();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ if (isSuccess && infrasList?.results && infrasList.results.length > 0) {
+ filterInfras(infrasList.results);
+ }
+ }, [isSuccess, infrasList]);
return (
<>
@@ -101,7 +90,7 @@ const InfraSelectorModal = ({
- {isFetching && (
+ {isLoading && (
@@ -111,7 +100,6 @@ const InfraSelectorModal = ({
infrasList={filteredInfrasList}
setFilter={setFilter}
filter={filter}
- getInfrasList={getInfrasList}
/>
) : (
>;
filter: string;
- getInfrasList: () => void;
};
const InfraSelectorModalBodyEdition = ({
infrasList,
setFilter,
filter = '',
- getInfrasList,
}: InfraSelectorModalBodyEditionProps) => {
const [isFocused, setIsFocused] = useState(undefined);
- const [runningDelete, setRunningDelete] = useState(undefined);
const [nameNewInfra, setNameNewInfra] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [selectedFile, setSelectedFile] = useState(undefined);
@@ -71,14 +68,12 @@ const InfraSelectorModalBodyEdition = ({
.unwrap()
.then(() => {
setSelectedFile(undefined);
- getInfrasList();
setErrorMessage(undefined);
});
} else {
postInfra({ body: { name: nameNewInfra } })
.unwrap()
.then(() => {
- getInfrasList();
setErrorMessage(undefined);
});
}
@@ -107,10 +102,7 @@ const InfraSelectorModalBodyEdition = ({
infra={infra}
key={nextId()}
isFocused={isFocused}
- runningDelete={runningDelete}
- setRunningDelete={setRunningDelete}
setIsFocused={setIsFocused}
- getInfrasList={getInfrasList}
/>
))}
diff --git a/front/src/common/InfraSelector/InfraSelectorModalBodyStandard.jsx b/front/src/common/InfraSelector/InfraSelectorModalBodyStandard.tsx
similarity index 78%
rename from front/src/common/InfraSelector/InfraSelectorModalBodyStandard.jsx
rename to front/src/common/InfraSelector/InfraSelectorModalBodyStandard.tsx
index ed1d83c53bb..ae41fd7f52e 100644
--- a/front/src/common/InfraSelector/InfraSelectorModalBodyStandard.jsx
+++ b/front/src/common/InfraSelector/InfraSelectorModalBodyStandard.tsx
@@ -1,5 +1,4 @@
import React, { useContext } from 'react';
-import PropTypes from 'prop-types';
import nextId from 'react-id-generator';
import { FaLock } from 'react-icons/fa';
import InputSNCF from 'common/BootstrapSNCF/InputSNCF';
@@ -8,21 +7,41 @@ import { getInfraID } from 'reducers/osrdconf/selectors';
import { updateInfraID, deleteItinerary } from 'reducers/osrdconf';
import { useTranslation } from 'react-i18next';
import { ModalContext } from 'common/BootstrapSNCF/ModalSNCF/ModalProvider';
+import { Infra } from 'common/api/osrdEditoastApi';
+
+type InfraSelectorModalBodyStandardProps = {
+ filter: string;
+ setFilter: (filterInput: string) => void;
+ infrasList: Infra[];
+ onlySelectionMode: boolean;
+ onInfraChange?: (infraId: number) => void;
+};
// Test coherence between actual & generated version, eg. if editoast is up to date with data
-export function editoastUpToDateIndicator(v, genv) {
- return ●;
+export function editoastUpToDateIndicator(
+ infraVersion: string,
+ infraGeneratedVersion: string | null
+) {
+ return (
+
+ ●
+
+ );
}
-export default function InfraSelectorModalBodyStandard(props) {
- const { infrasList, filter, setFilter, onlySelectionMode, onInfraChange } = props;
-
+export default function InfraSelectorModalBodyStandard({
+ filter = '',
+ setFilter,
+ infrasList,
+ onlySelectionMode = false,
+ onInfraChange,
+}: InfraSelectorModalBodyStandardProps) {
const { t } = useTranslation(['translation', 'infraManagement']);
const dispatch = useDispatch();
const infraID = useSelector(getInfraID);
const { closeModal } = useContext(ModalContext);
- function setInfraID(id) {
+ function setInfraID(id: number) {
dispatch(updateInfraID(id));
if (onInfraChange) onInfraChange(id);
dispatch(deleteItinerary());
@@ -83,17 +102,3 @@ export default function InfraSelectorModalBodyStandard(props) {
>
);
}
-
-InfraSelectorModalBodyStandard.defaultProps = {
- filter: '',
- onlySelectionMode: false,
- onInfraChange: undefined,
-};
-
-InfraSelectorModalBodyStandard.propTypes = {
- filter: PropTypes.string,
- infrasList: PropTypes.array.isRequired,
- setFilter: PropTypes.func.isRequired,
- onlySelectionMode: PropTypes.bool,
- onInfraChange: PropTypes.func,
-};
diff --git a/front/src/common/InfraSelector/consts.ts b/front/src/common/InfraSelector/consts.ts
new file mode 100644
index 00000000000..e5b797fa68a
--- /dev/null
+++ b/front/src/common/InfraSelector/consts.ts
@@ -0,0 +1,6 @@
+enum InfraLockState {
+ LOCK,
+ UNLOCK,
+}
+
+export default InfraLockState;
diff --git a/front/src/common/api/osrdEditoastApi.ts b/front/src/common/api/osrdEditoastApi.ts
index 3ede3e6be0e..ab08574a01b 100644
--- a/front/src/common/api/osrdEditoastApi.ts
+++ b/front/src/common/api/osrdEditoastApi.ts
@@ -72,7 +72,10 @@ const injectedRtkApi = api
query: () => ({ url: `/health/` }),
}),
getInfra: build.query({
- query: () => ({ url: `/infra/` }),
+ query: (queryArg) => ({
+ url: `/infra/`,
+ params: { page: queryArg.page, page_size: queryArg.pageSize },
+ }),
providesTags: ['infra'],
}),
postInfra: build.mutation({
@@ -660,13 +663,18 @@ export type GetElectricalProfileSetByIdLevelOrderApiArg = {
};
export type GetHealthApiResponse = unknown;
export type GetHealthApiArg = void;
-export type GetInfraApiResponse = /** status 200 The infra list */ {
+export type GetInfraApiResponse = /** status 200 The infras list */ {
count: number;
next: any;
previous: any;
results?: Infra[];
};
-export type GetInfraApiArg = void;
+export type GetInfraApiArg = {
+ /** Page number */
+ page?: number;
+ /** Number of elements by page */
+ pageSize?: number;
+};
export type PostInfraApiResponse = /** status 201 The created infra */ Infra;
export type PostInfraApiArg = {
/** Name of the infra to create */