|
|
|
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next' |
|
|
|
import { useDebounceFn } from 'ahooks' |
|
|
|
import { |
|
|
|
RiApps2Line, |
|
|
|
RiDragDropLine, |
|
|
|
RiExchange2Line, |
|
|
|
RiFile4Line, |
|
|
|
RiMessage3Line, |
|
|
|
@@ -16,7 +17,8 @@ import { |
|
|
|
} from '@remixicon/react' |
|
|
|
import AppCard from './AppCard' |
|
|
|
import NewAppCard from './NewAppCard' |
|
|
|
import useAppsQueryState from './hooks/useAppsQueryState' |
|
|
|
import useAppsQueryState from './hooks/use-apps-query-state' |
|
|
|
import { useDSLDragDrop } from './hooks/use-dsl-drag-drop' |
|
|
|
import type { AppListResponse } from '@/models/app' |
|
|
|
import { fetchAppList } from '@/service/apps' |
|
|
|
import { useAppContext } from '@/context/app-context' |
|
|
|
@@ -29,6 +31,7 @@ import { useStore as useTagStore } from '@/app/components/base/tag-management/st |
|
|
|
import TagManagementModal from '@/app/components/base/tag-management' |
|
|
|
import TagFilter from '@/app/components/base/tag-management/filter' |
|
|
|
import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label' |
|
|
|
import CreateFromDSLModal from '@/app/components/app/create-from-dsl-modal' |
|
|
|
|
|
|
|
const getKey = ( |
|
|
|
pageIndex: number, |
|
|
|
@@ -67,6 +70,9 @@ const Apps = () => { |
|
|
|
const [tagFilterValue, setTagFilterValue] = useState<string[]>(tagIDs) |
|
|
|
const [searchKeywords, setSearchKeywords] = useState(keywords) |
|
|
|
const newAppCardRef = useRef<HTMLDivElement>(null) |
|
|
|
const containerRef = useRef<HTMLDivElement>(null) |
|
|
|
const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(false) |
|
|
|
const [droppedDSLFile, setDroppedDSLFile] = useState<File | undefined>() |
|
|
|
const setKeywords = useCallback((keywords: string) => { |
|
|
|
setQuery(prev => ({ ...prev, keywords })) |
|
|
|
}, [setQuery]) |
|
|
|
@@ -74,6 +80,17 @@ const Apps = () => { |
|
|
|
setQuery(prev => ({ ...prev, tagIDs })) |
|
|
|
}, [setQuery]) |
|
|
|
|
|
|
|
const handleDSLFileDropped = useCallback((file: File) => { |
|
|
|
setDroppedDSLFile(file) |
|
|
|
setShowCreateFromDSLModal(true) |
|
|
|
}, []) |
|
|
|
|
|
|
|
const { dragging } = useDSLDragDrop({ |
|
|
|
onDSLFileDropped: handleDSLFileDropped, |
|
|
|
containerRef, |
|
|
|
enabled: isCurrentWorkspaceEditor, |
|
|
|
}) |
|
|
|
|
|
|
|
const { data, isLoading, error, setSize, mutate } = useSWRInfinite( |
|
|
|
(pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, isCreatedByMe, tagIDs, searchKeywords), |
|
|
|
fetchAppList, |
|
|
|
@@ -151,47 +168,81 @@ const Apps = () => { |
|
|
|
|
|
|
|
return ( |
|
|
|
<> |
|
|
|
<div className='sticky top-0 z-10 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]'> |
|
|
|
<TabSliderNew |
|
|
|
value={activeTab} |
|
|
|
onChange={setActiveTab} |
|
|
|
options={options} |
|
|
|
/> |
|
|
|
<div className='flex items-center gap-2'> |
|
|
|
<CheckboxWithLabel |
|
|
|
className='mr-2' |
|
|
|
label={t('app.showMyCreatedAppsOnly')} |
|
|
|
isChecked={isCreatedByMe} |
|
|
|
onChange={handleCreatedByMeChange} |
|
|
|
/> |
|
|
|
<TagFilter type='app' value={tagFilterValue} onChange={handleTagsChange} /> |
|
|
|
<Input |
|
|
|
showLeftIcon |
|
|
|
showClearIcon |
|
|
|
wrapperClassName='w-[200px]' |
|
|
|
value={keywords} |
|
|
|
onChange={e => handleKeywordsChange(e.target.value)} |
|
|
|
onClear={() => handleKeywordsChange('')} |
|
|
|
<div ref={containerRef} className='relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-background-body'> |
|
|
|
{dragging && ( |
|
|
|
<div className="absolute inset-0 z-50 m-0.5 rounded-2xl border-2 border-dashed border-components-dropzone-border-accent bg-[rgba(21,90,239,0.14)] p-2"> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
|
|
|
|
<div className='sticky top-0 z-10 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]'> |
|
|
|
<TabSliderNew |
|
|
|
value={activeTab} |
|
|
|
onChange={setActiveTab} |
|
|
|
options={options} |
|
|
|
/> |
|
|
|
<div className='flex items-center gap-2'> |
|
|
|
<CheckboxWithLabel |
|
|
|
className='mr-2' |
|
|
|
label={t('app.showMyCreatedAppsOnly')} |
|
|
|
isChecked={isCreatedByMe} |
|
|
|
onChange={handleCreatedByMeChange} |
|
|
|
/> |
|
|
|
<TagFilter type='app' value={tagFilterValue} onChange={handleTagsChange} /> |
|
|
|
<Input |
|
|
|
showLeftIcon |
|
|
|
showClearIcon |
|
|
|
wrapperClassName='w-[200px]' |
|
|
|
value={keywords} |
|
|
|
onChange={e => handleKeywordsChange(e.target.value)} |
|
|
|
onClear={() => handleKeywordsChange('')} |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
{(data && data[0].total > 0) |
|
|
|
? <div className='relative grid grow grid-cols-1 content-start gap-4 px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'> |
|
|
|
{isCurrentWorkspaceEditor |
|
|
|
&& <NewAppCard ref={newAppCardRef} onSuccess={mutate} />} |
|
|
|
{data.map(({ data: apps }) => apps.map(app => ( |
|
|
|
<AppCard key={app.id} app={app} onRefresh={mutate} /> |
|
|
|
)))} |
|
|
|
</div> |
|
|
|
: <div className='relative grid grow grid-cols-1 content-start gap-4 overflow-hidden px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'> |
|
|
|
{isCurrentWorkspaceEditor |
|
|
|
&& <NewAppCard ref={newAppCardRef} className='z-10' onSuccess={mutate} />} |
|
|
|
<NoAppsFound /> |
|
|
|
</div>} |
|
|
|
|
|
|
|
{isCurrentWorkspaceEditor && ( |
|
|
|
<div |
|
|
|
className={`flex items-center justify-center gap-2 py-4 ${dragging ? 'text-text-accent' : 'text-text-quaternary'}`} |
|
|
|
role="region" |
|
|
|
aria-label={t('app.newApp.dropDSLToCreateApp')} |
|
|
|
> |
|
|
|
<RiDragDropLine className="h-4 w-4" /> |
|
|
|
<span className="system-xs-regular">{t('app.newApp.dropDSLToCreateApp')}</span> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
<CheckModal /> |
|
|
|
<div ref={anchorRef} className='h-0'> </div> |
|
|
|
{showTagManagementModal && ( |
|
|
|
<TagManagementModal type='app' show={showTagManagementModal} /> |
|
|
|
)} |
|
|
|
</div> |
|
|
|
{(data && data[0].total > 0) |
|
|
|
? <div className='relative grid grow grid-cols-1 content-start gap-4 px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'> |
|
|
|
{isCurrentWorkspaceEditor |
|
|
|
&& <NewAppCard ref={newAppCardRef} onSuccess={mutate} />} |
|
|
|
{data.map(({ data: apps }) => apps.map(app => ( |
|
|
|
<AppCard key={app.id} app={app} onRefresh={mutate} /> |
|
|
|
)))} |
|
|
|
</div> |
|
|
|
: <div className='relative grid grow grid-cols-1 content-start gap-4 overflow-hidden px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'> |
|
|
|
{isCurrentWorkspaceEditor |
|
|
|
&& <NewAppCard ref={newAppCardRef} className='z-10' onSuccess={mutate} />} |
|
|
|
<NoAppsFound /> |
|
|
|
</div>} |
|
|
|
<CheckModal /> |
|
|
|
<div ref={anchorRef} className='h-0'> </div> |
|
|
|
{showTagManagementModal && ( |
|
|
|
<TagManagementModal type='app' show={showTagManagementModal} /> |
|
|
|
|
|
|
|
{showCreateFromDSLModal && ( |
|
|
|
<CreateFromDSLModal |
|
|
|
show={showCreateFromDSLModal} |
|
|
|
onClose={() => { |
|
|
|
setShowCreateFromDSLModal(false) |
|
|
|
setDroppedDSLFile(undefined) |
|
|
|
}} |
|
|
|
onSuccess={() => { |
|
|
|
setShowCreateFromDSLModal(false) |
|
|
|
setDroppedDSLFile(undefined) |
|
|
|
mutate() |
|
|
|
}} |
|
|
|
droppedFile={droppedDSLFile} |
|
|
|
/> |
|
|
|
)} |
|
|
|
</> |
|
|
|
) |