feat: FlowStack 发布系统首个可运行版本 (gin + React)
- Go gin 后端:流水线/节点/连线/运行/日志/GitOps/插件 REST API, SQLite(GORM) 自动建表 + seed,模拟执行引擎 + SSE 实时日志推送, 前端产物 go:embed 嵌入单二进制,一个端口同时服务 API 与页面 - React 19 前端:画布式流水线编辑器(React Flow + Tekton 任务库)、 GitOps 部署、批量发布、发布记录等 14 个模块页面, tRPC 全部替换为 REST(TanStack Query) - 首次启动生成随机密码管理员账号(日志 + data/initial-admin-password.txt) - run.sh 一键构建启动(默认端口 9527,支持 start/stop/restart/build/dev)
This commit is contained in:
commit
04d1342b27
115 files changed
+23268
No files matched your search
@@ -0,0 +1,154 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { Toaster } from 'sonner';
|
||||
import Sidebar from '@/components/Sidebar';
|
||||
import TopBar from '@/components/TopBar';
|
||||
import PipelineFlowEditor from '@/components/flow/PipelineFlowEditor';
|
||||
import BasicInfoPanel from '@/components/BasicInfoPanel';
|
||||
import TriggerPanel from '@/components/TriggerPanel';
|
||||
import VariablesPanel from '@/components/VariablesPanel';
|
||||
import ReleasePanel from '@/components/ReleasePanel';
|
||||
import PipelineList from '@/pages/PipelineList';
|
||||
import EnvironmentManager from '@/pages/EnvironmentManager';
|
||||
import CredentialManager from '@/pages/CredentialManager';
|
||||
import BuildNodeManager from '@/pages/BuildNodeManager';
|
||||
import ToolConfig from '@/pages/ToolConfig';
|
||||
import JenkinsImport from '@/pages/JenkinsImport';
|
||||
import BatchRelease from '@/pages/BatchRelease';
|
||||
import ReleaseRecords from '@/pages/ReleaseRecords';
|
||||
import WebhookConfig from '@/pages/WebhookConfig';
|
||||
import GitOpsDeploy from '@/pages/GitOpsDeploy';
|
||||
import PluginManager from '@/pages/PluginManager';
|
||||
import SystemSettings from '@/pages/SystemSettings';
|
||||
import { pipelineScenarios } from '@/data/pipelineData';
|
||||
|
||||
export type ModuleType = 'pipelines' | 'gitops' | 'batch-release' | 'release-records' | 'environments' | 'credentials' | 'build-nodes' | 'tools' | 'jenkins-import' | 'webhooks' | 'plugins' | 'settings';
|
||||
export type EditorTab = '基本信息' | '流程配置' | '触发设置' | '变量和缓存' | '发布';
|
||||
|
||||
export default function App() {
|
||||
// Module navigation
|
||||
const [activeModule, setActiveModule] = useState<ModuleType>('pipelines');
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
|
||||
// Pipeline list/editor view toggle
|
||||
const [pipelineView, setPipelineView] = useState<'list' | 'editor'>('list');
|
||||
// Current editing pipeline ID for flow editor
|
||||
const [currentPipelineId, setCurrentPipelineId] = useState<number>(1);
|
||||
// Pipeline editor state (only used when in pipeline editor mode)
|
||||
const [activeScenario, setActiveScenario] = useState<'go-backend' | 'vue-frontend'>('go-backend');
|
||||
const [activeTab, setActiveTab] = useState<EditorTab>('流程配置');
|
||||
const [isSimulating, setIsSimulating] = useState(false);
|
||||
const [executionStatus, setExecutionStatus] = useState<'idle' | 'running' | 'success' | 'failed'>('idle');
|
||||
|
||||
const scenario = pipelineScenarios[activeScenario];
|
||||
|
||||
const handleScenarioChange = (key: 'go-backend' | 'vue-frontend') => {
|
||||
setActiveScenario(key);
|
||||
};
|
||||
|
||||
const handleSelectPipeline = useCallback((id: string) => {
|
||||
setCurrentPipelineId(Number(id) || 1);
|
||||
setPipelineView('editor');
|
||||
setActiveTab('流程配置');
|
||||
}, []);
|
||||
|
||||
const handleSimulateRun = useCallback(() => {
|
||||
setIsSimulating(true);
|
||||
setExecutionStatus('running');
|
||||
setTimeout(() => {
|
||||
setIsSimulating(false);
|
||||
setExecutionStatus('success');
|
||||
}, 3000);
|
||||
}, []);
|
||||
|
||||
// Render content based on active module
|
||||
const renderContent = () => {
|
||||
switch (activeModule) {
|
||||
case 'pipelines':
|
||||
if (pipelineView === 'list') {
|
||||
return <PipelineList onSelectPipeline={handleSelectPipeline} />;
|
||||
}
|
||||
// Pipeline editor mode
|
||||
return (
|
||||
<div className="h-full flex flex-col">
|
||||
<TopBar
|
||||
pipelineName={scenario.name}
|
||||
activeTab={activeTab}
|
||||
onTabChange={setActiveTab}
|
||||
onSimulateRun={handleSimulateRun}
|
||||
isSimulating={isSimulating}
|
||||
scenarioKey={activeScenario}
|
||||
onScenarioChange={handleScenarioChange}
|
||||
executionStatus={executionStatus}
|
||||
onBack={() => setPipelineView('list')}
|
||||
/>
|
||||
<div className="flex-1 flex overflow-hidden">
|
||||
{activeTab === '流程配置' && (
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<PipelineFlowEditor pipelineId={currentPipelineId} />
|
||||
</div>
|
||||
)}
|
||||
{activeTab === '基本信息' && (
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<BasicInfoPanel />
|
||||
</div>
|
||||
)}
|
||||
{activeTab === '触发设置' && (
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<TriggerPanel />
|
||||
</div>
|
||||
)}
|
||||
{activeTab === '变量和缓存' && (
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<VariablesPanel />
|
||||
</div>
|
||||
)}
|
||||
{activeTab === '发布' && (
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<ReleasePanel />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
case 'environments':
|
||||
return <EnvironmentManager />;
|
||||
case 'credentials':
|
||||
return <CredentialManager />;
|
||||
case 'build-nodes':
|
||||
return <BuildNodeManager />;
|
||||
case 'tools':
|
||||
return <ToolConfig />;
|
||||
case 'jenkins-import':
|
||||
return <JenkinsImport />;
|
||||
case 'batch-release':
|
||||
return <BatchRelease />;
|
||||
case 'release-records':
|
||||
return <ReleaseRecords />;
|
||||
case 'webhooks':
|
||||
return <WebhookConfig />;
|
||||
case 'gitops':
|
||||
return <GitOpsDeploy />;
|
||||
case 'plugins':
|
||||
return <PluginManager />;
|
||||
case 'settings':
|
||||
return <SystemSettings />;
|
||||
default:
|
||||
return <PipelineList onSelectPipeline={handleSelectPipeline} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-screen w-screen flex overflow-hidden" style={{ background: 'var(--canvas-bg)', color: 'var(--text-primary)' }}>
|
||||
<Toaster position="top-right" richColors />
|
||||
<Sidebar
|
||||
activeModule={activeModule}
|
||||
onModuleChange={setActiveModule}
|
||||
collapsed={sidebarCollapsed}
|
||||
onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
/>
|
||||
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
|
||||
{renderContent()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user