Flowfile 0.3.0__py3-none-any.whl → 0.3.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Flowfile might be problematic. Click here for more details.

Files changed (149) hide show
  1. flowfile/__init__.py +13 -6
  2. flowfile/__main__.py +50 -15
  3. flowfile/api.py +383 -0
  4. flowfile/readme.md +130 -0
  5. flowfile/web/__init__.py +155 -0
  6. flowfile/web/static/assets/AirbyteReader-1ac35765.css +314 -0
  7. flowfile/web/static/assets/AirbyteReader-cb0c1d4a.js +921 -0
  8. flowfile/web/static/assets/CrossJoin-41efa4cb.css +100 -0
  9. flowfile/web/static/assets/CrossJoin-a514fa59.js +153 -0
  10. flowfile/web/static/assets/DatabaseConnectionSettings-0c04b2e5.css +77 -0
  11. flowfile/web/static/assets/DatabaseConnectionSettings-f2cecf33.js +151 -0
  12. flowfile/web/static/assets/DatabaseManager-30fa27e5.css +64 -0
  13. flowfile/web/static/assets/DatabaseManager-83ee3c98.js +484 -0
  14. flowfile/web/static/assets/DatabaseReader-dc0c6881.js +426 -0
  15. flowfile/web/static/assets/DatabaseReader-f50c6558.css +158 -0
  16. flowfile/web/static/assets/DatabaseWriter-2f570e53.css +96 -0
  17. flowfile/web/static/assets/DatabaseWriter-5afe9f8d.js +312 -0
  18. flowfile/web/static/assets/ExploreData-5bdae813.css +45 -0
  19. flowfile/web/static/assets/ExploreData-c7ee19cf.js +118306 -0
  20. flowfile/web/static/assets/ExternalSource-17b23a01.js +225 -0
  21. flowfile/web/static/assets/ExternalSource-e37b6275.css +94 -0
  22. flowfile/web/static/assets/Filter-90856b4f.js +238 -0
  23. flowfile/web/static/assets/Filter-a9d08ba1.css +20 -0
  24. flowfile/web/static/assets/Formula-38b71e9e.js +197 -0
  25. flowfile/web/static/assets/Formula-d60a74f4.css +17 -0
  26. flowfile/web/static/assets/FuzzyMatch-6857de82.css +254 -0
  27. flowfile/web/static/assets/FuzzyMatch-d0f1fe81.js +422 -0
  28. flowfile/web/static/assets/GoogleSheet-854294a4.js +2616 -0
  29. flowfile/web/static/assets/GoogleSheet-92084da7.css +233 -0
  30. flowfile/web/static/assets/GraphSolver-0c86bbc6.js +382 -0
  31. flowfile/web/static/assets/GraphSolver-17fd26db.css +68 -0
  32. flowfile/web/static/assets/GroupBy-ab1ea74b.css +51 -0
  33. flowfile/web/static/assets/GroupBy-f2772e9f.js +413 -0
  34. flowfile/web/static/assets/Join-41c0f331.css +109 -0
  35. flowfile/web/static/assets/Join-bc3e1cf7.js +247 -0
  36. flowfile/web/static/assets/ManualInput-03aa0245.js +391 -0
  37. flowfile/web/static/assets/ManualInput-ac7b9972.css +84 -0
  38. flowfile/web/static/assets/Output-48f81019.css +2642 -0
  39. flowfile/web/static/assets/Output-5b35eee8.js +536 -0
  40. flowfile/web/static/assets/Pivot-7164087c.js +408 -0
  41. flowfile/web/static/assets/Pivot-f415e85f.css +35 -0
  42. flowfile/web/static/assets/PolarsCode-3abf6507.js +2863 -0
  43. flowfile/web/static/assets/PolarsCode-650322d1.css +35 -0
  44. flowfile/web/static/assets/PopOver-b37ff9be.js +577 -0
  45. flowfile/web/static/assets/PopOver-bccfde04.css +32 -0
  46. flowfile/web/static/assets/Read-65966a3e.js +701 -0
  47. flowfile/web/static/assets/Read-80dc1675.css +197 -0
  48. flowfile/web/static/assets/RecordCount-c66c6d6d.js +121 -0
  49. flowfile/web/static/assets/RecordId-826dc095.js +339 -0
  50. flowfile/web/static/assets/Sample-4ed555c8.js +184 -0
  51. flowfile/web/static/assets/SecretManager-eac1e97d.js +382 -0
  52. flowfile/web/static/assets/Select-085f05cc.js +231 -0
  53. flowfile/web/static/assets/SettingsSection-1f5e79c1.js +87 -0
  54. flowfile/web/static/assets/SettingsSection-9c836ecc.css +47 -0
  55. flowfile/web/static/assets/Sort-3e6cb414.js +309 -0
  56. flowfile/web/static/assets/Sort-7ccfa0fe.css +51 -0
  57. flowfile/web/static/assets/TextToRows-606349bc.js +307 -0
  58. flowfile/web/static/assets/TextToRows-c92d1ec2.css +48 -0
  59. flowfile/web/static/assets/UnavailableFields-5edd5322.css +49 -0
  60. flowfile/web/static/assets/UnavailableFields-b41976ed.js +36 -0
  61. flowfile/web/static/assets/Union-8d9ac7f9.css +30 -0
  62. flowfile/web/static/assets/Union-fca91665.js +145 -0
  63. flowfile/web/static/assets/Unique-a59f830e.js +273 -0
  64. flowfile/web/static/assets/Unique-b5615727.css +51 -0
  65. flowfile/web/static/assets/Unpivot-246e9bbd.css +77 -0
  66. flowfile/web/static/assets/Unpivot-c3815565.js +441 -0
  67. flowfile/web/static/assets/airbyte-292aa232.png +0 -0
  68. flowfile/web/static/assets/api-22b338bd.js +60 -0
  69. flowfile/web/static/assets/cross_join-d30c0290.png +0 -0
  70. flowfile/web/static/assets/database_reader-ce1e55f3.svg +24 -0
  71. flowfile/web/static/assets/database_writer-b4ad0753.svg +23 -0
  72. flowfile/web/static/assets/designer-2394122a.css +10697 -0
  73. flowfile/web/static/assets/designer-e5bbe26f.js +69712 -0
  74. flowfile/web/static/assets/documentation-08045cf2.js +33 -0
  75. flowfile/web/static/assets/documentation-12216a74.css +50 -0
  76. flowfile/web/static/assets/dropDown-35135ba8.css +143 -0
  77. flowfile/web/static/assets/dropDown-5e7e9a5a.js +319 -0
  78. flowfile/web/static/assets/dropDownGeneric-50a91b99.js +72 -0
  79. flowfile/web/static/assets/dropDownGeneric-895680d6.css +10 -0
  80. flowfile/web/static/assets/element-icons-9c88a535.woff +0 -0
  81. flowfile/web/static/assets/element-icons-de5eb258.ttf +0 -0
  82. flowfile/web/static/assets/explore_data-8a0a2861.png +0 -0
  83. flowfile/web/static/assets/fa-brands-400-808443ae.ttf +0 -0
  84. flowfile/web/static/assets/fa-brands-400-d7236a19.woff2 +0 -0
  85. flowfile/web/static/assets/fa-regular-400-54cf6086.ttf +0 -0
  86. flowfile/web/static/assets/fa-regular-400-e3456d12.woff2 +0 -0
  87. flowfile/web/static/assets/fa-solid-900-aa759986.woff2 +0 -0
  88. flowfile/web/static/assets/fa-solid-900-d2f05935.ttf +0 -0
  89. flowfile/web/static/assets/fa-v4compatibility-0ce9033c.woff2 +0 -0
  90. flowfile/web/static/assets/fa-v4compatibility-30f6abf6.ttf +0 -0
  91. flowfile/web/static/assets/filter-d7708bda.png +0 -0
  92. flowfile/web/static/assets/formula-eeeb1611.png +0 -0
  93. flowfile/web/static/assets/fullEditor-178376bb.css +256 -0
  94. flowfile/web/static/assets/fullEditor-705c6ccb.js +630 -0
  95. flowfile/web/static/assets/fuzzy_match-40c161b2.png +0 -0
  96. flowfile/web/static/assets/genericNodeSettings-65587f20.js +137 -0
  97. flowfile/web/static/assets/genericNodeSettings-924759c7.css +46 -0
  98. flowfile/web/static/assets/graph_solver-8b7888b8.png +0 -0
  99. flowfile/web/static/assets/group_by-80561fc3.png +0 -0
  100. flowfile/web/static/assets/index-552863fd.js +58652 -0
  101. flowfile/web/static/assets/index-681a3ed0.css +8843 -0
  102. flowfile/web/static/assets/input_data-ab2eb678.png +0 -0
  103. flowfile/web/static/assets/join-349043ae.png +0 -0
  104. flowfile/web/static/assets/manual_input-ae98f31d.png +0 -0
  105. flowfile/web/static/assets/nodeTitle-cf9bae3c.js +227 -0
  106. flowfile/web/static/assets/nodeTitle-f4b12bcb.css +134 -0
  107. flowfile/web/static/assets/old_join-5d0eb604.png +0 -0
  108. flowfile/web/static/assets/output-06ec0371.png +0 -0
  109. flowfile/web/static/assets/pivot-9660df51.png +0 -0
  110. flowfile/web/static/assets/polars_code-05ce5dc6.png +0 -0
  111. flowfile/web/static/assets/record_count-dab44eb5.png +0 -0
  112. flowfile/web/static/assets/record_id-0b15856b.png +0 -0
  113. flowfile/web/static/assets/sample-693a88b5.png +0 -0
  114. flowfile/web/static/assets/secretApi-3ad510e1.js +46 -0
  115. flowfile/web/static/assets/select-b0d0437a.png +0 -0
  116. flowfile/web/static/assets/selectDynamic-b062bc9b.css +107 -0
  117. flowfile/web/static/assets/selectDynamic-bd644891.js +302 -0
  118. flowfile/web/static/assets/sort-2aa579f0.png +0 -0
  119. flowfile/web/static/assets/summarize-2a099231.png +0 -0
  120. flowfile/web/static/assets/text_to_rows-859b29ea.png +0 -0
  121. flowfile/web/static/assets/union-2d8609f4.png +0 -0
  122. flowfile/web/static/assets/unique-1958b98a.png +0 -0
  123. flowfile/web/static/assets/unpivot-d3cb4b5b.png +0 -0
  124. flowfile/web/static/assets/view-7a0f0be1.png +0 -0
  125. flowfile/web/static/assets/vue-codemirror.esm-dd17b478.js +22281 -0
  126. flowfile/web/static/assets/vue-content-loader.es-6b36f05e.js +210 -0
  127. flowfile/web/static/flowfile.svg +47 -0
  128. flowfile/web/static/icons/flowfile.png +0 -0
  129. flowfile/web/static/images/airbyte.png +0 -0
  130. flowfile/web/static/images/flowfile.svg +47 -0
  131. flowfile/web/static/images/google.svg +1 -0
  132. flowfile/web/static/images/sheets.png +0 -0
  133. flowfile/web/static/index.html +22 -0
  134. flowfile/web/static/vite.svg +1 -0
  135. flowfile/web/static/vue.svg +1 -0
  136. flowfile-0.3.0.2.dist-info/METADATA +235 -0
  137. {flowfile-0.3.0.dist-info → flowfile-0.3.0.2.dist-info}/RECORD +147 -15
  138. {flowfile-0.3.0.dist-info → flowfile-0.3.0.2.dist-info}/entry_points.txt +1 -1
  139. flowfile_core/configs/settings.py +7 -32
  140. flowfile_core/flowfile/FlowfileFlow.py +4 -2
  141. flowfile_core/flowfile/analytics/analytics_processor.py +1 -1
  142. flowfile_core/main.py +4 -1
  143. flowfile_core/schemas/input_schema.py +1 -8
  144. flowfile_frame/__init__.py +0 -1
  145. flowfile_frame/utils.py +0 -139
  146. flowfile-0.3.0.dist-info/METADATA +0 -219
  147. flowfile_frame/__main__.py +0 -12
  148. {flowfile-0.3.0.dist-info → flowfile-0.3.0.2.dist-info}/LICENSE +0 -0
  149. {flowfile-0.3.0.dist-info → flowfile-0.3.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,155 @@
1
+ """
2
+ flowfile/web/__init__.py
3
+ Web interface for Flowfile.
4
+ Extends the flowfile_core FastAPI app to serve the Vue.js frontend
5
+ and includes worker functionality.
6
+ """
7
+ import os
8
+ import time
9
+ from pathlib import Path
10
+ import webbrowser
11
+ import asyncio
12
+ from fastapi import FastAPI, Response
13
+ from fastapi.staticfiles import StaticFiles
14
+ from fastapi.responses import FileResponse, RedirectResponse
15
+
16
+ static_dir = Path(__file__).parent / "static"
17
+
18
+
19
+ def extend_app(app: FastAPI):
20
+ """
21
+ Extend the flowfile_core FastAPI app with routes to serve the Vue.js frontend
22
+ and worker functionality.
23
+ """
24
+ # Serve static files if the directory exists
25
+ if static_dir.exists():
26
+ # Mount the assets directory
27
+ if (static_dir / "assets").exists():
28
+ app.mount("/assets", StaticFiles(directory=str(static_dir / "assets")), name="assets")
29
+
30
+ # Mount other common directories
31
+ for dir_name in ["css", "js", "img", "fonts", "icons", "images"]:
32
+ dir_path = static_dir / dir_name
33
+ if dir_path.exists() and dir_path.is_dir():
34
+ app.mount(f"/{dir_name}", StaticFiles(directory=str(dir_path)), name=dir_name)
35
+
36
+ @app.get("/favicon.ico", include_in_schema=False)
37
+ async def favicon():
38
+ """Serve the favicon.ico file"""
39
+ favicon_path = static_dir / "favicon.ico"
40
+ if favicon_path.exists():
41
+ return FileResponse(favicon_path)
42
+ return Response(status_code=404)
43
+
44
+ @app.get("/flowfile.svg", include_in_schema=False)
45
+ async def svg_logo():
46
+ """Serve the SVG logo file"""
47
+ svg_path = static_dir / "flowfile.svg"
48
+ if svg_path.exists():
49
+ return FileResponse(svg_path, media_type="image/svg+xml")
50
+ return Response(status_code=404)
51
+
52
+ @app.get("/test")
53
+ async def get_worker_host():
54
+ from flowfile_core.configs.settings import WORKER_URL
55
+ return WORKER_URL
56
+
57
+ @app.get("/ui", include_in_schema=False)
58
+ async def web_ui_root():
59
+ """Serve the main index.html file for the web UI"""
60
+ index_path = static_dir / "index.html"
61
+ if index_path.exists():
62
+ return FileResponse(index_path)
63
+ return {"error": "Web UI not installed. Build the frontend and install it in the package."}
64
+
65
+ @app.get("/ui/{path:path}", include_in_schema=False)
66
+ async def serve_vue_app(path: str):
67
+ """Serve static files or the index.html for client-side routing"""
68
+ # Try to serve the requested file
69
+ file_path = static_dir / path
70
+ if file_path.exists() and file_path.is_file():
71
+ return FileResponse(file_path)
72
+
73
+ # If it's a directory, redirect to add trailing slash
74
+ if (static_dir / path).exists() and (static_dir / path).is_dir():
75
+ return RedirectResponse(f"/ui/{path}/")
76
+
77
+ # For client-side routing, serve the index.html
78
+ index_path = static_dir / "index.html"
79
+ if index_path.exists():
80
+ return FileResponse(index_path)
81
+
82
+ return {"error": f"File not found: {path}"}
83
+
84
+ # Include worker routes if simplified mode is enabled
85
+ include_worker_routes(app)
86
+
87
+ return app
88
+
89
+
90
+ def include_worker_routes(app: FastAPI):
91
+ """
92
+ Include worker routes from flowfile_worker for simplified deployments.
93
+ This creates a unified API that serves both the web UI and processes the worker operations.
94
+ """
95
+ try:
96
+ # Import worker modules
97
+ from flowfile_worker.routes import router as worker_router
98
+ from flowfile_worker import mp_context, CACHE_DIR
99
+
100
+ # Add lifecycle event handler for worker cleanup
101
+ @app.on_event("shutdown")
102
+ async def shutdown_worker():
103
+ """Clean up worker resources on shutdown"""
104
+ print("Cleaning up worker resources...")
105
+ for p in mp_context.active_children():
106
+ try:
107
+ p.terminate()
108
+ p.join()
109
+ except Exception as e:
110
+ print(f"Error cleaning up process: {e}")
111
+
112
+ try:
113
+ CACHE_DIR.cleanup()
114
+ except Exception as e:
115
+ print(f"Error cleaning up cache directory: {e}")
116
+
117
+ await asyncio.sleep(0.1)
118
+
119
+ # Include the worker router with a prefix
120
+ app.include_router(worker_router, prefix="/worker")
121
+
122
+ print("Worker functionality included in unified API")
123
+
124
+ except ImportError as e:
125
+ print(f"Worker module could not be imported, running without worker functionality: {e}")
126
+ print("This is normal for lightweight deployments that don't need data processing.")
127
+
128
+
129
+ def start_server(host="127.0.0.1", port=63578, open_browser=True):
130
+ """
131
+ Start the flowfile_core FastAPI app with the web UI routes and worker functionality.
132
+ This function is a wrapper around flowfile_core.main.run().
133
+ """
134
+ # Set electron mode
135
+ os.environ["FLOWFILE_MODE"] = "electron"
136
+
137
+ # Import core app
138
+ from flowfile_core.main import run, app as core_app
139
+
140
+ # Extend the core app with web UI routes and worker functionality
141
+ extend_app(core_app)
142
+
143
+ # Open browser if requested
144
+ if open_browser:
145
+ time.sleep(2)
146
+ webbrowser.open_new_tab(f"http://{host}:{port}/ui")
147
+
148
+ print("\n" + "=" * 60)
149
+ print(" FlowFile - Visual ETL Tool (Unified Mode)")
150
+ print(f" Web UI: http://{host}:{port}/ui")
151
+ print(f" API Docs: http://{host}:{port}/docs")
152
+ print("=" * 60 + "\n")
153
+
154
+ # Run the core app
155
+ run(host=host, port=port)
@@ -0,0 +1,314 @@
1
+
2
+ /* Array input styles */
3
+ .array-input-section[data-v-b2f2d704] {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 8px;
7
+ }
8
+ .input-with-button[data-v-b2f2d704] {
9
+ display: flex;
10
+ gap: 8px;
11
+ align-items: center;
12
+ }
13
+ .items-container[data-v-b2f2d704] {
14
+ display: flex;
15
+ flex-wrap: wrap;
16
+ gap: 10px; /* Space between items */
17
+ }
18
+ .item-box[data-v-b2f2d704] {
19
+ display: flex;
20
+ align-items: center;
21
+ padding: 5px 10px;
22
+ background-color: #f0f0f0;
23
+ border-radius: 4px;
24
+ font-size: 12px;
25
+ position: relative;
26
+ }
27
+ .remove-btn[data-v-b2f2d704] {
28
+ margin-left: 8px;
29
+ cursor: pointer;
30
+ color: #100f0f72;
31
+ font-weight: bold;
32
+ }
33
+ .add-btn[data-v-b2f2d704] {
34
+ padding: 4px 12px;
35
+ background: #7878ff5b;
36
+ border: none;
37
+ border-radius: 3px;
38
+ cursor: pointer;
39
+ font-size: 12px;
40
+ transition: background-color 0.2s;
41
+ white-space: nowrap;
42
+ }
43
+ .add-btn[data-v-b2f2d704]:hover {
44
+ background: #6363ff5b;
45
+ }
46
+
47
+ /* Your existing styles */
48
+ .form-container[data-v-b2f2d704] {
49
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
50
+ font-size: 13px;
51
+ color: #333;
52
+ }
53
+ .form-grid[data-v-b2f2d704] {
54
+ display: grid;
55
+ gap: 8px;
56
+ padding: 12px;
57
+ background: #fff;
58
+ border: 1px solid #eee;
59
+ border-radius: 4px;
60
+ }
61
+ .form-item-wrapper[data-v-b2f2d704] {
62
+ margin-bottom: 2px;
63
+ }
64
+ .single-item[data-v-b2f2d704] {
65
+ margin-bottom: 4px;
66
+ }
67
+ .compact-header[data-v-b2f2d704] {
68
+ font-size: 12px;
69
+ color: #666;
70
+ margin-bottom: 2px;
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 4px;
74
+ }
75
+ .minimal-header[data-v-b2f2d704] {
76
+ width: 100%;
77
+ text-align: left;
78
+ padding: 6px 8px;
79
+ background: #f5f5f5;
80
+ border: 1px solid #eee;
81
+ border-radius: 3px;
82
+ font-size: 12px;
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 6px;
86
+ cursor: pointer;
87
+ transition: background 0.2s;
88
+ }
89
+ .minimal-header[data-v-b2f2d704]:hover {
90
+ background: #f0f0f0;
91
+ }
92
+ .minimal-header.is-open[data-v-b2f2d704] {
93
+ border-bottom-left-radius: 0;
94
+ border-bottom-right-radius: 0;
95
+ }
96
+ .minimal-chevron[data-v-b2f2d704] {
97
+ font-size: 14px;
98
+ color: #999;
99
+ width: 12px;
100
+ }
101
+ .tag[data-v-b2f2d704] {
102
+ color: #ff4757;
103
+ font-size: 14px;
104
+ }
105
+ .type-indicator[data-v-b2f2d704] {
106
+ color: #999;
107
+ font-size: 11px;
108
+ }
109
+ .nested-content[data-v-b2f2d704] {
110
+ padding: 8px;
111
+ border: 1px solid #eee;
112
+ border-top: none;
113
+ background: #fff;
114
+ border-bottom-left-radius: 3px;
115
+ border-bottom-right-radius: 3px;
116
+ }
117
+ .nested-item[data-v-b2f2d704] {
118
+ margin-bottom: 6px;
119
+ }
120
+ .nested-item[data-v-b2f2d704]:last-child {
121
+ margin-bottom: 0;
122
+ }
123
+ .minimal-input[data-v-b2f2d704] {
124
+ box-sizing: border-box; /* Add this to include padding in width calculation */
125
+ width: 100%;
126
+ padding: 4px 8px;
127
+ border: 1px solid #ddd;
128
+ border-radius: 3px;
129
+ font-size: 12px;
130
+ background: #fff;
131
+ transition: border 0.2s;
132
+ }
133
+ .minimal-input[data-v-b2f2d704]:focus {
134
+ outline: none;
135
+ border-color: #666;
136
+ }
137
+ .minimal-input[data-v-b2f2d704]::placeholder {
138
+ color: #ccc;
139
+ }
140
+ .minimal-popover[data-v-b2f2d704] {
141
+ position: fixed;
142
+ background: rgba(0, 0, 0, 0.8);
143
+ color: #fff;
144
+ padding: 4px 8px;
145
+ border-radius: 3px;
146
+ font-size: 12px;
147
+ max-width: 250px;
148
+ z-index: 100;
149
+ pointer-events: none;
150
+ }
151
+ @media (max-width: 640px) {
152
+ .form-grid[data-v-b2f2d704] {
153
+ padding: 8px;
154
+ gap: 6px;
155
+ }
156
+ .minimal-header[data-v-b2f2d704] {
157
+ padding: 4px 6px;
158
+ }
159
+ .minimal-input[data-v-b2f2d704] {
160
+ padding: 3px 6px;
161
+ }
162
+ }
163
+
164
+ .to-front[data-v-9dcbd94f] {
165
+ z-index: 1000;
166
+ }
167
+ .config-section[data-v-9dcbd94f] {
168
+ margin-top: 16px;
169
+ }
170
+ .stream-section[data-v-9dcbd94f] {
171
+ margin-top: 16px;
172
+ }
173
+ .stream-select[data-v-9dcbd94f] {
174
+ width: 100%;
175
+ max-width: 400px;
176
+ }
177
+ .icon-button[data-v-9dcbd94f] {
178
+ padding: 2px;
179
+ border: none;
180
+ background: none;
181
+ cursor: pointer;
182
+ color: #666;
183
+ }
184
+ .icon-button[data-v-9dcbd94f]:hover {
185
+ color: #333;
186
+ }
187
+ .primary-button[data-v-9dcbd94f] {
188
+ display: inline-flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ cursor: pointer;
192
+ padding: 8px 16px;
193
+ background-color: #7878ff5b;
194
+ border: none;
195
+ border-radius: 4px;
196
+ font-size: 13px;
197
+ transition: background-color 0.3s ease;
198
+ }
199
+ .primary-button[data-v-9dcbd94f]:hover:not(:disabled) {
200
+ background-color: #b3b5ba;
201
+ }
202
+ .primary-button[data-v-9dcbd94f]:disabled {
203
+ opacity: 0.6;
204
+ cursor: not-allowed;
205
+ }
206
+ .secondary-button[data-v-9dcbd94f] {
207
+ display: inline-flex;
208
+ align-items: center;
209
+ gap: 4px;
210
+ padding: 4px 8px;
211
+ background-color: #f1f1f1;
212
+ border: 1px solid #ddd;
213
+ border-radius: 4px;
214
+ font-size: 12px;
215
+ color: #666;
216
+ transition: all 0.2s ease;
217
+ }
218
+ .secondary-button[data-v-9dcbd94f]:hover {
219
+ background-color: #e4e4e4;
220
+ color: #333;
221
+ }
222
+ .validation-banner[data-v-9dcbd94f] {
223
+ display: flex;
224
+ align-items: center;
225
+ gap: 8px;
226
+ padding: 12px;
227
+ margin-top: 12px;
228
+ border-radius: 4px;
229
+ font-size: 14px;
230
+ }
231
+ .validation-banner.success[data-v-9dcbd94f] {
232
+ background-color: #ecfdf5;
233
+ color: #047857;
234
+ }
235
+ .validation-banner.error[data-v-9dcbd94f] {
236
+ background-color: #fef2f2;
237
+ color: #dc2626;
238
+ }
239
+ .spin[data-v-9dcbd94f] {
240
+ animation: spin-9dcbd94f 1s linear infinite;
241
+ }
242
+ @keyframes spin-9dcbd94f {
243
+ from {
244
+ transform: rotate(0deg);
245
+ }
246
+ to {
247
+ transform: rotate(360deg);
248
+ }
249
+ }
250
+ .file-upload-label[data-v-9dcbd94f] {
251
+ display: flex;
252
+ align-items: center;
253
+ justify-content: flex-start;
254
+ background-color: #f5f5f5;
255
+ border: 1px solid #ddd;
256
+ border-radius: 4px;
257
+ padding: 10px 15px;
258
+ color: #333;
259
+ font-size: 16px;
260
+ font-weight: 500;
261
+ text-align: left;
262
+ user-select: none;
263
+ cursor: pointer;
264
+ transition: background-color 0.3s ease;
265
+ }
266
+ .file-upload-label[data-v-9dcbd94f]:hover {
267
+ background-color: #e4e4e4;
268
+ }
269
+ .file-icon[data-v-9dcbd94f] {
270
+ margin-right: 10px;
271
+ font-size: 20px;
272
+ width: 24px;
273
+ height: auto;
274
+ }
275
+ .attention-notice[data-v-9dcbd94f] {
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 6px;
279
+ padding: 4px 8px;
280
+ border-radius: 4px;
281
+ width: fit-content;
282
+ margin-top: 4px;
283
+ }
284
+ .docker-notice[data-v-9dcbd94f] {
285
+ font-size: 12px;
286
+ font-weight: 600;
287
+ }
288
+ .warning-icon[data-v-9dcbd94f] {
289
+ font-size: 14px;
290
+ animation: pulse-9dcbd94f 2s infinite;
291
+ }
292
+ .flex[data-v-9dcbd94f] {
293
+ display: flex;
294
+ }
295
+ .justify-between[data-v-9dcbd94f] {
296
+ justify-content: space-between;
297
+ }
298
+ .items-center[data-v-9dcbd94f] {
299
+ align-items: center;
300
+ }
301
+ .gap-2[data-v-9dcbd94f] {
302
+ gap: 8px;
303
+ }
304
+ @keyframes pulse-9dcbd94f {
305
+ 0% {
306
+ opacity: 1;
307
+ }
308
+ 50% {
309
+ opacity: 0.5;
310
+ }
311
+ 100% {
312
+ opacity: 1;
313
+ }
314
+ }