From de2c8b453430b74aeb44cbd6cbbec424bfc500f0 Mon Sep 17 00:00:00 2001 From: okxlin Date: Wed, 2 Aug 2023 09:20:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0pgadmin4=E5=88=B0?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pgadmin4/7.5/.env.sample | 4 + apps/pgadmin4/7.5/data.yml | 26 +++ apps/pgadmin4/7.5/docker-compose.yml | 26 +++ apps/pgadmin4/README.md | 286 ++++++++++++++++++++++++ apps/pgadmin4/data.yml | 20 ++ apps/pgadmin4/latest/.env.sample | 4 + apps/pgadmin4/latest/data.yml | 26 +++ apps/pgadmin4/latest/docker-compose.yml | 26 +++ apps/pgadmin4/logo.png | Bin 0 -> 10661 bytes 9 files changed, 418 insertions(+) create mode 100644 apps/pgadmin4/7.5/.env.sample create mode 100644 apps/pgadmin4/7.5/data.yml create mode 100644 apps/pgadmin4/7.5/docker-compose.yml create mode 100644 apps/pgadmin4/README.md create mode 100644 apps/pgadmin4/data.yml create mode 100644 apps/pgadmin4/latest/.env.sample create mode 100644 apps/pgadmin4/latest/data.yml create mode 100644 apps/pgadmin4/latest/docker-compose.yml create mode 100644 apps/pgadmin4/logo.png diff --git a/apps/pgadmin4/7.5/.env.sample b/apps/pgadmin4/7.5/.env.sample new file mode 100644 index 00000000..c073bbff --- /dev/null +++ b/apps/pgadmin4/7.5/.env.sample @@ -0,0 +1,4 @@ +CONTAINER_NAME="pgadmin4" +PANEL_APP_PORT_HTTP="40084" +PGADMIN_EMAIL="admin@example.com" +PGADMIN_PASSWORD="pgadmin4_pwd" diff --git a/apps/pgadmin4/7.5/data.yml b/apps/pgadmin4/7.5/data.yml new file mode 100644 index 00000000..ef76cd61 --- /dev/null +++ b/apps/pgadmin4/7.5/data.yml @@ -0,0 +1,26 @@ +additionalProperties: + formFields: + - default: 40084 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: admin@example.com + edit: true + envKey: PGADMIN_EMAIL + labelEn: Admin Email + labelZh: 管理员邮箱 + required: true + type: text + - default: pgadmin4 + edit: true + envKey: PGADMIN_PASSWORD + labelEn: Admin Password + labelZh: 管理员密码 + random: false + required: false + rule: paramComplexity + type: password diff --git a/apps/pgadmin4/7.5/docker-compose.yml b/apps/pgadmin4/7.5/docker-compose.yml new file mode 100644 index 00000000..2b40f8e3 --- /dev/null +++ b/apps/pgadmin4/7.5/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3' +services: + pgadmin4: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + volumes: + - pgadmin4-data:/var/lib/pgadmin + ports: + - "${PANEL_APP_PORT_HTTP}:80" + environment: + - PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL} + - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD} + - PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION=True + - PGADMIN_CONFIG_CONSOLE_LOG_LEVEL=10 + image: dpage/pgadmin4:7.5 + labels: + createdBy: "Apps" + +volumes: + pgadmin4-data: + +networks: + 1panel-network: + external: true diff --git a/apps/pgadmin4/README.md b/apps/pgadmin4/README.md new file mode 100644 index 00000000..d2c50388 --- /dev/null +++ b/apps/pgadmin4/README.md @@ -0,0 +1,286 @@ +# pgAdmin 4 + +pgAdmin 4 is a rewrite of the popular pgAdmin3 management tool for the +PostgreSQL (http://www.postgresql.org) database. + +In the following documentation and examples, *$PGADMIN4_SRC/* is used to denote +the top-level directory of a copy of the pgAdmin source tree, either from a +tarball or a git checkout. + +## Architecture + +pgAdmin 4 is written as a web application in Python, using jQuery and Bootstrap +for the client side processing and UI. On the server side, Flask is being +utilised. + +Although developed using web technologies, pgAdmin 4 can be deployed either on +a web server using a browser, or standalone on a workstation. The runtime/ +subdirectory contains an NWjs based runtime application intended to allow this, +which will execute the Python server and display the UI. + +## Building the Runtime + +To build the runtime, the following packages must be installed: + +* NodeJS 12+ +* Yarn + +Change into the runtime directory, and run *yarn install*. This will install the +dependencies required. + +In order to use the runtime in a development environment, you'll need to copy +*dev_config.json.in* file to *dev_config.json*, and edit the paths to the Python +executable and *pgAdmin.py* file, otherwise the runtime will use the default +paths it would expect to find in the standard package for your platform. + +You can then execute the runtime by running something like: + +```bash +node_modules/nw/nwjs/nw . +``` + +or on macOS: + +```bash +node_modules/nw/nwjs/nwjs.app/Contents/MacOS/nwjs . +``` + +# Configuring the Python Environment + +In order to run the Python code, a suitable runtime environment is required. +Python version 3.7 and later are currently supported. It is recommended that a +Python Virtual Environment is setup for this purpose, rather than using the +system Python environment. On Linux and Mac systems, the process is fairly +simple - adapt as required for your distribution: + +1. Create a virtual environment in an appropriate directory. The last argument is + the name of the environment; that can be changed as desired: + + ```bash + $ python3 -m venv venv + ``` + +2. Now activate the virtual environment: + + ```bash + $ source venv/bin/activate + ``` + +3. Some of the components used by pgAdmin require a very recent version of *pip*, + so update that to the latest: + + ```bash + $ pip install --upgrade pip + ``` + +4. Ensure that a PostgreSQL installation's bin/ directory is in the path (so + pg_config can be found for building psycopg3), and install the required + packages: + + ```bash + (venv) $ PATH=$PATH:/usr/local/pgsql/bin pip install -r $PGADMIN4_SRC/requirements.txt + ``` + + If you are planning to run the regression tests, you also need to install + additional requirements from web/regression/requirements.txt: + + ```bash + (venv) $ pip install -r $PGADMIN4_SRC/web/regression/requirements.txt + ``` + +5. Create a local configuration file for pgAdmin. Edit + $PGADMIN4_SRC/web/config_local.py and add any desired configuration options + (use the config.py file as a reference - any settings duplicated in + config_local.py will override those in config.py). A typical development + configuration may look like: + + ```python + from config import * + + # Debug mode + DEBUG = True + + # App mode + SERVER_MODE = True + + # Enable the test module + MODULE_BLACKLIST.remove('test') + + # Log + CONSOLE_LOG_LEVEL = DEBUG + FILE_LOG_LEVEL = DEBUG + + DEFAULT_SERVER = '127.0.0.1' + + UPGRADE_CHECK_ENABLED = True + + # Use a different config DB for each server mode. + if SERVER_MODE == False: + SQLITE_PATH = os.path.join( + DATA_DIR, + 'pgadmin4-desktop.db' + ) + else: + SQLITE_PATH = os.path.join( + DATA_DIR, + 'pgadmin4-server.db' + ) + ``` + + This configuration allows easy switching between server and desktop modes + for testing. + +6. The initial setup of the configuration database is interactive in server + mode, and non-interactive in desktop mode. You can run it either by + running: + + ```bash + (venv) $ python3 $PGADMIN4_SRC/web/setup.py + ``` + + or by starting pgAdmin 4: + + ```bash + (venv) $ python3 $PGADMIN4_SRC/web/pgAdmin4.py + ``` + + Whilst it is possible to automatically run setup in desktop mode by running + the runtime, that will not work in server mode as the runtime doesn't allow + command line interaction with the setup program. + +At this point you will be able to run pgAdmin 4 from the command line in either +server or desktop mode, and access it from a web browser using the URL shown in +the terminal once pgAdmin has started up. + +Setup of an environment on Windows is somewhat more complicated unfortunately, +please see *pkg/win32/README.txt* for complete details. + +# Building the Web Assets + +pgAdmin is dependent on a number of third party Javascript libraries. These, +along with it's own Javascript code, SCSS/CSS code and images must be +compiled into a "bundle" which is transferred to the browser for execution +and rendering. This is far more efficient than simply requesting each +asset as it's needed by the client. + +To create the bundle, you will need the 'yarn' package management tool to be +installed. Then, you can run the following commands on a *nix system to +download the required packages and build the bundle: + +```bash +(venv) $ cd $PGADMIN4_SRC +(venv) $ make install-node +(venv) $ make bundle +``` + +On Windows systems (where "make" is not available), the following commands +can be used: + +``` +C:\> cd $PGADMIN4_SRC\web +C:\$PGADMIN4_SRC\web> yarn install +C:\$PGADMIN4_SRC\web> yarn run bundle +``` + +# Creating pgAdmin themes + +To create a pgAdmin theme, you need to create a directory under +*web/pgadmin/static/scss/resources*. +Copy the sample file *_theme.variables.scss.sample* to the new directory and +rename it to *_theme.variables.scss*. Change the desired hexadecimal values of +the colors and bundle pgAdmin. You can also add a preview image in the theme +directory with the name as *\_preview.png*. It is recommended that the +preview image should not be larger in size as it may take time to load on slow +networks. Run the *yarn run bundle* and you're good to go. No other changes are +required, pgAdmin bundle will read the directory and create other required +entries to make them available in preferences. + +The name of the theme is derived from the directory name. Underscores (_) and +hyphens (-) will be replaced with spaces and the result will be camel cased. + +# Building the documentation + +In order to build the docs, an additional Python package is required in the +virtual environment. This can be installed with the pip package manager: + +```bash +$ source venv/bin/activate +(venv) $ pip install Sphinx +(venv) $ pip install sphinxcontrib-youtube +``` + +The docs can then be built using the Makefile in *$PGADMIN4_SRC*, e.g. + +```bash +(venv) $ make docs +``` + +The output can be found in *$PGADMIN4_SRC/docs/en_US/_build/html/index.html* + +# Building packages + +Most packages can be built using the Makefile in $PGADMIN4_SRC, provided all +the setup and configuration above has been completed. + +To build a source tarball: + +```bash +(venv) $ make src +``` + +To build a PIP Wheel, activate either a Python 3 virtual environment, configured +with all the required packages, and then run: + +```bash +(venv) $ make pip +``` + +To build the macOS AppBundle, please see *pkg/mac/README*. + +To build the Windows installer, please see *pkg/win32/README.txt*. +# Create Database Migrations + +In order to make changes to the SQLite DB, navigate to the 'web' directory: + +```bash +(venv) $ cd $PGADMIN4_SRC/web +``` + +Create a migration file with the following command: + +```bash +(venv) $ FLASK_APP=pgAdmin4.py flask db revision +``` + +This will create a file in: $PGADMIN4_SRC/web/migrations/versions/ . +Add any changes to the 'upgrade' function. +Increment the SCHEMA_VERSION in $PGADMIN4_SRC/web/pgadmin/model/__init__.py file. + +There is no need to increment the SETTINGS_SCHEMA_VERSION. + +# Support + +See https://www.pgadmin.org/support/ for support options. + +# Security Issues + +If you would like to report a security issue with pgAdmin, please email +**security (at) pgadmin (dot) org**. + +Note that this address should only be used for reporting security issues +that you believe you've found in the design or code of pgAdmin, pgAgent, +and the pgAdmin website. It should not be used to ask security questions. + +# Project info + +A GitHub project for pgAdmin 4 can be found at the address below: + +https://github.com/pgadmin-org/pgadmin4 + +Please submit any changes as Pull Requests against the *master* branch of the +*pgadmin-org/pgadmin4* repository. + +If you wish to discuss pgAdmin 4, or contribute to the project, please use the +pgAdmin Hackers mailing list: + +pgadmin-hackers@postgresql.org diff --git a/apps/pgadmin4/data.yml b/apps/pgadmin4/data.yml new file mode 100644 index 00000000..2e6ad56c --- /dev/null +++ b/apps/pgadmin4/data.yml @@ -0,0 +1,20 @@ +name: PGAdmin4 +tags: + - 工具 +title: PostgreSQL 的开源管理和开发平台 +type: 工具 +description: PostgreSQL 的开源管理和开发平台 +additionalProperties: + key: pgadmin4 + name: PGAdmin4 + tags: + - Tool + shortDescZh: PostgreSQL 的开源管理和开发平台 + shortDescEn: Open Source administration and development platform for PostgreSQL + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://www.pgadmin.org + github: https://github.com/pgadmin-org/pgadmin4 + document: https://www.pgadmin.org/docs diff --git a/apps/pgadmin4/latest/.env.sample b/apps/pgadmin4/latest/.env.sample new file mode 100644 index 00000000..c073bbff --- /dev/null +++ b/apps/pgadmin4/latest/.env.sample @@ -0,0 +1,4 @@ +CONTAINER_NAME="pgadmin4" +PANEL_APP_PORT_HTTP="40084" +PGADMIN_EMAIL="admin@example.com" +PGADMIN_PASSWORD="pgadmin4_pwd" diff --git a/apps/pgadmin4/latest/data.yml b/apps/pgadmin4/latest/data.yml new file mode 100644 index 00000000..ef76cd61 --- /dev/null +++ b/apps/pgadmin4/latest/data.yml @@ -0,0 +1,26 @@ +additionalProperties: + formFields: + - default: 40084 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: admin@example.com + edit: true + envKey: PGADMIN_EMAIL + labelEn: Admin Email + labelZh: 管理员邮箱 + required: true + type: text + - default: pgadmin4 + edit: true + envKey: PGADMIN_PASSWORD + labelEn: Admin Password + labelZh: 管理员密码 + random: false + required: false + rule: paramComplexity + type: password diff --git a/apps/pgadmin4/latest/docker-compose.yml b/apps/pgadmin4/latest/docker-compose.yml new file mode 100644 index 00000000..7d9eaf17 --- /dev/null +++ b/apps/pgadmin4/latest/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3' +services: + pgadmin4: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + volumes: + - pgadmin4-data:/var/lib/pgadmin + ports: + - "${PANEL_APP_PORT_HTTP}:80" + environment: + - PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL} + - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD} + - PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION=True + - PGADMIN_CONFIG_CONSOLE_LOG_LEVEL=10 + image: dpage/pgadmin4:latest + labels: + createdBy: "Apps" + +volumes: + pgadmin4-data: + +networks: + 1panel-network: + external: true diff --git a/apps/pgadmin4/logo.png b/apps/pgadmin4/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..87cc2d3aba356f1621001a0dca1df756f2d6a214 GIT binary patch literal 10661 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 literal 0 HcmV?d00001