From 53cdb515a42093314fc2a3ae3fdfdb9fa2132f27 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:54:39 +0100 Subject: [PATCH 01/25] [Core]: Change build.func to new design (#189) * Redesign LXC Description * Update build.func * Update README.md --- README.md | 116 ++++++++++++++++++++++++++++++++++++++---------- misc/build.func | 37 +++++++++++++-- 2 files changed, 126 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 6e45c85e07..c34b665d5c 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,116 @@
- - - +

+ + + +

Proxmox VE Helper-Scripts: A Community Legacy

Dear Community,

In agreement with tteck and Community-Scripts, this project has now transitioned into a community-driven effort. We aim to continue his work, building on the foundation he laid to support Proxmox users worldwide.

-

tteck, whose contribution has been invaluable, shared recently that he is now in hospice care. His scripts have empowered thousands, and we honor his legacy by carrying this project forward with the same passion and commitment. We’re deeply grateful for his vision, which made Proxmox accessible to so many.

-

To tteck: Your impact will be felt in this community for years to come. We thank you for everything.

-

Warm regards,
The Community

-
- ----

- Website | - Ko-Fi (for tteck🙏) | - Contribute | - Guides | - Discord | - Changelog + + Website + + + Contribute + + + Guides + + + Discord + + + Changelog +

+
+ +## 🚀  Introduction + +**Proxmox VE Helper-Scripts** is a community-driven initiative that simplifies the setup of Proxmox Virtual Environment (VE). Originally created by [tteck](https://github.com/tteck), these scripts automate and streamline the process of creating and configuring Linux containers (LXC) and virtual machines (VMs) on Proxmox VE. + --- -This community-managed project continues tteck’s original vision of simplifying Proxmox VE setup. The scripts allow users to create Linux containers or virtual machines interactively, with options for both simple and advanced configurations. While the basic setup adheres to default settings, the advanced setup offers extensive customization options for specific needs. +## 📦  Features -All configuration choices are displayed in a dialog box, where users can select their preferences. The script then validates these inputs to generate a final configuration for the container or virtual machine. +- **Interactive Setup**: Select simple or advanced options for your VM or LXC container configurations. +- **Customizable Configuration**: Advanced setup allows you to fine-tune your environment. +- **Ease of Use**: Scripts automatically validate inputs to generate the final configuration. +- **Proxmox Integration**: Seamlessly integrates with Proxmox VE to provide a user-friendly experience. +- **Community-Driven**: This project is actively maintained and improved by the community.
-

-Please exercise caution and thoroughly review scripts and automation tasks from external sources. Read more -

+## 🚀  Installation + +To install the Proxmox Helper Scripts, simply follow these steps: + +1. Open the [Website](https://helper-scripts.com/) +2. Search for the desired script, e.g. **"Home Assistant OS VM"**. +3. In the **"How To Install"** section, copy the provided **Bash command**. +4. Open the Proxmox shell on your **main node**. +5. Paste the command into the console and let's start! 🚀 + +For detailed instructions, check out our [official guides](https://github.com/community-scripts/ProxmoxVE/blob/main/USER_SUBMITTED_GUIDES.md). --- -### Note on the Transition: -This project is now maintained by the community in memory of tteck’s invaluable contribution. His dedication transformed the Proxmox experience for countless users, and we’re committed to continuing his work with the same dedication. +## ❤️  Community and Contributions + +The Proxmox Helper Scripts project is community-driven, and we highly appreciate any contributions—whether it's through reporting bugs, suggesting features, improving documentation, or spreading the word. We are committed to maintaining transparency and sustainability in this open-source effort. + +### 💖  Donate to Support the Project + +We offer two donation options to help maintain and grow this project: + +- **Ko-Fi for tteck**: [Donate to tteck](https://ko-fi.com/proxmoxhelperscripts) - All donations will go directly to support tteck’s legacy and help fund ongoing maintenance of the scripts. +- **Ko-Fi for Community Edition**: [Donate to Community Edition](https://ko-fi.com/community_scripts) - This is a nonprofit organization. All funds will go towards script maintenance, infrastructure, and server costs. Any remaining funds will be donated annually to 2-4 causes (e.g., cancer research, hospice care, etc.). + +Your contributions help keep the project running and support important charitable causes. + +
+ +## 💬  Get Help + +Have a question or ran into an issue? Join the conversation and get help from fellow community members: + +- **Discord**: Join our [Proxmox Helper Scripts Discord server](https://discord.gg/UHrpNWGwkH) to chat with other users and get support. +- **GitHub Discussions**: [Ask questions or report issues](https://github.com/community-scripts/ProxmoxVE/discussions). + +
+ +## 🤝  Found a bug or missing feature? + +If you’ve encountered an issue or identified an area for improvement, please file a new issue on our [GitHub issues page](https://github.com/community-scripts/ProxmoxVE/issues). If you’ve already found a solution or improvement, feel free to submit a pull request! We’d love to review and merge your contributions. + +
+ +## ✅  Requirements + +To use the Proxmox VE Helper-Scripts, your system should meet the following requirements: + +- **Proxmox VE version**: 8.x or higher +- **Linux**: Compatible with most distributions +- **Dependencies**: Ensure that your system has bash and curl installed. + +
+ +## 📜  License + +This project is licensed under the terms of the [MIT License](LICENSE). --- -
Proxmox® is a registered trademark of Proxmox Server Solutions GmbH.
+## 📢  Acknowledgments + +A special thank you to [tteck](https://github.com/tteck) for his foundational work, which has allowed the Proxmox community to thrive. We’re dedicated to keeping his vision alive and expanding upon it with the continued support of this vibrant community. + +## 📢  Acknowledgments + +A special thank you to [tteck](https://github.com/tteck) for his foundational work, which has allowed the Proxmox community to thrive. We’re dedicated to keeping his vision alive and expanding upon it with the continued support of this vibrant community. diff --git a/misc/build.func b/misc/build.func index ea73f0b450..8561313657 100644 --- a/misc/build.func +++ b/misc/build.func @@ -640,12 +640,41 @@ EOF' # This function sets the description of the container. description() { IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1) - pct set "$CTID" -description "
- # ${APP} LXC + # Generate LXC Description + DESCRIPTION=$(cat < + + Logo + + +

${APP} LXC

+ +

+ + spend Coffee + +

+ + + + GitHub + + + + Discussions + + + + Issues + +
+EOF +) + + # Set Description in LXC + pct set "$CTID" -description "$DESCRIPTION" - - " if [[ -f /etc/systemd/system/ping-instances.service ]]; then systemctl start ping-instances.service fi From bdb9d0ce51f3b305a585aeffd773e848739146be Mon Sep 17 00:00:00 2001 From: Bram Suurd <78373894+BramSuurdje@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:34:21 +0100 Subject: [PATCH 02/25] Fixing missing information on the new Homepage (#191) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mariadb.json * Update vaultwarden.json * Update vaultwarden.json * Update keycloak.json * Update json/keycloak.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Update mariadb.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --------- Co-authored-by: CanbiZ <47820557+MickLesk@users.noreply.github.com> Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- json/keycloak.json | 8 ++++++-- json/mariadb.json | 11 ++++++++--- json/vaultwarden.json | 6 +++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/json/keycloak.json b/json/keycloak.json index b61fb7b31e..e28d3d5453 100644 --- a/json/keycloak.json +++ b/json/keycloak.json @@ -9,7 +9,7 @@ "updateable": false, "privileged": false, "interface_port": "8080", - "documentation": null, + "documentation": "https://github.com/community-scripts/ProxmoxVE/discussions/193", "website": "https://www.keycloak.org/", "logo": "https://www.keycloak.org/resources/images/logo.svg", "description": "Keycloak is an open-source identity and access management solution that provides centralized authentication and authorization for modern applications and services. It enables organizations to secure their applications and services with a single sign-on (SSO) solution, reducing the need for users to remember multiple login credentials. Keycloak supports various authentication protocols, including SAML, OAuth, and OpenID Connect, and integrates with a wide range of applications and services. With Keycloak, administrators can manage user identities, define security policies, and monitor access to their applications and services. The software is designed to be scalable, flexible, and easy to use, making it a valuable tool for enhancing the security and usability of modern applications and services.", @@ -34,6 +34,10 @@ { "text": "First start can take a few minutes", "type": "warning" + }, + { + "text": "This script requires some extra steps after the installation, Please checkout the 'documentation'", + "type": "info" } ] -} \ No newline at end of file +} diff --git a/json/mariadb.json b/json/mariadb.json index 1129d082af..3dfc10097c 100644 --- a/json/mariadb.json +++ b/json/mariadb.json @@ -9,7 +9,7 @@ "updateable": false, "privileged": false, "interface_port": "3306", - "documentation": null, + "documentation": "https://github.com/community-scripts/ProxmoxVE/discussions/192", "website": "https://mariadb.org/", "logo": "https://raw.githubusercontent.com/loganmarchione/homelab-svg-assets/main/assets/mariadb.svg", "description": "MariaDB is a fork of the popular MySQL database management system that is developed and maintained by the open-source community. It is also commercially supported, offering enterprise-level features and support for organizations that require them. MariaDB aims to maintain high compatibility with MySQL, ensuring a drop-in replacement capability.", @@ -30,5 +30,10 @@ "username": null, "password": null }, - "notes": [] -} \ No newline at end of file + "notes": [ + { + "text": "This script requires some extra steps after the installation, Please checkout the 'documentation'", + "type": "info" + } + ] +} diff --git a/json/vaultwarden.json b/json/vaultwarden.json index a05336e9a7..d5d5c66eab 100644 --- a/json/vaultwarden.json +++ b/json/vaultwarden.json @@ -45,6 +45,10 @@ { "text": "Vaultwarden needs to be behind a proxy (Nginx Proxy Manager) to obtain HTTPS and to allow clients to connect.", "type": "warning" + }, + { + "text": "Build Settings for normal LXC: 4GB RAM - 6GB Storage - 4vCPU", + "type": "info" } ] -} \ No newline at end of file +} From ab240646f50c8f17b5927a4337e4638e4b2dce2d Mon Sep 17 00:00:00 2001 From: Bram Suurd <78373894+BramSuurdje@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:09:48 +0100 Subject: [PATCH 03/25] Fixing missing information on the new Homepage (#191) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mariadb.json * Update vaultwarden.json * Update vaultwarden.json * Update keycloak.json * Update json/keycloak.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Update mariadb.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --------- Co-authored-by: CanbiZ <47820557+MickLesk@users.noreply.github.com> Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> From 8f2e917b72d46d916057f576e698c607c73bf2f6 Mon Sep 17 00:00:00 2001 From: Rafael Rivera Date: Tue, 12 Nov 2024 12:48:18 -0800 Subject: [PATCH 04/25] Remove duplicate acknowledgements from README (#199) --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index c34b665d5c..bc60a1811b 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,3 @@ This project is licensed under the terms of the [MIT License](LICENSE). ## 📢  Acknowledgments A special thank you to [tteck](https://github.com/tteck) for his foundational work, which has allowed the Proxmox community to thrive. We’re dedicated to keeping his vision alive and expanding upon it with the continued support of this vibrant community. - -## 📢  Acknowledgments - -A special thank you to [tteck](https://github.com/tteck) for his foundational work, which has allowed the Proxmox community to thrive. We’re dedicated to keeping his vision alive and expanding upon it with the continued support of this vibrant community. From 1633cddf55c0efbb60c825072cc8509afffbc065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Gj=C3=B8by=20Thom?= <34199185+havardthom@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:32:27 +0100 Subject: [PATCH 05/25] Add website issue template (#200) --- .../{bug_report.yaml => script-issue.yaml} | 2 +- .github/ISSUE_TEMPLATE/website-issue.yaml | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) rename .github/ISSUE_TEMPLATE/{bug_report.yaml => script-issue.yaml} (98%) create mode 100644 .github/ISSUE_TEMPLATE/website-issue.yaml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/script-issue.yaml similarity index 98% rename from .github/ISSUE_TEMPLATE/bug_report.yaml rename to .github/ISSUE_TEMPLATE/script-issue.yaml index bed1043316..b8e83878bb 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/script-issue.yaml @@ -1,4 +1,4 @@ -name: Problems with a script. +name: Problems with a script description: Generate a report on an issue pertaining specifically to a script. For other inquires please share them in the Discussions section. body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/website-issue.yaml b/.github/ISSUE_TEMPLATE/website-issue.yaml new file mode 100644 index 0000000000..abfa19f446 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/website-issue.yaml @@ -0,0 +1,45 @@ +name: Problems with the website +description: Generate a report on an issue pertaining specifically to the website (https://community-scripts.github.io/ProxmoxVE/). For other inquires please share them in the Discussions section. +labels: ["website"] +body: + - type: markdown + attributes: + value: | + **IMPORTANT:** Failure to comply with the following guidelines may result in immediate closure. + - Prior to submitting, kindly search the closed issues to check if the problem you are reporting has already been addressed and resolved. If you come across a closed issue that pertains to your problem, please leave a comment on that issue instead of creating a new one. + - For suggestions, questions or feature/script requests, please share them in the [Discussions section.](https://github.com/community-scripts/ProxmoxVE/discussions) + - type: input + id: guidelines + attributes: + label: Please verify that you have read and understood the guidelines. + placeholder: 'yes' + validations: + required: true + - type: textarea + id: bug + attributes: + label: A clear and concise description of the issue. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Please provide a description of the expected behavior. + validations: + required: true + - type: textarea + id: screenshot + attributes: + label: If relevant, including screenshots or a code block can be helpful in clarifying the issue. + placeholder: Code blocks begin and conclude by enclosing the code with three backticks (```) above and below it. + validations: + required: false + - type: textarea + id: reproduce + attributes: + label: Please provide detailed steps to reproduce the issue. + placeholder: First do this, then this ... + validations: + required: false + + From 7e948d349c328ba6d8551a0c107768e193586627 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 13 Nov 2024 22:08:11 +1300 Subject: [PATCH 06/25] Suggested wording and improvements to README (#209) * Proposed rewording * Fixed typo in donations --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bc60a1811b..16100226a7 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ To install the Proxmox Helper Scripts, simply follow these steps: 2. Search for the desired script, e.g. **"Home Assistant OS VM"**. 3. In the **"How To Install"** section, copy the provided **Bash command**. 4. Open the Proxmox shell on your **main node**. -5. Paste the command into the console and let's start! 🚀 +5. Paste the command into the console, hit enter, and you are away! 🚀 For detailed instructions, check out our [official guides](https://github.com/community-scripts/ProxmoxVE/blob/main/USER_SUBMITTED_GUIDES.md). @@ -63,16 +63,14 @@ For detailed instructions, check out our [official guides](https://github.com/co ## ❤️  Community and Contributions -The Proxmox Helper Scripts project is community-driven, and we highly appreciate any contributions—whether it's through reporting bugs, suggesting features, improving documentation, or spreading the word. We are committed to maintaining transparency and sustainability in this open-source effort. +The Proxmox Helper Scripts project is community-driven, and we highly appreciate any contributions — whether it's through reporting bugs, suggesting features, improving documentation, or spreading the word. We are committed to maintaining transparency and sustainability in this open-source effort. -### 💖  Donate to Support the Project +### 💖  Donate to Support the Project (DRAFT) We offer two donation options to help maintain and grow this project: -- **Ko-Fi for tteck**: [Donate to tteck](https://ko-fi.com/proxmoxhelperscripts) - All donations will go directly to support tteck’s legacy and help fund ongoing maintenance of the scripts. -- **Ko-Fi for Community Edition**: [Donate to Community Edition](https://ko-fi.com/community_scripts) - This is a nonprofit organization. All funds will go towards script maintenance, infrastructure, and server costs. Any remaining funds will be donated annually to 2-4 causes (e.g., cancer research, hospice care, etc.). - -Your contributions help keep the project running and support important charitable causes. +- **Ko-Fi for tteck**: [Donate to tteck](https://ko-fi.com/proxmoxhelperscripts) - All donations will go directly to support tteck, the founder of this project. +- **Ko-Fi for Community Edition**: [Donate to this project](https://ko-fi.com/community_scripts) - All funds will go towards script maintenance infrastructure and server costs. **Our most immediate need is funding testing infrastructure**. Your contributions help keep the project running. To honor tteck's legacy this project will also raise money for charity (cancer research, hospice care). Of the money donated to this project, 30% will be donated to charity. Income, expenditure and charitable donations will be disclosed annually in a transparent manner.
@@ -110,3 +108,5 @@ This project is licensed under the terms of the [MIT License](LICENSE). ## 📢  Acknowledgments A special thank you to [tteck](https://github.com/tteck) for his foundational work, which has allowed the Proxmox community to thrive. We’re dedicated to keeping his vision alive and expanding upon it with the continued support of this vibrant community. + +Proxmox® is a registered trademark of [Proxmox Server Solutions GmbH](https://www.proxmox.com/en/about/company). \ No newline at end of file From c162f518e5124cd6e06a422a3ec0df33c358787a Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:05:21 +0100 Subject: [PATCH 07/25] Optimize Jellyfin / Jellyfin-Server update (#215) --- ct/jellyfin.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ct/jellyfin.sh b/ct/jellyfin.sh index ae6e09f12c..41c073a325 100644 --- a/ct/jellyfin.sh +++ b/ct/jellyfin.sh @@ -59,6 +59,7 @@ if [[ ! -d /usr/lib/jellyfin ]]; then msg_error "No ${APP} Installation Found!"; msg_info "Updating ${APP} LXC" apt-get update &>/dev/null apt-get -y upgrade &>/dev/null +apt-get --with-new-pkgs upgrade jellyfin jellyfin-server &>/dev/null msg_ok "Updated ${APP} LXC" exit } From dac521c6a36d7f940cb44e2434e1e6779c2ba987 Mon Sep 17 00:00:00 2001 From: Bram Suurd <78373894+BramSuurdje@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:45:39 +0100 Subject: [PATCH 08/25] Fixing Front end issues related to image loading and SEO (#219) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mariadb.json * Update vaultwarden.json * Update vaultwarden.json * Update keycloak.json * Update json/keycloak.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Update mariadb.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Add canonical link to layout for improved SEO and page indexing * Fix image source fallback for script logos to use a consistent relative path * Fix image source for script logos across components to consistently use the "/ProxmoxVE/logo.png" path * Update image source for script logos to use basePath for consistent paths across all components * Fix image source for script logos to ensure leading slash is consistent for all components' paths --------- Co-authored-by: CanbiZ <47820557+MickLesk@users.noreply.github.com> Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- frontend/src/app/layout.tsx | 1 + .../app/scripts/_components/ScriptAccordion.tsx | 5 +++-- .../app/scripts/_components/ScriptInfoBlocks.tsx | 14 +++++++++++--- .../src/app/scripts/_components/ScriptItem.tsx | 6 ++++-- frontend/src/components/CommandMenu.tsx | 5 +++-- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index b5422c8615..423c7ad1ef 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -64,6 +64,7 @@ export default function RootLayout({ src={`https://${analytics.url}/script.js`} data-website-id={analytics.token} > + diff --git a/frontend/src/app/scripts/_components/ScriptAccordion.tsx b/frontend/src/app/scripts/_components/ScriptAccordion.tsx index 4a39c40e94..96be28da21 100644 --- a/frontend/src/app/scripts/_components/ScriptAccordion.tsx +++ b/frontend/src/app/scripts/_components/ScriptAccordion.tsx @@ -12,6 +12,7 @@ import { cn } from "@/lib/utils"; import Image from "next/image"; import Link from "next/link"; import { useState } from "react"; +import { basePath } from "@/config/siteConfig"; export default function ScriptAccordion({ items, @@ -104,13 +105,13 @@ export default function ScriptAccordion({ >
((e.currentTarget as HTMLImageElement).src = - "/logo.png") + `/${basePath}/logo.png`) } alt={script.name} className="mr-1 w-4 h-4 rounded-full" diff --git a/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx b/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx index 962e516f8b..1c418c94cd 100644 --- a/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx +++ b/frontend/src/app/scripts/_components/ScriptInfoBlocks.tsx @@ -7,7 +7,7 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; -import { mostPopularScripts } from "@/config/siteConfig"; +import { basePath, mostPopularScripts } from "@/config/siteConfig"; import { extractDate } from "@/lib/time"; import { Category, Script } from "@/lib/types"; import { CalendarPlus } from "lucide-react"; @@ -92,11 +92,15 @@ export function LatestScripts({ items }: { items: Category[] }) {
+ ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) + } className="h-11 w-11 object-contain" />
@@ -161,10 +165,14 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
+ ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) + } className="h-11 w-11 object-contain" />
diff --git a/frontend/src/app/scripts/_components/ScriptItem.tsx b/frontend/src/app/scripts/_components/ScriptItem.tsx index 2d9848dbdc..835fce5769 100644 --- a/frontend/src/app/scripts/_components/ScriptItem.tsx +++ b/frontend/src/app/scripts/_components/ScriptItem.tsx @@ -14,6 +14,7 @@ import Description from "./ScriptItems/Description"; import InstallCommand from "./ScriptItems/InstallCommand"; import InterFaces from "./ScriptItems/InterFaces"; import Tooltips from "./ScriptItems/Tooltips"; +import { basePath } from "@/config/siteConfig"; function ScriptItem({ item, @@ -40,10 +41,11 @@ function ScriptItem({
- ((e.currentTarget as HTMLImageElement).src = "/logo.png") + ((e.currentTarget as HTMLImageElement).src = + `/${basePath}/logo.png`) } height={400} alt={item.name} diff --git a/frontend/src/components/CommandMenu.tsx b/frontend/src/components/CommandMenu.tsx index 140897e5a3..b1c8e1267e 100644 --- a/frontend/src/components/CommandMenu.tsx +++ b/frontend/src/components/CommandMenu.tsx @@ -15,6 +15,7 @@ import React from "react"; import { Badge } from "./ui/badge"; import { Button } from "./ui/button"; import { DialogTitle } from "./ui/dialog"; +import { basePath } from "@/config/siteConfig"; export const formattedBadge = (type: string) => { switch (type) { @@ -102,10 +103,10 @@ export default function CommandMenu() { >
setOpen(false)}> ((e.currentTarget as HTMLImageElement).src = - "/logo.png") + `/${basePath}/logo.png`) } unoptimized width={16} From 873c78bfd84c93fc3c1c3eeed896b5dd5cf83653 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 14 Nov 2024 10:11:08 +1300 Subject: [PATCH 09/25] Removed DRAFT label in README. (#232) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16100226a7..4ea7af9d97 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ For detailed instructions, check out our [official guides](https://github.com/co The Proxmox Helper Scripts project is community-driven, and we highly appreciate any contributions — whether it's through reporting bugs, suggesting features, improving documentation, or spreading the word. We are committed to maintaining transparency and sustainability in this open-source effort. -### 💖  Donate to Support the Project (DRAFT) +### 💖  Donate to Support the Project We offer two donation options to help maintain and grow this project: From 2c0749663846e4f85561423396152dc179445a0b Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 14 Nov 2024 10:11:19 +1300 Subject: [PATCH 10/25] Remove DRAFT (#231) * Proposed rewording * Fixed typo in donations * remove draft label From 612f41afddc4d5f08b73178519c00adeacd4d405 Mon Sep 17 00:00:00 2001 From: Bram Suurd <78373894+BramSuurdje@users.noreply.github.com> Date: Wed, 13 Nov 2024 22:33:45 +0100 Subject: [PATCH 11/25] Enhance Alerts component with dynamic colored notes using AlertColors from config for better visibility and consistency (#229) --- .../scripts/_components/ScriptItems/Alerts.tsx | 16 ++++++++++++++-- frontend/src/config/siteConfig.tsx | 7 +++++++ frontend/src/lib/types.ts | 4 +++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx b/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx index e4c56e1605..8d84a52a60 100644 --- a/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx +++ b/frontend/src/app/scripts/_components/ScriptItems/Alerts.tsx @@ -1,14 +1,26 @@ import TextCopyBlock from "@/components/TextCopyBlock"; +import { AlertColors } from "@/config/siteConfig"; import { Script } from "@/lib/types"; +import { cn } from "@/lib/utils"; import { Info } from "lucide-react"; +type NoteProps = { + text: string; + type: keyof typeof AlertColors; +} + export default function Alerts({ item }: { item: Script }) { return ( <> {item?.notes?.length > 0 && - item.notes.map((note: any, index: number) => ( + item.notes.map((note: NoteProps, index: number) => (
-

+

{TextCopyBlock(note.text)}

diff --git a/frontend/src/config/siteConfig.tsx b/frontend/src/config/siteConfig.tsx index 301a08c6d2..5fa0a8ed83 100644 --- a/frontend/src/config/siteConfig.tsx +++ b/frontend/src/config/siteConfig.tsx @@ -34,3 +34,10 @@ export const analytics = { url: "analytics.proxmoxve-scripts.com", token: "b60d3032-1a11-4244-a100-81d26c5c49a7", }; + +export const AlertColors = { + warning: + "border-yellow-400 bg-yellow-50 dark:border-yellow-900 dark:bg-yellow-900", + danger: "border-red-500/25 bg-destructive/25", + info: "border-cyan-500/25 bg-cyan-50 dark:border-cyan-900/25 dark:bg-cyan-900", +}; \ No newline at end of file diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 4f8d2ef235..3541d86a9f 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -1,3 +1,5 @@ +import { AlertColors } from "@/config/siteConfig"; + export type Script = { name: string; slug: string; @@ -29,7 +31,7 @@ export type Script = { notes: [ { text: string; - type: string; + type: keyof typeof AlertColors; }, ]; }; From f7adce2fdaae90c2ca3bc2a37b0c34abf51cc461 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:52:36 +0100 Subject: [PATCH 12/25] Remove Update Code from Adguard Home (#213) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove Update Code from Adguard Home * Update adguard.json * Update ct/adguard.sh Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Update json/adguard.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * improve Text in json --------- Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- ct/adguard.sh | 23 +---------------------- json/adguard.json | 9 +++++++-- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/ct/adguard.sh b/ct/adguard.sh index 6f4cf6f061..78ca4ec55f 100644 --- a/ct/adguard.sh +++ b/ct/adguard.sh @@ -60,28 +60,7 @@ if (( $(df /boot | awk 'NR==2{gsub("%","",$5); print $5}') > 80 )); then read -r -p "Warning: Storage is dangerously low, continue anyway? " prompt [[ ${prompt,,} =~ ^(y|yes)$ ]] || exit fi -wget -qL https://static.adguard.com/adguardhome/release/AdGuardHome_linux_amd64.tar.gz -msg_info "Stopping AdguardHome" -systemctl stop AdGuardHome -msg_ok "Stopped AdguardHome" - -msg_info "Updating AdguardHome" -tar -xvf AdGuardHome_linux_amd64.tar.gz &>/dev/null -mkdir -p adguard-backup -cp -r /opt/AdGuardHome/AdGuardHome.yaml /opt/AdGuardHome/data adguard-backup/ -cp AdGuardHome/AdGuardHome /opt/AdGuardHome/AdGuardHome -cp -r adguard-backup/* /opt/AdGuardHome/ -msg_ok "Updated AdguardHome" - -msg_info "Starting AdguardHome" -systemctl start AdGuardHome -msg_ok "Started AdguardHome" - -msg_info "Cleaning Up" -rm -rf AdGuardHome_linux_amd64.tar.gz AdGuardHome adguard-backup -msg_ok "Cleaned" -msg_ok "Updated Successfully" -exit +echo "Adguard Home should be updated via the user interface. You can access it at: ${BL}http://${IP}:3000" } start diff --git a/json/adguard.json b/json/adguard.json index fc2640ae13..ce11c7e90e 100644 --- a/json/adguard.json +++ b/json/adguard.json @@ -30,5 +30,10 @@ "username": null, "password": null }, - "notes": [] -} \ No newline at end of file + "notes": [ + { + "text": "Adguard Home can be updated via the user interface.", + "type": "warning" + } + ] +} From 3ef371805692d3e7108402583ff437dc814bc6c9 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:58:19 +0100 Subject: [PATCH 13/25] Merge adguard.sh (#238) --- ct/adguard.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ct/adguard.sh b/ct/adguard.sh index 78ca4ec55f..fa95241f48 100644 --- a/ct/adguard.sh +++ b/ct/adguard.sh @@ -60,7 +60,7 @@ if (( $(df /boot | awk 'NR==2{gsub("%","",$5); print $5}') > 80 )); then read -r -p "Warning: Storage is dangerously low, continue anyway? " prompt [[ ${prompt,,} =~ ^(y|yes)$ ]] || exit fi -echo "Adguard Home should be updated via the user interface. You can access it at: ${BL}http://${IP}:3000" +echo "Adguard Home should be updated via the user interface." } start From 72bee4454308bcb48406131649d349465cb92238 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 14 Nov 2024 00:05:55 +0100 Subject: [PATCH 14/25] remove storage Check in adguard.sh --- ct/adguard.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ct/adguard.sh b/ct/adguard.sh index fa95241f48..dd07e48b81 100644 --- a/ct/adguard.sh +++ b/ct/adguard.sh @@ -52,15 +52,11 @@ function default_settings() { VERB="no" echo_default } - function update_script() { header_info if [[ ! -d /opt/AdGuardHome ]]; then msg_error "No ${APP} Installation Found!"; exit; fi -if (( $(df /boot | awk 'NR==2{gsub("%","",$5); print $5}') > 80 )); then - read -r -p "Warning: Storage is dangerously low, continue anyway? " prompt - [[ ${prompt,,} =~ ^(y|yes)$ ]] || exit -fi -echo "Adguard Home should be updated via the user interface." +msg_error "Adguard Home should be updated via the user interface." +exit } start From 4e1a2bde2416e2636014bbf3527d6cd95b39688c Mon Sep 17 00:00:00 2001 From: Bram Suurd <78373894+BramSuurdje@users.noreply.github.com> Date: Thu, 14 Nov 2024 09:08:45 +0100 Subject: [PATCH 15/25] Add JSON Generator page for easier configuring of new metadata (#230) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update mariadb.json * Update vaultwarden.json * Update vaultwarden.json * Update keycloak.json * Update json/keycloak.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Update mariadb.json Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> * Add canonical link to layout for improved SEO and page indexing * Fix image source fallback for script logos to use a consistent relative path * Fix image source for script logos across components to consistently use the "/ProxmoxVE/logo.png" path * Update image source for script logos to use basePath for consistent paths across all components * Fix image source for script logos to ensure leading slash is consistent for all components' paths * Add JSON generator component with validation and UI elements for managing scripts, categories, and installation methods * Add calendar and label components; enhance JSON generator with date selection and script path updates for installation methods * Enhance Alerts component with dynamic colored notes using AlertColors from config for better visibility and consistency * Remove MultiSelect component * Update JSON generator: streamline install methods, enhance note type selection, and refine button behavior for better UX * Refactor AlertColors: unify warning and danger styles for consistency and improved visual hierarchy in alerts * Enhance JSONGenerator: improve SelectItem layout with color indicators for better visual representation of alert types * Refactor JSON schema definitions in JSONGenerator: separate InstallMethod and Note schemas for better structure and readability * Fix JSONGenerator: streamline SelectItem markup and enhance JSON display layout for improved readability and user experience * Refactor JSON schema handling: move schema definitions to separate file * Enhance error handling in JSONGenerator: display Zod validation errors on user input for better feedback and debugging * Export InstallMethodSchema and integrate into JSONGenerator for better validation of install method data input * Add Categories and Note components to JSONGenerator for better organization and modularity in the JSON editing interface * Remove unused imports --------- Co-authored-by: CanbiZ <47820557+MickLesk@users.noreply.github.com> Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- frontend/package-lock.json | 180 +++++++++- frontend/package.json | 9 +- .../json-editor/_components/Categories.tsx | 103 ++++++ .../json-editor/_components/InstallMethod.tsx | 189 ++++++++++ .../src/app/json-editor/_components/Note.tsx | 115 +++++++ .../src/app/json-editor/_schemas/schemas.ts | 43 +++ frontend/src/app/json-editor/page.tsx | 323 ++++++++++++++++++ frontend/src/components/ui/alert.tsx | 59 ++++ frontend/src/components/ui/calendar.tsx | 66 ++++ frontend/src/components/ui/label.tsx | 26 ++ frontend/src/components/ui/popover.tsx | 31 ++ frontend/src/components/ui/select.tsx | 160 +++++++++ frontend/src/components/ui/switch.tsx | 29 ++ frontend/src/components/ui/textarea.tsx | 22 ++ frontend/src/config/siteConfig.tsx | 4 +- 15 files changed, 1354 insertions(+), 5 deletions(-) create mode 100644 frontend/src/app/json-editor/_components/Categories.tsx create mode 100644 frontend/src/app/json-editor/_components/InstallMethod.tsx create mode 100644 frontend/src/app/json-editor/_components/Note.tsx create mode 100644 frontend/src/app/json-editor/_schemas/schemas.ts create mode 100644 frontend/src/app/json-editor/page.tsx create mode 100644 frontend/src/components/ui/alert.tsx create mode 100644 frontend/src/components/ui/calendar.tsx create mode 100644 frontend/src/components/ui/label.tsx create mode 100644 frontend/src/components/ui/popover.tsx create mode 100644 frontend/src/components/ui/select.tsx create mode 100644 frontend/src/components/ui/switch.tsx create mode 100644 frontend/src/components/ui/textarea.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c2e0b68f0f..851edf9b8e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,15 +13,20 @@ "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.1", + "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.2", "@vercel/analytics": "^1.2.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", + "date-fns": "^4.1.0", "framer-motion": "^11.11.11", "fuse.js": "^7.0.0", "lucide-react": "^0.453.0", @@ -33,13 +38,15 @@ "prettier-plugin-organize-imports": "^4.1.0", "react": "19.0.0-rc-02c0e824-20241028", "react-code-blocks": "^0.1.6", + "react-day-picker": "8.10.1", "react-dom": "19.0.0-rc-02c0e824-20241028", "react-icons": "^5.1.0", "react-simple-typewriter": "^5.0.1", "sharp": "^0.33.5", "simple-icons": "^13.5.0", "sonner": "^1.5.0", - "tailwind-merge": "^2.3.0" + "tailwind-merge": "^2.3.0", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^22", @@ -1028,6 +1035,12 @@ "node": ">=14" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", + "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==", + "license": "MIT" + }, "node_modules/@radix-ui/primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", @@ -1362,6 +1375,29 @@ } } }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-menu": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz", @@ -1438,6 +1474,43 @@ } } }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.2.tgz", + "integrity": "sha512-u2HRUyWW+lOiA2g0Le0tMmT55FGOEWHwPFt1EPfbLly7uXQExFo5duNKqG2DzmFXIdqOeNd+TpE8baHWJCyP9w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", @@ -1602,6 +1675,49 @@ } } }, + "node_modules/@radix-ui/react-select": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.2.tgz", + "integrity": "sha512-rZJtWmorC7dFRi0owDmoijm6nSJH1tVw64QGiNIZ9PNLyBDtG+iAq+XGsya052At4BfarzY/Dhv9wrrUr6IMZA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.6.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", @@ -1643,6 +1759,35 @@ } } }, + "node_modules/@radix-ui/react-switch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.1.tgz", + "integrity": "sha512-diPqDDoBcZPSicYoMWdWx+bCPuTRH4QSp9J+65IvtdS0Kuzt67bI6n32vCj8q6NZmYW/ah+2orOtMwcX5eQwIg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-tabs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.1.tgz", @@ -2935,6 +3080,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -6035,6 +6190,20 @@ "react": ">=16" } }, + "node_modules/react-day-picker": { + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz", + "integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "date-fns": "^2.28.0 || ^3.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "19.0.0-rc-02c0e824-20241028", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc-02c0e824-20241028.tgz", @@ -7550,6 +7719,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 6bd130d2b6..4d09c07474 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,15 +23,20 @@ "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.1", + "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.2", "@vercel/analytics": "^1.2.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", + "date-fns": "^4.1.0", "framer-motion": "^11.11.11", "fuse.js": "^7.0.0", "lucide-react": "^0.453.0", @@ -43,13 +48,15 @@ "prettier-plugin-organize-imports": "^4.1.0", "react": "19.0.0-rc-02c0e824-20241028", "react-code-blocks": "^0.1.6", + "react-day-picker": "8.10.1", "react-dom": "19.0.0-rc-02c0e824-20241028", "react-icons": "^5.1.0", "react-simple-typewriter": "^5.0.1", "sharp": "^0.33.5", "simple-icons": "^13.5.0", "sonner": "^1.5.0", - "tailwind-merge": "^2.3.0" + "tailwind-merge": "^2.3.0", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^22", diff --git a/frontend/src/app/json-editor/_components/Categories.tsx b/frontend/src/app/json-editor/_components/Categories.tsx new file mode 100644 index 0000000000..e3f4c61c81 --- /dev/null +++ b/frontend/src/app/json-editor/_components/Categories.tsx @@ -0,0 +1,103 @@ +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Category } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import { z } from "zod"; +import { ScriptSchema } from "../_schemas/schemas"; + +type Script = z.infer; + +type CategoryProps = { + script: Script; + setScript: (script: Script) => void; + setIsValid: (isValid: boolean) => void; + setZodErrors: (zodErrors: z.ZodError | null) => void; + categories: Category[]; +}; + +export default function Categories({ + script, + setScript, + categories, +}: Omit) { + const addCategory = (categoryId: number) => { + setScript({ + ...script, + categories: [...new Set([...script.categories, categoryId])], + }); + }; + + const removeCategory = (categoryId: number) => { + setScript({ + ...script, + categories: script.categories.filter((id: number) => id !== categoryId), + }); + }; + + return ( + <> +
+ + +
+ {script.categories.map((categoryId) => { + const category = categories.find((c) => c.id === categoryId); + return category ? ( + + {category.name} + + + ) : null; + })} +
+
+ + ); +} diff --git a/frontend/src/app/json-editor/_components/InstallMethod.tsx b/frontend/src/app/json-editor/_components/InstallMethod.tsx new file mode 100644 index 0000000000..df0ef66e72 --- /dev/null +++ b/frontend/src/app/json-editor/_components/InstallMethod.tsx @@ -0,0 +1,189 @@ +import { Button } from "@/components/ui/button"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { PlusCircle, Trash2 } from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { z } from "zod"; +import { InstallMethodSchema, ScriptSchema } from "../_schemas/schemas"; + +type Script = z.infer; + +type InstallMethodProps = { + script: Script; + setScript: (value: Script | ((prevState: Script) => Script)) => void; + setIsValid: (isValid: boolean) => void; + setZodErrors: (zodErrors: z.ZodError | null) => void; +}; + +export default function InstallMethod({ + script, + setScript, + setIsValid, + setZodErrors, +}: InstallMethodProps) { + const addInstallMethod = () => { + setScript((prev) => { + const method = InstallMethodSchema.parse({ + type: "default", + script: `/${prev.type}/${prev.slug}.sh`, + resources: { + cpu: null, + ram: null, + hdd: null, + os: null, + version: null, + }, + }); + return { + ...prev, + install_methods: [...prev.install_methods, method], + }; + }); + }; + + const updateInstallMethod = ( + index: number, + key: keyof Script["install_methods"][number], + value: Script["install_methods"][number][keyof Script["install_methods"][number]], + ) => { + setScript((prev) => { + const updatedMethods = prev.install_methods.map((method, i) => { + if (i === index) { + const updatedMethod = { ...method, [key]: value }; + + if (key === "type") { + updatedMethod.script = + value === "alpine" + ? `/${prev.type}/alpine-${prev.slug}.sh` + : `/${prev.type}/${prev.slug}.sh`; + } + + return updatedMethod; + } + return method; + }); + + const updated = { + ...prev, + install_methods: updatedMethods, + }; + + const result = ScriptSchema.safeParse(updated); + setIsValid(result.success); + if (!result.success) { + setZodErrors(result.error); + } else { + setZodErrors(null); + } + return updated; + }); + }; + + const removeInstallMethod = (index: number) => { + setScript((prev) => ({ + ...prev, + install_methods: prev.install_methods.filter((_, i) => i !== index), + })); + }; + + return ( + <> +

Install Methods

+ {script.install_methods.map((method, index) => ( +
+ +
+ ) => + updateInstallMethod(index, "resources", { + ...method.resources, + cpu: e.target.value ? Number(e.target.value) : null, + }) + } + /> + ) => + updateInstallMethod(index, "resources", { + ...method.resources, + ram: e.target.value ? Number(e.target.value) : null, + }) + } + /> + ) => + updateInstallMethod(index, "resources", { + ...method.resources, + hdd: e.target.value ? Number(e.target.value) : null, + }) + } + /> +
+
+ ) => + updateInstallMethod(index, "resources", { + ...method.resources, + os: e.target.value || null, + }) + } + /> + ) => + updateInstallMethod(index, "resources", { + ...method.resources, + version: e.target.value ? Number(e.target.value) : null, + }) + } + /> +
+ +
+ ))} + + + ); +} diff --git a/frontend/src/app/json-editor/_components/Note.tsx b/frontend/src/app/json-editor/_components/Note.tsx new file mode 100644 index 0000000000..84fc35d3ba --- /dev/null +++ b/frontend/src/app/json-editor/_components/Note.tsx @@ -0,0 +1,115 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { AlertColors } from "@/config/siteConfig"; +import { cn } from "@/lib/utils"; +import { PlusCircle, Trash2 } from "lucide-react"; +import { z } from "zod"; +import { ScriptSchema } from "../_schemas/schemas"; + +type Script = z.infer; + +type NoteProps = { + script: Script; + setScript: (script: Script) => void; + setIsValid: (isValid: boolean) => void; + setZodErrors: (zodErrors: z.ZodError | null) => void; +}; +export default function Note({ + script, + setScript, + setIsValid, + setZodErrors, +}: NoteProps) { + const addNote = () => { + const newScript: Script = { + ...script, + notes: [...script.notes, { text: "", type: "" }], + }; + setScript(newScript); + }; + + const updateNote = ( + index: number, + key: keyof Script["notes"][number], + value: string, + ) => { + const updated: Script = { + ...script, + notes: script.notes.map((note: Script["notes"][number], i: number) => + i === index ? { ...note, [key]: value } : note, + ), + }; + const result = ScriptSchema.safeParse(updated); + setIsValid(result.success); + if (!result.success) { + setZodErrors(result.error); + } else { + setZodErrors(null); + } + setScript(updated); + }; + + const removeNote = (index: number) => { + const newScript: Script = { + ...script, + notes: script.notes.filter((_: Script["notes"][number], i: number) => i !== index), + }; + setScript(newScript); + }; + + return ( + <> +

Notes

+ {script.notes.map((note, index) => ( +
+ ) => updateNote(index, "text", e.target.value)} + /> + + +
+ ))} + + + ); +} diff --git a/frontend/src/app/json-editor/_schemas/schemas.ts b/frontend/src/app/json-editor/_schemas/schemas.ts new file mode 100644 index 0000000000..1a67968847 --- /dev/null +++ b/frontend/src/app/json-editor/_schemas/schemas.ts @@ -0,0 +1,43 @@ +import { z } from "zod"; + +export const InstallMethodSchema = z.object({ + type: z.enum(["default", "alpine"], { + errorMap: () => ({ message: "Type must be either 'default' or 'alpine'" }) + }), + script: z.string().min(1, "Script content cannot be empty"), + resources: z.object({ + cpu: z.number().nullable(), + ram: z.number().nullable(), + hdd: z.number().nullable(), + os: z.string().nullable(), + version: z.number().nullable(), + }), +}); + +const NoteSchema = z.object({ + text: z.string().min(1, "Note text cannot be empty"), + type: z.string().min(1, "Note type cannot be empty"), +}); + +export const ScriptSchema = z.object({ + name: z.string().min(1, "Name is required"), + slug: z.string().min(1, "Slug is required"), + categories: z.array(z.number()), + date_created: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").min(1, "Date is required"), + type: z.enum(["vm", "ct", "misc"], { + errorMap: () => ({ message: "Type must be either 'vm', 'ct', or 'misc'" }) + }), + updateable: z.boolean(), + privileged: z.boolean(), + interface_port: z.number().nullable(), + documentation: z.string().nullable(), + website: z.string().url().nullable(), + logo: z.string().url().nullable(), + description: z.string().min(1, "Description is required"), + install_methods: z.array(InstallMethodSchema).min(1, "At least one install method is required"), + default_credentials: z.object({ + username: z.string().nullable(), + password: z.string().nullable(), + }), + notes: z.array(NoteSchema), +}); diff --git a/frontend/src/app/json-editor/page.tsx b/frontend/src/app/json-editor/page.tsx new file mode 100644 index 0000000000..144478b046 --- /dev/null +++ b/frontend/src/app/json-editor/page.tsx @@ -0,0 +1,323 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { Textarea } from "@/components/ui/textarea"; +import { fetchCategories } from "@/lib/data"; +import { Category } from "@/lib/types"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import { CalendarIcon, Check, Clipboard } from "lucide-react"; +import { useEffect, useState } from "react"; +import { toast } from "sonner"; +import { z } from "zod"; +import Categories from "./_components/Categories"; +import InstallMethod from "./_components/InstallMethod"; +import Note from "./_components/Note"; +import { ScriptSchema } from "./_schemas/schemas"; + +type Script = z.infer; + +export default function JSONGenerator() { + const [script, setScript] = useState