| | |
| | | import { useRouter } from 'next/navigation' |
| | | import { useContext } from 'use-context-selector' |
| | | import { useTranslation } from 'react-i18next' |
| | | import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react' |
| | | import { useDebounceFn, useKeyPress } from 'ahooks' |
| | | import { RiCloseLine } from '@remixicon/react' |
| | | import Uploader from './uploader' |
| | | import Button from '@/app/components/base/button' |
| | | import Input from '@/app/components/base/input' |
| | |
| | | import { NEED_REFRESH_APP_LIST_KEY } from '@/config' |
| | | import { getRedirection } from '@/utils/app-redirection' |
| | | import cn from '@/utils/classnames' |
| | | import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks' |
| | | import { noop } from 'lodash-es' |
| | | |
| | | type CreateFromDSLModalProps = { |
| | | show: boolean |
| | |
| | | const [showErrorModal, setShowErrorModal] = useState(false) |
| | | const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>() |
| | | const [importId, setImportId] = useState<string>() |
| | | const { handleCheckPluginDependencies } = usePluginDependencies() |
| | | |
| | | const readFile = (file: File) => { |
| | | const reader = new FileReader() |
| | |
| | | |
| | | if (!response) |
| | | return |
| | | const { id, status, app_id, app_mode, imported_dsl_version, current_dsl_version } = response |
| | | |
| | | const { id, status, app_id, imported_dsl_version, current_dsl_version } = response |
| | | if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) { |
| | | if (onSuccess) |
| | | onSuccess() |
| | |
| | | children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'), |
| | | }) |
| | | localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') |
| | | if (app_id) |
| | | await handleCheckPluginDependencies(app_id) |
| | | getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push) |
| | | getRedirection(isCurrentWorkspaceEditor, { id: app_id }, push) |
| | | } |
| | | else if (status === DSLImportStatus.PENDING) { |
| | | setVersions({ |
| | |
| | | notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) |
| | | } |
| | | } |
| | | // eslint-disable-next-line unused-imports/no-unused-vars |
| | | catch (e) { |
| | | notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) |
| | | } |
| | | isCreatingRef.current = false |
| | | } |
| | | |
| | | const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 }) |
| | | |
| | | useKeyPress(['meta.enter', 'ctrl.enter'], () => { |
| | | if (show && !isAppsFull && ((currentTab === CreateFromDSLModalTab.FROM_FILE && currentFile) || (currentTab === CreateFromDSLModalTab.FROM_URL && dslUrlValue))) |
| | | handleCreateApp() |
| | | }) |
| | | |
| | | useKeyPress('esc', () => { |
| | | if (show && !showErrorModal) |
| | | onClose() |
| | | }) |
| | | |
| | | const onDSLConfirm: MouseEventHandler = async () => { |
| | | try { |
| | |
| | | import_id: importId, |
| | | }) |
| | | |
| | | const { status, app_id, app_mode } = response |
| | | const { status, app_id } = response |
| | | |
| | | if (status === DSLImportStatus.COMPLETED) { |
| | | if (onSuccess) |
| | |
| | | type: 'success', |
| | | message: t('app.newApp.appCreated'), |
| | | }) |
| | | if (app_id) |
| | | await handleCheckPluginDependencies(app_id) |
| | | localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') |
| | | getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push) |
| | | getRedirection(isCurrentWorkspaceEditor, { id: app_id }, push) |
| | | } |
| | | else if (status === DSLImportStatus.FAILED) { |
| | | notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) |
| | | } |
| | | } |
| | | // eslint-disable-next-line unused-imports/no-unused-vars |
| | | catch (e) { |
| | | notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) |
| | | } |
| | |
| | | return ( |
| | | <> |
| | | <Modal |
| | | className='w-[520px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-0 shadow-xl' |
| | | className='p-0 w-[520px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl' |
| | | isShow={show} |
| | | onClose={noop} |
| | | onClose={() => { }} |
| | | > |
| | | <div className='title-2xl-semi-bold flex items-center justify-between pb-3 pl-6 pr-5 pt-6 text-text-primary'> |
| | | <div className='flex items-center justify-between pt-6 pl-6 pr-5 pb-3 text-text-primary title-2xl-semi-bold'> |
| | | {t('app.importFromDSL')} |
| | | <div |
| | | className='flex h-8 w-8 cursor-pointer items-center' |
| | | className='flex items-center w-8 h-8 cursor-pointer' |
| | | onClick={() => onClose()} |
| | | > |
| | | <RiCloseLine className='h-5 w-5 text-text-tertiary' /> |
| | | <RiCloseLine className='w-5 h-5 text-text-tertiary' /> |
| | | </div> |
| | | </div> |
| | | <div className='system-md-semibold flex h-9 items-center space-x-6 border-b border-divider-subtle px-6 text-text-tertiary'> |
| | | <div className='flex items-center px-6 h-9 space-x-6 system-md-semibold text-text-tertiary border-b border-divider-subtle'> |
| | | { |
| | | tabs.map(tab => ( |
| | | <div |
| | | key={tab.key} |
| | | className={cn( |
| | | 'relative flex h-full cursor-pointer items-center', |
| | | 'relative flex items-center h-full cursor-pointer', |
| | | currentTab === tab.key && 'text-text-primary', |
| | | )} |
| | | onClick={() => setCurrentTab(tab.key)} |
| | |
| | | {tab.label} |
| | | { |
| | | currentTab === tab.key && ( |
| | | <div className='absolute bottom-0 h-[2px] w-full bg-util-colors-blue-brand-blue-brand-600'></div> |
| | | <div className='absolute bottom-0 w-full h-[2px] bg-util-colors-blue-brand-blue-brand-600'></div> |
| | | ) |
| | | } |
| | | </div> |
| | |
| | | { |
| | | currentTab === CreateFromDSLModalTab.FROM_URL && ( |
| | | <div> |
| | | <div className='system-md-semibold mb-1 text-text-secondary'>DSL URL</div> |
| | | <div className='mb-1 system-md-semibold leading6'>DSL URL</div> |
| | | <Input |
| | | placeholder={t('app.importFromDSLUrlPlaceholder') || ''} |
| | | value={dslUrlValue} |
| | |
| | | )} |
| | | <div className='flex justify-end px-6 py-5'> |
| | | <Button className='mr-2' onClick={onClose}>{t('app.newApp.Cancel')}</Button> |
| | | <Button |
| | | disabled={buttonDisabled} |
| | | variant="primary" |
| | | onClick={handleCreateApp} |
| | | className="gap-1" |
| | | > |
| | | <span>{t('app.newApp.Create')}</span> |
| | | <div className='flex gap-0.5'> |
| | | <RiCommandLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' /> |
| | | <RiCornerDownLeftLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' /> |
| | | </div> |
| | | </Button> |
| | | <Button disabled={buttonDisabled} variant="primary" onClick={onCreate}>{t('app.newApp.Create')}</Button> |
| | | </div> |
| | | </Modal> |
| | | <Modal |
| | |
| | | onClose={() => setShowErrorModal(false)} |
| | | className='w-[480px]' |
| | | > |
| | | <div className='flex flex-col items-start gap-2 self-stretch pb-4'> |
| | | <div className='title-2xl-semi-bold text-text-primary'>{t('app.newApp.appCreateDSLErrorTitle')}</div> |
| | | <div className='system-md-regular flex grow flex-col text-text-secondary'> |
| | | <div className='flex pb-4 flex-col items-start gap-2 self-stretch'> |
| | | <div className='text-text-primary title-2xl-semi-bold'>{t('app.newApp.appCreateDSLErrorTitle')}</div> |
| | | <div className='flex flex-grow flex-col text-text-secondary system-md-regular'> |
| | | <div>{t('app.newApp.appCreateDSLErrorPart1')}</div> |
| | | <div>{t('app.newApp.appCreateDSLErrorPart2')}</div> |
| | | <br /> |
| | |
| | | <div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions?.systemVersion}</span></div> |
| | | </div> |
| | | </div> |
| | | <div className='flex items-start justify-end gap-2 self-stretch pt-6'> |
| | | <div className='flex pt-6 justify-end items-start gap-2 self-stretch'> |
| | | <Button variant='secondary' onClick={() => setShowErrorModal(false)}>{t('app.newApp.Cancel')}</Button> |
| | | <Button variant='primary' destructive onClick={onDSLConfirm}>{t('app.newApp.Confirm')}</Button> |
| | | </div> |