Skip to content

Commit

Permalink
feat: update launchpad network status (labring#5444)
Browse files Browse the repository at this point in the history
* fix read api

* update network

* update

* update

* update style
  • Loading branch information
zjy365 authored Mar 7, 2025
1 parent bf1e746 commit bd94480
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 27 deletions.
2 changes: 1 addition & 1 deletion frontend/desktop/src/components/desktop_content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export default function Desktop(props: any) {
const { data: notification } = await getGlobalNotification();
if (!notification) return;
const newID = notification?.uid;
const title = notification?.i18n[i18n.language].title;
const title = notification?.i18n[i18n?.language]?.title;

if (notification.licenseFrontend) {
message({
Expand Down
46 changes: 25 additions & 21 deletions frontend/desktop/src/pages/api/notification/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,56 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const { name } = req.body;
const payload = await verifyAccessToken(req.headers);
if (!payload) return jsonRes(res, { code: 401, message: 'failed to get info' });

const namespace = payload.workspaceId;
const _kc = await getUserKubeconfigNotPatch(payload.userCrName);
if (!_kc) return jsonRes(res, { code: 404, message: 'user is not found' });
const realKc = switchKubeconfigNamespace(_kc, namespace);
const kc = K8sApi(realKc);

const kc = K8sApi(switchKubeconfigNamespace(_kc, namespace));
const meta: CRDMeta = {
group: 'notification.sealos.io',
version: 'v1',
namespace,
plural: 'notifications'
};

// crd patch
const patch = [
{
op: 'add',
path: '/metadata/labels',
value: {
isRead: 'true'
}
value: { isRead: 'true' }
}
];
// const patch = [{ op: 'remove', path: '/metadata/labels/isRead' }]; // dev
const results = [];

let result = [];
for (const n of name) {
try {
let temp = await UpdateCRD(kc, meta, n, patch);
result.push(temp?.body);
const temp = await UpdateCRD(kc, meta, n, patch);
results.push(temp?.body);
} catch (err: any) {
if (err?.body?.code === 403) {
const temp = {
name: n,
reason: err?.body?.reason,
message: err?.body?.message,
code: 403
};

jsonRes(res, { data: temp });
} else {
throw err;
return jsonRes(res, {
data: {
name: n,
reason: err?.body?.reason,
message: err?.body?.message,
code: 403
}
});
}
return jsonRes(res, {
code: 500,
data: {
name: n,
message: err?.message || 'Unknown error'
}
});
}
}
jsonRes(res, { data: result });

return jsonRes(res, { data: results });
} catch (err) {
jsonRes(res, { code: 500, data: err });
return jsonRes(res, { code: 500, data: err });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -317,5 +317,7 @@
"selected": "Selected",
"please_select": "Please Select",
"refetching_success": "Refresh Successful",
"refresh": "refresh"
"refresh": "refresh",
"Ready": "Preparing",
"Accessible": "Accessible"
}
Original file line number Diff line number Diff line change
Expand Up @@ -317,5 +317,7 @@
"selected": "已选中",
"please_select": "请选择",
"refetching_success": "刷新成功",
"refresh": "刷新"
"refresh": "刷新",
"Ready": "准备中",
"Accessible": "可访问"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export const IconMap = {
container: require('./icons/container.svg').default,
arrowRight: require('./icons/arrowRight.svg').default,
chart: require('./icons/chart.svg').default,
export: require('./icons/export.svg').default
export: require('./icons/export.svg').default,
loading: require('./icons/loading.svg').default
};

export type IconType = keyof typeof IconMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import dayjs from 'dayjs';
import { useTranslation } from 'next-i18next';
import { useMemo } from 'react';
import MonitorModal from './MonitorModal';
import { useNetworkStatus } from '@/hooks/useNetworkStatus';

const AppMainInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => {
const { t } = useTranslation();
Expand All @@ -33,6 +34,18 @@ const AppMainInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => {
})),
[app]
);
const networkStatuses = useNetworkStatus(networks);

const statusMap = useMemo(
() =>
networkStatuses.reduce((acc, status) => {
if (status.data?.url) {
acc[status.data.url] = status.data;
}
return acc;
}, {} as Record<string, { isReady?: boolean; error?: string }>),
[networkStatuses]
);

return (
<Box p={'24px'} position={'relative'}>
Expand Down Expand Up @@ -110,7 +123,60 @@ const AppMainInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => {
</Flex>
</th>
<th>
<Flex alignItems={'center'} justifyContent={'space-between'}>
<Flex alignItems={'center'} gap={'2px'} justifyContent={'space-between'}>
{network.public && (
<>
{statusMap[network.public]?.isReady ? (
<Center
fontSize={'12px'}
fontWeight={400}
bg={'rgba(3, 152, 85, 0.05)'}
color={'#039855'}
borderRadius={'full'}
p={'2px 4px'}
gap={'2px'}
minW={'63px'}
>
<Center
w={'6px'}
h={'6px'}
borderRadius={'full'}
bg={'#039855'}
></Center>
{t('Accessible')}
</Center>
) : (
<Center
fontSize={'12px'}
fontWeight={400}
bg={'rgba(17, 24, 36, 0.05)'}
color={'#485264'}
borderRadius={'full'}
p={'2px 4px'}
gap={'2px'}
minW={'63px'}
>
<MyIcon
name={'loading'}
w={'12px'}
h={'12px'}
animation={'spin 1s linear infinite'}
sx={{
'@keyframes spin': {
'0%': {
transform: 'rotate(0deg)'
},
'100%': {
transform: 'rotate(360deg)'
}
}
}}
/>
{t('Ready')}
</Center>
)}
</>
)}
<MyTooltip
label={network.public ? t('Open Link') : ''}
placement={'bottom-start'}
Expand All @@ -126,9 +192,12 @@ const AppMainInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => {
}
: {})}
>
{network.public || '-'}
<Flex alignItems={'center'} gap={2}>
{network.public || '-'}
</Flex>
</Box>
</MyTooltip>

{!!network.public && (
<Center
flexShrink={0}
Expand Down
46 changes: 46 additions & 0 deletions frontend/providers/applaunchpad/src/hooks/useNetworkStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useQueries } from '@tanstack/react-query';

interface NetworkStatus {
url: string;
isReady: boolean;
error?: string;
}

interface ApiResponse {
code: number;
data?: { ready: boolean };
message?: string;
error?: string;
}

export const useNetworkStatus = (networks: { inline: string; public: string }[]) => {
const urlPairs = networks
.map((network) => network.public)
.filter(Boolean)
.map((originalUrl) => ({
originalUrl,
fetchUrl: originalUrl.replace(/^(wss|grpcs):\/\//, 'https://')
}));

return useQueries({
queries: urlPairs.map(({ originalUrl, fetchUrl }) => ({
queryKey: ['networkStatus', originalUrl],
queryFn: async (): Promise<NetworkStatus> => {
const response = await fetch(`/api/check-ready?url=${encodeURIComponent(fetchUrl)}`);
const data: ApiResponse = await response.json();
if (data.code !== 200) {
throw new Error(data.message || data.error || 'Service not ready');
}

return {
url: originalUrl,
isReady: data.data?.ready ?? false
};
},
retry: 5,
retryDelay: (attemptIndex: number) => Math.min(1000 * Math.pow(2, attemptIndex), 30000),
refetchIntervalInBackground: false,
staleTime: 1000 * 60 * 5
}))
} as const);
};
46 changes: 46 additions & 0 deletions frontend/providers/applaunchpad/src/pages/api/check-ready.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(request: NextApiRequest, res: NextApiResponse) {
try {
const { url } = request.query as { url: string };
if (!url) {
return jsonRes(res, {
code: 400,
error: '缺少 URL 参数'
});
}

const response = await fetch(url);

if (response.status === 503) {
return jsonRes(res, {
code: 503,
message: 'Service Unavailable (503)'
});
}

const text = await response.text();
if (text.includes('upstream not health')) {
return jsonRes(res, {
code: 503,
message: 'Upstream not healthy'
});
}

return jsonRes(res, {
code: 200,
data: {
ready: true
}
});
} catch (error: any) {
console.error(error);
return jsonRes(res, {
code: 500,
error: error?.message
});
}
}

0 comments on commit bd94480

Please sign in to comment.