From 8786ebdbcaa483c1b3f88c78b52bf1a27e65f9a9 Mon Sep 17 00:00:00 2001 From: Joel Date: Mon, 27 Oct 2025 10:58:57 +0800 Subject: [PATCH] feat: support use tempalte in create app --- web/app/components/apps/index.tsx | 107 +++++++++++++++++- web/app/components/apps/list.tsx | 13 ++- web/app/components/apps/new-app-card.tsx | 10 +- web/app/components/explore/app-card/index.tsx | 2 +- web/context/app-list-context.ts | 2 + 5 files changed, 129 insertions(+), 5 deletions(-) diff --git a/web/app/components/apps/index.tsx b/web/app/components/apps/index.tsx index c02741705f..ba611a597b 100644 --- a/web/app/components/apps/index.tsx +++ b/web/app/components/apps/index.tsx @@ -4,8 +4,15 @@ import List from './list' import useDocumentTitle from '@/hooks/use-document-title' import { useTranslation } from 'react-i18next' import AppListContext from '@/context/app-list-context' -import { useState } from 'react' +import { useCallback, useState } from 'react' import type { CurrentTryAppParams } from '@/context/explore-context' +import TryApp from '../explore/try-app' +import type { CreateAppModalProps } from '../explore/create-app-modal' +import CreateAppModal from '../explore/create-app-modal' +import { fetchAppDetail } from '@/service/explore' +import { DSLImportMode } from '@/models/app' +import { useImportDSL } from '@/hooks/use-import-dsl' +import DSLConfirmModal from '../app/create-from-dsl-modal/dsl-confirm-modal' const Apps = () => { const { t } = useTranslation() @@ -14,7 +21,11 @@ const Apps = () => { useEducationInit() const [currentTryAppParams, setCurrentTryAppParams] = useState(undefined) + const currApp = currentTryAppParams?.app const [isShowTryAppPanel, setIsShowTryAppPanel] = useState(false) + const hideTryAppPanel = useCallback(() => { + setIsShowTryAppPanel(false) + }, []) const setShowTryAppPanel = (showTryAppPanel: boolean, params?: CurrentTryAppParams) => { if (showTryAppPanel) setCurrentTryAppParams(params) @@ -22,15 +33,107 @@ const Apps = () => { setCurrentTryAppParams(undefined) setIsShowTryAppPanel(showTryAppPanel) } + const [isShowCreateModal, setIsShowCreateModal] = useState(false) + + const handleShowFromTryApp = useCallback(() => { + setIsShowCreateModal(true) + }, []) + + const [controlRefreshList, setControlRefreshList] = useState(0) + const [controlHideCreateFromTemplatePanel, setControlHideCreateFromTemplatePanel] = useState(0) + const onSuccess = useCallback(() => { + setControlRefreshList(prev => prev + 1) + setControlHideCreateFromTemplatePanel(prev => prev + 1) + }, []) + + const [showDSLConfirmModal, setShowDSLConfirmModal] = useState(false) + + const { + handleImportDSL, + handleImportDSLConfirm, + versions, + isFetching, + } = useImportDSL() + + const onConfirmDSL = useCallback(async () => { + await handleImportDSLConfirm({ + onSuccess, + }) + }, [handleImportDSLConfirm, onSuccess]) + + const onCreate: CreateAppModalProps['onConfirm'] = async ({ + name, + icon_type, + icon, + icon_background, + description, + }) => { + hideTryAppPanel() + + const { export_data } = await fetchAppDetail( + currApp?.app.id as string, + ) + const payload = { + mode: DSLImportMode.YAML_CONTENT, + yaml_content: export_data, + name, + icon_type, + icon, + icon_background, + description, + } + await handleImportDSL(payload, { + onSuccess: () => { + setIsShowCreateModal(false) + }, + onPending: () => { + setShowDSLConfirmModal(true) + }, + }) + } return (
- + + {isShowTryAppPanel && ( + + )} + + { + showDSLConfirmModal && ( + setShowDSLConfirmModal(false)} + onConfirm={onConfirmDSL} + confirmDisabled={isFetching} + /> + ) + } + + {isShowCreateModal && ( + setIsShowCreateModal(false)} + /> + )}
) diff --git a/web/app/components/apps/list.tsx b/web/app/components/apps/list.tsx index 4ee9a6d6d5..49cba78c5b 100644 --- a/web/app/components/apps/list.tsx +++ b/web/app/components/apps/list.tsx @@ -1,5 +1,6 @@ 'use client' +import type { FC } from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import { useRouter, @@ -66,7 +67,12 @@ const getKey = ( return null } -const List = () => { +type Props = { + controlRefreshList: number +} +const List: FC = ({ + controlRefreshList, +}) => { const { t } = useTranslation() const { systemFeatures } = useGlobalPublicStore() const router = useRouter() @@ -112,6 +118,11 @@ const List = () => { }, ) + useEffect(() => { + if (controlRefreshList > 0) + mutate() + }, [controlRefreshList]) + const anchorRef = useRef(null) const options = [ { value: 'all', text: t('app.types.all'), icon: }, diff --git a/web/app/components/apps/new-app-card.tsx b/web/app/components/apps/new-app-card.tsx index 7a10bc8527..8d051e9ecf 100644 --- a/web/app/components/apps/new-app-card.tsx +++ b/web/app/components/apps/new-app-card.tsx @@ -1,6 +1,6 @@ 'use client' -import React, { useMemo, useState } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import { useRouter, useSearchParams, @@ -11,6 +11,8 @@ import { useProviderContext } from '@/context/provider-context' import { FileArrow01, FilePlus01, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files' import cn from '@/utils/classnames' import dynamic from 'next/dynamic' +import AppListContext from '@/context/app-list-context' +import { useContextSelector } from 'use-context-selector' const CreateAppModal = dynamic(() => import('@/app/components/app/create-app-modal'), { ssr: false, @@ -52,6 +54,12 @@ const CreateAppCard = ({ return undefined }, [dslUrl]) + const controlHideCreateFromTemplatePanel = useContextSelector(AppListContext, ctx => ctx.controlHideCreateFromTemplatePanel) + useEffect(() => { + if (controlHideCreateFromTemplatePanel > 0) + setShowNewAppTemplateDialog(false) + }, [controlHideCreateFromTemplatePanel]) + return (