diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index c59d36c6b7c0..50c7c1f4bb63 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -1502,6 +1502,9 @@ importers: sealos-desktop-sdk: specifier: workspace:^ version: link:../../packages/client-sdk + swiper: + specifier: ^11.0.5 + version: 11.0.5 typescript: specifier: 5.2.2 version: 5.2.2 @@ -16150,6 +16153,11 @@ packages: stable: 0.1.8 dev: true + /swiper@11.0.5: + resolution: {integrity: sha512-rhCwupqSyRnWrtNzWzemnBLMoyYuoDgGgspAm/8iBD3jCvAWycPLH4Z3TB0O5520DHLzMx94yUMH/B9Efpa48w==} + engines: {node: '>= 4.7.0'} + dev: false + /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true diff --git a/frontend/providers/applaunchpad/src/services/monitorFetch.ts b/frontend/providers/applaunchpad/src/services/monitorFetch.ts index 044392139e23..83a345939034 100644 --- a/frontend/providers/applaunchpad/src/services/monitorFetch.ts +++ b/frontend/providers/applaunchpad/src/services/monitorFetch.ts @@ -2,7 +2,7 @@ import { AxiosRequestConfig } from 'axios'; export const monitorFetch = async (props: AxiosRequestConfig, kubeconfig: string) => { const { url, params } = props; - const queryString = new URLSearchParams(params).toString(); + const queryString = typeof params === 'object' ? new URLSearchParams(params).toString() : params; const requestOptions = { method: 'GET', headers: { @@ -10,8 +10,18 @@ export const monitorFetch = async (props: AxiosRequestConfig, kubeconfig: string } }; const doMain = process.env.MONITOR_URL || 'http://monitor-system.cloud.sealos.run'; - const response = await fetch(`${doMain}${url}?${queryString}`, requestOptions).then((res) => - res.json() - ); - return response; + + try { + const response = await fetch(`${doMain}${url}?${queryString}`, requestOptions); + + if (!response.ok) { + throw new Error(`Error monitorFetch ${response.status}`); + } + + const jsonResponse = await response.json(); + return jsonResponse; + } catch (error) { + console.error('Error monitorFetch:', error); + throw error; + } }; diff --git a/frontend/providers/template/arrow-right.svg b/frontend/providers/template/arrow-right.svg new file mode 100644 index 000000000000..15c8bc9e312b --- /dev/null +++ b/frontend/providers/template/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/providers/template/package.json b/frontend/providers/template/package.json index 5178614a302d..be1ec5db44a4 100644 --- a/frontend/providers/template/package.json +++ b/frontend/providers/template/package.json @@ -59,6 +59,7 @@ "remark-unwrap-images": "^3.0.1", "sass": "^1.68.0", "sealos-desktop-sdk": "workspace:^", + "swiper": "^11.0.5", "typescript": "5.2.2", "zustand": "^4.4.1" }, diff --git a/frontend/providers/template/src/components/Banner/index.tsx b/frontend/providers/template/src/components/Banner/index.tsx new file mode 100644 index 000000000000..f5dc25e44128 --- /dev/null +++ b/frontend/providers/template/src/components/Banner/index.tsx @@ -0,0 +1,183 @@ +import { Box, Flex, Image, Text } from '@chakra-ui/react'; +import { useRef } from 'react'; +import { Autoplay } from 'swiper/modules'; +import { Swiper, SwiperRef, SwiperSlide, useSwiper } from 'swiper/react'; +import 'swiper/css'; +import { ArrowRightIcon } from '../icons/ArrowRight'; + +export const SlideData = [ + { + image: + 'https://images.unsplash.com/photo-1546768292-fb12f6c92568?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80', + bg: '#824DFF', + title: '1111', + desc: 'Build the tools you can’t buy off the shelf', + borderRadius: '8px', + icon: 'https://jsd.onmicrosoft.cn/gh/appsmithorg/appsmith@release/static/logo.png' + }, + { + image: + 'https://images.unsplash.com/photo-1501446529957-6226bd447c46?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1489&q=80', + bg: '#3770FE', + title: '222', + desc: 'Make AI more knowledgeable about you', + borderRadius: '8px', + icon: 'https://jsd.onmicrosoft.cn/gh/appsmithorg/appsmith@release/static/logo.png' + }, + { + image: + 'https://images.unsplash.com/photo-1483729558449-99ef09a8c325?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80', + bg: '#824DFF', + title: '333', + desc: 'Build the tools you can’t buy off the shelf', + borderRadius: '8px', + icon: 'https://jsd.onmicrosoft.cn/gh/appsmithorg/appsmith@release/static/logo.png' + }, + { + image: + 'https://images.unsplash.com/photo-1475189778702-5ec9941484ae?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1351&q=80', + bg: '#824DFF', + title: '4444', + desc: 'Build the tools you can’t buy off the shelf', + borderRadius: '8px', + icon: 'https://jsd.onmicrosoft.cn/gh/appsmithorg/appsmith@release/static/logo.png' + } +]; + +export default function Banner() { + const swiperRef = useRef(null); + const swiper = useSwiper(); + + const handlePrev = () => { + if (swiperRef.current) { + swiperRef.current?.swiper.slidePrev(); + } + }; + + const handleNext = () => { + if (swiperRef.current) { + swiperRef.current?.swiper.slideNext(); + } + }; + + return ( + + + {SlideData.map((item, index) => ( + + + + + + + + + + {item.title} + + + + {item.desc} + + + {`slide-${index}`} + + + + + + + + + {SlideData[(index + 1) % SlideData.length].title} + + + + {SlideData[(index + 1) % SlideData.length].desc} + + + {`slide-${index}`} + + + + ))} + + + + + + + + + ); +} diff --git a/frontend/providers/template/src/components/icons/ArrowRight.tsx b/frontend/providers/template/src/components/icons/ArrowRight.tsx new file mode 100644 index 000000000000..e062da394840 --- /dev/null +++ b/frontend/providers/template/src/components/icons/ArrowRight.tsx @@ -0,0 +1,16 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const ArrowRightIcon = (props: IconProps) => ( + + + +); diff --git a/frontend/providers/template/src/components/icons/index.ts b/frontend/providers/template/src/components/icons/index.ts index b9e62018e695..fb9bdcb1522a 100644 --- a/frontend/providers/template/src/components/icons/index.ts +++ b/frontend/providers/template/src/components/icons/index.ts @@ -3,3 +3,4 @@ export * from './Share'; export * from './HomePage'; export * from './HtmlIcon'; export * from './MdIcon'; +export * from './ArrowRight'; diff --git a/frontend/providers/template/src/components/layout/appmenu.tsx b/frontend/providers/template/src/components/layout/appmenu.tsx index 1d7ceb19d1b9..7f59f361d7a8 100644 --- a/frontend/providers/template/src/components/layout/appmenu.tsx +++ b/frontend/providers/template/src/components/layout/appmenu.tsx @@ -1,16 +1,38 @@ -import { Box, Flex, Input, InputGroup, InputLeftElement, Text } from '@chakra-ui/react'; +import { useCachedStore } from '@/store/cached'; +import { useSearchStore } from '@/store/search'; +import { getLangStore, setLangStore } from '@/utils/cookieUtils'; +import { Box, Flex, FlexProps, Input, InputGroup, InputLeftElement, Text } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; -import SideBar from './sidebar'; import { useRouter } from 'next/router'; +import { useEffect } from 'react'; import MyIcon from '../Icon'; -import { useGlobalStore } from '@/store/global'; -import { useMemo } from 'react'; -import { useSearchStore } from '@/store/search'; +import SideBar from './sidebar'; export default function AppMenu({ isMobile }: { isMobile: boolean }) { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const router = useRouter(); const { searchValue, setSearchValue } = useSearchStore(); + const { insideCloud, setInsideCloud } = useCachedStore(); + + const changeI18n = async (newLang: string) => { + const lastLang = getLangStore(); + if (lastLang !== newLang && i18n?.changeLanguage) { + i18n.changeLanguage(newLang); + setLangStore(newLang); + } + }; + + const baseStyle: FlexProps = { + position: 'absolute', + justifyContent: 'center', + alignItems: 'center', + bg: 'rgba(150, 153, 180, 0.15)', + userSelect: 'none' + }; + + useEffect(() => { + setInsideCloud(!(window.top === window)); + }, [setInsideCloud]); return ( @@ -49,26 +71,48 @@ export default function AppMenu({ isMobile }: { isMobile: boolean }) { )} - - - router.push('/develop')}> - - {!isMobile && ( + {isMobile ? ( + router.push('/develop')}> + + + ) : ( + router.push('/develop')}> + {t('develop.Debugging Template')} - )} - + + )} + {insideCloud && ( + { + changeI18n(i18n?.language === 'en' ? 'zh' : 'en'); + }}> + {i18n?.language === 'en' ? 'En' : '中'} + + )} ); } diff --git a/frontend/providers/template/src/pages/api/listTemplate.ts b/frontend/providers/template/src/pages/api/listTemplate.ts index bc4b1b94c381..e85a704ba29a 100644 --- a/frontend/providers/template/src/pages/api/listTemplate.ts +++ b/frontend/providers/template/src/pages/api/listTemplate.ts @@ -41,24 +41,21 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< try { if (!hasAddCron) { + hasAddCron = true; cron.schedule('*/5 * * * *', async () => { const result = await (await fetch(`${baseurl}/api/updateRepo`)).json(); - console.log('scheduling cron: */5 * * * *', result); + console.log(`scheduling cron ${new Date().toString()}`, result); }); - hasAddCron = true; } - if (fs.existsSync(jsonPath)) { - console.log(1); - const templates = readTemplates(jsonPath, cdnUrl); - return jsonRes(res, { data: templates, code: 200 }); - } else { - console.log(2); + if (!fs.existsSync(jsonPath)) { + console.log(`${baseurl}/api/updateRepo`); await fetch(`${baseurl}/api/updateRepo`); - return jsonRes(res, { data: [], code: 201 }); } + + const templates = readTemplates(jsonPath, cdnUrl); + jsonRes(res, { data: templates, code: 200 }); } catch (error) { - console.log(error); jsonRes(res, { code: 500, data: 'error' }); } } diff --git a/frontend/providers/template/src/pages/api/updateRepo.ts b/frontend/providers/template/src/pages/api/updateRepo.ts index c21d6c8bfcc8..290f0fa5b3d5 100644 --- a/frontend/providers/template/src/pages/api/updateRepo.ts +++ b/frontend/providers/template/src/pages/api/updateRepo.ts @@ -98,7 +98,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< readFileList(_targetPath, fileList); const templateStaticMap: { [key: string]: number } = await GetTemplateStatic(); - console.log(templateStaticMap); let jsonObjArr: unknown[] = []; fileList.forEach((item: any) => { @@ -124,7 +123,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< jsonRes(res, { data: `success update template ${repoHttpUrl} branch ${branch}`, code: 200 }); } catch (err: any) { - console.log(err, '===update repo log==='); jsonRes(res, { code: 500, error: err diff --git a/frontend/providers/template/src/pages/index.tsx b/frontend/providers/template/src/pages/index.tsx index 3750448e28d7..47f84396ec6f 100644 --- a/frontend/providers/template/src/pages/index.tsx +++ b/frontend/providers/template/src/pages/index.tsx @@ -1,3 +1,5 @@ +import Banner from '@/components/Banner'; +import { GET } from '@/services/request'; import { useCachedStore } from '@/store/cached'; import { useSearchStore } from '@/store/search'; import { TemplateType } from '@/types/app'; @@ -15,24 +17,34 @@ import { Text, Tooltip } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; import { customAlphabet } from 'nanoid'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; import { MouseEvent, useEffect, useMemo } from 'react'; const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'); -export default function AppList({ tempaltes }: { tempaltes: any }) { +export default function AppList() { const { t } = useTranslation(); const router = useRouter(); const { searchValue } = useSearchStore(); const { setInsideCloud, insideCloud } = useCachedStore(); + const { data: FastDeployTemplates, refetch } = useQuery( + ['listTemplte'], + () => GET('/api/listTemplate'), + { + refetchInterval: 5 * 60 * 1000, + staleTime: 5 * 60 * 1000 + } + ); + const filterData = useMemo(() => { - const searchResults = tempaltes?.filter((item: TemplateType) => { + const searchResults = FastDeployTemplates?.filter((item: TemplateType) => { return item?.metadata?.name?.toLowerCase().includes(searchValue.toLowerCase()); }); - return searchValue ? searchResults : tempaltes; - }, [tempaltes, searchValue]); + return searchValue ? searchResults : FastDeployTemplates; + }, [FastDeployTemplates, searchValue]); const goDeploy = (name: string) => { if (!name) return; @@ -72,7 +84,8 @@ export default function AppList({ tempaltes }: { tempaltes: any }) { background={'linear-gradient(180deg, #FFF 0%, rgba(255, 255, 255, 0.70) 100%)'} py={'36px'} px="42px"> - {!!tempaltes?.length ? ( + {/* */} + {!!FastDeployTemplates?.length ? (