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:
Logan.Li committed 2026-10-27 02:44:10 +08:00
commit 04d1342b27
115 files changed
+23268

No files matched your search

+353
View File
@@ -0,0 +1,353 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
--canvas-bg: #f0f2f5;
--panel-bg: #ffffff;
--panel-bg-secondary: #f8f9fa;
--border-color: #d0d7de;
--border-color-light: #e1e4e8;
--text-primary: #1f2328;
--text-secondary: #656d76;
--text-tertiary: #8c959f;
--accent-blue: #0969da;
--accent-blue-light: #ddf4ff;
--accent-green: #1a7f37;
--accent-red: #cf222e;
--accent-amber: #9a6700;
--accent-purple: #8250df;
--node-source: #0969da;
--node-build: #9a6700;
--node-deploy: #1a7f37;
--node-test: #8250df;
--node-approval: #bc4c00;
--node-custom: #6e7781;
--line-active: #0969da;
--line-success: #1a7f37;
--line-pending: #d0d7de;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--canvas-bg: #0d1117;
--panel-bg: #161b22;
--panel-bg-secondary: #21262d;
--border-color: #30363d;
--border-color-light: #21262d;
--text-primary: #c9d1d9;
--text-secondary: #8b949e;
--text-tertiary: #6e7681;
--accent-blue: #58a6ff;
--accent-blue-light: #388bfd;
--accent-green: #3fb950;
--accent-red: #f85149;
--accent-amber: #d29922;
--accent-purple: #bc8cff;
--node-source: #58a6ff;
--node-build: #d29922;
--node-deploy: #3fb950;
--node-test: #bc8cff;
--node-approval: #f0883e;
--node-custom: #8b949e;
--line-active: #58a6ff;
--line-success: #3fb950;
--line-pending: #30363d;
}
body {
@apply bg-background text-foreground;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
overflow: hidden;
}
}
/* Dot grid background */
.dot-grid-bg {
background-color: var(--canvas-bg);
background-image: radial-gradient(circle, #d0d7de 1px, transparent 1px);
background-size: 20px 20px;
}
.dark .dot-grid-bg {
background-color: var(--canvas-bg);
background-image: radial-gradient(circle, #30363d 1px, transparent 1px);
background-size: 20px 20px;
}
/* Animated flowing line */
.flowing-line {
stroke-dasharray: 8 4;
animation: flowLine 0.8s linear infinite;
}
@keyframes flowLine {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -24;
}
}
/* Running status pulse */
.running-pulse {
animation: runningPulse 1.5s ease-in-out infinite;
}
@keyframes runningPulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.6);
opacity: 0.5;
}
}
/* Glow effect for active connections */
.glow-line {
filter: drop-shadow(0 0 2px rgba(9, 105, 218, 0.4));
}
.dark .glow-line {
filter: drop-shadow(0 0 3px rgba(88, 166, 255, 0.5));
}
/* Node hover lift - subtle */
.node-card {
transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.node-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
/* Scrollbar styling */
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #d0d7de;
border-radius: 3px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #8c959f;
}
.dark .custom-scrollbar::-webkit-scrollbar-thumb {
background: #30363d;
}
.dark .custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #484f58;
}
/* Minimap styling */
.minimap-bg {
background: rgba(255, 255, 255, 0.95);
border: 1px solid var(--border-color);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
.dark .minimap-bg {
background: rgba(22, 27, 34, 0.95);
border-color: var(--border-color);
}
/* Tab indicator animation */
.tab-indicator {
transition: left 0.3s ease, width 0.3s ease;
}
/* Draggable item ghost */
.dragging-ghost {
opacity: 0.8;
transform: rotate(2deg);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
/* Panel transitions */
.panel-transition {
transition: transform 0.3s ease, width 0.3s ease;
}
/* Flow particle on line */
@keyframes flowParticle {
0% {
offset-distance: 0%;
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
offset-distance: 100%;
opacity: 0;
}
}
.flow-particle {
animation: flowParticle 2s linear infinite;
offset-path: path('M0,0 C50,0 50,50 100,50');
}
/* Node selection ring - subtle */
@keyframes selectionRing {
0% {
box-shadow: 0 0 0 0px rgba(9, 105, 218, 0.25);
}
50% {
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.15);
}
100% {
box-shadow: 0 0 0 0px rgba(9, 105, 218, 0.25);
}
}
.selection-ring {
animation: selectionRing 2s ease-in-out infinite;
box-shadow: 0 0 0 1.5px var(--accent-blue);
}
/* Button hover effects */
.btn-primary {
background: var(--accent-blue);
color: white;
transition: opacity 0.15s ease;
}
.btn-primary:hover {
opacity: 0.9;
}
/* Responsive panel collapse */
@media (max-width: 1280px) {
.left-panel {
width: 48px !important;
}
}
/* Tab content fade-in animation */
.tab-content-fade {
animation: tabContentFadeIn 200ms ease-out;
}
@keyframes tabContentFadeIn {
0% {
opacity: 0;
transform: translateY(4px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* Focus ring for inputs - thinner */
input:focus,
textarea:focus {
outline: none;
ring: 1px;
ring-color: rgba(9, 105, 218, 0.25);
}
/* Script editor styling */
.script-editor {
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
}
/* Context menu styling */
.context-menu {
background: var(--panel-bg);
border: 1px solid var(--border-color);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
border-radius: 6px;
padding: 4px;
min-width: 160px;
}
.context-menu-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
font-size: 13px;
cursor: pointer;
transition: background 0.1s ease;
}
.context-menu-item:hover {
background: var(--panel-bg-secondary);
}
.context-menu-item-danger {
color: var(--accent-red);
}
.context-menu-item-danger:hover {
background: rgba(207, 34, 46, 0.08);
}