mirror of
https://github.com/eduardolat/pgbackweb.git
synced 2026-01-25 05:58:29 -06:00
Merge branch 'develop' into feat-add-devcontainer
This commit is contained in:
22
.air.toml
22
.air.toml
@@ -1,22 +0,0 @@
|
||||
# Docs for .air.toml
|
||||
# https://github.com/cosmtrek/air/blob/master/air_example.toml
|
||||
|
||||
root = "."
|
||||
|
||||
[build]
|
||||
cmd = "task build"
|
||||
full_bin = "task serve"
|
||||
delay = 100
|
||||
exclude_dir = ["tmp", "dist", "internal/database/dbgen"]
|
||||
exclude_regex = [
|
||||
"_test.go",
|
||||
"_generated.go",
|
||||
".sql.go",
|
||||
".gen.go",
|
||||
".min.js",
|
||||
".min.css",
|
||||
]
|
||||
include_ext = ["go", "sql", "js", "css", "json"]
|
||||
|
||||
[log]
|
||||
main_only = true
|
||||
7
.github/workflows/lint-test-build.yaml
vendored
7
.github/workflows/lint-test-build.yaml
vendored
@@ -1,11 +1,14 @@
|
||||
name: Lint, test, and build
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- main
|
||||
- develop
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
lint-test-build:
|
||||
|
||||
1
.github/workflows/publish-docker-image.yaml
vendored
1
.github/workflows/publish-docker-image.yaml
vendored
@@ -46,6 +46,7 @@ jobs:
|
||||
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--build-arg TARGETPLATFORM \
|
||||
$tag_args \
|
||||
-f ./docker/Dockerfile \
|
||||
--push .
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ dist/
|
||||
|
||||
# Temp files/folders
|
||||
tmp/
|
||||
temp/
|
||||
.task/
|
||||
|
||||
# Binaries for programs and plugins
|
||||
|
||||
48
CONTRIBUTING.md
Normal file
48
CONTRIBUTING.md
Normal file
@@ -0,0 +1,48 @@
|
||||
## PG Back Web - Contribution Guidelines
|
||||
|
||||
Thank you for your interest in contributing to the PG Back Web project! Please follow these guidelines to ensure smooth collaboration and consistent code quality.
|
||||
|
||||
### Main Branch Policy
|
||||
- The **main branch** reflects the latest **stable release** of the project.
|
||||
- **No direct commits** should ever be made to the main branch.
|
||||
- All development work should happen in feature branches and merged via **Pull Requests (PRs)** into the **develop** branch.
|
||||
- The **develop branch** contains the latest code under active development. Once a new release is ready, the main branch will be updated by merging from the development branch.
|
||||
|
||||
### Development Workflow
|
||||
1. **Fork the repository** and create a feature branch from the `develop` branch.
|
||||
- Use descriptive names for your branches, e.g., `feature/add-new-endpoint` or `bugfix/fix-connection-issue`.
|
||||
|
||||
2. **Make your changes** in your feature branch.
|
||||
|
||||
3. **Ensure all tests pass** and the code follows the project’s style guidelines.
|
||||
|
||||
4. **Open a Pull Request (PR)** against the `develop` branch.
|
||||
|
||||
5. Your PR will be reviewed by maintainers. Please be responsive to feedback.
|
||||
|
||||
6. Once approved, the changes will be merged into the `develop` branch. A merge into the `main` branch will only occur when releasing a new version.
|
||||
|
||||
### Project Dependencies
|
||||
This project requires the following dependencies installed on your system:
|
||||
- [**Taskfile**](https://taskfile.dev/) – Used to automate development tasks.
|
||||
- **Docker** – For containerized environments.
|
||||
- **Docker Compose** – To manage multi-container setups.
|
||||
|
||||
### How to Use Taskfile Commands
|
||||
- To see all available commands, run:
|
||||
```bash
|
||||
task --list
|
||||
```
|
||||
|
||||
- The **primary command** for development is:
|
||||
```bash
|
||||
task on
|
||||
```
|
||||
This command should be run from your **host environment** to start a local development server.
|
||||
|
||||
### Additional Notes
|
||||
- Always **write clear commit messages** that explain the purpose of your changes.
|
||||
- **Keep your fork up to date** with the latest changes from the `develop` branch.
|
||||
- Be respectful and follow the project’s code of conduct when interacting with other contributors.
|
||||
|
||||
We appreciate your contributions and are excited to have you on board!
|
||||
@@ -1,11 +1,22 @@
|
||||
# Declare the target platform to support multi-arch builds
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# To make sure we have the node, and golang binaries
|
||||
FROM node:20.17.0-bookworm AS node
|
||||
FROM golang:1.23.1-bookworm AS golang
|
||||
|
||||
# Set the base image, general environment variables, and move to temp dir
|
||||
# Set the base image
|
||||
FROM debian:12.7
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV PATH="$PATH:/usr/local/go/bin"
|
||||
|
||||
# Re-declare ARG after FROM to make it available in this build stage
|
||||
ARG TARGETPLATFORM
|
||||
RUN echo "Building for ${TARGETPLATFORM}"
|
||||
|
||||
# Set the general environment variables, and move to temp dir
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
ENV GOBIN="/usr/local/go-bin"
|
||||
ENV PATH="$PATH:/usr/local/go-bin:/usr/local/dl-bin:/usr/local/go/bin"
|
||||
RUN mkdir -p /app/temp /usr/local/go-bin /usr/local/dl-bin
|
||||
WORKDIR /app/temp
|
||||
|
||||
# Copy node binaries
|
||||
@@ -24,56 +35,49 @@ RUN apt update && apt install -y postgresql-common && \
|
||||
apt update && apt install -y \
|
||||
wget unzip tzdata git \
|
||||
postgresql-client-13 postgresql-client-14 \
|
||||
postgresql-client-15 postgresql-client-16 && \
|
||||
postgresql-client-15 postgresql-client-16 \
|
||||
postgresql-client-17 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install downloadable binaries
|
||||
RUN set -e && \
|
||||
if [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
echo "Downloading arm64 binaries" && \
|
||||
# Install task
|
||||
wget --no-verbose https://github.com/go-task/task/releases/download/v3.38.0/task_linux_arm64.tar.gz && \
|
||||
tar -xzf task_linux_arm64.tar.gz && \
|
||||
mv ./task /usr/local/bin/task && \
|
||||
mv ./task /usr/local/dl-bin/task && \
|
||||
# Install goose
|
||||
wget --no-verbose https://github.com/pressly/goose/releases/download/v3.22.0/goose_linux_arm64 && \
|
||||
mv ./goose_linux_arm64 /usr/local/bin/goose && \
|
||||
mv ./goose_linux_arm64 /usr/local/dl-bin/goose && \
|
||||
# Install sqlc
|
||||
wget --no-verbose https://github.com/sqlc-dev/sqlc/releases/download/v1.27.0/sqlc_1.27.0_linux_arm64.tar.gz && \
|
||||
tar -xzf sqlc_1.27.0_linux_arm64.tar.gz && \
|
||||
mv ./sqlc /usr/local/bin/sqlc && \
|
||||
mv ./sqlc /usr/local/dl-bin/sqlc && \
|
||||
# Install golangci-lint
|
||||
wget --no-verbose https://github.com/golangci/golangci-lint/releases/download/v1.60.3/golangci-lint-1.60.3-linux-arm64.tar.gz && \
|
||||
tar -xzf golangci-lint-1.60.3-linux-arm64.tar.gz && \
|
||||
mv ./golangci-lint-1.60.3-linux-arm64/golangci-lint /usr/local/bin/golangci-lint && \
|
||||
# Install air
|
||||
wget --no-verbose https://github.com/air-verse/air/releases/download/v1.52.3/air_1.52.3_linux_arm64 && \
|
||||
mv ./air_1.52.3_linux_arm64 /usr/local/bin/air; \
|
||||
mv ./golangci-lint-1.60.3-linux-arm64/golangci-lint /usr/local/dl-bin/golangci-lint; \
|
||||
else \
|
||||
echo "Downloading amd64 binaries" && \
|
||||
# Install task
|
||||
wget --no-verbose https://github.com/go-task/task/releases/download/v3.38.0/task_linux_amd64.tar.gz && \
|
||||
tar -xzf task_linux_amd64.tar.gz && \
|
||||
mv ./task /usr/local/bin/task && \
|
||||
mv ./task /usr/local/dl-bin/task && \
|
||||
# Install goose
|
||||
wget --no-verbose https://github.com/pressly/goose/releases/download/v3.22.0/goose_linux_x86_64 && \
|
||||
mv ./goose_linux_x86_64 /usr/local/bin/goose && \
|
||||
mv ./goose_linux_x86_64 /usr/local/dl-bin/goose && \
|
||||
# Install sqlc
|
||||
wget --no-verbose https://github.com/sqlc-dev/sqlc/releases/download/v1.27.0/sqlc_1.27.0_linux_amd64.tar.gz && \
|
||||
tar -xzf sqlc_1.27.0_linux_amd64.tar.gz && \
|
||||
mv ./sqlc /usr/local/bin/sqlc && \
|
||||
mv ./sqlc /usr/local/dl-bin/sqlc && \
|
||||
# Install golangci-lint
|
||||
wget --no-verbose https://github.com/golangci/golangci-lint/releases/download/v1.60.3/golangci-lint-1.60.3-linux-amd64.tar.gz && \
|
||||
tar -xzf golangci-lint-1.60.3-linux-amd64.tar.gz && \
|
||||
mv ./golangci-lint-1.60.3-linux-amd64/golangci-lint /usr/local/bin/golangci-lint && \
|
||||
# Install air
|
||||
wget --no-verbose https://github.com/air-verse/air/releases/download/v1.52.3/air_1.52.3_linux_amd64 && \
|
||||
mv ./air_1.52.3_linux_amd64 /usr/local/bin/air; \
|
||||
mv ./golangci-lint-1.60.3-linux-amd64/golangci-lint /usr/local/dl-bin/golangci-lint; \
|
||||
fi && \
|
||||
# Make binaries executable
|
||||
chmod +x /usr/local/bin/task && \
|
||||
chmod +x /usr/local/bin/goose && \
|
||||
chmod +x /usr/local/bin/sqlc && \
|
||||
chmod +x /usr/local/bin/golangci-lint && \
|
||||
chmod +x /usr/local/bin/air
|
||||
chmod +x /usr/local/dl-bin/*
|
||||
|
||||
# Go to the app dir, delete the temporary dir and create backups dir
|
||||
WORKDIR /app
|
||||
@@ -97,6 +101,9 @@ RUN go mod download
|
||||
# Copy the rest of the files
|
||||
COPY . .
|
||||
|
||||
# Fix permissions if needed
|
||||
RUN task fixperms
|
||||
|
||||
# Build the app
|
||||
RUN task build
|
||||
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
# Declare the target platform to support multi-arch builds
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# To make sure we have the node, and golang binaries
|
||||
FROM node:20.17.0-bookworm AS node
|
||||
FROM golang:1.23.1-bookworm AS golang
|
||||
|
||||
# Set the base image, general environment variables, and move to temp dir
|
||||
# Set the base image
|
||||
FROM debian:12.7
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV PATH="$PATH:/usr/local/go/bin"
|
||||
|
||||
# Re-declare ARG after FROM to make it available in this build stage
|
||||
ARG TARGETPLATFORM
|
||||
RUN echo "Building for ${TARGETPLATFORM}"
|
||||
|
||||
# Set the general environment variables, and move to temp dir
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
ENV GOBIN="/usr/local/go-bin"
|
||||
ENV PATH="$PATH:/usr/local/go-bin:/usr/local/dl-bin:/usr/local/go/bin"
|
||||
RUN mkdir -p /app/temp /usr/local/go-bin /usr/local/dl-bin
|
||||
WORKDIR /app/temp
|
||||
|
||||
# Copy node binaries
|
||||
@@ -24,56 +35,49 @@ RUN apt update && apt install -y postgresql-common && \
|
||||
apt update && apt install -y \
|
||||
wget unzip tzdata git \
|
||||
postgresql-client-13 postgresql-client-14 \
|
||||
postgresql-client-15 postgresql-client-16 && \
|
||||
postgresql-client-15 postgresql-client-16 \
|
||||
postgresql-client-17 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install downloadable binaries
|
||||
RUN set -e && \
|
||||
if [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
|
||||
echo "Downloading arm64 binaries" && \
|
||||
# Install task
|
||||
wget --no-verbose https://github.com/go-task/task/releases/download/v3.38.0/task_linux_arm64.tar.gz && \
|
||||
tar -xzf task_linux_arm64.tar.gz && \
|
||||
mv ./task /usr/local/bin/task && \
|
||||
mv ./task /usr/local/dl-bin/task && \
|
||||
# Install goose
|
||||
wget --no-verbose https://github.com/pressly/goose/releases/download/v3.22.0/goose_linux_arm64 && \
|
||||
mv ./goose_linux_arm64 /usr/local/bin/goose && \
|
||||
mv ./goose_linux_arm64 /usr/local/dl-bin/goose && \
|
||||
# Install sqlc
|
||||
wget --no-verbose https://github.com/sqlc-dev/sqlc/releases/download/v1.27.0/sqlc_1.27.0_linux_arm64.tar.gz && \
|
||||
tar -xzf sqlc_1.27.0_linux_arm64.tar.gz && \
|
||||
mv ./sqlc /usr/local/bin/sqlc && \
|
||||
mv ./sqlc /usr/local/dl-bin/sqlc && \
|
||||
# Install golangci-lint
|
||||
wget --no-verbose https://github.com/golangci/golangci-lint/releases/download/v1.60.3/golangci-lint-1.60.3-linux-arm64.tar.gz && \
|
||||
tar -xzf golangci-lint-1.60.3-linux-arm64.tar.gz && \
|
||||
mv ./golangci-lint-1.60.3-linux-arm64/golangci-lint /usr/local/bin/golangci-lint && \
|
||||
# Install air
|
||||
wget --no-verbose https://github.com/air-verse/air/releases/download/v1.52.3/air_1.52.3_linux_arm64 && \
|
||||
mv ./air_1.52.3_linux_arm64 /usr/local/bin/air; \
|
||||
mv ./golangci-lint-1.60.3-linux-arm64/golangci-lint /usr/local/dl-bin/golangci-lint; \
|
||||
else \
|
||||
echo "Downloading amd64 binaries" && \
|
||||
# Install task
|
||||
wget --no-verbose https://github.com/go-task/task/releases/download/v3.38.0/task_linux_amd64.tar.gz && \
|
||||
tar -xzf task_linux_amd64.tar.gz && \
|
||||
mv ./task /usr/local/bin/task && \
|
||||
mv ./task /usr/local/dl-bin/task && \
|
||||
# Install goose
|
||||
wget --no-verbose https://github.com/pressly/goose/releases/download/v3.22.0/goose_linux_x86_64 && \
|
||||
mv ./goose_linux_x86_64 /usr/local/bin/goose && \
|
||||
mv ./goose_linux_x86_64 /usr/local/dl-bin/goose && \
|
||||
# Install sqlc
|
||||
wget --no-verbose https://github.com/sqlc-dev/sqlc/releases/download/v1.27.0/sqlc_1.27.0_linux_amd64.tar.gz && \
|
||||
tar -xzf sqlc_1.27.0_linux_amd64.tar.gz && \
|
||||
mv ./sqlc /usr/local/bin/sqlc && \
|
||||
mv ./sqlc /usr/local/dl-bin/sqlc && \
|
||||
# Install golangci-lint
|
||||
wget --no-verbose https://github.com/golangci/golangci-lint/releases/download/v1.60.3/golangci-lint-1.60.3-linux-amd64.tar.gz && \
|
||||
tar -xzf golangci-lint-1.60.3-linux-amd64.tar.gz && \
|
||||
mv ./golangci-lint-1.60.3-linux-amd64/golangci-lint /usr/local/bin/golangci-lint && \
|
||||
# Install air
|
||||
wget --no-verbose https://github.com/air-verse/air/releases/download/v1.52.3/air_1.52.3_linux_amd64 && \
|
||||
mv ./air_1.52.3_linux_amd64 /usr/local/bin/air; \
|
||||
mv ./golangci-lint-1.60.3-linux-amd64/golangci-lint /usr/local/dl-bin/golangci-lint; \
|
||||
fi && \
|
||||
# Make binaries executable
|
||||
chmod +x /usr/local/bin/task && \
|
||||
chmod +x /usr/local/bin/goose && \
|
||||
chmod +x /usr/local/bin/sqlc && \
|
||||
chmod +x /usr/local/bin/golangci-lint && \
|
||||
chmod +x /usr/local/bin/air
|
||||
chmod +x /usr/local/dl-bin/*
|
||||
|
||||
# Go to the app dir, delete the temporary dir and create backups dir
|
||||
WORKDIR /app
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE databases
|
||||
DROP CONSTRAINT IF EXISTS databases_pg_version_check,
|
||||
ADD CONSTRAINT databases_pg_version_check
|
||||
CHECK (pg_version IN ('13', '14', '15', '16', '17'));
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE databases
|
||||
DROP CONSTRAINT IF EXISTS databases_pg_version_check,
|
||||
ADD CONSTRAINT databases_pg_version_check
|
||||
CHECK (pg_version IN ('13', '14', '15', '16'));
|
||||
-- +goose StatementEnd
|
||||
@@ -21,34 +21,41 @@ import (
|
||||
*/
|
||||
|
||||
type version struct {
|
||||
version string
|
||||
pgDump string
|
||||
psql string
|
||||
Version string
|
||||
PGDump string
|
||||
PSQL string
|
||||
}
|
||||
|
||||
type PGVersion enum.Member[version]
|
||||
|
||||
var (
|
||||
PG13 = PGVersion{version{
|
||||
version: "13",
|
||||
pgDump: "/usr/lib/postgresql/13/bin/pg_dump",
|
||||
psql: "/usr/lib/postgresql/13/bin/psql",
|
||||
Version: "13",
|
||||
PGDump: "/usr/lib/postgresql/13/bin/pg_dump",
|
||||
PSQL: "/usr/lib/postgresql/13/bin/psql",
|
||||
}}
|
||||
PG14 = PGVersion{version{
|
||||
version: "14",
|
||||
pgDump: "/usr/lib/postgresql/14/bin/pg_dump",
|
||||
psql: "/usr/lib/postgresql/14/bin/psql",
|
||||
Version: "14",
|
||||
PGDump: "/usr/lib/postgresql/14/bin/pg_dump",
|
||||
PSQL: "/usr/lib/postgresql/14/bin/psql",
|
||||
}}
|
||||
PG15 = PGVersion{version{
|
||||
version: "15",
|
||||
pgDump: "/usr/lib/postgresql/15/bin/pg_dump",
|
||||
psql: "/usr/lib/postgresql/15/bin/psql",
|
||||
Version: "15",
|
||||
PGDump: "/usr/lib/postgresql/15/bin/pg_dump",
|
||||
PSQL: "/usr/lib/postgresql/15/bin/psql",
|
||||
}}
|
||||
PG16 = PGVersion{version{
|
||||
version: "16",
|
||||
pgDump: "/usr/lib/postgresql/16/bin/pg_dump",
|
||||
psql: "/usr/lib/postgresql/16/bin/psql",
|
||||
Version: "16",
|
||||
PGDump: "/usr/lib/postgresql/16/bin/pg_dump",
|
||||
PSQL: "/usr/lib/postgresql/16/bin/psql",
|
||||
}}
|
||||
PG17 = PGVersion{version{
|
||||
Version: "17",
|
||||
PGDump: "/usr/lib/postgresql/17/bin/pg_dump",
|
||||
PSQL: "/usr/lib/postgresql/17/bin/psql",
|
||||
}}
|
||||
|
||||
PGVersions = []PGVersion{PG13, PG14, PG15, PG16, PG17}
|
||||
)
|
||||
|
||||
type Client struct{}
|
||||
@@ -69,6 +76,8 @@ func (Client) ParseVersion(version string) (PGVersion, error) {
|
||||
return PG15, nil
|
||||
case "16":
|
||||
return PG16, nil
|
||||
case "17":
|
||||
return PG17, nil
|
||||
default:
|
||||
return PGVersion{}, fmt.Errorf("pg version not allowed: %s", version)
|
||||
}
|
||||
@@ -76,12 +85,12 @@ func (Client) ParseVersion(version string) (PGVersion, error) {
|
||||
|
||||
// Test tests the connection to the PostgreSQL database
|
||||
func (Client) Test(version PGVersion, connString string) error {
|
||||
cmd := exec.Command(version.Value.psql, connString, "-c", "SELECT 1;")
|
||||
cmd := exec.Command(version.Value.PSQL, connString, "-c", "SELECT 1;")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"error running psql test v%s: %s",
|
||||
version.Value.version, output,
|
||||
version.Value.Version, output,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -152,7 +161,7 @@ func (Client) Dump(
|
||||
|
||||
errorBuffer := &bytes.Buffer{}
|
||||
reader, writer := io.Pipe()
|
||||
cmd := exec.Command(version.Value.pgDump, args...)
|
||||
cmd := exec.Command(version.Value.PGDump, args...)
|
||||
cmd.Stdout = writer
|
||||
cmd.Stderr = errorBuffer
|
||||
|
||||
@@ -161,7 +170,7 @@ func (Client) Dump(
|
||||
if err := cmd.Run(); err != nil {
|
||||
writer.CloseWithError(fmt.Errorf(
|
||||
"error running pg_dump v%s: %s",
|
||||
version.Value.version, errorBuffer.String(),
|
||||
version.Value.Version, errorBuffer.String(),
|
||||
))
|
||||
}
|
||||
}()
|
||||
@@ -248,12 +257,12 @@ func (Client) RestoreZip(
|
||||
return fmt.Errorf("dump.sql file not found in ZIP file: %s", zipPath)
|
||||
}
|
||||
|
||||
cmd = exec.Command(version.Value.psql, connString, "-f", dumpPath)
|
||||
cmd = exec.Command(version.Value.PSQL, connString, "-f", dumpPath)
|
||||
output, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"error running psql v%s command: %s",
|
||||
version.Value.version, output,
|
||||
version.Value.Version, output,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
3
internal/view/static/.gitignore
vendored
Normal file
3
internal/view/static/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# The build directory stores the JavaScript and CSS files that are generated
|
||||
# by the build process.
|
||||
build/
|
||||
1
internal/view/static/css/.gitignore
vendored
1
internal/view/static/css/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
style.min.css
|
||||
@@ -1,4 +1,8 @@
|
||||
html {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.table tbody tr {
|
||||
@apply hover:bg-base-200;
|
||||
}
|
||||
9
internal/view/static/css/partials/sweetalert2.css
Normal file
9
internal/view/static/css/partials/sweetalert2.css
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Fix sweetalert2 scroll issue
|
||||
https://github.com/sweetalert2/sweetalert2/issues/781#issuecomment-475108658
|
||||
*/
|
||||
body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown),
|
||||
html.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) {
|
||||
height: 100% !important;
|
||||
overflow-y: visible !important;
|
||||
}
|
||||
@@ -6,13 +6,4 @@
|
||||
@import "./partials/slim-select.css";
|
||||
@import "./partials/notyf.css";
|
||||
@import "./partials/scrollbar.css";
|
||||
|
||||
/*
|
||||
Fix sweetalert2 scroll issue
|
||||
https://github.com/sweetalert2/sweetalert2/issues/781#issuecomment-475108658
|
||||
*/
|
||||
body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown),
|
||||
html.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) {
|
||||
height: 100% !important;
|
||||
overflow-y: visible !important;
|
||||
}
|
||||
@import "./partials/sweetalert2.css";
|
||||
1
internal/view/static/js/.gitignore
vendored
1
internal/view/static/js/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
app.min.js
|
||||
@@ -1,77 +0,0 @@
|
||||
export const githubRepoInfo = {
|
||||
name: 'githubRepoInfo',
|
||||
fn: () => ({
|
||||
stars: '',
|
||||
latestRelease: '',
|
||||
|
||||
async init () {
|
||||
const stars = await this.getStars()
|
||||
if (stars !== null) {
|
||||
this.stars = stars
|
||||
}
|
||||
|
||||
const latestRelease = await this.getLatestRelease()
|
||||
if (latestRelease !== null) {
|
||||
this.latestRelease = latestRelease
|
||||
}
|
||||
},
|
||||
async getStars () {
|
||||
const cacheKey = 'pbw_gh_stars'
|
||||
const cachedData = this.getCachedData(cacheKey)
|
||||
if (cachedData !== null) {
|
||||
return cachedData
|
||||
}
|
||||
|
||||
const url = 'https://api.github.com/repos/eduardolat/pgbackweb'
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
return null
|
||||
}
|
||||
const data = await response.json()
|
||||
this.cacheData(cacheKey, data.stargazers_count)
|
||||
return data.stargazers_count
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
async getLatestRelease () {
|
||||
const cacheKey = 'pbw_gh_last_release'
|
||||
const cachedData = this.getCachedData(cacheKey)
|
||||
if (cachedData !== null) {
|
||||
return cachedData
|
||||
}
|
||||
|
||||
const url = 'https://api.github.com/repos/eduardolat/pgbackweb/releases/latest'
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
return null
|
||||
}
|
||||
const data = await response.json()
|
||||
this.cacheData(cacheKey, data.name)
|
||||
return data.name
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
getCachedData (key) {
|
||||
const cachedJSON = localStorage.getItem(key)
|
||||
if (!cachedJSON) {
|
||||
return null
|
||||
}
|
||||
const cached = JSON.parse(cachedJSON)
|
||||
if (Date.now() - cached.timestamp < 2 * 60 * 1000) {
|
||||
return cached.value
|
||||
}
|
||||
return null
|
||||
},
|
||||
cacheData (key, value) {
|
||||
const data = JSON.stringify({
|
||||
value,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
localStorage.setItem(key, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -2,14 +2,10 @@ import { initThemeHelper } from './init-theme-helper.js'
|
||||
import { initSweetAlert2 } from './init-sweetalert2.js'
|
||||
import { initNotyf } from './init-notyf.js'
|
||||
import { initHTMX } from './init-htmx.js'
|
||||
import { initAlpineComponents } from './init-alpine-components.js'
|
||||
import { initHelpers } from './init-helpers.js'
|
||||
import { initDashboardAsideScroll } from './dashboard-aside-scroll.js'
|
||||
|
||||
initThemeHelper()
|
||||
initSweetAlert2()
|
||||
initNotyf()
|
||||
initHTMX()
|
||||
initAlpineComponents()
|
||||
initHelpers()
|
||||
initDashboardAsideScroll()
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
export function initDashboardAsideScroll () {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const el = document.getElementById('dashboard-aside')
|
||||
const key = 'dashboard-aside-scroll-position'
|
||||
|
||||
if (!el) return
|
||||
|
||||
const saveScrollPosition = window.debounce(
|
||||
() => {
|
||||
const scrollPosition = el.scrollTop
|
||||
localStorage.setItem(key, scrollPosition)
|
||||
},
|
||||
200
|
||||
)
|
||||
el.addEventListener('scroll', saveScrollPosition)
|
||||
|
||||
const scrollPosition = localStorage.getItem(key)
|
||||
if (scrollPosition) {
|
||||
el.scrollTop = parseInt(scrollPosition, 10)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { changeThemeButton } from './alpine-components/change-theme-button.js'
|
||||
import { githubRepoInfo } from './alpine-components/github-repo-info.js'
|
||||
import { dashboardAsideItem } from './alpine-components/dashboard-aside-item.js'
|
||||
import { genericSlider } from './alpine-components/generic-slider.js'
|
||||
import { optionsDropdown } from './alpine-components/options-dropdown.js'
|
||||
|
||||
export function initAlpineComponents () {
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data(changeThemeButton.name, changeThemeButton.fn)
|
||||
Alpine.data(githubRepoInfo.name, githubRepoInfo.fn)
|
||||
Alpine.data(dashboardAsideItem.name, dashboardAsideItem.fn)
|
||||
Alpine.data(genericSlider.name, genericSlider.fn)
|
||||
Alpine.data(optionsDropdown.name, optionsDropdown.fn)
|
||||
})
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type ChangeThemeButtonParams struct {
|
||||
|
||||
func ChangeThemeButton(params ChangeThemeButtonParams) gomponents.Node {
|
||||
return html.Div(
|
||||
alpine.XData("changeThemeButton"),
|
||||
alpine.XData("alpineChangeThemeButton()"),
|
||||
alpine.XCloak(),
|
||||
|
||||
components.Classes{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export const changeThemeButton = {
|
||||
name: 'changeThemeButton',
|
||||
fn: () => ({
|
||||
window.alpineChangeThemeButton = function () {
|
||||
return {
|
||||
theme: '',
|
||||
|
||||
loadTheme () {
|
||||
@@ -16,5 +15,5 @@ export const changeThemeButton = {
|
||||
init () {
|
||||
this.loadTheme()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func OptionsDropdown(children ...gomponents.Node) gomponents.Node {
|
||||
return html.Div(
|
||||
html.Class("inline-block"),
|
||||
alpine.XData("options_dropdown"),
|
||||
alpine.XData("alpineOptionsDropdown()"),
|
||||
alpine.XOn("mouseenter", "open()"),
|
||||
alpine.XOn("mouseleave", "close()"),
|
||||
html.Button(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export const optionsDropdown = {
|
||||
name: 'options_dropdown',
|
||||
fn: () => ({
|
||||
window.alpineOptionsDropdown = function () {
|
||||
return {
|
||||
isOpen: false,
|
||||
buttonEl: null,
|
||||
contentEl: null,
|
||||
@@ -43,5 +42,5 @@ export const optionsDropdown = {
|
||||
this.contentEl.style.top = `${buttonRect.top - contentHeight}px`
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
25
internal/view/web/component/pg_version_select_options.go
Normal file
25
internal/view/web/component/pg_version_select_options.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package component
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/eduardolat/pgbackweb/internal/integration/postgres"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
func PGVersionSelectOptions(selectedVersion sql.NullString) gomponents.Node {
|
||||
return GMap(
|
||||
postgres.PGVersions,
|
||||
func(pgVersion postgres.PGVersion) gomponents.Node {
|
||||
return html.Option(
|
||||
html.Value(pgVersion.Value.Version),
|
||||
gomponents.Textf("PostgreSQL %s", pgVersion.Value.Version),
|
||||
gomponents.If(
|
||||
selectedVersion.Valid && selectedVersion.String == pgVersion.Value.Version,
|
||||
html.Selected(),
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func StarOnGithub(size size) gomponents.Node {
|
||||
return html.A(
|
||||
alpine.XData("githubRepoInfo"),
|
||||
alpine.XData("alpineStarOnGithub()"),
|
||||
alpine.XCloak(),
|
||||
components.Classes{
|
||||
"btn btn-neutral": true,
|
||||
|
||||
42
internal/view/web/component/star_on_github.inc.js
Normal file
42
internal/view/web/component/star_on_github.inc.js
Normal file
@@ -0,0 +1,42 @@
|
||||
window.alpineStarOnGithub = function () {
|
||||
return {
|
||||
stars: null,
|
||||
|
||||
async init () {
|
||||
const stars = await this.getStars()
|
||||
if (stars !== null) {
|
||||
this.stars = stars
|
||||
}
|
||||
},
|
||||
|
||||
async getStars () {
|
||||
const cacheKey = 'pbw-gh-stars'
|
||||
|
||||
const cachedJSON = localStorage.getItem(cacheKey)
|
||||
if (cachedJSON) {
|
||||
const cached = JSON.parse(cachedJSON)
|
||||
if (Date.now() - cached.timestamp < 2 * 60 * 1000) {
|
||||
return cached.value
|
||||
}
|
||||
}
|
||||
|
||||
const url = 'https://api.github.com/repos/eduardolat/pgbackweb'
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
return null
|
||||
}
|
||||
const data = await response.json()
|
||||
const value = data.stargazers_count
|
||||
const dataToCache = JSON.stringify({
|
||||
value,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
localStorage.setItem(cacheKey, dataToCache)
|
||||
return value
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package databases
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/database/dbgen"
|
||||
"github.com/eduardolat/pgbackweb/internal/validate"
|
||||
@@ -77,10 +79,7 @@ func createDatabaseButton() gomponents.Node {
|
||||
Required: true,
|
||||
HelpText: "The version of the database",
|
||||
Children: []gomponents.Node{
|
||||
html.Option(html.Value("13"), gomponents.Text("PostgreSQL 13")),
|
||||
html.Option(html.Value("14"), gomponents.Text("PostgreSQL 14")),
|
||||
html.Option(html.Value("15"), gomponents.Text("PostgreSQL 15")),
|
||||
html.Option(html.Value("16"), gomponents.Text("PostgreSQL 16")),
|
||||
component.PGVersionSelectOptions(sql.NullString{}),
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@@ -90,22 +90,10 @@ func editDatabaseButton(
|
||||
Required: true,
|
||||
HelpText: "The version of the database",
|
||||
Children: []gomponents.Node{
|
||||
html.Option(
|
||||
gomponents.If(database.PgVersion == "13", html.Selected()),
|
||||
html.Value("13"), gomponents.Text("PostgreSQL 13"),
|
||||
),
|
||||
html.Option(
|
||||
gomponents.If(database.PgVersion == "14", html.Selected()),
|
||||
html.Value("14"), gomponents.Text("PostgreSQL 14"),
|
||||
),
|
||||
html.Option(
|
||||
gomponents.If(database.PgVersion == "15", html.Selected()),
|
||||
html.Value("15"), gomponents.Text("PostgreSQL 15"),
|
||||
),
|
||||
html.Option(
|
||||
gomponents.If(database.PgVersion == "16", html.Selected()),
|
||||
html.Value("16"), gomponents.Text("PostgreSQL 16"),
|
||||
),
|
||||
component.PGVersionSelectOptions(sql.NullString{
|
||||
Valid: true,
|
||||
String: database.PgVersion,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/database/dbgen"
|
||||
"github.com/eduardolat/pgbackweb/internal/util/echoutil"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/reqctx"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/alpine"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/layout"
|
||||
"github.com/google/uuid"
|
||||
@@ -201,111 +199,8 @@ func indexPage(
|
||||
BgColors: []string{blueColor, greenColor, redColor},
|
||||
}),
|
||||
),
|
||||
html.Div(
|
||||
alpine.XData("genericSlider(4)"),
|
||||
alpine.XCloak(),
|
||||
html.Class("mt-6 flex flex-col justify-center items-center mx-auto"),
|
||||
component.H2Text("How to use PG Back Web"),
|
||||
component.CardBox(component.CardBoxParams{
|
||||
Class: "mt-4 space-y-4 max-w-[600px]",
|
||||
Children: []gomponents.Node{
|
||||
html.Div(
|
||||
html.Class("flex justify-center"),
|
||||
html.Ul(
|
||||
html.Class("steps"),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 1 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Create database"),
|
||||
),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 2 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Create destination"),
|
||||
),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 3 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Create backup"),
|
||||
),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 4 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Wait for executions"),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 1"),
|
||||
component.H3Text("Create database"),
|
||||
component.PText(`
|
||||
To create a database, click on the "Databases" menu item on the
|
||||
left sidebar. Then click on the "Create database" button. Fill
|
||||
in the form and click on the "Save" button. You can create as
|
||||
many databases as you want to backup.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 2"),
|
||||
component.H3Text("Create S3 destination (optional)"),
|
||||
component.PText(`
|
||||
To create a destination, click on the "Destinations" menu item on
|
||||
the left sidebar. Then click on the "Create destination" button.
|
||||
Fill in the form and click on the "Save" button. You can create
|
||||
as many destinations as you want to store the backups. If you
|
||||
don't want to use S3 destinations and store the backups locally,
|
||||
you can skip this step.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 3"),
|
||||
component.H3Text("Create backup"),
|
||||
component.PText(`
|
||||
To create a backup you need to have at least one database and one
|
||||
destination. Click on the "Backups" menu item on the left sidebar.
|
||||
Then click on the "Create backup" button. Fill in the form and
|
||||
click on the "Save" button. You can create as many backups as you
|
||||
want including any combination of databases and destinations.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 4"),
|
||||
component.H3Text("Wait for executions"),
|
||||
component.PText(`
|
||||
When your backup is created and active, the system will start
|
||||
creating executions based on the schedule you defined. You can
|
||||
also create executions manually by clicking the "Run backup now"
|
||||
button on the backups list. You can see the executions on the
|
||||
"Executions" menu item on the left sidebar and then click on the
|
||||
"Show details" button to see the details, logs, and download or
|
||||
delete the backup file.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
html.Class("mt-4 flex justify-between"),
|
||||
html.Button(
|
||||
alpine.XBind("disabled", "!hasPrevSlide"),
|
||||
alpine.XOn("click", "prevSlide"),
|
||||
html.Class("btn btn-neutral btn-ghost"),
|
||||
lucide.ChevronLeft(),
|
||||
component.SpanText("Previous"),
|
||||
),
|
||||
html.Button(
|
||||
alpine.XBind("disabled", "!hasNextSlide"),
|
||||
alpine.XOn("click", "nextSlide"),
|
||||
html.Class("btn btn-neutral btn-ghost"),
|
||||
component.SpanText("Next"),
|
||||
lucide.ChevronRight(),
|
||||
),
|
||||
),
|
||||
},
|
||||
}),
|
||||
),
|
||||
indexHowTo(),
|
||||
}
|
||||
|
||||
return layout.Dashboard(reqCtx, layout.DashboardParams{
|
||||
|
||||
119
internal/view/web/dashboard/summary/index_how_to.go
Normal file
119
internal/view/web/dashboard/summary/index_how_to.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package summary
|
||||
|
||||
import (
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/alpine"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
func indexHowTo() gomponents.Node {
|
||||
return html.Div(
|
||||
alpine.XData("alpineSummaryHowToSlider()"),
|
||||
alpine.XCloak(),
|
||||
html.Class("mt-6 flex flex-col justify-center items-center mx-auto"),
|
||||
|
||||
component.H2Text("How to use PG Back Web"),
|
||||
|
||||
component.CardBox(component.CardBoxParams{
|
||||
Class: "mt-4 space-y-4 max-w-[600px]",
|
||||
Children: []gomponents.Node{
|
||||
html.Div(
|
||||
html.Class("flex justify-center"),
|
||||
html.Ul(
|
||||
html.Class("steps"),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 1 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Create database"),
|
||||
),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 2 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Create destination"),
|
||||
),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 3 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Create backup"),
|
||||
),
|
||||
html.Li(
|
||||
html.Class("step"),
|
||||
alpine.XBind("class", "currentSlide >= 4 ? 'step-primary' : ''"),
|
||||
gomponents.Text("Wait for executions"),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 1"),
|
||||
component.H3Text("Create database"),
|
||||
component.PText(`
|
||||
To create a database, click on the "Databases" menu item on the
|
||||
left sidebar. Then click on the "Create database" button. Fill
|
||||
in the form and click on the "Save" button. You can create as
|
||||
many databases as you want to backup.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 2"),
|
||||
component.H3Text("Create S3 destination (optional)"),
|
||||
component.PText(`
|
||||
To create a destination, click on the "Destinations" menu item on
|
||||
the left sidebar. Then click on the "Create destination" button.
|
||||
Fill in the form and click on the "Save" button. You can create
|
||||
as many destinations as you want to store the backups. If you
|
||||
don't want to use S3 destinations and store the backups locally,
|
||||
you can skip this step.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 3"),
|
||||
component.H3Text("Create backup"),
|
||||
component.PText(`
|
||||
To create a backup you need to have at least one database and one
|
||||
destination. Click on the "Backups" menu item on the left sidebar.
|
||||
Then click on the "Create backup" button. Fill in the form and
|
||||
click on the "Save" button. You can create as many backups as you
|
||||
want including any combination of databases and destinations.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
alpine.XShow("currentSlide === 4"),
|
||||
component.H3Text("Wait for executions"),
|
||||
component.PText(`
|
||||
When your backup is created and active, the system will start
|
||||
creating executions based on the schedule you defined. You can
|
||||
also create executions manually by clicking the "Run backup now"
|
||||
button on the backups list. You can see the executions on the
|
||||
"Executions" menu item on the left sidebar and then click on the
|
||||
"Show details" button to see the details, logs, and download or
|
||||
delete the backup file.
|
||||
`),
|
||||
),
|
||||
|
||||
html.Div(
|
||||
html.Class("mt-4 flex justify-between"),
|
||||
html.Button(
|
||||
alpine.XBind("disabled", "!hasPrevSlide"),
|
||||
alpine.XOn("click", "prevSlide"),
|
||||
html.Class("btn btn-neutral btn-ghost"),
|
||||
lucide.ChevronLeft(),
|
||||
component.SpanText("Previous"),
|
||||
),
|
||||
html.Button(
|
||||
alpine.XBind("disabled", "!hasNextSlide"),
|
||||
alpine.XOn("click", "nextSlide"),
|
||||
html.Class("btn btn-neutral btn-ghost"),
|
||||
component.SpanText("Next"),
|
||||
lucide.ChevronRight(),
|
||||
),
|
||||
),
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
export const genericSlider = {
|
||||
name: 'genericSlider',
|
||||
fn: (slidesQty = 0) => ({
|
||||
currentSlide: slidesQty > 0 ? 1 : 0,
|
||||
window.alpineSummaryHowToSlider = function () {
|
||||
return {
|
||||
slidesQty: 4,
|
||||
currentSlide: 1,
|
||||
|
||||
get hasNextSlide () {
|
||||
return this.currentSlide < slidesQty
|
||||
return this.currentSlide < this.slidesQty
|
||||
},
|
||||
|
||||
get hasPrevSlide () {
|
||||
return this.currentSlide > 1
|
||||
},
|
||||
|
||||
nextSlide () {
|
||||
if (this.hasNextSlide) this.currentSlide++
|
||||
},
|
||||
|
||||
prevSlide () {
|
||||
if (this.hasPrevSlide) this.currentSlide--
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ func head() gomponents.Node {
|
||||
|
||||
return gomponents.Group([]gomponents.Node{
|
||||
html.Link(html.Rel("shortcut icon"), href("/favicon.ico")),
|
||||
html.Link(html.Rel("stylesheet"), href("/css/style.min.css")),
|
||||
html.Script(src("/js/app.min.js")),
|
||||
html.Link(html.Rel("stylesheet"), href("/build/style.min.css")),
|
||||
html.Script(src("/build/app.min.js")),
|
||||
|
||||
html.Script(src("/libs/htmx/htmx-2.0.1.min.js"), html.Defer()),
|
||||
html.Script(src("/libs/alpinejs/alpinejs-3.14.1.min.js"), html.Defer()),
|
||||
|
||||
@@ -118,7 +118,7 @@ func dashboardAsideItem(
|
||||
text, link string, strict bool,
|
||||
) gomponents.Node {
|
||||
return html.A(
|
||||
alpine.XData(fmt.Sprintf("dashboardAsideItem('%s', %t)", link, strict)),
|
||||
alpine.XData(fmt.Sprintf("alpineDashboardAsideItem('%s', %t)", link, strict)),
|
||||
html.Class("block flex flex-col items-center justify-center group"),
|
||||
html.Href(link),
|
||||
html.Button(
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
export const dashboardAsideItem = {
|
||||
name: 'dashboardAsideItem',
|
||||
fn: (link = '', strict = false) => ({
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const el = document.getElementById('dashboard-aside')
|
||||
const key = 'dashboard-aside-scroll-position'
|
||||
|
||||
if (!el) return
|
||||
|
||||
const saveScrollPosition = window.debounce(
|
||||
() => {
|
||||
const scrollPosition = el.scrollTop
|
||||
localStorage.setItem(key, scrollPosition)
|
||||
},
|
||||
200
|
||||
)
|
||||
el.addEventListener('scroll', saveScrollPosition)
|
||||
|
||||
const scrollPosition = localStorage.getItem(key)
|
||||
if (scrollPosition) {
|
||||
el.scrollTop = parseInt(scrollPosition, 10)
|
||||
}
|
||||
})
|
||||
|
||||
window.alpineDashboardAsideItem = function (link = '', strict = false) {
|
||||
return {
|
||||
link,
|
||||
strict,
|
||||
is_active: false,
|
||||
@@ -29,5 +49,5 @@ export const dashboardAsideItem = {
|
||||
this.checkActive()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
package layout
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/config"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/alpine"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/htmx"
|
||||
"github.com/maragudk/gomponents"
|
||||
@@ -28,7 +24,7 @@ func dashboardHeader() gomponents.Node {
|
||||
Size: component.SizeMd,
|
||||
}),
|
||||
component.StarOnGithub(component.SizeMd),
|
||||
dashboardHeaderCheckForUpdates(),
|
||||
dashboardHeaderUpdates(),
|
||||
component.HxLoadingMd("header-indicator"),
|
||||
),
|
||||
html.Div(
|
||||
@@ -55,26 +51,3 @@ func dashboardHeader() gomponents.Node {
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func dashboardHeaderCheckForUpdates() gomponents.Node {
|
||||
return html.A(
|
||||
alpine.XData("githubRepoInfo"),
|
||||
alpine.XCloak(),
|
||||
alpine.XShow(fmt.Sprintf(
|
||||
"latestRelease !== '' && latestRelease !== '%s'",
|
||||
config.Version,
|
||||
)),
|
||||
|
||||
components.Classes{
|
||||
"btn btn-warning": true,
|
||||
},
|
||||
html.Href("https://github.com/eduardolat/pgbackweb/releases"),
|
||||
html.Target("_blank"),
|
||||
lucide.ExternalLink(),
|
||||
component.SpanText("Update available"),
|
||||
html.Span(
|
||||
alpine.XShow("stars"),
|
||||
alpine.XText("'( ' + latestRelease + ' )'"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
32
internal/view/web/layout/dashboard_header_updates.go
Normal file
32
internal/view/web/layout/dashboard_header_updates.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package layout
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
lucide "github.com/eduardolat/gomponents-lucide"
|
||||
"github.com/eduardolat/pgbackweb/internal/config"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/alpine"
|
||||
"github.com/eduardolat/pgbackweb/internal/view/web/component"
|
||||
"github.com/maragudk/gomponents"
|
||||
"github.com/maragudk/gomponents/html"
|
||||
)
|
||||
|
||||
func dashboardHeaderUpdates() gomponents.Node {
|
||||
return html.A(
|
||||
alpine.XData("alpineDashboardHeaderUpdates()"),
|
||||
alpine.XCloak(),
|
||||
alpine.XShow(fmt.Sprintf(
|
||||
"latestRelease !== null && latestRelease !== '%s'",
|
||||
config.Version,
|
||||
)),
|
||||
|
||||
html.Class("btn btn-warning"),
|
||||
html.Href("https://github.com/eduardolat/pgbackweb/releases"),
|
||||
html.Target("_blank"),
|
||||
lucide.ExternalLink(),
|
||||
component.SpanText("Update available"),
|
||||
html.Span(
|
||||
alpine.XText("'( ' + latestRelease + ' )'"),
|
||||
),
|
||||
)
|
||||
}
|
||||
42
internal/view/web/layout/dashboard_header_updates.inc.js
Normal file
42
internal/view/web/layout/dashboard_header_updates.inc.js
Normal file
@@ -0,0 +1,42 @@
|
||||
window.alpineDashboardHeaderUpdates = function () {
|
||||
return {
|
||||
latestRelease: null,
|
||||
|
||||
async init () {
|
||||
const latestRelease = await this.getLatestRelease()
|
||||
if (latestRelease !== null) {
|
||||
this.latestRelease = latestRelease
|
||||
}
|
||||
},
|
||||
|
||||
async getLatestRelease () {
|
||||
const cacheKey = 'pbw-gh-last-release'
|
||||
|
||||
const cachedJSON = localStorage.getItem(cacheKey)
|
||||
if (cachedJSON) {
|
||||
const cached = JSON.parse(cachedJSON)
|
||||
if (Date.now() - cached.timestamp < 2 * 60 * 1000) {
|
||||
return cached.value
|
||||
}
|
||||
}
|
||||
|
||||
const url = 'https://api.github.com/repos/eduardolat/pgbackweb/releases/latest'
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
return null
|
||||
}
|
||||
const data = await response.json()
|
||||
const value = data.name
|
||||
const dataToCache = JSON.stringify({
|
||||
value,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
localStorage.setItem(cacheKey, dataToCache)
|
||||
return value
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
218
package-lock.json
generated
218
package-lock.json
generated
@@ -11,6 +11,8 @@
|
||||
"devDependencies": {
|
||||
"daisyui": "4.12.10",
|
||||
"esbuild": "0.23.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"glob": "11.0.0",
|
||||
"standard": "17.1.0",
|
||||
"tailwindcss": "3.4.6"
|
||||
}
|
||||
@@ -575,6 +577,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
@@ -675,6 +678,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@@ -730,10 +734,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -746,6 +751,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -972,6 +978,7 @@
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
@@ -1346,13 +1353,15 @@
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
@@ -2304,6 +2313,21 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
|
||||
"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@@ -2409,21 +2433,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz",
|
||||
"integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"jackspeak": "^4.0.1",
|
||||
"minimatch": "^10.0.0",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
"path-scurry": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
@@ -2801,6 +2829,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -3043,18 +3072,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz",
|
||||
"integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
@@ -3120,6 +3150,19 @@
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsx-ast-utils": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||
@@ -3240,10 +3283,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz",
|
||||
"integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
@@ -3268,15 +3315,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
|
||||
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
@@ -3296,6 +3344,7 @@
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
@@ -3600,16 +3649,17 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
|
||||
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
"lru-cache": "^11.0.0",
|
||||
"minipass": "^7.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.18"
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
@@ -4341,6 +4391,7 @@
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eastasianwidth": "^0.2.0",
|
||||
"emoji-regex": "^9.2.2",
|
||||
@@ -4359,6 +4410,7 @@
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
@@ -4373,6 +4425,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4381,13 +4434,15 @@
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
@@ -4485,6 +4540,7 @@
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
@@ -4501,6 +4557,7 @@
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
@@ -4513,6 +4570,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4560,6 +4618,83 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase/node_modules/jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase/node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sucrase/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase/node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -4790,6 +4925,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -4922,6 +5067,7 @@
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.1.0",
|
||||
"string-width": "^5.0.1",
|
||||
@@ -4940,6 +5086,7 @@
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
@@ -4957,6 +5104,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4966,6 +5114,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
@@ -4980,13 +5129,15 @@
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
@@ -5001,6 +5152,7 @@
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"devDependencies": {
|
||||
"daisyui": "4.12.10",
|
||||
"esbuild": "0.23.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"glob": "11.0.0",
|
||||
"standard": "17.1.0",
|
||||
"tailwindcss": "3.4.6"
|
||||
},
|
||||
@@ -25,4 +27,4 @@
|
||||
"Swal"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
107
scripts/build-js.mjs
Normal file
107
scripts/build-js.mjs
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* This script is responsible for creating the final build of all the project's
|
||||
* JavaScript.
|
||||
*
|
||||
* 1. Creates a prebuild of internal/view/static/js/app.js
|
||||
* 2. Creates a prebuild of all *.inc.js files in internal/view/web
|
||||
* 3. Combines the two prebuilds into a final build, minifies it, and stores
|
||||
* it in internal/view/static/build/app.min.js
|
||||
*
|
||||
* This script generates temporal files in the tmp directory.
|
||||
*/
|
||||
|
||||
import path from 'path'
|
||||
import fse from 'fs-extra'
|
||||
import * as esbuild from 'esbuild'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { glob } from 'glob'
|
||||
|
||||
// Obtains the project's root directory
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
const rootDir = path.join(__dirname, '..')
|
||||
|
||||
async function prebuildApp () {
|
||||
const entryFile = path.join(rootDir, './internal/view/static/js/app.js')
|
||||
const outFile = path.join(rootDir, './tmp/prebuild-app.js')
|
||||
|
||||
try {
|
||||
await esbuild.build({
|
||||
entryPoints: [entryFile],
|
||||
bundle: true,
|
||||
minify: false,
|
||||
outfile: outFile,
|
||||
format: 'iife'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error prebuilding app.js:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function prebuildIncludedFiles () {
|
||||
const alpineGlob = path.join(rootDir, './internal/view/web/**/*.inc.js')
|
||||
const tempFile = path.join(rootDir, './tmp/prebuild-incs.js')
|
||||
|
||||
try {
|
||||
const alpineFiles = await glob(alpineGlob)
|
||||
|
||||
let outFileContent = `// This file is auto-generated by ${__filename}. DO NOT EDIT.\n\n`
|
||||
|
||||
for (const file of alpineFiles) {
|
||||
const content = await fse.readFile(file, 'utf-8')
|
||||
outFileContent += content + '\n'
|
||||
}
|
||||
|
||||
await fse.outputFile(tempFile, outFileContent)
|
||||
} catch (error) {
|
||||
console.error('Error prebuilding *.inc.js files:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function mergePrebuilds () {
|
||||
const prebuilds = [
|
||||
path.join(rootDir, './tmp/prebuild-app.js'),
|
||||
path.join(rootDir, './tmp/prebuild-incs.js')
|
||||
]
|
||||
|
||||
const outFile = path.join(rootDir, './tmp/prebuild.js')
|
||||
|
||||
try {
|
||||
let outFileContent = ''
|
||||
|
||||
for (const file of prebuilds) {
|
||||
const content = await fse.readFile(file, 'utf-8')
|
||||
outFileContent += content + '\n\n'
|
||||
}
|
||||
|
||||
await fse.outputFile(outFile, outFileContent)
|
||||
} catch (error) {
|
||||
console.error('Error combining prebuilds:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function build () {
|
||||
const entryFile = path.join(rootDir, './tmp/prebuild.js')
|
||||
const outFile = path.join(rootDir, './internal/view/static/build/app.min.js')
|
||||
|
||||
try {
|
||||
await esbuild.build({
|
||||
entryPoints: [entryFile],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
outfile: outFile,
|
||||
format: 'iife'
|
||||
})
|
||||
|
||||
console.log('JavaScript builded successfully')
|
||||
} catch (error) {
|
||||
console.error('Error creating JavaScript build:', error)
|
||||
}
|
||||
}
|
||||
|
||||
await prebuildApp()
|
||||
await prebuildIncludedFiles()
|
||||
await mergePrebuilds()
|
||||
await build()
|
||||
@@ -33,12 +33,13 @@ check_command "/usr/lib/postgresql/15/bin/psql --version" "PostgreSQL 15 psql"
|
||||
check_command "/usr/lib/postgresql/15/bin/pg_dump --version" "PostgreSQL 15 pg_dump"
|
||||
check_command "/usr/lib/postgresql/16/bin/psql --version" "PostgreSQL 16 psql"
|
||||
check_command "/usr/lib/postgresql/16/bin/pg_dump --version" "PostgreSQL 16 pg_dump"
|
||||
check_command "/usr/lib/postgresql/17/bin/psql --version" "PostgreSQL 17 psql"
|
||||
check_command "/usr/lib/postgresql/17/bin/pg_dump --version" "PostgreSQL 17 pg_dump"
|
||||
|
||||
# Check software installed by downloading binaries
|
||||
check_command "task --version" "task"
|
||||
check_command "goose --version" "goose"
|
||||
check_command "sqlc version" "sqlc"
|
||||
check_command "golangci-lint --version" "golangci-lint"
|
||||
check_command "air -v" "air"
|
||||
|
||||
echo "All dependencies are working correctly!"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Fix permissions of all files in the current directory and subdirectories
|
||||
chmod -R 777 ./
|
||||
39
scripts/sqlc-prebuild.mjs
Normal file
39
scripts/sqlc-prebuild.mjs
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import path from 'path'
|
||||
import fse from 'fs-extra'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { glob } from 'glob'
|
||||
|
||||
const sourceGlobs = [
|
||||
'./internal/service/**/*.sql'
|
||||
]
|
||||
|
||||
const outputFilePath = './internal/database/dbgen/queries.gen.sql'
|
||||
|
||||
// Obtains the project's root directory
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
const rootDir = path.join(__dirname, '..')
|
||||
const absoluteOutputFilePath = path.join(rootDir, outputFilePath)
|
||||
|
||||
try {
|
||||
// Find all files that match the source globs
|
||||
const files = []
|
||||
for (const sourceGlob of sourceGlobs) {
|
||||
const foundFiles = await glob(path.join(rootDir, sourceGlob))
|
||||
files.push(...foundFiles)
|
||||
}
|
||||
|
||||
// Read each file and concatenate them into a single string
|
||||
let outFileContent = `-- This file is auto-generated by ${__filename}. DO NOT EDIT.\n\n`
|
||||
for (const file of files) {
|
||||
const content = await fse.readFile(file, 'utf-8')
|
||||
outFileContent += `-- file: ${file}\n\n${content}\n\n`
|
||||
}
|
||||
|
||||
await fse.ensureDir(path.dirname(absoluteOutputFilePath))
|
||||
await fse.outputFile(absoluteOutputFilePath, outFileContent)
|
||||
} catch (error) {
|
||||
console.error('Error creating SQLC prebuild:', error)
|
||||
}
|
||||
@@ -3,8 +3,7 @@ version: "2"
|
||||
sql:
|
||||
- engine: "postgresql"
|
||||
schema: "./internal/database/migrations/"
|
||||
queries:
|
||||
- "./internal/service/*/"
|
||||
queries: "./internal/database/dbgen/queries.gen.sql"
|
||||
gen:
|
||||
go:
|
||||
package: "dbgen"
|
||||
|
||||
@@ -2,6 +2,8 @@ version: "3"
|
||||
|
||||
dotenv: [".env"]
|
||||
|
||||
interval: 500ms
|
||||
|
||||
tasks:
|
||||
on:
|
||||
desc: Start development environment, should be run from the host machine
|
||||
@@ -15,7 +17,31 @@ tasks:
|
||||
|
||||
dev:
|
||||
desc: Build and serve the project with hot reloading
|
||||
cmd: air -c .air.toml
|
||||
watch: true
|
||||
sources:
|
||||
- "**/*.go"
|
||||
- "**/*.sql"
|
||||
- "**/*.js"
|
||||
- "**/*.css"
|
||||
- "**/*.json"
|
||||
- exclude: "./.git/**"
|
||||
- exclude: "./node_modules/**"
|
||||
- exclude: "./internal/database/dbgen/**"
|
||||
- exclude: "./internal/view/static/build/**"
|
||||
- exclude: "./temp/**"
|
||||
- exclude: "./tmp/**"
|
||||
- exclude: "./dist/**"
|
||||
- exclude: "**/*.test.go"
|
||||
- exclude: "**/*.generated.go"
|
||||
- exclude: "**/*.sql.go"
|
||||
- exclude: "**/*.gen.go"
|
||||
- exclude: "**/*.gen.sql"
|
||||
- exclude: "**/*.min.css"
|
||||
- exclude: "**/*.min.js"
|
||||
deps:
|
||||
- build
|
||||
cmds:
|
||||
- ./dist/app
|
||||
|
||||
build:
|
||||
desc: Build the project
|
||||
@@ -54,9 +80,14 @@ tasks:
|
||||
gen-db:
|
||||
desc: Generate sqlc files
|
||||
silent: true
|
||||
cmd: sqlc generate
|
||||
cmds:
|
||||
- ./scripts/sqlc-prebuild.mjs
|
||||
- sqlc generate
|
||||
sources:
|
||||
- ./internal/**/*.sql
|
||||
- ./internal/service/**/*.sql
|
||||
generates:
|
||||
- ./internal/database/queries.gen.sql
|
||||
- ./internal/database/dbgen/*.go
|
||||
|
||||
reset-db:
|
||||
desc: Reset the database
|
||||
@@ -68,12 +99,11 @@ tasks:
|
||||
cmds:
|
||||
- >
|
||||
npm run tailwindcss --
|
||||
--minify
|
||||
--config ./tailwind.config.js
|
||||
--input ./internal/view/static/css/style.css
|
||||
--output ./internal/view/static/css/style.min.css --minify
|
||||
- >
|
||||
npm run esbuild -- ./internal/view/static/js/app.js
|
||||
--bundle --minify --outfile=./internal/view/static/js/app.min.js
|
||||
--output ./internal/view/static/build/style.min.css
|
||||
- ./scripts/build-js.mjs
|
||||
|
||||
tidy:
|
||||
desc: Tidy the go.mod file
|
||||
@@ -118,6 +148,6 @@ tasks:
|
||||
- rm -rf ./tmp
|
||||
- rm -rf ./dist
|
||||
|
||||
fixperms: # Fixes the permissions of the files in the project
|
||||
fixperms:
|
||||
desc: Fixes the permissions of the files in the project
|
||||
cmd: ./scripts/fixperms.sh
|
||||
cmd: chmod -R 777 ./
|
||||
|
||||
Reference in New Issue
Block a user