Update app.py
Browse files
app.py
CHANGED
@@ -4,6 +4,7 @@ import os
|
|
4 |
import requests
|
5 |
import re
|
6 |
from collections import Counter
|
|
|
7 |
|
8 |
# Load token. Best practice is to use environment variables.
|
9 |
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
@@ -11,20 +12,65 @@ if not GITHUB_TOKEN: # Good practice to have this check.
|
|
11 |
raise ValueError("GITHUB_TOKEN environment variable not set!")
|
12 |
g = Github(GITHUB_TOKEN)
|
13 |
|
14 |
-
# Project templates (
|
15 |
PROJECT_TEMPLATES = {
|
16 |
"flask": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
"files": {
|
18 |
"app.py": """from flask import Flask
|
|
|
|
|
|
|
|
|
|
|
19 |
app = Flask(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
@app.route('/')
|
21 |
def hello():
|
22 |
return "Hello, Flask!"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
if __name__ == '__main__':
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
app.run(debug=True)""",
|
25 |
-
"requirements.txt": "Flask
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
28 |
},
|
29 |
"react": {
|
30 |
"files": {
|
@@ -95,7 +141,538 @@ code {
|
|
95 |
}""",
|
96 |
".gitignore": "node_modules/\ndist/"
|
97 |
}
|
98 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
|
101 |
def get_file_content(owner, repo_name, path, branch="main"):
|
@@ -148,11 +725,12 @@ def github_tool(
|
|
148 |
file_url: str = None,
|
149 |
repo_url: str = None,
|
150 |
template_name: str = None,
|
|
|
151 |
):
|
152 |
"""Manages GitHub repositories."""
|
153 |
user = g.get_user()
|
154 |
|
155 |
-
try: # Single try block for ALL actions
|
156 |
if action == "import_repository":
|
157 |
if not all([owner, repo_name, vcs_url]):
|
158 |
raise ValueError("Missing parameters: owner, repo_name, vcs_url")
|
@@ -168,10 +746,9 @@ def github_tool(
|
|
168 |
}
|
169 |
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
|
170 |
response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
|
171 |
-
response.raise_for_status()
|
172 |
return "Repository import started."
|
173 |
|
174 |
-
|
175 |
elif action == "create_repository":
|
176 |
if not repo_name:
|
177 |
raise ValueError("Missing parameter: repo_name")
|
@@ -187,23 +764,82 @@ def github_tool(
|
|
187 |
)
|
188 |
repo = user.create_repo(name=repo_name)
|
189 |
template = PROJECT_TEMPLATES[template_name]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
for file_path, file_content in template["files"].items():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
191 |
repo.create_file(
|
192 |
-
|
193 |
-
f"Create {
|
194 |
-
|
195 |
branch="main",
|
196 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
|
198 |
|
199 |
-
elif action == "create_file":
|
200 |
if not all([repo_name, path, content, message]):
|
201 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
202 |
repo = user.get_repo(repo_name)
|
203 |
repo.create_file(path, message, content, branch=branch)
|
204 |
return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
|
205 |
|
206 |
-
elif action == "get_file":
|
207 |
if not all([repo_name, path]):
|
208 |
raise ValueError("Missing parameters: repo_name, path")
|
209 |
repo = user.get_repo(repo_name)
|
@@ -212,13 +848,13 @@ def github_tool(
|
|
212 |
f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
|
213 |
)
|
214 |
|
215 |
-
elif action == "get_file_content_by_url":
|
216 |
if not file_url:
|
217 |
raise ValueError("Missing parameter: file_url")
|
218 |
-
file_content = get_file_content(None, None, None, None)
|
219 |
return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
|
220 |
|
221 |
-
elif action == "delete_file":
|
222 |
if not all([repo_name, path]):
|
223 |
raise ValueError("Missing parameters: repo_name, path")
|
224 |
repo = user.get_repo(repo_name)
|
@@ -226,7 +862,7 @@ def github_tool(
|
|
226 |
repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
|
227 |
return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
|
228 |
|
229 |
-
elif action == "update_file":
|
230 |
if not all([repo_name, path, content, message]):
|
231 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
232 |
repo = user.get_repo(repo_name)
|
@@ -234,7 +870,7 @@ def github_tool(
|
|
234 |
repo.update_file(path, message, content, file_contents.sha, branch=branch)
|
235 |
return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
|
236 |
|
237 |
-
elif action == "list_branches":
|
238 |
if not repo_name:
|
239 |
raise ValueError("Missing parameter: repo_name")
|
240 |
repo = user.get_repo(repo_name)
|
@@ -242,7 +878,7 @@ def github_tool(
|
|
242 |
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
|
243 |
return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
|
244 |
|
245 |
-
elif action == "create_branch":
|
246 |
if not all([repo_name, base, head]):
|
247 |
raise ValueError("Missing parameters: repo_name, base, head")
|
248 |
repo = user.get_repo(repo_name)
|
@@ -250,21 +886,21 @@ def github_tool(
|
|
250 |
repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
|
251 |
return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
|
252 |
|
253 |
-
elif action == "delete_branch":
|
254 |
if not all([repo_name, branch]):
|
255 |
raise ValueError("Missing parameters: repo_name, branch")
|
256 |
repo = user.get_repo(repo_name)
|
257 |
repo.get_git_ref(f"heads/{branch}").delete()
|
258 |
return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
|
259 |
|
260 |
-
elif action == "create_pull_request":
|
261 |
if not all([repo_name, title, body, base, head]):
|
262 |
raise ValueError("Missing parameters: repo_name, title, body, base, head")
|
263 |
repo = user.get_repo(repo_name)
|
264 |
pr = repo.create_pull(title=title, body=body, base=base, head=head)
|
265 |
return f"Pull request created! [Open Pull Request]({pr.html_url})"
|
266 |
|
267 |
-
elif action == "list_open_pull_requests":
|
268 |
if not repo_name:
|
269 |
raise ValueError("Missing parameter: repo_name")
|
270 |
repo = user.get_repo(repo_name)
|
@@ -274,14 +910,14 @@ def github_tool(
|
|
274 |
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
|
275 |
return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
|
276 |
|
277 |
-
elif action == "create_issue":
|
278 |
if not all([repo_name, title, body]):
|
279 |
raise ValueError("Missing parameters: repo_name, title, body")
|
280 |
repo = user.get_repo(repo_name)
|
281 |
issue = repo.create_issue(title=title, body=body)
|
282 |
return f"Issue created! [Open Issue]({issue.html_url})"
|
283 |
|
284 |
-
elif action == "list_issues":
|
285 |
if not repo_name:
|
286 |
raise ValueError("Missing parameter: repo_name")
|
287 |
repo = user.get_repo(repo_name)
|
@@ -291,7 +927,7 @@ def github_tool(
|
|
291 |
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
292 |
return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
|
293 |
|
294 |
-
elif action == "add_label_to_issue":
|
295 |
if not all([repo_name, issue_number, labels]):
|
296 |
raise ValueError("Missing parameters: repo_name, issue_number, labels")
|
297 |
repo = user.get_repo(repo_name)
|
@@ -302,7 +938,7 @@ def github_tool(
|
|
302 |
f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
303 |
)
|
304 |
|
305 |
-
elif action == "close_issue":
|
306 |
if not all([repo_name, issue_number]):
|
307 |
raise ValueError("Missing parameters: repo_name, issue_number")
|
308 |
repo = user.get_repo(repo_name)
|
@@ -310,7 +946,7 @@ def github_tool(
|
|
310 |
issue.edit(state='closed')
|
311 |
return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
|
312 |
|
313 |
-
elif action == "add_comment_to_issue":
|
314 |
if not all([repo_name, issue_number, message]):
|
315 |
raise ValueError("Missing parameters: repo_name, issue_number, message")
|
316 |
repo = user.get_repo(repo_name)
|
@@ -318,7 +954,7 @@ def github_tool(
|
|
318 |
issue.create_comment(body=message)
|
319 |
return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
320 |
|
321 |
-
elif action == "create_release":
|
322 |
if not all([repo_name, tag, name, message]):
|
323 |
raise ValueError("Missing parameters: repo_name, tag, name, message")
|
324 |
repo = user.get_repo(repo_name)
|
@@ -327,7 +963,7 @@ def github_tool(
|
|
327 |
f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
|
328 |
)
|
329 |
|
330 |
-
elif action == "list_releases":
|
331 |
if not repo_name:
|
332 |
raise ValueError("Missing parameter: repo_name")
|
333 |
repo = user.get_repo(repo_name)
|
@@ -337,14 +973,14 @@ def github_tool(
|
|
337 |
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
|
338 |
return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
|
339 |
|
340 |
-
elif action == "fork_repository":
|
341 |
if not repo_name:
|
342 |
raise ValueError("Missing parameter: repo_name")
|
343 |
repo = g.get_repo(repo_name)
|
344 |
fork = user.create_fork(repo)
|
345 |
return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
|
346 |
|
347 |
-
elif action == "list_forks":
|
348 |
if not repo_name:
|
349 |
raise ValueError("Missing parameter: repo_name")
|
350 |
repo = g.get_repo(repo_name)
|
@@ -354,7 +990,7 @@ def github_tool(
|
|
354 |
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
|
355 |
return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
|
356 |
|
357 |
-
elif action == "list_files":
|
358 |
if not all([owner, repo_name]):
|
359 |
raise ValueError("Missing parameters: owner, repo_name")
|
360 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
@@ -364,7 +1000,7 @@ def github_tool(
|
|
364 |
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
|
365 |
return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
|
366 |
|
367 |
-
elif action == "get_repository_info":
|
368 |
if not all([owner, repo_name]):
|
369 |
raise ValueError("Missing parameters: owner, repo_name")
|
370 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
@@ -383,7 +1019,7 @@ def github_tool(
|
|
383 |
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
|
384 |
return f"Repository info for **`{repo_name}`**:\n{info_md}"
|
385 |
|
386 |
-
elif action == "get_file_content":
|
387 |
if not all([owner, repo_name, path]):
|
388 |
raise ValueError("Missing parameters: owner, repo_name, path")
|
389 |
content_text = get_file_content(owner, repo_name, path, branch)
|
@@ -391,7 +1027,7 @@ def github_tool(
|
|
391 |
f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
|
392 |
)
|
393 |
|
394 |
-
elif action == "analyze_repository_by_url":
|
395 |
if not repo_url:
|
396 |
raise ValueError("Missing parameter: repo_url")
|
397 |
owner, repo_name = extract_repo_info(repo_url)
|
@@ -419,7 +1055,7 @@ def github_tool(
|
|
419 |
])
|
420 |
return analysis_md
|
421 |
|
422 |
-
elif action == "analyze_repository_content":
|
423 |
if not all([owner, repo_name]):
|
424 |
raise ValueError("Missing parameters: owner, repo_name")
|
425 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
@@ -454,7 +1090,7 @@ def github_tool(
|
|
454 |
except requests.exceptions.RequestException as e:
|
455 |
return f"**Connection Error:** {e}"
|
456 |
except Exception as e:
|
457 |
-
return f"**Unexpected Error:** {e}"
|
458 |
|
459 |
|
460 |
with gr.Blocks() as demo:
|
@@ -466,6 +1102,11 @@ with gr.Blocks() as demo:
|
|
466 |
"import_repository",
|
467 |
"create_repository",
|
468 |
"create_project_from_template",
|
|
|
|
|
|
|
|
|
|
|
469 |
"create_file",
|
470 |
"get_file",
|
471 |
"get_file_content_by_url",
|
@@ -497,9 +1138,29 @@ with gr.Blocks() as demo:
|
|
497 |
template_name = gr.Dropdown(
|
498 |
choices=[""] + list(PROJECT_TEMPLATES.keys()), # Add "" as a choice
|
499 |
label="Project Template",
|
500 |
-
value="",
|
501 |
allow_custom_value=True, # Use allow_custom_value instead of allow_none
|
502 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
503 |
branch = gr.Textbox(label="Branch", value="main")
|
504 |
path = gr.Textbox(label="File Path")
|
505 |
content = gr.Code(label="File Content", lines=5, language='python') # Larger code box
|
@@ -517,32 +1178,58 @@ with gr.Blocks() as demo:
|
|
517 |
file_url = gr.Textbox(label="File URL")
|
518 |
repo_url = gr.Textbox(label="Repository URL")
|
519 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
run_button = gr.Button("Execute")
|
521 |
output = gr.Markdown(label="Result") # Use Markdown for richer output
|
522 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
523 |
run_button.click(
|
524 |
github_tool,
|
525 |
-
inputs=
|
526 |
-
action,
|
527 |
-
repo_name,
|
528 |
-
branch,
|
529 |
-
path,
|
530 |
-
content,
|
531 |
-
message,
|
532 |
-
owner,
|
533 |
-
vcs_url,
|
534 |
-
title,
|
535 |
-
body,
|
536 |
-
base,
|
537 |
-
head,
|
538 |
-
issue_number,
|
539 |
-
labels,
|
540 |
-
tag,
|
541 |
-
release_name,
|
542 |
-
file_url,
|
543 |
-
repo_url,
|
544 |
-
template_name,
|
545 |
-
],
|
546 |
outputs=output,
|
547 |
api_name="github_tool"
|
548 |
)
|
|
|
4 |
import requests
|
5 |
import re
|
6 |
from collections import Counter
|
7 |
+
import jinja2 # Import Jinja2
|
8 |
|
9 |
# Load token. Best practice is to use environment variables.
|
10 |
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
|
|
12 |
raise ValueError("GITHUB_TOKEN environment variable not set!")
|
13 |
g = Github(GITHUB_TOKEN)
|
14 |
|
15 |
+
# Project templates (parameterized with Jinja2) including shadcn.
|
16 |
PROJECT_TEMPLATES = {
|
17 |
"flask": {
|
18 |
+
"params": { # Define parameters for the template
|
19 |
+
"database_type": {
|
20 |
+
"type": "choice",
|
21 |
+
"default": "sqlite",
|
22 |
+
"choices": ["sqlite", "postgresql", "mysql"],
|
23 |
+
"description": "Type of database to configure for the Flask app."
|
24 |
+
}
|
25 |
+
},
|
26 |
"files": {
|
27 |
"app.py": """from flask import Flask
|
28 |
+
from flask_sqlalchemy import SQLAlchemy
|
29 |
+
import os
|
30 |
+
|
31 |
+
basedir = os.path.abspath(os.path.dirname(__file__))
|
32 |
+
|
33 |
app = Flask(__name__)
|
34 |
+
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or \\
|
35 |
+
'{{database_uri}}' # Placeholder for database URI
|
36 |
+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
37 |
+
|
38 |
+
db = SQLAlchemy(app)
|
39 |
+
|
40 |
+
class HelloWorld(db.Model):
|
41 |
+
id = db.Column(db.Integer, primary_key=True)
|
42 |
+
message = db.Column(db.String(128))
|
43 |
+
|
44 |
+
def __repr__(self):
|
45 |
+
return f'<HelloWorld {self.message}>'
|
46 |
+
|
47 |
@app.route('/')
|
48 |
def hello():
|
49 |
return "Hello, Flask!"
|
50 |
+
|
51 |
+
@app.route('/db_test')
|
52 |
+
def db_test():
|
53 |
+
try:
|
54 |
+
HelloWorld.query.first() # Simple DB query to test connection
|
55 |
+
return "Database connection successful!"
|
56 |
+
except Exception as e:
|
57 |
+
return f"Database connection failed: {e}"
|
58 |
+
|
59 |
+
|
60 |
if __name__ == '__main__':
|
61 |
+
with app.app_context(): # Create application context for DB operations
|
62 |
+
db.create_all()
|
63 |
+
if not HelloWorld.query.first(): # Initialize DB with a default entry if empty
|
64 |
+
default_hello = HelloWorld(message="Hello, Database!")
|
65 |
+
db.session.add(default_hello)
|
66 |
+
db.session.commit()
|
67 |
app.run(debug=True)""",
|
68 |
+
"requirements.txt": """Flask
|
69 |
+
Flask-SQLAlchemy
|
70 |
+
{{sqlalchemy_dependency}} # Placeholder for SQLAlchemy dependency""", # Conditional dependency
|
71 |
+
".gitignore": "__pycache__/\n*.pyc\nvenv/\ninstance/\n*.db"
|
72 |
+
},
|
73 |
+
"post_process": "install_dependencies" # Define a post-processing action
|
74 |
},
|
75 |
"react": {
|
76 |
"files": {
|
|
|
141 |
}""",
|
142 |
".gitignore": "node_modules/\ndist/"
|
143 |
}
|
144 |
+
},
|
145 |
+
"django": {
|
146 |
+
"files": {
|
147 |
+
"manage.py": """#!/usr/bin/env python
|
148 |
+
import os
|
149 |
+
import sys
|
150 |
+
|
151 |
+
if __name__ == "__main__":
|
152 |
+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
|
153 |
+
try:
|
154 |
+
from django.core.management import execute_from_command_line
|
155 |
+
except ImportError as exc:
|
156 |
+
raise ImportError(
|
157 |
+
"Couldn't import Django. Are you sure it is installed and "
|
158 |
+
"available on your PYTHONPATH environment variable? Did you "
|
159 |
+
"forget to activate a virtual environment?"
|
160 |
+
) from exc
|
161 |
+
execute_from_command_line(sys.argv)""",
|
162 |
+
"myapp/settings.py": """import os
|
163 |
+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
164 |
+
SECRET_KEY = 'your_secret_key_here'
|
165 |
+
DEBUG = True
|
166 |
+
ALLOWED_HOSTS = []
|
167 |
+
INSTALLED_APPS = [
|
168 |
+
'django.contrib.admin',
|
169 |
+
'django.contrib.auth',
|
170 |
+
'django.contrib.contenttypes',
|
171 |
+
'django.contrib.sessions',
|
172 |
+
'django.contrib.messages',
|
173 |
+
'django.contrib.staticfiles',
|
174 |
+
]
|
175 |
+
MIDDLEWARE = [
|
176 |
+
'django.middleware.security.SecurityMiddleware',
|
177 |
+
'django.contrib.sessions.middleware.SessionMiddleware',
|
178 |
+
'django.middleware.common.CommonMiddleware',
|
179 |
+
'django.middleware.csrf.CsrfViewMiddleware',
|
180 |
+
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
181 |
+
'django.contrib.messages.middleware.MessageMiddleware',
|
182 |
+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
183 |
+
]
|
184 |
+
ROOT_URLCONF = 'myapp.urls'
|
185 |
+
TEMPLATES = [
|
186 |
+
{
|
187 |
+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
188 |
+
'DIRS': [],
|
189 |
+
'APP_DIRS': True,
|
190 |
+
'OPTIONS': {
|
191 |
+
'context_processors': [
|
192 |
+
'django.template.context_processors.debug',
|
193 |
+
'django.template.context_processors.request',
|
194 |
+
'django.contrib.auth.context_processors.auth',
|
195 |
+
'django.contrib.messages.context_processors.messages',
|
196 |
+
],
|
197 |
+
},
|
198 |
+
},
|
199 |
+
]
|
200 |
+
WSGI_APPLICATION = 'myapp.wsgi.application'
|
201 |
+
DATABASES = {
|
202 |
+
'default': {
|
203 |
+
'ENGINE': 'django.db.backends.sqlite3',
|
204 |
+
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
205 |
+
}
|
206 |
+
}
|
207 |
+
AUTH_PASSWORD_VALIDATORS = [
|
208 |
+
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},
|
209 |
+
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},
|
210 |
+
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},
|
211 |
+
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
|
212 |
+
]
|
213 |
+
LANGUAGE_CODE = 'en-us'
|
214 |
+
TIME_ZONE = 'UTC'
|
215 |
+
USE_I18N = True
|
216 |
+
USE_L10N = True
|
217 |
+
USE_TZ = True
|
218 |
+
STATIC_URL = '/static/'
|
219 |
+
""",
|
220 |
+
"myapp/urls.py": """from django.contrib import admin
|
221 |
+
from django.urls import path
|
222 |
+
from django.http import HttpResponse
|
223 |
+
|
224 |
+
def home(request):
|
225 |
+
return HttpResponse("Hello, Django!")
|
226 |
+
|
227 |
+
urlpatterns = [
|
228 |
+
path('admin/', admin.site.urls),
|
229 |
+
path('', home, name='home'),
|
230 |
+
]""",
|
231 |
+
"myapp/wsgi.py": """import os
|
232 |
+
from django.core.wsgi import get_wsgi_application
|
233 |
+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
|
234 |
+
application = get_wsgi_application()""",
|
235 |
+
"requirements.txt": "Django",
|
236 |
+
".gitignore": "__pycache__/\n*.pyc\nvenv/\ndb.sqlite3\n",
|
237 |
+
},
|
238 |
+
"rename_files": {"myapp": "{{repo_name_snake_case}}"} # Placeholder for repo name
|
239 |
+
},
|
240 |
+
"nodejs_express": {
|
241 |
+
"files": {
|
242 |
+
"server.js": """const express = require('express')
|
243 |
+
const app = express()
|
244 |
+
const port = 3000
|
245 |
+
|
246 |
+
app.get('/', (req, res) => {
|
247 |
+
res.send('Hello World from Express!')
|
248 |
+
})
|
249 |
+
|
250 |
+
app.listen(port, () => {
|
251 |
+
console.log(`Server listening on port ${port}`)
|
252 |
+
})""",
|
253 |
+
"package.json": """{
|
254 |
+
"name": "express-app",
|
255 |
+
"version": "1.0.0",
|
256 |
+
"description": "",
|
257 |
+
"main": "server.js",
|
258 |
+
"scripts": {
|
259 |
+
"start": "node server.js"
|
260 |
+
},
|
261 |
+
"dependencies": {
|
262 |
+
"express": "^4.17.1"
|
263 |
+
}
|
264 |
+
}""",
|
265 |
+
".gitignore": "node_modules/\n"
|
266 |
+
}
|
267 |
+
},
|
268 |
+
"static_website": {
|
269 |
+
"files": {
|
270 |
+
"index.html": """<!DOCTYPE html>
|
271 |
+
<html>
|
272 |
+
<head>
|
273 |
+
<title>Simple Static Website</title>
|
274 |
+
</head>
|
275 |
+
<body>
|
276 |
+
<h1>Hello from Static Website!</h1>
|
277 |
+
<p>This is a basic HTML page.</p>
|
278 |
+
</body>
|
279 |
+
</html>""",
|
280 |
+
"style.css": """body {
|
281 |
+
font-family: sans-serif;
|
282 |
+
margin: 20px;
|
283 |
+
}""",
|
284 |
+
"script.js": """console.log("Hello from JavaScript!");""",
|
285 |
+
".gitignore": ""
|
286 |
+
}
|
287 |
+
},
|
288 |
+
"python_script": {
|
289 |
+
"files": {
|
290 |
+
"main.py": """def main():
|
291 |
+
print("Hello from Python script!")
|
292 |
+
|
293 |
+
if __name__ == "__main__":
|
294 |
+
main()""",
|
295 |
+
"requirements.txt": "",
|
296 |
+
".gitignore": "__pycache__/\n*.pyc\nvenv/\n"
|
297 |
+
}
|
298 |
+
},
|
299 |
+
"empty": {
|
300 |
+
"files": {
|
301 |
+
"README.md": "# {{repo_name}}", # Placeholder for repo name
|
302 |
+
".gitignore": ""
|
303 |
+
},
|
304 |
+
"rename_files": {"README.md": "{{readme_filename}}"} # Placeholder for readme filename
|
305 |
+
},
|
306 |
+
"shadcn": {
|
307 |
+
"files": {
|
308 |
+
"package.json": """{
|
309 |
+
"name": "shadcn-react-app",
|
310 |
+
"private": true,
|
311 |
+
"version": "0.0.0",
|
312 |
+
"type": "module",
|
313 |
+
"scripts": {
|
314 |
+
"dev": "vite",
|
315 |
+
"build": "vite build",
|
316 |
+
"preview": "vite preview",
|
317 |
+
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
318 |
+
"preview": "vite preview"
|
319 |
+
},
|
320 |
+
"dependencies": {
|
321 |
+
"@radix-ui/react-slot": "^1.0.2",
|
322 |
+
"class-variance-authority": "^0.7.0",
|
323 |
+
"clsx": "^2.1.0",
|
324 |
+
"lucide-react": "^0.303.0",
|
325 |
+
"react": "^18.2.0",
|
326 |
+
"react-dom": "^18.2.0",
|
327 |
+
"tailwind-merge": "^2.2.0",
|
328 |
+
"tailwindcss-animate": "^1.0.7"
|
329 |
+
},
|
330 |
+
"devDependencies": {
|
331 |
+
"@vitejs/plugin-react": "^4.2.1",
|
332 |
+
"autoprefixer": "^10.4.16",
|
333 |
+
"eslint": "^8.55.0",
|
334 |
+
"eslint-plugin-react": "^7.33.2",
|
335 |
+
"eslint-plugin-react-hooks": "^4.6.0",
|
336 |
+
"eslint-plugin-react-refresh": "^0.4.5",
|
337 |
+
"postcss": "^8.4.33",
|
338 |
+
"tailwindcss": "^3.4.1",
|
339 |
+
"vite": "^5.0.8"
|
340 |
+
}
|
341 |
+
}""",
|
342 |
+
"vite.config.js": """import { defineConfig } from 'vite'
|
343 |
+
import react from '@vitejs/plugin-react'
|
344 |
+
|
345 |
+
// https://vitejs.dev/config/
|
346 |
+
export default defineConfig({
|
347 |
+
plugins: [react()],
|
348 |
+
})""",
|
349 |
+
"index.html": """<!doctype html>
|
350 |
+
<html lang="en">
|
351 |
+
<head>
|
352 |
+
<meta charset="UTF-8" />
|
353 |
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
354 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
355 |
+
<title>Vite + React + Shadcn</title>
|
356 |
+
</head>
|
357 |
+
<body class="bg-background">
|
358 |
+
<div id="root"></div>
|
359 |
+
<script type="module" src="/src/main.jsx"></script>
|
360 |
+
</body>
|
361 |
+
</html>""",
|
362 |
+
"src/main.jsx": """import React from 'react'
|
363 |
+
import ReactDOM from 'react-dom/client'
|
364 |
+
import App from './App.jsx'
|
365 |
+
import './index.css'
|
366 |
+
|
367 |
+
ReactDOM.createRoot(document.getElementById('root')).render(
|
368 |
+
<React.StrictMode>
|
369 |
+
<App />
|
370 |
+
</React.StrictMode>,
|
371 |
+
)""",
|
372 |
+
"src/App.jsx": """import React from 'react'
|
373 |
+
import { Button } from "./components/ui/button"
|
374 |
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./components/ui/card"
|
375 |
+
|
376 |
+
|
377 |
+
function App() {
|
378 |
+
return (
|
379 |
+
<div className="container mx-auto py-10">
|
380 |
+
<h1 className="text-3xl font-bold text-center mb-5">
|
381 |
+
Witaj w aplikacji Shadcn UI!
|
382 |
+
</h1>
|
383 |
+
|
384 |
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
385 |
+
<Card>
|
386 |
+
<CardHeader>
|
387 |
+
<CardTitle>Karta 1</CardTitle>
|
388 |
+
<CardDescription>Prosta karta z Shadcn UI.</CardDescription>
|
389 |
+
</CardHeader>
|
390 |
+
<CardContent>
|
391 |
+
<p>Zawartość karty.</p>
|
392 |
+
<Button className="mt-4">Przycisk Akcji</Button>
|
393 |
+
</CardContent>
|
394 |
+
</Card>
|
395 |
+
|
396 |
+
<Card>
|
397 |
+
<CardHeader>
|
398 |
+
<CardTitle>Karta 2</CardTitle>
|
399 |
+
<CardDescription>Kolejna karta dla przykładu.</CardDescription>
|
400 |
+
</CardHeader>
|
401 |
+
<CardContent>
|
402 |
+
<p>Więcej zawartości.</p>
|
403 |
+
<Button variant="secondary" className="mt-4">Przycisk Wtórny</Button>
|
404 |
+
</CardContent>
|
405 |
+
</Card>
|
406 |
+
|
407 |
+
<Card className="lg:col-span-1 md:col-span-2">
|
408 |
+
<CardHeader>
|
409 |
+
<CardTitle>Dłuższa Karta</CardTitle>
|
410 |
+
<CardDescription>Karta zajmująca więcej miejsca.</CardDescription>
|
411 |
+
</CardHeader>
|
412 |
+
<CardContent>
|
413 |
+
<p>
|
414 |
+
Ta karta demonstruje jak karty mogą dostosowywać się do różnych
|
415 |
+
rozmiarów ekranów i układów. Shadcn UI i Tailwind CSS
|
416 |
+
dają dużą elastyczność w projektowaniu interfejsów.
|
417 |
+
</p>
|
418 |
+
<Button variant="destructive" className="mt-4">Przycisk Destrukcyjny</Button>
|
419 |
+
</CardContent>
|
420 |
+
</Card>
|
421 |
+
</div>
|
422 |
+
</div>
|
423 |
+
)
|
424 |
+
}
|
425 |
+
|
426 |
+
export default App""",
|
427 |
+
"src/index.css": """@tailwind base;
|
428 |
+
@tailwind components;
|
429 |
+
@tailwind utilities;
|
430 |
+
|
431 |
+
@layer base {
|
432 |
+
:root {
|
433 |
+
--background: 0 0% 100%;
|
434 |
+
--foreground: 222.2 84.9% 4.9%;
|
435 |
+
|
436 |
+
--card: 0 0% 100%;
|
437 |
+
--card-foreground: 222.2 84.9% 4.9%;
|
438 |
+
|
439 |
+
--popover: 0 0% 100%;
|
440 |
+
--popover-foreground: 222.2 84.9% 4.9%;
|
441 |
+
|
442 |
+
--primary: 221.2 83.2% 53.3%;
|
443 |
+
--primary-foreground: 210 40% 98%;
|
444 |
+
|
445 |
+
--secondary: 210 40% 96.1%;
|
446 |
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
447 |
+
|
448 |
+
--muted: 210 40% 96.1%;
|
449 |
+
--muted-foreground: 215.4 16.3% 46.9%;
|
450 |
+
|
451 |
+
--accent: 210 40% 96.1%;
|
452 |
+
--accent-foreground: 222.2 47.4% 11.2%;
|
453 |
+
|
454 |
+
--destructive: 0 84.2% 60.2%;
|
455 |
+
--destructive-foreground: 210 40% 98%;
|
456 |
+
|
457 |
+
--border: 214.3 31.8% 91.4%;
|
458 |
+
--input: 214.3 31.8% 91.4%;
|
459 |
+
--ring: 221.2 83.2% 53.3%;
|
460 |
+
|
461 |
+
--radius: 0.5rem;
|
462 |
+
}
|
463 |
+
|
464 |
+
.dark {
|
465 |
+
--background: 222.2 84.9% 4.9%;
|
466 |
+
--foreground: 210 40% 98%;
|
467 |
+
|
468 |
+
--card: 222.2 84.9% 4.9%;
|
469 |
+
--card-foreground: 210 40% 98%;
|
470 |
+
|
471 |
+
--popover: 222.2 84.9% 4.9%;
|
472 |
+
--popover-foreground: 210 40% 98%;
|
473 |
+
|
474 |
+
--primary: 217.2 91.2% 59.8%;
|
475 |
+
--primary-foreground: 222.2 47.4% 11.2%;
|
476 |
+
|
477 |
+
--secondary: 217.2 32.6% 17.5%;
|
478 |
+
--secondary-foreground: 210 40% 98%;
|
479 |
+
|
480 |
+
--muted: 217.2 32.6% 17.5%;
|
481 |
+
--muted-foreground: 215 20.2% 65.1%;
|
482 |
+
|
483 |
+
--accent: 217.2 32.6% 17.5%;
|
484 |
+
--accent-foreground: 210 40% 98%;
|
485 |
+
|
486 |
+
--destructive: 0 62.8% 30.6%;
|
487 |
+
--destructive-foreground: 210 40% 98%;
|
488 |
+
|
489 |
+
--border: 217.2 32.6% 17.5%;
|
490 |
+
--input: 217.2 32.6% 17.5%;
|
491 |
+
--ring: 224.9 98.6% 67.3%;
|
492 |
+
}
|
493 |
+
}
|
494 |
+
|
495 |
+
@layer components {
|
496 |
+
.container {
|
497 |
+
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
|
498 |
+
}
|
499 |
+
}
|
500 |
+
""",
|
501 |
+
"postcss.config.js": """module.exports = {
|
502 |
+
plugins: {
|
503 |
+
tailwindcss: {},
|
504 |
+
autoprefixer: {},
|
505 |
+
},
|
506 |
+
}""",
|
507 |
+
"tailwind.config.js": """/** @type {import('tailwindcss').Config} */
|
508 |
+
module.exports = {
|
509 |
+
darkMode: ["class"],
|
510 |
+
content: [
|
511 |
+
'./pages/**/*.{js,jsx}',
|
512 |
+
'./components/**/*.{js,jsx}',
|
513 |
+
'./app/**/*.{js,jsx}',
|
514 |
+
'./src/**/*.{js,jsx}',
|
515 |
+
],
|
516 |
+
prefix: "",
|
517 |
+
theme: {
|
518 |
+
container: {
|
519 |
+
center: true,
|
520 |
+
padding: "2rem",
|
521 |
+
screens: {
|
522 |
+
"2xl": "1400px",
|
523 |
+
},
|
524 |
+
},
|
525 |
+
extend: {
|
526 |
+
colors: {
|
527 |
+
border: "hsl(var(--border))",
|
528 |
+
input: "hsl(var(--input))",
|
529 |
+
ring: "hsl(var(--ring))",
|
530 |
+
background: "hsl(var(--background))",
|
531 |
+
foreground: "hsl(var(--foreground))",
|
532 |
+
primary: {
|
533 |
+
DEFAULT: "hsl(var(--primary))",
|
534 |
+
foreground: "hsl(var(--primary-foreground))",
|
535 |
+
},
|
536 |
+
secondary: {
|
537 |
+
DEFAULT: "hsl(var(--secondary))",
|
538 |
+
foreground: "hsl(var(--secondary-foreground))",
|
539 |
+
},
|
540 |
+
destructive: {
|
541 |
+
DEFAULT: "hsl(var(--destructive))",
|
542 |
+
foreground: "hsl(var(--destructive-foreground))",
|
543 |
+
},
|
544 |
+
muted: {
|
545 |
+
DEFAULT: "hsl(var(--muted))",
|
546 |
+
foreground: "hsl(var(--muted-foreground))",
|
547 |
+
},
|
548 |
+
accent: {
|
549 |
+
DEFAULT: "hsl(var(--accent))",
|
550 |
+
foreground: "hsl(var(--accent-foreground))",
|
551 |
+
},
|
552 |
+
popover: {
|
553 |
+
DEFAULT: "hsl(var(--popover))",
|
554 |
+
foreground: "hsl(var(--popover-foreground))",
|
555 |
+
},
|
556 |
+
card: {
|
557 |
+
DEFAULT: "hsl(var(--card))",
|
558 |
+
foreground: "hsl(var(--card-foreground))",
|
559 |
+
},
|
560 |
+
},
|
561 |
+
borderRadius: {
|
562 |
+
lg: "var(--radius)",
|
563 |
+
md: "calc(var(--radius) - 2px)",
|
564 |
+
sm: "calc(var(--radius) - 4px)",
|
565 |
+
},
|
566 |
+
keyframes: {
|
567 |
+
"accordion-down": {
|
568 |
+
from: { height: "0" },
|
569 |
+
to: { height: "var(--radix-accordion-content-height)" },
|
570 |
+
},
|
571 |
+
"accordion-up": {
|
572 |
+
from: { height: "var(--radix-accordion-content-height)" },
|
573 |
+
},
|
574 |
+
},
|
575 |
+
animation: {
|
576 |
+
"accordion-down": "accordion-down 0.2s ease-out",
|
577 |
+
"accordion-up": "accordion-up 0.2s ease-out",
|
578 |
+
},
|
579 |
+
},
|
580 |
+
},
|
581 |
+
plugins: [require("tailwindcss-animate")],
|
582 |
+
}""",
|
583 |
+
"src/components/ui/button.jsx": """import * as React from "react"
|
584 |
+
import { cn } from "@/lib/utils"
|
585 |
+
import { Slot } from "@radix-ui/react-slot"
|
586 |
+
import { cva } from "class-variance-authority";
|
587 |
+
|
588 |
+
const buttonVariants = cva(
|
589 |
+
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
590 |
+
{
|
591 |
+
variants: {
|
592 |
+
variant: {
|
593 |
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
594 |
+
destructive:
|
595 |
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
596 |
+
outline:
|
597 |
+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
598 |
+
secondary:
|
599 |
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
600 |
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
601 |
+
link: "underline-offset-4 hover:underline text-primary",
|
602 |
+
},
|
603 |
+
size: {
|
604 |
+
default: "h-10 px-4 py-2",
|
605 |
+
sm: "h-9 rounded-md px-3",
|
606 |
+
lg: "h-11 rounded-md px-8",
|
607 |
+
icon: "h-10 w-10",
|
608 |
+
},
|
609 |
+
},
|
610 |
+
defaultVariants: {
|
611 |
+
variant: "default",
|
612 |
+
size: "default",
|
613 |
+
},
|
614 |
+
}
|
615 |
+
)
|
616 |
+
|
617 |
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
618 |
+
const Comp = asChild ? Slot : "button"
|
619 |
+
return (<Comp
|
620 |
+
className={cn(buttonVariants({ variant, size, className }))}
|
621 |
+
ref={ref} {...props} />)
|
622 |
+
})
|
623 |
+
Button.displayName = "Button"
|
624 |
+
|
625 |
+
export { Button, buttonVariants }""",
|
626 |
+
"src/components/ui/card.jsx": """import * as React from "react"
|
627 |
+
import { cn } from "@/lib/utils"
|
628 |
+
|
629 |
+
const Card = React.forwardRef(({ className, ...props }, ref) => (<div
|
630 |
+
className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
631 |
+
ref={ref}
|
632 |
+
{...props} />))
|
633 |
+
Card.displayName = "Card"
|
634 |
+
|
635 |
+
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (<div
|
636 |
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
637 |
+
ref={ref}
|
638 |
+
{...props} />))
|
639 |
+
CardHeader.displayName = "CardHeader"
|
640 |
+
|
641 |
+
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (<h3
|
642 |
+
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
643 |
+
ref={ref}
|
644 |
+
{...props} />))
|
645 |
+
CardTitle.displayName = "CardTitle"
|
646 |
+
|
647 |
+
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (<p
|
648 |
+
className={cn("text-sm text-muted-foreground", className)}
|
649 |
+
ref={ref}
|
650 |
+
{...props} />))
|
651 |
+
CardDescription.displayName = "CardDescription"
|
652 |
+
|
653 |
+
const CardContent = React.forwardRef(({ className, ...props }, ref) => (<div
|
654 |
+
className={cn("p-6 pt-0", className)}
|
655 |
+
ref={ref}
|
656 |
+
{...props} />))
|
657 |
+
CardContent.displayName = "CardContent"
|
658 |
+
|
659 |
+
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (<div
|
660 |
+
className={cn("flex items-center p-6 pt-0", className)}
|
661 |
+
ref={ref}
|
662 |
+
{...props} />))
|
663 |
+
CardFooter.displayName = "CardFooter"
|
664 |
+
|
665 |
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }""",
|
666 |
+
"src/lib/utils.js": """import { clsx } from "clsx"
|
667 |
+
import { twMerge } from "tailwind-merge"
|
668 |
+
|
669 |
+
export function cn(...inputs) {
|
670 |
+
return twMerge(clsx(inputs))
|
671 |
+
}"""
|
672 |
+
},
|
673 |
+
"post_process": "shadcn_setup" # Now using a specific post_process action
|
674 |
+
},
|
675 |
+
}
|
676 |
|
677 |
|
678 |
def get_file_content(owner, repo_name, path, branch="main"):
|
|
|
725 |
file_url: str = None,
|
726 |
repo_url: str = None,
|
727 |
template_name: str = None,
|
728 |
+
template_params: dict = None # New parameter for template parameters
|
729 |
):
|
730 |
"""Manages GitHub repositories."""
|
731 |
user = g.get_user()
|
732 |
|
733 |
+
try: # Single try block for ALL actions
|
734 |
if action == "import_repository":
|
735 |
if not all([owner, repo_name, vcs_url]):
|
736 |
raise ValueError("Missing parameters: owner, repo_name, vcs_url")
|
|
|
746 |
}
|
747 |
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
|
748 |
response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
|
749 |
+
response.raise_for_status() # Handle potential HTTP errors.
|
750 |
return "Repository import started."
|
751 |
|
|
|
752 |
elif action == "create_repository":
|
753 |
if not repo_name:
|
754 |
raise ValueError("Missing parameter: repo_name")
|
|
|
764 |
)
|
765 |
repo = user.create_repo(name=repo_name)
|
766 |
template = PROJECT_TEMPLATES[template_name]
|
767 |
+
|
768 |
+
# Prepare template parameters, use defaults if not provided
|
769 |
+
template_params_final = {}
|
770 |
+
if "params" in template:
|
771 |
+
for param_name, param_config in template["params"].items():
|
772 |
+
template_params_final[param_name] = template_params.get(param_name,
|
773 |
+
param_config.get("default")) if template_params else param_config.get(
|
774 |
+
"default")
|
775 |
+
|
776 |
+
# Handle file renaming and content templating
|
777 |
+
repo_name_snake_case = repo_name.replace("-", "_") # For django app names
|
778 |
+
readme_filename = "README.md" # Default readme name
|
779 |
+
|
780 |
+
env = jinja2.Environment() # Initialize Jinja2 environment
|
781 |
+
|
782 |
for file_path, file_content in template["files"].items():
|
783 |
+
final_file_path = file_path
|
784 |
+
final_file_content = file_content
|
785 |
+
|
786 |
+
# Apply file renaming if defined in template
|
787 |
+
if "rename_files" in template:
|
788 |
+
for old_name, new_name_template in template["rename_files"].items():
|
789 |
+
if file_path == old_name:
|
790 |
+
final_file_path = new_name_template.replace("{{repo_name_snake_case}}",
|
791 |
+
repo_name_snake_case).replace("{{repo_name}}",
|
792 |
+
repo_name).replace(
|
793 |
+
"{{readme_filename}}", readme_filename)
|
794 |
+
|
795 |
+
# Render file content using Jinja2 template
|
796 |
+
template_render = env.from_string(final_file_content)
|
797 |
+
final_file_content = template_render.render(
|
798 |
+
repo_name=repo_name,
|
799 |
+
repo_name_snake_case=repo_name_snake_case,
|
800 |
+
readme_filename=readme_filename,
|
801 |
+
**template_params_final # Pass template parameters to Jinja2
|
802 |
+
)
|
803 |
+
|
804 |
repo.create_file(
|
805 |
+
final_file_path,
|
806 |
+
f"Create {final_file_path} from template {template_name}",
|
807 |
+
final_file_content,
|
808 |
branch="main",
|
809 |
)
|
810 |
+
|
811 |
+
# Post-processing actions (example: install dependencies)
|
812 |
+
if "post_process" in template:
|
813 |
+
post_process_action = template["post_process"]
|
814 |
+
if post_process_action == "install_dependencies":
|
815 |
+
print(
|
816 |
+
f"Post-processing: install_dependencies for {repo_name} (Not fully implemented in this example).") # existing message
|
817 |
+
elif post_process_action == "shadcn_setup": # New post-process action
|
818 |
+
instructions = f"""
|
819 |
+
**Konfiguracja Shadcn UI wymaga dodatkowych kroków po stronie klienta!**
|
820 |
+
|
821 |
+
1. **Sklonuj repozytorium:** `git clone https://github.com/{user.login}/{repo_name}.git`
|
822 |
+
2. **Przejdź do katalogu projektu:** `cd {repo_name}`
|
823 |
+
3. **Zainstaluj zależności:** `npm install` (lub `yarn install`, `pnpm install`)
|
824 |
+
4. **Zainicjuj Shadcn UI:** `npx shadcn-ui@latest init`
|
825 |
+
5. **Uruchom aplikację:** `npm run dev` (lub odpowiednia komenda dla Twojego menedżera pakietów)
|
826 |
+
|
827 |
+
Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfigurowana i gotowa do rozwoju.
|
828 |
+
"""
|
829 |
+
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})\n\n{instructions}"
|
830 |
+
else:
|
831 |
+
print(f"Unknown post-process action: {post_process_action}") # Handle unknown actions
|
832 |
+
|
833 |
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
|
834 |
|
835 |
+
elif action == "create_file": # ... rest of actions - no changes needed in most of them ...
|
836 |
if not all([repo_name, path, content, message]):
|
837 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
838 |
repo = user.get_repo(repo_name)
|
839 |
repo.create_file(path, message, content, branch=branch)
|
840 |
return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
|
841 |
|
842 |
+
elif action == "get_file": # ...
|
843 |
if not all([repo_name, path]):
|
844 |
raise ValueError("Missing parameters: repo_name, path")
|
845 |
repo = user.get_repo(repo_name)
|
|
|
848 |
f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
|
849 |
)
|
850 |
|
851 |
+
elif action == "get_file_content_by_url": # ...
|
852 |
if not file_url:
|
853 |
raise ValueError("Missing parameter: file_url")
|
854 |
+
file_content = get_file_content(None, None, None, None) # Dummy call to avoid UnboundLocalError. get_file_content changed!
|
855 |
return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
|
856 |
|
857 |
+
elif action == "delete_file": # ...
|
858 |
if not all([repo_name, path]):
|
859 |
raise ValueError("Missing parameters: repo_name, path")
|
860 |
repo = user.get_repo(repo_name)
|
|
|
862 |
repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
|
863 |
return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
|
864 |
|
865 |
+
elif action == "update_file": # ...
|
866 |
if not all([repo_name, path, content, message]):
|
867 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
868 |
repo = user.get_repo(repo_name)
|
|
|
870 |
repo.update_file(path, message, content, file_contents.sha, branch=branch)
|
871 |
return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
|
872 |
|
873 |
+
elif action == "list_branches": # ...
|
874 |
if not repo_name:
|
875 |
raise ValueError("Missing parameter: repo_name")
|
876 |
repo = user.get_repo(repo_name)
|
|
|
878 |
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
|
879 |
return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
|
880 |
|
881 |
+
elif action == "create_branch": # ...
|
882 |
if not all([repo_name, base, head]):
|
883 |
raise ValueError("Missing parameters: repo_name, base, head")
|
884 |
repo = user.get_repo(repo_name)
|
|
|
886 |
repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
|
887 |
return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
|
888 |
|
889 |
+
elif action == "delete_branch": # ...
|
890 |
if not all([repo_name, branch]):
|
891 |
raise ValueError("Missing parameters: repo_name, branch")
|
892 |
repo = user.get_repo(repo_name)
|
893 |
repo.get_git_ref(f"heads/{branch}").delete()
|
894 |
return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
|
895 |
|
896 |
+
elif action == "create_pull_request": # ...
|
897 |
if not all([repo_name, title, body, base, head]):
|
898 |
raise ValueError("Missing parameters: repo_name, title, body, base, head")
|
899 |
repo = user.get_repo(repo_name)
|
900 |
pr = repo.create_pull(title=title, body=body, base=base, head=head)
|
901 |
return f"Pull request created! [Open Pull Request]({pr.html_url})"
|
902 |
|
903 |
+
elif action == "list_open_pull_requests": # ...
|
904 |
if not repo_name:
|
905 |
raise ValueError("Missing parameter: repo_name")
|
906 |
repo = user.get_repo(repo_name)
|
|
|
910 |
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
|
911 |
return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
|
912 |
|
913 |
+
elif action == "create_issue": # ...
|
914 |
if not all([repo_name, title, body]):
|
915 |
raise ValueError("Missing parameters: repo_name, title, body")
|
916 |
repo = user.get_repo(repo_name)
|
917 |
issue = repo.create_issue(title=title, body=body)
|
918 |
return f"Issue created! [Open Issue]({issue.html_url})"
|
919 |
|
920 |
+
elif action == "list_issues": # ...
|
921 |
if not repo_name:
|
922 |
raise ValueError("Missing parameter: repo_name")
|
923 |
repo = user.get_repo(repo_name)
|
|
|
927 |
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
928 |
return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
|
929 |
|
930 |
+
elif action == "add_label_to_issue": # ...
|
931 |
if not all([repo_name, issue_number, labels]):
|
932 |
raise ValueError("Missing parameters: repo_name, issue_number, labels")
|
933 |
repo = user.get_repo(repo_name)
|
|
|
938 |
f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
939 |
)
|
940 |
|
941 |
+
elif action == "close_issue": # ...
|
942 |
if not all([repo_name, issue_number]):
|
943 |
raise ValueError("Missing parameters: repo_name, issue_number")
|
944 |
repo = user.get_repo(repo_name)
|
|
|
946 |
issue.edit(state='closed')
|
947 |
return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
|
948 |
|
949 |
+
elif action == "add_comment_to_issue": # ...
|
950 |
if not all([repo_name, issue_number, message]):
|
951 |
raise ValueError("Missing parameters: repo_name, issue_number, message")
|
952 |
repo = user.get_repo(repo_name)
|
|
|
954 |
issue.create_comment(body=message)
|
955 |
return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
956 |
|
957 |
+
elif action == "create_release": # ...
|
958 |
if not all([repo_name, tag, name, message]):
|
959 |
raise ValueError("Missing parameters: repo_name, tag, name, message")
|
960 |
repo = user.get_repo(repo_name)
|
|
|
963 |
f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
|
964 |
)
|
965 |
|
966 |
+
elif action == "list_releases": # ...
|
967 |
if not repo_name:
|
968 |
raise ValueError("Missing parameter: repo_name")
|
969 |
repo = user.get_repo(repo_name)
|
|
|
973 |
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
|
974 |
return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
|
975 |
|
976 |
+
elif action == "fork_repository": # ...
|
977 |
if not repo_name:
|
978 |
raise ValueError("Missing parameter: repo_name")
|
979 |
repo = g.get_repo(repo_name)
|
980 |
fork = user.create_fork(repo)
|
981 |
return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
|
982 |
|
983 |
+
elif action == "list_forks": # ...
|
984 |
if not repo_name:
|
985 |
raise ValueError("Missing parameter: repo_name")
|
986 |
repo = g.get_repo(repo_name)
|
|
|
990 |
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
|
991 |
return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
|
992 |
|
993 |
+
elif action == "list_files": # ...
|
994 |
if not all([owner, repo_name]):
|
995 |
raise ValueError("Missing parameters: owner, repo_name")
|
996 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
|
|
1000 |
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
|
1001 |
return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
|
1002 |
|
1003 |
+
elif action == "get_repository_info": # ...
|
1004 |
if not all([owner, repo_name]):
|
1005 |
raise ValueError("Missing parameters: owner, repo_name")
|
1006 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
|
|
1019 |
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
|
1020 |
return f"Repository info for **`{repo_name}`**:\n{info_md}"
|
1021 |
|
1022 |
+
elif action == "get_file_content": # ...
|
1023 |
if not all([owner, repo_name, path]):
|
1024 |
raise ValueError("Missing parameters: owner, repo_name, path")
|
1025 |
content_text = get_file_content(owner, repo_name, path, branch)
|
|
|
1027 |
f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
|
1028 |
)
|
1029 |
|
1030 |
+
elif action == "analyze_repository_by_url": # ...
|
1031 |
if not repo_url:
|
1032 |
raise ValueError("Missing parameter: repo_url")
|
1033 |
owner, repo_name = extract_repo_info(repo_url)
|
|
|
1055 |
])
|
1056 |
return analysis_md
|
1057 |
|
1058 |
+
elif action == "analyze_repository_content": # ...
|
1059 |
if not all([owner, repo_name]):
|
1060 |
raise ValueError("Missing parameters: owner, repo_name")
|
1061 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
|
|
1090 |
except requests.exceptions.RequestException as e:
|
1091 |
return f"**Connection Error:** {e}"
|
1092 |
except Exception as e:
|
1093 |
+
return f"**Unexpected Error:** {e}" # Catch all.
|
1094 |
|
1095 |
|
1096 |
with gr.Blocks() as demo:
|
|
|
1102 |
"import_repository",
|
1103 |
"create_repository",
|
1104 |
"create_project_from_template",
|
1105 |
+
# Modular actions - to be added later in UI if needed
|
1106 |
+
# "create_repository_structure",
|
1107 |
+
# "add_dependencies",
|
1108 |
+
# "configure_database",
|
1109 |
+
# "add_authentication",
|
1110 |
"create_file",
|
1111 |
"get_file",
|
1112 |
"get_file_content_by_url",
|
|
|
1138 |
template_name = gr.Dropdown(
|
1139 |
choices=[""] + list(PROJECT_TEMPLATES.keys()), # Add "" as a choice
|
1140 |
label="Project Template",
|
1141 |
+
value="", # Set default value to "" (no selection)
|
1142 |
allow_custom_value=True, # Use allow_custom_value instead of allow_none
|
1143 |
)
|
1144 |
+
# Template parameters UI - dynamically generated based on template
|
1145 |
+
template_params_ui = {}
|
1146 |
+
with gr.Row(): # Display parameters in a row for better layout
|
1147 |
+
for template_key, template_config in PROJECT_TEMPLATES.items():
|
1148 |
+
if "params" in template_config:
|
1149 |
+
with gr.Column(visible=False, elem_classes=f"params_{template_key}") as params_section: # Hide initially
|
1150 |
+
for param_name, param_details in template_config["params"].items():
|
1151 |
+
if param_details["type"] == "choice":
|
1152 |
+
template_params_ui[param_name] = gr.Dropdown(
|
1153 |
+
choices=param_details["choices"],
|
1154 |
+
label=param_details["description"] or param_name,
|
1155 |
+
value=param_details["default"]
|
1156 |
+
)
|
1157 |
+
else: # Add other input types if needed (e.g., Textbox for string parameters)
|
1158 |
+
template_params_ui[param_name] = gr.Textbox(
|
1159 |
+
label=param_details["description"] or param_name,
|
1160 |
+
value=param_details["default"] if "default" in param_details else ""
|
1161 |
+
)
|
1162 |
+
template_params_ui[template_key] = params_section # Store the section itself for visibility control
|
1163 |
+
|
1164 |
branch = gr.Textbox(label="Branch", value="main")
|
1165 |
path = gr.Textbox(label="File Path")
|
1166 |
content = gr.Code(label="File Content", lines=5, language='python') # Larger code box
|
|
|
1178 |
file_url = gr.Textbox(label="File URL")
|
1179 |
repo_url = gr.Textbox(label="Repository URL")
|
1180 |
|
1181 |
+
# Function to show/hide template parameters based on template selection
|
1182 |
+
def show_template_params(template_name):
|
1183 |
+
visibility_map = {key: gr.Column.update(visible=False) for key in PROJECT_TEMPLATES if
|
1184 |
+
"params" in PROJECT_TEMPLATES[key]} # Initially hide all
|
1185 |
+
if template_name and template_name in PROJECT_TEMPLATES and "params" in PROJECT_TEMPLATES[template_name]:
|
1186 |
+
visibility_map[template_name] = gr.Column.update(visible=True) # Show for selected template
|
1187 |
+
return [visibility_map.get(key, gr.Column.update(visible=False)) for key in PROJECT_TEMPLATES if
|
1188 |
+
"params" in PROJECT_TEMPLATES[key]] # Return list in consistent order
|
1189 |
+
|
1190 |
+
template_param_visibility_outputs = [template_params_ui[key] for key in PROJECT_TEMPLATES if
|
1191 |
+
"params" in PROJECT_TEMPLATES[key]] # Get list of output components for visibility
|
1192 |
+
template_name.change(
|
1193 |
+
show_template_params,
|
1194 |
+
inputs=[template_name],
|
1195 |
+
outputs=template_param_visibility_outputs
|
1196 |
+
)
|
1197 |
+
|
1198 |
run_button = gr.Button("Execute")
|
1199 |
output = gr.Markdown(label="Result") # Use Markdown for richer output
|
1200 |
|
1201 |
+
input_components = [
|
1202 |
+
action,
|
1203 |
+
repo_name,
|
1204 |
+
branch,
|
1205 |
+
path,
|
1206 |
+
content,
|
1207 |
+
message,
|
1208 |
+
owner,
|
1209 |
+
vcs_url,
|
1210 |
+
title,
|
1211 |
+
body,
|
1212 |
+
base,
|
1213 |
+
head,
|
1214 |
+
issue_number,
|
1215 |
+
labels,
|
1216 |
+
tag,
|
1217 |
+
release_name,
|
1218 |
+
file_url,
|
1219 |
+
repo_url,
|
1220 |
+
template_name,
|
1221 |
+
]
|
1222 |
+
|
1223 |
+
# Add template parameters dynamically to input components
|
1224 |
+
for template_key in PROJECT_TEMPLATES:
|
1225 |
+
if "params" in PROJECT_TEMPLATES[template_key]:
|
1226 |
+
for param_name in template_params_ui: # Use keys from template_params_ui which are param names
|
1227 |
+
if param_name in PROJECT_TEMPLATES[template_key]["params"]: # Check if parameter belongs to template
|
1228 |
+
input_components.append(template_params_ui[param_name]) # Append parameter component
|
1229 |
+
|
1230 |
run_button.click(
|
1231 |
github_tool,
|
1232 |
+
inputs=input_components, # Use dynamically built input list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1233 |
outputs=output,
|
1234 |
api_name="github_tool"
|
1235 |
)
|