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,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);
|
||||
}
|
||||
Reference in new issue
Block a user