diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index f6e3efb5..39f35b2b 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/README.md b/README.md index beb76d8c..7100fbd0 100644 --- a/README.md +++ b/README.md @@ -5,31 +5,37 @@
- Easily backup and restore your database instances with Portabase
-
- Explore the Docs »
-
-
- View Demo
- ·
- Report Bug
- ·
- Request Feature
-
- 
-
+
+ Free, open-source, and self-hosted solution for automated backup and restoration of your database instances.
+ + [](LICENSE) + [](https://hub.docker.com/r/solucetechnologies/portabase) + [](https://github.com/RostislavDugin/postgresus) + + [](https://www.postgresql.org/) + [](https://www.mysql.com/) + [](https://mariadb.org/) + [](https://github.com/RostislavDugin/postgresus) + ++ + Documentation • + Demo • + Installation • + Contributing • + Report Bug • + Request Feature + +
+ +  + - - - ## 📚 Table of Contents - [About The Project](#about-the-project) - - [Built With](#built-with) - [Getting Started](#getting-started) - [Prerequisites](#prerequisites) - [Installation](#installation) @@ -44,17 +50,17 @@ ## About The Project -**Portabase** is a server dashboard tool designed to simplify the backup and restoration of your database instances. It integrates seamlessly with Portabase agents for managing operations securely and efficiently. +**Portabase** is a server dashboard tool designed to simplify the backup and restoration of your database instances. It +integrates seamlessly with Portabase agents for managing operations securely and efficiently. GitHub Repository: [Portabase](https://github.com/Soluce-Technologies/portabase) ### 🔧 Built With -- [![NextJS][NextJS]][NextJS-url] (v15 with App Router) +- [![NextJS][NextJS]][NextJS-url] (v16 with App Router) - [![Drizzle][Drizzle]][Drizzle-url] - [![ShadcnUI][ShadcnUI]][ShadcnUI-url] -- BetterAuth -- React Email +- [![BetterAuth][BetterAuth]][BetterAuth-url] --- @@ -147,29 +153,29 @@ Give the project a ⭐ if you like it! # Environment NODE_ENV=production -# Database + # Database DATABASE_URL=postgresql://devuser:changeme@db:5432/devdb?schema=public -# Project Info + # Project Info PROJECT_NAME="Portabase" PROJECT_DESCRIPTION="Portabase is a powerful database manager" PROJECT_URL=http://app.portabase.io PROJECT_SECRET= -# SMTP (Email) + # SMTP (Email) SMTP_HOST= SMTP_PORT=587 SMTP_USER= SMTP_PASSWORD= SMTP_FROM= -# Google OAuth + # Google OAuth AUTH_GOOGLE_ID= AUTH_GOOGLE_SECRET= AUTH_GOOGLE_METHOD= -# S3/MinIO Configuration + # S3/MinIO Configuration S3_ENDPOINT=http://app.s3.portabase.io S3_ACCESS_KEY= S3_SECRET_KEY= @@ -177,10 +183,10 @@ S3_BUCKET_NAME=portabase S3_PORT=9000 S3_USE_SSL=true -# Storage Backend: 'local' or 's3' + # Storage Backend: 'local' or 's3' STORAGE_TYPE=local -# Retention + # Retention RETENTION_CRON="* * * * *" ``` @@ -219,8 +225,17 @@ Thanks to all contributors and the open-source community! --- [NextJS]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white + +[BetterAuth]: https://img.shields.io/badge/Better%20Auth-FFF?logo=betterauth&logoColor=000&style=for-the-badge + [Drizzle]: https://img.shields.io/badge/Drizzle-111?style=for-the-badge&logo=Drizzle&logoColor=c5f74f + [ShadcnUI]: https://img.shields.io/badge/shadcn/ui-000000?style=for-the-badge&logo=shadcn/ui&logoColor=white + [NextJS-url]: https://nextjs.org/ + +[BetterAuth-url]: https://www.better-auth.com/ + [Drizzle-url]: https://orm.drizzle.team/ + [ShadcnUI-url]: https://ui.shadcn.com/ diff --git a/components.json b/components.json index bcec1f91..38a8e6a9 100644 --- a/components.json +++ b/components.json @@ -10,11 +10,15 @@ "cssVariables": true, "prefix": "" }, + "iconLibrary": "radix", "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks" + }, + "registries": { + "@reui": "https://reui.io/r/{name}.json" } -} \ No newline at end of file +} diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index cefb92df..64efecb7 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -10,6 +10,8 @@ services: image: solucetechnologies/portabase:1.1.3-rc.3 ports: - '8887:80' + environment: + TZ: "Europe/Paris" env_file: - .env depends_on: diff --git a/docker-compose.yml b/docker-compose.yml index a7524bce..1eaa8803 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,42 @@ name: portabase-dev services: - db: - image: postgres:16-alpine - ports: - - "5433:5432" - volumes: - - postgres-data:/var/lib/postgresql/data - environment: - - POSTGRES_DB=devdb - - POSTGRES_USER=devuser - - POSTGRES_PASSWORD=changeme - healthcheck: - test: ["CMD-SHELL", "pg_isready -U devuser -d devdb"] - interval: 10s - timeout: 5s - retries: 5 + +# app: +# build: +# context: . +# dockerfile: docker/dockerfile/Dockerfile +# target: dev +# ports: +# - "8887:8887" +# environment: +# - TZ=Europe/Paris +# - NODE_ENV=development +# depends_on: +# db: +# condition: service_healthy +# volumes: +# - .:/app +# - /app/node_modules +# container_name: portabase-app + + + + db: + image: postgres:16-alpine + ports: + - "5433:5432" + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + - POSTGRES_DB=devdb + - POSTGRES_USER=devuser + - POSTGRES_PASSWORD=changeme + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U devuser -d devdb" ] + interval: 10s + timeout: 5s + retries: 5 volumes: - postgres-data: + postgres-data: diff --git a/docker/dockerfile/Dockerfile b/docker/dockerfile/Dockerfile index 4ce19996..9103e889 100644 --- a/docker/dockerfile/Dockerfile +++ b/docker/dockerfile/Dockerfile @@ -3,6 +3,7 @@ FROM node:22-alpine AS base ENV YARN_VERSION=4.9.1 RUN apk add --update --no-cache \ + tzdata \ build-base \ libc6-compat \ openssl \ diff --git a/docker/entrypoints/app-prod-entrypoint.sh b/docker/entrypoints/app-prod-entrypoint.sh index 2fbfb3cb..23e73a04 100644 --- a/docker/entrypoints/app-prod-entrypoint.sh +++ b/docker/entrypoints/app-prod-entrypoint.sh @@ -1,5 +1,15 @@ #!/bin/bash +if [ -n "$TZ" ]; then + if [ -f "/usr/share/zoneinfo/$TZ" ]; then + ln -sf /usr/share/zoneinfo/$TZ /etc/localtime + echo "$TZ" > /etc/timezone + echo "[INFO] Timezone set to $TZ" + else + echo "[WARN] Timezone '$TZ' not found. Using default." + fi +fi + node server.js exec "$@" \ No newline at end of file diff --git a/package.json b/package.json index 50a0844a..a371c59d 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,9 @@ "drizzle-zod": "^0.7.1", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", - "lucide-react": "^0.510.0", + "lucide-react": "^0.553.0", "minio": "^8.0.5", + "motion": "^12.23.24", "next": "16.0.0", "next-safe-action": "^7.10.8", "next-themes": "^0.4.6", @@ -81,6 +82,7 @@ "react-hook-form": "^7.56.3", "react-resizable-panels": "^3.0.2", "react-twc": "^1.4.2", + "react-use-measure": "^2.1.7", "recharts": "^2.15.3", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", diff --git a/portabase.config.ts b/portabase.config.ts index a6d6a4b6..7a29222a 100644 --- a/portabase.config.ts +++ b/portabase.config.ts @@ -43,6 +43,7 @@ export const PORTABASE_DEFAULT_SETTINGS = { "'self'", "https://api.iconify.design", "https://code.iconify.design", + "https://api.github.com", ], OBJECT_SRC: ["'none'"], diff --git a/src/components/ui/sliding-number.tsx b/src/components/ui/sliding-number.tsx new file mode 100644 index 00000000..ac9c085d --- /dev/null +++ b/src/components/ui/sliding-number.tsx @@ -0,0 +1,235 @@ +'use client'; + +import * as React from 'react'; +import { + useSpring, + useTransform, + motion, + useInView, + type MotionValue, + type SpringOptions, + type UseInViewOptions, +} from 'motion/react'; +import useMeasure from 'react-use-measure'; +import {cn} from "@/lib/utils"; + + +type SlidingNumberRollerProps = { + prevValue: number; + value: number; + place: number; + transition: SpringOptions; +}; + +function SlidingNumberRoller({ + prevValue, + value, + place, + transition, + }: SlidingNumberRollerProps) { + const startNumber = Math.floor(prevValue / place) % 10; + const targetNumber = Math.floor(value / place) % 10; + const animatedValue = useSpring(startNumber, transition); + + React.useEffect(() => { + animatedValue.set(targetNumber); + }, [targetNumber, animatedValue]); + + const [measureRef, { height }] = useMeasure(); + + return ( + + 0 + {Array.from({ length: 10 }, (_, i) => ( +Rows per page
+Rows per page