|
@@ -1,7 +1,7 @@
|
|
|
'use client'
|
|
|
|
|
|
import type { MouseEventHandler } from 'react'
|
|
|
-import { useRef, useState } from 'react'
|
|
|
+import { useMemo, useRef, useState } from 'react'
|
|
|
import { useRouter } from 'next/navigation'
|
|
|
import { useContext } from 'use-context-selector'
|
|
|
import { useTranslation } from 'react-i18next'
|
|
@@ -10,25 +10,38 @@ import Uploader from './uploader'
|
|
|
import Button from '@/app/components/base/button'
|
|
|
import Modal from '@/app/components/base/modal'
|
|
|
import { ToastContext } from '@/app/components/base/toast'
|
|
|
-import { importApp } from '@/service/apps'
|
|
|
+import {
|
|
|
+ importApp,
|
|
|
+ importAppFromUrl,
|
|
|
+} from '@/service/apps'
|
|
|
import { useAppContext } from '@/context/app-context'
|
|
|
import { useProviderContext } from '@/context/provider-context'
|
|
|
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
|
|
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
|
|
import { getRedirection } from '@/utils/app-redirection'
|
|
|
+import cn from '@/utils/classnames'
|
|
|
|
|
|
type CreateFromDSLModalProps = {
|
|
|
show: boolean
|
|
|
onSuccess?: () => void
|
|
|
onClose: () => void
|
|
|
+ activeTab?: string
|
|
|
+ dslUrl?: string
|
|
|
}
|
|
|
|
|
|
-const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProps) => {
|
|
|
+export enum CreateFromDSLModalTab {
|
|
|
+ FROM_FILE = 'from-file',
|
|
|
+ FROM_URL = 'from-url',
|
|
|
+}
|
|
|
+
|
|
|
+const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDSLModalTab.FROM_FILE, dslUrl = '' }: CreateFromDSLModalProps) => {
|
|
|
const { push } = useRouter()
|
|
|
const { t } = useTranslation()
|
|
|
const { notify } = useContext(ToastContext)
|
|
|
const [currentFile, setDSLFile] = useState<File>()
|
|
|
const [fileContent, setFileContent] = useState<string>()
|
|
|
+ const [currentTab, setCurrentTab] = useState(activeTab)
|
|
|
+ const [dslUrlValue, setDslUrlValue] = useState(dslUrl)
|
|
|
|
|
|
const readFile = (file: File) => {
|
|
|
const reader = new FileReader()
|
|
@@ -53,15 +66,26 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProp
|
|
|
|
|
|
const isCreatingRef = useRef(false)
|
|
|
const onCreate: MouseEventHandler = async () => {
|
|
|
+ if (currentTab === CreateFromDSLModalTab.FROM_FILE && !currentFile)
|
|
|
+ return
|
|
|
+ if (currentTab === CreateFromDSLModalTab.FROM_URL && !dslUrlValue)
|
|
|
+ return
|
|
|
if (isCreatingRef.current)
|
|
|
return
|
|
|
isCreatingRef.current = true
|
|
|
- if (!currentFile)
|
|
|
- return
|
|
|
try {
|
|
|
- const app = await importApp({
|
|
|
- data: fileContent || '',
|
|
|
- })
|
|
|
+ let app
|
|
|
+
|
|
|
+ if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
|
|
|
+ app = await importApp({
|
|
|
+ data: fileContent || '',
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (currentTab === CreateFromDSLModalTab.FROM_URL) {
|
|
|
+ app = await importAppFromUrl({
|
|
|
+ url: dslUrlValue || '',
|
|
|
+ })
|
|
|
+ }
|
|
|
if (onSuccess)
|
|
|
onSuccess()
|
|
|
if (onClose)
|
|
@@ -76,24 +100,95 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProp
|
|
|
isCreatingRef.current = false
|
|
|
}
|
|
|
|
|
|
+ const tabs = [
|
|
|
+ {
|
|
|
+ key: CreateFromDSLModalTab.FROM_FILE,
|
|
|
+ label: t('app.importFromDSLFile'),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: CreateFromDSLModalTab.FROM_URL,
|
|
|
+ label: t('app.importFromDSLUrl'),
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ const buttonDisabled = useMemo(() => {
|
|
|
+ if (isAppsFull)
|
|
|
+ return true
|
|
|
+ if (currentTab === CreateFromDSLModalTab.FROM_FILE)
|
|
|
+ return !currentFile
|
|
|
+ if (currentTab === CreateFromDSLModalTab.FROM_URL)
|
|
|
+ return !dslUrlValue
|
|
|
+ return false
|
|
|
+ }, [isAppsFull, currentTab, currentFile, dslUrlValue])
|
|
|
+
|
|
|
return (
|
|
|
<Modal
|
|
|
- className='px-8 py-6 max-w-[520px] w-[520px] rounded-xl'
|
|
|
+ className='p-0 w-[520px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'
|
|
|
isShow={show}
|
|
|
onClose={() => { }}
|
|
|
>
|
|
|
- <div className='relative pb-2 text-xl font-medium leading-[30px] text-gray-900'>{t('app.createFromConfigFile')}</div>
|
|
|
- <div className='absolute right-4 top-4 p-2 cursor-pointer' onClick={onClose}>
|
|
|
- <RiCloseLine className='w-4 h-4 text-gray-500' />
|
|
|
+ <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 items-center w-8 h-8 cursor-pointer'
|
|
|
+ onClick={() => onClose()}
|
|
|
+ >
|
|
|
+ <RiCloseLine className='w-5 h-5 text-text-tertiary' />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <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 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 w-full h-[2px] bg-util-colors-blue-brand-blue-brand-600'></div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ ))
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ <div className='px-6 py-4'>
|
|
|
+ {
|
|
|
+ currentTab === CreateFromDSLModalTab.FROM_FILE && (
|
|
|
+ <Uploader
|
|
|
+ className='mt-0'
|
|
|
+ file={currentFile}
|
|
|
+ updateFile={handleFile}
|
|
|
+ />
|
|
|
+ )
|
|
|
+ }
|
|
|
+ {
|
|
|
+ currentTab === CreateFromDSLModalTab.FROM_URL && (
|
|
|
+ <div>
|
|
|
+ <div className='mb-1 system-md-semibold leading6'>DSL URL</div>
|
|
|
+ <input
|
|
|
+ placeholder={t('app.importFromDSLUrlPlaceholder') || ''}
|
|
|
+ className='px-2 w-full h-8 border border-components-input-border-active bg-components-input-bg-active rounded-lg outline-none appearance-none placeholder:text-components-input-text-placeholder system-sm-regular'
|
|
|
+ value={dslUrlValue}
|
|
|
+ onChange={e => setDslUrlValue(e.target.value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
</div>
|
|
|
- <Uploader
|
|
|
- file={currentFile}
|
|
|
- updateFile={handleFile}
|
|
|
- />
|
|
|
- {isAppsFull && <AppsFull loc='app-create-dsl' />}
|
|
|
- <div className='pt-6 flex justify-end'>
|
|
|
+ {isAppsFull && (
|
|
|
+ <div className='px-6'>
|
|
|
+ <AppsFull className='mt-0' loc='app-create-dsl' />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <div className='flex justify-end px-6 py-5'>
|
|
|
<Button className='mr-2' onClick={onClose}>{t('app.newApp.Cancel')}</Button>
|
|
|
- <Button disabled={isAppsFull || !currentFile} variant="primary" onClick={onCreate}>{t('app.newApp.Create')}</Button>
|
|
|
+ <Button disabled={buttonDisabled} variant="primary" onClick={onCreate}>{t('app.newApp.Create')}</Button>
|
|
|
</div>
|
|
|
</Modal>
|
|
|
)
|