This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new c39684335 blueprint and project 404 redirection & UI message (#8556)
c39684335 is described below

commit c39684335991bcd8550b0f8656ddecedac8372ab
Author: Veet Moradiya <[email protected]>
AuthorDate: Wed Aug 27 08:53:33 2025 +0530

    blueprint and project 404 redirection & UI message (#8556)
---
 config-ui/src/hooks/use-refresh-data.ts            |  9 +++++---
 .../routes/blueprint/detail/blueprint-detail.tsx   | 22 +++++++++++++++-----
 config-ui/src/routes/project/detail/index.tsx      | 24 ++++++++++++++++++----
 3 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/config-ui/src/hooks/use-refresh-data.ts 
b/config-ui/src/hooks/use-refresh-data.ts
index 34fc62474..5e1fa7a0f 100644
--- a/config-ui/src/hooks/use-refresh-data.ts
+++ b/config-ui/src/hooks/use-refresh-data.ts
@@ -26,6 +26,7 @@ export const useRefreshData = <T>(request: (signal: 
AbortSignal) => Promise<T>,
     state: 'ready' | 'pending' | 'error';
     deps?: React.DependencyList;
     data?: T;
+    error?: unknown;  
     abortController?: AbortController;
     timer?: number;
   }>({
@@ -37,15 +38,14 @@ export const useRefreshData = <T>(request: (signal: 
AbortSignal) => Promise<T>,
       data: ref.current.data,
       ready: ref.current.state === 'ready',
       pending: ref.current.state === 'pending',
-      error: ref.current.state === 'error',
+      error: ref.current.error,  
     };
   }
 
-  // When the last state transition has not waited until the new request is 
completed
-  // Reset status to pending
   ref.current.state = 'pending';
   ref.current.deps = deps;
   ref.current.data = undefined;
+  ref.current.error = undefined;
   clearTimeout(ref.current.timer);
   ref.current.abortController?.abort();
   ref.current.timer = window.setTimeout(() => {
@@ -54,6 +54,7 @@ export const useRefreshData = <T>(request: (signal: 
AbortSignal) => Promise<T>,
       .then((data: T) => {
         ref.current.data = data;
         ref.current.state = 'ready';
+        ref.current.error = undefined;
         setVersion((v) => v + 1);
       })
       .catch((err: unknown) => {
@@ -61,6 +62,7 @@ export const useRefreshData = <T>(request: (signal: 
AbortSignal) => Promise<T>,
           return;
         }
         ref.current.state = 'error';
+        ref.current.error = err;
         console.error(err);
         setVersion((v) => v + 1);
       });
@@ -69,5 +71,6 @@ export const useRefreshData = <T>(request: (signal: 
AbortSignal) => Promise<T>,
   return {
     ready: false,
     pending: true,
+    error: undefined,
   };
 };
diff --git a/config-ui/src/routes/blueprint/detail/blueprint-detail.tsx 
b/config-ui/src/routes/blueprint/detail/blueprint-detail.tsx
index 78a7b6e4f..52491bac9 100644
--- a/config-ui/src/routes/blueprint/detail/blueprint-detail.tsx
+++ b/config-ui/src/routes/blueprint/detail/blueprint-detail.tsx
@@ -17,12 +17,13 @@
  */
 
 import { useEffect, useState } from 'react';
-import { useLocation } from 'react-router-dom';
-import { Tabs } from 'antd';
-
+import { useLocation, useNavigate } from 'react-router-dom';
+import { Tabs, message } from 'antd';
+import axios from 'axios';
 import API from '@/api';
 import { PageLoading } from '@/components';
 import { useRefreshData } from '@/hooks';
+import { PATHS } from '@/config';
 
 import { FromEnum } from '../types';
 
@@ -40,16 +41,27 @@ export const BlueprintDetail = ({ id, from }: Props) => {
   const [activeKey, setActiveKey] = useState('status');
 
   const { state } = useLocation();
+  const navigate = useNavigate();
 
   useEffect(() => {
     setActiveKey(state?.activeKey ?? 'status');
   }, [state]);
 
-  const { ready, data } = useRefreshData(async () => {
-    const [bpRes, pipelineRes] = await Promise.all([API.blueprint.get(id), 
API.blueprint.pipelines(id)]);
+  const { ready, data, error } = useRefreshData(async () => {
+    const [bpRes, pipelineRes] = await Promise.all([
+      API.blueprint.get(id),
+      API.blueprint.pipelines(id),
+    ]);
     return [bpRes, pipelineRes.pipelines[0]];
   }, [version]);
 
+  useEffect(() => {
+     if (axios.isAxiosError(error) && error.response?.status === 404) {
+      message.error(`Blueprint not found with id: ${id}`);
+      navigate(PATHS.BLUEPRINTS(), { replace: true });
+    }
+  }, [error, navigate, id]);
+
   const handlRefresh = () => {
     setVersion((v) => v + 1);
   };
diff --git a/config-ui/src/routes/project/detail/index.tsx 
b/config-ui/src/routes/project/detail/index.tsx
index fb37a68eb..7c6a8b2ba 100644
--- a/config-ui/src/routes/project/detail/index.tsx
+++ b/config-ui/src/routes/project/detail/index.tsx
@@ -17,9 +17,11 @@
  */
 
 import { useEffect, useState } from 'react';
-import { useParams, useLocation } from 'react-router-dom';
+import { useParams, useLocation, useNavigate } from 'react-router-dom';
+import axios from 'axios';
+
 import { Helmet } from 'react-helmet';
-import { Tabs } from 'antd';
+import { Tabs, message } from 'antd';
 
 import API from '@/api';
 import { PageHeader, PageLoading } from '@/components';
@@ -39,12 +41,22 @@ export const ProjectDetailPage = () => {
 
   const { pname } = useParams() as { pname: string };
   const { state } = useLocation();
+  const navigate = useNavigate();
 
   useEffect(() => {
     setTabId(state?.tabId ?? 'blueprint');
   }, [state]);
 
-  const { ready, data } = useRefreshData(() => API.project.get(pname), [pname, 
version]);
+  const { ready, data, error } = useRefreshData(() => API.project.get(pname), 
[pname, version]);
+
+  useEffect(() => {
+    if (axios.isAxiosError(error) && error.response?.status === 404) {
+      message.error(`Project not found with project name: ${pname}`);
+      setTimeout(() => {
+        navigate(PATHS.PROJECTS(), { replace: true });
+      }, 100);
+    }
+  }, [error, navigate, pname]);
 
   const handleChangeTabId = (tabId: string) => {
     setTabId(tabId);
@@ -54,10 +66,14 @@ export const ProjectDetailPage = () => {
     setVersion((v) => v + 1);
   };
 
-  if (!ready || !data) {
+  if (!ready && !error) {
     return <PageLoading />;
   }
 
+  if (!data) {
+    return null;
+  }
+
   return (
     <PageHeader
       breadcrumbs={[

Reply via email to