Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcca55a200 | ||
|
|
d655d0437d | ||
|
|
8dc79e73bd | ||
|
|
39359dd2f1 | ||
|
|
64c48ad237 | ||
|
|
ee0cfef31a | ||
|
|
5a22876176 | ||
|
|
ca01116700 | ||
|
|
c93000a6e2 | ||
|
|
058da752a1 | ||
|
|
4b477aed5d | ||
|
|
f7bc826262 | ||
|
|
5a701b7c61 | ||
|
|
78db1e3c36 | ||
|
|
1184752540 | ||
|
|
7c6e83c6fe | ||
|
|
0d926d4c7f | ||
|
|
595a0dfc55 | ||
|
|
466e969776 | ||
|
|
878c14dec0 | ||
|
|
4490f6f838 | ||
|
|
4746fbd346 | ||
|
|
5d619fd455 | ||
|
|
c5cbb33a06 | ||
|
|
a9ae7ca099 | ||
|
|
d21e1eb17e | ||
|
|
bb570a50ae | ||
|
|
36949aef99 | ||
|
|
557f33c4f9 | ||
|
|
eef295f9d8 | ||
|
|
b8377be1b5 | ||
|
|
789f169135 | ||
|
|
64446790d2 | ||
|
|
be4db5ce04 | ||
|
|
c90f831493 | ||
|
|
251bf05692 | ||
|
|
3e713cf58b | ||
|
|
78c098c9ea | ||
|
|
6bf2733628 | ||
|
|
a1608900ed | ||
|
|
745a91393c | ||
|
|
f4ea95da12 | ||
|
|
22f2ac0507 | ||
|
|
15ea450abe | ||
|
|
923168833c | ||
|
|
e385aec7f7 | ||
|
|
c42e00a090 | ||
|
|
e20e862c22 | ||
|
|
a5b5ede8fd | ||
|
|
07fa09f3c7 | ||
|
|
7e3a932890 | ||
|
|
3b9eef3bb7 | ||
|
|
90630e386b | ||
|
|
c1a7984e1f | ||
|
|
aa7720f226 | ||
|
|
8e58bcc4c0 | ||
|
|
caad254fca | ||
|
|
c649fcca94 | ||
|
|
f04fecb6c7 | ||
|
|
c69315bb43 | ||
|
|
4bddb5c36c | ||
|
|
9a793a30b3 | ||
|
|
f6275688e7 | ||
|
|
10077f13c4 | ||
|
|
1afcc5c835 | ||
|
|
149e093c88 | ||
|
|
99d1c99963 | ||
|
|
b5af4ead0d | ||
|
|
9b85e0a4cd | ||
|
|
0be4fb937f | ||
|
|
05eb956aab | ||
|
|
36cb8e8428 | ||
|
|
28b1f68750 | ||
|
|
0b58bfe6bf | ||
|
|
7dfcc73e95 | ||
|
|
cbb89b09b1 | ||
|
|
7d0ba9448b | ||
|
|
05b595d32d | ||
|
|
396a22b6be | ||
|
|
7be7d3a024 | ||
|
|
8ba7cea2f1 | ||
|
|
e3aa616edd | ||
|
|
dc8832192d | ||
|
|
72794f9524 | ||
|
|
b337b64eb1 | ||
|
|
67ef438730 | ||
|
|
29053098fc | ||
|
|
b9a3178b43 | ||
|
|
7d068130a4 | ||
|
|
cb070fc365 | ||
|
|
396f6c9d73 | ||
|
|
8b7eeca545 | ||
|
|
702bc8c8ce | ||
|
|
cba3dc9457 | ||
|
|
4baaff4566 | ||
|
|
bdcf1f986f | ||
|
|
7609038a16 | ||
|
|
619680e71f | ||
|
|
fec63c6cf3 | ||
|
|
3e031ad334 | ||
|
|
75cbf9165e | ||
|
|
b6924a84d6 | ||
|
|
96f3ac8a53 | ||
|
|
dd4639d602 | ||
|
|
bfa859e9ce | ||
|
|
b1eba4fc4c | ||
|
|
4b183f7988 | ||
|
|
fb3b2a4635 | ||
|
|
db3d0c6e21 | ||
|
|
cedfd12f6a | ||
|
|
c9013a39b8 | ||
|
|
e04f5a0938 | ||
|
|
48dd32f0e4 | ||
|
|
87c1023c4f | ||
|
|
7ab096d87f | ||
|
|
736879567f | ||
|
|
e2b27da2ef | ||
|
|
4baae7512b | ||
|
|
6949b41fb9 | ||
|
|
4fd1e16bb4 | ||
|
|
c0c9034326 | ||
|
|
6c7f5d1a6b | ||
|
|
c9920063dd | ||
|
|
40b916dc2e | ||
|
|
16e8df8f78 | ||
|
|
b9f9ad8027 | ||
|
|
30107e38f3 | ||
|
|
8ea3346a9d | ||
|
|
c067289012 | ||
|
|
cad4c6b8af | ||
|
|
2ec460bf8f | ||
|
|
acf5eb7a26 | ||
|
|
0431cf7fc1 | ||
|
|
259a534a71 | ||
|
|
2a22cf077c | ||
|
|
1f2f405057 | ||
|
|
5483f70d4b | ||
|
|
af1c70f192 | ||
|
|
d8e00e6586 | ||
|
|
eb1c36bf5b | ||
|
|
377bf554b6 | ||
|
|
1d27cb9251 | ||
|
|
5c57fd0170 | ||
|
|
d6f01b552a | ||
|
|
4fbfcdfee9 | ||
|
|
cba42ef277 | ||
|
|
4fc49390ed | ||
|
|
a73f58160f | ||
|
|
14f617681f | ||
|
|
52829d6f31 | ||
|
|
b2864add54 | ||
|
|
1219dcb1d8 | ||
|
|
39401469fd | ||
|
|
8a6a6624ae | ||
|
|
7aec8bd9d7 | ||
|
|
a5a2a7c52f | ||
|
|
2836285ba2 | ||
|
|
b9686fcb00 | ||
|
|
edb74a0839 | ||
|
|
1ccdbf27e2 | ||
|
|
5fbf0b9fe5 | ||
|
|
8428df97ca | ||
|
|
978979c39f | ||
|
|
0e0d0c7c2e | ||
|
|
f4b910bffc | ||
|
|
e20e75aeba | ||
|
|
46a9d4a69d | ||
|
|
35cbe968f4 | ||
|
|
23eaa47fea | ||
|
|
861c66d180 | ||
|
|
1d7d6561f6 | ||
|
|
6d1e918c78 | ||
|
|
1e7517dc98 | ||
|
|
60265b306f | ||
|
|
f12d6336cf | ||
|
|
05938fa6e1 | ||
|
|
cc9297327b | ||
|
|
3ac789f615 | ||
|
|
4c2ae44e4c | ||
|
|
32fb3f3c1f | ||
|
|
625508e32a | ||
|
|
39a0f46159 | ||
|
|
62baa0dccb | ||
|
|
1f17051bec | ||
|
|
ad9a67d6d1 | ||
|
|
0ccfa7900c | ||
|
|
d98f411ea9 | ||
|
|
c19fc3628c | ||
|
|
20132f8daa | ||
|
|
7e2add8db1 | ||
|
|
d6ecc531e0 | ||
|
|
ed941b5b95 | ||
|
|
41e4f3eed9 | ||
|
|
bd3eeb7111 | ||
|
|
f1e7782ca2 | ||
|
|
4ede084b8f | ||
|
|
a6faa77e5b | ||
|
|
e2c5d9a916 | ||
|
|
26f79bafc6 | ||
|
|
47a0009d32 | ||
|
|
e33468e661 | ||
|
|
e24bd7c0e8 | ||
|
|
569bf4d5a2 | ||
|
|
f65d856d13 | ||
|
|
1daf4b08e5 | ||
|
|
80df33c179 | ||
|
|
1fd9353d4d | ||
|
|
62921600bd | ||
|
|
686f52f636 | ||
|
|
947630e0f0 | ||
|
|
64d5457e2b | ||
|
|
ec19fc2b01 | ||
|
|
993e1eb1b6 | ||
|
|
1131e0f742 | ||
|
|
d92a836647 | ||
|
|
288ba1d1f9 | ||
|
|
9587d2bb3b | ||
|
|
c2a54f3524 | ||
|
|
097080ba97 |
No files matched your search
@@ -23,6 +23,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Upgrade yarn
|
||||
run: |
|
||||
yarn set version berry
|
||||
|
||||
- name: Install Node modules
|
||||
run: |
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# Secrets:
|
||||
# EDB_REPO_USERNAME - Username for accessing EDB Repos 1.0
|
||||
# EDB_REPO_PASSWORD - Password for accessing EDB Repos 1.0
|
||||
# EDB_SBP_URL - URL to the EDB StackBuilder Plus catalog
|
||||
|
||||
name: Run Python tests on EPAS
|
||||
|
||||
@@ -30,30 +31,55 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, windows-latest]
|
||||
pgver: [11, 12, 13, 14, 15]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup the EDB APT repo
|
||||
- name: Setup the EDB APT repo on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
sudo su -c 'echo "deb [arch=amd64] https://apt.enterprisedb.com/$(lsb_release -cs)-edb/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/edb-$(lsb_release -cs).list'
|
||||
sudo su -c 'echo "machine apt.enterprisedb.com login ${{ secrets.EDB_REPO_USERNAME }} password ${{ secrets.EDB_REPO_PASSWORD }}" > /etc/apt/auth.conf.d/edb.conf'
|
||||
sudo wget -q -O - https://apt.enterprisedb.com/edb-deb.gpg.key | sudo apt-key add -
|
||||
|
||||
- name: Install platform dependencies
|
||||
- name: Install platform dependencies on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libpq-dev libffi-dev libssl-dev libkrb5-dev zlib1g-dev edb-as${{ matrix.pgver }}-server edb-as${{ matrix.pgver }}-server-pldebugger edb-as${{ matrix.pgver }}-pgagent
|
||||
|
||||
- name: Create the tablespace directory
|
||||
- name: Install platform dependencies on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
FOR /f "delims=" %%F IN ('python tools\get_sb_package.py "${{ secrets.EDB_SBP_URL }}" "edb_as${{ matrix.pgver }}_dbserver" "windows-x64"') DO SET INSTALLER_EXE=%%F
|
||||
ECHO Running %INSTALLER_EXE%...
|
||||
%INSTALLER_EXE% --prefix C:\EPAS\${{ matrix.pgver }} --datadir C:\EPAS\${{ matrix.pgver }}\data --serverport 58${{ matrix.pgver }} --superpassword enterprisedb --create_samples no --install_runtimes 0 --mode unattended --unattendedmodeui none --disable-components stackbuilderplus${{ matrix.pgver < 15 && ',pgadmin4' || '' }}
|
||||
|
||||
choco install -y mitkerberos
|
||||
|
||||
REM Ignore error 3010 (reboot required)
|
||||
IF %ERRORLEVEL% EQU 3010 cmd /c "exit /b 0"
|
||||
shell: cmd
|
||||
|
||||
- name: Create the tablespace directory on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
sudo mkdir -p /var/lib/edb-as/tablespaces/${{ matrix.pgver }}
|
||||
sudo chown enterprisedb:enterprisedb /var/lib/edb-as/tablespaces/${{ matrix.pgver }}
|
||||
|
||||
- name: Start PostgreSQL
|
||||
- name: Create the tablespace directory on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
mkdir "C:\EPAS\${{ matrix.pgver }}\tablespaces"
|
||||
icacls "C:\EPAS\${{ matrix.pgver }}\tablespaces" /grant "NETWORK SERVICE":(OI)(CI)F /T
|
||||
shell: cmd
|
||||
|
||||
- name: Start PostgreSQL on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
# Note: we use a custom port for PostgreSQL as the runner may already have a version of PostgreSQL installed
|
||||
sudo su -c "echo local all all trust > /etc/edb-as/${{ matrix.pgver }}/main/pg_hba.conf"
|
||||
@@ -69,10 +95,23 @@ jobs:
|
||||
|
||||
psql -U enterprisedb -d postgres -p 58${{ matrix.pgver }} -c 'CREATE EXTENSION IF NOT EXISTS pgagent;'
|
||||
|
||||
- name: Install Python dependencies
|
||||
- name: Install Python dependencies on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: make install-python-testing
|
||||
|
||||
- name: Create the test configuration
|
||||
- name: Install Python dependencies on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
SET LIB=C:\EPAS\${{ matrix.pgver }}\lib;%LIB%
|
||||
SET INCLUDE=C:\EPAS\${{ matrix.pgver }}\include;%INCLUDE%
|
||||
python -m venv venv
|
||||
call venv\Scripts\activate.bat
|
||||
python -m pip install --upgrade pip
|
||||
pip install wheel sphinx sphinxcontrib-youtube -r web\regression\requirements.txt
|
||||
shell: cmd
|
||||
|
||||
- name: Create the test configuration on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
cat <<EOF > web/config_local.py
|
||||
from config import *
|
||||
@@ -143,21 +182,104 @@ jobs:
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Run the tests
|
||||
- name: Create the test configuration on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
FOR /f "delims=" %%D IN ('python -c "import os; print(os.getcwd().replace('\\', '\\\\'))"') DO SET WORKING_DIR=%%D
|
||||
|
||||
> web\config_local.py (
|
||||
@echo.from config import *
|
||||
@echo.
|
||||
@echo.# Debug mode
|
||||
@echo.DEBUG = True
|
||||
@echo.
|
||||
@echo.# App mode
|
||||
@echo.SERVER_MODE = False
|
||||
@echo.
|
||||
@echo.# Log
|
||||
@echo.CONSOLE_LOG_LEVEL = DEBUG
|
||||
@echo.FILE_LOG_LEVEL = DEBUG
|
||||
@echo.
|
||||
@echo.DEFAULT_SERVER = '127.0.0.1'
|
||||
@echo.
|
||||
@echo.UPGRADE_CHECK_ENABLED = False
|
||||
@echo.
|
||||
@echo.LOG_FILE = "%WORKING_DIR%\\var\\pgadmin4.log"
|
||||
@echo.SESSION_DB_PATH = "%WORKING_DIR%\\var\\sessions"
|
||||
@echo.STORAGE_DIR = "%WORKING_DIR%\\var\\storage"
|
||||
@echo.SQLITE_PATH = "%WORKING_DIR%\\var\\pgadmin4.db"
|
||||
@echo.TEST_SQLITE_PATH = "%WORKING_DIR%\\var\\test_pgadmin4.db"
|
||||
@echo.AZURE_CREDENTIAL_CACHE_DIR = "%WORKING_DIR%\\var\\azurecredentialcache"
|
||||
)
|
||||
|
||||
> web\regression\test_config.json (
|
||||
@echo.{
|
||||
@echo. "pgAdmin4_login_credentials": {
|
||||
@echo. "new_password": "NEWPASSWORD",
|
||||
@echo. "login_password": "PASSWORD",
|
||||
@echo. "login_username": "USER@EXAMPLE.COM"
|
||||
@echo. },
|
||||
@echo. "pgAdmin4_test_user_credentials": {
|
||||
@echo. "new_password": "NEWPASSWORD",
|
||||
@echo. "login_password": "PASSWORD",
|
||||
@echo. "login_username": "USER2@EXAMPLE.COM"
|
||||
@echo. },
|
||||
@echo. "pgAdmin4_test_non_admin_credentials": {
|
||||
@echo. "new_password": "NEWPASSWORD",
|
||||
@echo. "login_password": "PASSWORD",
|
||||
@echo. "login_username": "USER@EXAMPLE.COM"
|
||||
@echo. },
|
||||
@echo. "server_group": 1,
|
||||
@echo. "server_credentials": [
|
||||
@echo. {
|
||||
@echo. "name": "EPAS ${{ matrix.pgver }}",
|
||||
@echo. "comment": "EPAS ${{ matrix.pgver }} Server",
|
||||
@echo. "db_username": "enterprisedb",
|
||||
@echo. "host": "127.0.0.1",
|
||||
@echo. "db_password": "enterprisedb",
|
||||
@echo. "db_port": 58${{ matrix.pgver }},
|
||||
@echo. "maintenance_db": "postgres",
|
||||
@echo. "sslmode": "prefer",
|
||||
@echo. "tablespace_path": "C:\\EPAS\\${{ matrix.pgver }}\\tablespaces",
|
||||
@echo. "enabled": true,
|
||||
@echo. "default_binary_paths": {
|
||||
@echo. "pg": "",
|
||||
@echo. "ppas": "C:\\EPAS\\${{ matrix.pgver }}\\bin"
|
||||
@echo. }
|
||||
@echo. }
|
||||
@echo. ],
|
||||
@echo. "server_update_data": [
|
||||
@echo. {
|
||||
@echo. "comment": "This is test update comment"
|
||||
@echo. }
|
||||
@echo. ]
|
||||
@echo.}
|
||||
)
|
||||
shell: cmd
|
||||
|
||||
- name: Run the tests on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-22.04' }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
make check-python
|
||||
|
||||
- name: Run the tests on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
call venv\Scripts\activate.bat
|
||||
python web\regression\runtests.py --exclude feature_tests
|
||||
shell: cmd
|
||||
|
||||
- name: Archive server log
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: server-log-pg${{ matrix.pgver }}
|
||||
name: server-log-epas${{ matrix.pgver }}
|
||||
path: var/pgadmin4.log
|
||||
|
||||
- name: Archive regression log
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: regression-log-pg${{ matrix.pgver }}
|
||||
name: regression-log-epas${{ matrix.pgver }}
|
||||
path: web/regression/regression.log
|
||||
@@ -1,5 +1,8 @@
|
||||
name: Run Python tests on PostgreSQL
|
||||
|
||||
# Note: we use a custom port (and installation directory on Windows) for
|
||||
# PostgreSQL as the runners may already have a version installed.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
@@ -17,7 +20,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
pgver: [11, 12, 13, 14, 15]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -25,7 +28,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup the PGDG APT repo
|
||||
- name: Setup the PGDG APT repo on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
@@ -42,6 +45,25 @@ jobs:
|
||||
run: |
|
||||
brew install postgresql@${{ matrix.pgver }}
|
||||
|
||||
- name: Uninstall PostgreSQL if already present
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
if exist "C:\Program Files\PostgreSQL\{{ matrix.pgver }}\uninstall-postgresql.exe" (
|
||||
"C:\Program Files\PostgreSQL\{{ matrix.pgver }}\uninstall-postgresql.exe" --mode unattended
|
||||
)
|
||||
reg delete "HKLM\SOFTWARE\PostgreSQL" /f
|
||||
shell: cmd
|
||||
|
||||
- name: Install platform dependencies on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
choco install -y postgresql${{ matrix.pgver }} --params "/Password:postgres /Port:59${{ matrix.pgver }}" --ia "--prefix C:\PostgreSQL\${{ matrix.pgver }} --datadir C:\PostgreSQL\${{ matrix.pgver }}\data --install_runtimes 0 --disable-components pgAdmin,stackbuilder --enable-components server,commandlinetools"
|
||||
choco install -y mitkerberos
|
||||
|
||||
REM Ignore error 3010 (reboot required)
|
||||
IF %ERRORLEVEL% EQU 3010 cmd /c "exit /b 0"
|
||||
shell: cmd
|
||||
|
||||
- name: Create the tablespace directory on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
@@ -53,10 +75,16 @@ jobs:
|
||||
run: |
|
||||
mkdir -p /usr/local/var/tablespaces/${{ matrix.pgver }}
|
||||
|
||||
- name: Create the tablespace directory on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
mkdir "C:\PostgreSQL\${{ matrix.pgver }}\tablespaces"
|
||||
icacls "C:\PostgreSQL\${{ matrix.pgver }}\tablespaces" /grant "NETWORK SERVICE":(OI)(CI)F /T
|
||||
shell: cmd
|
||||
|
||||
- name: Start PostgreSQL on Linux
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
# Note: we use a custom port for PostgreSQL as the runner may already have a version of PostgreSQL installed
|
||||
sudo su -c "echo local all all trust > /etc/postgresql/${{ matrix.pgver }}/main/pg_hba.conf"
|
||||
sudo sed -i "s/port = 543[0-9]/port = 59${{ matrix.pgver }}/g" /etc/postgresql/${{ matrix.pgver }}/main/postgresql.conf
|
||||
sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = '\$libdir\/plugin_debugger'/g" /etc/postgresql/${{ matrix.pgver }}/main/postgresql.conf
|
||||
@@ -73,7 +101,6 @@ jobs:
|
||||
- name: Start PostgreSQL on macOS
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
run: |
|
||||
# Note: we use a custom port for PostgreSQL as the runner may already have a version of PostgreSQL installed
|
||||
echo local all all trust > /usr/local/var/postgresql@${{ matrix.pgver }}/pg_hba.conf
|
||||
sed -i '' "s/#port = 543[0-9]/port = 59${{ matrix.pgver }}/g" /usr/local/var/postgresql@${{ matrix.pgver }}/postgresql.conf
|
||||
brew services restart postgresql@${{ matrix.pgver }}
|
||||
@@ -85,10 +112,23 @@ jobs:
|
||||
|
||||
psql postgres -p 59${{ matrix.pgver }} -c 'CREATE ROLE postgres SUPERUSER LOGIN;'
|
||||
|
||||
- name: Install Python dependencies
|
||||
- name: Install Python dependencies on Linux and macOS
|
||||
if: ${{ matrix.os == 'macos-latest' || matrix.os == 'ubuntu-latest' }}
|
||||
run: make install-python-testing
|
||||
|
||||
- name: Create the test configuration
|
||||
- name: Install Python dependencies on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
SET LIB=C:\PostgreSQL\${{ matrix.pgver }}\lib;%LIB%
|
||||
SET INCLUDE=C:\PostgreSQL\${{ matrix.pgver }}\include;%INCLUDE%
|
||||
python -m venv venv
|
||||
call venv\Scripts\activate.bat
|
||||
python -m pip install --upgrade pip
|
||||
pip install wheel sphinx sphinxcontrib-youtube -r web\regression\requirements.txt
|
||||
shell: cmd
|
||||
|
||||
- name: Create the test configuration on Linux and macOS
|
||||
if: ${{ matrix.os == 'macos-latest' || matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
cat <<EOF > web/config_local.py
|
||||
from config import *
|
||||
@@ -138,12 +178,12 @@ jobs:
|
||||
"name": "PostgreSQL ${{ matrix.pgver }}",
|
||||
"comment": "PostgreSQL ${{ matrix.pgver }} Server",
|
||||
"db_username": "postgres",
|
||||
"host": "${{ matrix.os == 'macos-latest' && '/tmp' || '/var/run/postgresql' }}",
|
||||
"host": "${{ matrix.os == 'macos-latest' && '/tmp' || matrix.os == 'ubuntu-latest' && '/var/run/postgresql' || '127.0.0.1' }}",
|
||||
"db_password": "postgres",
|
||||
"db_port": 59${{ matrix.pgver }},
|
||||
"maintenance_db": "postgres",
|
||||
"sslmode": "prefer",
|
||||
"tablespace_path": "${{ matrix.os == 'macos-latest' && format('/usr/local/var/tablespaces/{0}', matrix.pgver) || format('/var/lib/postgresql/tablespaces/{0}', matrix.pgver) }}",
|
||||
"tablespace_path": "${{ matrix.os == 'macos-latest' && format('/usr/local/var/tablespaces/{0}', matrix.pgver) || format('/var/lib/postgresql/tablespaces/{0}', matrix.pgver) }}",
|
||||
"enabled": true,
|
||||
"default_binary_paths": {
|
||||
"pg": "${{ matrix.os == 'macos-latest' && format('/usr/local/opt/postgresql@{0}/bin', matrix.pgver) || format('/usr/lib/postgresql/{0}/bin', matrix.pgver) }}",
|
||||
@@ -159,11 +199,94 @@ jobs:
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Run the tests
|
||||
- name: Create the test configuration on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
FOR /f "delims=" %%D IN ('python -c "import os; print(os.getcwd().replace('\\', '\\\\'))"') DO SET WORKING_DIR=%%D
|
||||
|
||||
> web\config_local.py (
|
||||
@echo.from config import *
|
||||
@echo.
|
||||
@echo.# Debug mode
|
||||
@echo.DEBUG = True
|
||||
@echo.
|
||||
@echo.# App mode
|
||||
@echo.SERVER_MODE = False
|
||||
@echo.
|
||||
@echo.# Log
|
||||
@echo.CONSOLE_LOG_LEVEL = DEBUG
|
||||
@echo.FILE_LOG_LEVEL = DEBUG
|
||||
@echo.
|
||||
@echo.DEFAULT_SERVER = '127.0.0.1'
|
||||
@echo.
|
||||
@echo.UPGRADE_CHECK_ENABLED = False
|
||||
@echo.
|
||||
@echo.LOG_FILE = "%WORKING_DIR%\\var\\pgadmin4.log"
|
||||
@echo.SESSION_DB_PATH = "%WORKING_DIR%\\var\\sessions"
|
||||
@echo.STORAGE_DIR = "%WORKING_DIR%\\var\\storage"
|
||||
@echo.SQLITE_PATH = "%WORKING_DIR%\\var\\pgadmin4.db"
|
||||
@echo.TEST_SQLITE_PATH = "%WORKING_DIR%\\var\\test_pgadmin4.db"
|
||||
@echo.AZURE_CREDENTIAL_CACHE_DIR = "%WORKING_DIR%\\var\\azurecredentialcache"
|
||||
)
|
||||
|
||||
> web\regression\test_config.json (
|
||||
@echo.{
|
||||
@echo. "pgAdmin4_login_credentials": {
|
||||
@echo. "new_password": "NEWPASSWORD",
|
||||
@echo. "login_password": "PASSWORD",
|
||||
@echo. "login_username": "USER@EXAMPLE.COM"
|
||||
@echo. },
|
||||
@echo. "pgAdmin4_test_user_credentials": {
|
||||
@echo. "new_password": "NEWPASSWORD",
|
||||
@echo. "login_password": "PASSWORD",
|
||||
@echo. "login_username": "USER2@EXAMPLE.COM"
|
||||
@echo. },
|
||||
@echo. "pgAdmin4_test_non_admin_credentials": {
|
||||
@echo. "new_password": "NEWPASSWORD",
|
||||
@echo. "login_password": "PASSWORD",
|
||||
@echo. "login_username": "USER@EXAMPLE.COM"
|
||||
@echo. },
|
||||
@echo. "server_group": 1,
|
||||
@echo. "server_credentials": [
|
||||
@echo. {
|
||||
@echo. "name": "PostgreSQL ${{ matrix.pgver }}",
|
||||
@echo. "comment": "PostgreSQL ${{ matrix.pgver }} Server",
|
||||
@echo. "db_username": "postgres",
|
||||
@echo. "host": "127.0.0.1",
|
||||
@echo. "db_password": "postgres",
|
||||
@echo. "db_port": 59${{ matrix.pgver }},
|
||||
@echo. "maintenance_db": "postgres",
|
||||
@echo. "sslmode": "prefer",
|
||||
@echo. "tablespace_path": "C:\\PostgreSQL\\${{ matrix.pgver }}\\tablespaces",
|
||||
@echo. "enabled": true,
|
||||
@echo. "default_binary_paths": {
|
||||
@echo. "pg": "C:\\PostgreSQL\\${{ matrix.pgver }}\\bin",
|
||||
@echo. "ppas": ""
|
||||
@echo. }
|
||||
@echo. }
|
||||
@echo. ],
|
||||
@echo. "server_update_data": [
|
||||
@echo. {
|
||||
@echo. "comment": "This is test update comment"
|
||||
@echo. }
|
||||
@echo. ]
|
||||
@echo.}
|
||||
)
|
||||
shell: cmd
|
||||
|
||||
- name: Run the tests on Linux and macOS
|
||||
if: ${{ matrix.os == 'macos-latest' || matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
make check-python
|
||||
|
||||
- name: Run the tests on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
call venv\Scripts\activate.bat
|
||||
python web\regression\runtests.py --exclude feature_tests
|
||||
shell: cmd
|
||||
|
||||
- name: Archive server log
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -177,3 +300,5 @@ jobs:
|
||||
with:
|
||||
name: regression-log-${{ matrix.os }}-pg${{ matrix.pgver }}
|
||||
path: web/regression/regression.log
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
.idea
|
||||
.vscode
|
||||
.yarn
|
||||
.yarnrc.yml
|
||||
/*.diff
|
||||
/*.patch
|
||||
/dist
|
||||
|
||||
@@ -13,7 +13,7 @@ Name Version
|
||||
Python 3.6+ PSF https://www.python.org/
|
||||
nw 0.50.2 MIT git://github.com/nwjs/npm-installer.git
|
||||
asynckit 0.4.0 MIT git+https://github.com/alexindigo/asynckit.git
|
||||
axios 1.3.4 MIT https://github.com/axios/axios.git
|
||||
axios 1.4.0 MIT https://github.com/axios/axios.git
|
||||
bootstrap 4.6.2 MIT git+https://github.com/twbs/bootstrap.git
|
||||
combined-stream 1.0.8 MIT git://github.com/felixge/node-combined-stream.git
|
||||
delayed-stream 1.0.0 MIT git://github.com/felixge/node-delayed-stream.git
|
||||
@@ -30,7 +30,7 @@ Python Dependencies
|
||||
|
||||
Name Version Licence URL
|
||||
---- ------- ------- ---
|
||||
Flask 2.2.3 BSD-3-Clause https://palletsprojects.com/p/flask
|
||||
Flask 2.2.4 BSD-3-Clause https://palletsprojects.com/p/flask
|
||||
Flask-Gravatar 0.5.0 BSD https://github.com/zzzsochi/Flask-Gravatar/
|
||||
Flask-Login 0.6.2 MIT https://github.com/maxcountryman/flask-login
|
||||
Flask-Mail 0.9.1 BSD https://github.com/rduplain/flask-mail
|
||||
@@ -39,20 +39,20 @@ Flask-SQLAlchemy 3.0.3
|
||||
Flask-WTF 1.1.1 BSD-3-Clause https://github.com/wtforms/flask-wtf/
|
||||
Flask-Compress 1.13 MIT https://github.com/colour-science/flask-compress
|
||||
Flask-Paranoid 0.3.0 UNKNOWN https://github.com/miguelgrinberg/flask-paranoid
|
||||
flask-babel 3.0.1 BSD-3-Clause Unknown
|
||||
flask-babel 3.1.0 BSD-3-Clause https://github.com/python-babel/flask-babel
|
||||
Flask-Security-Too 5.1.2 MIT https://github.com/Flask-Middleware/flask-security
|
||||
Flask-SocketIO 5.3.3 Unknown https://github.com/miguelgrinberg/flask-socketio
|
||||
WTForms 3.0.1 BSD-3-Clause https://wtforms.readthedocs.io/
|
||||
passlib 1.7.4 BSD https://passlib.readthedocs.io
|
||||
pytz 2022.7.1 MIT http://pythonhosted.org/pytz
|
||||
pytz 2023.3 MIT http://pythonhosted.org/pytz
|
||||
speaklater3 1.4 UNKNOWN https://github.com/ThomasWaldmann/speaklater
|
||||
sqlparse 0.4.3 BSD-3-Clause https://github.com/andialbrecht/sqlparse
|
||||
psutil 5.9.4 BSD-3-Clause https://github.com/giampaolo/psutil
|
||||
sqlparse 0.4.4 Unknown Unknown
|
||||
psutil 5.9.5 BSD-3-Clause https://github.com/giampaolo/psutil
|
||||
psycopg 3.1.8 GNU Lesser General Public License v3 (LGPLv3) https://psycopg.org/psycopg3/
|
||||
python-dateutil 2.8.2 Dual License https://github.com/dateutil/dateutil
|
||||
SQLAlchemy 2.0.7 MIT https://www.sqlalchemy.org
|
||||
SQLAlchemy 2.0.11 MIT https://www.sqlalchemy.org
|
||||
bcrypt 4.0.1 Apache License, Version 2.0 https://github.com/pyca/bcrypt/
|
||||
cryptography 40.0.1 (Apache-2.0 OR BSD-3-Clause) AND PSF-2.0 https://github.com/pyca/cryptography
|
||||
cryptography 40.0.2 (Apache-2.0 OR BSD-3-Clause) AND PSF-2.0 https://github.com/pyca/cryptography
|
||||
sshtunnel 0.4.0 MIT https://github.com/pahaz/sshtunnel
|
||||
ldap3 2.9.1 LGPL v3 https://github.com/cannatag/ldap3
|
||||
gssapi 1.8.2 LICENSE.txt https://github.com/pythongssapi/python-gssapi
|
||||
@@ -61,106 +61,107 @@ httpagentparser 1.9.5
|
||||
user-agents 2.2.0 MIT https://github.com/selwin/python-user-agents
|
||||
pywinpty 2.0.* Unknown Unknown
|
||||
Authlib 1.2.0 BSD 3-Clause License https://authlib.org/
|
||||
requests 2.28.2 Apache 2.0 https://requests.readthedocs.io
|
||||
pyotp 2.8.0 MIT License https://github.com/pyotp/pyotp
|
||||
qrcode 7.4.2 BSD https://github.com/lincolnloop/python-qrcode
|
||||
Pillow 9.4.0 HPND https://python-pillow.org
|
||||
boto3 1.26.101 Apache License 2.0 https://github.com/boto/boto3
|
||||
botocore 1.29.101 Apache License 2.0 https://github.com/boto/botocore
|
||||
Pillow 9.5.0 HPND https://python-pillow.org
|
||||
boto3 1.26.121 Apache License 2.0 https://github.com/boto/boto3
|
||||
botocore 1.29.121 Apache License 2.0 https://github.com/boto/botocore
|
||||
urllib3 1.26.15 MIT https://urllib3.readthedocs.io/
|
||||
azure-mgmt-rdbms 10.1.0 MIT License https://github.com/Azure/azure-sdk-for-python
|
||||
azure-mgmt-resource 23.0.0 MIT License https://github.com/Azure/azure-sdk-for-python
|
||||
azure-mgmt-resource 23.0.1 MIT License https://github.com/Azure/azure-sdk-for-python
|
||||
azure-mgmt-subscription 3.1.1 MIT License https://github.com/Azure/azure-sdk-for-python
|
||||
azure-identity 1.12.0 MIT License https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/identity/azure-identity
|
||||
google-api-python-client 2.83.0 Apache 2.0 https://github.com/googleapis/google-api-python-client/
|
||||
azure-identity 1.13.0 MIT License https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/identity/azure-identity
|
||||
google-api-python-client 2.86.0 Apache 2.0 https://github.com/googleapis/google-api-python-client/
|
||||
google-auth-oauthlib 1.0.0 Apache 2.0 https://github.com/GoogleCloudPlatform/google-auth-library-python-oauthlib
|
||||
Werkzeug 2.2.3 BSD-3-Clause https://palletsprojects.com/p/werkzeug/
|
||||
keyring 23.13.1 Unknown https://github.com/jaraco/keyring
|
||||
|
||||
NOTE: This report was generated using Python 3.11. Full information may not be
|
||||
shown for Python modules that are not required with this version.
|
||||
|
||||
44 dependencies listed.
|
||||
45 dependencies listed.
|
||||
|
||||
Javascript Dependencies
|
||||
=======================
|
||||
|
||||
Name Version Licence URL
|
||||
---- ------- ------- ---
|
||||
@ampproject/remapping 2.2.0 Apache-2.0 git+https://github.com/ampproject/remapping.git
|
||||
@ampproject/remapping 2.2.1 Apache-2.0 git+https://github.com/ampproject/remapping.git
|
||||
anti-trojan-source 1.4.1 Apache-2.0 https://github.com/lirantal/anti-trojan-source.git
|
||||
eve 0.5.4 Apache-2.0 git@github.com:adobe-webplatform/eve.git
|
||||
jmespath 0.16.0 Apache-2.0 git://github.com/jmespath/jmespath.js
|
||||
jsoneditor 9.9.2 Apache-2.0 https://github.com/josdejong/jsoneditor.git
|
||||
jsoneditor 9.10.2 Apache-2.0 https://github.com/josdejong/jsoneditor.git
|
||||
paths-js 0.4.11 Apache-2.0 https://github.com/andreaferretti/paths-js.git
|
||||
rc-dock 3.2.16 Apache-2.0 https://github.com/ticlo/rc-dock.git
|
||||
rc-dock 3.2.18 Apache-2.0 https://github.com/ticlo/rc-dock.git
|
||||
rc-new-window 0.1.13 Apache-2.0 https://github.com/ticlo/rc-new-window.git
|
||||
snapsvg 0.5.1 Apache-2.0 git@github.com:adobe-webplatform/Snap.svg.git
|
||||
spdx-correct 3.1.1 Apache-2.0 https://github.com/jslicense/spdx-correct.js.git
|
||||
spdx-correct 3.2.0 Apache-2.0 https://github.com/jslicense/spdx-correct.js.git
|
||||
validate-npm-package-license 3.0.4 Apache-2.0 https://github.com/kemitchell/validate-npm-package-license.js.git
|
||||
@babel/code-frame 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/compat-data 7.20.10 MIT https://github.com/babel/babel.git
|
||||
@babel/core 7.20.12 MIT https://github.com/babel/babel.git
|
||||
@babel/generator 7.20.7 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-annotate-as-pure 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-compilation-targets 7.20.7 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-create-class-features-plugin 7.20.12 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-environment-visitor 7.18.9 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-function-name 7.19.0 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-hoist-variables 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-member-expression-to-functions 7.20.7 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-module-imports 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-module-transforms 7.20.11 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-optimise-call-expression 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-plugin-utils 7.20.2 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-replace-supers 7.20.7 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-simple-access 7.20.2 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-skip-transparent-expression-wrappers 7.20.0 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-split-export-declaration 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-string-parser 7.19.4 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-validator-identifier 7.19.1 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-validator-option 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/helpers 7.20.13 MIT https://github.com/babel/babel.git
|
||||
@babel/highlight 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/parser 7.20.13 MIT https://github.com/babel/babel.git
|
||||
@babel/code-frame 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/compat-data 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/core 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/generator 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-annotate-as-pure 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-compilation-targets 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-create-class-features-plugin 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-environment-visitor 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-function-name 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-hoist-variables 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-member-expression-to-functions 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-module-imports 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-module-transforms 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-optimise-call-expression 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-plugin-utils 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-replace-supers 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-simple-access 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-skip-transparent-expression-wrappers 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-split-export-declaration 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-string-parser 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-validator-identifier 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helper-validator-option 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/helpers 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/highlight 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/parser 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-proposal-class-properties 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-syntax-jsx 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-display-name 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-jsx 7.20.13 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-jsx-development 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-pure-annotations 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/preset-react 7.18.6 MIT https://github.com/babel/babel.git
|
||||
@babel/runtime 7.20.13 MIT https://github.com/babel/babel.git
|
||||
@babel/template 7.20.7 MIT https://github.com/babel/babel.git
|
||||
@babel/traverse 7.20.13 MIT https://github.com/babel/babel.git
|
||||
@babel/types 7.20.7 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-syntax-jsx 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-display-name 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-jsx 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-jsx-development 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/plugin-transform-react-pure-annotations 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/preset-react 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/runtime 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/template 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/traverse 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@babel/types 7.22.5 MIT https://github.com/babel/babel.git
|
||||
@date-io/core 1.3.13 MIT https://github.com/dmtrKovalenko/date-io
|
||||
@date-io/date-fns 1.3.13 MIT https://github.com/dmtrKovalenko/date-io
|
||||
@emotion/babel-plugin 11.10.6 MIT https://github.com/emotion-js/emotion/tree/main/packages/babel-plugin
|
||||
@emotion/cache 11.10.5 MIT https://github.com/emotion-js/emotion/tree/main/packages/cache
|
||||
@emotion/babel-plugin 11.11.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/babel-plugin
|
||||
@emotion/cache 11.11.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/cache
|
||||
@emotion/hash 0.8.0 MIT https://github.com/emotion-js/emotion/tree/master/packages/hash
|
||||
@emotion/hash 0.9.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/hash
|
||||
@emotion/is-prop-valid 1.2.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/is-prop-valid
|
||||
@emotion/memoize 0.8.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/memoize
|
||||
@emotion/react 11.10.6 MIT https://github.com/emotion-js/emotion/tree/main/packages/react
|
||||
@emotion/serialize 1.1.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/serialize
|
||||
@emotion/sheet 1.2.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/sheet
|
||||
@emotion/hash 0.9.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/hash
|
||||
@emotion/is-prop-valid 1.2.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/is-prop-valid
|
||||
@emotion/memoize 0.8.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/memoize
|
||||
@emotion/react 11.11.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/react
|
||||
@emotion/serialize 1.1.2 MIT https://github.com/emotion-js/emotion/tree/main/packages/serialize
|
||||
@emotion/sheet 1.2.2 MIT https://github.com/emotion-js/emotion/tree/main/packages/sheet
|
||||
@emotion/stylis 0.8.5 MIT https://github.com/emotion-js/emotion/tree/master/packages/stylis
|
||||
@emotion/unitless 0.8.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/unitless
|
||||
@emotion/unitless 0.8.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/unitless
|
||||
@emotion/unitless 0.7.5 MIT https://github.com/emotion-js/emotion/tree/master/packages/unitless
|
||||
@emotion/use-insertion-effect-with-fallbacks 1.0.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/use-insertion-effect-with-fallbacks
|
||||
@emotion/utils 1.2.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/utils
|
||||
@emotion/weak-memoize 0.3.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/weak-memoize
|
||||
@floating-ui/core 1.2.5 MIT https://github.com/floating-ui/floating-ui.git
|
||||
@floating-ui/dom 1.2.5 MIT https://github.com/floating-ui/floating-ui.git
|
||||
@emotion/use-insertion-effect-with-fallbacks 1.0.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/use-insertion-effect-with-fallbacks
|
||||
@emotion/utils 1.2.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/utils
|
||||
@emotion/weak-memoize 0.3.1 MIT https://github.com/emotion-js/emotion/tree/main/packages/weak-memoize
|
||||
@floating-ui/core 1.3.1 MIT https://github.com/floating-ui/floating-ui.git
|
||||
@floating-ui/dom 1.4.2 MIT https://github.com/floating-ui/floating-ui.git
|
||||
@istanbuljs/schema 0.1.3 MIT git+https://github.com/istanbuljs/schema.git
|
||||
@jridgewell/gen-mapping 0.3.2 MIT https://github.com/jridgewell/gen-mapping
|
||||
@jridgewell/gen-mapping 0.1.1 MIT https://github.com/jridgewell/gen-mapping
|
||||
@jridgewell/gen-mapping 0.3.3 MIT https://github.com/jridgewell/gen-mapping
|
||||
@jridgewell/resolve-uri 3.1.0 MIT https://github.com/jridgewell/resolve-uri
|
||||
@jridgewell/set-array 1.1.2 MIT https://github.com/jridgewell/set-array
|
||||
@jridgewell/sourcemap-codec 1.4.15 MIT git+https://github.com/jridgewell/sourcemap-codec.git
|
||||
@jridgewell/sourcemap-codec 1.4.14 MIT git+https://github.com/jridgewell/sourcemap-codec.git
|
||||
@jridgewell/trace-mapping 0.3.17 MIT git+https://github.com/jridgewell/trace-mapping.git
|
||||
@material-ui/core 4.11.0 MIT https://github.com/mui-org/material-ui.git
|
||||
@jridgewell/trace-mapping 0.3.18 MIT git+https://github.com/jridgewell/trace-mapping.git
|
||||
@material-ui/core 4.12.4 MIT https://github.com/mui-org/material-ui.git
|
||||
@material-ui/icons 4.11.3 MIT https://github.com/mui-org/material-ui.git
|
||||
@material-ui/lab 4.0.0-alpha.58 MIT https://github.com/mui-org/material-ui.git
|
||||
@material-ui/lab 4.0.0-alpha.61 MIT https://github.com/mui-org/material-ui.git
|
||||
@material-ui/pickers 3.3.10 MIT https://github.com/mui-org/material-ui-pickers
|
||||
@material-ui/styles 4.11.5 MIT https://github.com/mui-org/material-ui.git
|
||||
@material-ui/system 4.12.2 MIT https://github.com/mui-org/material-ui.git
|
||||
@@ -175,25 +176,28 @@ validate-npm-package-license 3.0.4
|
||||
@projectstorm/react-diagrams-core 6.7.4 MIT https://github.com/projectstorm/react-diagrams.git
|
||||
@projectstorm/react-diagrams-defaults 6.7.4 MIT https://github.com/projectstorm/react-diagrams.git
|
||||
@projectstorm/react-diagrams-routing 6.7.4 MIT https://github.com/projectstorm/react-diagrams.git
|
||||
@rc-component/portal 1.1.1 MIT https://github.com/react-component/portal.git
|
||||
@rc-component/trigger 1.13.6 MIT https://github.com/react-component/trigger.git
|
||||
@react-dnd/asap 5.0.2 MIT https://github.com/react-dnd/react-dnd
|
||||
@react-dnd/invariant 4.0.2 MIT https://github.com/react-dnd/react-dnd
|
||||
@react-dnd/shallowequal 4.0.2 MIT https://github.com/react-dnd/react-dnd
|
||||
@remix-run/router 1.3.0 MIT https://github.com/remix-run/react-router
|
||||
@remix-run/router 1.6.3 MIT https://github.com/remix-run/react-router
|
||||
@simonwep/pickr 1.8.2 MIT https://github.com/Simonwep/pickr.git
|
||||
@sindresorhus/is 0.7.0 MIT https://github.com/sindresorhus/is.git
|
||||
@socket.io/component-emitter 3.1.0 MIT https://github.com/socketio/emitter.git
|
||||
@szhsin/react-menu 2.3.4 MIT https://github.com/szhsin/react-menu.git
|
||||
@types/classnames 2.3.1 MIT Unknown
|
||||
@types/minimist 1.2.2 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/node 18.11.18 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/node 20.3.1 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/normalize-package-data 2.4.1 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/parse-json 4.0.0 MIT https://www.github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/prop-types 15.7.5 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react 18.0.27 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react 16.14.35 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react-dom 16.9.17 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react-transition-group 4.4.5 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/scheduler 0.16.2 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react 18.2.13 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react 16.14.43 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react 17.0.62 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react-dom 17.0.20 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/react-transition-group 4.4.6 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/scheduler 0.16.3 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
@types/styled-jsx 2.2.9 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
ajv 8.12.0 MIT https://github.com/ajv-validator/ajv.git
|
||||
ajv 6.12.6 MIT https://github.com/ajv-validator/ajv.git
|
||||
@@ -207,7 +211,7 @@ async 2.6.4
|
||||
attr-accept 2.2.2 MIT https://github.com/react-dropzone/attr-accept.git
|
||||
axios 0.21.4 MIT https://github.com/axios/axios.git
|
||||
babel-plugin-macros 3.1.0 MIT https://github.com/kentcdodds/babel-plugin-macros
|
||||
babel-plugin-styled-components 2.0.7 MIT https://github.com/styled-components/babel-plugin-styled-components.git
|
||||
babel-plugin-styled-components 2.1.3 MIT https://github.com/styled-components/babel-plugin-styled-components.git
|
||||
babel-plugin-syntax-jsx 6.18.0 MIT https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-jsx
|
||||
babelify 10.0.0 MIT https://github.com/babel/babelify.git
|
||||
balanced-match 1.0.2 MIT git://github.com/juliangruber/balanced-match.git
|
||||
@@ -219,7 +223,7 @@ brace 0.11.1
|
||||
brace-expansion 1.1.11 MIT git://github.com/juliangruber/brace-expansion.git
|
||||
braces 3.0.2 MIT https://github.com/micromatch/braces.git
|
||||
browserfs 1.4.3 MIT https://github.com/jvilk/BrowserFS.git
|
||||
browserslist 4.21.4 MIT https://github.com/browserslist/browserslist.git
|
||||
browserslist 4.21.9 MIT https://github.com/browserslist/browserslist.git
|
||||
callsites 3.1.0 MIT https://github.com/sindresorhus/callsites.git
|
||||
camelcase 6.3.0 MIT https://github.com/sindresorhus/camelcase.git
|
||||
camelcase-keys 7.0.2 MIT https://github.com/sindresorhus/camelcase-keys.git
|
||||
@@ -227,11 +231,11 @@ camelize 1.0.1
|
||||
caniuse-api 3.0.0 MIT https://github.com/nyalab/caniuse-api.git
|
||||
chalk 2.4.2 MIT https://github.com/chalk/chalk.git
|
||||
chart.js 3.9.1 MIT https://github.com/chartjs/Chart.js.git
|
||||
chartjs-plugin-zoom 1.3.0 MIT https://github.com/chartjs/chartjs-plugin-zoom.git
|
||||
chartjs-plugin-zoom 2.0.1 MIT https://github.com/chartjs/chartjs-plugin-zoom.git
|
||||
classnames 2.3.2 MIT https://github.com/JedWatson/classnames.git
|
||||
closest 0.0.1 MIT https://github.com/ForbesLindesay/closest.git
|
||||
clsx 1.2.1 MIT https://github.com/lukeed/clsx.git
|
||||
codemirror 5.65.11 MIT https://github.com/codemirror/CodeMirror.git
|
||||
codemirror 5.65.13 MIT https://github.com/codemirror/CodeMirror.git
|
||||
color-convert 1.9.3 MIT https://github.com/Qix-/color-convert.git
|
||||
color-name 1.1.3 MIT git@github.com:dfcreative/color-name.git
|
||||
colord 2.9.3 MIT https://github.com/omgovich/colord.git
|
||||
@@ -239,21 +243,21 @@ commander 7.2.0
|
||||
concat-map 0.0.1 MIT git://github.com/substack/node-concat-map.git
|
||||
convert-source-map 1.9.0 MIT git://github.com/thlorenz/convert-source-map.git
|
||||
convert-units 2.3.4 MIT git://github.com/ben-ng/convert-units.git
|
||||
core-js 3.27.2 MIT https://github.com/zloirock/core-js.git
|
||||
core-js 3.31.0 MIT https://github.com/zloirock/core-js.git
|
||||
cosmiconfig 7.1.0 MIT git+https://github.com/davidtheclark/cosmiconfig.git
|
||||
css-line-break 2.1.0 MIT git+ssh://git@github.com/niklasvh/css-line-break.git
|
||||
css-to-react-native 3.1.0 MIT git+https://github.com/styled-components/css-to-react-native.git
|
||||
css-to-react-native 3.2.0 MIT git+https://github.com/styled-components/css-to-react-native.git
|
||||
css-tree 1.1.3 MIT https://github.com/csstree/csstree.git
|
||||
css-vendor 2.0.8 MIT git@github.com:cssinjs/css-vendor.git
|
||||
cssesc 3.0.0 MIT https://github.com/mathiasbynens/cssesc.git
|
||||
cssnano 5.1.14 MIT https://github.com/cssnano/cssnano.git
|
||||
cssnano-preset-default 5.2.13 MIT https://github.com/cssnano/cssnano.git
|
||||
cssnano 5.1.15 MIT https://github.com/cssnano/cssnano.git
|
||||
cssnano-preset-default 5.2.14 MIT https://github.com/cssnano/cssnano.git
|
||||
cssnano-utils 3.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
csso 4.2.0 MIT https://github.com/css/csso.git
|
||||
csstype 2.6.21 MIT https://github.com/frenic/csstype
|
||||
csstype 3.1.1 MIT https://github.com/frenic/csstype
|
||||
csstype 3.1.2 MIT https://github.com/frenic/csstype
|
||||
dagre 0.8.5 MIT https://github.com/dagrejs/dagre.git
|
||||
date-fns 2.29.3 MIT https://github.com/date-fns/date-fns
|
||||
date-fns 2.30.0 MIT https://github.com/date-fns/date-fns
|
||||
debug 4.3.4 MIT git://github.com/debug-js/debug.git
|
||||
decamelize 5.0.1 MIT https://github.com/sindresorhus/decamelize.git
|
||||
decamelize 1.2.0 MIT https://github.com/sindresorhus/decamelize.git
|
||||
@@ -265,8 +269,8 @@ dnd-core 16.0.1
|
||||
dom-align 1.12.4 MIT git@github.com:yiminghe/dom-align.git
|
||||
dom-helpers 5.2.1 MIT git+https://github.com/react-bootstrap/dom-helpers.git
|
||||
dom-serializer 1.4.1 MIT git://github.com/cheeriojs/dom-renderer.git
|
||||
engine.io-client 6.2.3 MIT https://github.com/socketio/engine.io-client.git
|
||||
engine.io-parser 5.0.6 MIT git@github.com:socketio/engine.io-parser.git
|
||||
engine.io-client 6.5.0 MIT https://github.com/socketio/engine.io-client.git
|
||||
engine.io-parser 5.1.0 MIT git@github.com:socketio/engine.io-parser.git
|
||||
error-ex 1.3.2 MIT https://github.com/qix-/node-error-ex.git
|
||||
escalade 3.1.1 MIT https://github.com/lukeed/escalade.git
|
||||
escape-string-regexp 1.0.5 MIT https://github.com/sindresorhus/escape-string-regexp.git
|
||||
@@ -299,9 +303,9 @@ import-fresh 3.3.0
|
||||
indent-string 5.0.0 MIT https://github.com/sindresorhus/indent-string.git
|
||||
insert-if 1.2.0 MIT git+https://github.com/chipto/insert-if.git
|
||||
ip-address 7.1.0 MIT git://github.com/beaugunderson/ip-address.git
|
||||
is-any-array 2.0.0 MIT https://github.com/cheminfo-js/is-any-array.git
|
||||
is-any-array 2.0.1 MIT https://github.com/cheminfo-js/is-any-array.git
|
||||
is-arrayish 0.2.1 MIT https://github.com/qix-/node-is-arrayish.git
|
||||
is-core-module 2.11.0 MIT git+https://github.com/inspect-js/is-core-module.git
|
||||
is-core-module 2.12.1 MIT git+https://github.com/inspect-js/is-core-module.git
|
||||
is-extglob 2.1.1 MIT https://github.com/jonschlinkert/is-extglob.git
|
||||
is-glob 4.0.3 MIT https://github.com/micromatch/is-glob.git
|
||||
is-in-browser 1.1.3 MIT git+https://github.com/tuxsudo/is-in-browser.git
|
||||
@@ -310,7 +314,7 @@ is-plain-obj 1.1.0
|
||||
is-relative 1.0.0 MIT https://github.com/jonschlinkert/is-relative.git
|
||||
is-unc-path 1.0.0 MIT https://github.com/jonschlinkert/is-unc-path.git
|
||||
javascript-natural-sort 0.7.1 MIT https://github.com/Bill4Time/javascript-natural-sort.git
|
||||
jquery 3.6.3 MIT https://github.com/jquery/jquery.git
|
||||
jquery 3.7.0 MIT https://github.com/jquery/jquery.git
|
||||
jquery-contextmenu 2.9.2 MIT git://github.com/swisnl/jQuery-contextMenu.git
|
||||
js-tokens 4.0.0 MIT https://github.com/lydell/js-tokens.git
|
||||
jsbn 1.1.0 MIT https://github.com/andyperlitch/jsbn.git
|
||||
@@ -321,17 +325,17 @@ json-schema-traverse 1.0.0
|
||||
json-schema-traverse 0.4.1 MIT git+https://github.com/epoberezkin/json-schema-traverse.git
|
||||
json-source-map 0.6.1 MIT git+https://github.com/epoberezkin/json-source-map.git
|
||||
json5 2.2.3 MIT git+https://github.com/json5/json5.git
|
||||
jss 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-camel-case 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-default-unit 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-global 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-nested 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-props-sort 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-rule-value-function 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-vendor-prefixer 10.9.2 MIT https://github.com/cssinjs/jss.git
|
||||
jss 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-camel-case 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-default-unit 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-global 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-nested 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-props-sort 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-rule-value-function 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
jss-plugin-vendor-prefixer 10.10.0 MIT https://github.com/cssinjs/jss.git
|
||||
karma-coverage 2.2.0 MIT git://github.com/karma-runner/karma-coverage.git
|
||||
kind-of 6.0.3 MIT https://github.com/jonschlinkert/kind-of.git
|
||||
lilconfig 2.0.6 MIT https://github.com/antonk52/lilconfig
|
||||
lilconfig 2.1.0 MIT https://github.com/antonk52/lilconfig
|
||||
lines-and-columns 1.2.4 MIT https://github.com/eventualbuddha/lines-and-columns.git
|
||||
locate-path 6.0.0 MIT https://github.com/sindresorhus/locate-path.git
|
||||
lodash 4.17.21 MIT https://github.com/lodash/lodash.git
|
||||
@@ -374,11 +378,11 @@ ml-array-rescale 1.3.7
|
||||
ml-matrix 6.10.4 MIT https://github.com/mljs/matrix.git
|
||||
mobius1-selectr 2.4.13 MIT git+https://github.com/Mobius1/Selectr.git
|
||||
moment 2.29.4 MIT https://github.com/moment/moment.git
|
||||
moment-timezone 0.5.40 MIT https://github.com/moment/moment-timezone.git
|
||||
moment-timezone 0.5.43 MIT https://github.com/moment/moment-timezone.git
|
||||
ms 2.1.2 MIT https://github.com/zeit/ms.git
|
||||
nanoid 3.3.4 MIT https://github.com/ai/nanoid.git
|
||||
nanopop 2.2.0 MIT https://github.com/Simonwep/nanopop.git
|
||||
node-releases 2.0.8 MIT https://github.com/chicoxyzzy/node-releases.git
|
||||
nanoid 3.3.6 MIT https://github.com/ai/nanoid.git
|
||||
nanopop 2.3.0 MIT https://github.com/Simonwep/nanopop.git
|
||||
node-releases 2.0.12 MIT https://github.com/chicoxyzzy/node-releases.git
|
||||
normalize-url 6.1.0 MIT https://github.com/sindresorhus/normalize-url.git
|
||||
notificar 1.0.1 MIT git+https://github.com/neeksandhu/notificar.git
|
||||
notistack 1.0.10 MIT git+https://github.com/iamhosseindhv/notistack.git
|
||||
@@ -399,16 +403,16 @@ picomatch 2.3.1
|
||||
picomodal 3.0.0 MIT https://github.com/Nycto/PicoModal.git
|
||||
popper.js 1.16.1-lts MIT git+https://github.com/FezVrasta/popper.js.git
|
||||
popper.js 1.16.1 MIT git+https://github.com/FezVrasta/popper.js.git
|
||||
postcss 8.4.21 MIT https://github.com/postcss/postcss.git
|
||||
postcss 8.4.24 MIT https://github.com/postcss/postcss.git
|
||||
postcss-calc 8.2.4 MIT https://github.com/postcss/postcss-calc.git
|
||||
postcss-colormin 5.3.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-colormin 5.3.1 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-convert-values 5.1.3 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-discard-comments 5.1.2 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-discard-duplicates 5.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-discard-empty 5.1.1 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-discard-overridden 5.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-merge-longhand 5.1.7 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-merge-rules 5.1.3 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-merge-rules 5.1.4 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-minify-font-values 5.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-minify-gradients 5.1.1 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-minify-params 5.1.4 MIT https://github.com/cssnano/cssnano.git
|
||||
@@ -423,9 +427,9 @@ postcss-normalize-unicode 5.1.1
|
||||
postcss-normalize-url 5.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-normalize-whitespace 5.1.1 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-ordered-values 5.1.3 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-reduce-initial 5.1.1 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-reduce-initial 5.1.2 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-reduce-transforms 5.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-selector-parser 6.0.11 MIT https://github.com/postcss/postcss-selector-parser.git
|
||||
postcss-selector-parser 6.0.13 MIT https://github.com/postcss/postcss-selector-parser.git
|
||||
postcss-svgo 5.1.0 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-unique-selectors 5.1.1 MIT https://github.com/cssnano/cssnano.git
|
||||
postcss-value-parser 4.2.0 MIT https://github.com/TrySound/postcss-value-parser.git
|
||||
@@ -437,14 +441,14 @@ raf 3.4.1
|
||||
rc-align 4.0.15 MIT git@github.com:react-component/align.git
|
||||
rc-dropdown 3.6.2 MIT git@github.com:react-component/dropdown.git
|
||||
rc-dropdown 4.0.1 MIT git@github.com:react-component/dropdown.git
|
||||
rc-menu 9.8.2 MIT git@github.com:react-component/menu.git
|
||||
rc-menu 9.9.2 MIT git@github.com:react-component/menu.git
|
||||
rc-menu 9.6.4 MIT git@github.com:react-component/menu.git
|
||||
rc-motion 2.6.3 MIT git@github.com:react-component/motion.git
|
||||
rc-overflow 1.2.8 MIT git@github.com:react-component/overflow.git
|
||||
rc-resize-observer 1.2.1 MIT git@github.com:react-component/resize-observer.git
|
||||
rc-motion 2.7.3 MIT git@github.com:react-component/motion.git
|
||||
rc-overflow 1.3.1 MIT git@github.com:react-component/overflow.git
|
||||
rc-resize-observer 1.3.1 MIT git@github.com:react-component/resize-observer.git
|
||||
rc-tabs 11.16.1 MIT git@github.com:react-component/tabs.git
|
||||
rc-trigger 5.3.4 MIT https://github.com/react-component/trigger.git
|
||||
rc-util 5.27.1 MIT git@github.com:react-component/util.git
|
||||
rc-util 5.34.0 MIT git@github.com:react-component/util.git
|
||||
re-resizable 6.9.6 MIT https://github.com/bokuweb/react-resizable-box.git
|
||||
react 17.0.2 MIT https://github.com/facebook/react.git
|
||||
react-aspen 1.2.0 MIT https://github.com/neeksandhu/react-aspen.git
|
||||
@@ -455,25 +459,25 @@ react-dnd-html5-backend 16.0.1
|
||||
react-dom 17.0.2 MIT https://github.com/facebook/react.git
|
||||
react-draggable 4.4.5 MIT https://github.com/react-grid-layout/react-draggable.git
|
||||
react-dropzone 14.2.3 MIT https://github.com/react-dropzone/react-dropzone.git
|
||||
react-is 16.13.1 MIT https://github.com/facebook/react.git
|
||||
react-is 17.0.2 MIT https://github.com/facebook/react.git
|
||||
react-resize-detector 8.0.3 MIT git+https://github.com/maslianok/react-resize-detector.git
|
||||
react-is 16.13.1 MIT https://github.com/facebook/react.git
|
||||
react-resize-detector 9.1.0 MIT git+https://github.com/maslianok/react-resize-detector.git
|
||||
react-rnd 10.4.1 MIT https://github.com/bokuweb/react-rnd.git
|
||||
react-router 6.7.0 MIT https://github.com/remix-run/react-router
|
||||
react-router-dom 6.7.0 MIT https://github.com/remix-run/react-router
|
||||
react-select 5.7.2 MIT https://github.com/JedWatson/react-select/tree/master/packages/react-select
|
||||
react-router 6.13.0 MIT https://github.com/remix-run/react-router
|
||||
react-router-dom 6.13.0 MIT https://github.com/remix-run/react-router
|
||||
react-select 5.7.3 MIT https://github.com/JedWatson/react-select/tree/master/packages/react-select
|
||||
react-table 7.8.0 MIT https://github.com/tannerlinsley/react-table
|
||||
react-transition-state 1.1.5 MIT https://github.com/szhsin/react-transition-state.git
|
||||
react-virtualized-auto-sizer 1.0.7 MIT https://github.com/bvaughn/react-virtualized-auto-sizer.git
|
||||
react-window 1.8.8 MIT https://github.com/bvaughn/react-window.git
|
||||
react-virtualized-auto-sizer 1.0.20 MIT https://github.com/bvaughn/react-virtualized-auto-sizer.git
|
||||
react-window 1.8.9 MIT https://github.com/bvaughn/react-window.git
|
||||
read-pkg 6.0.0 MIT https://github.com/sindresorhus/read-pkg.git
|
||||
read-pkg-up 8.0.0 MIT https://github.com/sindresorhus/read-pkg-up.git
|
||||
redent 4.0.0 MIT https://github.com/sindresorhus/redent.git
|
||||
redux 4.2.0 MIT https://github.com/reduxjs/redux.git
|
||||
redux 4.2.1 MIT https://github.com/reduxjs/redux.git
|
||||
regenerator-runtime 0.13.11 MIT https://github.com/facebook/regenerator/tree/main/packages/runtime
|
||||
require-from-string 2.0.2 MIT https://github.com/floatdrop/require-from-string.git
|
||||
resize-observer-polyfill 1.5.1 MIT https://github.com/que-etc/resize-observer-polyfill.git
|
||||
resolve 1.22.1 MIT git://github.com/browserify/resolve.git
|
||||
resolve 1.22.2 MIT git://github.com/browserify/resolve.git
|
||||
resolve-from 4.0.0 MIT https://github.com/sindresorhus/resolve-from.git
|
||||
reusify 1.0.4 MIT git+https://github.com/mcollina/reusify.git
|
||||
rifm 0.7.0 MIT https://github.com/istarkov/rifm.git
|
||||
@@ -482,15 +486,15 @@ scheduler 0.20.2
|
||||
shallowequal 1.1.0 MIT https://github.com/dashed/shallowequal.git
|
||||
slash 4.0.0 MIT https://github.com/sindresorhus/slash.git
|
||||
snapsvg-cjs 0.0.6 MIT git+https://github.com/geelen/Snap.svg-cjs.git
|
||||
socket.io-client 4.5.4 MIT https://github.com/socketio/socket.io-client.git
|
||||
socket.io-parser 4.2.2 MIT https://github.com/socketio/socket.io-parser.git
|
||||
socket.io-client 4.7.0 MIT https://github.com/socketio/socket.io-client.git
|
||||
socket.io-parser 4.2.4 MIT https://github.com/socketio/socket.io-parser.git
|
||||
spdx-expression-parse 3.0.1 MIT https://github.com/jslicense/spdx-expression-parse.js.git
|
||||
split.js 1.6.5 MIT https://github.com/nathancahill/split
|
||||
stable 0.1.8 MIT https://github.com/Two-Screen/stable.git
|
||||
strip-indent 4.0.0 MIT https://github.com/sindresorhus/strip-indent.git
|
||||
styled-components 5.3.6 MIT git+https://github.com/styled-components/styled-components.git
|
||||
styled-components 5.3.11 MIT git+https://github.com/styled-components/styled-components.git
|
||||
stylehacks 5.1.1 MIT https://github.com/cssnano/cssnano.git
|
||||
stylis 4.1.3 MIT https://github.com/thysultan/stylis.js
|
||||
stylis 4.2.0 MIT https://github.com/thysultan/stylis.js
|
||||
supports-color 5.5.0 MIT https://github.com/chalk/supports-color.git
|
||||
supports-color 7.2.0 MIT https://github.com/chalk/supports-color.git
|
||||
supports-preserve-symlinks-flag 1.0.0 MIT git+https://github.com/inspect-js/node-supports-preserve-symlinks-flag.git
|
||||
@@ -500,9 +504,9 @@ text-segmentation 1.0.3
|
||||
tiny-warning 1.0.3 MIT https://github.com/alexreardon/tiny-warning.git
|
||||
to-fast-properties 2.0.0 MIT https://github.com/sindresorhus/to-fast-properties.git
|
||||
to-regex-range 5.0.1 MIT https://github.com/micromatch/to-regex-range.git
|
||||
trim-newlines 4.0.2 MIT https://github.com/sindresorhus/trim-newlines.git
|
||||
trim-newlines 4.1.1 MIT https://github.com/sindresorhus/trim-newlines.git
|
||||
unc-path-regex 0.1.2 MIT https://github.com/regexhq/unc-path-regex.git
|
||||
update-browserslist-db 1.0.10 MIT https://github.com/browserslist/update-db.git
|
||||
update-browserslist-db 1.0.11 MIT https://github.com/browserslist/update-db.git
|
||||
uplot 1.6.24 MIT git+https://github.com/leeoniya/uPlot.git
|
||||
uplot-react 1.1.4 MIT https://github.com/skalinichev/uplot-wrappers.git
|
||||
use-isomorphic-layout-effect 1.1.2 MIT git+https://github.com/Andarist/use-isomorphic-layout-effect.git
|
||||
@@ -510,7 +514,7 @@ util-deprecate 1.0.2
|
||||
utrie 1.0.2 MIT git+ssh://git@github.com/niklasvh/utrie.git
|
||||
valid-filename 2.0.1 MIT https://github.com/sindresorhus/valid-filename.git
|
||||
wkx 0.5.0 MIT http://github.com/cschwarz/wkx.git
|
||||
ws 8.2.3 MIT https://github.com/websockets/ws.git
|
||||
ws 8.11.0 MIT https://github.com/websockets/ws.git
|
||||
xmlhttprequest-ssl 2.0.0 MIT git://github.com/mjwwit/node-XMLHttpRequest.git
|
||||
xterm 4.19.0 MIT https://github.com/xtermjs/xterm.js
|
||||
xterm-addon-fit 0.5.0 MIT https://github.com/xtermjs/xterm.js
|
||||
@@ -524,25 +528,25 @@ react-leaflet 3.2.5
|
||||
@trysound/sax 0.2.0 ISC git://github.com/svg/sax.git
|
||||
boolbase 1.0.0 ISC https://github.com/fb55/boolbase
|
||||
css-color-keywords 1.0.0 ISC https://github.com/sonicdoe/css-color-keywords.git
|
||||
css-declaration-sorter 6.3.1 ISC https://github.com/Siilwyn/css-declaration-sorter.git
|
||||
electron-to-chromium 1.4.284 ISC https://github.com/kilian/electron-to-chromium/
|
||||
css-declaration-sorter 6.4.0 ISC https://github.com/Siilwyn/css-declaration-sorter.git
|
||||
electron-to-chromium 1.4.437 ISC https://github.com/kilian/electron-to-chromium/
|
||||
fastq 1.15.0 ISC git+https://github.com/mcollina/fastq.git
|
||||
glob-parent 5.1.2 ISC https://github.com/gulpjs/glob-parent.git
|
||||
hosted-git-info 4.1.0 ISC git+https://github.com/npm/hosted-git-info.git
|
||||
jsonrepair 2.2.1 ISC https://github.com/josdejong/jsonrepair.git
|
||||
jsonrepair 3.2.0 ISC https://github.com/josdejong/jsonrepair.git
|
||||
lru-cache 6.0.0 ISC git://github.com/isaacs/node-lru-cache.git
|
||||
lru-cache 5.1.1 ISC git://github.com/isaacs/node-lru-cache.git
|
||||
minimatch 3.1.2 ISC git://github.com/isaacs/minimatch.git
|
||||
picocolors 1.0.0 ISC https://github.com/alexeyraspopov/picocolors.git
|
||||
react-timer-hook 3.0.5 ISC git+https://github.com/amrlabib/react-timer-hook.git
|
||||
semver 7.3.8 ISC https://github.com/npm/node-semver.git
|
||||
react-timer-hook 3.0.6 ISC git+https://github.com/amrlabib/react-timer-hook.git
|
||||
semver 6.3.0 ISC https://github.com/npm/node-semver
|
||||
semver 7.5.2 ISC https://github.com/npm/node-semver.git
|
||||
vanilla-picker 2.12.1 ISC https://github.com/Sphinxxxx/vanilla-picker.git
|
||||
yallist 4.0.0 ISC git+https://github.com/isaacs/yallist.git
|
||||
yallist 3.1.1 ISC git+https://github.com/isaacs/yallist.git
|
||||
yaml 1.10.2 ISC https://github.com/eemeli/yaml.git
|
||||
yargs-parser 20.2.9 ISC https://github.com/yargs/yargs-parser.git
|
||||
ace-builds 1.14.0 BSD-3-Clause https://github.com/ajaxorg/ace-builds.git
|
||||
ace-builds 1.23.0 BSD-3-Clause https://github.com/ajaxorg/ace-builds.git
|
||||
hoist-non-react-statics 3.3.2 BSD-3-Clause git://github.com/mridgway/hoist-non-react-statics.git
|
||||
hyphenate-style-name 1.0.4 BSD-3-Clause git+ssh://git@github.com/rexxars/hyphenate-style-name.git
|
||||
istanbul-lib-coverage 3.2.0 BSD-3-Clause git+ssh://git@github.com/istanbuljs/istanbuljs.git
|
||||
@@ -555,28 +559,28 @@ source-map 0.6.1
|
||||
source-map 0.5.7 BSD-3-Clause http://github.com/mozilla/source-map.git
|
||||
source-map-js 1.0.2 BSD-3-Clause https://github.com/7rulnik/source-map-js.git
|
||||
sprintf-js 1.1.2 BSD-3-Clause https://github.com/alexei/sprintf.js.git
|
||||
caniuse-lite 1.0.30001448 CC-BY-4.0 https://github.com/browserslist/caniuse-lite.git
|
||||
caniuse-lite 1.0.30001506 CC-BY-4.0 https://github.com/browserslist/caniuse-lite.git
|
||||
css-select 4.3.0 BSD-2-Clause git://github.com/fb55/css-select.git
|
||||
css-what 6.1.0 BSD-2-Clause https://github.com/fb55/css-what
|
||||
domelementtype 2.3.0 BSD-2-Clause git://github.com/fb55/domelementtype.git
|
||||
domhandler 4.3.1 BSD-2-Clause git://github.com/fb55/domhandler.git
|
||||
domutils 2.8.0 BSD-2-Clause git://github.com/fb55/domutils.git
|
||||
entities 2.2.0 BSD-2-Clause git://github.com/fb55/entities.git
|
||||
leaflet 1.9.3 BSD-2-Clause git://github.com/Leaflet/Leaflet.git
|
||||
leaflet 1.9.4 BSD-2-Clause git://github.com/Leaflet/Leaflet.git
|
||||
normalize-package-data 3.0.3 BSD-2-Clause git://github.com/npm/normalize-package-data.git
|
||||
nth-check 2.1.1 BSD-2-Clause https://github.com/fb55/nth-check
|
||||
uri-js 4.4.1 BSD-2-Clause http://github.com/garycourt/uri-js
|
||||
FileSaver 0.10.0 UNKNOWN Unknown
|
||||
heap 0.2.5 UNKNOWN git://github.com/qiao/heap.js.git
|
||||
mdn-data 2.0.14 CC0-1.0 https://github.com/mdn/data.git
|
||||
spdx-license-ids 3.0.12 CC0-1.0 https://github.com/jslicense/spdx-license-ids.git
|
||||
spdx-license-ids 3.0.13 CC0-1.0 https://github.com/jslicense/spdx-license-ids.git
|
||||
mousetrap 1.6.5 Apache-2.0 WITH LLVM-exception git://github.com/ccampbell/mousetrap.git
|
||||
pako 1.0.11 (MIT AND Zlib) https://github.com/nodeca/pako.git
|
||||
spdx-exceptions 2.3.0 CC-BY-3.0 https://github.com/kemitchell/spdx-exceptions.json.git
|
||||
tslib 2.4.1 0BSD https://github.com/Microsoft/tslib.git
|
||||
tslib 2.5.3 0BSD https://github.com/Microsoft/tslib.git
|
||||
tslib 2.3.1 0BSD https://github.com/Microsoft/tslib.git
|
||||
type-fest 1.4.0 (MIT OR CC0-1.0) https://github.com/sindresorhus/type-fest.git
|
||||
webcabin-docker 2.2.5 MIT* Unknown
|
||||
|
||||
492 dependencies listed.
|
||||
495 dependencies listed.
|
||||
|
||||
@@ -62,7 +62,7 @@ RUN export CPPFLAGS="-DPNG_ARM_NEON_OPT=0" && \
|
||||
# Next, create the base environment for Python
|
||||
#########################################################################
|
||||
|
||||
FROM alpine:latest as env-builder
|
||||
FROM alpine:latest AS env-builder
|
||||
|
||||
# Install dependencies
|
||||
COPY requirements.txt /
|
||||
@@ -90,7 +90,7 @@ RUN apk add --no-cache \
|
||||
# Now, create a documentation build container for the Sphinx docs
|
||||
#########################################################################
|
||||
|
||||
FROM env-builder as docs-builder
|
||||
FROM env-builder AS docs-builder
|
||||
|
||||
# Install Sphinx
|
||||
RUN /venv/bin/python3 -m pip install --no-cache-dir sphinx
|
||||
@@ -114,14 +114,14 @@ RUN rm -rf /pgadmin4/docs/en_US/_build/html/_static/*.png
|
||||
# Create additional builders to get all of the PostgreSQL utilities
|
||||
#########################################################################
|
||||
|
||||
FROM postgres:10-alpine as pg10-builder
|
||||
FROM postgres:11-alpine as pg11-builder
|
||||
FROM postgres:12-alpine as pg12-builder
|
||||
FROM postgres:13-alpine as pg13-builder
|
||||
FROM postgres:14-alpine as pg14-builder
|
||||
FROM postgres:15-alpine as pg15-builder
|
||||
FROM postgres:10-alpine AS pg10-builder
|
||||
FROM postgres:11-alpine AS pg11-builder
|
||||
FROM postgres:12-alpine AS pg12-builder
|
||||
FROM postgres:13-alpine AS pg13-builder
|
||||
FROM postgres:14-alpine AS pg14-builder
|
||||
FROM postgres:15-alpine AS pg15-builder
|
||||
|
||||
FROM alpine:latest as tool-builder
|
||||
FROM alpine:latest AS tool-builder
|
||||
|
||||
# Copy the PG binaries
|
||||
COPY --from=pg10-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-10/
|
||||
@@ -205,7 +205,7 @@ RUN apk add \
|
||||
chown pgadmin:root /pgadmin4/config_distro.py && \
|
||||
chmod g=u /pgadmin4/config_distro.py && \
|
||||
chmod g=u /etc/passwd && \
|
||||
setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/python3.10 && \
|
||||
setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/python3.11 && \
|
||||
echo "pgadmin ALL = NOPASSWD: /usr/sbin/postfix start" > /etc/sudoers.d/postfix && \
|
||||
echo "pgadminr ALL = NOPASSWD: /usr/sbin/postfix start" >> /etc/sudoers.d/postfix
|
||||
|
||||
|
||||
@@ -217,6 +217,7 @@ REM Main build sequence Ends
|
||||
ECHO Installing javascript dependencies...
|
||||
CD "%BUILDROOT%\web"
|
||||
CALL yarn install || EXIT /B 1
|
||||
CALL npm rebuild || EXIT /B 1
|
||||
|
||||
ECHO Bundling javascript...
|
||||
CALL yarn run bundle || EXIT /B 1
|
||||
@@ -274,15 +275,10 @@ REM Main build sequence Ends
|
||||
REM YARN END
|
||||
|
||||
REM WGET
|
||||
REM FOR /f "tokens=2 delims='" %%i IN ('yarn info nw ^| findstr "latest: "') DO SET "NW_VERSION=%%i"
|
||||
REM :GET_NW
|
||||
REM wget https://dl.nwjs.io/v%NW_VERSION%/nwjs-v%NW_VERSION%-win-x64.zip -O "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip"
|
||||
REM IF %ERRORLEVEL% NEQ 0 GOTO GET_NW
|
||||
|
||||
REM Remove the above commented code once below issue is fixed
|
||||
REM Pining NWjs because of https://github.com/nwjs/nw.js/issues/8039 in 0.74.0
|
||||
SET "NW_VERSION=0.72.0"
|
||||
wget https://dl.nwjs.io/v%NW_VERSION%/nwjs-v%NW_VERSION%-win-x64.zip -O "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip"
|
||||
FOR /f "tokens=2 delims='" %%i IN ('yarn info nw ^| findstr "latest: "') DO SET "NW_VERSION=%%i"
|
||||
:GET_NW
|
||||
wget https://dl.nwjs.io/v%NW_VERSION%/nwjs-v%NW_VERSION%-win-x64.zip -O "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip"
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO GET_NW
|
||||
|
||||
tar -C "%TMPDIR%" -xvf "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip" || EXIT /B 1
|
||||
REM WGET END
|
||||
|
||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 217 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 18 KiB |
@@ -178,7 +178,9 @@ The following example shows both a minimally defined and a fully defined server:
|
||||
"TunnelHost": "192.168.1.253",
|
||||
"TunnelPort": 22,
|
||||
"TunnelUsername": "username",
|
||||
"TunnelAuthentication": 0
|
||||
"TunnelAuthentication": 0,
|
||||
"PasswordExecCommand": "echo 'test'",
|
||||
"PasswordExecExpiration": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ Use the fields in the *Definition* tab to define the index:
|
||||
* Move the *Unique?* switch to the *Yes* position to check for duplicate values
|
||||
in the table when the index is created and when data is added. The default is
|
||||
*No*.
|
||||
* Move the *NULLs not distinct?* switch to the *Yes* position to treat null values as not distinct. The default is
|
||||
*No*. This option is available only on PostgreSQL 15 and above.
|
||||
* Move the *Clustered?* switch to the *Yes* position to instruct the server to
|
||||
cluster the table.
|
||||
* Move the *Concurrent build?* switch to the *Yes* position to build the index
|
||||
|
||||
@@ -26,16 +26,12 @@ When using main browser window, the following keyboard shortcuts are available:
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+d | Delete object |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+m | Delete/Drop multiple objects |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Ctrl+[ | Dialog tab backward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Ctrl+] | Dialog tab forward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+g | Direct debugging |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+u | Drop Cascade multiple objects |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+e | Edit object properties |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+f | File main menu |
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
`Master Password`:index:
|
||||
************************
|
||||
|
||||
.. note:: pgAdmin 4 uses the operating system password store by default to store the saved server passwords in desktop mode from version 7.2 onwards and Master password will not be required.
|
||||
If the operating system password store is not available then pgAdmin 4 will continue to use a master password as per the configuration settings.
|
||||
|
||||
A master password is required to secure and later unlock the saved server
|
||||
passwords. This is applicable only for desktop mode users.
|
||||
passwords. This is applicable for desktop mode and in server mode if authentication source contains OAuth2 or Kerberos or Webserver.
|
||||
|
||||
* You are prompted to enter the master password when you open the window for
|
||||
the first time after starting the application.
|
||||
@@ -56,3 +59,4 @@ passwords. This is applicable only for desktop mode users.
|
||||
|
||||
.. warning:: Resetting the master password will also remove all saved passwords
|
||||
and close all existing established connections.
|
||||
|
||||
@@ -58,12 +58,14 @@ following options (in alphabetical order):
|
||||
| *Create* | Click *Create* to access a context menu that provides context-sensitive selections. |
|
||||
| | Your selection opens a *Create* dialog for creating a new object. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete/Drop* | Click to delete the currently selected object from the server. |
|
||||
| *Delete* | Click to delete the currently selected object from the server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Cascade)* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Force)* | Click to delete the currently selected database with force option. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Disconnect from server* | Click to disconnect from the currently selected server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Drop Cascade* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Properties...* | Click to review or modify the currently selected object's properties. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Refresh* | Click to refresh the currently selected object. |
|
||||
|
||||
@@ -59,6 +59,8 @@ Use the fields on the *Display* panel to specify general display preferences:
|
||||
| *Full* | This will disable resizing, docking/undocking of the panels |
|
||||
+---------------------+-------------------------------------------------------------------+
|
||||
|
||||
* When the *Show empty object collections?* switch is turned off, then all object
|
||||
collections which are empty will be hidden from browser tree.
|
||||
* When the *Show system objects?* switch is set to *True*, the client will
|
||||
display system objects such as system schemas (for example, *pg_temp*) or
|
||||
system columns (for example, *xmin* or *ctid*) in the tree control.
|
||||
@@ -88,6 +90,30 @@ displayed in the *Browser* tree control:
|
||||
catalogs, you can reduce the number of object types displayed to increase
|
||||
speed.
|
||||
|
||||
Use the fields on the *Object Breadcrumbs* panel to change object breadcrumbs
|
||||
related settings:
|
||||
|
||||
.. image:: images/preferences_browser_breadcrumbs.png
|
||||
:alt: Preferences dialog object breadcrumbs section
|
||||
:align: center
|
||||
|
||||
* Use *Enable object breadcrumbs?* to enable or disable object breadcrumbs
|
||||
displayed on on object mouse hover.
|
||||
|
||||
* Use *Show comment with object breadcrumbs?* to enable or disable the
|
||||
comment visibility which comes displayed with object breadcrumbs.
|
||||
|
||||
|
||||
Use the fields on the *Processes* panel to change processes tab
|
||||
related settings:
|
||||
|
||||
.. image:: images/preferences_browser_processes.png
|
||||
:alt: Preferences dialog processes section
|
||||
:align: center
|
||||
|
||||
* Change *Process details/logs retention days* to the number of days,
|
||||
the process info and logs will be automatically cleared.
|
||||
|
||||
Use fields on the *Properties* panel to specify browser properties:
|
||||
|
||||
.. image:: images/preferences_browser_properties.png
|
||||
@@ -440,6 +466,9 @@ preferences for copied data.
|
||||
* Specify the maximum width of the column in pixels when 'Columns sized by' is
|
||||
set to *Column data*. If 'Columns sized by' is set to *Column name* then this
|
||||
setting won't have any effect.
|
||||
* Specify the number of records to fetch in one batch in query tool when
|
||||
query result set is large. Changing this value will override
|
||||
ON_DEMAND_ROW_COUNT setting from config file.
|
||||
* Use the *Result copy field separator* drop-down listbox to select the field
|
||||
separator for copied data.
|
||||
* Use the *Result copy quote character* drop-down listbox to select the quote
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
`Publication Dialog`:index:
|
||||
***************************
|
||||
|
||||
`Logical replication <https://www.postgresql.org/docs/13/logical-replication.html>`_ uses a *publish* and *subscribe* model with one or more *subscribers* subscribing to one or more *publications* on a publisher node.
|
||||
`Logical replication <https://www.postgresql.org/docs/15/logical-replication.html>`_ uses a *publish* and *subscribe* model with one or more *subscribers* subscribing to one or more *publications* on a publisher node.
|
||||
|
||||
Use the *publication* dialog to create a publication. A publication is a set of changes generated from a table or a group of tables, and might also be described as a change set or replication set.
|
||||
Use the *publication* dialog to create a publication. A publication is a set of changes generated from a table or a group of tables or a schema or a group of schemas, and might also be described as a change set or replication set.
|
||||
|
||||
The *publication* dialog organizes the development of a publication through the following dialog tabs: *General* and *Definition*. The *SQL* tab displays the SQL code generated by dialog selections.
|
||||
The *publication* dialog organizes the development of a publication through the following dialog tabs: *General*, *Tables* and *Options*. The *SQL* tab displays the SQL code generated by dialog selections.
|
||||
|
||||
.. image:: images/publication_general.png
|
||||
:alt: Publication dialog general tab
|
||||
@@ -19,20 +19,39 @@ Use the fields in the *General* tab to identify the publication:
|
||||
* Use the *Name* field to add a descriptive name for the publication. The name will be displayed in the *pgAdmin* tree control.
|
||||
* The *Owner* field takes the name of the user automatically as current connected user. You can change the owner after creating publication using alter publication.
|
||||
|
||||
Click the *Definition* tab to continue.
|
||||
Click the *Tables* tab to continue.
|
||||
|
||||
.. image:: images/publication_definition.png
|
||||
Tables tab for PostgreSQL version <= 14
|
||||
|
||||
.. image:: images/publication_tables_14.png
|
||||
:alt: Publication dialog definition tab
|
||||
:align: center
|
||||
|
||||
Use the *Definition* tab to set properties for the publication:
|
||||
Tables tab for PostgreSQL version >= 15
|
||||
|
||||
.. image:: images/publication_tables_15.png
|
||||
:alt: Publication dialog definition tab
|
||||
:align: center
|
||||
|
||||
Use the *Tables* tab to set table properties for the publication:
|
||||
|
||||
* Move the switch next to *All tables?* to *Yes* to replicate all the tables of the database, including tables created in the future.
|
||||
* Move the switch next to *Only table?* to *Yes* to replicate only the listed tables excluding all its descendant tables.
|
||||
* Specify a table or list of tables separated by a comma in *Tables* field to replicate all the listed table.
|
||||
* Specify a table or list of tables separated by a comma in *Tables* field to replicate all the listed table. With PostgreSQL 15 forward, specify a table or list of tables to replicate all the listed tables along with specific columns and/or WHERE clause to filter rows.
|
||||
* With PostgreSQL 15 forward, specify a schema or list of schemas separated by a comma in *Tables In Schema* field to replicate all the listed schemas. This field will be disabled if any columns are selected for tables.
|
||||
|
||||
Click the *Options* tab to continue.
|
||||
|
||||
.. image:: images/publication_options.png
|
||||
:alt: Publication dialog options tab
|
||||
:align: center
|
||||
|
||||
Use the *Options* tab to set option properties for the publication:
|
||||
|
||||
* Use the *With* section to determine which DML operations will be published by the new publication to the subscribers. Move the switch next to *INSERT*, *UPDATE*, *DELETE*, or *TRUNCATE* to *No* if you do not want to replicate any of these DML operations from Publication to Subscription. By default, all the switches are set to *Yes* allowing all the DML operations.
|
||||
|
||||
.. note:: A published table must have a “replica identity” configured in order to be able to replicate UPDATE and DELETE operations. You can change with ALTER TABLE statement. For more information on replica identity see `Logical Replication Publication <https://www.postgresql.org/docs/13/logical-replication-publication.html>`_.
|
||||
|
||||
.. note:: A published table must have a “replica identity” configured in order to be able to replicate UPDATE and DELETE operations. You can change with ALTER TABLE statement. For more information on replica identity see `Logical Replication Publication <https://www.postgresql.org/docs/15/logical-replication-publication.html>`_.
|
||||
|
||||
Click the *SQL* tab to continue.
|
||||
|
||||
|
||||
@@ -178,7 +178,12 @@ Data Editing Options
|
||||
| | | |
|
||||
| | * Click *Copy with headers* to copy the highlighted content along with the header. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Paste* | Click the *Paste* icon to paste a previously copied row into a new row. | Accesskey + P |
|
||||
| *Paste* | Click the *Paste* icon to paste a previously copied row with or without serial/identity values: | Accesskey + P |
|
||||
| | | |
|
||||
| | * Click the *Paste* icon to paste a previously copied row into a new row. | |
|
||||
| | | |
|
||||
| | * Click the *Paste with SERIAL/IDENTITY values?* if you want to paste the copied column values | |
|
||||
| | in the serial/identity columns. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Delete* | Click the *Delete* icon to mark the selected rows for deletion. These marked rows get deleted | Accesskey + D |
|
||||
| | when you click the *Save Data Changes* icon. | |
|
||||
|
||||
@@ -11,6 +11,10 @@ notes for it.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release_notes_7_4
|
||||
release_notes_7_3
|
||||
release_notes_7_2
|
||||
release_notes_7_1
|
||||
release_notes_7_0
|
||||
release_notes_6_21
|
||||
release_notes_6_20
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
***********
|
||||
Version 7.1
|
||||
***********
|
||||
|
||||
Release date: 2023-05-04
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.0.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 11, 12, 13, 14 and 15
|
||||
|
||||
**EDB Advanced Server**: 11, 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 15.2
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #2078 <https://github.com/pgadmin-org/pgadmin4/issues/2078>`_ - Show object breadcrumbs path along with its comment on object hover.
|
||||
| `Issue #3275 <https://github.com/pgadmin-org/pgadmin4/issues/3275>`_ - Allow on demand record count setting to be changed per user using preferences.
|
||||
| `Issue #3316 <https://github.com/pgadmin-org/pgadmin4/issues/3316>`_ - Added support to show statistics for materialized views.
|
||||
| `Issue #3318 <https://github.com/pgadmin-org/pgadmin4/issues/3318>`_ - Added support to create an unnamed index.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #5044 <https://github.com/pgadmin-org/pgadmin4/issues/5044>`_ - Fixed an issue where query tool hangs for some time when multiple columns are selected to open geometry viewer.
|
||||
| `Issue #5777 <https://github.com/pgadmin-org/pgadmin4/issues/5777>`_ - Fixed an issue where the browser tree state is not remembered when reopening pgAdmin.
|
||||
| `Issue #5820 <https://github.com/pgadmin-org/pgadmin4/issues/5820>`_ - Fixed an issue where collation was set to none if we remove it while creating partitioned table.
|
||||
| `Issue #5922 <https://github.com/pgadmin-org/pgadmin4/issues/5922>`_ - Ensure that when pasting a row in query tool grid, default value is used for autogenerated/serial columns.
|
||||
| `Issue #6059 <https://github.com/pgadmin-org/pgadmin4/issues/6059>`_ - Show proper message if the debugger is stopped by the user.
|
||||
| `Issue #6075 <https://github.com/pgadmin-org/pgadmin4/issues/6075>`_ - Ensure that the save button is enabled when registering a new server fails due to an API error.
|
||||
| `Issue #6077 <https://github.com/pgadmin-org/pgadmin4/issues/6077>`_ - The search object, query tool, and psql tool menu should not be displayed for pgAgent.
|
||||
| `Issue #6120 <https://github.com/pgadmin-org/pgadmin4/issues/6120>`_ - Fixed error occurring while logging out from pgAdmin keeping a query tool opened.
|
||||
| `Issue #6128 <https://github.com/pgadmin-org/pgadmin4/issues/6128>`_ - Fix a SQL error occurring on roles dependents SQL.
|
||||
| `Issue #6130 <https://github.com/pgadmin-org/pgadmin4/issues/6130>`_ - Ensure to quote the primary key value if needed while deleting rows from the table.
|
||||
| `Issue #6137 <https://github.com/pgadmin-org/pgadmin4/issues/6137>`_ - Fixed error occurring while dumping the servers from CLI.
|
||||
| `Issue #6138 <https://github.com/pgadmin-org/pgadmin4/issues/6138>`_ - Throw an appropriate error when a table for which View/Edit data is open, is deleted, and query is executed.
|
||||
| `Issue #6151 <https://github.com/pgadmin-org/pgadmin4/issues/6151>`_ - Ensure that internal users are able to login when auth sources are [ldap, internal].
|
||||
| `Issue #6158 <https://github.com/pgadmin-org/pgadmin4/issues/6158>`_ - Fixed an issue with the properties tab not getting updated if the user updates the selected node.
|
||||
| `Issue #6159 <https://github.com/pgadmin-org/pgadmin4/issues/6159>`_ - Ensure that the ERD tool should work with the external database after moving to psycopg3.
|
||||
| `Issue #6180 <https://github.com/pgadmin-org/pgadmin4/issues/6180>`_ - Fixed an issue where PSQL is not working if the PGUSER env variable is set and service file is used for server connection details.
|
||||
| `Issue #6183 <https://github.com/pgadmin-org/pgadmin4/issues/6183>`_ - Mac crash when you press Command-Shift-C.
|
||||
| `Issue #6189 <https://github.com/pgadmin-org/pgadmin4/issues/6189>`_ - Fix an issue in View SQL when column level privileges are set with multiple roles.
|
||||
| `Issue #6191 <https://github.com/pgadmin-org/pgadmin4/issues/6191>`_ - Fixed an issue where Reset Password is not working after upgrading to latest flask-security-too.
|
||||
| `Issue #6234 <https://github.com/pgadmin-org/pgadmin4/issues/6234>`_ - Usernames/roles with special character are not double quoted when assigning privileges.
|
||||
@@ -0,0 +1,55 @@
|
||||
***********
|
||||
Version 7.2
|
||||
***********
|
||||
|
||||
Release date: 2023-06-01
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.1.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 11, 12, 13, 14 and 15
|
||||
|
||||
**EDB Advanced Server**: 11, 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 15.2
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #3831 <https://github.com/pgadmin-org/pgadmin4/issues/3831>`_ - Add Option to only show active connections on Dashboard.
|
||||
| `Issue #4769 <https://github.com/pgadmin-org/pgadmin4/issues/4769>`_ - Allow pgAdmin to retrive master password from external script/program.
|
||||
| `Issue #5048 <https://github.com/pgadmin-org/pgadmin4/issues/5048>`_ - Add an option to hide/show empty object collection nodes.
|
||||
| `Issue #5123 <https://github.com/pgadmin-org/pgadmin4/issues/5123>`_ - Added support to use standard OS secret store to save server/ssh tunnel passwords instead of master password in pgAdmin desktop mode.
|
||||
| `Issue #5868 <https://github.com/pgadmin-org/pgadmin4/issues/5868>`_ - Implement new PostgreSQL 15 features in publication dialog and SQL.
|
||||
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #5789 <https://github.com/pgadmin-org/pgadmin4/issues/5789>`_ - Fixed an issue where Foreign Key columns are shown in the wrong order in SQL and Properties.
|
||||
| `Issue #5817 <https://github.com/pgadmin-org/pgadmin4/issues/5817>`_ - Ensure that a new row should be added on top in the User Management dialog.
|
||||
| `Issue #5926 <https://github.com/pgadmin-org/pgadmin4/issues/5926>`_ - Fixed an issue where REVOKE ALL DDL in table SQL was added only for one role.
|
||||
| `Issue #6003 <https://github.com/pgadmin-org/pgadmin4/issues/6003>`_ - Indicate the user if all the server's children nodes are hidden from the preferences setting.
|
||||
| `Issue #6026 <https://github.com/pgadmin-org/pgadmin4/issues/6026>`_ - Tools menu should be toggled for "pause replay of wal" and "resume replay of wal".
|
||||
| `Issue #6043 <https://github.com/pgadmin-org/pgadmin4/issues/6043>`_ - Make the 'Connect to server' dialog a modal dialog.
|
||||
| `Issue #6080 <https://github.com/pgadmin-org/pgadmin4/issues/6080>`_ - pgAdmin icon not showing on taskbar on Windows 10.
|
||||
| `Issue #6127 <https://github.com/pgadmin-org/pgadmin4/issues/6127>`_ - Fixed an issue where properties were not visible for FTS Parsers, FTS Templates, MViews, and Rules in Catalog objects.
|
||||
| `Issue #6147 <https://github.com/pgadmin-org/pgadmin4/issues/6147>`_ - Heartbeat is getting logged, though no server is connected in pgAdmin.
|
||||
| `Issue #6204 <https://github.com/pgadmin-org/pgadmin4/issues/6204>`_ - Ensure that name can't be empty in edit mode for Primary Key and Index.
|
||||
| `Issue #6221 <https://github.com/pgadmin-org/pgadmin4/issues/6221>`_ - Fix circular reference error for the multirange data types in the query tool.
|
||||
| `Issue #6247 <https://github.com/pgadmin-org/pgadmin4/issues/6247>`_ - Fixed an issue where PSQL tool prompts for password if using password exec command.
|
||||
| `Issue #6253 <https://github.com/pgadmin-org/pgadmin4/issues/6253>`_ - Fix an issue in the register server when setting the role, an arbitrary SQL query can be fired.
|
||||
| `Issue #6267 <https://github.com/pgadmin-org/pgadmin4/issues/6267>`_ - Ensure the user is able to log in if the specified OAUTH2_USERNAME_CLAIM is present in the OAuth2 profile.
|
||||
| `Issue #6278 <https://github.com/pgadmin-org/pgadmin4/issues/6278>`_ - Use dependent instead of dependant in the message.
|
||||
| `Issue #6279 <https://github.com/pgadmin-org/pgadmin4/issues/6279>`_ - Fix incorrect number of foreign tables displayed. Show column comments in RE-SQL.
|
||||
| `Issue #6280 <https://github.com/pgadmin-org/pgadmin4/issues/6280>`_ - View SQL tab not quoting column comments.
|
||||
| `Issue #6281 <https://github.com/pgadmin-org/pgadmin4/issues/6281>`_ - VarChar Field Sizes are missing from Query's Grid header.
|
||||
| `Issue #6331 <https://github.com/pgadmin-org/pgadmin4/issues/6331>`_ - Separate multiple Blocking PIDs with delimiter on Dashboard.
|
||||
@@ -0,0 +1,35 @@
|
||||
***********
|
||||
Version 7.3
|
||||
***********
|
||||
|
||||
Release date: 2023-06-06
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.2.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 11, 12, 13, 14 and 15
|
||||
|
||||
**EDB Advanced Server**: 11, 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 15.3
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #6136 <https://github.com/pgadmin-org/pgadmin4/issues/6136>`_ - Fix an issue where editing a database object de-selects it on the browser tree.
|
||||
| `Issue #6341 <https://github.com/pgadmin-org/pgadmin4/issues/6341>`_ - Ensure that SSH Tunnel should work properly after upgrading to 7.2 from 7.1
|
||||
| `Issue #6342 <https://github.com/pgadmin-org/pgadmin4/issues/6342>`_ - Fixed an issue where pgadmin is unable to take the defined role.
|
||||
| `Issue #6345 <https://github.com/pgadmin-org/pgadmin4/issues/6345>`_ - Fixed an issue where Foreign Key with 3 or more columns are shown in the wrong order in SQL and Properties.
|
||||
| `Issue #6353 <https://github.com/pgadmin-org/pgadmin4/issues/6353>`_ - Ensure that the master password dialog should not be visible if the parameter MASTER_PASSWORD_REQUIRED is set to False.
|
||||
@@ -0,0 +1,47 @@
|
||||
***********
|
||||
Version 7.4
|
||||
***********
|
||||
|
||||
Release date: 2023-06-29
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.3.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 11, 12, 13, 14 and 15
|
||||
|
||||
**EDB Advanced Server**: 11, 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 15.3
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #6367 <https://github.com/pgadmin-org/pgadmin4/issues/6367>`_ - Added support to drop databases using the 'WITH (FORCE)' option.
|
||||
| `Issue #6368 <https://github.com/pgadmin-org/pgadmin4/issues/6368>`_ - Add "[ NULLS [ NOT ] DISTINCT ]" option while creating an Index.
|
||||
| `Issue #6370 <https://github.com/pgadmin-org/pgadmin4/issues/6370>`_ - Added 'OR REPLACE' clause while creating trigger.
|
||||
| `Issue #6371 <https://github.com/pgadmin-org/pgadmin4/issues/6371>`_ - Added security_invoker option while creating a view.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #5306 <https://github.com/pgadmin-org/pgadmin4/issues/5306>`_ - Fix an issue where object explorer tree crashes occasionally.
|
||||
| `Issue #6065 <https://github.com/pgadmin-org/pgadmin4/issues/6065>`_ - Ensure that query tool shortcuts are working properly.
|
||||
| `Issue #6258 <https://github.com/pgadmin-org/pgadmin4/issues/6258>`_ - Add Password exec command and Expiration time to server export JSON and also allow them to import.
|
||||
| `Issue #6266 <https://github.com/pgadmin-org/pgadmin4/issues/6266>`_ - When opening pgAdmin the layout should be auto reset if it is corrupted. Reset layout menu should work if layout is corrupted while using pgAdmin.
|
||||
| `Issue #6291 <https://github.com/pgadmin-org/pgadmin4/issues/6291>`_ - Fix an issue where loading more rows indicator will not disappear if connection is lost.
|
||||
| `Issue #6340 <https://github.com/pgadmin-org/pgadmin4/issues/6340>`_ - Fix an encoding error when connecting through Pgbouncer.
|
||||
| `Issue #6352 <https://github.com/pgadmin-org/pgadmin4/issues/6352>`_ - Fix an issue where explain plan details is showing HTML escaped characters.
|
||||
| `Issue #6354 <https://github.com/pgadmin-org/pgadmin4/issues/6354>`_ - Fixed an issue where queries with temporary tables in the same transaction is not working.
|
||||
| `Issue #6363 <https://github.com/pgadmin-org/pgadmin4/issues/6363>`_ - Fixed an issue where preview images for themes were not loading.
|
||||
| `Issue #6420 <https://github.com/pgadmin-org/pgadmin4/issues/6420>`_ - Fix raise notice from func/proc or code blocks are no longer displayed live.
|
||||
| `Issue #6431 <https://github.com/pgadmin-org/pgadmin4/issues/6431>`_ - Fix an issue where PSQL is not working if the database name have quotes or double quotes.
|
||||
| `Issue #6435 <https://github.com/pgadmin-org/pgadmin4/issues/6435>`_ - Fix an issue where all the menus are enabled when pgAdmin is opened and no object is selected in the object explorer.
|
||||
|
||||
@@ -49,14 +49,16 @@ following selections (options appear in alphabetical order):
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Debugging* | Click through to open the :ref:`Debug <debugger>` tool or to select *Set breakpoint* to stop or pause a script execution. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete/Drop* | Click to delete the currently selected object from the server. |
|
||||
| *Delete* | Click to delete the currently selected object from the server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Cascade)* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Force)* | Click to delete the currently selected database with force option. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Disconnect Database...* | Click to terminate a database connection. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Disconnect from server* | Click to disconnect from the currently selected server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Drop Cascade* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Debugging* | Click to access the :ref:`Debugger <debugger>` tool. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Grant Wizard* | Click to access the :ref:`Grant Wizard <grant_wizard>` tool. |
|
||||
|
||||
@@ -51,6 +51,8 @@ Use the fields in the *Definition* tab to define the unique constraint:
|
||||
* If enabled, move the *Deferred?* switch to the *Yes* position to specify the
|
||||
timing of the constraint is deferred to the end of the statement. The default
|
||||
is *No*.
|
||||
* Move the *NULLs not distinct?* switch to the *Yes* position to treat null values as not distinct. The default is
|
||||
*No*. This option is available only on PostgreSQL 15 and above.
|
||||
|
||||
Click the *SQL* tab to continue.
|
||||
|
||||
|
||||
@@ -39,7 +39,10 @@ Use the fields in the *Definition* tab to define properties of the view:
|
||||
|
||||
* Set the *Security Barrier* switch to *Yes* to indicate that the view is to act
|
||||
as a security barrier. For more information about defining and using a
|
||||
security barrier rule, see Section 38.5 of the PostgreSQL documentation.
|
||||
security barrier rule, see Rules and Privileges of the PostgreSQL documentation.
|
||||
* Set the *Security Invoker* switch to *Yes* to indicate that the underlying base
|
||||
relations are to be checked against the privileges of the user of the view rather
|
||||
than the view owner. This option is available from PostgreSQL 15 onwards.
|
||||
* Use the drop-down listbox next to *Check options* to select from *No*, *Local*
|
||||
or *Cascaded*:
|
||||
|
||||
|
||||
@@ -141,10 +141,7 @@ _build_runtime() {
|
||||
# YARN END
|
||||
|
||||
# WGET:
|
||||
# NW_VERSION=$(yarn info nw | grep latest | awk -F "'" '{ print $2}')
|
||||
# Remove the above commented code once below issue is fixed
|
||||
# Pining NWjs because of https://github.com/nwjs/nw.js/issues/8039 in 0.74.0
|
||||
NW_VERSION="0.72.0"
|
||||
NW_VERSION=$(yarn info nw | grep latest | awk -F "'" '{ print $2}')
|
||||
|
||||
pushd "${BUILDROOT}" > /dev/null || exit
|
||||
while true;do
|
||||
|
||||
@@ -11,7 +11,8 @@ _setup_env() {
|
||||
APP_LONG_VERSION=${APP_LONG_VERSION}-${APP_SUFFIX}
|
||||
fi
|
||||
BUNDLE_DIR="${BUILD_ROOT}/${APP_NAME}.app"
|
||||
DMG_NAME="${DIST_ROOT}"/$(echo "${APP_NAME}" | sed 's/ //g' | awk '{print tolower($0)}')-"${APP_LONG_VERSION}.dmg"
|
||||
DMG_NAME="${DIST_ROOT}"/$(echo "${APP_NAME}" | sed 's/ //g' | awk '{print tolower($0)}')-"${APP_LONG_VERSION}-$(uname -m).dmg"
|
||||
PYTHON_OS_VERSION="11"
|
||||
}
|
||||
|
||||
_cleanup() {
|
||||
@@ -29,22 +30,25 @@ _build_runtime() {
|
||||
# NOTE: The nw download servers seem to be very unreliable, so at the moment we're using wget
|
||||
# in a retry loop as Yarn/Npm don't seem to like that.
|
||||
|
||||
# uname -m returns "x86_64" on Intel, but we need "x64"
|
||||
NW_ARCH="x64"
|
||||
if [ "$(uname -m)" == "arm64" ]; then
|
||||
NW_ARCH="arm64"
|
||||
fi
|
||||
|
||||
# YARN:
|
||||
# yarn add --cwd "${BUILDROOT}" nw
|
||||
# YARN END
|
||||
|
||||
# WGET:
|
||||
# NW_VERSION=$(yarn info nw | grep latest | awk -F "'" '{ print $2}')
|
||||
# Remove the above commented code once below issue is fixed
|
||||
# Pining NWjs because of https://github.com/nwjs/nw.js/issues/8039 in 0.74.0
|
||||
NW_VERSION="0.72.0"
|
||||
NW_VERSION=$(yarn info nw | grep latest | awk -F "'" '{ print $2}')
|
||||
|
||||
pushd "${BUILD_ROOT}" > /dev/null || exit
|
||||
while true;do
|
||||
wget "https://dl.nwjs.io/v${NW_VERSION}/nwjs-v${NW_VERSION}-osx-x64.zip" && break
|
||||
rm "nwjs-v${NW_VERSION}-osx-x64.zip"
|
||||
wget "https://dl.nwjs.io/v${NW_VERSION}/nwjs-v${NW_VERSION}-osx-${NW_ARCH}.zip" && break
|
||||
rm "nwjs-v${NW_VERSION}-osx-${NW_ARCH}.zip"
|
||||
done
|
||||
unzip "nwjs-v${NW_VERSION}-osx-x64.zip"
|
||||
unzip "nwjs-v${NW_VERSION}-osx-${NW_ARCH}.zip"
|
||||
popd > /dev/null || exit
|
||||
# WGET END
|
||||
|
||||
@@ -53,7 +57,7 @@ _build_runtime() {
|
||||
# YARN END
|
||||
|
||||
# WGET:
|
||||
cp -R "${BUILD_ROOT}/nwjs-v${NW_VERSION}-osx-x64"/nwjs.app "${BUILD_ROOT}/"
|
||||
cp -R "${BUILD_ROOT}/nwjs-v${NW_VERSION}-osx-${NW_ARCH}"/nwjs.app "${BUILD_ROOT}/"
|
||||
# WGET END
|
||||
|
||||
mv "${BUILD_ROOT}/nwjs.app" "${BUNDLE_DIR}"
|
||||
@@ -82,13 +86,15 @@ _create_python_env() {
|
||||
fi
|
||||
|
||||
git clone https://github.com/gregneagle/relocatable-python.git "${BUILD_ROOT}/relocatable_python"
|
||||
PATH=$PATH:/usr/local/pgsql/bin "${SYSTEM_PYTHON_EXE}" \
|
||||
"${SYSTEM_PYTHON_EXE}" \
|
||||
"${BUILD_ROOT}/relocatable_python/make_relocatable_python_framework.py" \
|
||||
--upgrade-pip \
|
||||
--python-version "${PGADMIN_PYTHON_VERSION}" \
|
||||
--pip-requirements "${SOURCE_DIR}/requirements.txt" \
|
||||
--os-version "${PYTHON_OS_VERSION}" \
|
||||
--destination "${BUNDLE_DIR}/Contents/Frameworks/"
|
||||
|
||||
"${BUNDLE_DIR}/Contents/Frameworks/Python.framework/Versions/Current/bin/python3" -m ensurepip --upgrade || exit 1
|
||||
"${BUNDLE_DIR}/Contents/Frameworks/Python.framework/Versions/Current/bin/pip3" install -r "${SOURCE_DIR}/requirements.txt" || exit 1
|
||||
|
||||
# Make sure all the .so's in the Python env have the executable bit set
|
||||
# so they get properly signed later
|
||||
OLD_IFS=${IFS}
|
||||
@@ -136,7 +142,7 @@ _build_docs() {
|
||||
source "${BUILD_ROOT}/venv/bin/activate"
|
||||
pip3 install --upgrade pip
|
||||
pip3 install -r "${SOURCE_DIR}/requirements.txt"
|
||||
pip3 install sphinx
|
||||
pip3 install sphinx==6.1.3
|
||||
pip3 install sphinxcontrib-youtube
|
||||
|
||||
cd "${SOURCE_DIR}" || exit
|
||||
|
||||
@@ -53,8 +53,8 @@ if [ "${PGADMIN_POSTGRES_DIR}" == "" ]; then
|
||||
fi
|
||||
|
||||
if [ "${PGADMIN_PYTHON_VERSION}" == "" ]; then
|
||||
echo "PGADMIN_PYTHON_VERSION not set. Setting it to the default: 3.9.9"
|
||||
export PGADMIN_PYTHON_VERSION=3.9.9
|
||||
echo "PGADMIN_PYTHON_VERSION not set. Setting it to the default: 3.11.2"
|
||||
export PGADMIN_PYTHON_VERSION=3.11.2
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
@@ -39,15 +39,15 @@ yum groupinstall -y "Development Tools"
|
||||
|
||||
if [ "${OS_VERSION}" == "8" ]; then
|
||||
yum install -y expect fakeroot postgresql15-devel python3.9-devel nodejs yarn rpm-build rpm-sign yum-utils krb5-devel
|
||||
pip3.9 install sphinx
|
||||
pip3.9 install sphinx==6.1.3
|
||||
pip3.9 install sphinxcontrib-youtube
|
||||
elif [ "${OS_VERSION}" == "9" ]; then
|
||||
yum install -y expect libpq5-devel postgresql15-devel python3-devel nodejs yarn rpm-build rpm-sign yum-utils krb5-devel
|
||||
pip3 install sphinx
|
||||
pip3 install sphinx==6.1.3
|
||||
pip3 install sphinxcontrib-youtube
|
||||
else
|
||||
yum install -y expect fakeroot postgresql15-devel python3-devel nodejs yarn rpm-build rpm-sign yum-utils krb5-devel
|
||||
pip3 install sphinx
|
||||
pip3 install sphinx==6.1.3
|
||||
pip3 install sphinxcontrib-youtube
|
||||
fi
|
||||
|
||||
|
||||
@@ -18,16 +18,16 @@ Flask-SQLAlchemy==3.0.*
|
||||
Flask-WTF==1.1.1
|
||||
Flask-Compress==1.*
|
||||
Flask-Paranoid==0.*
|
||||
Flask-Babel==3.0.*
|
||||
Flask-Babel==3.1.*
|
||||
Flask-Security-Too==5.1.*
|
||||
Flask-SocketIO==5.3.*
|
||||
WTForms==3.0.*
|
||||
passlib==1.*
|
||||
pytz==2022.*
|
||||
pytz==2023.*
|
||||
speaklater3==1.*
|
||||
sqlparse==0.*
|
||||
psutil==5.9.*
|
||||
psycopg[c]==3.1.*
|
||||
psycopg[c]==3.1.8
|
||||
python-dateutil==2.*
|
||||
SQLAlchemy==2.*
|
||||
bcrypt==4.0.*
|
||||
@@ -40,7 +40,6 @@ httpagentparser==1.9.*
|
||||
user-agents==2.2.0
|
||||
pywinpty==2.0.*; sys_platform=="win32"
|
||||
Authlib==1.2.*
|
||||
requests==2.28.*
|
||||
pyotp==2.*
|
||||
qrcode==7.*
|
||||
Pillow==9.*
|
||||
@@ -48,8 +47,10 @@ boto3==1.26.*
|
||||
botocore==1.29.*
|
||||
urllib3==1.26.*
|
||||
azure-mgmt-rdbms==10.1.0
|
||||
azure-mgmt-resource==23.0.0
|
||||
azure-mgmt-resource==23.0.1
|
||||
azure-mgmt-subscription==3.1.1
|
||||
azure-identity==1.12.0
|
||||
azure-identity==1.13.0
|
||||
google-api-python-client==2.*
|
||||
google-auth-oauthlib==1.0.0
|
||||
Werkzeug==2.2.3
|
||||
keyring==23.*
|
||||
@@ -5,7 +5,7 @@
|
||||
"repository": "https://github.com/postgres/pgadmin4.git",
|
||||
"author": "pgAdmin Development Team (https://www.pgadmin.org/)",
|
||||
"license": "PostgreSQL",
|
||||
"chromium-args": "--disable-popup-blocking --disable-gpu",
|
||||
"chromium-args": "--disable-popup-blocking --disable-gpu --disable-devtools",
|
||||
"user-agent": "Nwjs:%nwver-%osinfo-%chromium_ver",
|
||||
"nodejs": true,
|
||||
"window": {
|
||||
@@ -19,13 +19,16 @@
|
||||
"always-on-top": true,
|
||||
"icon": "assets/pgAdmin4.png"
|
||||
},
|
||||
"icons": {
|
||||
"256": "assets/pgAdmin4.png"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"axios": "^1.4.0",
|
||||
"bootstrap": "^4.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.37.0",
|
||||
"nw": "^0.72.0"
|
||||
"eslint": "^8.42.0",
|
||||
"nw": "^0.77.0"
|
||||
},
|
||||
"scripts": {
|
||||
"linter": "yarn eslint --no-eslintrc -c .eslintrc.js --ext .js ."
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724"
|
||||
integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==
|
||||
|
||||
"@eslint/eslintrc@^2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02"
|
||||
integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==
|
||||
"@eslint/eslintrc@^2.0.3":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331"
|
||||
integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
espree "^9.5.1"
|
||||
espree "^9.5.2"
|
||||
globals "^13.19.0"
|
||||
ignore "^5.2.0"
|
||||
import-fresh "^3.2.1"
|
||||
@@ -29,15 +29,15 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@8.37.0":
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.37.0.tgz#cf1b5fa24217fe007f6487a26d765274925efa7d"
|
||||
integrity sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==
|
||||
"@eslint/js@8.42.0":
|
||||
version "8.42.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.42.0.tgz#484a1d638de2911e6f5a30c12f49c7e4a3270fb6"
|
||||
integrity sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.8":
|
||||
version "0.11.8"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
|
||||
integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==
|
||||
"@humanwhocodes/config-array@^0.11.10":
|
||||
version "0.11.10"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
|
||||
integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==
|
||||
dependencies:
|
||||
"@humanwhocodes/object-schema" "^1.2.1"
|
||||
debug "^4.1.1"
|
||||
@@ -126,10 +126,10 @@ asynckit@^0.4.0:
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
axios@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024"
|
||||
integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==
|
||||
axios@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
|
||||
integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
@@ -430,29 +430,29 @@ escape-string-regexp@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
eslint-scope@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
|
||||
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
|
||||
eslint-scope@^7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
|
||||
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc"
|
||||
integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
|
||||
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
|
||||
|
||||
eslint@^8.37.0:
|
||||
version "8.37.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.37.0.tgz#1f660ef2ce49a0bfdec0b0d698e0b8b627287412"
|
||||
integrity sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==
|
||||
eslint@^8.42.0:
|
||||
version "8.42.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.42.0.tgz#7bebdc3a55f9ed7167251fe7259f75219cade291"
|
||||
integrity sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.4.0"
|
||||
"@eslint/eslintrc" "^2.0.2"
|
||||
"@eslint/js" "8.37.0"
|
||||
"@humanwhocodes/config-array" "^0.11.8"
|
||||
"@eslint/eslintrc" "^2.0.3"
|
||||
"@eslint/js" "8.42.0"
|
||||
"@humanwhocodes/config-array" "^0.11.10"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@nodelib/fs.walk" "^1.2.8"
|
||||
ajv "^6.10.0"
|
||||
@@ -461,9 +461,9 @@ eslint@^8.37.0:
|
||||
debug "^4.3.2"
|
||||
doctrine "^3.0.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
eslint-scope "^7.1.1"
|
||||
eslint-visitor-keys "^3.4.0"
|
||||
espree "^9.5.1"
|
||||
eslint-scope "^7.2.0"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
espree "^9.5.2"
|
||||
esquery "^1.4.2"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
@@ -471,13 +471,12 @@ eslint@^8.37.0:
|
||||
find-up "^5.0.0"
|
||||
glob-parent "^6.0.2"
|
||||
globals "^13.19.0"
|
||||
grapheme-splitter "^1.0.4"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.2.0"
|
||||
import-fresh "^3.0.0"
|
||||
imurmurhash "^0.1.4"
|
||||
is-glob "^4.0.0"
|
||||
is-path-inside "^3.0.3"
|
||||
js-sdsl "^4.1.4"
|
||||
js-yaml "^4.1.0"
|
||||
json-stable-stringify-without-jsonify "^1.0.1"
|
||||
levn "^0.4.1"
|
||||
@@ -489,14 +488,14 @@ eslint@^8.37.0:
|
||||
strip-json-comments "^3.1.0"
|
||||
text-table "^0.2.0"
|
||||
|
||||
espree@^9.5.1:
|
||||
version "9.5.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4"
|
||||
integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==
|
||||
espree@^9.5.2:
|
||||
version "9.5.2"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b"
|
||||
integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==
|
||||
dependencies:
|
||||
acorn "^8.8.0"
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^3.4.0"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
|
||||
esquery@^1.4.2:
|
||||
version "1.5.0"
|
||||
@@ -705,10 +704,10 @@ graceful-fs@^4.1.10:
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
|
||||
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
|
||||
|
||||
grapheme-splitter@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
|
||||
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
|
||||
graphemer@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
|
||||
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
||||
|
||||
has-ansi@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -847,11 +846,6 @@ isurl@^1.0.0-alpha5:
|
||||
has-to-string-tag-x "^1.2.0"
|
||||
is-object "^1.0.1"
|
||||
|
||||
js-sdsl@^4.1.4:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430"
|
||||
integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
@@ -967,10 +961,10 @@ number-is-nan@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==
|
||||
|
||||
nw@^0.72.0:
|
||||
version "0.72.0"
|
||||
resolved "https://registry.yarnpkg.com/nw/-/nw-0.72.0.tgz#b8d340c165756b2f07320e999f5aaa486131e38f"
|
||||
integrity sha512-uMLsvXe3cDJ+YY8Jcd+YoLg7ggqJAbpTskNx0X21Z6gn9oWWnte9eJsWNC/9J5itg3TzzqyvIyUfXsMGekqPmw==
|
||||
nw@^0.77.0:
|
||||
version "0.77.0"
|
||||
resolved "https://registry.yarnpkg.com/nw/-/nw-0.77.0.tgz#f6fa0f5e68d65e124ca66b9759b87f1fd8291b89"
|
||||
integrity sha512-5M+3Nv3/x1VJbzr6fdR/uXaA2M6H3/UHpxTSidmUYFHF2FP4xTTxwLXbb0/WdX+oNXby8XeqiF1bGDqKi7ti1g==
|
||||
dependencies:
|
||||
chalk "~1.1.3"
|
||||
decompress "^4.2.0"
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
# Get the URL to the latest version of a package in a StackBuilder catalog
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from urllib.request import urlopen, urlretrieve
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print('Usage: {} <Catalog URL> <Application ID> <Platform>'.
|
||||
format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
# Get the catalog
|
||||
catalog = urlopen(sys.argv[1]).read().decode('utf-8')
|
||||
apps = ET.fromstring(catalog)
|
||||
|
||||
downloads = []
|
||||
for a in apps:
|
||||
if a.find('id').text == sys.argv[2] and \
|
||||
a.find('platform').text == sys.argv[3]:
|
||||
downloads.append({'version': a.find('version').text,
|
||||
'url': a.find('alturl').text,
|
||||
'format': a.find('format').text})
|
||||
|
||||
if len(downloads) == 0:
|
||||
print('No matching URLs found.')
|
||||
sys.exit(1)
|
||||
|
||||
# Make sure we're looking at the latest version
|
||||
downloads = sorted(downloads, key=lambda d: d['version'], reverse=True)
|
||||
|
||||
# Get the file
|
||||
filename, headers = urlretrieve(downloads[0]['url'])
|
||||
|
||||
if sys.argv[3].startswith('windows') and downloads[0]['format'] == 'exe':
|
||||
os.rename(filename, '{}.exe'.format(filename))
|
||||
filename = '{}.exe'.format(filename)
|
||||
|
||||
print(filename)
|
||||
@@ -18,8 +18,8 @@ pip install --upgrade pip
|
||||
if [ ${TEST} -eq 1 ];
|
||||
then
|
||||
echo Installing requirements for running Python tests...
|
||||
pip install --no-cache-dir wheel sphinx sphinxcontrib-youtube -r web/regression/requirements.txt || { echo 'ERROR: Failed to install Python requirements.' ; exit 1; }
|
||||
pip install --no-cache-dir wheel sphinx==6.1.3 sphinxcontrib-youtube -r web/regression/requirements.txt || { echo 'ERROR: Failed to install Python requirements.' ; exit 1; }
|
||||
else
|
||||
echo Installing requirements for executing and building only...
|
||||
pip install --no-cache-dir wheel sphinx sphinxcontrib-youtube -r requirements.txt || { echo 'ERROR: Failed to install Python requirements.' ; exit 1; }
|
||||
pip install --no-cache-dir wheel sphinx==6.1.3 sphinxcontrib-youtube -r requirements.txt || { echo 'ERROR: Failed to install Python requirements.' ; exit 1; }
|
||||
fi
|
||||
@@ -221,6 +221,8 @@ def edit_browsers_json(browser_name, browser_version):
|
||||
'port': '4444', 'path': '/wd/hub'}})
|
||||
(existing_data['firefox']['versions']).update(data_to_insert)
|
||||
updated_data = existing_data
|
||||
print(updated_data)
|
||||
|
||||
else:
|
||||
print("Browser version not matched")
|
||||
file_edited = False
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
logFilters:
|
||||
- code: YN0013
|
||||
level: discard
|
||||
@@ -43,7 +43,7 @@ APP_ICON = 'pg-icon'
|
||||
|
||||
# Application version number components
|
||||
APP_RELEASE = 7
|
||||
APP_REVISION = 0
|
||||
APP_REVISION = 4
|
||||
|
||||
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
|
||||
# for GA releases.
|
||||
@@ -52,7 +52,7 @@ APP_SUFFIX = ''
|
||||
# Numeric application version for upgrade checks. Should be in the format:
|
||||
# [X]XYYZZ, where X is the release version, Y is the revision, with a leading
|
||||
# zero if needed, and Z represents the suffix, with a leading zero if needed
|
||||
APP_VERSION_INT = 70000
|
||||
APP_VERSION_INT = 70400
|
||||
|
||||
# DO NOT CHANGE!
|
||||
# The application version string, constructed from the components
|
||||
@@ -78,6 +78,7 @@ LANGUAGES = {
|
||||
'cs': 'Czech',
|
||||
'fr': 'French',
|
||||
'de': 'German',
|
||||
'id': 'Indonesian',
|
||||
'it': 'Italian',
|
||||
'ja': 'Japanese',
|
||||
'ko': 'Korean',
|
||||
@@ -576,6 +577,24 @@ ALLOW_SAVE_TUNNEL_PASSWORD = False
|
||||
MASTER_PASSWORD_REQUIRED = True
|
||||
|
||||
##########################################################################
|
||||
|
||||
# pgAdmin encrypts the database connection and ssh tunnel password using a
|
||||
# master password or pgAdmin login password (for other authentication sources)
|
||||
# before storing it in the pgAdmin configuration database.
|
||||
#
|
||||
# Below setting is used to allow the user to specify the path to a script
|
||||
# or program that will return an encryption key which will be used to
|
||||
# encrypt the passwords. This setting is used only in server mode when
|
||||
# auth sources are oauth, Kerberos, and webserver.
|
||||
#
|
||||
# You can pass the current username as an argument to the external script
|
||||
# by specifying %u in config value.
|
||||
# E.g. - MASTER_PASSWORD_HOOK = '<PATH>/passwdgen_script.sh %u'
|
||||
##########################################################################
|
||||
MASTER_PASSWORD_HOOK = None
|
||||
|
||||
##########################################################################
|
||||
|
||||
# Allows pgAdmin4 to create session cookies based on IP address, so even
|
||||
# if a cookie is stolen, the attacker will not be able to connect to the
|
||||
# server using that stolen cookie.
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.10.1",
|
||||
"@babel/plugin-syntax-jsx": "^7.16.0",
|
||||
"@babel/preset-env": "^7.10.2",
|
||||
"@babel/preset-typescript": "^7.8.3",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@emotion/core": "^10.0.14",
|
||||
"@emotion/memoize": "^0.7.5",
|
||||
"@emotion/react": "^11.1.5",
|
||||
"@emotion/styled": "^10.0.14",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@emotion/utils": "^1.0.0",
|
||||
"@svgr/webpack": "^6.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
||||
"@typescript-eslint/parser": "^5.57.0",
|
||||
"@wojtekmaj/enzyme-adapter-react-17": "^0.8.0",
|
||||
"autoprefixer": "^10.2.4",
|
||||
@@ -28,18 +28,19 @@
|
||||
"babel-loader": "^8.1.0",
|
||||
"browserify": "^17.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"core-js": "^3.2.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.2",
|
||||
"css-minimizer-webpack-plugin": "^3.0.0",
|
||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||
"enzyme": "^3.11.0",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-plugin-react": "^7.20.5",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"exports-loader": "^2.0.0",
|
||||
"exports-loader": "^4.0.0",
|
||||
"html-react-parser": "^1.2.7",
|
||||
"image-minimizer-webpack-plugin": "^2.2.0",
|
||||
"image-minimizer-webpack-plugin": "^3.8.2",
|
||||
"imagemin": "^8.0.1",
|
||||
"imagemin-mozjpeg": "^10.0.0",
|
||||
"imagemin-optipng": "^8.0.0",
|
||||
"imagemin-pngquant": "^9.0.2",
|
||||
@@ -59,7 +60,7 @@
|
||||
"karma-sourcemap-loader": "^0.4.0",
|
||||
"karma-webpack": "^5.0.0",
|
||||
"loader-utils": "^3.2.1",
|
||||
"mini-css-extract-plugin": "^1.3.5",
|
||||
"mini-css-extract-plugin": "^2.7.6",
|
||||
"postcss-loader": "^7.1.0",
|
||||
"process": "^0.11.10",
|
||||
"prop-types": "^15.7.2",
|
||||
@@ -79,7 +80,7 @@
|
||||
"webpack": "^5.76.3",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-cli": "^4.5.0",
|
||||
"yarn-audit-html": "^4.0.0"
|
||||
"yarn-audit-html": "4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
@@ -87,10 +88,10 @@
|
||||
"@date-io/core": "^1.3.6",
|
||||
"@date-io/date-fns": "1.x",
|
||||
"@emotion/sheet": "^1.0.1",
|
||||
"@material-ui/core": "4.11.0",
|
||||
"@material-ui/core": "4.12.4",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "4.0.0-alpha.58",
|
||||
"@material-ui/pickers": "^3.2.10",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@material-ui/pickers": "3.3.10",
|
||||
"@projectstorm/react-diagrams": "^6.6.1",
|
||||
"@simonwep/pickr": "^1.5.1",
|
||||
"@szhsin/react-menu": "^2.2.0",
|
||||
@@ -107,7 +108,7 @@
|
||||
"brace": "^0.11.1",
|
||||
"browserfs": "^1.4.3",
|
||||
"chart.js": "^3.0.0",
|
||||
"chartjs-plugin-zoom": "^1.2.1",
|
||||
"chartjs-plugin-zoom": "^2.0.1",
|
||||
"classnames": "^2.2.6",
|
||||
"closest": "^0.0.1",
|
||||
"codemirror": "^5.59.2",
|
||||
@@ -150,7 +151,7 @@
|
||||
"react-draggable": "^4.4.4",
|
||||
"react-dropzone": "^14.2.1",
|
||||
"react-leaflet": "^3.2.2",
|
||||
"react-resize-detector": "^8.0.3",
|
||||
"react-resize-detector": "^9.1.0",
|
||||
"react-rnd": "^10.3.5",
|
||||
"react-router-dom": "^6.2.2",
|
||||
"react-select": "^5.7.2",
|
||||
@@ -180,7 +181,7 @@
|
||||
"bundle:watch": "yarn run linter && yarn run webpacker:watch",
|
||||
"bundle:dev": "yarn run linter && yarn run webpacker",
|
||||
"bundle:analyze": "cross-env NODE_ENV=production ANALYZE=true yarn run bundle:dev",
|
||||
"bundle": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 yarn run bundle:dev",
|
||||
"bundle": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=2048 yarn run bundle:dev",
|
||||
"test:karma-once": "yarn run linter && yarn run karma start --single-run",
|
||||
"test:karma": "yarn run linter && yarn run karma start",
|
||||
"test:karma-coverage": "yarn run test:karma-once --reporters coverage,progress",
|
||||
@@ -191,5 +192,6 @@
|
||||
"auditjs": "yarn audit --groups dependencies",
|
||||
"auditpy": "safety check --full-report -i 51668 -i 52495",
|
||||
"audit": "yarn run auditjs && yarn run auditpy"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@3.5.0"
|
||||
}
|
||||
@@ -12,6 +12,8 @@ a webserver, this will provide the WSGI interface, otherwise, we're going
|
||||
to start a web server."""
|
||||
|
||||
import sys
|
||||
if sys.version_info <= (3, 9):
|
||||
import select
|
||||
|
||||
if sys.version_info < (3, 4):
|
||||
raise RuntimeError('This application must be run under Python 3.4 '
|
||||
@@ -33,7 +35,7 @@ if 'PGADMIN_SERVER_MODE' in os.environ:
|
||||
else:
|
||||
builtins.SERVER_MODE = None
|
||||
|
||||
if (3, 10) > sys.version_info > (3, 8) and os.name == 'posix':
|
||||
if (3, 10) > sys.version_info > (3, 8, 99) and os.name == 'posix':
|
||||
# Fix eventlet issue with Python 3.9.
|
||||
# Ref: https://github.com/eventlet/eventlet/issues/670
|
||||
# This was causing issue in psycopg3
|
||||
|
||||
@@ -44,7 +44,7 @@ class RdsProvider(AbsProvider):
|
||||
|
||||
def init_args(self, parsers):
|
||||
""" Create the command line parser for this provider """
|
||||
self.parser = parsers.add_parser('rds',
|
||||
self.parser = parsers.add_parser('aws',
|
||||
help='Amazon RDS PostgreSQL',
|
||||
epilog='Credentials are read from '
|
||||
'~/.aws/config by default and '
|
||||
@@ -289,6 +289,10 @@ class AuthSourceManager:
|
||||
if msg is not None and 'username' in msg:
|
||||
self.form._fields['email'].data = msg['username']
|
||||
return status, msg
|
||||
else:
|
||||
current_app.logger.debug(
|
||||
"Authentication initiated via source: %s is failed." %
|
||||
source.get_source_name())
|
||||
|
||||
return status, msg
|
||||
|
||||
|
||||
@@ -106,8 +106,9 @@ class InternalAuthentication(BaseAuthentication):
|
||||
|
||||
def authenticate(self, form):
|
||||
username = form.data['email']
|
||||
user = getattr(form, 'user',
|
||||
User.query.filter_by(username=username).first())
|
||||
if user and user.is_authenticated and form.validate_on_submit():
|
||||
return True, None
|
||||
if form.validate_on_submit():
|
||||
user = getattr(form, 'user',
|
||||
User.query.filter_by(username=username).first())
|
||||
if user and user.is_authenticated:
|
||||
return True, None
|
||||
return False, self.messages('USER_DOES_NOT_EXIST')
|
||||
@@ -137,19 +137,18 @@ class OAuth2Authentication(BaseAuthentication):
|
||||
username = profile[username_claim]
|
||||
else:
|
||||
error_msg = "The claim '%s' is required to login into " \
|
||||
"pgAdmin. Please update your Oauth2 profile." % (
|
||||
"pgAdmin. Please update your OAuth2 profile." % (
|
||||
username_claim)
|
||||
current_app.logger.exception(error_msg)
|
||||
return False, gettext(error_msg)
|
||||
|
||||
if not email or email == '':
|
||||
current_app.logger.exception(
|
||||
"An email id is required to login into pgAdmin. "
|
||||
"Please update your Oauth2 profile."
|
||||
)
|
||||
return False, gettext(
|
||||
"An email id is required to login into pgAdmin. "
|
||||
"Please update your Oauth2 profile.")
|
||||
else:
|
||||
if not email or email == '':
|
||||
error_msg = "An email id or OAUTH2_USERNAME_CLAIM is" \
|
||||
" required to login into pgAdmin. Please update your" \
|
||||
" OAuth2 profile for email id or set" \
|
||||
" OAUTH2_USERNAME_CLAIM config parameter."
|
||||
current_app.logger.exception(error_msg)
|
||||
return False, gettext(error_msg)
|
||||
|
||||
user, msg = self.__auto_create_user(username, email)
|
||||
if user:
|
||||
|
||||
@@ -11,14 +11,18 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from smtplib import SMTPConnectError, SMTPResponseException, \
|
||||
SMTPServerDisconnected, SMTPDataError, SMTPHeloError, SMTPException, \
|
||||
SMTPAuthenticationError, SMTPSenderRefused, SMTPRecipientsRefused
|
||||
from socket import error as SOCKETErrorException
|
||||
from urllib.request import urlopen
|
||||
from pgadmin.utils.constants import KEY_RING_SERVICE_NAME, \
|
||||
KEY_RING_USERNAME_FORMAT, KEY_RING_DESKTOP_USER, KEY_RING_TUNNEL_FORMAT
|
||||
|
||||
import time
|
||||
|
||||
import keyring
|
||||
from flask import current_app, render_template, url_for, make_response, \
|
||||
flash, Response, request, after_this_request, redirect, session
|
||||
from flask_babel import gettext
|
||||
@@ -31,7 +35,7 @@ from flask_security.recoverable import reset_password_token_status, \
|
||||
generate_reset_password_token, update_password
|
||||
from flask_security.signals import reset_password_instructions_sent
|
||||
from flask_security.utils import config_value, do_flash, get_url, \
|
||||
get_message, slash_url_suffix, login_user, send_mail, logout_user, \
|
||||
get_message, slash_url_suffix, login_user, send_mail, \
|
||||
get_post_logout_redirect
|
||||
from flask_security.views import _security, view_commit, _ctx
|
||||
from werkzeug.datastructures import MultiDict
|
||||
@@ -51,11 +55,12 @@ from pgadmin.browser.register_browser_preferences import \
|
||||
from pgadmin.utils.master_password import validate_master_password, \
|
||||
set_masterpass_check_text, cleanup_master_password, get_crypt_key, \
|
||||
set_crypt_key, process_masterpass_disabled
|
||||
from pgadmin.model import User
|
||||
from pgadmin.model import User, db
|
||||
from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE,\
|
||||
INTERNAL, KERBEROS, LDAP, QT_DEFAULT_PLACEHOLDER, OAUTH2, WEBSERVER,\
|
||||
VW_EDT_DEFAULT_PLACEHOLDER
|
||||
from pgadmin.authenticate import AuthSourceManager
|
||||
from pgadmin.utils.exception import CryptKeyMissing
|
||||
|
||||
try:
|
||||
from flask_security.views import default_render_json
|
||||
@@ -741,11 +746,15 @@ def get_nodes():
|
||||
return make_json_response(data=nodes)
|
||||
|
||||
|
||||
def form_master_password_response(existing=True, present=False, errmsg=None):
|
||||
def form_master_password_response(existing=True, present=False, errmsg=None,
|
||||
keyring_name='',
|
||||
invalid_master_password_hook=False):
|
||||
return make_json_response(data={
|
||||
'present': present,
|
||||
'reset': existing,
|
||||
'errmsg': errmsg,
|
||||
'keyring_name': keyring_name,
|
||||
'invalid_master_password_hook': invalid_master_password_hook,
|
||||
'is_error': True if errmsg else False
|
||||
})
|
||||
|
||||
@@ -780,8 +789,19 @@ def reset_master_password():
|
||||
Removes the master password and remove all saved passwords
|
||||
This password will be used to encrypt/decrypt saved server passwords
|
||||
"""
|
||||
if not config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
# This is to set the Desktop user password so it will not ask for
|
||||
# migrate exiting passwords as those are getting cleared
|
||||
keyring.set_password(KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_DESKTOP_USER.format(
|
||||
current_user.username), 'test')
|
||||
cleanup_master_password()
|
||||
return make_json_response(data=get_crypt_key()[0])
|
||||
status, crypt_key = get_crypt_key()
|
||||
# Set masterpass_check if MASTER_PASSWORD_HOOK is set which provides
|
||||
# encryption key
|
||||
if config.MASTER_PASSWORD_REQUIRED and config.MASTER_PASSWORD_HOOK:
|
||||
set_masterpass_check_text(crypt_key)
|
||||
return make_json_response(data=status)
|
||||
|
||||
|
||||
@blueprint.route("/master_password", endpoint="set_master_password",
|
||||
@@ -804,9 +824,133 @@ def set_master_password():
|
||||
if data != '':
|
||||
data = json.loads(data)
|
||||
|
||||
# Master password is not applicable for server mode
|
||||
# Enable master password if oauth is used
|
||||
if not config.SERVER_MODE or OAUTH2 in config.AUTHENTICATION_SOURCES \
|
||||
if not config.DISABLED_LOCAL_PASSWORD_STORAGE and \
|
||||
(config.ALLOW_SAVE_PASSWORD or config.ALLOW_SAVE_TUNNEL_PASSWORD):
|
||||
if data.get('password') and config.MASTER_PASSWORD_REQUIRED and\
|
||||
not validate_master_password(data.get('password')):
|
||||
return form_master_password_response(
|
||||
present=False,
|
||||
keyring_name=config.KEYRING_NAME,
|
||||
errmsg=gettext("Incorrect master password")
|
||||
)
|
||||
from pgadmin.model import Server
|
||||
from pgadmin.utils.crypto import decrypt
|
||||
desktop_user = current_user
|
||||
|
||||
enc_key = data['password']
|
||||
if not config.MASTER_PASSWORD_REQUIRED:
|
||||
status, enc_key = get_crypt_key()
|
||||
if not status:
|
||||
raise CryptKeyMissing
|
||||
|
||||
try:
|
||||
all_server = Server.query.all()
|
||||
# pgAdmin will use the OS password manager to store the server
|
||||
# password, here migrating the existing saved server password to
|
||||
# OS password manager
|
||||
if keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME, KEY_RING_DESKTOP_USER.format(
|
||||
desktop_user.username)) or enc_key:
|
||||
is_migrated = False
|
||||
|
||||
for server in all_server:
|
||||
if enc_key:
|
||||
if server.password and config.ALLOW_SAVE_PASSWORD \
|
||||
and server.save_password:
|
||||
name = KEY_RING_USERNAME_FORMAT.format(server.name,
|
||||
server.id)
|
||||
password = decrypt(server.password,
|
||||
enc_key).decode()
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(KEY_RING_SERVICE_NAME, name,
|
||||
password)
|
||||
is_migrated = True
|
||||
setattr(server, 'password', None)
|
||||
|
||||
if server.tunnel_password and \
|
||||
config.ALLOW_SAVE_TUNNEL_PASSWORD:
|
||||
tname = KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id)
|
||||
tpassword = decrypt(server.tunnel_password,
|
||||
enc_key).decode()
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(KEY_RING_SERVICE_NAME, tname,
|
||||
tpassword)
|
||||
is_migrated = True
|
||||
setattr(server, 'tunnel_password', None)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_DESKTOP_USER.format(
|
||||
desktop_user.username), 'test')
|
||||
return form_master_password_response(
|
||||
existing=True,
|
||||
present=True,
|
||||
keyring_name=config.KEYRING_NAME if is_migrated else ''
|
||||
)
|
||||
else:
|
||||
if len(all_server) == 0:
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_DESKTOP_USER.format(
|
||||
desktop_user.username), 'test')
|
||||
return form_master_password_response(
|
||||
present=True,
|
||||
)
|
||||
else:
|
||||
is_master_password_present = True
|
||||
keyring_name = ''
|
||||
for server in all_server:
|
||||
is_password_present = \
|
||||
server.save_password or server.tunnel_password
|
||||
if server.password and is_password_present:
|
||||
is_master_password_present = False
|
||||
keyring_name = config.KEYRING_NAME
|
||||
break
|
||||
|
||||
if is_master_password_present:
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_DESKTOP_USER.format(
|
||||
desktop_user.username),
|
||||
'test')
|
||||
|
||||
return form_master_password_response(
|
||||
present=is_master_password_present,
|
||||
keyring_name=keyring_name
|
||||
)
|
||||
except Exception as e:
|
||||
current_app.logger.warning(
|
||||
'Fail set password using OS password manager'
|
||||
', fallback to master password. Error: {0}'.format(e)
|
||||
)
|
||||
config.DISABLED_LOCAL_PASSWORD_STORAGE = True
|
||||
|
||||
# If the master password is required and the master password hook
|
||||
# is specified then try to retrieve the encryption key and update data.
|
||||
# If there is an error while retrieving it, return an error message.
|
||||
if config.SERVER_MODE and config.MASTER_PASSWORD_REQUIRED and \
|
||||
config.MASTER_PASSWORD_HOOK:
|
||||
status, enc_key = get_crypt_key()
|
||||
if status:
|
||||
data = {'password': enc_key, 'submit_password': True}
|
||||
else:
|
||||
error = gettext('The master password could not be retrieved from '
|
||||
'the MASTER_PASSWORD_HOOK utility specified {0}.'
|
||||
'Please check that the hook utility is configured'
|
||||
' correctly.'.format(config.MASTER_PASSWORD_HOOK))
|
||||
return form_master_password_response(
|
||||
existing=False,
|
||||
present=False,
|
||||
errmsg=error,
|
||||
invalid_master_password_hook=True
|
||||
)
|
||||
|
||||
# Master password is applicable for Desktop mode and in server mode
|
||||
# only when auth sources are oauth, kerberos, webserver.
|
||||
if (not config.SERVER_MODE) or OAUTH2 in config.AUTHENTICATION_SOURCES \
|
||||
or KERBEROS in config.AUTHENTICATION_SOURCES \
|
||||
or WEBSERVER in config.AUTHENTICATION_SOURCES \
|
||||
and config.MASTER_PASSWORD_REQUIRED:
|
||||
@@ -814,12 +958,18 @@ def set_master_password():
|
||||
if current_user.masterpass_check is not None and \
|
||||
data.get('submit_password', False) and \
|
||||
not validate_master_password(data.get('password')):
|
||||
errmsg = '' if config.MASTER_PASSWORD_HOOK \
|
||||
else gettext("Incorrect master password")
|
||||
invalid_master_password_hook = \
|
||||
True if config.MASTER_PASSWORD_HOOK else False
|
||||
return form_master_password_response(
|
||||
existing=True,
|
||||
present=False,
|
||||
errmsg=gettext("Incorrect master password")
|
||||
errmsg=errmsg,
|
||||
invalid_master_password_hook=invalid_master_password_hook
|
||||
)
|
||||
|
||||
# if master password received in request
|
||||
if data != '' and data.get('password', '') != '':
|
||||
|
||||
# store the master pass in the memory
|
||||
@@ -840,16 +990,23 @@ def set_master_password():
|
||||
# master pass
|
||||
set_masterpass_check_text(data.get('password'))
|
||||
|
||||
# If password in request is empty then try to get it with
|
||||
# get_crypt_key method. If get_crypt_key() returns false status and
|
||||
# masterpass_check is already set, provide a pop to enter
|
||||
# master password(present) without the reset option.(existing).
|
||||
elif not get_crypt_key()[0] and \
|
||||
current_user.masterpass_check is not None:
|
||||
return form_master_password_response(
|
||||
existing=True,
|
||||
present=False,
|
||||
)
|
||||
|
||||
# If get_crypt_key return True,but crypt_key is none and
|
||||
# user entered blank password, return error message.
|
||||
elif not get_crypt_key()[1]:
|
||||
error_message = None
|
||||
# If user attempted to enter a blank password, then throw error
|
||||
if data.get('submit_password') and data.get('password') == '':
|
||||
# If user attempted to enter a blank password, then throw error
|
||||
error_message = gettext("Master password cannot be empty")
|
||||
return form_master_password_response(
|
||||
existing=False,
|
||||
@@ -1080,7 +1237,8 @@ if hasattr(config, 'SECURITY_RECOVERABLE') and config.SECURITY_RECOVERABLE:
|
||||
if invalid or expired:
|
||||
return redirect(url_for('browser.forgot_password'))
|
||||
has_error = False
|
||||
form = _security.reset_password_form()
|
||||
form_class = _security.forms.get('reset_password_form').cls
|
||||
form = form_class(request.form) if request.form else form_class()
|
||||
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
|
||||
@@ -16,6 +16,9 @@ from pgadmin.browser.utils import PGChildModule
|
||||
from pgadmin.utils import PgAdminModule
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.utils.constants import PGADMIN_NODE
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.browser.utils import PGChildNodeView
|
||||
|
||||
|
||||
class CollectionNodeModule(PgAdminModule, PGChildModule, metaclass=ABCMeta):
|
||||
@@ -94,6 +97,42 @@ class CollectionNodeModule(PgAdminModule, PGChildModule, metaclass=ABCMeta):
|
||||
|
||||
return obj
|
||||
|
||||
def has_nodes(self, sid, did, scid=None, tid=None, vid=None,
|
||||
base_template_path=''):
|
||||
if self.pref_show_empty_coll_nodes.get():
|
||||
return True
|
||||
|
||||
try:
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
manager = driver.connection_manager(sid)
|
||||
conn = manager.connection(did=did)
|
||||
if '{1}' in base_template_path:
|
||||
template_base_path = base_template_path.format(
|
||||
manager.server_type, manager.version)
|
||||
else:
|
||||
template_base_path = base_template_path.format(manager.version)
|
||||
|
||||
last_system_oid = 0 if self.show_system_objects else \
|
||||
PGChildNodeView._DATABASE_LAST_SYSTEM_OID
|
||||
|
||||
sql = render_template(
|
||||
"/".join([template_base_path, PGChildNodeView._COUNT_SQL]),
|
||||
did=did,
|
||||
scid=scid,
|
||||
tid=tid,
|
||||
vid=vid,
|
||||
datlastsysoid=last_system_oid,
|
||||
showsysobj=self.show_system_objects,
|
||||
conn=conn
|
||||
)
|
||||
|
||||
status, res = conn.execute_dict(sql)
|
||||
|
||||
return int(res['rows'][0]['count']) > 0 if status \
|
||||
else True
|
||||
except Exception as _:
|
||||
return True
|
||||
|
||||
@property
|
||||
def node_type(self):
|
||||
return '%s' % (self._NODE_TYPE)
|
||||
@@ -239,3 +278,6 @@ class CollectionNodeModule(PgAdminModule, PGChildModule, metaclass=ABCMeta):
|
||||
self.collection_label, 'node', self.SHOW_ON_BROWSER,
|
||||
category_label=gettext('Nodes')
|
||||
)
|
||||
self.pref_show_empty_coll_nodes = self.browser_preference.preference(
|
||||
'show_empty_coll_nodes'
|
||||
)
|
||||
@@ -10,7 +10,8 @@ import sys
|
||||
from flask_babel import gettext
|
||||
from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\
|
||||
PREF_LABEL_KEYBOARD_SHORTCUTS, PREF_LABEL_TABS_SETTINGS, \
|
||||
PREF_LABEL_OPTIONS, QT_DEFAULT_PLACEHOLDER, VW_EDT_DEFAULT_PLACEHOLDER
|
||||
PREF_LABEL_OPTIONS, QT_DEFAULT_PLACEHOLDER, VW_EDT_DEFAULT_PLACEHOLDER, \
|
||||
PREF_LABEL_BREADCRUMBS
|
||||
from flask import current_app
|
||||
import config
|
||||
|
||||
@@ -28,6 +29,16 @@ def register_browser_preferences(self):
|
||||
category_label=PREF_LABEL_DISPLAY
|
||||
)
|
||||
|
||||
self.show_empty_coll_nodes = self.preference.register(
|
||||
'display', 'show_empty_coll_nodes',
|
||||
gettext("Show empty object collections?"), 'boolean', True,
|
||||
category_label=PREF_LABEL_DISPLAY,
|
||||
help_str=gettext(
|
||||
'If turned off, then all object collections which are empty '
|
||||
'will be hidden from browser tree.'
|
||||
)
|
||||
)
|
||||
|
||||
self.show_user_defined_templates = self.preference.register(
|
||||
'display', 'show_user_defined_templates',
|
||||
gettext("Show template databases?"), 'boolean', False,
|
||||
@@ -332,36 +343,6 @@ def register_browser_preferences(self):
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'grid_menu_drop_multiple',
|
||||
gettext('Delete/Drop multiple objects'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 77, 'char': 'm'}
|
||||
},
|
||||
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'grid_menu_drop_cascade_multiple',
|
||||
gettext('Drop Cascade multiple objects'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 85, 'char': 'u'}
|
||||
},
|
||||
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'context_menu',
|
||||
@@ -557,3 +538,25 @@ def register_browser_preferences(self):
|
||||
' back to the default title with placeholders.'
|
||||
)
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'breadcrumbs', 'breadcrumbs_enable',
|
||||
gettext("Enable object breadcrumbs?"),
|
||||
'boolean',
|
||||
True, category_label=PREF_LABEL_BREADCRUMBS,
|
||||
help_str=gettext(
|
||||
'Enable breadcrumbs to show the complete path of an object in the '
|
||||
'object explorer. The breadcrumbs are displayed on object mouse '
|
||||
'hover.'
|
||||
)
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'breadcrumbs', 'breadcrumbs_show_comment',
|
||||
gettext("Show comment with object breadcrumbs?"),
|
||||
'boolean',
|
||||
True, category_label=PREF_LABEL_BREADCRUMBS,
|
||||
help_str=gettext(
|
||||
'Show object comment along with breadcrumbs.'
|
||||
)
|
||||
)
|
||||
@@ -33,8 +33,12 @@ from pgadmin.utils.constants import UNAUTH_REQ, MIMETYPE_APP_JS, \
|
||||
SERVER_CONNECTION_CLOSED
|
||||
from sqlalchemy import or_
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.utils.constants import KEY_RING_SERVICE_NAME, \
|
||||
KEY_RING_USERNAME_FORMAT, KEY_RING_TUNNEL_FORMAT, KEY_RING_DESKTOP_USER
|
||||
from .... import socketio as sio
|
||||
|
||||
import keyring
|
||||
|
||||
|
||||
def has_any(data, keys):
|
||||
"""
|
||||
@@ -245,6 +249,21 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
current_app.logger.exception(e)
|
||||
errmsg = str(e)
|
||||
|
||||
is_password_saved = bool(server.save_password)
|
||||
is_tunnel_password_saved = bool(server.tunnel_password)
|
||||
|
||||
if not config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
sname = KEY_RING_USERNAME_FORMAT.format(server.name, server.id)
|
||||
spassword = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME, sname)
|
||||
|
||||
is_password_saved = bool(spassword)
|
||||
tunnelname = KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id)
|
||||
tunnel_password = keyring.get_password(KEY_RING_SERVICE_NAME,
|
||||
tunnelname)
|
||||
is_tunnel_password_saved = bool(tunnel_password)
|
||||
|
||||
yield self.generate_browser_node(
|
||||
"%d" % (server.id),
|
||||
gid,
|
||||
@@ -261,9 +280,8 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
wal_pause=wal_paused,
|
||||
host=server.host,
|
||||
port=server.port,
|
||||
is_password_saved=bool(server.save_password),
|
||||
is_tunnel_password_saved=True
|
||||
if server.tunnel_password is not None else False,
|
||||
is_password_saved=is_password_saved,
|
||||
is_tunnel_password_saved=is_tunnel_password_saved,
|
||||
was_connected=was_connected,
|
||||
errmsg=errmsg,
|
||||
user_id=server.user_id,
|
||||
@@ -271,7 +289,8 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
shared=server.shared,
|
||||
is_kerberos_conn=bool(server.kerberos_conn),
|
||||
gss_authenticated=manager.gss_authenticated,
|
||||
cloud_status=server.cloud_status
|
||||
cloud_status=server.cloud_status,
|
||||
description=server.comment
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -572,6 +591,22 @@ class ServerNode(PGChildNodeView):
|
||||
manager.release()
|
||||
errmsg = "{0} : {1}".format(server.name, result)
|
||||
|
||||
is_password_saved = bool(server.save_password)
|
||||
is_tunnel_password_saved = bool(server.tunnel_password)
|
||||
|
||||
if not config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
sname = KEY_RING_USERNAME_FORMAT.format(server.name, server.id)
|
||||
spassword = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME, sname)
|
||||
|
||||
is_password_saved = bool(spassword)
|
||||
|
||||
tunnelname = KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id)
|
||||
tunnel_password = keyring.get_password(KEY_RING_SERVICE_NAME,
|
||||
tunnelname)
|
||||
is_tunnel_password_saved = bool(tunnel_password)
|
||||
|
||||
res.append(
|
||||
self.blueprint.generate_browser_node(
|
||||
"%d" % (server.id),
|
||||
@@ -588,14 +623,14 @@ class ServerNode(PGChildNodeView):
|
||||
user=manager.user_info if connected else None,
|
||||
in_recovery=in_recovery,
|
||||
wal_pause=wal_paused,
|
||||
is_password_saved=bool(server.save_password),
|
||||
is_tunnel_password_saved=True
|
||||
if server.tunnel_password is not None else False,
|
||||
is_password_saved=is_password_saved,
|
||||
is_tunnel_password_saved=is_tunnel_password_saved,
|
||||
errmsg=errmsg,
|
||||
username=server.username,
|
||||
shared=server.shared,
|
||||
is_kerberos_conn=bool(server.kerberos_conn),
|
||||
gss_authenticated=manager.gss_authenticated
|
||||
gss_authenticated=manager.gss_authenticated,
|
||||
description=server.comment
|
||||
)
|
||||
)
|
||||
|
||||
@@ -712,6 +747,20 @@ class ServerNode(PGChildNodeView):
|
||||
server_name = s.name
|
||||
get_driver(PG_DEFAULT_DRIVER).delete_manager(s.id)
|
||||
db.session.delete(s)
|
||||
if not config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
try:
|
||||
sname = KEY_RING_USERNAME_FORMAT.format(
|
||||
s.name,
|
||||
s.id)
|
||||
# Get password form OS password manager
|
||||
is_present = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME, sname)
|
||||
# Delete saved password from OS password manager
|
||||
if is_present:
|
||||
keyring.delete_password(KEY_RING_SERVICE_NAME,
|
||||
sname)
|
||||
except keyring.errors.KeyringError as e:
|
||||
config.DISABLED_LOCAL_PASSWORD_STORAGE = True
|
||||
db.session.commit()
|
||||
self.delete_shared_server(server_name, gid, sid)
|
||||
QueryHistory.clear_history(current_user.id, sid)
|
||||
@@ -782,6 +831,10 @@ class ServerNode(PGChildNodeView):
|
||||
data = request.form if request.form else json.loads(
|
||||
request.data
|
||||
)
|
||||
|
||||
old_server_name = ''
|
||||
if 'name' in data:
|
||||
old_server_name = server.name
|
||||
if 'db_res' in data:
|
||||
data['db_res'] = ','.join(data['db_res'])
|
||||
|
||||
@@ -814,6 +867,25 @@ class ServerNode(PGChildNodeView):
|
||||
)
|
||||
|
||||
try:
|
||||
if len(old_server_name) and old_server_name != server.name and \
|
||||
not config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
# If server name is changed then update keyring with
|
||||
# new server name
|
||||
password = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_USERNAME_FORMAT.format(old_server_name,
|
||||
server.id))
|
||||
|
||||
keyring.set_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_USERNAME_FORMAT.format(server.name, server.id),
|
||||
password)
|
||||
|
||||
server_name = KEY_RING_USERNAME_FORMAT.format(
|
||||
old_server_name, server.id)
|
||||
# Delete saved password from OS password manager
|
||||
keyring.delete_password(KEY_RING_SERVICE_NAME,
|
||||
server_name)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
@@ -846,7 +918,8 @@ class ServerNode(PGChildNodeView):
|
||||
server_type='pg', # default server type
|
||||
username=server.username,
|
||||
role=server.role,
|
||||
is_password_saved=bool(server.save_password)
|
||||
is_password_saved=bool(server.save_password),
|
||||
description=server.comment
|
||||
)
|
||||
)
|
||||
|
||||
@@ -975,20 +1048,20 @@ class ServerNode(PGChildNodeView):
|
||||
shared_server)
|
||||
server_owner = server.server_owner
|
||||
|
||||
use_ssh_tunnel = 0
|
||||
use_ssh_tunnel = False
|
||||
tunnel_host = None
|
||||
tunnel_port = 22
|
||||
tunnel_username = None
|
||||
tunnel_authentication = 0
|
||||
tunnel_authentication = False
|
||||
connection_params = \
|
||||
self.convert_connection_parameter(server.connection_params)
|
||||
|
||||
if server.use_ssh_tunnel:
|
||||
use_ssh_tunnel = server.use_ssh_tunnel
|
||||
use_ssh_tunnel = bool(server.use_ssh_tunnel)
|
||||
tunnel_host = server.tunnel_host
|
||||
tunnel_port = server.tunnel_port
|
||||
tunnel_username = server.tunnel_username
|
||||
tunnel_authentication = server.tunnel_authentication
|
||||
tunnel_authentication = bool(server.tunnel_authentication)
|
||||
|
||||
response = {
|
||||
'id': server.id,
|
||||
@@ -1049,10 +1122,11 @@ class ServerNode(PGChildNodeView):
|
||||
if data[item] == '':
|
||||
data[item] = None
|
||||
|
||||
# Get enc key
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
if not crypt_key_present:
|
||||
raise CryptKeyMissing
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
# Get enc key
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
if not crypt_key_present:
|
||||
raise CryptKeyMissing
|
||||
|
||||
# Some fields can be provided with service file so they are optional
|
||||
if 'service' in data and not data['service']:
|
||||
@@ -1144,7 +1218,9 @@ class ServerNode(PGChildNodeView):
|
||||
# login with password
|
||||
have_password = True
|
||||
password = data['password']
|
||||
password = encrypt(password, crypt_key)
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
password = encrypt(password, crypt_key)
|
||||
|
||||
elif 'passfile' in data['connection_params'] and \
|
||||
data['connection_params']['passfile'] != '':
|
||||
passfile = data['connection_params']['passfile']
|
||||
@@ -1152,8 +1228,10 @@ class ServerNode(PGChildNodeView):
|
||||
if 'tunnel_password' in data and data["tunnel_password"] != '':
|
||||
have_tunnel_password = True
|
||||
tunnel_password = data['tunnel_password']
|
||||
tunnel_password = \
|
||||
encrypt(tunnel_password, crypt_key)
|
||||
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
tunnel_password = \
|
||||
encrypt(tunnel_password, crypt_key)
|
||||
|
||||
status, errmsg = conn.connect(
|
||||
password=password,
|
||||
@@ -1174,15 +1252,31 @@ class ServerNode(PGChildNodeView):
|
||||
else:
|
||||
if 'save_password' in data and data['save_password'] and \
|
||||
have_password and config.ALLOW_SAVE_PASSWORD:
|
||||
setattr(server, 'password', password)
|
||||
db.session.commit()
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
setattr(server, 'password', password)
|
||||
db.session.commit()
|
||||
else:
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_USERNAME_FORMAT.format(server.name,
|
||||
server.id),
|
||||
password)
|
||||
|
||||
if 'save_tunnel_password' in data and \
|
||||
data['save_tunnel_password'] and \
|
||||
have_tunnel_password and \
|
||||
config.ALLOW_SAVE_TUNNEL_PASSWORD:
|
||||
setattr(server, 'tunnel_password', tunnel_password)
|
||||
db.session.commit()
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
setattr(server, 'tunnel_password', tunnel_password)
|
||||
db.session.commit()
|
||||
else:
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id),
|
||||
tunnel_password)
|
||||
|
||||
user = manager.user_info
|
||||
connected = True
|
||||
@@ -1206,7 +1300,9 @@ class ServerNode(PGChildNodeView):
|
||||
else None,
|
||||
is_kerberos_conn=bool(server.kerberos_conn),
|
||||
gss_authenticated=manager.gss_authenticated if
|
||||
manager and manager.gss_authenticated else False
|
||||
manager and manager.gss_authenticated else False,
|
||||
is_password_saved=bool(server.save_password),
|
||||
is_tunnel_password_saved=bool(server.tunnel_password)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1376,18 +1472,33 @@ class ServerNode(PGChildNodeView):
|
||||
manager.update(server)
|
||||
conn = manager.connection()
|
||||
|
||||
# Get enc key
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
if not crypt_key_present:
|
||||
raise CryptKeyMissing
|
||||
crypt_key = None
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE or \
|
||||
not keyring.get_password(KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_DESKTOP_USER.format(
|
||||
current_user.username)):
|
||||
# Get enc key
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
if not crypt_key_present:
|
||||
raise CryptKeyMissing
|
||||
|
||||
# If server using SSH Tunnel
|
||||
if server.use_ssh_tunnel:
|
||||
|
||||
if 'tunnel_password' not in data:
|
||||
if server.tunnel_password is None:
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE \
|
||||
and server.tunnel_password is None:
|
||||
prompt_tunnel_password = True
|
||||
else:
|
||||
tunnel_password = server.tunnel_password
|
||||
if not config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
# Get password form OS password manager
|
||||
tunnel_password = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id))
|
||||
prompt_tunnel_password = not bool(tunnel_password)
|
||||
else:
|
||||
tunnel_password = server.tunnel_password
|
||||
else:
|
||||
tunnel_password = data['tunnel_password'] \
|
||||
if 'tunnel_password' in data else ''
|
||||
@@ -1397,9 +1508,11 @@ class ServerNode(PGChildNodeView):
|
||||
# Encrypt the password before saving with user's login
|
||||
# password key.
|
||||
try:
|
||||
tunnel_password = encrypt(tunnel_password, crypt_key) \
|
||||
if tunnel_password is not None else \
|
||||
server.tunnel_password
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
tunnel_password = encrypt(tunnel_password, crypt_key) \
|
||||
if tunnel_password is not None else \
|
||||
server.tunnel_password
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
@@ -1420,20 +1533,38 @@ class ServerNode(PGChildNodeView):
|
||||
elif passfile_param and passfile_param != '':
|
||||
passfile = passfile_param
|
||||
else:
|
||||
password = conn_passwd or server.password
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
password = conn_passwd or server.password
|
||||
else:
|
||||
# Get password form OS password manager
|
||||
password = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_USERNAME_FORMAT.format(server.name,
|
||||
server.id))
|
||||
else:
|
||||
password = data['password'] if 'password' in data else None
|
||||
save_password = data['save_password']\
|
||||
if 'save_password' in data else False
|
||||
|
||||
# Encrypt the password before saving with user's login
|
||||
# password key.
|
||||
try:
|
||||
password = encrypt(password, crypt_key) \
|
||||
if password is not None else server.password
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
try:
|
||||
# Encrypt the password before saving with user's login
|
||||
# password key.
|
||||
password = encrypt(password, crypt_key) \
|
||||
if password is not None else server.password
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
elif save_password and config.ALLOW_SAVE_PASSWORD:
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_USERNAME_FORMAT.format(
|
||||
server.name, server.id), password)
|
||||
# Get password form OS password manager
|
||||
password = keyring.get_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_USERNAME_FORMAT.format(server.name, server.id))
|
||||
|
||||
# Check do we need to prompt for the database server or ssh tunnel
|
||||
# password or both. Return the password template in case password is
|
||||
@@ -1483,7 +1614,7 @@ class ServerNode(PGChildNodeView):
|
||||
|
||||
# Save the encrypted password using the user's login
|
||||
# password key, if there is any password to save
|
||||
if password:
|
||||
if password and config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'password', password)
|
||||
else:
|
||||
@@ -1499,8 +1630,18 @@ class ServerNode(PGChildNodeView):
|
||||
|
||||
if save_tunnel_password and config.ALLOW_SAVE_TUNNEL_PASSWORD:
|
||||
try:
|
||||
# Save the encrypted tunnel password.
|
||||
setattr(server, 'tunnel_password', tunnel_password)
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
# Save the encrypted tunnel password.
|
||||
setattr(server, 'tunnel_password', tunnel_password)
|
||||
else:
|
||||
# Store the password using OS password manager
|
||||
keyring.set_password(
|
||||
KEY_RING_SERVICE_NAME,
|
||||
KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id),
|
||||
tunnel_password)
|
||||
setattr(server, 'tunnel_password', None)
|
||||
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
# Release Connection
|
||||
@@ -1790,7 +1931,7 @@ class ServerNode(PGChildNodeView):
|
||||
try:
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
|
||||
msg = None
|
||||
# Execute SQL to pause or resume WAL replay
|
||||
if conn.connected():
|
||||
if pause:
|
||||
@@ -1803,6 +1944,7 @@ class ServerNode(PGChildNodeView):
|
||||
return internal_server_error(
|
||||
errormsg=str(res)
|
||||
)
|
||||
msg = gettext('WAL replay paused')
|
||||
else:
|
||||
sql = "SELECT pg_xlog_replay_resume();"
|
||||
if manager.version >= 100000:
|
||||
@@ -1813,9 +1955,10 @@ class ServerNode(PGChildNodeView):
|
||||
return internal_server_error(
|
||||
errormsg=str(res)
|
||||
)
|
||||
msg = gettext('WAL replay resumed')
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext('WAL replay paused'),
|
||||
info=msg,
|
||||
data={'in_recovery': True, 'wal_pause': pause}
|
||||
)
|
||||
return gone(errormsg=gettext('Please connect the server.'))
|
||||
@@ -1970,9 +2113,24 @@ class ServerNode(PGChildNodeView):
|
||||
server = ServerModule. \
|
||||
get_shared_server_properties(server, shared_server)
|
||||
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'save_password', None)
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
if server.shared and server.user_id != current_user.id:
|
||||
setattr(shared_server, 'save_password', None)
|
||||
else:
|
||||
setattr(server, 'save_password', None)
|
||||
else:
|
||||
try:
|
||||
server_name = KEY_RING_USERNAME_FORMAT.format(server.name,
|
||||
server.id)
|
||||
# Get password form OS password manager
|
||||
is_present = keyring.get_password(KEY_RING_SERVICE_NAME,
|
||||
server_name)
|
||||
if is_present:
|
||||
# Delete saved password from OS password manager
|
||||
keyring.delete_password(KEY_RING_SERVICE_NAME,
|
||||
server_name)
|
||||
except keyring.errors.KeyringError as e:
|
||||
config.DISABLED_LOCAL_PASSWORD_STORAGE = True
|
||||
setattr(server, 'save_password', None)
|
||||
|
||||
# If password was saved then clear the flag also
|
||||
@@ -2012,9 +2170,19 @@ class ServerNode(PGChildNodeView):
|
||||
success=0,
|
||||
info=self.not_found_error_msg()
|
||||
)
|
||||
|
||||
setattr(server, 'tunnel_password', None)
|
||||
db.session.commit()
|
||||
if config.DISABLED_LOCAL_PASSWORD_STORAGE:
|
||||
setattr(server, 'tunnel_password', None)
|
||||
db.session.commit()
|
||||
else:
|
||||
server_name = KEY_RING_TUNNEL_FORMAT.format(server.name,
|
||||
server.id)
|
||||
# Get password form OS password manager
|
||||
is_present = keyring.get_password(KEY_RING_SERVICE_NAME,
|
||||
server_name)
|
||||
if is_present:
|
||||
# Delete saved password from OS password manager
|
||||
keyring.delete_password(KEY_RING_SERVICE_NAME, server_name)
|
||||
setattr(server, 'tunnel_password', None)
|
||||
except Exception as e:
|
||||
current_app.logger.error(
|
||||
"Unable to clear ssh tunnel password."
|
||||
|
||||
@@ -195,7 +195,9 @@ class DatabaseView(PGChildNodeView):
|
||||
],
|
||||
'vopts': [
|
||||
{}, {'get': 'variable_options'}
|
||||
]
|
||||
],
|
||||
'delete': [{'delete': 'delete'},
|
||||
{'delete': 'delete'}]
|
||||
})
|
||||
|
||||
def check_precondition(action=None):
|
||||
@@ -386,7 +388,8 @@ class DatabaseView(PGChildNodeView):
|
||||
canDisconn=can_dis_conn,
|
||||
canDrop=can_drop,
|
||||
isTemplate=row['is_template'],
|
||||
inode=True if row['datallowconn'] else False
|
||||
inode=True if row['datallowconn'] else False,
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1001,7 +1004,8 @@ class DatabaseView(PGChildNodeView):
|
||||
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, self._DELETE_SQL]),
|
||||
datname=res, conn=self.conn
|
||||
datname=res, conn=self.conn,
|
||||
with_force=self.cmd == 'delete'
|
||||
)
|
||||
|
||||
status, msg = default_conn.execute_scalar(sql)
|
||||
|
||||
@@ -60,7 +60,9 @@ class CastModule(CollectionNodeModule):
|
||||
:param sid: server id
|
||||
:param did: database id
|
||||
"""
|
||||
yield self.generate_browser_collection_node(did)
|
||||
if self.has_nodes(sid, did,
|
||||
base_template_path=CastView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(did)
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
@@ -148,6 +150,7 @@ class CastView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
"""
|
||||
|
||||
node_type = blueprint.node_type
|
||||
BASE_TEMPLATE_PATH = 'casts/sql/#{0}#'
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
@@ -208,7 +211,8 @@ class CastView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
).connection_manager(kwargs['sid'])
|
||||
self.conn = self.manager.connection(did=kwargs['did'])
|
||||
# Set template path for the SQL scripts
|
||||
self.template_path = 'casts/sql/#{0}#'.format(self.manager.version)
|
||||
self.template_path = self.BASE_TEMPLATE_PATH.format(
|
||||
self.manager.version)
|
||||
|
||||
self.datistemplate = False
|
||||
if (
|
||||
@@ -282,7 +286,8 @@ class CastView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
icon="icon-cast"
|
||||
icon="icon-cast",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -449,12 +454,17 @@ class CastView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
cid,
|
||||
did,
|
||||
name,
|
||||
"icon-{0}".format(self.node_type)
|
||||
"icon-{0}".format(self.node_type),
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
SELECT COUNT(*)
|
||||
FROM pg_catalog.pg_cast ca
|
||||
WHERE 1=1
|
||||
{# Check for Show system object #}
|
||||
{% if (not showsysobj) and datlastsysoid %}
|
||||
AND ca.oid > {{datlastsysoid}}::OID
|
||||
{% endif %}
|
||||
@@ -1,6 +1,7 @@
|
||||
SELECT
|
||||
ca.oid,
|
||||
pg_catalog.concat(pg_catalog.format_type(st.oid,NULL),'->',pg_catalog.format_type(tt.oid,tt.typtypmod)) as name
|
||||
pg_catalog.concat(pg_catalog.format_type(st.oid,NULL),'->',pg_catalog.format_type(tt.oid,tt.typtypmod)) as name,
|
||||
des.description
|
||||
FROM pg_catalog.pg_cast ca
|
||||
JOIN pg_catalog.pg_type st ON st.oid=castsource
|
||||
JOIN pg_catalog.pg_namespace ns ON ns.oid=st.typnamespace
|
||||
|
||||
@@ -65,7 +65,10 @@ class EventTriggerModule(CollectionNodeModule):
|
||||
"""
|
||||
Generate the event_trigger node
|
||||
"""
|
||||
yield self.generate_browser_collection_node(sid)
|
||||
if self.has_nodes(
|
||||
sid, did,
|
||||
base_template_path=EventTriggerView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(sid)
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
@@ -149,6 +152,7 @@ class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
node_type = blueprint.node_type
|
||||
node_icon = "icon-%s" % blueprint.node_type
|
||||
BASE_TEMPLATE_PATH = 'event_triggers/sql/#{0}#'
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
@@ -194,7 +198,7 @@ class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
PG_DEFAULT_DRIVER
|
||||
).connection_manager(kwargs['sid'])
|
||||
self.conn = self.manager.connection(did=kwargs['did'])
|
||||
self.template_path = 'event_triggers/sql/#{0}#'.format(
|
||||
self.template_path = self.BASE_TEMPLATE_PATH.format(
|
||||
self.manager.version)
|
||||
|
||||
self.datistemplate = False
|
||||
@@ -264,7 +268,8 @@ class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
self.node_icon
|
||||
self.node_icon,
|
||||
description=row['comment']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -481,12 +486,17 @@ class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
status, etid = self.conn.execute_scalar(sql)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
etid,
|
||||
did,
|
||||
data['name'],
|
||||
self.node_icon
|
||||
self.node_icon,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
SELECT COUNT(*)
|
||||
FROM pg_catalog.pg_event_trigger e
|
||||
@@ -1,4 +1,5 @@
|
||||
SELECT e.oid, e.evtname AS name
|
||||
SELECT e.oid, e.evtname AS name,
|
||||
pg_catalog.obj_description(e.oid, 'pg_event_trigger') AS comment
|
||||
FROM pg_catalog.pg_event_trigger e
|
||||
{% if etid %}
|
||||
WHERE e.oid={{etid}}::oid
|
||||
|
||||
@@ -48,7 +48,9 @@ class ExtensionModule(CollectionNodeModule):
|
||||
"""
|
||||
Generate the collection node
|
||||
"""
|
||||
yield self.generate_browser_collection_node(did)
|
||||
if self.has_nodes(sid, did,
|
||||
base_template_path=ExtensionView.EXT_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(did)
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
@@ -188,7 +190,8 @@ class ExtensionView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
'icon-extension'
|
||||
'icon-extension',
|
||||
description=row['comment']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -327,12 +330,17 @@ class ExtensionView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
eid,
|
||||
did,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
SELECT COUNT(*)
|
||||
FROM pg_catalog.pg_extension x
|
||||
WHERE 1=1
|
||||
@@ -75,7 +75,10 @@ class ForeignDataWrapperModule(CollectionNodeModule):
|
||||
sid: Server ID
|
||||
did: Database Id
|
||||
"""
|
||||
yield self.generate_browser_collection_node(did)
|
||||
if self.has_nodes(
|
||||
sid, did,
|
||||
base_template_path=ForeignDataWrapperView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(did)
|
||||
|
||||
@property
|
||||
def script_load(self):
|
||||
@@ -179,6 +182,7 @@ class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
"""
|
||||
|
||||
node_type = blueprint.node_type
|
||||
BASE_TEMPLATE_PATH = 'foreign_data_wrappers/sql/#{0}#'
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
@@ -235,7 +239,7 @@ class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
kwargs['did']]['datistemplate']
|
||||
|
||||
# Set the template path for the SQL scripts
|
||||
self.template_path = 'foreign_data_wrappers/sql/#{0}#'.format(
|
||||
self.template_path = self.BASE_TEMPLATE_PATH.format(
|
||||
self.manager.version
|
||||
)
|
||||
|
||||
@@ -299,7 +303,8 @@ class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
icon="icon-foreign_data_wrapper"
|
||||
icon="icon-foreign_data_wrapper",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -505,12 +510,17 @@ class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
fid,
|
||||
did,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
@@ -290,7 +290,8 @@ class ForeignServerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
row['oid'],
|
||||
fid,
|
||||
row['name'],
|
||||
icon="icon-foreign_server"
|
||||
icon="icon-foreign_server",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -503,12 +504,17 @@ class ForeignServerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
fsid,
|
||||
fid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
SELECT COUNT(*)
|
||||
FROM pg_catalog.pg_foreign_data_wrapper fdw
|
||||
@@ -74,7 +74,10 @@ class LanguageModule(CollectionNodeModule):
|
||||
sid: Server ID
|
||||
did: Database Id
|
||||
"""
|
||||
yield self.generate_browser_collection_node(did)
|
||||
if self.has_nodes(
|
||||
sid, did,
|
||||
base_template_path=LanguageView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(did)
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
@@ -175,6 +178,7 @@ class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
_NOT_FOUND_LANG_INFORMATION = \
|
||||
gettext("Could not find the language information.")
|
||||
node_type = blueprint.node_type
|
||||
BASE_TEMPLATE_PATH = "languages/sql/#{0}#"
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
@@ -241,7 +245,7 @@ class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
# Set the template path for the SQL scripts
|
||||
self.template_path = (
|
||||
"languages/sql/#{0}#".format(self.manager.version)
|
||||
self.BASE_TEMPLATE_PATH.format(self.manager.version)
|
||||
)
|
||||
|
||||
return f(*args, **kwargs)
|
||||
@@ -296,7 +300,8 @@ class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
icon="icon-language"
|
||||
icon="icon-language",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -434,12 +439,17 @@ class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
lid,
|
||||
did,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
SELECT COUNT(*)
|
||||
FROM
|
||||
pg_catalog.pg_language lan JOIN pg_catalog.pg_proc hp ON hp.oid=lanplcallfoid
|
||||
WHERE lanispl IS TRUE
|
||||
@@ -12,7 +12,7 @@ import json
|
||||
from functools import wraps
|
||||
|
||||
from pgadmin.browser.server_groups.servers import databases
|
||||
from flask import render_template, request, jsonify
|
||||
from flask import render_template, request, jsonify, current_app as app
|
||||
from flask_babel import gettext
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
from pgadmin.browser.utils import PGChildNodeView
|
||||
@@ -21,8 +21,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from urllib.parse import unquote
|
||||
|
||||
|
||||
class PublicationModule(CollectionNodeModule):
|
||||
@@ -73,7 +71,10 @@ class PublicationModule(CollectionNodeModule):
|
||||
sid: Server ID
|
||||
did: Database Id
|
||||
"""
|
||||
yield self.generate_browser_collection_node(did)
|
||||
if self.has_nodes(
|
||||
sid, did,
|
||||
base_template_path=PublicationView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(did)
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
@@ -167,6 +168,7 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
_NOT_FOUND_PUB_INFORMATION = \
|
||||
gettext("Could not find the publication information.")
|
||||
node_type = blueprint.node_type
|
||||
BASE_TEMPLATE_PATH = 'publications/{0}/#{1}#/sql'
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
@@ -188,7 +190,9 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
'stats': [{'get': 'statistics'}],
|
||||
'dependency': [{'get': 'dependencies'}],
|
||||
'dependent': [{'get': 'dependents'}],
|
||||
'get_schemas': [{}, {'get': 'get_schemas'}],
|
||||
'get_tables': [{}, {'get': 'get_tables'}],
|
||||
'get_all_columns': [{}, {'get': 'get_all_columns'}],
|
||||
'delete': [{'delete': 'delete'}, {'delete': 'delete'}]
|
||||
})
|
||||
|
||||
@@ -222,9 +226,8 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
self.manager = self.driver.connection_manager(kwargs['sid'])
|
||||
self.conn = self.manager.connection(did=kwargs['did'])
|
||||
# Set the template path for the SQL scripts
|
||||
self.template_path = (
|
||||
"publications/sql/#{0}#".format(self.manager.version)
|
||||
)
|
||||
self.template_path = self.BASE_TEMPLATE_PATH.format(
|
||||
self.manager.server_type, self.manager.version)
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
@@ -249,22 +252,16 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
return internal_server_error(errormsg=res)
|
||||
for rows in res['rows']:
|
||||
if not rows['all_table']:
|
||||
get_name_sql = render_template(
|
||||
"/".join([self.template_path, self._DELETE_SQL]),
|
||||
pbid=rows['oid'], conn=self.conn
|
||||
)
|
||||
status, pname = self.conn.execute_scalar(get_name_sql)
|
||||
table_sql = render_template(
|
||||
"/".join([self.template_path,
|
||||
self._GET_TABLE_FOR_PUBLICATION]),
|
||||
pname=pname
|
||||
pbid=rows['oid']
|
||||
)
|
||||
|
||||
pub_table = []
|
||||
status, table_res = self.conn.execute_dict(table_sql)
|
||||
|
||||
for table in table_res['rows']:
|
||||
pub_table.append(table['pubtable'])
|
||||
pub_table = \
|
||||
[table['table_name'] for table in table_res['rows']]
|
||||
|
||||
pub_table = ", ".join(str(elem) for elem in pub_table)
|
||||
|
||||
@@ -381,24 +378,42 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
return False, gone(self._NOT_FOUND_PUB_INFORMATION)
|
||||
|
||||
if not res['rows'][0]['all_table']:
|
||||
get_name_sql = render_template(
|
||||
"/".join([self.template_path, self._DELETE_SQL]),
|
||||
pbid=pbid, conn=self.conn
|
||||
)
|
||||
status, pname = self.conn.execute_scalar(get_name_sql)
|
||||
if self.manager.version >= 150000:
|
||||
schema_name_sql = render_template(
|
||||
"/".join([self.template_path, 'get_pub_schemas.sql']),
|
||||
pbid=pbid
|
||||
)
|
||||
status, snames_list_res = self.conn.execute_dict(
|
||||
schema_name_sql)
|
||||
|
||||
if len(snames_list_res['rows']) != 0:
|
||||
res['rows'][0]['pubschema'] = \
|
||||
[sname_dict['sname'] for sname_dict
|
||||
in snames_list_res['rows']]
|
||||
|
||||
table_sql = render_template(
|
||||
"/".join([self.template_path,
|
||||
self._GET_TABLE_FOR_PUBLICATION]),
|
||||
pname=pname
|
||||
pbid=pbid
|
||||
)
|
||||
|
||||
pub_table = []
|
||||
pub_table_names_list = []
|
||||
status, table_res = self.conn.execute_dict(table_sql)
|
||||
|
||||
for table in table_res['rows']:
|
||||
pub_table.append(table['pubtable'])
|
||||
pub_table_names_list.append(table['table_name'])
|
||||
if 'columns' in table and 'where' in table:
|
||||
pub_table.append({
|
||||
'table_name': table['table_name'],
|
||||
'columns': table['columns'],
|
||||
'where': table['where'],
|
||||
})
|
||||
else:
|
||||
pub_table.append(table['table_name'])
|
||||
|
||||
res['rows'][0]['pubtable'] = pub_table
|
||||
res['rows'][0]['pubtable_names'] = pub_table_names_list
|
||||
|
||||
return True, res['rows'][0]
|
||||
|
||||
@@ -626,21 +641,74 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
"""
|
||||
drop_table_data = []
|
||||
add_table_data = []
|
||||
update_table_data = []
|
||||
drop_table = False
|
||||
add_table = False
|
||||
update_table = False
|
||||
|
||||
for table in old_data['pubtable']:
|
||||
if 'pubtable' in data and table not in data['pubtable']:
|
||||
drop_table_data.append(table)
|
||||
drop_table = True
|
||||
if self.manager.version < 150000:
|
||||
for table in old_data['pubtable']:
|
||||
if 'pubtable' in data and table not in data['pubtable']:
|
||||
drop_table_data.append(table)
|
||||
drop_table = True
|
||||
|
||||
if 'pubtable' in data:
|
||||
for table in data['pubtable']:
|
||||
if table not in old_data['pubtable']:
|
||||
if 'pubtable' in data:
|
||||
for table in data['pubtable']:
|
||||
if table not in old_data['pubtable']:
|
||||
add_table_data.append(table)
|
||||
add_table = True
|
||||
elif self.manager.version >= 150000:
|
||||
if 'pubtable' in data and 'deleted' in data['pubtable']:
|
||||
for table in data['pubtable']['deleted']:
|
||||
drop_table_data.append(table)
|
||||
drop_table = True
|
||||
|
||||
if 'pubtable' in data and 'changed' in data['pubtable']:
|
||||
update_table_data = [*old_data['pubtable']]
|
||||
for index, table1 in enumerate(old_data['pubtable']):
|
||||
for table2 in data['pubtable']['changed']:
|
||||
if table1['table_name'] == table2['table_name']:
|
||||
update_table_data[index] = table2
|
||||
update_table = True
|
||||
break
|
||||
|
||||
if 'pubtable' in data and 'added' in data['pubtable']:
|
||||
for table in data['pubtable']['added']:
|
||||
add_table_data.append(table)
|
||||
add_table = True
|
||||
|
||||
return drop_table, add_table, drop_table_data, add_table_data
|
||||
return drop_table, add_table, update_table, drop_table_data, \
|
||||
add_table_data, update_table_data
|
||||
|
||||
def _get_schema_details_to_add_and_delete(self, old_data, data):
|
||||
"""
|
||||
This function returns the schemas which need to add and delete
|
||||
:param old_data:
|
||||
:param data:
|
||||
:return:
|
||||
"""
|
||||
drop_schema_data = []
|
||||
add_schema_data = []
|
||||
drop_schema = False
|
||||
add_schema = False
|
||||
|
||||
if 'pubschema' in old_data:
|
||||
for schema in old_data['pubschema']:
|
||||
if 'pubschema' in data and schema not in data['pubschema']:
|
||||
drop_schema_data.append(schema)
|
||||
drop_schema = True
|
||||
|
||||
if 'pubschema' in data:
|
||||
for schema in data['pubschema']:
|
||||
if 'pubschema' in old_data and \
|
||||
schema not in old_data['pubschema']:
|
||||
add_schema_data.append(schema)
|
||||
add_schema = True
|
||||
elif 'pubschema' not in old_data:
|
||||
add_schema_data.append(schema)
|
||||
add_schema = True
|
||||
|
||||
return drop_schema, add_schema, drop_schema_data, add_schema_data
|
||||
|
||||
def get_sql(self, data, pbid=None):
|
||||
"""
|
||||
@@ -664,11 +732,33 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if len(res['rows']) == 0:
|
||||
return gone(self._NOT_FOUND_PUB_INFORMATION)
|
||||
|
||||
old_data = self._get_old_table_data(res['rows'][0]['name'], res)
|
||||
snames_list = []
|
||||
|
||||
drop_table, add_table, drop_table_data, add_table_data = \
|
||||
if self.manager.version >= 150000:
|
||||
schema_name_sql = render_template(
|
||||
"/".join([self.template_path, 'get_pub_schemas.sql']),
|
||||
pbid=pbid
|
||||
)
|
||||
status, snames_list_res = self.conn.execute_dict(
|
||||
schema_name_sql)
|
||||
|
||||
if len(snames_list_res['rows']) != 0:
|
||||
snames_list = [sname_dict['sname'] for sname_dict
|
||||
in snames_list_res['rows']]
|
||||
|
||||
old_data = self._get_old_table_data(res['rows'][0]['name'], res,
|
||||
snames_list)
|
||||
|
||||
if len(snames_list) != 0:
|
||||
old_data['pubschema'] = snames_list
|
||||
|
||||
drop_table, add_table, update_table, drop_table_data, \
|
||||
add_table_data, update_table_data = \
|
||||
self._get_table_details_to_add_and_delete(old_data, data)
|
||||
|
||||
drop_schema, add_schema, drop_schema_data, add_schema_data = \
|
||||
self._get_schema_details_to_add_and_delete(old_data, data)
|
||||
|
||||
for arg in required_args:
|
||||
if arg not in data:
|
||||
data[arg] = old_data[arg]
|
||||
@@ -680,7 +770,10 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
"/".join([self.template_path, self._UPDATE_SQL]),
|
||||
data=data, o_data=old_data, conn=self.conn,
|
||||
drop_table=drop_table, drop_table_data=drop_table_data,
|
||||
add_table=add_table, add_table_data=add_table_data
|
||||
add_table=add_table, add_table_data=add_table_data,
|
||||
update_table=update_table, update_table_data=update_table_data,
|
||||
drop_schema=drop_schema, drop_schema_data=drop_schema_data,
|
||||
add_schema=add_schema, add_schema_data=add_schema_data,
|
||||
)
|
||||
return sql.strip('\n'), data['name'] if 'name' in data \
|
||||
else old_data['name']
|
||||
@@ -691,6 +784,39 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
data=data, conn=self.conn)
|
||||
return sql.strip('\n'), data['name']
|
||||
|
||||
@check_precondition
|
||||
def get_schemas(self, gid, sid, did):
|
||||
"""
|
||||
This function will return the list of schemas for the specified
|
||||
server group id, server id and database id.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
did: Database ID
|
||||
"""
|
||||
res = []
|
||||
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, 'get_all_schemas.sql']),
|
||||
conn=self.conn
|
||||
)
|
||||
status, rset = self.conn.execute_2darray(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
res.append(
|
||||
{
|
||||
'label': row['nspname'],
|
||||
'value': row['nspname'],
|
||||
}
|
||||
)
|
||||
return make_json_response(
|
||||
data=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def get_tables(self, gid, sid, did):
|
||||
"""
|
||||
@@ -711,12 +837,14 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
status, rset = self.conn.execute_2darray(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
res.append(
|
||||
{
|
||||
'label': row['table'],
|
||||
'value': row['table']
|
||||
'value': row['table'],
|
||||
'tid': row['tid']
|
||||
}
|
||||
)
|
||||
return make_json_response(
|
||||
@@ -724,24 +852,64 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
status=200
|
||||
)
|
||||
|
||||
def _get_old_table_data(self, pname, res):
|
||||
@check_precondition
|
||||
def get_all_columns(self, gid, sid, did):
|
||||
"""
|
||||
This function returns the columns list.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
did: Database ID
|
||||
tid: Table ID
|
||||
"""
|
||||
data = request.args
|
||||
|
||||
res = []
|
||||
|
||||
sql = render_template("/".join([self.template_path,
|
||||
'get_all_columns.sql']),
|
||||
tid=data['tid'], conn=self.conn)
|
||||
status, rset = self.conn.execute_2darray(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
for row in rset['rows']:
|
||||
res.append(
|
||||
{
|
||||
'label': row['column'],
|
||||
'value': row['column'],
|
||||
}
|
||||
)
|
||||
return make_json_response(
|
||||
data=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
def _get_old_table_data(self, pname, res, exempt_schema_list=[]):
|
||||
"""
|
||||
This function return table details before update
|
||||
:param pname:
|
||||
:param res:
|
||||
:return:old_data
|
||||
"""
|
||||
|
||||
table_sql = render_template(
|
||||
"/".join([self.template_path, self._GET_TABLE_FOR_PUBLICATION]),
|
||||
pname=pname
|
||||
"/".join([self.template_path,
|
||||
self._GET_TABLE_FOR_PUBLICATION]),
|
||||
pbid=res['rows'][0]['oid']
|
||||
)
|
||||
|
||||
pub_table = []
|
||||
status, table_res = self.conn.execute_dict(table_sql)
|
||||
|
||||
for table in table_res['rows']:
|
||||
pub_table.append(table['pubtable'])
|
||||
if 'columns' in table and 'where' in table:
|
||||
pub_table.append({
|
||||
'table_name': table['table_name'],
|
||||
'columns': table['columns'],
|
||||
'where': table['where'],
|
||||
})
|
||||
else:
|
||||
pub_table.append(table['table_name'])
|
||||
|
||||
res['rows'][0]['pubtable'] = pub_table
|
||||
|
||||
@@ -777,6 +945,20 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
if len(res['rows']) == 0:
|
||||
return gone(self._NOT_FOUND_PUB_INFORMATION)
|
||||
|
||||
snames_list = []
|
||||
|
||||
if self.manager.version >= 150000:
|
||||
schema_name_sql = render_template(
|
||||
"/".join([self.template_path, 'get_pub_schemas.sql']),
|
||||
pbid=pbid
|
||||
)
|
||||
status, snames_list_res = self.conn.execute_dict(
|
||||
schema_name_sql)
|
||||
|
||||
if len(snames_list_res['rows']) != 0:
|
||||
snames_list = [sname_dict['sname'] for sname_dict
|
||||
in snames_list_res['rows']]
|
||||
|
||||
get_name_sql = render_template(
|
||||
"/".join([self.template_path, self._DELETE_SQL]),
|
||||
pbid=pbid, conn=self.conn
|
||||
@@ -784,7 +966,10 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
status, pname = self.conn.execute_scalar(get_name_sql)
|
||||
|
||||
# Get old table details
|
||||
old_data = self._get_old_table_data(pname, res)
|
||||
old_data = self._get_old_table_data(pname, res, snames_list)
|
||||
|
||||
if len(snames_list) != 0:
|
||||
old_data['pubschema'] = snames_list
|
||||
|
||||
sql = render_template("/".join([self.template_path,
|
||||
self._CREATE_SQL]),
|
||||
@@ -936,5 +1121,4 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, PublicationView, 'Database')
|
||||
PublicationView.register_node_view(blueprint)
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getNodeAjaxOptions, getNodeListByName } from '../../../../../../static/js/node_ajax';
|
||||
import { getNodeAjaxOptions,getNodeListByName } from '../../../../../../static/js/node_ajax';
|
||||
import PublicationSchema from './publication.ui';
|
||||
|
||||
define('pgadmin.node.publication', [
|
||||
@@ -23,7 +23,6 @@ define('pgadmin.node.publication', [
|
||||
label: gettext('Publications'),
|
||||
type: 'coll-publication',
|
||||
columns: ['name', 'pubowner', 'pubtable', 'all_table'],
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,6 +39,7 @@ define('pgadmin.node.publication', [
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
hasDepends: true,
|
||||
width: pgBrowser.stdW.md + 'px',
|
||||
|
||||
Init: function() {
|
||||
|
||||
@@ -69,12 +69,13 @@ define('pgadmin.node.publication', [
|
||||
data: {action: 'create'},
|
||||
}]);
|
||||
},
|
||||
|
||||
|
||||
|
||||
getSchema: function(treeNodeInfo, itemNodeData){
|
||||
return new PublicationSchema(
|
||||
{
|
||||
publicationTable: ()=>getNodeAjaxOptions('get_tables', this, treeNodeInfo, itemNodeData),
|
||||
allTables: ()=>getNodeAjaxOptions('get_tables', this, treeNodeInfo, itemNodeData),
|
||||
allSchemas:()=>getNodeAjaxOptions('get_schemas', this, treeNodeInfo, itemNodeData),
|
||||
getColumns: (params)=>getNodeAjaxOptions('get_all_columns', this, treeNodeInfo, itemNodeData,{urlParams: params, useCache:false}),
|
||||
role:()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
},{
|
||||
node_info: treeNodeInfo.server,
|
||||
|
||||
@@ -10,7 +10,6 @@ import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class DefaultWithSchema extends BaseUISchema {
|
||||
constructor(node_info) {
|
||||
super();
|
||||
@@ -33,21 +32,126 @@ export class DefaultWithSchema extends BaseUISchema {
|
||||
},{
|
||||
id: 'evnt_truncate', label: gettext('TRUNCATE'),
|
||||
type: 'switch', group: gettext('With'),
|
||||
visible: function() {
|
||||
return !_.isUndefined(this.node_info['node_info'])
|
||||
&& !_.isUndefined(this.node_info['node_info'].version)
|
||||
&& this.node_info['node_info'].version >= 110000;
|
||||
},
|
||||
|
||||
min_version: 110000,
|
||||
},{
|
||||
id: 'publish_via_partition_root', label: gettext('Publish via root?'),
|
||||
type: 'switch', group: gettext('With'),
|
||||
visible: function() {
|
||||
return !_.isUndefined(this.node_info['node_info'])
|
||||
&& !_.isUndefined(this.node_info['node_info'].version)
|
||||
&& this.node_info['node_info'].version >= 130000;
|
||||
min_version: 130000,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export class PublicationTableSchema extends BaseUISchema {
|
||||
constructor(allTables,getColumns) {
|
||||
super({
|
||||
table_name: undefined,
|
||||
where: undefined,
|
||||
columns:undefined,
|
||||
});
|
||||
this.allTables = allTables;
|
||||
this.getColumns=getColumns;
|
||||
this.allTablesOptions = [];
|
||||
this.varTypes = {};
|
||||
this.allReadOnly = false;
|
||||
}
|
||||
|
||||
isConnected(state) {
|
||||
return Boolean(state.connected);
|
||||
}
|
||||
|
||||
getPlaceHolderMsg(variable) {
|
||||
let msg = '';
|
||||
if (variable?.min_server_version && variable?.max_server_version) {
|
||||
msg = gettext('%s <= Supported version >= %s', variable?.max_server_version, variable?.min_server_version);
|
||||
} else if (variable?.min_server_version) {
|
||||
msg = gettext('Supported version >= %s', variable?.min_server_version);
|
||||
} else if (variable?.max_server_version) {
|
||||
msg = gettext('Supported version <= %s', variable?.max_server_version);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
getTableOid(tabName) {
|
||||
// Here we will fetch the table oid from table name
|
||||
// iterate over list to find table oid
|
||||
for(const t of this.allTablesOptions) {
|
||||
if(t.label === tabName) {
|
||||
return t.tid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isTableName(state){
|
||||
return Boolean(state.table_name);
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [
|
||||
{
|
||||
id: 'table_name',
|
||||
label: gettext('Table Name'),
|
||||
type: 'select',
|
||||
noEmpty: true,
|
||||
disabled:function (state) {
|
||||
return !obj.isNew(state);
|
||||
},
|
||||
editable: function (state) {
|
||||
return obj.isNew(state) || !obj.allReadOnly;
|
||||
},
|
||||
cell: () => ({
|
||||
cell: 'select',
|
||||
options: this.allTables,
|
||||
optionsLoaded: (options) => {
|
||||
obj.allTablesOptions=options;
|
||||
},
|
||||
controlProps: { allowClear: false },
|
||||
}),
|
||||
},
|
||||
}];
|
||||
{
|
||||
id: 'columns',
|
||||
label: gettext('Columns'),
|
||||
type: 'select',
|
||||
deps:['table_name'],
|
||||
disabled: (state) => !obj.isTableName(state),
|
||||
depChange: (state) => {
|
||||
if(!state.table_name) {
|
||||
return {
|
||||
columns: null,
|
||||
};
|
||||
}
|
||||
},
|
||||
editable: function (state) {
|
||||
return obj.isNew(state) || !obj.allReadOnly;
|
||||
},
|
||||
cell: (state) => {
|
||||
let tid = obj.getTableOid(state.table_name);
|
||||
return{
|
||||
cell: 'select',
|
||||
options: (state.table_name && tid) ? ()=>obj.getColumns({tid: tid}) : [],
|
||||
optionsReloadBasis: tid,
|
||||
controlProps: { allowClear: true, multiple: true},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'where',
|
||||
label: gettext('Where'),
|
||||
type: 'sql',
|
||||
deps: ['table_name'],
|
||||
disabled: (state) => !obj.isTableName(state),
|
||||
editable: function (state) {
|
||||
return obj.isNew(state) || !obj.allReadOnly;
|
||||
},
|
||||
cell: () => ({
|
||||
cell: 'sql',
|
||||
controlProps: {
|
||||
lineWrapping: true,
|
||||
}
|
||||
}),
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +159,11 @@ export default class PublicationSchema extends BaseUISchema {
|
||||
constructor(fieldOptions={}, node_info={}, initValues={}) {
|
||||
super({
|
||||
name: undefined,
|
||||
pubowner: (node_info) ? node_info['node_info'].user.name: undefined,
|
||||
pubtable: undefined,
|
||||
all_table: undefined,
|
||||
pubowner: (node_info) ? node_info['node_info']?.user.name: undefined,
|
||||
pubtable: [],
|
||||
pubtable_names: [],
|
||||
pubschema: undefined,
|
||||
all_table: false,
|
||||
evnt_insert:true,
|
||||
evnt_delete:true,
|
||||
evnt_update:true,
|
||||
@@ -69,11 +175,16 @@ export default class PublicationSchema extends BaseUISchema {
|
||||
|
||||
this.fieldOptions = {
|
||||
role: [],
|
||||
publicationTable: [],
|
||||
allTables: [],
|
||||
allSchemas:[],
|
||||
...fieldOptions,
|
||||
};
|
||||
this.node_info = node_info;
|
||||
this.paramSchema = new PublicationTableSchema(this.fieldOptions.allTables, this.fieldOptions.getColumns);
|
||||
this.version=!_.isUndefined(this.node_info['node_info']) && !_.isUndefined(this.node_info['node_info'].version) && this.node_info['node_info'].version;
|
||||
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
return 'oid';
|
||||
}
|
||||
@@ -81,7 +192,9 @@ export default class PublicationSchema extends BaseUISchema {
|
||||
isAllTable(state) {
|
||||
let allTable = state.all_table;
|
||||
if(allTable){
|
||||
state.pubtable = '';
|
||||
state.pubtable = [];
|
||||
state.pubtable_names = '';
|
||||
state.pubschema = undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -101,16 +214,40 @@ export default class PublicationSchema extends BaseUISchema {
|
||||
return true;
|
||||
}
|
||||
|
||||
isColumn(state){
|
||||
let table=state.pubtable, columnsList=[];
|
||||
if(!_.isUndefined(table) && table.length > 0){
|
||||
table?.forEach(i=>{
|
||||
if(i.columns!=undefined && i.columns.length!==0){
|
||||
columnsList.push(i.columns);
|
||||
}
|
||||
});
|
||||
if(columnsList?.length > 0){
|
||||
state.pubschema=undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isConnected(state) {
|
||||
return Boolean(state.connected);
|
||||
}
|
||||
|
||||
getVersion(){
|
||||
return (
|
||||
!_.isUndefined(this.node_info['node_info']) &&
|
||||
!_.isUndefined(this.node_info['node_info'].version) &&
|
||||
this.node_info['node_info'].version
|
||||
);
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [{
|
||||
id: 'name', label: gettext('Name'), type: 'text',
|
||||
mode: ['properties', 'create', 'edit'], noEmpty: true,
|
||||
visible: function() {
|
||||
return !_.isUndefined(this.node_info['node_info'])
|
||||
&& !_.isUndefined(this.node_info['node_info'].version)
|
||||
&& this.node_info['node_info'].version >= 100000;
|
||||
},
|
||||
min_version: 100000,
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string', mode: ['properties'],
|
||||
type: 'text',
|
||||
@@ -123,26 +260,56 @@ export default class PublicationSchema extends BaseUISchema {
|
||||
mode: ['edit', 'properties', 'create'], controlProps: { allowClear: false},
|
||||
},{
|
||||
id: 'all_table', label: gettext('All tables?'), type: 'switch',
|
||||
group: gettext('Definition'), mode: ['edit', 'properties', 'create'], deps: ['name'],
|
||||
group: gettext('Tables'), mode: ['edit', 'properties', 'create'], deps: ['name'],
|
||||
readonly: (state) => {return !obj.isNew(state);},
|
||||
},{
|
||||
id: 'only_table', label: gettext('Only table?'), type: 'switch',
|
||||
group: gettext('Definition'), mode: ['edit', 'create'],
|
||||
deps: ['name', 'pubtable', 'all_table'], readonly: obj.isTable,
|
||||
group: gettext('Tables'), mode: ['edit', 'create'],
|
||||
deps: ['name', 'pubtable', 'all_table'], readonly: (state) => {
|
||||
if(obj.isNew(state))
|
||||
return obj.isTable(state);
|
||||
else
|
||||
return true;
|
||||
},
|
||||
helpMessageMode: ['edit', 'create'],
|
||||
helpMessage: gettext('If ONLY is specified before the table name, only that table is added to the publication. If ONLY is not specified, the table and all its descendant tables (if any) are added.'),
|
||||
},{
|
||||
id: 'pubtable', label: gettext('Tables'), type: 'select',
|
||||
id: 'pubschema', label: gettext('Tables in Schema'), type: 'select',
|
||||
controlProps: { allowClear: true, multiple: true, creatable: true },
|
||||
options: this.fieldOptions.publicationTable,
|
||||
group: gettext('Definition'), mode: ['edit', 'create', 'properties'],
|
||||
options: this.fieldOptions.allSchemas, deps: ['all_table','pubtable'],
|
||||
disabled: (state)=>{return obj.isColumn(state) || obj.isAllTable(state);},
|
||||
group: this.version < 150000 ? null : gettext('Tables'), mode: ['edit', 'create', 'properties'],
|
||||
min_version: 150000,
|
||||
},
|
||||
{
|
||||
id: 'pubtable_names', label: gettext('Tables'), cell: 'string',
|
||||
type: (state)=>{
|
||||
let table= (!_.isUndefined(state?.pubtable_names) && state?.pubtable_names.length > 0) ? state?.pubtable_names : [];
|
||||
return {
|
||||
type: 'select',
|
||||
options: table,
|
||||
controlProps: { allowClear: true, multiple: true, creatable: true },
|
||||
};
|
||||
},
|
||||
group: gettext('Tables'), mode: ['properties'],
|
||||
deps: ['all_table'], disabled: obj.isAllTable,
|
||||
},{
|
||||
},
|
||||
{
|
||||
id: 'pubtable', label: this.version < 150000 ? gettext('Tables') : gettext(''),
|
||||
type: this.version < 150000 ? 'select' : 'collection',
|
||||
controlProps: this.version < 150000 ? { allowClear: true, multiple: true, creatable: true } : null,
|
||||
options: this.version < 150000 ? this.fieldOptions.allTables : [],
|
||||
group: gettext('Tables'), mode: ['edit', 'create'],
|
||||
deps: ['all_table'], disabled: obj.isAllTable, schema: this.version < 150000 ? null : this.paramSchema,
|
||||
uniqueCol: this.version < 150000 ? null : ['table_name'],
|
||||
canAdd: this.version < 150000 ? null : (state)=> !obj.isConnected(state),
|
||||
canDelete: this.version<150000?null : (state)=> !obj.isConnected(state),
|
||||
},
|
||||
{
|
||||
type: 'nested-fieldset', mode: ['create','edit', 'properties'],
|
||||
label: gettext('With'), group: gettext('Definition'),
|
||||
label: gettext('With'), group: gettext('Options'),
|
||||
schema : new DefaultWithSchema(this.node_info),
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{% if data.evnt_delete or data.evnt_update or data.evnt_truncate %}
|
||||
{% set add_comma_after_insert = 'insert' %}
|
||||
{% endif %}
|
||||
{% if data.evnt_truncate %}
|
||||
{% set add_comma_after_delete = 'delete' %}
|
||||
{% endif %}
|
||||
{% if data.evnt_delete or data.evnt_truncate%}
|
||||
{% set add_comma_after_update = 'update' %}
|
||||
{% endif %}
|
||||
{% if data.publish_via_partition_root%}
|
||||
{% set add_comma_after_truncate = 'truncate' %}
|
||||
{% endif %}
|
||||
{### Create PUBLICATION ###}
|
||||
CREATE PUBLICATION {{ conn|qtIdent(data.name) }}
|
||||
{% if data.all_table %}
|
||||
FOR ALL TABLES
|
||||
{% elif data.pubtable or data.pubschema %}
|
||||
FOR {% if data.pubtable %}TABLE {% if data.only_table%}ONLY {% endif %}{% for pub_table in data.pubtable %}{% if loop.index != 1 %}, {% endif %}{{pub_table['table_name']}}{% if pub_table['columns'] %} ({% for column in pub_table['columns'] %}{% if loop.index != 1 %}, {% endif %}{{column}}{% endfor %}){% endif %}{% if pub_table['where'] %} WHERE ({{pub_table['where']}}){% endif %}{% endfor %}{% endif %}{% if data.pubtable and data.pubschema %},{% endif %}
|
||||
{% if data.pubschema %}
|
||||
TABLES IN SCHEMA {% for pub_schema in data.pubschema %}{% if loop.index != 1 %}, {% endif %}{{ pub_schema }}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if data.evnt_insert or data.evnt_update or data.evnt_delete or data.evnt_truncate %}
|
||||
WITH (publish = '{% if data.evnt_insert %}insert{% if add_comma_after_insert == 'insert' %}, {% endif %}{% endif %}{% if data.evnt_update %}update{% if add_comma_after_update == 'update' %}, {% endif %}{% endif %}{% if data.evnt_delete %}delete{% if add_comma_after_delete == 'delete' %}, {% endif %}{% endif %}{% if data.evnt_truncate %}truncate{% endif %}', publish_via_partition_root = {{ data.publish_via_partition_root|lower }});
|
||||
{% endif %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
|
||||
SELECT
|
||||
nsp.nspname
|
||||
FROM
|
||||
pg_catalog.pg_namespace nsp
|
||||
WHERE
|
||||
nspname NOT LIKE E'pg\\_%' AND
|
||||
NOT ({{ CATALOGS.LIST('nsp') }})
|
||||
ORDER BY nspname;
|
||||
@@ -0,0 +1,4 @@
|
||||
SELECT n.nspname AS sname
|
||||
FROM pg_catalog.pg_publication_namespace pubnsp
|
||||
JOIN pg_catalog.pg_namespace n ON pubnsp.pnnspid = n.oid
|
||||
WHERE pnpubid = {{pbid}} :: oid;
|
||||
@@ -0,0 +1,6 @@
|
||||
SELECT pg_catalog.quote_ident(n.nspname) || '.' || pg_catalog.quote_ident(cls.relname) AS table_name,
|
||||
(SELECT array_agg(attname) FROM pg_attribute att WHERE attrelid = prel.prrelid AND attnum IN (SELECT unnest(prattrs) FROM pg_publication_rel WHERE oid = prel.oid ) ) AS columns,
|
||||
pg_catalog.pg_get_expr(prel.prqual, prel.prrelid) AS where
|
||||
FROM pg_publication_rel prel
|
||||
JOIN pg_class cls ON cls.oid = prel.prrelid
|
||||
JOIN pg_catalog.pg_namespace n ON cls.relnamespace = n.oid WHERE prel.prpubid = {{pbid}} :: oid;
|
||||
@@ -0,0 +1,67 @@
|
||||
{% if data.evnt_delete or data.evnt_update or data.evnt_truncate %}
|
||||
{% set add_comma_after_insert = 'insert' %}
|
||||
{% endif %}
|
||||
{% if data.evnt_truncate %}
|
||||
{% set add_comma_after_delete = 'delete' %}
|
||||
{% endif %}
|
||||
{% if data.evnt_delete or data.evnt_truncate%}
|
||||
{% set add_comma_after_update = 'update' %}
|
||||
{% endif %}
|
||||
{### Alter publication owner ###}
|
||||
{% if data.pubowner %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
OWNER TO {{ conn|qtIdent(data.pubowner) }};
|
||||
|
||||
{% endif %}
|
||||
{### Alter publication event ###}
|
||||
{% if (data.evnt_insert is defined and data.evnt_insert != o_data.evnt_insert) or (data.evnt_update is defined and data.evnt_update != o_data.evnt_update) or (data.evnt_delete is defined and data.evnt_delete != o_data.evnt_delete) or (data.evnt_truncate is defined and data.evnt_truncate != o_data.evnt_truncate) %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} SET
|
||||
(publish = '{% if data.evnt_insert %}insert{% if add_comma_after_insert == 'insert' %}, {% endif %}{% endif %}{% if data.evnt_update %}update{% if add_comma_after_update == 'update' %}, {% endif %}{% endif %}{% if data.evnt_delete %}delete{% if add_comma_after_delete == 'delete' %}, {% endif %}{% endif %}{% if data.evnt_truncate %}truncate{% endif %}');
|
||||
|
||||
{% endif %}
|
||||
{### Alter publication partition root ###}
|
||||
{% if data.publish_via_partition_root is defined and data.publish_via_partition_root != o_data.publish_via_partition_root%}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} SET
|
||||
(publish_via_partition_root = {{ data.publish_via_partition_root|lower }});
|
||||
|
||||
{% endif %}
|
||||
{### Alter drop publication table ###}
|
||||
{% if drop_table %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
DROP TABLE {% if data.only_table%}ONLY {% endif %}{% for pub_table in drop_table_data %}{% if loop.index != 1 %}, {% endif %}{{ pub_table['table_name'] or pub_table }}{% endfor %};
|
||||
|
||||
{% endif %}
|
||||
|
||||
{### Alter drop publication schema ###}
|
||||
{% if drop_schema %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
DROP TABLES IN SCHEMA {% for pub_schema in drop_schema_data %}{% if loop.index != 1 %}, {% endif %}{{ pub_schema }}{% endfor %};
|
||||
|
||||
{% endif %}
|
||||
|
||||
{### Alter update publication table ###}
|
||||
{% if update_table %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
SET TABLE {% for pub_table in update_table_data %}{% if loop.index != 1 %}, TABLE {% endif %}{{ pub_table['table_name'] or pub_table }}{% if pub_table['columns'] %} ({% for column in pub_table['columns'] %}{% if loop.index != 1 %}, {% endif %}{{ column }}{% endfor %}){% endif %}{% if pub_table['where'] %} WHERE ({{pub_table['where']}}){% endif %}{% endfor %};
|
||||
|
||||
{% endif %}
|
||||
|
||||
{### Alter publication table ###}
|
||||
{% if add_table %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
ADD TABLE {% if data.only_table%}ONLY {% endif %}{% for pub_table in add_table_data %}{% if loop.index != 1 %}, {% endif %}{{ pub_table['table_name'] or pub_table }}{% if pub_table['columns'] %} ({% for column in pub_table['columns'] %}{% if loop.index != 1 %}, {% endif %}{{ column }}{% endfor %}){% endif %}{% if pub_table['where'] %} WHERE ({{pub_table['where']}}){% endif %}{% endfor %};
|
||||
|
||||
{% endif %}
|
||||
|
||||
{### Alter add publication schema ###}
|
||||
{% if add_schema %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
ADD TABLES IN SCHEMA {% for pub_schema in add_schema_data %}{% if loop.index != 1 %}, {% endif %}{{ pub_schema }}{% endfor %};
|
||||
|
||||
{% endif %}
|
||||
|
||||
{### Alter publication name ###}
|
||||
{% if data.name != o_data.name %}
|
||||
ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }}
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
{% endif %}
|
||||
@@ -0,0 +1,2 @@
|
||||
SELECT COUNT(*)
|
||||
FROM pg_catalog.pg_publication c
|
||||
@@ -0,0 +1,7 @@
|
||||
SELECT
|
||||
pg_catalog.quote_ident(attname) as column
|
||||
FROM
|
||||
pg_attribute
|
||||
WHERE
|
||||
attrelid = '{{ tid }}' :: regclass
|
||||
and attstattarget =-1;
|
||||
@@ -0,0 +1,15 @@
|
||||
SELECT
|
||||
pg_catalog.quote_ident(c.table_schema)|| '.' || pg_catalog.quote_ident(c.table_name) AS table,
|
||||
(
|
||||
pg_catalog.quote_ident(c.table_schema)|| '.' || pg_catalog.quote_ident(c.table_name)
|
||||
):: regclass :: oid as tid
|
||||
FROM
|
||||
information_schema.tables c
|
||||
WHERE
|
||||
c.table_type = 'BASE TABLE'
|
||||
AND c.table_schema NOT LIKE 'pg\_%'
|
||||
AND c.table_schema NOT LIKE 'pgagent'
|
||||
AND c.table_schema NOT LIKE 'sys'
|
||||
AND c.table_schema NOT IN ('information_schema')
|
||||
ORDER BY
|
||||
1;
|
||||
@@ -0,0 +1,4 @@
|
||||
SELECT pg_catalog.quote_ident(n.nspname) || '.' || pg_catalog.quote_ident(cls.relname) AS table_name
|
||||
FROM pg_publication_rel prel
|
||||
JOIN pg_class cls ON cls.oid = prel.prrelid
|
||||
JOIN pg_catalog.pg_namespace n ON cls.relnamespace = n.oid WHERE prel.prpubid = {{pbid}} :: oid;
|
||||