/* * @Author: ZhaoYing * @Date: 2026-02-03 16:34:12 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-03-19 21:29:45 */ /** * Application Management Page * Displays and manages all applications in the workspace * Supports creating, editing, and deleting applications */ import React, { useState, useRef, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, App, Select, Space, Dropdown, type SegmentedProps, Flex, Form } from 'antd'; import clsx from 'clsx'; import { useSearchParams } from 'react-router-dom' import ApplicationModal, { types } from './components/ApplicationModal'; import type { Application, ApplicationModalRef, Query, UploadWorkflowModalRef } from './types'; import SearchInput from '@/components/SearchInput' import { getApplicationListUrl, deleteApplication, copyApplication } from '@/api/application' import PageScrollList, { type PageScrollListRef } from '@/components/PageScrollList' import { formatDateTime } from '@/utils/format'; import UploadWorkflowModal from './components/UploadWorkflowModal' import UploadModal from './components/UploadModal' import PageTabs from '@/components/PageTabs' import MySharing from './MySharing' import RbCard from '@/components/RbCard' import RbButton from '@/components/RbButton' import RbDescriptions from '@/components/RbDescriptions' const tabKeys = ['apps', 'sharing', 'myShare'] /** * Application management main component */ const ApplicationManagement: React.FC = () => { const { t } = useTranslation(); const { modal } = App.useApp(); const [searchParams] = useSearchParams() const applicationModalRef = useRef(null); const scrollListRef = useRef(null) const uploadWorkflowModalRef = useRef(null); const uploadModalRef = useRef(null); const [form] = Form.useForm() const query = Form.useWatch([], form) const [activeTab, setActiveTab] = useState('apps'); useEffect(() => { // Convert URLSearchParams to a plain object for easier access const data = Object.fromEntries(searchParams) const { type } = data form.setFieldValue('type', type || undefined) }, [searchParams]) /** Refresh application list */ const refresh = () => { scrollListRef.current?.refresh(); } /** Open create application modal */ const handleCreate = () => { applicationModalRef.current?.handleOpen(); } /** Navigate to application configuration page */ const handleEdit = (item: Application) => { let url = `/#/application/config/${item.id}` if (item.is_shared) { url += `/${activeTab}` } window.open(url); } /** Delete application with confirmation */ const handleDelete = (item: Application) => { modal.confirm({ title: t('common.confirmDeleteDesc', { name: item.name }), okText: t('common.delete'), cancelText: t('common.cancel'), okType: 'danger', onOk: () => { deleteApplication(item.id) .then(() => { refresh(); }) .catch(() => { console.error('Failed to delete application'); }); } }) } const handleImport = () => { uploadWorkflowModalRef.current?.handleOpen() } const handleClick = ({ key }: { key: string }) => { switch (key) { case 'thirdParty': handleImport() break; case 'import': uploadModalRef.current?.handleOpen() } } const formatTabItems = useMemo(() => { return tabKeys.map(value => ({ value, label: t(`application.${value}`), })) }, [tabKeys, t]) /** Handle tab change */ const handleChangeTab = (value: SegmentedProps['value']) => { setActiveTab(value as string); form.resetFields() } const handleCopy = (item: Application) => { modal.confirm({ title: t('application.confirmCopyDesc', { app: item.name }), okText: t('common.copy'), cancelText: t('common.cancel'), onOk: () => { copyApplication(item.id) .then(() => { setActiveTab('apps') }) } }); } return ( <>
{activeTab !== 'myShare' &&