diff --git a/shared/types/index.ts b/shared/types/index.ts index 07cc84aab..1e588ea3b 100644 --- a/shared/types/index.ts +++ b/shared/types/index.ts @@ -438,6 +438,7 @@ export interface ExportEsStatus { created_at: Date; updated_at: Date; user?: User; + error?: string; } export type Answer = { diff --git a/targets/export-elasticsearch/src/repositories/graphql/mutation.ts b/targets/export-elasticsearch/src/repositories/graphql/mutation.ts index b9adb0d28..8e721c079 100644 --- a/targets/export-elasticsearch/src/repositories/graphql/mutation.ts +++ b/targets/export-elasticsearch/src/repositories/graphql/mutation.ts @@ -16,8 +16,8 @@ mutation createExportEsStatus($id: uuid!, $user_id: uuid!, $environment: String! }`; export const updateOneExportEsStatus = ` -mutation updateOneExportEsStatus($id: uuid!, $status: String!, $updated_at: timestamptz) { - update_export_es_status_by_pk(pk_columns: {id: $id}, _set: {status: $status, updated_at: $updated_at}) { +mutation updateOneExportEsStatus($id: uuid!, $status: String!, $updated_at: timestamptz, $error: String) { + update_export_es_status_by_pk(pk_columns: {id: $id}, _set: {status: $status, updated_at: $updated_at, error: $error}) { id environment status @@ -29,26 +29,6 @@ mutation updateOneExportEsStatus($id: uuid!, $status: String!, $updated_at: time } created_at updated_at - } -}`; - -export const updateExportEsStatus = ` -mutation updateExportEsStatus($old_status: String!, $new_status: String!, $updated_at: timestamptz) { - update_export_es_status( - where: {status: {_eq: $old_status }} - _set: {status: $new_status, updated_at: $updated_at}) { - returning { - id - environment - status - user_id - user { - name - email - created_at - } - created_at - updated_at - } + error } }`; diff --git a/targets/export-elasticsearch/src/repositories/graphql/queries.ts b/targets/export-elasticsearch/src/repositories/graphql/queries.ts index 342725bbd..6fc5b6b9a 100644 --- a/targets/export-elasticsearch/src/repositories/graphql/queries.ts +++ b/targets/export-elasticsearch/src/repositories/graphql/queries.ts @@ -1,20 +1,3 @@ -export const getExportEsStatusById = ` -query getExportEsStatusById($id: uuid!) { - export_es_status_by_pk(id: $id) { - id - environment - status - user_id - user { - name - email - created_at - } - created_at - updated_at - } -}`; - export const getAllExport = ` query getAllExport { export_es_status(order_by: {updated_at: desc}) { @@ -29,6 +12,7 @@ query getAllExport { } created_at updated_at + error } }`; @@ -46,6 +30,7 @@ query getExportEsStatusByEnvironments($environment: String!) { } created_at updated_at + error } }`; @@ -63,6 +48,7 @@ query getLatestExportEsStatus($environment: String!) { } created_at updated_at + error } } `; @@ -81,5 +67,6 @@ query getExportEsStatusByStatus($status: String!) { } created_at updated_at + error } }`; diff --git a/targets/export-elasticsearch/src/repositories/status.ts b/targets/export-elasticsearch/src/repositories/status.ts index e3e951399..5f506a239 100644 --- a/targets/export-elasticsearch/src/repositories/status.ts +++ b/targets/export-elasticsearch/src/repositories/status.ts @@ -8,10 +8,8 @@ import { createExportEsStatus, getAllExport, getExportEsStatusByEnvironments, - getExportEsStatusById, getExportEsStatusByStatus, getLatestExportEsStatus, - updateExportEsStatus, updateOneExportEsStatus, } from "./graphql"; @@ -52,7 +50,8 @@ export class ExportRepository { public async updateOne( id: string, status: Status, - updatedAt: Date + updatedAt: Date, + error?: string ): Promise { const res = await gqlClient() .mutation<{ update_export_es_status_by_pk: ExportEsStatus }>( @@ -61,6 +60,7 @@ export class ExportRepository { id, status, updated_at: updatedAt, + error: error ?? null, } ) .toPromise(); @@ -73,46 +73,6 @@ export class ExportRepository { return res.data.update_export_es_status_by_pk; } - public async updateAll( - oldStatus: Status, - newStatus: Status, - updatedAt: Date - ): Promise { - const res = await gqlClient() - .mutation<{ update_export_es_status_by_pk: ExportEsStatus[] }>( - updateExportEsStatus, - { - new_status: newStatus, - old_status: oldStatus, - updated_at: updatedAt, - } - ) - .toPromise(); - if (res.error) { - throw res.error; - } - if (!res.data?.update_export_es_status_by_pk) { - throw new Error("Failed to update, undefined object"); - } - return res.data.update_export_es_status_by_pk; - } - - public async getOneById(id: string): Promise { - const res = await gqlClient() - .query<{ export_es_status_by_pk: ExportEsStatus }>( - getExportEsStatusById, - { id } - ) - .toPromise(); - if (res.error) { - throw res.error; - } - if (!res.data?.export_es_status_by_pk) { - throw new Error("Failed to get, undefined object"); - } - return res.data.export_es_status_by_pk; - } - public async getLatestByEnv( environment: Environment ): Promise { diff --git a/targets/export-elasticsearch/src/services/__test__/fake/export.ts b/targets/export-elasticsearch/src/services/__test__/fake/export.ts index 68f322911..395c766e0 100644 --- a/targets/export-elasticsearch/src/services/__test__/fake/export.ts +++ b/targets/export-elasticsearch/src/services/__test__/fake/export.ts @@ -37,36 +37,7 @@ export class FakeExportRepository { status, updated_at: updatedAt, user_id: "updated-id", - }; - } - - async updateAll( - _oldStatus: Status, - newStatus: Status, - updatedAt: Date - ): Promise { - await wait(100); - return [ - { - created_at: new Date(), - environment: Environment.preproduction, - id: "1", - status: newStatus, - updated_at: updatedAt, - user_id: "updatedAll-id", - }, - ]; - } - - async getOneById(id: string): Promise { - await wait(100); - return { - created_at: new Date(), - environment: Environment.preproduction, - id, - status: Status.completed, - updated_at: new Date(), - user_id: "getOne-id", + error: "error", }; } diff --git a/targets/export-elasticsearch/src/services/export.ts b/targets/export-elasticsearch/src/services/export.ts index c63f2f75f..c5dce4465 100644 --- a/targets/export-elasticsearch/src/services/export.ts +++ b/targets/export-elasticsearch/src/services/export.ts @@ -65,12 +65,12 @@ export class ExportService { Status.completed, new Date() ); - } catch (e) { - console.error(e); + } catch (e: any) { return await this.exportRepository.updateOne( id, Status.failed, - new Date() + new Date(), + e.message ); } } else { diff --git a/targets/export-elasticsearch/src/workers/ingester-preprod.ts b/targets/export-elasticsearch/src/workers/ingester-preprod.ts index 79488302e..d9dad069c 100644 --- a/targets/export-elasticsearch/src/workers/ingester-preprod.ts +++ b/targets/export-elasticsearch/src/workers/ingester-preprod.ts @@ -22,7 +22,6 @@ const ingester = async (): Promise => { ); resolve("Export elasticsearch completed successfully"); } catch (error: unknown) { - console.error("Error during export : ", JSON.stringify(error, null, 2)); reject(error); } }); diff --git a/targets/frontend/src/components/export-es/Status.tsx b/targets/frontend/src/components/export-es/Status.tsx index 1ee6a29cd..e1ff30401 100644 --- a/targets/frontend/src/components/export-es/Status.tsx +++ b/targets/frontend/src/components/export-es/Status.tsx @@ -1,18 +1,44 @@ import { Status as StatusType } from "@shared/types"; -import { MdTimelapse } from "react-icons/md"; -import { Box, Typography } from "@mui/material"; +import { + Box, + CircularProgress, + Popover, + Typography, + Button, + IconButton, +} from "@mui/material"; import { fr } from "@codegouvfr/react-dsfr"; +import React from "react"; +import ContentCopyIcon from "@mui/icons-material/ContentCopy"; type StatusProps = { status?: StatusType; + error?: string; }; -export function Status({ status }: StatusProps): JSX.Element { +export function Status({ status, error }: StatusProps): JSX.Element { + const [anchorEl, setAnchorEl] = React.useState( + null + ); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + const id = open ? "simple-popover" : undefined; + const errorDisplayed = + error ?? "Aucune information sur l'erreur n'a été enregistrée"; + if (!status) { return ( + En cours{" "} - ); } @@ -32,17 +58,50 @@ export function Status({ status }: StatusProps): JSX.Element { case StatusType.running: return ( - En cours{" "} - + + En cours ); case StatusType.failed: return ( - - Erreur - + <> + + + + {errorDisplayed}{" "} + { + navigator.clipboard.writeText(errorDisplayed); + handleClose(); + }} + > + + + + + ); default: return {status}; diff --git a/targets/frontend/src/hooks/exportEs.ts b/targets/frontend/src/hooks/exportEs.ts index 0e4e1aa4a..92d234270 100644 --- a/targets/frontend/src/hooks/exportEs.ts +++ b/targets/frontend/src/hooks/exportEs.ts @@ -14,7 +14,8 @@ type ExportEsState = { export function useExportEs(): [ ExportEsState, () => void, - (environment: Environment, user: User) => void + (environment: Environment, user: User) => void, + (env: Environment) => Date ] { const [state, setState] = useState({ error: null, @@ -57,6 +58,14 @@ export function useExportEs(): [ }); }; + const getLatestDeployDate = (env: Environment) => { + const lastestCompleted = state?.exportData.filter( + (data) => data.status === Status.completed && data.environment === env + )[0]; + + return lastestCompleted?.created_at; + }; + const runExportEs = (environment: Environment, user: User) => { const newExportEs: ExportEsStatus = { created_at: new Date(), @@ -131,5 +140,5 @@ export function useExportEs(): [ }); }; - return [state, getExportEs, runExportEs]; + return [state, getExportEs, runExportEs, getLatestDeployDate]; } diff --git a/targets/frontend/src/modules/export/components/document-list.tsx b/targets/frontend/src/modules/export/components/document-list.tsx index b8d30179a..c8b26352d 100644 --- a/targets/frontend/src/modules/export/components/document-list.tsx +++ b/targets/frontend/src/modules/export/components/document-list.tsx @@ -30,7 +30,7 @@ export default function DocumentList({ {isLoadingDocs ? ( - + ) : ( <> diff --git a/targets/frontend/src/modules/export/components/export.tsx b/targets/frontend/src/modules/export/components/export.tsx index ae94cb40d..57a02544d 100644 --- a/targets/frontend/src/modules/export/components/export.tsx +++ b/targets/frontend/src/modules/export/components/export.tsx @@ -10,15 +10,16 @@ import { Stack, Typography, } from "@mui/material"; -import { FixedSnackBar } from "src/components/utils/SnackBar"; import { ShowDocumentsToUpdateModal } from "./ShowDocumentsToUpdateModal"; +import { FixedSnackBar } from "src/components/utils/SnackBar"; export function Export(): JSX.Element { const [validateExportPreprodModal, setValidateExportPreprodModal] = useState(false); const [validateExportProdModal, setValidateExportProdModal] = useState(false); - const [exportEsState, getExportEs, runExportEs] = useExportEs(); + const [exportEsState, getExportEs, runExportEs, getLatestDeployDate] = + useExportEs(); const { user }: any = useUser(); @@ -28,24 +29,13 @@ export function Export(): JSX.Element { getExportEs(); }, []); - function getLatestDeployDate(env: Environment) { - const lastestCompleted = exportEsState?.exportData.filter( - (data) => data.status === StatusType.completed && data.environment === env - )[0]; - - return lastestCompleted?.created_at; - } - - if (exportEsState.error) { - return ( - -
{JSON.stringify(exportEsState.error, null, 2)}
-
- ); - } - return ( <> + {exportEsState.error && ( + +
{JSON.stringify(exportEsState.error, null, 2)}
+
+ )}

Cette page permet de mettre à jour les données des environnements de{" "} production et pre-production @@ -57,6 +47,8 @@ export function Export(): JSX.Element { color="primary" variant="contained" disabled={ + exportEsState.latestExportPreproduction?.status === + StatusType.running || exportEsState.latestExportProduction?.status === StatusType.running } onClick={() => { @@ -69,7 +61,9 @@ export function Export(): JSX.Element { color="secondary" variant="contained" disabled={ - exportEsState.latestExportPreproduction?.status === "running" + exportEsState.latestExportPreproduction?.status === + StatusType.running || + exportEsState.latestExportProduction?.status === StatusType.running } onClick={() => { setValidateExportPreprodModal(true); @@ -107,14 +101,15 @@ export function Export(): JSX.Element { updated_at, user, status, - }: any) => { + error, + }) => { return ( - {user.name} + {user?.name} @@ -135,7 +130,7 @@ export function Export(): JSX.Element { - + ); diff --git a/targets/frontend/src/pages/api/export.ts b/targets/frontend/src/pages/api/export.ts index 987dcb84d..8ae22bfca 100644 --- a/targets/frontend/src/pages/api/export.ts +++ b/targets/frontend/src/pages/api/export.ts @@ -2,7 +2,8 @@ import { NextApiRequest, NextApiResponse } from "next"; const URL_EXPORT = process.env.URL_EXPORT ?? "http://localhost:8787"; -export default (req: NextApiRequest, res: NextApiResponse) => { +const main = (req: NextApiRequest, res: NextApiResponse) => { + // GET if (req.method === "GET") { const promises = [ fetch(URL_EXPORT + "/export"), @@ -28,6 +29,8 @@ export default (req: NextApiRequest, res: NextApiResponse) => { }); }); } + + // POST if (req.method === "POST") { const { environment, userId } = req.body; fetch(URL_EXPORT + "/export", { @@ -58,3 +61,5 @@ export default (req: NextApiRequest, res: NextApiResponse) => { }); } }; + +export default main; diff --git a/targets/hasura/migrations/default/1702537735282_alter_table_public_export_es_status_add_column_error/down.sql b/targets/hasura/migrations/default/1702537735282_alter_table_public_export_es_status_add_column_error/down.sql new file mode 100644 index 000000000..76c158755 --- /dev/null +++ b/targets/hasura/migrations/default/1702537735282_alter_table_public_export_es_status_add_column_error/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."export_es_status" add column "error" text +-- null; diff --git a/targets/hasura/migrations/default/1702537735282_alter_table_public_export_es_status_add_column_error/up.sql b/targets/hasura/migrations/default/1702537735282_alter_table_public_export_es_status_add_column_error/up.sql new file mode 100644 index 000000000..9778c3a1a --- /dev/null +++ b/targets/hasura/migrations/default/1702537735282_alter_table_public_export_es_status_add_column_error/up.sql @@ -0,0 +1,2 @@ +alter table "public"."export_es_status" add column "error" text + null;