From 0067075ed109c5a0330269250591eec4f7ef5739 Mon Sep 17 00:00:00 2001 From: Bram Suurd <78373894+BramSuurdje@users.noreply.github.com> Date: Sat, 28 Jun 2025 00:38:09 +0200 Subject: [PATCH] Remove npm legacy errors, created single source of truth for ESlint. updated analytics url. updated script background (#5498) * Update ScriptAccordion and ScriptItem components for improved styling * Add README.md for Proxmox VE Helper-Scripts Frontend * Remove testing dependencies and related test files from the frontend project * Update analytics URL in siteConfig to point to community-scripts.org * Refactor ESLint configuration to have one source of truth and run "npm lint" to apply new changes * Update lint script in package.json to remove npm * Add 'next' option to ESLint configuration for improved compatibility * Update package dependencies and versions in package.json and package-lock.json * Refactor theme provider import and enhance calendar component for dynamic icon rendering * rename sidebar, alerts and buttons * rename description and interfaces files * rename more files * change folder name * Refactor tooltip logic to improve updateable condition handling * Enhance CommandMenu to prevent duplicate scripts across categories * Remove test step from frontend CI/CD workflow --- .github/workflows/frontend-cicd.yml | 3 - frontend/.eslintrc.json | 5 - frontend/.vscode/settings.json | 51 + frontend/README.md | 281 + frontend/eslint.config.mjs | 41 + frontend/package-lock.json | 8376 ++++++++++++----- frontend/package.json | 30 +- frontend/src/__tests__/app/page.test.tsx | 11 - .../__tests__/public/validate-json.test.ts | 56 - frontend/src/__tests__/setupTests.ts | 4 - frontend/src/app/api/categories/route.ts | 30 +- frontend/src/app/api/versions/route.ts | 23 +- frontend/src/app/category-view/page.tsx | 357 +- frontend/src/app/data/page.tsx | 160 +- .../src/app/json-editor/_components/Note.tsx | 150 - .../{Categories.tsx => categories.tsx} | 48 +- .../{InstallMethod.tsx => install-method.tsx} | 71 +- .../src/app/json-editor/_components/note.tsx | 159 + .../src/app/json-editor/_schemas/schemas.ts | 4 +- frontend/src/app/json-editor/page.tsx | 108 +- frontend/src/app/layout.tsx | 20 +- frontend/src/app/manifest.ts | 7 +- frontend/src/app/page.tsx | 40 +- frontend/src/app/robots.ts | 3 +- .../_components/ScriptItems/InterFaces.tsx | 21 - ...InstallCommand.tsx => install-command.tsx} | 110 +- .../src/app/scripts/_components/Sidebar.tsx | 43 - ...sourceDisplay.tsx => resource-display.tsx} | 11 +- ...riptAccordion.tsx => script-accordion.tsx} | 39 +- ...tInfoBlocks.tsx => script-info-blocks.tsx} | 45 +- .../{ScriptItem.tsx => script-item.tsx} | 65 +- .../Alerts.tsx => script-items/alerts.tsx} | 28 +- .../Buttons.tsx => script-items/buttons.tsx} | 29 +- .../config-file.tsx} | 0 .../default-password.tsx} | 37 +- .../default-settings.tsx} | 23 +- .../description.tsx} | 5 +- .../script-items/install-command.tsx | 149 + .../_components/script-items/interfaces.tsx | 25 + .../tool-tips.tsx} | 19 +- .../src/app/scripts/_components/sidebar.tsx | 46 + .../{VersionBadge.tsx => version-badge.tsx} | 6 +- frontend/src/app/scripts/page.tsx | 48 +- frontend/src/app/sitemap.ts | 9 +- frontend/src/components/Navbar.tsx | 86 - ...icationChart.tsx => application-chart.tsx} | 48 +- .../{CommandMenu.tsx => command-menu.tsx} | 143 +- frontend/src/components/{FAQ.tsx => faq.tsx} | 3 +- .../src/components/{Footer.tsx => footer.tsx} | 19 +- .../{handleCopy.tsx => handle-copy.tsx} | 0 .../src/components/{Modal.tsx => modal.tsx} | 7 +- frontend/src/components/navbar.tsx | 86 + ...{TextCopyBlock.tsx => text-copy-block.tsx} | 6 +- frontend/src/components/theme-provider.tsx | 3 +- frontend/src/components/ui/alert.tsx | 26 +- .../components/ui/animated-gradient-text.tsx | 4 +- frontend/src/components/ui/badge.tsx | 8 +- frontend/src/components/ui/button.tsx | 21 +- frontend/src/components/ui/calendar.tsx | 32 +- .../src/components/ui/code-copy-button.tsx | 18 +- frontend/src/components/ui/codeblock.tsx | 51 +- frontend/src/components/ui/command.tsx | 15 +- .../src/components/ui/config-copy-button.tsx | 18 +- frontend/src/components/ui/dialog.tsx | 44 +- frontend/src/components/ui/dropdown-menu.tsx | 18 +- frontend/src/components/ui/input.tsx | 3 +- frontend/src/components/ui/label.tsx | 26 +- .../src/components/ui/navigation-menu.tsx | 11 +- frontend/src/components/ui/number-ticker.tsx | 8 +- frontend/src/components/ui/particles.tsx | 46 +- frontend/src/components/ui/popover.tsx | 20 +- frontend/src/components/ui/select.tsx | 78 +- frontend/src/components/ui/sheet.tsx | 52 +- frontend/src/components/ui/sonner.tsx | 6 +- .../components/ui/star-on-github-button.tsx | 18 +- frontend/src/components/ui/switch.tsx | 18 +- frontend/src/components/ui/table.tsx | 52 +- frontend/src/components/ui/textarea.tsx | 14 +- frontend/src/components/ui/theme-toggle.tsx | 12 +- frontend/src/components/ui/tooltip.tsx | 22 +- .../config/{faqConfig.tsx => faq-config.tsx} | 4 +- frontend/src/config/site-config.tsx | 72 + frontend/src/config/siteConfig.tsx | 72 - .../hooks/{useVersions.ts => use-versions.ts} | 6 +- frontend/src/lib/data.ts | 12 +- frontend/src/lib/types.ts | 14 +- frontend/src/lib/utils.ts | 4 +- frontend/src/styles/globals.css | 3 +- frontend/tailwind.config.ts | 25 +- frontend/tsconfig.json | 30 +- frontend/vitest.config.mjs | 12 +- 91 files changed, 8049 insertions(+), 4043 deletions(-) delete mode 100644 frontend/.eslintrc.json create mode 100644 frontend/.vscode/settings.json create mode 100644 frontend/README.md create mode 100644 frontend/eslint.config.mjs delete mode 100644 frontend/src/__tests__/app/page.test.tsx delete mode 100644 frontend/src/__tests__/public/validate-json.test.ts delete mode 100644 frontend/src/__tests__/setupTests.ts delete mode 100644 frontend/src/app/json-editor/_components/Note.tsx rename frontend/src/app/json-editor/_components/{Categories.tsx => categories.tsx} (77%) rename frontend/src/app/json-editor/_components/{InstallMethod.tsx => install-method.tsx} (84%) create mode 100644 frontend/src/app/json-editor/_components/note.tsx delete mode 100644 frontend/src/app/scripts/_components/ScriptItems/InterFaces.tsx rename frontend/src/app/scripts/_components/ScriptItems/{InstallCommand.tsx => install-command.tsx} (50%) delete mode 100644 frontend/src/app/scripts/_components/Sidebar.tsx rename frontend/src/app/scripts/_components/{ResourceDisplay.tsx => resource-display.tsx} (91%) rename frontend/src/app/scripts/_components/{ScriptAccordion.tsx => script-accordion.tsx} (83%) rename frontend/src/app/scripts/_components/{ScriptInfoBlocks.tsx => script-info-blocks.tsx} (85%) rename frontend/src/app/scripts/_components/{ScriptItem.tsx => script-item.tsx} (78%) rename frontend/src/app/scripts/_components/{ScriptItems/Alerts.tsx => script-items/alerts.tsx} (55%) rename frontend/src/app/scripts/_components/{ScriptItems/Buttons.tsx => script-items/buttons.tsx} (90%) rename frontend/src/app/scripts/_components/{ScriptItems/ConfigFile.tsx => script-items/config-file.tsx} (100%) rename frontend/src/app/scripts/_components/{ScriptItems/DefaultPassword.tsx => script-items/default-password.tsx} (55%) rename frontend/src/app/scripts/_components/{ScriptItems/DefaultSettings.tsx => script-items/default-settings.tsx} (60%) rename frontend/src/app/scripts/_components/{ScriptItems/Description.tsx => script-items/description.tsx} (74%) create mode 100644 frontend/src/app/scripts/_components/script-items/install-command.tsx create mode 100644 frontend/src/app/scripts/_components/script-items/interfaces.tsx rename frontend/src/app/scripts/_components/{ScriptItems/Tooltips.tsx => script-items/tool-tips.tsx} (84%) create mode 100644 frontend/src/app/scripts/_components/sidebar.tsx rename frontend/src/app/scripts/_components/{VersionBadge.tsx => version-badge.tsx} (74%) delete mode 100644 frontend/src/components/Navbar.tsx rename frontend/src/components/{ApplicationChart.tsx => application-chart.tsx} (93%) rename frontend/src/components/{CommandMenu.tsx => command-menu.tsx} (62%) rename frontend/src/components/{FAQ.tsx => faq.tsx} (96%) rename frontend/src/components/{Footer.tsx => footer.tsx} (82%) rename frontend/src/components/{handleCopy.tsx => handle-copy.tsx} (100%) rename frontend/src/components/{Modal.tsx => modal.tsx} (92%) create mode 100644 frontend/src/components/navbar.tsx rename frontend/src/components/{TextCopyBlock.tsx => text-copy-block.tsx} (92%) rename frontend/src/config/{faqConfig.tsx => faq-config.tsx} (88%) create mode 100644 frontend/src/config/site-config.tsx delete mode 100644 frontend/src/config/siteConfig.tsx rename frontend/src/hooks/{useVersions.ts => use-versions.ts} (91%) diff --git a/.github/workflows/frontend-cicd.yml b/.github/workflows/frontend-cicd.yml index b092ca1e9..1e045517a 100644 --- a/.github/workflows/frontend-cicd.yml +++ b/.github/workflows/frontend-cicd.yml @@ -44,9 +44,6 @@ jobs: - name: Install dependencies run: npm ci --prefer-offline --legacy-peer-deps - - name: Run tests - run: npm run test - - name: Configure Next.js for pages uses: actions/configure-pages@v5 with: diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json deleted file mode 100644 index 32ef36a56..000000000 --- a/frontend/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": ["next/core-web-vitals"], - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"] -} diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json new file mode 100644 index 000000000..9f2f44827 --- /dev/null +++ b/frontend/.vscode/settings.json @@ -0,0 +1,51 @@ +{ + // Disable the default formatter, use eslint instead + "prettier.enable": false, + "editor.formatOnSave": false, + + // Auto fix + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "never" + }, + + // Silent the stylistic rules in you IDE, but still auto fix them + "eslint.rules.customizations": [ + { "rule": "style/*", "severity": "off", "fixable": true }, + { "rule": "format/*", "severity": "off", "fixable": true }, + { "rule": "*-indent", "severity": "off", "fixable": true }, + { "rule": "*-spacing", "severity": "off", "fixable": true }, + { "rule": "*-spaces", "severity": "off", "fixable": true }, + { "rule": "*-order", "severity": "off", "fixable": true }, + { "rule": "*-dangle", "severity": "off", "fixable": true }, + { "rule": "*-newline", "severity": "off", "fixable": true }, + { "rule": "*quotes", "severity": "off", "fixable": true }, + { "rule": "*semi", "severity": "off", "fixable": true } + ], + + // Enable eslint for all supported languages + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "vue", + "html", + "markdown", + "json", + "json5", + "jsonc", + "yaml", + "toml", + "xml", + "gql", + "graphql", + "astro", + "svelte", + "css", + "less", + "scss", + "pcss", + "postcss" + ] +} diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 000000000..5021df53a --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,281 @@ +# Proxmox VE Helper-Scripts Frontend + +> ๐ **Modern frontend for the Community-Scripts Proxmox VE Helper-Scripts repository** + +A comprehensive, user-friendly interface built with Next.js that provides access to 300+ automation scripts for Proxmox Virtual Environment management. This frontend serves as the official website for the Community-Scripts organization's Proxmox VE Helper-Scripts repository. + + + + + + + +## ๐ Features + +### Core Functionality + +- **๐ Script Management**: Browse, search, and filter 300+ Proxmox VE scripts +- **๐ฑ Responsive Design**: Mobile-first approach with modern UI/UX +- **๐ Advanced Search**: Fuzzy search with category filtering +- **๐ Analytics Integration**: Built-in analytics for usage tracking +- **๐ Dark/Light Mode**: Theme switching with system preference detection +- **โก Performance Optimized**: Static site generation for lightning-fast loading + +### Technical Features + +- **๐จ Modern UI Components**: Built with Radix UI and shadcn/ui +- **๐ Data Visualization**: Charts and metrics using Chart.js +- **๐ State Management**: React Query for efficient data fetching +- **๐ Type Safety**: Full TypeScript implementation +- **๐ Static Export**: Optimized for GitHub Pages deployment + +## ๐ ๏ธ Tech Stack + +### Frontend Framework + +- **[Next.js 15.2.4](https://nextjs.org/)** - React framework with App Router +- **[React 19.0.0](https://react.dev/)** - Latest React with concurrent features +- **[TypeScript 5.8.2](https://www.typescriptlang.org/)** - Type-safe JavaScript + +### Styling & UI + +- **[Tailwind CSS 3.4.17](https://tailwindcss.com/)** - Utility-first CSS framework +- **[Radix UI](https://www.radix-ui.com/)** - Unstyled, accessible UI components +- **[shadcn/ui](https://ui.shadcn.com/)** - Re-usable components built on Radix UI +- **[Framer Motion](https://www.framer.com/motion/)** - Animation library +- **[Lucide React](https://lucide.dev/)** - Icon library + +### Data & State Management + +- **[TanStack Query 5.71.1](https://tanstack.com/query)** - Powerful data synchronization +- **[Zod 3.24.2](https://zod.dev/)** - TypeScript-first schema validation +- **[nuqs 2.4.1](https://nuqs.47ng.com/)** - Type-safe search params state manager + +### Development Tools + +- **[Vitest 3.1.1](https://vitest.dev/)** - Fast unit testing framework +- **[React Testing Library](https://testing-library.com/react)** - Simple testing utilities +- **[ESLint](https://eslint.org/)** - Code linting and formatting +- **[Prettier](https://prettier.io/)** - Code formatting + +### Additional Libraries + +- **[Chart.js](https://www.chartjs.org/)** - Data visualization +- **[Fuse.js](https://fusejs.io/)** - Fuzzy search +- **[date-fns](https://date-fns.org/)** - Date utility library +- **[Next Themes](https://github.com/pacocoursey/next-themes)** - Theme management + +## ๐ Getting Started + +### Prerequisites + +- **Node.js 18+** (recommend using the latest LTS version) +- **npm**, **yarn**, **pnpm**, or **bun** package manager +- **Git** for version control + +### Installation + +1. **Clone the repository** + + ```bash + git clone https://github.com/community-scripts/ProxmoxVE.git + cd ProxmoxVE/frontend + ``` + +2. **Install dependencies** + + ```bash + # Using npm + npm install + + # Using yarn + yarn install + + # Using pnpm + pnpm install + + # Using bun + bun install + ``` + +3. **Start the development server** + + ```bash + npm run dev + # or + yarn dev + # or + pnpm dev + # or + bun dev + ``` + +4. **Open your browser** + + Navigate to [http://localhost:3000](http://localhost:3000) to see the application running. + +### Environment Configuration + +The application uses the following environment variables: + +- `BASE_PATH`: Set to "ProxmoxVE" for GitHub Pages deployment +- Analytics configuration is handled in `src/config/siteConfig.tsx` + +## ๐งช Development + +### Available Scripts + +```bash +# Development +npm run dev # Start development server with Turbopack +npm run build # Build for production +npm run start # Start production server (after build) + +# Code Quality +npm run lint # Run ESLint +npm run typecheck # Run TypeScript type checking +npm run format:write # Format code with Prettier +npm run format:check # Check code formatting + +# Deployment +npm run deploy # Build and deploy to GitHub Pages +``` + +### Development Workflow + +1. **Feature Development** + + - Create a new branch for your feature + - Follow the established TypeScript and React patterns + - Use the existing component library (shadcn/ui) + - Ensure responsive design principles + +2. **Code Standards** + + - Follow TypeScript strict mode + - Use functional components with hooks + - Implement proper error boundaries + - Write descriptive variable and function names + - Use early returns for better readability + +3. **Styling Guidelines** + + - Use Tailwind CSS utility classes + - Follow mobile-first responsive design + - Implement dark/light mode considerations + - Use CSS variables from the design system + +4. **Testing** + - Write unit tests for utility functions + - Test React components with React Testing Library + - Ensure accessibility standards are met + - Run tests before committing + +### Component Development + +The project uses a component-driven development approach: + +```typescript +// Example component structure +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; + +interface ComponentProps { + title: string; + className?: string; +} + +export const Component = ({ title, className }: ComponentProps) => { + return ( +
No categories available. Please check the API endpoint.
)} - {selectedCategoryIndex !== null ? ( -- {categories.reduce((total, category) => total + (category.scripts?.length || 0), 0)} Total scripts -
-+ Created at: + {" "} + {script.date_created || "No date available"} +
++ {truncateDescription(script.description || "No description available.")} +
+ {renderResources(script)} ++ {categories.reduce((total, category) => total + (category.scripts?.length || 0), 0)} + {" "} + Total scripts +
++ {(category as any).description || "No description available."} +
+Loading...
; - if (error) returnError: {error}
; + if (loading) + returnLoading...
; + if (error) { + return ( ++ Error: + {error} +
+ ); + } const requestSort = (key: string) => { - let direction: 'ascending' | 'descending' = 'ascending'; - if (sortConfig && sortConfig.key === key && sortConfig.direction === 'ascending') { - direction = 'descending'; + let direction: "ascending" | "descending" = "ascending"; + if (sortConfig && sortConfig.key === key && sortConfig.direction === "ascending") { + direction = "descending"; } setSortConfig({ key, direction }); }; @@ -102,8 +116,8 @@ const DataFetcher: React.FC = () => { const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); - const hours = String(date.getHours()).padStart(2, '0'); - const minutes = String(date.getMinutes()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); const timezoneOffset = dateString.slice(-6); return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`; }; @@ -114,49 +128,76 @@ const DataFetcher: React.FC = () => {
{summary?.total_entries} results found
-Status Legend: ๐ installing {summary?.status_count["installing"] ?? 0} | โ๏ธ completed {summary?.status_count["done"] ?? 0} | โ failed {summary?.status_count["failed"] ?? 0} | โ unknown
-+ {summary?.total_entries} + {" "} + results found +
++ Status Legend: ๐ installing + {summary?.status_count.installing ?? 0} + {" "} + | โ๏ธ completed + {summary?.status_count.done ?? 0} + {" "} + | โ failed + {summary?.status_count.failed ?? 0} + {" "} + | โ unknown +
+requestSort('status')}>Status | -requestSort('type')}>Type | -requestSort('nsapp')}>Application | -requestSort('os_type')}>OS | -requestSort('os_version')}>OS Version | -requestSort('disk_size')}>Disk Size | -requestSort('core_count')}>Core Count | -requestSort('ram_size')}>RAM Size | -requestSort('method')}>Method | -requestSort('pve_version')}>PVE Version | -requestSort('error')}>Error Message | -requestSort('created_at')}>Created At | +requestSort("status")}>Status | +requestSort("type")}>Type | +requestSort("nsapp")}>Application | +requestSort("os_type")}>OS | +requestSort("os_version")}>OS Version | +requestSort("disk_size")}>Disk Size | +requestSort("core_count")}>Core Count | +requestSort("ram_size")}>RAM Size | +requestSort("method")}>Method | +requestSort("pve_version")}>PVE Version | +requestSort("error")}>Error Message | +requestSort("created_at")}>Created At |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- {item.status === "done" ? ( - "โ๏ธ" - ) : item.status === "failed" ? ( - "โ" - ) : item.status === "installing" ? ( - "๐" - ) : ( - item.status - )} + {item.status === "done" + ? ( + "โ๏ธ" + ) + : item.status === "failed" + ? ( + "โ" + ) + : item.status === "installing" + ? ( + "๐" + ) + : ( + item.status + )} + | ++ {item.type === "lxc" + ? ( + "๐ฆ" + ) + : item.type === "vm" + ? ( + "๐ฅ๏ธ" + ) + : ( + item.type + )} | -{item.type === "lxc" ? ( - "๐ฆ" - ) : item.type === "vm" ? ( - "๐ฅ๏ธ" - ) : ( - item.type - )} | {item.nsapp} | {item.os_type} | {item.os_version} | @@ -175,11 +216,14 @@ const DataFetcher: React.FC = () => {